summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/components
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn53
-rw-r--r--chromium/components/OWNERS1
-rw-r--r--chromium/components/about_ui/credit_utils.cc5
-rw-r--r--chromium/components/app_modal/app_modal_dialog_queue.h7
-rw-r--r--chromium/components/app_modal/javascript_dialog_extensions_client.h2
-rw-r--r--chromium/components/app_modal/javascript_dialog_manager.cc23
-rw-r--r--chromium/components/app_modal/javascript_dialog_manager.h4
-rw-r--r--chromium/components/arc/BUILD.gn16
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.cc11
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.h4
-rw-r--r--chromium/components/arc/arc_bridge_service.h8
-rw-r--r--chromium/components/arc/arc_features.cc5
-rw-r--r--chromium/components/arc/arc_features.h1
-rw-r--r--chromium/components/arc/arc_service.cc18
-rw-r--r--chromium/components/arc/arc_service.h35
-rw-r--r--chromium/components/arc/arc_service_manager.cc33
-rw-r--r--chromium/components/arc/arc_service_manager.h82
-rw-r--r--chromium/components/arc/arc_service_manager_unittest.cc209
-rw-r--r--chromium/components/arc/arc_session.cc193
-rw-r--r--chromium/components/arc/arc_session_runner.cc31
-rw-r--r--chromium/components/arc/arc_session_runner.h11
-rw-r--r--chromium/components/arc/arc_session_runner_unittest.cc22
-rw-r--r--chromium/components/arc/arc_util.cc10
-rw-r--r--chromium/components/arc/arc_util.h4
-rw-r--r--chromium/components/arc/audio/DEPS2
-rw-r--r--chromium/components/arc/audio/arc_audio_bridge.cc8
-rw-r--r--chromium/components/arc/audio/arc_audio_bridge.h1
-rw-r--r--chromium/components/arc/bitmap/bitmap_struct_traits.h6
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits.cc6
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.cc6
-rw-r--r--chromium/components/arc/clipboard/arc_clipboard_bridge.cc207
-rw-r--r--chromium/components/arc/clipboard/arc_clipboard_bridge.h18
-rw-r--r--chromium/components/arc/common/ARC_SECURITY_OWNERS4
-rw-r--r--chromium/components/arc/common/OWNERS3
-rw-r--r--chromium/components/arc/common/accessibility_helper.mojom9
-rw-r--r--chromium/components/arc/common/app.mojom42
-rw-r--r--chromium/components/arc/common/arc_bridge.mojom9
-rw-r--r--chromium/components/arc/common/cast_receiver.mojom29
-rw-r--r--chromium/components/arc/common/clipboard.mojom60
-rw-r--r--chromium/components/arc/common/oemcrypto.mojom227
-rw-r--r--chromium/components/arc/common/video_encode_accelerator.mojom40
-rw-r--r--chromium/components/arc/common/voice_interaction_framework.mojom6
-rw-r--r--chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc13
-rw-r--r--chromium/components/arc/ime/arc_ime_bridge_impl.cc19
-rw-r--r--chromium/components/arc/ime/arc_ime_service.cc57
-rw-r--r--chromium/components/arc/ime/arc_ime_service.h12
-rw-r--r--chromium/components/arc/ime/arc_ime_service_unittest.cc32
-rw-r--r--chromium/components/arc/intent_helper/DEPS7
-rw-r--r--chromium/components/arc/intent_helper/activity_icon_loader.h1
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc25
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.h11
-rw-r--r--chromium/components/arc/intent_helper/intent_filter_struct_traits.h18
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model.cc (renamed from chromium/components/arc/intent_helper/link_handler_model_impl.cc)79
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model.h (renamed from chromium/components/arc/intent_helper/link_handler_model_impl.h)59
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model_unittest.cc (renamed from chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc)10
-rw-r--r--chromium/components/arc/metrics/arc_metrics_service.cc11
-rw-r--r--chromium/components/arc/net/arc_net_host_impl.cc30
-rw-r--r--chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc7
-rw-r--r--chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h1
-rw-r--r--chromium/components/arc/power/DEPS2
-rw-r--r--chromium/components/arc/power/arc_power_bridge.cc8
-rw-r--r--chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc14
-rw-r--r--chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h3
-rw-r--r--chromium/components/autofill/android/BUILD.gn53
-rw-r--r--chromium/components/autofill/android/autofill_provider_android.cc4
-rw-r--r--chromium/components/autofill/android/autofill_provider_android.h3
-rw-r--r--chromium/components/autofill/android/form_data_android.cc4
-rw-r--r--chromium/components/autofill/android/form_data_android.h2
-rw-r--r--chromium/components/autofill/android/java/strings/autofill_strings.grd103
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_am.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ar.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_bg.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ca.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_cs.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_da.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_de.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_el.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_en-GB.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_es-419.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_es.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_fa.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_fi.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_fil.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_fr.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_hi.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_hr.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_hu.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_id.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_it.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_iw.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ja.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ko.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_lt.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_lv.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_nl.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_no.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_pl.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-BR.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-PT.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ro.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_ru.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_sk.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_sl.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_sr.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_sv.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_sw.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_th.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_tr.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_uk.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_vi.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-CN.xtb5
-rw-r--r--chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-TW.xtb5
-rw-r--r--chromium/components/autofill/content/browser/BUILD.gn8
-rw-r--r--chromium/components/autofill/content/browser/DEPS5
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc10
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h5
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.cc10
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc22
-rw-r--r--chromium/components/autofill/content/browser/payments/OWNERS1
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc10
-rw-r--r--chromium/components/autofill/content/common/autofill_agent.mojom4
-rw-r--r--chromium/components/autofill/content/common/autofill_driver.mojom15
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.cc59
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.h46
-rw-r--r--chromium/components/autofill/content/renderer/BUILD.gn5
-rw-r--r--chromium/components/autofill/content/renderer/DEPS1
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc28
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h4
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc43
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc91
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h17
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc5
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc9
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h4
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc8
-rw-r--r--chromium/components/autofill/content/renderer/test_password_autofill_agent.cc6
-rw-r--r--chromium/components/autofill/content/renderer/test_password_autofill_agent.h3
-rw-r--r--chromium/components/autofill/content/renderer/test_password_generation_agent.cc6
-rw-r--r--chromium/components/autofill/content/renderer/test_password_generation_agent.h4
-rw-r--r--chromium/components/autofill/core/DEPS1
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn23
-rw-r--r--chromium/components/autofill/core/browser/address.cc99
-rw-r--r--chromium/components/autofill/core/browser/address.h11
-rw-r--r--chromium/components/autofill/core/browser/address_i18n.cc10
-rw-r--r--chromium/components/autofill/core/browser/address_i18n.h5
-rw-r--r--chromium/components/autofill/core/browser/address_i18n_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/address_validation_util.cc155
-rw-r--r--chromium/components/autofill/core/browser/address_validation_util.h23
-rw-r--r--chromium/components/autofill/core/browser/address_validation_util_unittest.cc232
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant.h6
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h17
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc23
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h11
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc14
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc19
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h16
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc143
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h35
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc336
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc301
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h247
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc503
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.cc129
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.h43
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator.cc38
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_unittest.cc242
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.cc144
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.h108
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc243
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc10
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h3
-rw-r--r--chromium/components/autofill/core/browser/contact_info.cc29
-rw-r--r--chromium/components/autofill/core/browser/contact_info.h10
-rw-r--r--chromium/components/autofill/core/browser/credit_card.cc89
-rw-r--r--chromium/components/autofill/core/browser/credit_card.h10
-rw-r--r--chromium/components/autofill/core/browser/credit_card_unittest.cc166
-rw-r--r--chromium/components/autofill/core/browser/detail_input.cc17
-rw-r--r--chromium/components/autofill/core/browser/detail_input.h50
-rw-r--r--chromium/components/autofill/core/browser/dialog_section.h27
-rw-r--r--chromium/components/autofill/core/browser/form_group.cc28
-rw-r--r--chromium/components/autofill/core/browser/form_group.h28
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc168
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h24
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc277
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc14
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h20
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc27
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc (renamed from chromium/components/autofill/content/browser/payments/payments_client_unittest.cc)24
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h6
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc1039
-rw-r--r--chromium/components/autofill/core/browser/phone_email_validation_util.cc70
-rw-r--r--chromium/components/autofill/core/browser/phone_email_validation_util.h20
-rw-r--r--chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc211
-rw-r--r--chromium/components/autofill/core/browser/phone_number.cc93
-rw-r--r--chromium/components/autofill/core/browser/phone_number.h10
-rw-r--r--chromium/components/autofill/core/browser/popup_item_ids.h1
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto14
-rw-r--r--chromium/components/autofill/core/browser/server_field_types_util.cc83
-rw-r--r--chromium/components/autofill/core/browser/server_field_types_util.h48
-rw-r--r--chromium/components/autofill/core/browser/state_names.cc106
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc9
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h10
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h4
-rw-r--r--chromium/components/autofill/core/browser/validation.cc19
-rw-r--r--chromium/components/autofill/core/browser/validation.h5
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc1
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc17
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc10
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc5
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h23
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc95
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h43
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc79
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h64
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h24
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc98
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.cc9
-rw-r--r--chromium/components/autofill_strings.grdp51
-rw-r--r--chromium/components/background_task_scheduler/BUILD.gn20
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.cc2
-rw-r--r--chromium/components/bookmarks/common/android/bookmark_id.cc6
-rw-r--r--chromium/components/bookmarks/common/android/bookmark_id.h6
-rw-r--r--chromium/components/browser_sync/abstract_profile_sync_service_test.cc9
-rw-r--r--chromium/components/browser_sync/abstract_profile_sync_service_test.h4
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.cc58
-rw-r--r--chromium/components/browser_sync/profile_sync_service.cc37
-rw-r--r--chromium/components/browser_sync/profile_sync_service.h1
-rw-r--r--chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc131
-rw-r--r--chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc10
-rw-r--r--chromium/components/browser_sync/profile_sync_service_startup_unittest.cc9
-rw-r--r--chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc9
-rw-r--r--chromium/components/browser_sync/profile_sync_service_unittest.cc27
-rw-r--r--chromium/components/browser_sync/profile_sync_test_util.cc8
-rw-r--r--chromium/components/browser_sync/profile_sync_test_util.h2
-rw-r--r--chromium/components/browser_sync/test_profile_sync_service.cc4
-rw-r--r--chromium/components/browser_watcher/BUILD.gn19
-rw-r--r--chromium/components/browser_watcher/dump_stability_report_main_win.cc58
-rw-r--r--chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc23
-rw-r--r--chromium/components/browser_watcher/minidump_user_streams.h18
-rw-r--r--chromium/components/browser_watcher/postmortem_minidump_writer_win.cc8
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.cc114
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.h40
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector_unittest.cc101
-rw-r--r--chromium/components/browser_watcher/stability_data_names.cc1
-rw-r--r--chromium/components/browser_watcher/stability_data_names.h1
-rw-r--r--chromium/components/browser_watcher/stability_paths.cc3
-rw-r--r--chromium/components/browser_watcher/stability_paths_unittest.cc6
-rw-r--r--chromium/components/browser_watcher/stability_report.proto69
-rw-r--r--chromium/components/browser_watcher/stability_report_extractor.cc114
-rw-r--r--chromium/components/browser_watcher/stability_report_extractor_unittest.cc10
-rw-r--r--chromium/components/browser_watcher/stability_report_user_stream_data_source.cc212
-rw-r--r--chromium/components/browser_watcher/stability_report_user_stream_data_source.h40
-rw-r--r--chromium/components/browser_watcher/watcher_client_win.cc25
-rw-r--r--chromium/components/browser_watcher/watcher_client_win.h14
-rw-r--r--chromium/components/browser_watcher/watcher_client_win_unittest.cc85
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win.cc44
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win.h5
-rw-r--r--chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc3
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.cc55
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.h13
-rw-r--r--chromium/components/captive_portal/BUILD.gn2
-rw-r--r--chromium/components/captive_portal/captive_portal_metrics.cc17
-rw-r--r--chromium/components/captive_portal/captive_portal_metrics.h33
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.cc108
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.h54
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_unittest.cc259
-rw-r--r--chromium/components/cast_certificate/cast_crl.cc28
-rw-r--r--chromium/components/cast_certificate/cast_crl_unittest.cc53
-rw-r--r--chromium/components/cast_channel/cast_auth_util.cc169
-rw-r--r--chromium/components/cast_channel/cast_auth_util.h2
-rw-r--r--chromium/components/cast_channel/cast_auth_util_unittest.cc61
-rw-r--r--chromium/components/cast_channel/cast_channel_enum.h2
-rw-r--r--chromium/components/cast_channel/cast_message_util.cc7
-rw-r--r--chromium/components/cast_channel/cast_socket.cc105
-rw-r--r--chromium/components/cast_channel/cast_socket.h95
-rw-r--r--chromium/components/cast_channel/cast_socket_service.cc21
-rw-r--r--chromium/components/cast_channel/cast_socket_service.h15
-rw-r--r--chromium/components/cast_channel/cast_socket_service_unittest.cc4
-rw-r--r--chromium/components/cast_channel/cast_socket_unittest.cc113
-rw-r--r--chromium/components/cast_channel/cast_test_util.h5
-rw-r--r--chromium/components/cast_channel/logger.cc4
-rw-r--r--chromium/components/cdm/browser/cdm_message_filter_android.cc30
-rw-r--r--chromium/components/cdm/browser/cdm_message_filter_android.h17
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.cc461
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.h37
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc49
-rw-r--r--chromium/components/cdm/renderer/BUILD.gn2
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc5
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.h6
-rw-r--r--chromium/components/cdm/renderer/widevine_key_system_properties.cc3
-rw-r--r--chromium/components/cdm/renderer/widevine_key_system_properties.h4
-rw-r--r--chromium/components/certificate_reporting/error_reporter.cc2
-rw-r--r--chromium/components/chrome_cleaner/public/typemaps/DEPS1
-rw-r--r--chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc10
-rw-r--r--chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.h3
-rw-r--r--chromium/components/component_updater/component_updater_service.cc44
-rw-r--r--chromium/components/component_updater/component_updater_service.h18
-rw-r--r--chromium/components/component_updater/component_updater_service_internal.h6
-rw-r--r--chromium/components/component_updater/component_updater_service_unittest.cc28
-rw-r--r--chromium/components/component_updater/default_component_installer.cc6
-rw-r--r--chromium/components/component_updater/default_component_installer.h3
-rw-r--r--chromium/components/component_updater/default_component_installer_unittest.cc21
-rw-r--r--chromium/components/component_updater/mock_component_updater_service.h2
-rw-r--r--chromium/components/components_strings.grd1
-rw-r--r--chromium/components/content_settings/core/browser/BUILD.gn5
-rw-r--r--chromium/components/content_settings/core/browser/DEPS1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.cc8
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.cc12
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.h17
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.cc18
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.cc7
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils_unittest.cc11
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc54
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.h27
-rw-r--r--chromium/components/content_settings/core/browser/user_modifiable_provider.h30
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.cc24
-rw-r--r--chromium/components/content_settings/core/common/content_settings.cc9
-rw-r--r--chromium/components/content_settings/core/common/content_settings.h1
-rw-r--r--chromium/components/content_settings/core/common/content_settings.mojom1
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern.cc51
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern.h26
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern_parser.cc15
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc120
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc13
-rw-r--r--chromium/components/content_settings/core/common/content_settings_struct_traits.cc3
-rw-r--r--chromium/components/content_settings/core/common/content_settings_struct_traits.h5
-rw-r--r--chromium/components/content_settings/core/common/content_settings_types.h26
-rw-r--r--chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc27
-rw-r--r--chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h14
-rw-r--r--chromium/components/crash/content/app/BUILD.gn67
-rw-r--r--chromium/components/crash/content/app/DEPS1
-rw-r--r--chromium/components/crash/content/app/crash_export_stubs.cc52
-rw-r--r--chromium/components/crash/content/app/crash_export_thunks.cc101
-rw-r--r--chromium/components/crash/content/app/crash_export_thunks.h83
-rw-r--r--chromium/components/crash/content/app/crashpad.cc138
-rw-r--r--chromium/components/crash/content/app/crashpad.h45
-rw-r--r--chromium/components/crash/content/app/crashpad_mac.mm8
-rw-r--r--chromium/components/crash/content/app/crashpad_win.cc70
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc5
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc6
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handling_win.cc10
-rw-r--r--chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc6
-rw-r--r--chromium/components/crash/content/app/run_as_crashpad_handler_win.cc30
-rw-r--r--chromium/components/crash/content/app/run_as_crashpad_handler_win.h20
-rw-r--r--chromium/components/crash/content/browser/BUILD.gn2
-rw-r--r--chromium/components/crash/content/browser/child_process_crash_observer_android.cc52
-rw-r--r--chromium/components/crash/content/browser/child_process_crash_observer_android.h39
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android.cc96
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android.h49
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.cc2
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.h6
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.cc58
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.h27
-rw-r--r--chromium/components/crash/content/tools/crash_service.cc19
-rw-r--r--chromium/components/cronet/android/BUILD.gn214
-rw-r--r--chromium/components/cronet/ios/BUILD.gn54
-rw-r--r--chromium/components/cronet/ios/test/BUILD.gn2
-rw-r--r--chromium/components/cryptauth/BUILD.gn6
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc31
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h11
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc59
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc216
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h133
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc212
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h2
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager.cc34
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager.h12
-rw-r--r--chromium/components/cryptauth/device_capability_manager.cc214
-rw-r--r--chromium/components/cryptauth/device_capability_manager.h143
-rw-r--r--chromium/components/cryptauth/device_capability_manager_unittest.cc417
-rw-r--r--chromium/components/cryptauth/remote_device_provider.cc79
-rw-r--r--chromium/components/cryptauth/remote_device_provider.h78
-rw-r--r--chromium/components/cryptauth/remote_device_provider_unittest.cc347
-rw-r--r--chromium/components/cryptauth/secure_channel_unittest.cc7
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc124
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.h1
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc444
-rw-r--r--chromium/components/data_reduction_proxy/content/renderer/BUILD.gn31
-rw-r--r--chromium/components/data_reduction_proxy/content/renderer/DEPS5
-rw-r--r--chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.cc123
-rw-r--r--chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h37
-rw-r--r--chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer_unittest.cc172
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/BUILD.gn2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc20
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc497
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h107
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc12
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc30
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h19
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc683
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc8
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc51
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc21
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h15
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc5
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc42
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc255
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc54
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h24
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc139
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc43
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h17
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc8
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc40
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h13
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc29
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc89
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h24
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc114
-rw-r--r--chromium/components/data_reduction_proxy/core/common/lofi_decider.h10
-rw-r--r--chromium/components/data_usage/core/data_use.cc7
-rw-r--r--chromium/components/data_usage/core/data_use.h4
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator.cc8
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator.h6
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator_unittest.cc12
-rw-r--r--chromium/components/discardable_memory/common/discardable_shared_memory_heap.cc44
-rw-r--r--chromium/components/discardable_memory/common/discardable_shared_memory_heap.h6
-rw-r--r--chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc48
-rw-r--r--chromium/components/dom_distiller/README3
-rw-r--r--chromium/components/dom_distiller/content/browser/BUILD.gn3
-rw-r--r--chromium/components/dom_distiller/content/browser/distillability_driver.cc50
-rw-r--r--chromium/components/dom_distiller/content/browser/distillability_driver.h15
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_android.h16
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc4
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h4
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc3
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents.h3
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc25
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc29
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h15
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc3
-rw-r--r--chromium/components/dom_distiller/core/distiller_url_fetcher.cc2
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_model.h2
-rw-r--r--chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc2
-rw-r--r--chromium/components/domain_reliability/context.h4
-rw-r--r--chromium/components/domain_reliability/google_configs.cc22
-rw-r--r--chromium/components/domain_reliability/monitor.cc1
-rw-r--r--chromium/components/domain_reliability/uploader.cc2
-rw-r--r--chromium/components/domain_reliability/util.cc1
-rw-r--r--chromium/components/doodle/BUILD.gn47
-rw-r--r--chromium/components/doodle/DEPS12
-rw-r--r--chromium/components/doodle/OWNERS1
-rw-r--r--chromium/components/doodle/doodle_fetcher.h48
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl.cc216
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl.h93
-rw-r--r--chromium/components/doodle/doodle_fetcher_impl_unittest.cc439
-rw-r--r--chromium/components/doodle/doodle_service.cc337
-rw-r--r--chromium/components/doodle/doodle_service.h161
-rw-r--r--chromium/components/doodle/doodle_service_unittest.cc743
-rw-r--r--chromium/components/doodle/doodle_types.cc193
-rw-r--r--chromium/components/doodle/doodle_types.h85
-rw-r--r--chromium/components/doodle/doodle_types_unittest.cc213
-rw-r--r--chromium/components/doodle/pref_names.cc14
-rw-r--r--chromium/components/doodle/pref_names.h17
-rw-r--r--chromium/components/download/BUILD.gn9
-rw-r--r--chromium/components/download/OWNERS2
-rw-r--r--chromium/components/download/content/BUILD.gn14
-rw-r--r--chromium/components/download/content/internal/download_driver_impl.cc1
-rw-r--r--chromium/components/download/internal/BUILD.gn31
-rw-r--r--chromium/components/download/internal/DEPS1
-rw-r--r--chromium/components/download/internal/android/network_status_listener_android.cc51
-rw-r--r--chromium/components/download/internal/android/network_status_listener_android.h43
-rw-r--r--chromium/components/download/internal/config.cc18
-rw-r--r--chromium/components/download/internal/config.h11
-rw-r--r--chromium/components/download/internal/controller_impl.cc101
-rw-r--r--chromium/components/download/internal/controller_impl.h6
-rw-r--r--chromium/components/download/internal/controller_impl_unittest.cc133
-rw-r--r--chromium/components/download/internal/download_service_impl.cc9
-rw-r--r--chromium/components/download/internal/download_service_impl.h4
-rw-r--r--chromium/components/download/internal/download_service_impl_unittest.cc3
-rw-r--r--chromium/components/download/internal/download_store.cc8
-rw-r--r--chromium/components/download/internal/entry.cc14
-rw-r--r--chromium/components/download/internal/entry.h15
-rw-r--r--chromium/components/download/internal/entry_utils.cc32
-rw-r--r--chromium/components/download/internal/entry_utils.h27
-rw-r--r--chromium/components/download/internal/entry_utils_unittest.cc66
-rw-r--r--chromium/components/download/internal/file_monitor.h6
-rw-r--r--chromium/components/download/internal/file_monitor_impl.cc16
-rw-r--r--chromium/components/download/internal/file_monitor_impl.h6
-rw-r--r--chromium/components/download/internal/file_monitor_unittest.cc13
-rw-r--r--chromium/components/download/internal/proto/entry.proto10
-rw-r--r--chromium/components/download/internal/proto_conversions.cc13
-rw-r--r--chromium/components/download/internal/proto_conversions_unittest.cc4
-rw-r--r--chromium/components/download/internal/scheduler/device_status_listener.cc27
-rw-r--r--chromium/components/download/internal/scheduler/device_status_listener.h18
-rw-r--r--chromium/components/download/internal/scheduler/device_status_listener_unittest.cc15
-rw-r--r--chromium/components/download/internal/scheduler/network_status_listener.cc45
-rw-r--r--chromium/components/download/internal/scheduler/network_status_listener.h77
-rw-r--r--chromium/components/download/internal/stats.cc6
-rw-r--r--chromium/components/download/internal/stats.h4
-rw-r--r--chromium/components/download/internal/test/BUILD.gn10
-rw-r--r--chromium/components/download/public/BUILD.gn2
-rw-r--r--chromium/components/download/public/DEPS1
-rw-r--r--chromium/components/download/public/client.h37
-rw-r--r--chromium/components/download/public/download_metadata.cc31
-rw-r--r--chromium/components/download/public/download_metadata.h44
-rw-r--r--chromium/components/download/public/download_params.h6
-rw-r--r--chromium/components/download/public/download_service.h2
-rw-r--r--chromium/components/error_page/common/BUILD.gn2
-rw-r--r--chromium/components/error_page/common/error.cc37
-rw-r--r--chromium/components/error_page/common/error.h57
-rw-r--r--chromium/components/error_page/common/localized_error.cc16
-rw-r--r--chromium/components/error_page/common/localized_error.h2
-rw-r--r--chromium/components/error_page/common/net_error_info.cc2
-rw-r--r--chromium/components/error_page/common/net_error_info.h4
-rw-r--r--chromium/components/error_page/renderer/BUILD.gn42
-rw-r--r--chromium/components/error_page/renderer/DEPS8
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core.cc1057
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core.h293
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core_unittest.cc2585
-rw-r--r--chromium/components/exo/BUILD.gn5
-rw-r--r--chromium/components/exo/DEPS5
-rw-r--r--chromium/components/exo/buffer.cc17
-rw-r--r--chromium/components/exo/buffer.h6
-rw-r--r--chromium/components/exo/buffer_unittest.cc74
-rw-r--r--chromium/components/exo/display.cc10
-rw-r--r--chromium/components/exo/display.h4
-rw-r--r--chromium/components/exo/display_unittest.cc6
-rw-r--r--chromium/components/exo/gaming_seat.h4
-rw-r--r--chromium/components/exo/gaming_seat_ozone.cc16
-rw-r--r--chromium/components/exo/keyboard_unittest.cc1
-rw-r--r--chromium/components/exo/layer_tree_frame_sink_holder.cc36
-rw-r--r--chromium/components/exo/layer_tree_frame_sink_holder.h32
-rw-r--r--chromium/components/exo/notification_surface.cc72
-rw-r--r--chromium/components/exo/pointer.cc14
-rw-r--r--chromium/components/exo/pointer.h4
-rw-r--r--chromium/components/exo/pointer_unittest.cc4
-rw-r--r--chromium/components/exo/shell_surface.cc153
-rw-r--r--chromium/components/exo/shell_surface.h12
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc124
-rw-r--r--chromium/components/exo/sub_surface.cc3
-rw-r--r--chromium/components/exo/sub_surface_unittest.cc73
-rw-r--r--chromium/components/exo/surface.cc637
-rw-r--r--chromium/components/exo/surface.h135
-rw-r--r--chromium/components/exo/surface_tree_host.cc222
-rw-r--r--chromium/components/exo/surface_tree_host.h81
-rw-r--r--chromium/components/exo/surface_unittest.cc503
-rw-r--r--chromium/components/exo/wayland/BUILD.gn30
-rw-r--r--chromium/components/exo/wayland/clients/client_base.cc130
-rw-r--r--chromium/components/exo/wayland/clients/client_base.h20
-rw-r--r--chromium/components/exo/wayland/clients/client_helper.cc20
-rw-r--r--chromium/components/exo/wayland/clients/client_helper.h20
-rw-r--r--chromium/components/exo/wayland/clients/rects.cc21
-rw-r--r--chromium/components/exo/wayland/clients/simple.cc4
-rw-r--r--chromium/components/exo/wayland/clients/subsurface.cc158
-rw-r--r--chromium/components/exo/wayland/clients/yuv.cc14
-rw-r--r--chromium/components/exo/wayland/server.cc150
-rw-r--r--chromium/components/exo/wm_helper.h3
-rw-r--r--chromium/components/exo/wm_helper_ash.cc20
-rw-r--r--chromium/components/exo/wm_helper_ash.h1
-rw-r--r--chromium/components/exo/wm_helper_mus.cc5
-rw-r--r--chromium/components/exo/wm_helper_mus.h1
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.cc2
-rw-r--r--chromium/components/favicon/core/favicon_driver.h6
-rw-r--r--chromium/components/favicon/core/favicon_driver_impl.cc5
-rw-r--r--chromium/components/favicon/core/favicon_driver_impl.h2
-rw-r--r--chromium/components/favicon/core/favicon_handler.cc56
-rw-r--r--chromium/components/favicon/core/favicon_handler.h20
-rw-r--r--chromium/components/favicon/core/favicon_handler_unittest.cc99
-rw-r--r--chromium/components/favicon/core/favicon_service.h9
-rw-r--r--chromium/components/favicon/core/favicon_service_impl.cc4
-rw-r--r--chromium/components/favicon/core/favicon_service_impl.h3
-rw-r--r--chromium/components/favicon/core/large_icon_service.cc15
-rw-r--r--chromium/components/favicon/core/large_icon_service.h6
-rw-r--r--chromium/components/favicon/core/large_icon_service_unittest.cc25
-rw-r--r--chromium/components/favicon/ios/web_favicon_driver.h2
-rw-r--r--chromium/components/favicon/ios/web_favicon_driver.mm11
-rw-r--r--chromium/components/favicon_base/select_favicon_frames.cc6
-rw-r--r--chromium/components/feature_engagement/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/BUILD.gn)14
-rw-r--r--chromium/components/feature_engagement/DEPS (renamed from chromium/components/feature_engagement_tracker/DEPS)0
-rw-r--r--chromium/components/feature_engagement/OWNERS5
-rw-r--r--chromium/components/feature_engagement/README.md (renamed from chromium/components/feature_engagement_tracker/README.md)81
-rw-r--r--chromium/components/feature_engagement/components_unittests.filter22
-rw-r--r--chromium/components/feature_engagement/internal/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/internal/BUILD.gn)85
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.cc141
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.h (renamed from chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h)46
-rw-r--r--chromium/components/feature_engagement/internal/availability_model.h (renamed from chromium/components/feature_engagement_tracker/internal/availability_model.h)10
-rw-r--r--chromium/components/feature_engagement/internal/availability_model_impl.cc (renamed from chromium/components/feature_engagement_tracker/internal/availability_model_impl.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/availability_model_impl.h (renamed from chromium/components/feature_engagement_tracker/internal/availability_model_impl.h)23
-rw-r--r--chromium/components/feature_engagement/internal/availability_model_impl_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/availability_model_impl_unittest.cc)10
-rw-r--r--chromium/components/feature_engagement/internal/chrome_variations_configuration.cc (renamed from chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc)12
-rw-r--r--chromium/components/feature_engagement/internal/chrome_variations_configuration.h (renamed from chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.h)14
-rw-r--r--chromium/components/feature_engagement/internal/chrome_variations_configuration_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration_unittest.cc)10
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator.cc (renamed from chromium/components/feature_engagement_tracker/internal/condition_validator.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/condition_validator.h)16
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/condition_validator_unittest.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/configuration.cc (renamed from chromium/components/feature_engagement_tracker/internal/configuration.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/configuration.h (renamed from chromium/components/feature_engagement_tracker/internal/configuration.h)10
-rw-r--r--chromium/components/feature_engagement/internal/configuration_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/configuration_unittest.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/editable_configuration.cc (renamed from chromium/components/feature_engagement_tracker/internal/editable_configuration.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/editable_configuration.h (renamed from chromium/components/feature_engagement_tracker/internal/editable_configuration.h)12
-rw-r--r--chromium/components/feature_engagement/internal/editable_configuration_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/event_model.h (renamed from chromium/components/feature_engagement_tracker/internal/model.h)23
-rw-r--r--chromium/components/feature_engagement/internal/event_model_impl.cc (renamed from chromium/components/feature_engagement_tracker/internal/model_impl.cc)48
-rw-r--r--chromium/components/feature_engagement/internal/event_model_impl.h (renamed from chromium/components/feature_engagement_tracker/internal/model_impl.h)38
-rw-r--r--chromium/components/feature_engagement/internal/event_model_impl_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc)184
-rw-r--r--chromium/components/feature_engagement/internal/event_storage_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/storage_validator.h)22
-rw-r--r--chromium/components/feature_engagement/internal/event_store.h (renamed from chromium/components/feature_engagement_tracker/internal/store.h)22
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.cc)31
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.h)18
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator_unittest.cc)54
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_event_storage_validator.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc)33
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_event_storage_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.h)30
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_event_storage_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator_unittest.cc)33
-rw-r--r--chromium/components/feature_engagement/internal/in_memory_event_store.cc51
-rw-r--r--chromium/components/feature_engagement/internal/in_memory_event_store.h (renamed from chromium/components/feature_engagement_tracker/internal/in_memory_store.h)26
-rw-r--r--chromium/components/feature_engagement/internal/in_memory_event_store_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc)18
-rw-r--r--chromium/components/feature_engagement/internal/init_aware_event_model.cc69
-rw-r--r--chromium/components/feature_engagement/internal/init_aware_event_model.h (renamed from chromium/components/feature_engagement_tracker/internal/init_aware_model.h)28
-rw-r--r--chromium/components/feature_engagement/internal/init_aware_event_model_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc)54
-rw-r--r--chromium/components/feature_engagement/internal/never_availability_model.cc (renamed from chromium/components/feature_engagement_tracker/internal/never_availability_model.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/never_availability_model.h (renamed from chromium/components/feature_engagement_tracker/internal/never_availability_model.h)12
-rw-r--r--chromium/components/feature_engagement/internal/never_availability_model_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/never_availability_model_unittest.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator.cc (renamed from chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/never_condition_validator.h)18
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc)32
-rw-r--r--chromium/components/feature_engagement/internal/never_event_storage_validator.cc24
-rw-r--r--chromium/components/feature_engagement/internal/never_event_storage_validator.h34
-rw-r--r--chromium/components/feature_engagement/internal/never_event_storage_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/never_storage_validator_unittest.cc)18
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator.cc (renamed from chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc)16
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator.h (renamed from chromium/components/feature_engagement_tracker/internal/once_condition_validator.h)20
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc)83
-rw-r--r--chromium/components/feature_engagement/internal/persistent_availability_store.cc (renamed from chromium/components/feature_engagement_tracker/internal/availability_store.cc)22
-rw-r--r--chromium/components/feature_engagement/internal/persistent_availability_store.h (renamed from chromium/components/feature_engagement_tracker/internal/availability_store.h)26
-rw-r--r--chromium/components/feature_engagement/internal/persistent_availability_store_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc)78
-rw-r--r--chromium/components/feature_engagement/internal/persistent_event_store.cc (renamed from chromium/components/feature_engagement_tracker/internal/persistent_store.cc)30
-rw-r--r--chromium/components/feature_engagement/internal/persistent_event_store.h59
-rw-r--r--chromium/components/feature_engagement/internal/persistent_event_store_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/persistent_store_unittest.cc)42
-rw-r--r--chromium/components/feature_engagement/internal/proto/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn)0
-rw-r--r--chromium/components/feature_engagement/internal/proto/availability.proto (renamed from chromium/components/feature_engagement_tracker/internal/proto/availability.proto)4
-rw-r--r--chromium/components/feature_engagement/internal/proto/event.proto (renamed from chromium/components/feature_engagement_tracker/internal/proto/event.proto)4
-rw-r--r--chromium/components/feature_engagement/internal/single_invalid_configuration.cc (renamed from chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/single_invalid_configuration.h (renamed from chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h)12
-rw-r--r--chromium/components/feature_engagement/internal/single_invalid_configuration_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc)8
-rw-r--r--chromium/components/feature_engagement/internal/stats.cc (renamed from chromium/components/feature_engagement_tracker/internal/stats.cc)14
-rw-r--r--chromium/components/feature_engagement/internal/stats.h (renamed from chromium/components/feature_engagement_tracker/internal/stats.h)22
-rw-r--r--chromium/components/feature_engagement/internal/system_time_provider.cc (renamed from chromium/components/feature_engagement_tracker/internal/system_time_provider.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/system_time_provider.h (renamed from chromium/components/feature_engagement_tracker/internal/system_time_provider.h)12
-rw-r--r--chromium/components/feature_engagement/internal/system_time_provider_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc)6
-rw-r--r--chromium/components/feature_engagement/internal/test/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/internal/test/BUILD.gn)4
-rw-r--r--chromium/components/feature_engagement/internal/time_provider.h (renamed from chromium/components/feature_engagement_tracker/internal/time_provider.h)10
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc)174
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.h (renamed from chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h)51
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl_unittest.cc (renamed from chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc)167
-rw-r--r--chromium/components/feature_engagement/public/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/public/BUILD.gn)22
-rw-r--r--chromium/components/feature_engagement/public/event_constants.cc (renamed from chromium/components/feature_engagement_tracker/public/event_constants.cc)8
-rw-r--r--chromium/components/feature_engagement/public/event_constants.h (renamed from chromium/components/feature_engagement_tracker/public/event_constants.h)22
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.cc (renamed from chromium/components/feature_engagement_tracker/public/feature_constants.cc)10
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.h (renamed from chromium/components/feature_engagement_tracker/public/feature_constants.h)14
-rw-r--r--chromium/components/feature_engagement/public/feature_list.cc (renamed from chromium/components/feature_engagement_tracker/public/feature_list.cc)12
-rw-r--r--chromium/components/feature_engagement/public/feature_list.h (renamed from chromium/components/feature_engagement_tracker/public/feature_list.h)22
-rw-r--r--chromium/components/feature_engagement/public/tracker.h (renamed from chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h)50
-rw-r--r--chromium/components/feature_engagement/test/BUILD.gn (renamed from chromium/components/feature_engagement_tracker/test/BUILD.gn)8
-rw-r--r--chromium/components/feature_engagement_tracker/OWNERS5
-rw-r--r--chromium/components/feature_engagement_tracker/components_unittests.filter21
-rw-r--r--chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc150
-rw-r--r--chromium/components/feature_engagement_tracker/internal/in_memory_store.cc50
-rw-r--r--chromium/components/feature_engagement_tracker/internal/init_aware_model.cc65
-rw-r--r--chromium/components/feature_engagement_tracker/internal/never_storage_validator.cc23
-rw-r--r--chromium/components/feature_engagement_tracker/internal/never_storage_validator.h34
-rw-r--r--chromium/components/feature_engagement_tracker/internal/persistent_store.h59
-rw-r--r--chromium/components/feedback/BUILD.gn4
-rw-r--r--chromium/components/feedback/feedback_data.cc18
-rw-r--r--chromium/components/feedback/feedback_data.h9
-rw-r--r--chromium/components/feedback/feedback_data_unittest.cc58
-rw-r--r--chromium/components/feedback/feedback_report.cc4
-rw-r--r--chromium/components/feedback/feedback_uploader.cc141
-rw-r--r--chromium/components/feedback/feedback_uploader.h61
-rw-r--r--chromium/components/feedback/feedback_uploader_chrome.cc100
-rw-r--r--chromium/components/feedback/feedback_uploader_chrome.h37
-rw-r--r--chromium/components/feedback/feedback_uploader_delegate.cc8
-rw-r--r--chromium/components/feedback/feedback_uploader_delegate.h11
-rw-r--r--chromium/components/feedback/feedback_uploader_dispatch_unittest.cc (renamed from chromium/components/feedback/feedback_uploader_chrome_unittest.cc)29
-rw-r--r--chromium/components/feedback/feedback_uploader_factory.cc11
-rw-r--r--chromium/components/feedback/feedback_uploader_factory.h20
-rw-r--r--chromium/components/feedback/feedback_uploader_unittest.cc59
-rw-r--r--chromium/components/feedback/feedback_util.cc27
-rw-r--r--chromium/components/feedback/feedback_util.h22
-rw-r--r--chromium/components/feedback/system_logs/system_logs_fetcher.h5
-rw-r--r--chromium/components/filesystem/OWNERS6
-rw-r--r--chromium/components/flags_ui/flags_storage.h2
-rw-r--r--chromium/components/flags_ui/pref_service_flags_storage.cc4
-rw-r--r--chromium/components/flags_ui/pref_service_flags_storage.h1
-rw-r--r--chromium/components/font_service/OWNERS3
-rw-r--r--chromium/components/gcm_driver/instance_id/android/BUILD.gn4
-rw-r--r--chromium/components/google/core/browser/google_url_tracker.cc9
-rw-r--r--chromium/components/guest_view/browser/BUILD.gn2
-rw-r--r--chromium/components/guest_view/browser/PRESUBMIT.py27
-rw-r--r--chromium/components/guest_view/browser/bad_message.cc48
-rw-r--r--chromium/components/guest_view/browser/bad_message.h53
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.h4
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager.cc16
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_filter.cc20
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_filter.h6
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.h3
-rw-r--r--chromium/components/history/core/browser/BUILD.gn5
-rw-r--r--chromium/components/history/core/browser/OWNERS2
-rw-r--r--chromium/components/history/core/browser/browsing_history_driver.h83
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.cc749
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.h266
-rw-r--r--chromium/components/history/core/browser/browsing_history_service_unittest.cc698
-rw-r--r--chromium/components/history/core/browser/expire_history_backend.cc66
-rw-r--r--chromium/components/history/core/browser/expire_history_backend.h22
-rw-r--r--chromium/components/history/core/browser/expire_history_backend_unittest.cc147
-rw-r--r--chromium/components/history/core/browser/history_backend.cc51
-rw-r--r--chromium/components/history/core/browser/history_backend.h14
-rw-r--r--chromium/components/history/core/browser/history_backend_db_unittest.cc5
-rw-r--r--chromium/components/history/core/browser/history_backend_unittest.cc116
-rw-r--r--chromium/components/history/core/browser/history_querying_unittest.cc4
-rw-r--r--chromium/components/history/core/browser/history_service.cc6
-rw-r--r--chromium/components/history/core/browser/history_service.h8
-rw-r--r--chromium/components/history/core/browser/history_service_unittest.cc8
-rw-r--r--chromium/components/history/core/browser/history_types.cc9
-rw-r--r--chromium/components/history/core/browser/history_types.h12
-rw-r--r--chromium/components/history/core/browser/thumbnail_database.cc43
-rw-r--r--chromium/components/history/core/browser/thumbnail_database.h9
-rw-r--r--chromium/components/history/core/browser/thumbnail_database_unittest.cc130
-rw-r--r--chromium/components/history/core/browser/top_sites_backend.cc3
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge.cc439
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge.h86
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc1195
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_metadata_database.cc28
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_metadata_database.h3
-rw-r--r--chromium/components/history/core/browser/web_history_service.cc2
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h11
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.mm26
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm17
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.h10
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm18
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm23
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h2
-rw-r--r--chromium/components/invalidation/impl/BUILD.gn1
-rw-r--r--chromium/components/keyed_service/core/dependency_graph.cc38
-rw-r--r--chromium/components/keyed_service/core/keyed_service_base_factory.h3
-rw-r--r--chromium/components/language/OWNERS1
-rw-r--r--chromium/components/leveldb/OWNERS6
-rw-r--r--chromium/components/leveldb/leveldb_service_impl.cc26
-rw-r--r--chromium/components/leveldb/public/cpp/util.cc3
-rw-r--r--chromium/components/leveldb/public/cpp/util.h4
-rw-r--r--chromium/components/leveldb/public/interfaces/leveldb.mojom8
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.cc87
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.h14
-rw-r--r--chromium/components/leveldb_proto/options.h16
-rw-r--r--chromium/components/leveldb_proto/proto_database.h5
-rw-r--r--chromium/components/leveldb_proto/proto_database_impl_unittest.cc69
-rw-r--r--chromium/components/login/base_screen_handler_utils.h7
-rw-r--r--chromium/components/login/screens/screen_context.cc2
-rw-r--r--chromium/components/machine_intelligence/ranker_model_loader_unittest.cc21
-rw-r--r--chromium/components/machine_intelligence/ranker_url_fetcher.cc4
-rw-r--r--chromium/components/metrics/BUILD.gn27
-rw-r--r--chromium/components/metrics/DEPS1
-rw-r--r--chromium/components/metrics/OWNERS6
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.cc25
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.h4
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc36
-rw-r--r--chromium/components/metrics/component_metrics_provider.cc91
-rw-r--r--chromium/components/metrics/component_metrics_provider.h37
-rw-r--r--chromium/components/metrics/component_metrics_provider_unittest.cc58
-rw-r--r--chromium/components/metrics/daily_event.cc10
-rw-r--r--chromium/components/metrics/daily_event_unittest.cc8
-rw-r--r--chromium/components/metrics/data_use_tracker.h2
-rw-r--r--chromium/components/metrics/delegating_provider.cc112
-rw-r--r--chromium/components/metrics/delegating_provider.h60
-rw-r--r--chromium/components/metrics/drive_metrics_provider.cc2
-rw-r--r--chromium/components/metrics/drive_metrics_provider.h4
-rw-r--r--chromium/components/metrics/drive_metrics_provider_fuchsia.cc16
-rw-r--r--chromium/components/metrics/drive_metrics_provider_linux.cc2
-rw-r--r--chromium/components/metrics/file_metrics_provider.cc2
-rw-r--r--chromium/components/metrics/file_metrics_provider.h2
-rw-r--r--chromium/components/metrics/file_metrics_provider_unittest.cc30
-rw-r--r--chromium/components/metrics/generate_expired_histograms_array.gni42
-rw-r--r--chromium/components/metrics/metrics_log.cc101
-rw-r--r--chromium/components/metrics/metrics_log.h59
-rw-r--r--chromium/components/metrics/metrics_log_manager_unittest.cc2
-rw-r--r--chromium/components/metrics/metrics_log_store_unittest.cc2
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc121
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc15
-rw-r--r--chromium/components/metrics/metrics_pref_names.h6
-rw-r--r--chromium/components/metrics/metrics_provider.cc22
-rw-r--r--chromium/components/metrics/metrics_provider.h38
-rw-r--r--chromium/components/metrics/metrics_service.cc170
-rw-r--r--chromium/components/metrics/metrics_service.h27
-rw-r--r--chromium/components/metrics/metrics_service_client.h5
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc28
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc61
-rw-r--r--chromium/components/metrics/metrics_state_manager.h6
-rw-r--r--chromium/components/metrics/metrics_state_manager_unittest.cc22
-rw-r--r--chromium/components/metrics/net/net_metrics_log_uploader.cc4
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.cc78
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.h23
-rw-r--r--chromium/components/metrics/net/network_metrics_provider_unittest.cc51
-rw-r--r--chromium/components/metrics/profiler/profiler_metrics_provider.cc2
-rw-r--r--chromium/components/metrics/profiler/profiler_metrics_provider.h9
-rw-r--r--chromium/components/metrics/profiler/profiler_metrics_provider_unittest.cc2
-rw-r--r--chromium/components/metrics/proto/cast_logs.proto3
-rw-r--r--chromium/components/metrics/proto/omnibox_event.proto4
-rw-r--r--chromium/components/metrics/proto/omnibox_input_type.proto4
-rw-r--r--chromium/components/metrics/proto/perf_stat.proto4
-rw-r--r--chromium/components/metrics/proto/system_profile.proto51
-rw-r--r--chromium/components/metrics/proto/translate_event.proto5
-rw-r--r--chromium/components/metrics/proto/ukm/report.proto4
-rw-r--r--chromium/components/metrics/proto/ukm/source.proto5
-rw-r--r--chromium/components/metrics/proto/user_action_event.proto2
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc4
-rw-r--r--chromium/components/metrics/test_metrics_provider.cc11
-rw-r--r--chromium/components/metrics/test_metrics_provider.h10
-rw-r--r--chromium/components/metrics/test_metrics_service_client.cc5
-rw-r--r--chromium/components/metrics/test_metrics_service_client.h2
-rw-r--r--chromium/components/mime_util/BUILD.gn34
-rw-r--r--chromium/components/mime_util/DEPS4
-rw-r--r--chromium/components/mime_util/OWNERS7
-rw-r--r--chromium/components/mime_util/mime_util.cc203
-rw-r--r--chromium/components/mime_util/mime_util.h24
-rw-r--r--chromium/components/mime_util/mime_util_unittest.cc55
-rw-r--r--chromium/components/minidump_uploader/BUILD.gn2
-rw-r--r--chromium/components/multidevice/OWNERS4
-rw-r--r--chromium/components/multidevice/README.md14
-rw-r--r--chromium/components/multidevice/service/public/interfaces/BUILD.gn11
-rw-r--r--chromium/components/multidevice/service/public/interfaces/OWNERS2
-rw-r--r--chromium/components/multidevice/service/public/interfaces/device_sync.mojom101
-rw-r--r--chromium/components/nacl/broker/BUILD.gn2
-rw-r--r--chromium/components/nacl/loader/BUILD.gn9
-rw-r--r--chromium/components/net_log/net_export_file_writer.cc20
-rw-r--r--chromium/components/net_log/net_export_file_writer.h20
-rw-r--r--chromium/components/net_log/net_export_file_writer_unittest.cc12
-rw-r--r--chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.pngbin2645 -> 2628 bytes
-rw-r--r--chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.pngbin3244 -> 3247 bytes
-rw-r--r--chromium/components/neterror/resources/neterror.css1
-rw-r--r--chromium/components/neterror/resources/offline.js16
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator.cc73
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator.h6
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc140
-rw-r--r--chromium/components/network_session_configurator/common/BUILD.gn2
-rw-r--r--chromium/components/network_session_configurator/common/network_features.cc12
-rw-r--r--chromium/components/network_session_configurator/common/network_features.h18
-rw-r--r--chromium/components/network_session_configurator/common/network_switch_list.h24
-rw-r--r--chromium/components/network_time/network_time_tracker.cc2
-rw-r--r--chromium/components/new_or_sad_tab_strings.grdp23
-rw-r--r--chromium/components/ntp_snippets/BUILD.gn45
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc16
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc296
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h64
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc1028
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_listener.h14
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.cc86
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.h47
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc32
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h10
-rw-r--r--chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider_unittest.cc152
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_json_request.cc18
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_json_request.h14
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc16
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.cc23
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.h11
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc120
-rw-r--r--chromium/components/ntp_snippets/callbacks.h12
-rw-r--r--chromium/components/ntp_snippets/category.h12
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc9
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.h2
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.cc54
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.h12
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics_unittest.cc139
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc65
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h25
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service_unittest.cc6
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc81
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h76
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc244
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_json_request.cc (renamed from chromium/components/ntp_snippets/remote/contextual_json_request.cc)17
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_json_request.h (renamed from chromium/components/ntp_snippets/remote/contextual_json_request.h)6
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_json_request_unittest.cc (renamed from chromium/components/ntp_snippets/remote/contextual_json_request_unittest.cc)4
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h44
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc305
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h104
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc267
-rw-r--r--chromium/components/ntp_snippets/fake_content_suggestions_provider_observer.h2
-rw-r--r--chromium/components/ntp_snippets/features.cc34
-rw-r--r--chromium/components/ntp_snippets/features.h7
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider.cc18
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider.h21
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.cc3
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.h2
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc16
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc21
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/pref_names.cc6
-rw-r--r--chromium/components/ntp_snippets/pref_names.h6
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc25
-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.cc30
-rw-r--r--chromium/components/ntp_snippets/remote/cached_image_fetcher.h14
-rw-r--r--chromium/components/ntp_snippets/remote/cached_image_fetcher_unittest.cc34
-rw-r--r--chromium/components/ntp_snippets/remote/json_request.cc4
-rw-r--r--chromium/components/ntp_snippets/remote/json_request_unittest.cc2
-rw-r--r--chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc30
-rw-r--r--chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h6
-rw-r--r--chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc55
-rw-r--r--chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto5
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion.cc34
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion.h14
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion_builder.cc239
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion_builder.h98
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc1
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_database.cc29
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_database.h4
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc67
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc4
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc413
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h56
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc2053
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h2
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc74
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h9
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc385
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h53
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc (renamed from chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc)32
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h75
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc (renamed from chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc)22
-rw-r--r--chromium/components/ntp_snippets/remote/test_utils.cc2
-rw-r--r--chromium/components/ntp_snippets/remote/test_utils.h5
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc20
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/status.h15
-rw-r--r--chromium/components/ntp_snippets/time_serialization.cc18
-rw-r--r--chromium/components/ntp_snippets/time_serialization.h22
-rw-r--r--chromium/components/ntp_snippets_strings.grdp30
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn2
-rw-r--r--chromium/components/ntp_tiles/constants.cc6
-rw-r--r--chromium/components/ntp_tiles/constants.h7
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl.cc4
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc29
-rw-r--r--chromium/components/ntp_tiles/metrics.cc5
-rw-r--r--chromium/components/ntp_tiles/metrics_unittest.cc31
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc168
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.h35
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc585
-rw-r--r--chromium/components/ntp_tiles/popular_sites.h7
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.cc108
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.h6
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl_unittest.cc254
-rw-r--r--chromium/components/ntp_tiles/pref_names.cc6
-rw-r--r--chromium/components/ntp_tiles/pref_names.h5
-rw-r--r--chromium/components/ntp_tiles/section_type.h30
-rw-r--r--chromium/components/ntp_tiles/tile_source.h2
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc8
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h3
-rw-r--r--chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html13
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc19
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h3
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator.cc8
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator.h2
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc12
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_provider.h3
-rw-r--r--chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h2
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc5
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider.h2
-rw-r--r--chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc8
-rw-r--r--chromium/components/offline_pages/content/renovations/BUILD.gn19
-rw-r--r--chromium/components/offline_pages/content/renovations/DEPS4
-rw-r--r--chromium/components/offline_pages/content/renovations/render_frame_script_injector.cc48
-rw-r--r--chromium/components/offline_pages/content/renovations/render_frame_script_injector.h37
-rw-r--r--chromium/components/offline_pages/core/BUILD.gn12
-rw-r--r--chromium/components/offline_pages/core/DEPS2
-rw-r--r--chromium/components/offline_pages/core/archive_manager.cc4
-rw-r--r--chromium/components/offline_pages/core/archive_manager.h5
-rw-r--r--chromium/components/offline_pages/core/background/BUILD.gn1
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.cc17
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.h6
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.cc13
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.h9
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_stub_taco.cc10
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_stub_taco.h3
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_unittest.cc3
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.cc6
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.h11
-rw-r--r--chromium/components/offline_pages/core/client_id.cc14
-rw-r--r--chromium/components/offline_pages/core/client_id.h5
-rw-r--r--chromium/components/offline_pages/core/client_namespace_constants.cc2
-rw-r--r--chromium/components/offline_pages/core/offline_event_logger.cc1
-rw-r--r--chromium/components/offline_pages/core/offline_event_logger.h4
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.cc5
-rw-r--r--chromium/components/offline_pages/core/offline_page_item.cc23
-rw-r--r--chromium/components/offline_pages/core/offline_page_item.h11
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc78
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_sql.h2
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc104
-rw-r--r--chromium/components/offline_pages/core/offline_page_model.h14
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl.cc66
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl.h9
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc59
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_query.cc119
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_query.h45
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_query_unittest.cc319
-rw-r--r--chromium/components/offline_pages/core/offline_page_types.h9
-rw-r--r--chromium/components/offline_pages/core/offline_pages_ukm_reporter.cc47
-rw-r--r--chromium/components/offline_pages/core/offline_pages_ukm_reporter.h27
-rw-r--r--chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc18
-rw-r--r--chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.h29
-rw-r--r--chromium/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc42
-rw-r--r--chromium/components/offline_pages/core/offline_time_utils.cc19
-rw-r--r--chromium/components/offline_pages/core/offline_time_utils.h25
-rw-r--r--chromium/components/offline_pages/core/prefetch/BUILD.gn55
-rw-r--r--chromium/components/offline_pages/core/prefetch/DEPS1
-rw-r--r--chromium/components/offline_pages/core/prefetch/README.md3
-rw-r--r--chromium/components/offline_pages/core/prefetch/add_unique_urls_task.cc35
-rw-r--r--chromium/components/offline_pages/core/prefetch/add_unique_urls_task.h8
-rw-r--r--chromium/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc164
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_archives_task.cc186
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_archives_task.h59
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_archives_task_unittest.cc323
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_cleanup_task.cc176
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_cleanup_task.h55
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc154
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_completed_task.cc97
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_completed_task.h41
-rw-r--r--chromium/components/offline_pages/core/prefetch/download_completed_task_unittest.cc156
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.cc139
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h43
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc188
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc6
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.h4
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc6
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc141
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h14
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc68
-rw-r--r--chromium/components/offline_pages/core/prefetch/get_operation_task.cc92
-rw-r--r--chromium/components/offline_pages/core/prefetch/get_operation_task.h14
-rw-r--r--chromium/components/offline_pages/core/prefetch/get_operation_task_unittest.cc96
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_archives_task.cc114
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_archives_task.h43
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_archives_task_unittest.cc182
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_completed_task.cc70
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_completed_task.h43
-rw-r--r--chromium/components/offline_pages/core/prefetch/import_completed_task_unittest.cc137
-rw-r--r--chromium/components/offline_pages/core/prefetch/mark_operation_done_task.cc89
-rw-r--r--chromium/components/offline_pages/core/prefetch/mark_operation_done_task.h68
-rw-r--r--chromium/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc163
-rw-r--r--chromium/components/offline_pages/core/prefetch/metrics_finalization_task.cc231
-rw-r--r--chromium/components/offline_pages/core/prefetch/metrics_finalization_task.h38
-rw-r--r--chromium/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc253
-rw-r--r--chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.cc118
-rw-r--r--chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.h90
-rw-r--r--chromium/components/offline_pages/core/prefetch/page_bundle_update_task.cc200
-rw-r--r--chromium/components/offline_pages/core/prefetch/page_bundle_update_task.h68
-rw-r--r--chromium/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc250
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_background_task_handler.h37
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_configuration.cc15
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_configuration.h29
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h51
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc206
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h45
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc105
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader.cc113
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader.h85
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc184
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h89
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc (renamed from chromium/components/offline_pages/core/prefetch/prefetch_downloader_unittest.cc)173
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_importer.cc18
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_importer.h30
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_item.cc52
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_item.h35
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_item_unittest.cc136
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory.h24
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc71
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h32
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc122
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc4
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.h2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service.h4
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc42
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_impl.h14
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc64
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h10
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_types.cc19
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_types.h107
-rw-r--r--chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.cc131
-rw-r--r--chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h42
-rw-r--r--chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc173
-rw-r--r--chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc186
-rw-r--r--chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.h62
-rw-r--r--chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc365
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/README.md149
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.cc87
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h49
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota_unittest.cc114
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc71
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store.h15
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc246
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h60
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc68
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.cc9
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.h18
-rw-r--r--chromium/components/offline_pages/core/prefetch/suggested_articles_observer.cc9
-rw-r--r--chromium/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc10
-rw-r--r--chromium/components/offline_pages/core/prefetch/task_test_base.cc73
-rw-r--r--chromium/components/offline_pages/core/prefetch/task_test_base.h28
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc21
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h12
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.cc43
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.h49
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_importer.h11
-rw-r--r--chromium/components/offline_pages/core/renovations/BUILD.gn43
-rw-r--r--chromium/components/offline_pages/core/renovations/DEPS4
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovation.h29
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovation_loader.cc108
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovation_loader.h59
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovation_loader_unittest.cc76
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovator.cc55
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovator.h51
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc89
-rw-r--r--chromium/components/offline_pages/core/renovations/script_injector.h33
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.cc56
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.h18
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller_unittest.cc5
-rw-r--r--chromium/components/offline_pages/core/stub_offline_page_model.cc3
-rw-r--r--chromium/components/offline_pages/core/stub_offline_page_model.h3
-rw-r--r--chromium/components/offline_pages/core/task_queue.cc18
-rw-r--r--chromium/components/offline_pages/core/task_queue.h15
-rw-r--r--chromium/components/offline_pages/core/task_queue_unittest.cc27
-rw-r--r--chromium/components/offline_pages/resources/PRESUBMIT.py11
-rw-r--r--chromium/components/offline_pages/resources/compiled_resources2.gyp11
-rw-r--r--chromium/components/offline_pages/resources/renovations.js48
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn3
-rw-r--r--chromium/components/os_crypt/BUILD.gn3
-rw-r--r--chromium/components/os_crypt/os_crypt.h5
-rw-r--r--chromium/components/os_crypt/os_crypt_linux.cc44
-rw-r--r--chromium/components/os_crypt/os_crypt_linux_unittest.cc30
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker.cc4
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker.h2
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker_linux.cc36
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker_linux.h10
-rw-r--r--chromium/components/os_crypt/os_crypt_unittest.cc13
-rw-r--r--chromium/components/page_info_strings.grdp32
-rw-r--r--chromium/components/pairing/message_buffer.h6
-rw-r--r--chromium/components/password_manager/content/browser/BUILD.gn5
-rw-r--r--chromium/components/password_manager/content/browser/bad_message.h1
-rw-r--r--chromium/components/password_manager/content/browser/content_credential_manager.cc62
-rw-r--r--chromium/components/password_manager/content/browser/content_credential_manager.h49
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc27
-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_unittest.cc25
-rw-r--r--chromium/components/password_manager/content/common/credential_manager.typemap1
-rw-r--r--chromium/components/password_manager/content/common/credential_manager_struct_traits.cc47
-rw-r--r--chromium/components/password_manager/content/common/credential_manager_struct_traits.h9
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client.cc20
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc9
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn5
-rw-r--r--chromium/components/password_manager/core/browser/DEPS3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc (renamed from chromium/components/password_manager/content/browser/credential_manager_impl.cc)188
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.h (renamed from chromium/components/password_manager/content/browser/credential_manager_impl.h)99
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc (renamed from chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc)151
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc5
-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_password_form_manager_unittest.cc14
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc14
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc14
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc17
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios.cc2
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios_unittest.cc1
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc19
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.cc13
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h15
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.cc136
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.h21
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc464
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc87
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h29
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc243
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc172
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.h67
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc98
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc201
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h16
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h31
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_driver.h11
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h16
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc13
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h26
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc39
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.h24
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc231
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc29
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.h10
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector.cc96
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector.h34
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h18
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc140
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc114
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h124
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default.cc40
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default.h24
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default_unittest.cc51
-rw-r--r--chromium/components/password_manager/core/browser/password_store_origin_unittest.h16
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc354
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service.cc7
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc43
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc2
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc12
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h12
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_driver.cc2
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_driver.h1
-rw-r--r--chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.cc12
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.h3
-rw-r--r--chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.cc10
-rw-r--r--chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.h12
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.h8
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc21
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h3
-rw-r--r--chromium/components/payments/android/payment_manifest_web_data_service.cc4
-rw-r--r--chromium/components/payments/android/payment_manifest_web_data_service.h2
-rw-r--r--chromium/components/payments/content/BUILD.gn14
-rw-r--r--chromium/components/payments/content/DEPS4
-rw-r--r--chromium/components/payments/content/android/payment_manifest_downloader_android.h2
-rw-r--r--chromium/components/payments/content/android/payment_manifest_parser_android.cc34
-rw-r--r--chromium/components/payments/content/payment_details_validation.cc8
-rw-r--r--chromium/components/payments/content/payment_manifest_parser_host.cc8
-rw-r--r--chromium/components/payments/content/payment_request.cc43
-rw-r--r--chromium/components/payments/content/payment_request.h6
-rw-r--r--chromium/components/payments/content/payment_request_spec.cc12
-rw-r--r--chromium/components/payments/content/payment_request_spec.h10
-rw-r--r--chromium/components/payments/content/payment_request_state_unittest.cc58
-rw-r--r--chromium/components/payments/content/payment_response_helper.cc52
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc8
-rw-r--r--chromium/components/payments/core/BUILD.gn210
-rw-r--r--chromium/components/payments/core/DEPS4
-rw-r--r--chromium/components/payments/core/address_normalizer_impl_unittest.cc9
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument.cc12
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument.h9
-rw-r--r--chromium/components/payments/core/autofill_payment_instrument_unittest.cc36
-rw-r--r--chromium/components/payments/core/can_make_payment_query.cc18
-rw-r--r--chromium/components/payments/core/can_make_payment_query.h43
-rw-r--r--chromium/components/payments/core/can_make_payment_query_unittest.cc66
-rw-r--r--chromium/components/payments/core/currency_formatter_unittest.cc2
-rw-r--r--chromium/components/payments/core/features.cc10
-rw-r--r--chromium/components/payments/core/features.h8
-rw-r--r--chromium/components/payments/core/journey_logger.cc191
-rw-r--r--chromium/components/payments/core/journey_logger.h126
-rw-r--r--chromium/components/payments/core/journey_logger_unittest.cc713
-rw-r--r--chromium/components/payments/core/payment_address.h2
-rw-r--r--chromium/components/payments/core/payment_address_unittest.cc2
-rw-r--r--chromium/components/payments/core/payment_currency_amount.cc71
-rw-r--r--chromium/components/payments/core/payment_currency_amount.h53
-rw-r--r--chromium/components/payments/core/payment_currency_amount_unittest.cc106
-rw-r--r--chromium/components/payments/core/payment_details.cc115
-rw-r--r--chromium/components/payments/core/payment_details.h69
-rw-r--r--chromium/components/payments/core/payment_details_modifier.cc76
-rw-r--r--chromium/components/payments/core/payment_details_modifier.h61
-rw-r--r--chromium/components/payments/core/payment_details_modifier_unittest.cc120
-rw-r--r--chromium/components/payments/core/payment_details_unittest.cc136
-rw-r--r--chromium/components/payments/core/payment_instrument.h5
-rw-r--r--chromium/components/payments/core/payment_item.cc64
-rw-r--r--chromium/components/payments/core/payment_item.h55
-rw-r--r--chromium/components/payments/core/payment_item_unittest.cc121
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.cc (renamed from chromium/components/payments/content/payment_manifest_downloader.cc)7
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.h (renamed from chromium/components/payments/content/payment_manifest_downloader.h)6
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader_unittest.cc (renamed from chromium/components/payments/content/payment_manifest_downloader_unittest.cc)8
-rw-r--r--chromium/components/payments/core/payment_method_data.cc26
-rw-r--r--chromium/components/payments/core/payment_method_data_unittest.cc58
-rw-r--r--chromium/components/payments/core/payment_request_data_util.cc24
-rw-r--r--chromium/components/payments/core/payment_request_data_util.h3
-rw-r--r--chromium/components/payments/core/payment_shipping_option.cc62
-rw-r--r--chromium/components/payments/core/payment_shipping_option.h54
-rw-r--r--chromium/components/payments/core/payment_shipping_option_unittest.cc110
-rw-r--r--chromium/components/payments/core/payments_profile_comparator.cc46
-rw-r--r--chromium/components/payments/core/payments_profile_comparator.h13
-rw-r--r--chromium/components/payments/core/payments_profile_comparator_unittest.cc29
-rw-r--r--chromium/components/payments/core/payments_validators.cc (renamed from chromium/components/payments/content/payments_validators.cc)55
-rw-r--r--chromium/components/payments/core/payments_validators.h (renamed from chromium/components/payments/content/payments_validators.h)30
-rw-r--r--chromium/components/payments/core/payments_validators_unittest.cc (renamed from chromium/components/payments/content/payments_validators_unittest.cc)216
-rw-r--r--chromium/components/payments/core/subkey_requester_unittest.cc7
-rw-r--r--chromium/components/payments/core/test_payment_request_delegate.cc47
-rw-r--r--chromium/components/payments/core/test_payment_request_delegate.h43
-rw-r--r--chromium/components/payments_strings.grdp392
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.cc39
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.h11
-rw-r--r--chromium/components/pdf/common/BUILD.gn2
-rw-r--r--chromium/components/pdf/common/pdf.mojom20
-rw-r--r--chromium/components/pdf/renderer/DEPS1
-rw-r--r--chromium/components/pdf/renderer/OWNERS4
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.cc50
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.h16
-rw-r--r--chromium/components/plugins/renderer/DEPS1
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.cc31
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.h6
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc21
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.h5
-rw-r--r--chromium/components/policy/BUILD.gn29
-rw-r--r--chromium/components/policy/core/common/BUILD.gn1
-rw-r--r--chromium/components/policy_strings.grdp3
-rw-r--r--chromium/components/pref_registry/pref_registry_syncable.cc2
-rw-r--r--chromium/components/prefs/in_memory_pref_store.h1
-rw-r--r--chromium/components/prefs/in_memory_pref_store_unittest.cc2
-rw-r--r--chromium/components/prefs/json_pref_store.cc5
-rw-r--r--chromium/components/prefs/json_pref_store.h2
-rw-r--r--chromium/components/prefs/json_pref_store_unittest.cc16
-rw-r--r--chromium/components/prefs/overlay_user_pref_store.cc8
-rw-r--r--chromium/components/prefs/overlay_user_pref_store.h1
-rw-r--r--chromium/components/prefs/overlay_user_pref_store_unittest.cc4
-rw-r--r--chromium/components/prefs/persistent_pref_store.h3
-rw-r--r--chromium/components/prefs/persistent_pref_store_unittest.cc6
-rw-r--r--chromium/components/prefs/persistent_pref_store_unittest.h15
-rw-r--r--chromium/components/prefs/pref_filter.h3
-rw-r--r--chromium/components/prefs/pref_member.cc18
-rw-r--r--chromium/components/prefs/pref_member.h2
-rw-r--r--chromium/components/prefs/pref_notifier_impl.h3
-rw-r--r--chromium/components/prefs/pref_service.cc12
-rw-r--r--chromium/components/prefs/pref_service.h8
-rw-r--r--chromium/components/prefs/pref_value_store.cc9
-rw-r--r--chromium/components/prefs/pref_value_store.h2
-rw-r--r--chromium/components/prefs/testing_pref_store.cc2
-rw-r--r--chromium/components/prefs/testing_pref_store.h1
-rw-r--r--chromium/components/previews/core/previews_experiments.cc41
-rw-r--r--chromium/components/previews/core/previews_experiments_unittest.cc27
-rw-r--r--chromium/components/previews/core/previews_features.cc4
-rw-r--r--chromium/components/previews/core/previews_io_data_unittest.cc56
-rw-r--r--chromium/components/printing/DEPS4
-rw-r--r--chromium/components/printing/browser/DEPS3
-rw-r--r--chromium/components/printing/browser/print_manager_utils.cc1
-rw-r--r--chromium/components/printing/common/BUILD.gn1
-rw-r--r--chromium/components/printing/common/print_messages.cc4
-rw-r--r--chromium/components/printing/common/print_messages.h7
-rw-r--r--chromium/components/printing/renderer/BUILD.gn12
-rw-r--r--chromium/components/printing/renderer/DEPS2
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.cc (renamed from chromium/components/printing/renderer/print_web_view_helper.cc)382
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.h (renamed from chromium/components/printing/renderer/print_web_view_helper.h)84
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_android.cc (renamed from chromium/components/printing/renderer/print_web_view_helper_android.cc)4
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_linux.cc (renamed from chromium/components/printing/renderer/print_web_view_helper_linux.cc)18
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_mac.mm (renamed from chromium/components/printing/renderer/print_web_view_helper_mac.mm)46
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_pdf_win.cc (renamed from chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc)12
-rw-r--r--chromium/components/printing/service/BUILD.gn47
-rw-r--r--chromium/components/printing/service/DEPS7
-rw-r--r--chromium/components/printing/service/OWNERS5
-rw-r--r--chromium/components/printing/service/pdf_compositor_impl.cc12
-rw-r--r--chromium/components/printing/service/pdf_compositor_manifest.json4
-rw-r--r--chromium/components/printing/service/pdf_compositor_service.cc6
-rw-r--r--chromium/components/printing/service/pdf_compositor_service.h2
-rw-r--r--chromium/components/printing/service/pdf_compositor_service_unittest.cc136
-rw-r--r--chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json17
-rw-r--r--chromium/components/printing/service/public/cpp/pdf_compositor_client.cc3
-rw-r--r--chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc2
-rw-r--r--chromium/components/printing/service/public/interfaces/pdf_compositor.mojom13
-rw-r--r--chromium/components/printing/service/test_service_main.cc33
-rw-r--r--chromium/components/rappor/log_uploader.cc2
-rw-r--r--chromium/components/reading_list/core/reading_list_model_impl.cc7
-rw-r--r--chromium/components/reading_list/core/reading_list_model_unittest.cc29
-rw-r--r--chromium/components/reading_list/ios/reading_list_model_bridge_observer.h1
-rw-r--r--chromium/components/resources/OWNERS1
-rw-r--r--chromium/components/resources/components_resources.grd1
-rw-r--r--chromium/components/resources/default_100_percent/autofill/cc-generic.pngbin175 -> 242 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/cc-generic.pngbin190 -> 368 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/amex.pngbin0 -> 2664 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/cc-generic.pngbin0 -> 645 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/diners.pngbin0 -> 4396 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/discover.pngbin0 -> 3026 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/jcb.pngbin0 -> 4594 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/mastercard.pngbin0 -> 2907 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/mir.pngbin0 -> 1975 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/unionpay.pngbin0 -> 4117 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/visa.pngbin0 -> 2788 bytes
-rw-r--r--chromium/components/resources/offline_pages_resources.grdp4
-rw-r--r--chromium/components/resources/sync_driver_resources.grdp1
-rw-r--r--chromium/components/safe_browsing/BUILD.gn11
-rw-r--r--chromium/components/safe_browsing/android/BUILD.gn (renamed from chromium/components/safe_browsing_db/android/BUILD.gn)3
-rw-r--r--chromium/components/safe_browsing/android/DEPS3
-rw-r--r--chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc (renamed from chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc)9
-rw-r--r--chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h (renamed from chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.h)10
-rw-r--r--chromium/components/safe_browsing/base_ping_manager.cc5
-rw-r--r--chromium/components/safe_browsing/base_resource_throttle.cc129
-rw-r--r--chromium/components/safe_browsing/base_resource_throttle.h23
-rw-r--r--chromium/components/safe_browsing/base_ui_manager.cc21
-rw-r--r--chromium/components/safe_browsing/base_ui_manager.h17
-rw-r--r--chromium/components/safe_browsing/browser/BUILD.gn3
-rw-r--r--chromium/components/safe_browsing/browser/DEPS2
-rw-r--r--chromium/components/safe_browsing/browser/base_parallel_resource_throttle.cc87
-rw-r--r--chromium/components/safe_browsing/browser/base_parallel_resource_throttle.h77
-rw-r--r--chromium/components/safe_browsing/browser/browser_url_loader_throttle.cc67
-rw-r--r--chromium/components/safe_browsing/browser/browser_url_loader_throttle.h19
-rw-r--r--chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.cc31
-rw-r--r--chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.h3
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc188
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.h50
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_url_request_context_getter.cc2
-rw-r--r--chromium/components/safe_browsing/browser/threat_details.cc136
-rw-r--r--chromium/components/safe_browsing/browser/threat_details.h21
-rw-r--r--chromium/components/safe_browsing/browser/threat_details_cache.cc2
-rw-r--r--chromium/components/safe_browsing/browser/url_checker_delegate.h23
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing.mojom29
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing_prefs.cc4
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing_prefs.h6
-rw-r--r--chromium/components/safe_browsing/common/utils.cc5
-rw-r--r--chromium/components/safe_browsing/common/utils.h10
-rw-r--r--chromium/components/safe_browsing/db/BUILD.gn91
-rw-r--r--chromium/components/safe_browsing/db/DEPS10
-rw-r--r--chromium/components/safe_browsing/db/remote_database_manager.cc (renamed from chromium/components/safe_browsing_db/remote_database_manager.cc)9
-rw-r--r--chromium/components/safe_browsing/db/remote_database_manager.h (renamed from chromium/components/safe_browsing_db/remote_database_manager.h)0
-rw-r--r--chromium/components/safe_browsing/db/remote_database_manager_unittest.cc (renamed from chromium/components/safe_browsing_db/remote_database_manager_unittest.cc)4
-rw-r--r--chromium/components/safe_browsing/db/safe_browsing_api_handler.cc (renamed from chromium/components/safe_browsing_db/safe_browsing_api_handler.cc)2
-rw-r--r--chromium/components/safe_browsing/db/safe_browsing_api_handler.h (renamed from chromium/components/safe_browsing_db/safe_browsing_api_handler.h)2
-rw-r--r--chromium/components/safe_browsing/db/safe_browsing_api_handler_unittest.cc (renamed from chromium/components/safe_browsing_db/safe_browsing_api_handler_unittest.cc)45
-rw-r--r--chromium/components/safe_browsing/db/safe_browsing_api_handler_util.cc (renamed from chromium/components/safe_browsing_db/safe_browsing_api_handler_util.cc)57
-rw-r--r--chromium/components/safe_browsing/db/safe_browsing_api_handler_util.h (renamed from chromium/components/safe_browsing_db/safe_browsing_api_handler_util.h)0
-rw-r--r--chromium/components/safe_browsing/features.cc42
-rw-r--r--chromium/components/safe_browsing/features.h21
-rw-r--r--chromium/components/safe_browsing/net_event_logger.cc75
-rw-r--r--chromium/components/safe_browsing/net_event_logger.h40
-rw-r--r--chromium/components/safe_browsing/password_protection/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.cc76
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.h20
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.cc145
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.h112
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc235
-rw-r--r--chromium/components/safe_browsing/proto/csd.proto (renamed from chromium/components/safe_browsing/csd.proto)20
-rw-r--r--chromium/components/safe_browsing/proto/webui.proto106
-rw-r--r--chromium/components/safe_browsing/renderer/BUILD.gn8
-rw-r--r--chromium/components/safe_browsing/renderer/DEPS3
-rw-r--r--chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.cc117
-rw-r--r--chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.h56
-rw-r--r--chromium/components/safe_browsing/renderer/threat_dom_details.cc8
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc32
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h4
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc29
-rw-r--r--chromium/components/safe_browsing/triggers/BUILD.gn10
-rw-r--r--chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc68
-rw-r--r--chromium/components/safe_browsing/triggers/ad_sampler_trigger.h37
-rw-r--r--chromium/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc193
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager.cc97
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager.h20
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc190
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler.cc105
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler.h27
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc147
-rw-r--r--chromium/components/safe_browsing/web_ui/BUILD.gn4
-rw-r--r--chromium/components/safe_browsing/web_ui/DEPS3
-rw-r--r--chromium/components/safe_browsing/web_ui/resources/safe_browsing.css6
-rw-r--r--chromium/components/safe_browsing/web_ui/resources/safe_browsing.html18
-rw-r--r--chromium/components/safe_browsing/web_ui/resources/safe_browsing.js32
-rw-r--r--chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc224
-rw-r--r--chromium/components/safe_browsing/web_ui/safe_browsing_ui.h4
-rw-r--r--chromium/components/safe_browsing_db/BUILD.gn95
-rw-r--r--chromium/components/safe_browsing_db/DEPS4
-rw-r--r--chromium/components/safe_browsing_db/metadata.proto1
-rw-r--r--chromium/components/safe_browsing_db/notification_types.h30
-rw-r--r--chromium/components/safe_browsing_db/util.h13
-rw-r--r--chromium/components/safe_browsing_db/v4_database.cc16
-rw-r--r--chromium/components/safe_browsing_db/v4_database.h4
-rw-r--r--chromium/components/safe_browsing_db/v4_feature_list.cc23
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc57
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h11
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc53
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager.cc58
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager.h30
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc45
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util.h6
-rw-r--r--chromium/components/safe_browsing_db/v4_store.cc25
-rw-r--r--chromium/components/safe_browsing_db/v4_store.h15
-rw-r--r--chromium/components/safe_browsing_db/v4_update_protocol_manager.cc21
-rw-r--r--chromium/components/safe_browsing_db/v4_update_protocol_manager.h7
-rw-r--r--chromium/components/safe_json/json_sanitizer_android.cc15
-rw-r--r--chromium/components/search/OWNERS1
-rw-r--r--chromium/components/search/search.cc99
-rw-r--r--chromium/components/search/search.h28
-rw-r--r--chromium/components/search/search_android_unittest.cc3
-rw-r--r--chromium/components/search/search_unittest.cc143
-rw-r--r--chromium/components/search_engines/default_search_manager.cc1
-rw-r--r--chromium/components/search_engines/default_search_manager.h1
-rw-r--r--chromium/components/search_engines/default_search_manager_unittest.cc2
-rw-r--r--chromium/components/search_engines/default_search_policy_handler.cc5
-rw-r--r--chromium/components/search_engines/keyword_web_data_service.cc6
-rw-r--r--chromium/components/search_engines/keyword_web_data_service.h13
-rw-r--r--chromium/components/search_engines/prepopulated_engines.json2
-rw-r--r--chromium/components/search_engines/prepopulated_engines_schema.json4
-rw-r--r--chromium/components/search_engines/search_terms_data.cc4
-rw-r--r--chromium/components/search_engines/search_terms_data.h4
-rw-r--r--chromium/components/search_engines/template_url.cc9
-rw-r--r--chromium/components/search_engines/template_url.h5
-rw-r--r--chromium/components/search_engines/template_url_data.cc26
-rw-r--r--chromium/components/search_engines/template_url_data.h4
-rw-r--r--chromium/components/search_engines/template_url_data_util.cc16
-rw-r--r--chromium/components/search_engines/template_url_fetcher.cc2
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.cc582
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data_unittest.cc6
-rw-r--r--chromium/components/search_engines/template_url_service.cc13
-rw-r--r--chromium/components/search_engines/template_url_service_client.h5
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc16
-rw-r--r--chromium/components/search_provider_logos/BUILD.gn47
-rw-r--r--chromium/components/search_provider_logos/DEPS3
-rw-r--r--chromium/components/search_provider_logos/OWNERS2
-rw-r--r--chromium/components/search_provider_logos/features.cc8
-rw-r--r--chromium/components/search_provider_logos/features.h14
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.cc38
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.h6
-rw-r--r--chromium/components/search_provider_logos/google_logo_api_unittest.cc106
-rw-r--r--chromium/components/search_provider_logos/logo_cache.cc18
-rw-r--r--chromium/components/search_provider_logos/logo_cache_unittest.cc12
-rw-r--r--chromium/components/search_provider_logos/logo_common.h9
-rw-r--r--chromium/components/search_provider_logos/logo_service.cc207
-rw-r--r--chromium/components/search_provider_logos/logo_service.h68
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.cc14
-rw-r--r--chromium/components/search_provider_logos/logo_tracker_unittest.cc37
-rw-r--r--chromium/components/search_provider_logos/switches.cc8
-rw-r--r--chromium/components/search_provider_logos/switches.h3
-rw-r--r--chromium/components/security_interstitials/content/unsafe_resource.cc21
-rw-r--r--chromium/components/security_interstitials/core/BUILD.gn9
-rw-r--r--chromium/components/security_interstitials/core/base_safe_browsing_error_ui.h10
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/list_of_interstitials.html6
-rw-r--r--chromium/components/security_interstitials/core/mitm_software_ui.cc137
-rw-r--r--chromium/components/security_interstitials/core/mitm_software_ui.h49
-rw-r--r--chromium/components/security_interstitials_strings.grdp69
-rw-r--r--chromium/components/security_state/content/BUILD.gn3
-rw-r--r--chromium/components/security_state/content/content_utils.cc107
-rw-r--r--chromium/components/security_state/content/content_utils_browsertest.cc41
-rw-r--r--chromium/components/security_state/content/content_utils_unittest.cc259
-rw-r--r--chromium/components/security_state/content/ssl_status_input_event_data.cc29
-rw-r--r--chromium/components/security_state/content/ssl_status_input_event_data.h38
-rw-r--r--chromium/components/security_state/core/BUILD.gn1
-rw-r--r--chromium/components/security_state/core/insecure_input_event_data.h22
-rw-r--r--chromium/components/security_state/core/security_state.cc112
-rw-r--r--chromium/components/security_state/core/security_state.h24
-rw-r--r--chromium/components/security_state/core/security_state_ui.cc1
-rw-r--r--chromium/components/security_state/core/security_state_unittest.cc114
-rw-r--r--chromium/components/security_state_strings.grdp44
-rw-r--r--chromium/components/session_manager/session_manager_types.h6
-rw-r--r--chromium/components/sessions/core/base_session_service.cc45
-rw-r--r--chromium/components/sessions/core/base_session_service.h16
-rw-r--r--chromium/components/sessions/core/base_session_service_delegate.h11
-rw-r--r--chromium/components/sessions/core/live_tab_context.h8
-rw-r--r--chromium/components/sessions/core/persistent_tab_restore_service.cc312
-rw-r--r--chromium/components/sessions/core/tab_restore_service.h7
-rw-r--r--chromium/components/sessions/core/tab_restore_service_client.h16
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.cc25
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn7
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc17
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc4
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn12
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_android.cc2
-rw-r--r--chromium/components/signin/core/browser/chrome_connected_header_helper.cc5
-rw-r--r--chromium/components/signin/core/browser/dice_header_helper.cc14
-rw-r--r--chromium/components/signin/core/browser/dice_header_helper.h7
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.cc12
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.h4
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches_unittest.cc59
-rw-r--r--chromium/components/signin/core/browser/resources/signin_index.css10
-rw-r--r--chromium/components/signin/core/browser/resources/signin_index.html14
-rw-r--r--chromium/components/signin/core/browser/resources/signin_internals.js37
-rw-r--r--chromium/components/signin/core/browser/scoped_account_consistency.cc63
-rw-r--r--chromium/components/signin/core/browser/scoped_account_consistency.h56
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.cc10
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.h4
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc106
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc22
-rw-r--r--chromium/components/signin/core/browser/signin_manager.h7
-rw-r--r--chromium/components/signin/core/browser/signin_manager_base.cc6
-rw-r--r--chromium/components/signin/core/browser/signin_manager_base.h6
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.h6
-rw-r--r--chromium/components/signin/core/browser/signin_status_metrics_provider.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_status_metrics_provider.h2
-rw-r--r--chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc2
-rw-r--r--chromium/components/signin/core/browser/webdata/token_web_data.cc23
-rw-r--r--chromium/components/signin/core/browser/webdata/token_web_data.h8
-rw-r--r--chromium/components/signin/core/common/profile_management_switches.cc57
-rw-r--r--chromium/components/signin/core/common/profile_management_switches.h42
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.h4
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.mm8
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service_unittest.mm17
-rw-r--r--chromium/components/spellcheck/browser/BUILD.gn4
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc13
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h21
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc29
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc3
-rw-r--r--chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc5
-rw-r--r--chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h1
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.cc2
-rw-r--r--chromium/components/spellcheck/common/BUILD.gn2
-rw-r--r--chromium/components/spellcheck/common/OWNERS2
-rw-r--r--chromium/components/spellcheck/common/spellcheck.mojom13
-rw-r--r--chromium/components/spellcheck/common/spellcheck.typemap7
-rw-r--r--chromium/components/spellcheck/common/spellcheck_struct_traits.cc50
-rw-r--r--chromium/components/spellcheck/common/spellcheck_struct_traits.h47
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_panel.cc8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_panel.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h5
-rw-r--r--chromium/components/storage_monitor/image_capture_device.mm16
-rw-r--r--chromium/components/storage_monitor/image_capture_device_manager_unittest.mm15
-rw-r--r--chromium/components/storage_monitor/media_storage_util.cc29
-rw-r--r--chromium/components/storage_monitor/media_storage_util_unittest.cc67
-rw-r--r--chromium/components/storage_monitor/portable_device_watcher_win.cc2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.cc57
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.h3
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc48
-rw-r--r--chromium/components/storage_monitor/storage_monitor_mac.h6
-rw-r--r--chromium/components/storage_monitor/storage_monitor_mac.mm49
-rw-r--r--chromium/components/storage_monitor/storage_monitor_mac_unittest.mm7
-rw-r--r--chromium/components/strings/components_google_chrome_strings_pt-PT.xtb2
-rw-r--r--chromium/components/strings/components_strings_am.xtb79
-rw-r--r--chromium/components/strings/components_strings_ar.xtb79
-rw-r--r--chromium/components/strings/components_strings_bg.xtb79
-rw-r--r--chromium/components/strings/components_strings_bn.xtb81
-rw-r--r--chromium/components/strings/components_strings_ca.xtb81
-rw-r--r--chromium/components/strings/components_strings_cs.xtb79
-rw-r--r--chromium/components/strings/components_strings_da.xtb81
-rw-r--r--chromium/components/strings/components_strings_de.xtb81
-rw-r--r--chromium/components/strings/components_strings_el.xtb79
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb79
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb79
-rw-r--r--chromium/components/strings/components_strings_es.xtb79
-rw-r--r--chromium/components/strings/components_strings_et.xtb79
-rw-r--r--chromium/components/strings/components_strings_fa.xtb79
-rw-r--r--chromium/components/strings/components_strings_fi.xtb80
-rw-r--r--chromium/components/strings/components_strings_fil.xtb79
-rw-r--r--chromium/components/strings/components_strings_fr.xtb79
-rw-r--r--chromium/components/strings/components_strings_gu.xtb85
-rw-r--r--chromium/components/strings/components_strings_hi.xtb81
-rw-r--r--chromium/components/strings/components_strings_hr.xtb79
-rw-r--r--chromium/components/strings/components_strings_hu.xtb79
-rw-r--r--chromium/components/strings/components_strings_id.xtb129
-rw-r--r--chromium/components/strings/components_strings_it.xtb79
-rw-r--r--chromium/components/strings/components_strings_iw.xtb79
-rw-r--r--chromium/components/strings/components_strings_ja.xtb79
-rw-r--r--chromium/components/strings/components_strings_kn.xtb75
-rw-r--r--chromium/components/strings/components_strings_ko.xtb79
-rw-r--r--chromium/components/strings/components_strings_lt.xtb79
-rw-r--r--chromium/components/strings/components_strings_lv.xtb79
-rw-r--r--chromium/components/strings/components_strings_ml.xtb79
-rw-r--r--chromium/components/strings/components_strings_mr.xtb81
-rw-r--r--chromium/components/strings/components_strings_ms.xtb79
-rw-r--r--chromium/components/strings/components_strings_nl.xtb79
-rw-r--r--chromium/components/strings/components_strings_no.xtb79
-rw-r--r--chromium/components/strings/components_strings_pl.xtb83
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb81
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb83
-rw-r--r--chromium/components/strings/components_strings_ro.xtb79
-rw-r--r--chromium/components/strings/components_strings_ru.xtb79
-rw-r--r--chromium/components/strings/components_strings_sk.xtb79
-rw-r--r--chromium/components/strings/components_strings_sl.xtb79
-rw-r--r--chromium/components/strings/components_strings_sr.xtb79
-rw-r--r--chromium/components/strings/components_strings_sv.xtb79
-rw-r--r--chromium/components/strings/components_strings_sw.xtb81
-rw-r--r--chromium/components/strings/components_strings_ta.xtb79
-rw-r--r--chromium/components/strings/components_strings_te.xtb79
-rw-r--r--chromium/components/strings/components_strings_th.xtb79
-rw-r--r--chromium/components/strings/components_strings_tr.xtb79
-rw-r--r--chromium/components/strings/components_strings_uk.xtb81
-rw-r--r--chromium/components/strings/components_strings_vi.xtb79
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb79
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb79
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc7
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h9
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc19
-rw-r--r--chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc17
-rw-r--r--chromium/components/subresource_filter/content/browser/content_activation_list_utils.h2
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc77
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h39
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc121
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h17
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc47
-rw-r--r--chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc13
-rw-r--r--chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h5
-rw-r--r--chromium/components/subresource_filter/content/browser/page_load_statistics.cc18
-rw-r--r--chromium/components/subresource_filter/content/browser/page_load_statistics.h13
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc8
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_client.h26
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc37
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h18
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc178
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h13
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc214
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc4
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h7
-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/verified_ruleset_dealer.cc3
-rw-r--r--chromium/components/subresource_filter/content/common/BUILD.gn2
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_messages.h13
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_utils.cc26
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_utils.h19
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc87
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h15
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_constants.h4
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.cc47
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.h20
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc20
-rw-r--r--chromium/components/subresource_filter/core/common/activation_list.cc9
-rw-r--r--chromium/components/subresource_filter/core/common/activation_list.h17
-rw-r--r--chromium/components/subresource_filter/core/common/document_subresource_filter.cc4
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.cc6
-rw-r--r--chromium/components/suggestions/image_manager.cc2
-rw-r--r--chromium/components/suggestions/suggestions_service_impl.cc2
-rw-r--r--chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js1
-rw-r--r--chromium/components/sync/BUILD.gn11
-rw-r--r--chromium/components/sync/android/BUILD.gn2
-rw-r--r--chromium/components/sync_bookmarks/BUILD.gn7
-rw-r--r--chromium/components/sync_bookmarks/bookmark_data_type_controller.h1
-rw-r--r--chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc11
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_associator.cc3
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_controller.cc169
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_controller.h69
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_controller_unittest.cc244
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.cc61
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.h47
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc21
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.cc77
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.h5
-rw-r--r--chromium/components/sync_preferences/pref_model_associator_unittest.cc2
-rw-r--r--chromium/components/sync_sessions/favicon_cache_unittest.cc4
-rw-r--r--chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc3
-rw-r--r--chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc11
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc51
-rw-r--r--chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc5
-rw-r--r--chromium/components/sync_sessions/session_data_type_controller_unittest.cc11
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.cc112
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.h19
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager_unittest.cc117
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc7
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.cc7
-rw-r--r--chromium/components/sync_sessions/task_tracker.cc4
-rw-r--r--chromium/components/task_scheduler_util/common/variations_util.cc5
-rw-r--r--chromium/components/task_scheduler_util/common/variations_util_unittest.cc93
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.cc5
-rw-r--r--chromium/components/tracing/BUILD.gn8
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter.cc8
-rw-r--r--chromium/components/tracing/common/DEPS7
-rw-r--r--chromium/components/tracing/common/graphics_memory_dump_provider_android.cc1
-rw-r--r--chromium/components/tracing/common/process_metrics_memory_dump_provider.cc29
-rw-r--r--chromium/components/tracing/common/process_metrics_memory_dump_provider.h33
-rw-r--r--chromium/components/translate/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/ui_devtools/BUILD.gn2
-rw-r--r--chromium/components/ui_devtools/devtools_server.h3
-rw-r--r--chromium/components/ui_devtools/protocol.json357
-rw-r--r--chromium/components/ui_devtools/string_util.cc11
-rw-r--r--chromium/components/ui_devtools/string_util.h2
-rw-r--r--chromium/components/ui_devtools/views/BUILD.gn3
-rw-r--r--chromium/components/ui_devtools/views/DEPS2
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_css_agent.cc69
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_css_agent.h22
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_dom_agent.cc424
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_dom_agent.h72
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_overlay_agent.cc92
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_overlay_agent.h45
-rw-r--r--chromium/components/ui_devtools/views/ui_devtools_unittest.cc211
-rw-r--r--chromium/components/ui_devtools/views/ui_element.cc37
-rw-r--r--chromium/components/ui_devtools/views/ui_element.h8
-rw-r--r--chromium/components/ui_devtools/views/view_element.cc15
-rw-r--r--chromium/components/ui_devtools/views/view_element.h4
-rw-r--r--chromium/components/ui_devtools/views/widget_element.cc9
-rw-r--r--chromium/components/ui_devtools/views/widget_element.h4
-rw-r--r--chromium/components/ui_devtools/views/window_element.cc9
-rw-r--r--chromium/components/ui_devtools/views/window_element.h4
-rw-r--r--chromium/components/ukm/BUILD.gn2
-rw-r--r--chromium/components/ukm/debug_page/BUILD.gn1
-rw-r--r--chromium/components/ukm/debug_page/debug_page.cc49
-rw-r--r--chromium/components/ukm/ukm_interface.cc22
-rw-r--r--chromium/components/ukm/ukm_service.cc37
-rw-r--r--chromium/components/ukm/ukm_service.h6
-rw-r--r--chromium/components/ukm/ukm_service_unittest.cc38
-rw-r--r--chromium/components/ukm/ukm_source.cc17
-rw-r--r--chromium/components/ukm/ukm_source.h19
-rw-r--r--chromium/components/update_client/BUILD.gn1
-rw-r--r--chromium/components/update_client/action_runner.cc34
-rw-r--r--chromium/components/update_client/action_runner.h6
-rw-r--r--chromium/components/update_client/action_runner_win.cc13
-rw-r--r--chromium/components/update_client/background_downloader_win.cc40
-rw-r--r--chromium/components/update_client/background_downloader_win.h8
-rw-r--r--chromium/components/update_client/component.cc87
-rw-r--r--chromium/components/update_client/component_patcher.cc21
-rw-r--r--chromium/components/update_client/component_patcher.h5
-rw-r--r--chromium/components/update_client/component_patcher_operation.cc26
-rw-r--r--chromium/components/update_client/component_patcher_operation.h7
-rw-r--r--chromium/components/update_client/component_patcher_unittest.cc29
-rw-r--r--chromium/components/update_client/component_patcher_unittest.h8
-rw-r--r--chromium/components/update_client/component_unpacker.cc30
-rw-r--r--chromium/components/update_client/component_unpacker.h12
-rw-r--r--chromium/components/update_client/component_unpacker_unittest.cc41
-rw-r--r--chromium/components/update_client/configurator.h5
-rw-r--r--chromium/components/update_client/crx_downloader.cc38
-rw-r--r--chromium/components/update_client/crx_downloader.h6
-rw-r--r--chromium/components/update_client/out_of_process_patcher.h2
-rw-r--r--chromium/components/update_client/ping_manager.cc1
-rw-r--r--chromium/components/update_client/ping_manager_unittest.cc5
-rw-r--r--chromium/components/update_client/protocol_builder.cc4
-rw-r--r--chromium/components/update_client/request_sender.cc46
-rw-r--r--chromium/components/update_client/request_sender.h6
-rw-r--r--chromium/components/update_client/request_sender_unittest.cc23
-rw-r--r--chromium/components/update_client/task_send_uninstall_ping.cc3
-rw-r--r--chromium/components/update_client/task_traits.h28
-rw-r--r--chromium/components/update_client/task_update.cc3
-rw-r--r--chromium/components/update_client/test_configurator.cc19
-rw-r--r--chromium/components/update_client/test_configurator.h14
-rw-r--r--chromium/components/update_client/update_checker.cc25
-rw-r--r--chromium/components/update_client/update_checker.h2
-rw-r--r--chromium/components/update_client/update_checker_unittest.cc22
-rw-r--r--chromium/components/update_client/update_client.cc8
-rw-r--r--chromium/components/update_client/update_client_unittest.cc187
-rw-r--r--chromium/components/update_client/update_engine.cc24
-rw-r--r--chromium/components/update_client/update_engine.h4
-rw-r--r--chromium/components/update_client/update_query_params.cc2
-rw-r--r--chromium/components/update_client/updater_state_unittest.cc6
-rw-r--r--chromium/components/update_client/url_fetcher_downloader.cc2
-rw-r--r--chromium/components/update_client/url_fetcher_downloader.h3
-rw-r--r--chromium/components/update_client/utils.cc2
-rw-r--r--chromium/components/url_formatter/OWNERS1
-rw-r--r--chromium/components/url_formatter/android/BUILD.gn5
-rw-r--r--chromium/components/url_formatter/elide_url.cc54
-rw-r--r--chromium/components/url_formatter/elide_url_unittest.cc24
-rw-r--r--chromium/components/url_formatter/idn_spoof_checker.cc5
-rw-r--r--chromium/components/url_formatter/top_domains/alexa_domains.list2
-rw-r--r--chromium/components/url_formatter/top_domains/alexa_skeletons.gperf2
-rwxr-xr-xchromium/components/url_formatter/top_domains/make_alexa_top_list.py2
-rw-r--r--chromium/components/url_formatter/url_formatter.cc13
-rw-r--r--chromium/components/url_formatter/url_formatter.h27
-rw-r--r--chromium/components/url_formatter/url_formatter_unittest.cc112
-rw-r--r--chromium/components/url_matcher/url_matcher_factory_unittest.cc2
-rw-r--r--chromium/components/url_pattern_index/flat/url_pattern_index.fbs12
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.cc14
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.h8
-rw-r--r--chromium/components/user_manager/fake_user_manager.cc2
-rw-r--r--chromium/components/user_manager/user.cc13
-rw-r--r--chromium/components/user_manager/user.h7
-rw-r--r--chromium/components/user_manager/user_manager_base.cc25
-rw-r--r--chromium/components/variations/BUILD.gn3
-rw-r--r--chromium/components/variations/android/variations_associated_data_android.cc6
-rw-r--r--chromium/components/variations/android/variations_associated_data_android.h23
-rw-r--r--chromium/components/variations/client_filterable_state.cc2
-rw-r--r--chromium/components/variations/proto/study.proto1
-rw-r--r--chromium/components/variations/service/BUILD.gn1
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.cc89
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.h40
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator_unittest.cc2
-rw-r--r--chromium/components/variations/service/variations_service.cc92
-rw-r--r--chromium/components/variations/service/variations_service.h21
-rw-r--r--chromium/components/variations/service/variations_service_unittest.cc1
-rw-r--r--chromium/components/variations/study_filtering_unittest.cc3
-rw-r--r--chromium/components/vector_icons/BUILD.gn5
-rw-r--r--chromium/components/vector_icons/README.md48
-rw-r--r--chromium/components/vector_icons/accessibility.icon25
-rw-r--r--chromium/components/vector_icons/help_outline.icon34
-rw-r--r--chromium/components/vector_icons/reload.1x.icon23
-rw-r--r--chromium/components/vector_icons/reload.icon27
-rw-r--r--chromium/components/vector_icons/usb.icon38
-rw-r--r--chromium/components/viz/BUILD.gn1
-rw-r--r--chromium/components/viz/DEPS2
-rw-r--r--chromium/components/viz/OWNERS50
-rw-r--r--chromium/components/viz/PRESUBMIT.py322
-rw-r--r--chromium/components/viz/README.md224
-rw-r--r--chromium/components/viz/client/BUILD.gn3
-rw-r--r--chromium/components/viz/client/DEPS4
-rw-r--r--chromium/components/viz/client/client_layer_tree_frame_sink.cc54
-rw-r--r--chromium/components/viz/client/client_layer_tree_frame_sink.h55
-rw-r--r--chromium/components/viz/client/client_shared_bitmap_manager.cc8
-rw-r--r--chromium/components/viz/client/client_shared_bitmap_manager.h6
-rw-r--r--chromium/components/viz/client/hit_test_data_provider.h31
-rw-r--r--chromium/components/viz/client/local_surface_id_provider.cc10
-rw-r--r--chromium/components/viz/common/BUILD.gn61
-rw-r--r--chromium/components/viz/common/DEPS4
-rw-r--r--chromium/components/viz/common/README.md4
-rw-r--r--chromium/components/viz/common/display/renderer_settings.h3
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args.cc130
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args.h145
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc125
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.cc354
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.h275
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc610
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.cc180
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.h91
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc351
-rw-r--r--chromium/components/viz/common/gl_helper_benchmark.cc2
-rw-r--r--chromium/components/viz/common/gl_helper_scaling.cc10
-rw-r--r--chromium/components/viz/common/gl_helper_scaling.h8
-rw-r--r--chromium/components/viz/common/gl_helper_unittest.cc12
-rw-r--r--chromium/components/viz/common/gpu/DEPS2
-rw-r--r--chromium/components/viz/common/gpu/in_process_context_provider.h3
-rw-r--r--chromium/components/viz/common/gpu/vulkan_context_provider.h30
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc73
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h45
-rw-r--r--chromium/components/viz/common/hit_test/DEPS4
-rw-r--r--chromium/components/viz/common/hit_test/aggregated_hit_test_region.h15
-rw-r--r--chromium/components/viz/common/quads/DEPS6
-rw-r--r--chromium/components/viz/common/quads/copy_output_request.cc68
-rw-r--r--chromium/components/viz/common/quads/copy_output_request.h114
-rw-r--r--chromium/components/viz/common/quads/copy_output_result.cc47
-rw-r--r--chromium/components/viz/common/quads/copy_output_result.h79
-rw-r--r--chromium/components/viz/common/quads/release_callback.h21
-rw-r--r--chromium/components/viz/common/quads/resource_format.h35
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.cc65
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.h61
-rw-r--r--chromium/components/viz/common/quads/single_release_callback.cc29
-rw-r--r--chromium/components/viz/common/quads/single_release_callback.h35
-rw-r--r--chromium/components/viz/common/resources/DEPS2
-rw-r--r--chromium/components/viz/common/resources/buffer_to_texture_target_map.cc2
-rw-r--r--chromium/components/viz/common/resources/platform_color.h2
-rw-r--r--chromium/components/viz/common/resources/resource_format.h28
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc29
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h35
-rw-r--r--chromium/components/viz/common/resources/resource_id.h19
-rw-r--r--chromium/components/viz/common/resources/returned_resource.h56
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.cc48
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.h54
-rw-r--r--chromium/components/viz/common/surfaces/DEPS1
-rw-r--r--chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h2
-rw-r--r--chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc17
-rw-r--r--chromium/components/viz/common/surfaces/stub_surface_reference_factory.h34
-rw-r--r--chromium/components/viz/common/surfaces/surface_id.h8
-rw-r--r--chromium/components/viz/common/surfaces/surface_info.h10
-rw-r--r--chromium/components/viz/common/switches.cc18
-rw-r--r--chromium/components/viz/common/switches.h18
-rw-r--r--chromium/components/viz/common/traced_value.cc54
-rw-r--r--chromium/components/viz/common/traced_value.h43
-rw-r--r--chromium/components/viz/common/viz_resource_format_export.h29
-rw-r--r--chromium/components/viz/host/BUILD.gn16
-rw-r--r--chromium/components/viz/host/DEPS14
-rw-r--r--chromium/components/viz/host/OWNERS1
-rw-r--r--chromium/components/viz/host/frame_sink_observer.h26
-rw-r--r--chromium/components/viz/host/hit_test/DEPS3
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.cc95
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.h95
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query_unittest.cc668
-rw-r--r--chromium/components/viz/host/host_frame_sink_client.h24
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.cc234
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.h147
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager_unittests.cc426
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.cc82
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.h30
-rw-r--r--chromium/components/viz/host/server_gpu_memory_buffer_manager.cc42
-rw-r--r--chromium/components/viz/host/server_gpu_memory_buffer_manager.h16
-rw-r--r--chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc106
-rw-r--r--chromium/components/viz/presubmit_checks.py339
-rw-r--r--chromium/components/viz/service/BUILD.gn66
-rw-r--r--chromium/components/viz/service/DEPS11
-rw-r--r--chromium/components/viz/service/display/DEPS7
-rw-r--r--chromium/components/viz/service/display/color_lut_cache.cc134
-rw-r--r--chromium/components/viz/service/display/color_lut_cache.h61
-rw-r--r--chromium/components/viz/service/display/display.cc52
-rw-r--r--chromium/components/viz/service/display/display.h30
-rw-r--r--chromium/components/viz/service/display/display_scheduler.cc31
-rw-r--r--chromium/components/viz/service/display/display_scheduler.h32
-rw-r--r--chromium/components/viz/service/display/display_scheduler_unittest.cc61
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc46
-rw-r--r--chromium/components/viz/service/display/dynamic_geometry_binding.cc68
-rw-r--r--chromium/components/viz/service/display/dynamic_geometry_binding.h38
-rw-r--r--chromium/components/viz/service/display/geometry_binding.cc74
-rw-r--r--chromium/components/viz/service/display/geometry_binding.h64
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc3730
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h381
-rw-r--r--chromium/components/viz/service/display/gl_renderer_draw_cache.cc13
-rw-r--r--chromium/components/viz/service/display/gl_renderer_draw_cache.h56
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc2531
-rw-r--r--chromium/components/viz/service/display/program_binding.cc277
-rw-r--r--chromium/components/viz/service/display/program_binding.h446
-rw-r--r--chromium/components/viz/service/display/shader.cc1026
-rw-r--r--chromium/components/viz/service/display/shader.h326
-rw-r--r--chromium/components/viz/service/display/shader_unittest.cc59
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc704
-rw-r--r--chromium/components/viz/service/display/skia_renderer.h119
-rw-r--r--chromium/components/viz/service/display/static_geometry_binding.cc74
-rw-r--r--chromium/components/viz/service/display/static_geometry_binding.h39
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc134
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h51
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_perftest.cc30
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_pixeltest.cc54
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc230
-rw-r--r--chromium/components/viz/service/display_embedder/DEPS3
-rw-r--r--chromium/components/viz/service/display_embedder/OWNERS6
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue.h4
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc6
-rw-r--r--chromium/components/viz/service/display_embedder/display_output_surface.cc10
-rw-r--r--chromium/components/viz/service/display_embedder/display_output_surface.h13
-rw-r--r--chromium/components/viz/service/display_embedder/display_output_surface_ozone.cc4
-rw-r--r--chromium/components/viz/service/display_embedder/display_output_surface_ozone.h7
-rw-r--r--chromium/components/viz/service/display_embedder/display_provider.h14
-rw-r--r--chromium/components/viz/service/display_embedder/gpu_display_provider.cc18
-rw-r--r--chromium/components/viz/service/display_embedder/gpu_display_provider.h6
-rw-r--r--chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc14
-rw-r--r--chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h2
-rw-r--r--chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h10
-rw-r--r--chromium/components/viz/service/frame_sinks/DEPS2
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc86
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h64
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc112
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h75
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_client.h14
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h1
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc449
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc32
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h20
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc28
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_client.h3
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc114
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h88
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc60
-rw-r--r--chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc106
-rw-r--r--chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h74
-rw-r--r--chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc163
-rw-r--r--chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h108
-rw-r--r--chromium/components/viz/service/frame_sinks/primary_begin_frame_source.cc15
-rw-r--r--chromium/components/viz/service/frame_sinks/primary_begin_frame_source.h36
-rw-r--r--chromium/components/viz/service/frame_sinks/referenced_surface_tracker.cc8
-rw-r--r--chromium/components/viz/service/frame_sinks/referenced_surface_tracker.h6
-rw-r--r--chromium/components/viz/service/frame_sinks/referenced_surface_tracker_unittest.cc24
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc159
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h108
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_references_unittest.cc64
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_resource_holder.cc11
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_resource_holder.h14
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_resource_holder_client.h4
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc465
-rw-r--r--chromium/components/viz/service/gl/DEPS19
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc568
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h210
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl_unittest.cc97
-rw-r--r--chromium/components/viz/service/hit_test/DEPS10
-rw-r--r--chromium/components/viz/service/hit_test/OWNERS1
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.cc127
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.h54
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h31
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc1021
-rw-r--r--chromium/components/viz/service/surfaces/DEPS12
-rw-r--r--chromium/components/viz/service/surfaces/direct_surface_reference_factory.cc31
-rw-r--r--chromium/components/viz/service/surfaces/direct_surface_reference_factory.h42
-rw-r--r--chromium/components/viz/service/surfaces/surface.cc418
-rw-r--r--chromium/components/viz/service/surfaces/surface.h266
-rw-r--r--chromium/components/viz/service/surfaces/surface_client.h55
-rw-r--r--chromium/components/viz/service/surfaces/surface_deadline_observer.h18
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_deadline.cc77
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_deadline.h60
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_tracker.cc205
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_tracker.h81
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest.cc300
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest.h87
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest_delegate.h35
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest_unittest.cc505
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.cc588
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.h332
-rw-r--r--chromium/components/viz/service/surfaces/surface_observer.h50
-rw-r--r--chromium/components/viz/service/surfaces/surface_reference.cc27
-rw-r--r--chromium/components/viz/service/surfaces/surface_reference.h59
-rw-r--r--chromium/components/viz/service/surfaces/surface_unittest.cc114
-rw-r--r--chromium/components/viz/test/BUILD.gn44
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.cc18
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.h7
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer_unittest.cc9
-rw-r--r--chromium/components/web_contents_delegate_android/BUILD.gn82
-rw-r--r--chromium/components/web_contents_delegate_android/DEPS2
-rw-r--r--chromium/components/web_contents_delegate_android/java/DEPS (renamed from chromium/components/web_contents_delegate_android/android/DEPS)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble.9.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble.9.png)bin580 -> 580 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble_arrow_up.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble_arrow_up.png)bin263 -> 263 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png)bin1311 -> 1311 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/ic_warning.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/ic_warning.png)bin166 -> 166 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble.9.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble.9.png)bin262 -> 262 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble_arrow_up.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble_arrow_up.png)bin99 -> 99 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png)bin761 -> 761 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/ic_warning.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/ic_warning.png)bin171 -> 171 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble.9.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble.9.png)bin742 -> 742 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble_arrow_up.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble_arrow_up.png)bin313 -> 313 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png)bin1827 -> 1827 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/ic_warning.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/ic_warning.png)bin202 -> 202 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xxhdpi/ic_warning.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xxhdpi/ic_warning.png)bin269 -> 269 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable-xxxhdpi/ic_warning.png (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi/ic_warning.png)bin338 -> 338 bytes
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable/color_button_background.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable/color_button_background.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/drawable/color_picker_border.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/drawable/color_picker_border.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/layout/color_picker_advanced_component.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_advanced_component.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_content.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_title.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_title.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/layout/validation_message_bubble.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/layout/validation_message_bubble.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/values/colors.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/values/colors.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/res/values/dimens.xml (renamed from chromium/components/web_contents_delegate_android/android/java/res/values/dimens.xml)0
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb19
-rw-r--r--chromium/components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd146
-rw-r--r--chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc11
-rw-r--r--chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc5
-rw-r--r--chromium/components/web_contents_delegate_android_strings.grdp51
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager.h4
-rw-r--r--chromium/components/web_resource/resource_request_allowed_notifier.cc6
-rw-r--r--chromium/components/web_resource/resource_request_allowed_notifier.h6
-rw-r--r--chromium/components/web_resource/resource_request_allowed_notifier_unittest.cc2
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client.cc5
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client.h3
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client_result.cc15
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc1
-rw-r--r--chromium/components/webcrypto/BUILD.gn1
-rw-r--r--chromium/components/webcrypto/DEPS1
-rw-r--r--chromium/components/webcrypto/fuzzer_support.cc4
-rw-r--r--chromium/components/webdata/common/web_data_request_manager.h5
-rw-r--r--chromium/components/webdata/common/web_data_service_base.cc7
-rw-r--r--chromium/components/webdata/common/web_data_service_base.h14
-rw-r--r--chromium/components/webdata/common/web_database_service.cc37
-rw-r--r--chromium/components/webdata/common/web_database_service.h21
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.cc44
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.h3
-rw-r--r--chromium/components/wifi/wifi_test.cc2
2168 files changed, 84220 insertions, 32278 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index 93afa70f243..3592db024f5 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -77,11 +77,10 @@ test("components_unittests") {
"//components/data_usage/core:unit_tests",
"//components/device_event_log:unit_tests",
"//components/dom_distiller/core:unit_tests",
- "//components/doodle:unit_tests",
"//components/download:unit_tests",
"//components/favicon/core:unit_tests",
"//components/favicon_base:unit_tests",
- "//components/feature_engagement_tracker:unit_tests",
+ "//components/feature_engagement:unit_tests",
"//components/flags_ui:unit_tests",
"//components/gcm_driver:unit_tests",
"//components/gcm_driver/crypto:unit_tests",
@@ -98,7 +97,6 @@ test("components_unittests") {
"//components/login:unit_tests",
"//components/machine_intelligence:unit_tests",
"//components/metrics:unit_tests",
- "//components/mime_util:unit_tests",
"//components/navigation_metrics:unit_tests",
"//components/net_log:unit_tests",
"//components/network_session_configurator/browser:unit_tests",
@@ -182,6 +180,7 @@ test("components_unittests") {
"//components/crash/content/app:unit_tests",
"//components/crash/core/common:unit_tests",
"//components/data_reduction_proxy/content/browser:unit_tests",
+ "//components/data_reduction_proxy/content/renderer:unit_tests",
"//components/data_reduction_proxy/core/browser:unit_tests",
"//components/data_reduction_proxy/core/common:unit_tests",
"//components/data_use_measurement/core:unit_tests",
@@ -189,8 +188,6 @@ test("components_unittests") {
"//components/discardable_memory/service:unit_tests",
"//components/dom_distiller/content/browser:unit_tests",
"//components/domain_reliability:unit_tests",
- "//components/download/content:unit_tests",
- "//components/error_page/renderer:unit_tests",
"//components/favicon/content:unit_tests",
"//components/gcm_driver/instance_id:unit_tests",
"//components/history/content/browser:unit_tests",
@@ -322,11 +319,31 @@ test("components_unittests") {
if (safe_browsing_mode == 1) {
deps += [ "//components/safe_browsing_db:unit_tests_desktop" ]
} else if (safe_browsing_mode == 2) {
- deps += [ "//components/safe_browsing_db:unit_tests_mobile" ]
+ deps += [ "//components/safe_browsing/db:unit_tests_mobile" ]
+ }
+
+ # No components should depend on Chrome.
+ if (is_chromeos) {
+ # TODO(bug 758767): //chromeos depends on a target in //chrome, and this
+ # target indirectly on //chromeos. The //chromeos -> //chrome dependency
+ # should be fixed and all of chrome added to the assert_no_deps.
+ #
+ # Until this case is fixed, we can blacklist the main Chrome targets which
+ # aren't actually used. This should prevent most major regressions.
+ assert_no_deps = [
+ "//chrome:*", # Catches targets in this file and not subdirs.
+ "//chrome/browser", # No * due to //chrome/browser/chromeos mess.
+ "//chrome/common/*",
+ "//chrome/renderer/*",
+ "//chrome/test/*",
+ ]
+ } else {
+ # Other platforms have clean dependencies.
+ assert_no_deps = [ "//chrome/*" ]
}
if (is_ios) {
- assert_no_deps = ios_assert_no_deps
+ assert_no_deps += ios_assert_no_deps
}
}
@@ -405,6 +422,7 @@ if (!is_ios) {
"dom_distiller/content/browser/distillable_page_utils_browsertest.cc",
"dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc",
"dom_distiller/content/browser/test/dom_distiller_js_browsertest.cc",
+ "offline_pages/content/renovations/test/page_renovator_browsertest.cc",
"password_manager/content/renderer/credential_manager_client_browsertest.cc",
"security_state/content/content_utils_browsertest.cc",
]
@@ -427,6 +445,8 @@ if (!is_ios) {
"//components/dom_distiller/content/browser",
"//components/dom_distiller/core",
"//components/dom_distiller/core:test_support",
+ "//components/offline_pages/content/renovations",
+ "//components/offline_pages/core/renovations",
"//components/password_manager/content/browser",
"//components/password_manager/content/renderer",
"//components/security_state/content",
@@ -488,9 +508,26 @@ if (!is_ios) {
}
if (enable_basic_printing || enable_print_preview) {
- sources += [ "printing/test/print_web_view_helper_browsertest.cc" ]
+ sources += [ "printing/test/print_render_frame_helper_browsertest.cc" ]
deps += [ "//components/printing/test:test_support" ]
}
+
+ if (is_chromeos) {
+ # TODO(bug 758767): //chromeos depends on a target in //chrome, and this
+ # target indirectly on //chromeos. The //chromeos -> //chrome dependency
+ # should be fixed and all of chrome added to the assert_no_deps. For
+ # now, blacklist large parts of Chrome to prevent the most obvious
+ # regressions.
+ assert_no_deps = [
+ "//chrome:*", # Catches targets in this file and not subdirs.
+ "//chrome/browser", # No * due to //chrome/browser/chromeos problem.
+ "//chrome/common/*",
+ "//chrome/renderer/*",
+ "//chrome/test/*",
+ ]
+ } else {
+ assert_no_deps = [ "//chrome/*" ]
+ }
}
test("components_perftests") {
diff --git a/chromium/components/OWNERS b/chromium/components/OWNERS
index 00b920b916f..64cd98d0551 100644
--- a/chromium/components/OWNERS
+++ b/chromium/components/OWNERS
@@ -4,6 +4,7 @@ jochen@chromium.org
sdefresne@chromium.org
# Note: Best not to use globs (like autofill*) due to crbug.com/397984
+
per-file app_modal_strings.grdp=file://components/app_modal/OWNERS
per-file autofill_strings.grdp=file://components/autofill/OWNERS
per-file bookmark_bar_strings.grdp=file://components/bookmarks/OWNERS
diff --git a/chromium/components/about_ui/credit_utils.cc b/chromium/components/about_ui/credit_utils.cc
index 238512d62ef..d6c81ad5dde 100644
--- a/chromium/components/about_ui/credit_utils.cc
+++ b/chromium/components/about_ui/credit_utils.cc
@@ -61,11 +61,6 @@ static base::android::ScopedJavaLocalRef<jbyteArray> GetJavaWrapperCredits(
env, reinterpret_cast<const uint8_t*>(html_content_arr),
html_content.size());
}
-
-// The RegisterNativesImpl is a static function, so has to be called somewhere.
-bool RegisterAboutUIUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
#endif
} // namespace about_ui
diff --git a/chromium/components/app_modal/app_modal_dialog_queue.h b/chromium/components/app_modal/app_modal_dialog_queue.h
index 3b945b6ba85..9d7ebd5554f 100644
--- a/chromium/components/app_modal/app_modal_dialog_queue.h
+++ b/chromium/components/app_modal/app_modal_dialog_queue.h
@@ -5,8 +5,7 @@
#ifndef COMPONENTS_APP_MODAL_APP_MODAL_DIALOG_QUEUE_H_
#define COMPONENTS_APP_MODAL_APP_MODAL_DIALOG_QUEUE_H_
-#include <deque>
-
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
namespace base {
@@ -22,7 +21,7 @@ class JavaScriptAppModalDialog;
// This class is a singleton.
class AppModalDialogQueue {
public:
- typedef std::deque<JavaScriptAppModalDialog*>::iterator iterator;
+ typedef base::circular_deque<JavaScriptAppModalDialog*>::iterator iterator;
// Returns the singleton instance.
static AppModalDialogQueue* GetInstance();
@@ -77,7 +76,7 @@ class AppModalDialogQueue {
// Contains all app modal dialogs which are waiting to be shown. The currently
// active modal dialog is not included.
- std::deque<JavaScriptAppModalDialog*> app_modal_dialog_queue_;
+ base::circular_deque<JavaScriptAppModalDialog*> app_modal_dialog_queue_;
// The currently active app-modal dialog box. nullptr if there is no active
// app-modal dialog box.
diff --git a/chromium/components/app_modal/javascript_dialog_extensions_client.h b/chromium/components/app_modal/javascript_dialog_extensions_client.h
index f85976e99b1..c9c94de90fd 100644
--- a/chromium/components/app_modal/javascript_dialog_extensions_client.h
+++ b/chromium/components/app_modal/javascript_dialog_extensions_client.h
@@ -33,7 +33,7 @@ class JavaScriptDialogExtensionsClient {
// |web_contents| in the |name_out| if there is one, returning true;
// returns false otherwise.
virtual bool GetExtensionName(content::WebContents* web_contents,
- const GURL& origin_url,
+ const GURL& alerting_frame_url,
std::string* name_out) = 0;
};
diff --git a/chromium/components/app_modal/javascript_dialog_manager.cc b/chromium/components/app_modal/javascript_dialog_manager.cc
index de3674c309b..5894fe995e6 100644
--- a/chromium/components/app_modal/javascript_dialog_manager.cc
+++ b/chromium/components/app_modal/javascript_dialog_manager.cc
@@ -43,7 +43,7 @@ class DefaultExtensionsClient : public JavaScriptDialogExtensionsClient {
void OnDialogOpened(content::WebContents* web_contents) override {}
void OnDialogClosed(content::WebContents* web_contents) override {}
bool GetExtensionName(content::WebContents* web_contents,
- const GURL& origin_url,
+ const GURL& alerting_frame_url,
std::string* name_out) override {
return false;
}
@@ -93,25 +93,26 @@ JavaScriptDialogManager::~JavaScriptDialogManager() {
base::string16 JavaScriptDialogManager::GetTitle(
content::WebContents* web_contents,
- const GURL& origin_url) {
+ const GURL& alerting_frame_url) {
// For extensions, show the extension name, but only if the origin of
// the alert matches the top-level WebContents.
std::string name;
- if (extensions_client_->GetExtensionName(web_contents, origin_url, &name))
+ if (extensions_client_->GetExtensionName(web_contents, alerting_frame_url,
+ &name))
return base::UTF8ToUTF16(name);
// Otherwise, return the formatted URL. For non-standard URLs such as |data:|,
// just say "This page".
bool is_same_origin_as_main_frame =
- (web_contents->GetURL().GetOrigin() == origin_url.GetOrigin());
- if (origin_url.IsStandard() && !origin_url.SchemeIsFile() &&
- !origin_url.SchemeIsFileSystem()) {
+ (web_contents->GetURL().GetOrigin() == alerting_frame_url.GetOrigin());
+ if (alerting_frame_url.IsStandard() && !alerting_frame_url.SchemeIsFile() &&
+ !alerting_frame_url.SchemeIsFileSystem()) {
#if defined(OS_ANDROID)
base::string16 url_string = url_formatter::FormatUrlForSecurityDisplay(
- origin_url, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+ alerting_frame_url, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
#else
- base::string16 url_string =
- url_formatter::ElideHost(origin_url, gfx::FontList(), kUrlElideWidth);
+ base::string16 url_string = url_formatter::ElideHost(
+ alerting_frame_url, gfx::FontList(), kUrlElideWidth);
#endif
return l10n_util::GetStringFUTF16(
is_same_origin_as_main_frame ? IDS_JAVASCRIPT_MESSAGEBOX_TITLE
@@ -126,7 +127,7 @@ base::string16 JavaScriptDialogManager::GetTitle(
void JavaScriptDialogManager::RunJavaScriptDialog(
content::WebContents* web_contents,
- const GURL& origin_url,
+ const GURL& alerting_frame_url,
content::JavaScriptDialogType dialog_type,
const base::string16& message_text,
const base::string16& default_prompt_text,
@@ -176,7 +177,7 @@ void JavaScriptDialogManager::RunJavaScriptDialog(
last_close_time_ = base::TimeTicks();
}
- base::string16 dialog_title = GetTitle(web_contents, origin_url);
+ base::string16 dialog_title = GetTitle(web_contents, alerting_frame_url);
extensions_client_->OnDialogOpened(web_contents);
diff --git a/chromium/components/app_modal/javascript_dialog_manager.h b/chromium/components/app_modal/javascript_dialog_manager.h
index 23212628f30..ee4f0bcc924 100644
--- a/chromium/components/app_modal/javascript_dialog_manager.h
+++ b/chromium/components/app_modal/javascript_dialog_manager.h
@@ -39,11 +39,11 @@ class JavaScriptDialogManager : public content::JavaScriptDialogManager {
// Gets the title for a dialog.
base::string16 GetTitle(content::WebContents* web_contents,
- const GURL& origin_url);
+ const GURL& alerting_frame_url);
// JavaScriptDialogManager:
void RunJavaScriptDialog(content::WebContents* web_contents,
- const GURL& origin_url,
+ const GURL& alerting_frame_url,
content::JavaScriptDialogType dialog_type,
const base::string16& message_text,
const base::string16& default_prompt_text,
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index d5454b56e53..65e46991cf2 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -7,8 +7,6 @@ import("//testing/test.gni")
static_library("arc") {
sources = [
- "arc_util.cc",
- "arc_util.h",
"audio/arc_audio_bridge.cc",
"audio/arc_audio_bridge.h",
"bluetooth/bluetooth_struct_traits.cc",
@@ -37,8 +35,8 @@ static_library("arc") {
"intent_helper/intent_constants.h",
"intent_helper/intent_filter.cc",
"intent_helper/intent_filter.h",
- "intent_helper/link_handler_model_impl.cc",
- "intent_helper/link_handler_model_impl.h",
+ "intent_helper/link_handler_model.cc",
+ "intent_helper/link_handler_model.h",
"intent_helper/page_transition_util.cc",
"intent_helper/page_transition_util.h",
"lock_screen/arc_lock_screen_bridge.cc",
@@ -104,8 +102,6 @@ static_library("arc_base") {
"arc_browser_context_keyed_service_factory_base.h",
"arc_features.cc",
"arc_features.h",
- "arc_service.cc",
- "arc_service.h",
"arc_service_manager.cc",
"arc_service_manager.h",
"arc_session.cc",
@@ -114,6 +110,8 @@ static_library("arc_base") {
"arc_session_runner.h",
"arc_stop_reason.cc",
"arc_stop_reason.h",
+ "arc_util.cc",
+ "arc_util.h",
"instance_holder.h",
]
@@ -124,6 +122,7 @@ static_library("arc_base") {
"//components/signin/core/account_id",
"//components/user_manager",
"//mojo/edk/system",
+ "//ui/aura",
]
public_deps = [
@@ -141,6 +140,7 @@ mojom("arc_bindings") {
"common/bitmap.mojom",
"common/bluetooth.mojom",
"common/boot_phase_monitor.mojom",
+ "common/cast_receiver.mojom",
"common/clipboard.mojom",
"common/crash_collector.mojom",
"common/enterprise_reporting.mojom",
@@ -153,6 +153,7 @@ mojom("arc_bindings") {
"common/net.mojom",
"common/notifications.mojom",
"common/obb_mounter.mojom",
+ "common/oemcrypto.mojom",
"common/policy.mojom",
"common/power.mojom",
"common/print.mojom",
@@ -214,7 +215,6 @@ static_library("arc_test_support") {
source_set("unit_tests") {
testonly = true
sources = [
- "arc_service_manager_unittest.cc",
"arc_session_runner_unittest.cc",
"arc_util_unittest.cc",
"bluetooth/bluetooth_struct_traits_unittest.cc",
@@ -224,7 +224,7 @@ source_set("unit_tests") {
"intent_helper/arc_intent_helper_bridge_unittest.cc",
"intent_helper/font_size_util_unittest.cc",
"intent_helper/intent_filter_unittest.cc",
- "intent_helper/link_handler_model_impl_unittest.cc",
+ "intent_helper/link_handler_model_unittest.cc",
"intent_helper/page_transition_util_unittest.cc",
]
diff --git a/chromium/components/arc/arc_bridge_host_impl.cc b/chromium/components/arc/arc_bridge_host_impl.cc
index 02c5720605c..872e4107fd1 100644
--- a/chromium/components/arc/arc_bridge_host_impl.cc
+++ b/chromium/components/arc/arc_bridge_host_impl.cc
@@ -115,6 +115,12 @@ void ArcBridgeHostImpl::OnBootPhaseMonitorInstanceReady(
std::move(boot_phase_monitor_ptr));
}
+void ArcBridgeHostImpl::OnCastReceiverInstanceReady(
+ mojom::CastReceiverInstancePtr cast_receiver_ptr) {
+ OnInstanceReady(arc_bridge_service_->cast_receiver(),
+ std::move(cast_receiver_ptr));
+}
+
void ArcBridgeHostImpl::OnClipboardInstanceReady(
mojom::ClipboardInstancePtr clipboard_ptr) {
OnInstanceReady(arc_bridge_service_->clipboard(), std::move(clipboard_ptr));
@@ -180,6 +186,11 @@ void ArcBridgeHostImpl::OnObbMounterInstanceReady(
std::move(obb_mounter_ptr));
}
+void ArcBridgeHostImpl::OnOemCryptoInstanceReady(
+ mojom::OemCryptoInstancePtr oemcrypto_ptr) {
+ OnInstanceReady(arc_bridge_service_->oemcrypto(), std::move(oemcrypto_ptr));
+}
+
void ArcBridgeHostImpl::OnPolicyInstanceReady(
mojom::PolicyInstancePtr policy_ptr) {
OnInstanceReady(arc_bridge_service_->policy(), std::move(policy_ptr));
diff --git a/chromium/components/arc/arc_bridge_host_impl.h b/chromium/components/arc/arc_bridge_host_impl.h
index d1d6b4f346a..9e79bee967e 100644
--- a/chromium/components/arc/arc_bridge_host_impl.h
+++ b/chromium/components/arc/arc_bridge_host_impl.h
@@ -47,6 +47,8 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
mojom::BluetoothInstancePtr bluetooth_ptr) override;
void OnBootPhaseMonitorInstanceReady(
mojom::BootPhaseMonitorInstancePtr boot_phase_monitor_ptr) override;
+ void OnCastReceiverInstanceReady(
+ mojom::CastReceiverInstancePtr cast_receiver_ptr) override;
void OnClipboardInstanceReady(
mojom::ClipboardInstancePtr clipboard_ptr) override;
void OnCrashCollectorInstanceReady(
@@ -67,6 +69,8 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
mojom::NotificationsInstancePtr notifications_ptr) override;
void OnObbMounterInstanceReady(
mojom::ObbMounterInstancePtr obb_mounter_ptr) override;
+ void OnOemCryptoInstanceReady(
+ mojom::OemCryptoInstancePtr oemcrypto_ptr) override;
void OnPolicyInstanceReady(mojom::PolicyInstancePtr policy_ptr) override;
void OnPowerInstanceReady(mojom::PowerInstancePtr power_ptr) override;
void OnPrintInstanceReady(mojom::PrintInstancePtr print_ptr) override;
diff --git a/chromium/components/arc/arc_bridge_service.h b/chromium/components/arc/arc_bridge_service.h
index e69c0de19e1..2c446c4f66b 100644
--- a/chromium/components/arc/arc_bridge_service.h
+++ b/chromium/components/arc/arc_bridge_service.h
@@ -20,6 +20,7 @@ class AudioInstance;
class AuthInstance;
class BluetoothInstance;
class BootPhaseMonitorInstance;
+class CastReceiverInstance;
class ClipboardInstance;
class CrashCollectorInstance;
class EnterpriseReportingInstance;
@@ -32,6 +33,7 @@ class MetricsInstance;
class NetInstance;
class NotificationsInstance;
class ObbMounterInstance;
+class OemCryptoInstance;
class PolicyInstance;
class PowerInstance;
class PrintInstance;
@@ -64,6 +66,9 @@ class ArcBridgeService {
InstanceHolder<mojom::BootPhaseMonitorInstance>* boot_phase_monitor() {
return &boot_phase_monitor_;
}
+ InstanceHolder<mojom::CastReceiverInstance>* cast_receiver() {
+ return &cast_receiver_;
+ }
InstanceHolder<mojom::ClipboardInstance>* clipboard() { return &clipboard_; }
InstanceHolder<mojom::CrashCollectorInstance>* crash_collector() {
return &crash_collector_;
@@ -90,6 +95,7 @@ class ArcBridgeService {
InstanceHolder<mojom::ObbMounterInstance>* obb_mounter() {
return &obb_mounter_;
}
+ InstanceHolder<mojom::OemCryptoInstance>* oemcrypto() { return &oemcrypto_; }
InstanceHolder<mojom::PolicyInstance>* policy() { return &policy_; }
InstanceHolder<mojom::PowerInstance>* power() { return &power_; }
InstanceHolder<mojom::PrintInstance>* print() { return &print_; }
@@ -120,6 +126,7 @@ class ArcBridgeService {
InstanceHolder<mojom::AuthInstance> auth_;
InstanceHolder<mojom::BluetoothInstance> bluetooth_;
InstanceHolder<mojom::BootPhaseMonitorInstance> boot_phase_monitor_;
+ InstanceHolder<mojom::CastReceiverInstance> cast_receiver_;
InstanceHolder<mojom::ClipboardInstance> clipboard_;
InstanceHolder<mojom::CrashCollectorInstance> crash_collector_;
InstanceHolder<mojom::EnterpriseReportingInstance> enterprise_reporting_;
@@ -132,6 +139,7 @@ class ArcBridgeService {
InstanceHolder<mojom::NetInstance> net_;
InstanceHolder<mojom::NotificationsInstance> notifications_;
InstanceHolder<mojom::ObbMounterInstance> obb_mounter_;
+ InstanceHolder<mojom::OemCryptoInstance> oemcrypto_;
InstanceHolder<mojom::PolicyInstance> policy_;
InstanceHolder<mojom::PowerInstance> power_;
InstanceHolder<mojom::PrintInstance> print_;
diff --git a/chromium/components/arc/arc_features.cc b/chromium/components/arc/arc_features.cc
index f0ab3c4b751..0ab06d6c9da 100644
--- a/chromium/components/arc/arc_features.cc
+++ b/chromium/components/arc/arc_features.cc
@@ -12,4 +12,9 @@ const base::Feature kBootCompletedBroadcastFeature {
"ArcBootCompletedBroadcast", base::FEATURE_ENABLED_BY_DEFAULT
};
+// Controls experimental native bridge feature for ARC.
+const base::Feature kNativeBridgeExperimentFeature {
+ "ArcNativeBridgeExperiment", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
} // namespace arc
diff --git a/chromium/components/arc/arc_features.h b/chromium/components/arc/arc_features.h
index 30ac5a47c3c..d2bd9d8ae71 100644
--- a/chromium/components/arc/arc_features.h
+++ b/chromium/components/arc/arc_features.h
@@ -13,6 +13,7 @@ namespace arc {
// Please keep alphabetized.
extern const base::Feature kBootCompletedBroadcastFeature;
+extern const base::Feature kNativeBridgeExperimentFeature;
} // namespace arc
diff --git a/chromium/components/arc/arc_service.cc b/chromium/components/arc/arc_service.cc
deleted file mode 100644
index e40cc4d8123..00000000000
--- a/chromium/components/arc/arc_service.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/arc/arc_service.h"
-
-#include "components/arc/arc_bridge_service.h"
-
-namespace arc {
-
-ArcService::ArcService(ArcBridgeService* bridge_service)
- : arc_bridge_service_(bridge_service) {
- DCHECK(arc_bridge_service());
-}
-
-ArcService::~ArcService() {}
-
-} // namespace arc
diff --git a/chromium/components/arc/arc_service.h b/chromium/components/arc/arc_service.h
deleted file mode 100644
index d9524178642..00000000000
--- a/chromium/components/arc/arc_service.h
+++ /dev/null
@@ -1,35 +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.
-
-#ifndef COMPONENTS_ARC_ARC_SERVICE_H_
-#define COMPONENTS_ARC_ARC_SERVICE_H_
-
-#include "base/macros.h"
-
-namespace arc {
-
-class ArcBridgeService;
-
-// Abstract class whose lifecycle will be managed by the ArcServiceManager. It
-// is guaranteed that once the ownership of an ArcService has been transferred
-// to ArcServiceManager, it will outlive the ArcBridgeService, so it is safe to
-// keep a weak reference to it.
-class ArcService {
- public:
- virtual ~ArcService();
-
- ArcBridgeService* arc_bridge_service() const { return arc_bridge_service_; }
-
- protected:
- explicit ArcService(ArcBridgeService* arc_bridge_service);
-
- private:
- ArcBridgeService* const arc_bridge_service_; // owned by ArcServiceManager.
-
- DISALLOW_COPY_AND_ASSIGN(ArcService);
-};
-
-} // namespace arc
-
-#endif // COMPONENTS_ARC_ARC_SERVICE_H_
diff --git a/chromium/components/arc/arc_service_manager.cc b/chromium/components/arc/arc_service_manager.cc
index 3ecd33bdf89..b483206356a 100644
--- a/chromium/components/arc/arc_service_manager.cc
+++ b/chromium/components/arc/arc_service_manager.cc
@@ -43,37 +43,4 @@ ArcBridgeService* ArcServiceManager::arc_bridge_service() {
return arc_bridge_service_.get();
}
-bool ArcServiceManager::AddServiceInternal(
- const std::string& name,
- std::unique_ptr<ArcService> service) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!name.empty() && services_.count(name) != 0) {
- LOG(ERROR) << "Ignoring registration of service with duplicate name: "
- << name;
- return false;
- }
- services_.insert(std::make_pair(name, std::move(service)));
- return true;
-}
-
-ArcService* ArcServiceManager::GetNamedServiceInternal(
- const std::string& name) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (name.empty()) {
- LOG(ERROR) << "kArcServiceName[] should be a fully-qualified class name.";
- return nullptr;
- }
- auto service = services_.find(name);
- if (service == services_.end()) {
- LOG(ERROR) << "Named service " << name << " not found";
- return nullptr;
- }
- return service->second.get();
-}
-
-void ArcServiceManager::Shutdown() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- services_.clear();
-}
-
} // namespace arc
diff --git a/chromium/components/arc/arc_service_manager.h b/chromium/components/arc/arc_service_manager.h
index f918bb2d93c..1e84e21d97b 100644
--- a/chromium/components/arc/arc_service_manager.h
+++ b/chromium/components/arc/arc_service_manager.h
@@ -6,16 +6,9 @@
#define COMPONENTS_ARC_ARC_SERVICE_MANAGER_H_
#include <memory>
-#include <string>
-#include <type_traits>
-#include <unordered_map>
-#include <utility>
-#include <vector>
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
-#include "components/arc/arc_service.h"
#include "components/signin/core/account_id/account_id.h"
namespace content {
@@ -26,42 +19,10 @@ namespace arc {
class ArcBridgeService;
-namespace internal {
-
-// If an ArcService is declared with a name, e.g.:
-//
-// class MyArcService : public ArcService {
-// public:
-// static const char kArcServiceName[];
-// ...
-// };
-//
-// it can then be retrieved from ArcServiceManager in a type-safe way using
-// GetService<T>(). This two functions allow AddService() to get the name only
-// if it was provided, or use an empty string otherwise.
-//
-// Although the typename is always specified explicitly by the caller, the
-// parameter is required in order for SFINAE to work correctly. It is not used
-// and can be nullptr, though.
-//
-// In order to avoid collisions, kArcServiceName should be the fully-qualified
-// name of the class.
-template <typename T>
-decltype(T::kArcServiceName, std::string()) GetArcServiceName(T* unused) {
- if (strlen(T::kArcServiceName) == 0)
- LOG(ERROR) << "kArcServiceName[] should be a fully-qualified class name.";
- return T::kArcServiceName;
-}
-
-template <typename T>
-std::string GetArcServiceName(...) {
- return std::string();
-}
-
-} // namespace internal
-
-// Manages creation and destruction of services that communicate with the ARC
-// instance via the ArcBridgeService.
+// Holds ARC related global information. Specifically, it owns ArcBridgeService
+// instance.
+// TODO(hidehiko): Consider to migrate into another global ARC class, such as
+// ArcSessionManager or ArcServiceLauncher.
class ArcServiceManager {
public:
ArcServiceManager();
@@ -93,49 +54,14 @@ class ArcServiceManager {
// class was created on.
ArcBridgeService* arc_bridge_service();
- // Adds a service to the managed services list. Returns false if another
- // named service with that name had already been added.
- template <typename T>
- bool AddService(std::unique_ptr<T> service) {
- return AddServiceInternal(internal::GetArcServiceName<T>(nullptr),
- std::move(service));
- }
-
- // Gets the named service from the managed services list. This uses SFINAE, so
- // you can only call this function if the service specified by T provides a
- // static member variable called kArcServiceName[] (otherwise this will not
- // compile).
- template <typename T>
- T* GetService() {
- return static_cast<T*>(GetNamedServiceInternal(T::kArcServiceName));
- }
-
- // Does the same as GetService(), but with the global instance. Return nullptr
- // when the instance hasn't been created or has already been destructed.
- template <typename T> static T* GetGlobalService() {
- auto* service_manager = ArcServiceManager::Get();
- if (!service_manager)
- return nullptr;
- return service_manager->GetService<T>();
- }
-
// Gets the global instance of the ARC Service Manager. This can only be
// called on the thread that this class was created on.
static ArcServiceManager* Get();
- // Called to shut down all ARC services.
- void Shutdown();
-
private:
- // Helper methods for AddService and GetService.
- bool AddServiceInternal(const std::string& name,
- std::unique_ptr<ArcService> service);
- ArcService* GetNamedServiceInternal(const std::string& name);
-
THREAD_CHECKER(thread_checker_);
std::unique_ptr<ArcBridgeService> arc_bridge_service_;
- std::unordered_multimap<std::string, std::unique_ptr<ArcService>> services_;
// This holds the pointer to the BrowserContext (practically Profile)
// which is allowed to use ARC.
diff --git a/chromium/components/arc/arc_service_manager_unittest.cc b/chromium/components/arc/arc_service_manager_unittest.cc
deleted file mode 100644
index cd9f9dc7cc8..00000000000
--- a/chromium/components/arc/arc_service_manager_unittest.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <utility>
-
-#include "base/auto_reset.h"
-#include "base/memory/ptr_util.h"
-#include "components/arc/arc_bridge_service.h"
-#include "components/arc/arc_service_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace arc {
-
-namespace {
-
-class AnonymousService : public ArcService {
- public:
- AnonymousService(ArcBridgeService* arc_bridge_service, bool* alive)
- : ArcService(arc_bridge_service), alive_(alive, true) {}
- ~AnonymousService() override = default;
-
- private:
- base::AutoReset<bool> alive_;
-};
-
-class NamedService : public ArcService {
- public:
- static const char kArcServiceName[];
- NamedService(ArcBridgeService* arc_bridge_service, bool* alive)
- : ArcService(arc_bridge_service), alive_(alive, true) {}
- ~NamedService() override = default;
-
- private:
- base::AutoReset<bool> alive_;
-};
-
-class DifferentNamedService : public ArcService {
- public:
- static const char kArcServiceName[];
- DifferentNamedService(ArcBridgeService* arc_bridge_service, bool* alive)
- : ArcService(arc_bridge_service), alive_(alive, true) {}
- ~DifferentNamedService() override = default;
-
- private:
- base::AutoReset<bool> alive_;
-};
-
-class EmptyNamedService : public ArcService {
- public:
- static const char kArcServiceName[];
- EmptyNamedService(ArcBridgeService* arc_bridge_service, bool* alive)
- : ArcService(arc_bridge_service), alive_(alive, true) {}
- ~EmptyNamedService() override = default;
-
- private:
- base::AutoReset<bool> alive_;
-};
-
-const char NamedService::kArcServiceName[] =
- "arc::(anonymous namespace)::NamedService";
-
-const char DifferentNamedService::kArcServiceName[] =
- "arc::(anonymous namespace)::DifferentNamedService";
-
-const char EmptyNamedService::kArcServiceName[] = "";
-
-} // namespace
-
-class ArcServiceManagerTest : public testing::Test {
- public:
- ArcServiceManagerTest() = default;
-
- void SetUp() override {
- arc_bridge_service_ = base::MakeUnique<ArcBridgeService>();
- }
-
- void TearDown() override { arc_bridge_service_.reset(); }
-
- ArcBridgeService* arc_bridge_service() { return arc_bridge_service_.get(); }
-
- private:
- std::unique_ptr<ArcBridgeService> arc_bridge_service_;
-
- DISALLOW_COPY_AND_ASSIGN(ArcServiceManagerTest);
-};
-
-// Exercises the basic getter functionality of ArcServiceManager.
-TEST_F(ArcServiceManagerTest, BasicGetter) {
- bool named_service_alive = false;
-
- // ArcServiceManager is empty, GetService() should return nullptr.
- auto manager = base::MakeUnique<ArcServiceManager>();
- EXPECT_EQ(nullptr, manager->GetService<NamedService>());
-
- EXPECT_TRUE(manager->AddService(base::MakeUnique<NamedService>(
- arc_bridge_service(), &named_service_alive)));
- EXPECT_TRUE(named_service_alive);
- EXPECT_NE(nullptr, manager->GetService<NamedService>());
-
- // Finally, the service should not be alive anymore.
- manager.reset();
- EXPECT_FALSE(named_service_alive);
-}
-
-// There is no way to distinguish between anonymous services, so it should be
-// possible to add them twice (not that it's recommended).
-TEST_F(ArcServiceManagerTest, MultipleAnonymousServices) {
- bool anonymous_service_alive = false;
- bool second_anonymous_service_alive = false;
-
- auto manager = base::MakeUnique<ArcServiceManager>();
-
- EXPECT_TRUE(manager->AddService(base::MakeUnique<AnonymousService>(
- arc_bridge_service(), &anonymous_service_alive)));
- EXPECT_TRUE(anonymous_service_alive);
- EXPECT_TRUE(manager->AddService(base::MakeUnique<AnonymousService>(
- arc_bridge_service(), &second_anonymous_service_alive)));
- EXPECT_TRUE(second_anonymous_service_alive);
-
- // Finally, the individual services should not be alive anymore.
- manager.reset();
- EXPECT_FALSE(anonymous_service_alive);
- EXPECT_FALSE(second_anonymous_service_alive);
-}
-
-// Named services can only be added once, but can still be retrieved.
-TEST_F(ArcServiceManagerTest, MultipleNamedServices) {
- bool named_service_alive = false;
- bool second_named_service_alive = false;
- bool different_named_service_alive = false;
-
- auto manager = base::MakeUnique<ArcServiceManager>();
-
- auto named_service = base::MakeUnique<NamedService>(arc_bridge_service(),
- &named_service_alive);
- NamedService* raw_named_service = named_service.get();
- EXPECT_TRUE(named_service_alive);
- EXPECT_TRUE(manager->AddService(std::move(named_service)));
- auto second_named_service = base::MakeUnique<NamedService>(
- arc_bridge_service(), &second_named_service_alive);
- EXPECT_TRUE(second_named_service_alive);
- // This will fail and immediately destroy the service.
- EXPECT_FALSE(manager->AddService(std::move(second_named_service)));
- EXPECT_FALSE(second_named_service_alive);
-
- // We should still be able to add a different-named service.
- auto different_named_service = base::MakeUnique<DifferentNamedService>(
- arc_bridge_service(), &different_named_service_alive);
- DifferentNamedService* raw_different_named_service =
- different_named_service.get();
- EXPECT_TRUE(different_named_service_alive);
- EXPECT_TRUE(manager->AddService(std::move(different_named_service)));
-
- // And find both.
- EXPECT_EQ(raw_named_service, manager->GetService<NamedService>());
- EXPECT_EQ(raw_different_named_service,
- manager->GetService<DifferentNamedService>());
-
- manager.reset();
- EXPECT_FALSE(named_service_alive);
- EXPECT_FALSE(different_named_service_alive);
-}
-
-// Named services with an empty name are treated as anonymous services.
-// Developers shouldn't do that, though, and will trigger an error log.
-TEST_F(ArcServiceManagerTest, EmptyNamedServices) {
- bool empty_named_service_alive = false;
-
- auto manager = base::MakeUnique<ArcServiceManager>();
-
- EXPECT_TRUE(manager->AddService(base::MakeUnique<EmptyNamedService>(
- arc_bridge_service(), &empty_named_service_alive)));
- EXPECT_TRUE(empty_named_service_alive);
- EXPECT_EQ(nullptr, manager->GetService<EmptyNamedService>());
-
- manager.reset();
- EXPECT_FALSE(empty_named_service_alive);
-}
-
-// Tests if GetGlobalService works as expected regardless of whether the
-// global pointer is null.
-TEST_F(ArcServiceManagerTest, TestGetGlobalService) {
- // The getter should return nullptr when no global instance is available.
- EXPECT_EQ(nullptr, ArcServiceManager::GetGlobalService<NamedService>());
-
- // Create a manager. This will automatically be registered as a global
- // instance.
- auto manager = base::MakeUnique<ArcServiceManager>();
-
- // The getter should return nullptr when the manager doesn't know about the
- // NamedService instance.
- EXPECT_EQ(nullptr, ArcServiceManager::GetGlobalService<NamedService>());
-
- // Register the instance and retry. The getter should return non-null this
- // time.
- bool unused;
- EXPECT_TRUE(manager->AddService(base::MakeUnique<NamedService>(
- arc_bridge_service(), &unused)));
- EXPECT_NE(nullptr, ArcServiceManager::GetGlobalService<NamedService>());
-
- // Remove the global instance. The same GetGlobalService() call should return
- // nullptr now.
- manager.reset();
- EXPECT_EQ(nullptr, ArcServiceManager::GetGlobalService<NamedService>());
-}
-
-} // namespace arc
diff --git a/chromium/components/arc/arc_session.cc b/chromium/components/arc/arc_session.cc
index bfe9c8a4b91..64b543e2454 100644
--- a/chromium/components/arc/arc_session.cc
+++ b/chromium/components/arc/arc_session.cc
@@ -12,7 +12,6 @@
#include <string>
#include <utility>
-#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/macros.h"
@@ -48,11 +47,6 @@ namespace {
using StartArcInstanceResult =
chromeos::SessionManagerClient::StartArcInstanceResult;
-const base::FilePath::CharType kArcBridgeSocketPath[] =
- FILE_PATH_LITERAL("/var/run/chrome/arc_bridge.sock");
-
-const char kArcBridgeSocketGroup[] = "arc-bridge";
-
// This is called when StopArcInstance D-Bus method completes. Since we have the
// ArcInstanceStopped() callback and are notified if StartArcInstance fails, we
// don't need to do anything when StopArcInstance completes.
@@ -118,8 +112,6 @@ class ArcSessionImpl : public ArcSession,
//
// NOT_STARTED
// Start() ->
- // CREATING_SOCKET
- // CreateSocket() -> OnSocketCreated() ->
// STARTING_INSTANCE
// -> OnInstanceStarted() ->
// CONNECTING_MOJO
@@ -132,14 +124,12 @@ class ArcSessionImpl : public ArcSession,
//
// NOT_STARTED
// StartForLoginScreen() ->
- // CREATING_SOCKET
- // CreateSocket() -> OnSocketCreated() ->
// STARTING_INSTANCE
// -> OnInstanceStarted() ->
// RUNNING_FOR_LOGIN_SCREEN
//
- // Start() can also be used at any of these 3 state (from CREATING_SOCKET to
- // RUNNING_FOR_LOGIN_SCREEN) to turn the instance for login screen into a
+ // Start() can also be used at both STARTING_INSTANCE and
+ // RUNNING_FOR_LOGIN_SCREEN to turn the instance for login screen into a
// fully functional one.
//
// Regardless of whether the instance is for login screen or not, at any
@@ -152,21 +142,17 @@ class ArcSessionImpl : public ArcSession,
//
// NOT_STARTED:
// Do nothing. Immediately transition to the STOPPED state.
- // CREATING_SOCKET:
- // The main task of the phase runs on BlockingPool thread. So, Stop() just
- // sets the flag and return. On the main task completion, a callback
- // will run on the main (practically UI) thread, and the flag is checked
- // at the beginning of them. This should work under the assumption that
- // the main tasks do not block indefinitely.
// STARTING_INSTANCE:
- // The ARC instance is starting via SessionManager. So, similar to
- // CREATING_SOCKET case, Stop() just sets the flag and return. In its
- // callback, it checks if ARC instance is successfully started or not.
- // In case of success, a request to stop the ARC instance is sent to
+ // The ARC instance is starting via SessionManager. Stop() just sets the
+ // flag and return. On the main task completion, a callback will run on the
+ // thread, and the flag is checked at the beginning of them. This should
+ // work under the assumption that the main tasks do not block indefinitely.
+ // In its callback, it checks if ARC instance is successfully started or
+ // not. In case of success, a request to stop the ARC instance is sent to
// SessionManager. Its completion will be notified via ArcInstanceStopped.
// Otherwise, it just turns into STOPPED state.
// CONNECTING_MOJO:
- // The main task runs on BlockingPool thread, but it is blocking call.
+ // The main task runs on TaskScheduler's thread, but it is a blocking call.
// So, Stop() sends a request to cancel the blocking by closing the pipe
// whose read side is also polled. Then, in its callback, similar to
// STARTING_INSTANCE, a request to stop the ARC instance is sent to
@@ -192,9 +178,6 @@ class ArcSessionImpl : public ArcSession,
// ARC is not yet started.
NOT_STARTED,
- // An UNIX socket is being created.
- CREATING_SOCKET,
-
// The request to start or resume the instance has been sent.
STARTING_INSTANCE,
@@ -223,17 +206,11 @@ class ArcSessionImpl : public ArcSession,
void OnShutdown() override;
private:
- // Creates the UNIX socket on a worker pool and then processes its file
- // descriptor.
- static mojo::edk::ScopedPlatformHandle CreateSocket();
- void OnSocketCreated(bool instance_is_for_login_screen,
- mojo::edk::ScopedPlatformHandle fd);
-
// DBus callback for StartArcInstance().
void OnInstanceStarted(bool instance_is_for_login_screen,
- mojo::edk::ScopedPlatformHandle socket_fd,
StartArcInstanceResult result,
- const std::string& container_instance_id);
+ const std::string& container_instance_id,
+ base::ScopedFD socket_fd);
// Synchronously accepts a connection on |socket_fd| and then processes the
// connected socket's file descriptor.
@@ -275,10 +252,6 @@ class ArcSessionImpl : public ArcSession,
// that, when Start() is called to resume the boot, the flag is unset.
bool login_screen_instance_requested_ = false;
- // The handle StartForLoginScreen() has created. The variable has a
- // valid handle only when |state_| is RUNNING_FOR_LOGIN_SCREEN.
- mojo::edk::ScopedPlatformHandle socket_fd_;
-
// Container instance id passed from session_manager.
// Should be available only after OnInstanceStarted().
std::string container_instance_id_;
@@ -322,7 +295,7 @@ void ArcSessionImpl::Start() {
// RUNNING_FOR_LOGIN_SCREEN.
DCHECK_GE(State::RUNNING_FOR_LOGIN_SCREEN, state_);
- // Flip the flag now so that callback functions like OnSocketCreated()
+ // Flip the flag now so that callback functions like OnInstanceStarted()
// can do the right thing.
login_screen_instance_requested_ = false;
@@ -330,16 +303,13 @@ void ArcSessionImpl::Start() {
// An instance for login screen does not exist. Start a new one from
// scratch.
VLOG(2) << "Starting ARC session";
- VLOG(2) << "Creating socket...";
- state_ = State::CREATING_SOCKET;
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, {base::MayBlock()},
- base::Bind(&ArcSessionImpl::CreateSocket),
- base::Bind(&ArcSessionImpl::OnSocketCreated, weak_factory_.GetWeakPtr(),
- false /* not for login screen */));
- } else if (state_ == State::CREATING_SOCKET) {
- VLOG(2) << "Requested to start ARC instance with an existing socket";
- // OnSocketCreated() will start a fully featured instance.
+ state_ = State::STARTING_INSTANCE;
+ SendStartArcInstanceDBusMessage(
+ false /* instance_is_for_login_screen */,
+ base::Bind(&ArcSessionImpl::OnInstanceStarted,
+ weak_factory_.GetWeakPtr(),
+ false /* instance_is_for_login_screen */));
+
} else if (state_ == State::STARTING_INSTANCE) {
VLOG(2) << "Requested to resume an existing ARC instance";
// OnInstanceStarted() will start a fully featured instance.
@@ -347,76 +317,11 @@ void ArcSessionImpl::Start() {
VLOG(2) << "Resuming an existing ARC instance";
state_ = State::STARTING_INSTANCE;
SendStartArcInstanceDBusMessage(
- false /* not for login screen */,
+ false /* instance_is_for_login_screen */,
base::Bind(&ArcSessionImpl::OnInstanceStarted,
- weak_factory_.GetWeakPtr(), false /* the same */,
- base::Passed(&socket_fd_)));
- }
-}
-
-// static
-mojo::edk::ScopedPlatformHandle ArcSessionImpl::CreateSocket() {
- base::FilePath socket_path(kArcBridgeSocketPath);
-
- mojo::edk::ScopedPlatformHandle socket_fd = mojo::edk::CreateServerHandle(
- mojo::edk::NamedPlatformHandle(socket_path.value()));
- if (!socket_fd.is_valid())
- return socket_fd;
-
- // Change permissions on the socket.
- struct group arc_bridge_group;
- struct group* arc_bridge_group_res = nullptr;
- char buf[10000];
- if (HANDLE_EINTR(getgrnam_r(kArcBridgeSocketGroup, &arc_bridge_group, buf,
- sizeof(buf), &arc_bridge_group_res)) < 0) {
- PLOG(ERROR) << "getgrnam_r";
- return mojo::edk::ScopedPlatformHandle();
- }
-
- if (!arc_bridge_group_res) {
- LOG(ERROR) << "Group '" << kArcBridgeSocketGroup << "' not found";
- return mojo::edk::ScopedPlatformHandle();
- }
-
- if (HANDLE_EINTR(chown(kArcBridgeSocketPath, -1, arc_bridge_group.gr_gid)) <
- 0) {
- PLOG(ERROR) << "chown";
- return mojo::edk::ScopedPlatformHandle();
- }
-
- if (!base::SetPosixFilePermissions(socket_path, 0660)) {
- PLOG(ERROR) << "Could not set permissions: " << socket_path.value();
- return mojo::edk::ScopedPlatformHandle();
- }
-
- return socket_fd;
-}
-
-void ArcSessionImpl::OnSocketCreated(
- bool instance_is_for_login_screen,
- mojo::edk::ScopedPlatformHandle socket_fd) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK_EQ(state_, State::CREATING_SOCKET);
-
- if (stop_requested_) {
- VLOG(1) << "Stop() called while connecting";
- OnStopped(ArcStopReason::SHUTDOWN);
- return;
+ weak_factory_.GetWeakPtr(),
+ false /* instance_is_for_login_screen */));
}
-
- if (!socket_fd.is_valid()) {
- LOG(ERROR) << "ARC: Error creating socket";
- OnStopped(ArcStopReason::GENERIC_BOOT_FAILURE);
- return;
- }
-
- VLOG(2) << "Socket is created. Starting ARC instance"
- << (instance_is_for_login_screen ? " for login screen" : "");
- state_ = State::STARTING_INSTANCE;
- SendStartArcInstanceDBusMessage(
- instance_is_for_login_screen,
- base::Bind(&ArcSessionImpl::OnInstanceStarted, weak_factory_.GetWeakPtr(),
- instance_is_for_login_screen, base::Passed(&socket_fd)));
}
// static
@@ -425,11 +330,14 @@ void ArcSessionImpl::SendStartArcInstanceDBusMessage(
const chromeos::SessionManagerClient::StartArcInstanceCallback& cb) {
chromeos::SessionManagerClient* session_manager_client =
chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+ const bool native_bridge_experiment =
+ base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature);
if (instance_is_for_login_screen) {
session_manager_client->StartArcInstance(
chromeos::SessionManagerClient::ArcStartupMode::LOGIN_SCREEN,
// All variables below except |cb| will be ignored.
- cryptohome::Identification(), false, false, cb);
+ cryptohome::Identification(), false, false,
+ native_bridge_experiment, cb);
return;
}
@@ -448,14 +356,14 @@ void ArcSessionImpl::SendStartArcInstanceDBusMessage(
session_manager_client->StartArcInstance(
chromeos::SessionManagerClient::ArcStartupMode::FULL, cryptohome_id,
- skip_boot_completed_broadcast, scan_vendor_priv_app, cb);
+ skip_boot_completed_broadcast, scan_vendor_priv_app,
+ native_bridge_experiment, cb);
}
-void ArcSessionImpl::OnInstanceStarted(
- bool instance_is_for_login_screen,
- mojo::edk::ScopedPlatformHandle socket_fd,
- StartArcInstanceResult result,
- const std::string& container_instance_id) {
+void ArcSessionImpl::OnInstanceStarted(bool instance_is_for_login_screen,
+ StartArcInstanceResult result,
+ const std::string& container_instance_id,
+ base::ScopedFD socket_fd) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(state_, State::STARTING_INSTANCE);
@@ -492,16 +400,15 @@ void ArcSessionImpl::OnInstanceStarted(
VLOG(2) << "ARC instance for login screen is successfully started.";
if (login_screen_instance_requested_) {
state_ = State::RUNNING_FOR_LOGIN_SCREEN;
- socket_fd_ = std::move(socket_fd);
} else {
// Start() has been called.
VLOG(2) << "Resuming an existing ARC instance";
state_ = State::STARTING_INSTANCE;
SendStartArcInstanceDBusMessage(
- false /* not for login screen */,
+ false /* instance_is_for_login_screen */,
base::Bind(&ArcSessionImpl::OnInstanceStarted,
- weak_factory_.GetWeakPtr(), false /* the same */,
- base::Passed(&socket_fd_)));
+ weak_factory_.GetWeakPtr(),
+ false /* instance_is_for_login_screen */));
}
return;
}
@@ -518,9 +425,16 @@ void ArcSessionImpl::OnInstanceStarted(
return;
}
+ // For production, |socket_fd| passed from session_manager is either a valid
+ // socket or a valid file descriptor (/dev/null). For testing, |socket_fd|
+ // might be invalid.
+ mojo::edk::PlatformHandle raw_handle(socket_fd.release());
+ raw_handle.needs_connection = true;
+
+ mojo::edk::ScopedPlatformHandle mojo_socket_fd(raw_handle);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
- base::Bind(&ArcSessionImpl::ConnectMojo, base::Passed(&socket_fd),
+ base::Bind(&ArcSessionImpl::ConnectMojo, base::Passed(&mojo_socket_fd),
base::Passed(&cancel_fd)),
base::Bind(&ArcSessionImpl::OnMojoConnected, weak_factory_.GetWeakPtr()));
}
@@ -620,15 +534,12 @@ void ArcSessionImpl::Stop() {
OnStopped(ArcStopReason::SHUTDOWN);
return;
- case State::CREATING_SOCKET:
case State::STARTING_INSTANCE:
// Before starting the ARC instance, we do nothing here.
// At some point, a callback will be invoked on UI thread,
// and stopping procedure will be run there.
// On Chrome shutdown, it is not the case because the message loop is
// already stopped here. Practically, it is not a problem because;
- // - On socket creating, it is ok to simply ignore such cases,
- // because we no-longer continue the bootstrap procedure.
// - On starting instance, the container instance can be leaked.
// Practically it is not problematic because the session manager will
// clean it up.
@@ -640,7 +551,7 @@ void ArcSessionImpl::Stop() {
return;
case State::CONNECTING_MOJO:
- // Mojo connection is being waited on a BlockingPool thread.
+ // Mojo connection is being waited on TaskScheduler's thread.
// Request to cancel it. Following stopping procedure will run
// in its callback.
accept_cancel_pipe_.reset();
@@ -690,7 +601,7 @@ void ArcSessionImpl::ArcInstanceStopped(
container_instance_id_.clear();
// In case that crash happens during before the Mojo channel is connected,
- // unlock the BlockingPool thread.
+ // unlock the TaskScheduler's thread.
accept_cancel_pipe_.reset();
ArcStopReason reason;
@@ -714,13 +625,12 @@ void ArcSessionImpl::StartForLoginScreen() {
DCHECK_EQ(State::NOT_STARTED, state_);
VLOG(2) << "Starting ARC session for login screen";
- VLOG(2) << "Creating socket...";
login_screen_instance_requested_ = true;
- state_ = State::CREATING_SOCKET;
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, {base::MayBlock()}, base::Bind(&ArcSessionImpl::CreateSocket),
- base::Bind(&ArcSessionImpl::OnSocketCreated, weak_factory_.GetWeakPtr(),
- true /* for login screen */));
+ state_ = State::STARTING_INSTANCE;
+ SendStartArcInstanceDBusMessage(
+ true /* instance_is_for_login_screen */,
+ base::Bind(&ArcSessionImpl::OnInstanceStarted, weak_factory_.GetWeakPtr(),
+ true /* instance_is_for_login_screen */));
}
bool ArcSessionImpl::IsForLoginScreen() {
@@ -746,8 +656,7 @@ void ArcSessionImpl::OnShutdown() {
// Here, the message loop is already stopped, and the Chrome will be soon
// shutdown. Thus, it is not necessary to take care about restarting case.
- // If ArcSession is waiting for mojo connection, cancels it. The BlockingPool
- // will be joined later.
+ // If ArcSession is waiting for mojo connection, cancels it.
accept_cancel_pipe_.reset();
// Stops the ARC instance to let it graceful shutdown.
diff --git a/chromium/components/arc/arc_session_runner.cc b/chromium/components/arc/arc_session_runner.cc
index c9af9939e28..ecdeff29a9d 100644
--- a/chromium/components/arc/arc_session_runner.cc
+++ b/chromium/components/arc/arc_session_runner.cc
@@ -8,6 +8,7 @@
#include "base/memory/ref_counted.h"
#include "base/task_runner.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/arc/arc_util.h"
namespace arc {
@@ -142,6 +143,11 @@ bool ArcSessionRunner::IsStopped() const {
return state_ == State::STOPPED;
}
+bool ArcSessionRunner::IsLoginScreenInstanceStarting() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return state_ == State::STARTING_FOR_LOGIN_SCREEN;
+}
+
void ArcSessionRunner::SetRestartDelayForTesting(
const base::TimeDelta& restart_delay) {
DCHECK_EQ(state_, State::STOPPED);
@@ -165,6 +171,14 @@ void ArcSessionRunner::StartArcSession() {
arc_session_->Start();
}
+void ArcSessionRunner::RestartArcSession() {
+ VLOG(0) << "Restarting ARC instance";
+ // The order is important here. Call StartArcSession(), then notify observers.
+ StartArcSession();
+ for (auto& observer : observer_list_)
+ observer.OnSessionRestarting();
+}
+
void ArcSessionRunner::OnSessionReady() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(state_, State::STARTING);
@@ -211,7 +225,7 @@ void ArcSessionRunner::OnSessionStopped(ArcStopReason stop_reason) {
// PostTask, because observer callback may call RequestStart()/Stop().
VLOG(0) << "ARC restarting";
restart_timer_.Start(FROM_HERE, restart_delay_,
- base::Bind(&ArcSessionRunner::StartArcSession,
+ base::Bind(&ArcSessionRunner::RestartArcSession,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -223,17 +237,20 @@ void ArcSessionRunner::OnSessionStopped(ArcStopReason stop_reason) {
}
void ArcSessionRunner::EmitLoginPromptVisibleCalled() {
+ if (ShouldArcOnlyStartAfterLogin()) {
+ // Skip starting ARC for now. We'll have another chance to start the full
+ // instance after the user logs in.
+ return;
+ }
// Since 'login-prompt-visible' Upstart signal starts all Upstart jobs the
// container may depend on such as cras, EmitLoginPromptVisibleCalled() is the
// safe place to start the container for login screen.
DCHECK(!arc_session_);
DCHECK_EQ(state_, State::STOPPED);
-
- // TODO(yusukes): Once Chrome OS side is ready, uncomment the following:
- // arc_session_ = factory_.Run();
- // arc_session_->AddObserver(this);
- // state_ = State::STARTING_FOR_LOGIN_SCREEN;
- // arc_session_->StartForLoginScreen();
+ arc_session_ = factory_.Run();
+ arc_session_->AddObserver(this);
+ state_ = State::STARTING_FOR_LOGIN_SCREEN;
+ arc_session_->StartForLoginScreen();
}
} // namespace arc
diff --git a/chromium/components/arc/arc_session_runner.h b/chromium/components/arc/arc_session_runner.h
index 13bf3ea575a..994b465e0f5 100644
--- a/chromium/components/arc/arc_session_runner.h
+++ b/chromium/components/arc/arc_session_runner.h
@@ -32,6 +32,11 @@ class ArcSessionRunner : public ArcSession::Observer,
// RequestStop(), so may be called multiple times for one RequestStart().
virtual void OnSessionStopped(ArcStopReason reason, bool restarting) = 0;
+ // Called when ARC session is stopped, but is being restarted automatically.
+ // Unlike OnSessionStopped() with |restarting| == true, this is called
+ // _after_ the container is actually created.
+ virtual void OnSessionRestarting() = 0;
+
protected:
virtual ~Observer() = default;
};
@@ -66,6 +71,9 @@ class ArcSessionRunner : public ArcSession::Observer,
bool IsRunning() const;
bool IsStopped() const;
+ // Returns whether LoginScreen instance is starting.
+ bool IsLoginScreenInstanceStarting() const;
+
// Returns the current ArcSession instance for testing purpose.
ArcSession* GetArcSessionForTesting() { return arc_session_.get(); }
@@ -115,6 +123,9 @@ class ArcSessionRunner : public ArcSession::Observer,
// Starts to run an ARC instance.
void StartArcSession();
+ // Restarts an ARC instance.
+ void RestartArcSession();
+
// ArcSession::Observer:
void OnSessionReady() override;
void OnSessionStopped(ArcStopReason reason) override;
diff --git a/chromium/components/arc/arc_session_runner_unittest.cc b/chromium/components/arc/arc_session_runner_unittest.cc
index 144d0b0bb6f..ab2204c002e 100644
--- a/chromium/components/arc/arc_session_runner_unittest.cc
+++ b/chromium/components/arc/arc_session_runner_unittest.cc
@@ -29,6 +29,9 @@ class DoNothingObserver : public ArcSessionRunner::Observer {
void OnSessionStopped(ArcStopReason reason, bool restarting) override {
// Do nothing.
}
+ void OnSessionRestarting() override {
+ // Do nothing.
+ }
};
} // namespace
@@ -48,6 +51,7 @@ class ArcSessionRunnerTest : public testing::Test,
stop_reason_ = ArcStopReason::SHUTDOWN;
restarting_ = false;
stopped_called_ = false;
+ restarting_called_ = false;
// We inject FakeArcSession here so we do not need task_runner.
arc_session_runner_ =
@@ -80,6 +84,7 @@ class ArcSessionRunnerTest : public testing::Test,
}
bool stopped_called() { return stopped_called_; }
+ bool restarting_called() { return restarting_called_; }
void ResetArcSessionFactory(
const ArcSessionRunner::ArcSessionFactory& factory) {
@@ -109,11 +114,14 @@ class ArcSessionRunnerTest : public testing::Test,
stop_reason_ = stop_reason;
restarting_ = restarting;
stopped_called_ = true;
+ restarting_called_ = false;
}
+ void OnSessionRestarting() override { restarting_called_ = true; }
ArcStopReason stop_reason_;
bool restarting_;
bool stopped_called_;
+ bool restarting_called_;
std::unique_ptr<ArcSessionRunner> arc_session_runner_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -133,6 +141,7 @@ TEST_F(ArcSessionRunnerTest, Basic) {
void OnSessionStopped(ArcStopReason reason, bool restarting) override {
stopped_called_ = true;
}
+ void OnSessionRestarting() override {}
private:
bool stopped_called_ = false;
@@ -187,9 +196,7 @@ TEST_F(ArcSessionRunnerTest, BootFailure) {
}
// Does the same with the mini instance for login screen.
-// TODO(yusukes): Enable the test once EmitLoginPromptVisibleCalled() is fully
-// enabled.
-TEST_F(ArcSessionRunnerTest, DISABLED_BootFailureForLoginScreen) {
+TEST_F(ArcSessionRunnerTest, BootFailureForLoginScreen) {
ResetArcSessionFactory(
base::Bind(&ArcSessionRunnerTest::CreateBootFailureArcSession,
ArcStopReason::CRASH));
@@ -212,9 +219,7 @@ TEST_F(ArcSessionRunnerTest, DISABLED_BootFailureForLoginScreen) {
// Tests that RequestStart() works even after EmitLoginPromptVisibleCalled()
// is called.
-// TODO(yusukes): Enable the test once EmitLoginPromptVisibleCalled() is fully
-// enabled.
-TEST_F(ArcSessionRunnerTest, DISABLED_StartWithLoginScreenInstance) {
+TEST_F(ArcSessionRunnerTest, StartWithLoginScreenInstance) {
EXPECT_TRUE(arc_session_runner()->IsStopped());
chromeos::DBusThreadManager::Get()
@@ -259,8 +264,10 @@ TEST_F(ArcSessionRunnerTest, OnSessionStopped) {
arc_session()->StopWithReason(ArcStopReason::GENERIC_BOOT_FAILURE);
EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, stop_reason());
EXPECT_TRUE(restarting());
+ EXPECT_FALSE(restarting_called());
EXPECT_TRUE(arc_session_runner()->IsStopped());
base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(restarting_called());
EXPECT_TRUE(arc_session_runner()->IsRunning());
// Simulate crash.
@@ -268,14 +275,17 @@ TEST_F(ArcSessionRunnerTest, OnSessionStopped) {
arc_session()->StopWithReason(ArcStopReason::CRASH);
EXPECT_EQ(ArcStopReason::CRASH, stop_reason());
EXPECT_TRUE(restarting());
+ EXPECT_FALSE(restarting_called());
EXPECT_TRUE(arc_session_runner()->IsStopped());
base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(restarting_called());
EXPECT_TRUE(arc_session_runner()->IsRunning());
// Graceful stop.
arc_session_runner()->RequestStop(false);
EXPECT_EQ(ArcStopReason::SHUTDOWN, stop_reason());
EXPECT_FALSE(restarting());
+ EXPECT_FALSE(restarting_called());
EXPECT_TRUE(arc_session_runner()->IsStopped());
}
diff --git a/chromium/components/arc/arc_util.cc b/chromium/components/arc/arc_util.cc
index 0ebc98c1e2d..83436fe2d1e 100644
--- a/chromium/components/arc/arc_util.cc
+++ b/chromium/components/arc/arc_util.cc
@@ -33,6 +33,7 @@ constexpr char kAvailabilityOfficiallySupported[] = "officially-supported";
constexpr char kAlwaysStart[] = "always-start";
constexpr char kAlwaysStartWithNoPlayStore[] =
"always-start-with-no-play-store";
+constexpr char kOnlyStartAfterLogin[] = "only-start-after-login";
void SetArcCpuRestrictionCallback(
login_manager::ContainerCpuRestrictionState state,
@@ -106,6 +107,15 @@ void SetArcAlwaysStartForTesting(bool play_store_available) {
play_store_available ? kAlwaysStart : kAlwaysStartWithNoPlayStore);
}
+bool ShouldArcOnlyStartAfterLogin() {
+ const auto* command_line = base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(chromeos::switches::kArcStartMode))
+ return false;
+ const std::string value =
+ command_line->GetSwitchValueASCII(chromeos::switches::kArcStartMode);
+ return value == kOnlyStartAfterLogin;
+}
+
bool IsArcKioskAvailable() {
const auto* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chromium/components/arc/arc_util.h b/chromium/components/arc/arc_util.h
index 6b2f6acc945..7558ac3944d 100644
--- a/chromium/components/arc/arc_util.h
+++ b/chromium/components/arc/arc_util.h
@@ -51,6 +51,9 @@ bool ShouldArcAlwaysStart();
// Store UI is added.
void SetArcAlwaysStartForTesting(bool play_store_available);
+// Returns true if ARC should only start after the user has logged in.
+bool ShouldArcOnlyStartAfterLogin();
+
// Returns true if ARC is installed and running ARC kiosk apps on the current
// device is officially supported.
// It doesn't follow that ARC is available for user sessions and
@@ -93,6 +96,7 @@ bool IsArcAppWindow(aura::Window* window);
// Adjusts the amount of CPU the ARC instance is allowed to use. When
// |do_restrict| is true, the limit is adjusted so ARC can only use tightly
// restricted CPU resources.
+// TODO(yusukes): Use enum instead of bool.
void SetArcCpuRestriction(bool do_restrict);
} // namespace arc
diff --git a/chromium/components/arc/audio/DEPS b/chromium/components/arc/audio/DEPS
index dc121e766b9..5ff5c5b2fa8 100644
--- a/chromium/components/arc/audio/DEPS
+++ b/chromium/components/arc/audio/DEPS
@@ -1,4 +1,4 @@
include_rules = [
- "+ash",
+ "+ash/system/audio/tray_audio.h",
"+chromeos/audio",
]
diff --git a/chromium/components/arc/audio/arc_audio_bridge.cc b/chromium/components/arc/audio/arc_audio_bridge.cc
index 432dad4b6b8..880acb390ae 100644
--- a/chromium/components/arc/audio/arc_audio_bridge.cc
+++ b/chromium/components/arc/audio/arc_audio_bridge.cc
@@ -56,13 +56,7 @@ ArcAudioBridge::ArcAudioBridge(content::BrowserContext* context,
ArcAudioBridge::~ArcAudioBridge() {
if (cras_audio_handler_)
cras_audio_handler_->RemoveAudioObserver(this);
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->audio()->RemoveObserver(this);
+ arc_bridge_service_->audio()->RemoveObserver(this);
}
void ArcAudioBridge::OnInstanceReady() {
diff --git a/chromium/components/arc/audio/arc_audio_bridge.h b/chromium/components/arc/audio/arc_audio_bridge.h
index c49cd8829b7..7938f6f57e0 100644
--- a/chromium/components/arc/audio/arc_audio_bridge.h
+++ b/chromium/components/arc/audio/arc_audio_bridge.h
@@ -9,7 +9,6 @@
#include "base/macros.h"
#include "chromeos/audio/cras_audio_handler.h"
-#include "components/arc/arc_service.h"
#include "components/arc/common/audio.mojom.h"
#include "components/arc/instance_holder.h"
#include "components/keyed_service/core/keyed_service.h"
diff --git a/chromium/components/arc/bitmap/bitmap_struct_traits.h b/chromium/components/arc/bitmap/bitmap_struct_traits.h
index 7aefb77f8c8..141251d94b6 100644
--- a/chromium/components/arc/bitmap/bitmap_struct_traits.h
+++ b/chromium/components/arc/bitmap/bitmap_struct_traits.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
#define COMPONENTS_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
+#include "base/containers/span.h"
#include "components/arc/common/bitmap.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -12,12 +13,11 @@ namespace mojo {
template <>
struct StructTraits<arc::mojom::ArcBitmapDataView, SkBitmap> {
- static const mojo::CArray<uint8_t> pixel_data(const SkBitmap& r) {
+ static const base::span<const uint8_t> pixel_data(const SkBitmap& r) {
const SkImageInfo& info = r.info();
DCHECK_EQ(info.colorType(), kRGBA_8888_SkColorType);
- return mojo::CArray<uint8_t>(
- r.getSize(), r.getSize(), static_cast<uint8_t*>(r.getPixels()));
+ return base::make_span(static_cast<uint8_t*>(r.getPixels()), r.getSize());
}
static uint32_t width(const SkBitmap& r) { return r.width(); }
static uint32_t height(const SkBitmap& r) { return r.height(); }
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
index 37d95bf886f..c09ac04fef0 100644
--- a/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
@@ -4,13 +4,13 @@
#include "components/arc/bluetooth/bluetooth_struct_traits.h"
-#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_advertisement.h"
@@ -27,9 +27,7 @@ bool IsNonHex(char c) {
std::string StripNonHex(const std::string& str) {
std::string result = str;
- result.erase(std::remove_if(result.begin(), result.end(), IsNonHex),
- result.end());
-
+ base::EraseIf(result, IsNonHex);
return result;
}
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
index 03cbd21ffb9..d61499788ea 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <algorithm>
#include <cctype>
#include <iomanip>
#include <ios>
@@ -12,6 +11,7 @@
#include <vector>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/arc/bluetooth/bluetooth_type_converters.h"
@@ -36,9 +36,7 @@ bool IsNonHex(char c) {
std::string StripNonHex(const std::string& str) {
std::string result = str;
- result.erase(std::remove_if(result.begin(), result.end(), IsNonHex),
- result.end());
-
+ base::EraseIf(result, IsNonHex);
return result;
}
diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
index 40f5932aa18..2ad80c7d6c0 100644
--- a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -5,20 +5,27 @@
#include "components/arc/clipboard/arc_clipboard_bridge.h"
#include <utility>
+#include <vector>
+#include "base/auto_reset.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_checker.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/clipboard_types.h"
+#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
namespace arc {
namespace {
+// Payload in an Android Binder Parcel should be less than 800 Kb. Save 512
+// bytes for headers, descriptions and mime types.
+constexpr size_t kMaxBinderParcelSizeInBytes = 800 * 1024 - 512;
+constexpr char kMimeTypeTextError[] = "text/error";
+constexpr char kErrorSizeTooBigForBinder[] = "size too big for binder";
+
// Singleton factory for ArcClipboardBridge.
class ArcClipboardBridgeFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase<
@@ -38,6 +45,100 @@ class ArcClipboardBridgeFactory
~ArcClipboardBridgeFactory() override = default;
};
+mojom::ClipRepresentationPtr CreateHTML(const ui::Clipboard* clipboard) {
+ DCHECK(clipboard);
+
+ base::string16 markup16;
+ // Unused. URL is sent from CreatePlainText() by reading it from the Bookmark.
+ std::string url;
+ uint32_t fragment_start, fragment_end;
+
+ clipboard->ReadHTML(ui::CLIPBOARD_TYPE_COPY_PASTE, &markup16, &url,
+ &fragment_start, &fragment_end);
+
+ std::string text(base::UTF16ToUTF8(
+ markup16.substr(fragment_start, fragment_end - fragment_start)));
+
+ std::string mime_type(ui::Clipboard::kMimeTypeHTML);
+
+ // Send non-sanitized HTML content. Instance should sanitize it if needed.
+ return mojom::ClipRepresentation::New(mime_type,
+ mojom::ClipValue::NewText(text));
+}
+
+mojom::ClipRepresentationPtr CreatePlainText(const ui::Clipboard* clipboard) {
+ DCHECK(clipboard);
+
+ // Unused. Title is not used at Instance.
+ base::string16 title;
+ std::string text;
+ std::string mime_type(ui::Clipboard::kMimeTypeText);
+
+ // Both Bookmark and AsciiText are represented by text/plain. If both are
+ // present, only use Bookmark.
+ clipboard->ReadBookmark(&title, &text);
+ if (text.size() == 0)
+ clipboard->ReadAsciiText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
+
+ return mojom::ClipRepresentation::New(mime_type,
+ mojom::ClipValue::NewText(text));
+}
+
+void ProcessHTML(const mojom::ClipRepresentation* repr,
+ ui::ScopedClipboardWriter* writer) {
+ DCHECK(repr);
+ DCHECK(repr->value->is_text());
+ DCHECK(writer);
+
+ writer->WriteHTML(base::UTF8ToUTF16(repr->value->get_text()), std::string());
+}
+
+void ProcessPlainText(const mojom::ClipRepresentation* repr,
+ ui::ScopedClipboardWriter* writer) {
+ DCHECK(repr);
+ DCHECK(repr->value->is_text());
+ DCHECK(writer);
+
+ writer->WriteText(base::UTF8ToUTF16(repr->value->get_text()));
+}
+
+bool DoesClipFitIntoInstance(const mojom::ClipDataPtr& clip_data) {
+ // Checks whether the ClipData will fit at Instance's Binder.Parcel.
+ // (See: android.os.Binder.java # checkParcel() for details).
+ //
+ // It calculates an upper-bound limit by multiplying UTF8 strings' size by 2.
+ //
+ // A precise check could be done at Instance, but it will require:
+ // 1: Sending the Clip via Mojo to Instance (memory * 2 + time O(memory))
+ // 2: Converting the char* (UTF8) to Java UTF16 Strings (memory * 2 again +
+ // time O(memory))
+ // 3: Creating a temp Parcel with the clip data (memory * 2 again +
+ // time O(memory))
+ //
+ // An estimate (non-precise) check could be done at Instance as well, but will
+ // require at least steps 1 and 2.
+ //
+ // A simple screenshot + copy to clipboard at Host could take about 4Mb, since
+ // it is encoded in an HTML <IMG> tag.
+ //
+ // The purpose of this hack, is to avoid sending and converting this 4Mb
+ // several times.
+
+ // TODO(ricardoq): Instead of doing UTF8.size() * 2, get the real size from
+ // the unconverted UTF16 string.
+
+ size_t size_at_instance_in_bytes = 0;
+ for (const auto& repr : clip_data->representations) {
+ if (repr->value->is_text())
+ size_at_instance_in_bytes +=
+ repr->value->get_text().size() * sizeof(base::string16::value_type);
+ else
+ size_at_instance_in_bytes += repr->value->get_blob().size();
+ }
+
+ return size_at_instance_in_bytes < kMaxBinderParcelSizeInBytes;
+}
+
} // namespace
// static
@@ -48,19 +149,17 @@ ArcClipboardBridge* ArcClipboardBridge::GetForBrowserContext(
ArcClipboardBridge::ArcClipboardBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service)
- : arc_bridge_service_(bridge_service), binding_(this) {
+ : arc_bridge_service_(bridge_service),
+ binding_(this),
+ event_originated_at_instance_(false) {
arc_bridge_service_->clipboard()->AddObserver(this);
+ ui::ClipboardMonitor::GetInstance()->AddObserver(this);
}
ArcClipboardBridge::~ArcClipboardBridge() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->clipboard()->RemoveObserver(this);
+ ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
+ arc_bridge_service_->clipboard()->RemoveObserver(this);
}
void ArcClipboardBridge::OnInstanceReady() {
@@ -72,13 +171,35 @@ void ArcClipboardBridge::OnInstanceReady() {
clipboard_instance->Init(std::move(host_proxy));
}
-void ArcClipboardBridge::SetTextContent(const std::string& text) {
+void ArcClipboardBridge::OnClipboardDataChanged() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (event_originated_at_instance_) {
+ // Ignore this event, since this event was triggered by a 'copy' in
+ // Instance, and not by Host.
+ return;
+ }
+
+ mojom::ClipboardInstance* clipboard_instance = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_bridge_service_->clipboard(), OnHostClipboardUpdated);
+ if (!clipboard_instance)
+ return;
+
+ // TODO(ricardoq): should only inform Instance when a supported mime_type is
+ // copied to the clipboard.
+ clipboard_instance->OnHostClipboardUpdated();
+}
+
+void ArcClipboardBridge::SetTextContentDeprecated(const std::string& text) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // Order is important. AutoReset should outlive ScopedClipboardWriter.
+ base::AutoReset<bool> auto_reset(&event_originated_at_instance_, true);
ui::ScopedClipboardWriter writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
writer.WriteText(base::UTF8ToUTF16(text));
}
-void ArcClipboardBridge::GetTextContent() {
+void ArcClipboardBridge::GetTextContentDeprecated() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::string16 text;
@@ -86,10 +207,68 @@ void ArcClipboardBridge::GetTextContent() {
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
mojom::ClipboardInstance* clipboard_instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_bridge_service_->clipboard(), OnGetTextContent);
+ arc_bridge_service_->clipboard(), OnGetTextContentDeprecated);
if (!clipboard_instance)
return;
- clipboard_instance->OnGetTextContent(base::UTF16ToUTF8(text));
+ clipboard_instance->OnGetTextContentDeprecated(base::UTF16ToUTF8(text));
+}
+
+void ArcClipboardBridge::SetClipContent(mojom::ClipDataPtr clip_data) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ if (!clipboard)
+ return;
+
+ // Order is important. AutoReset should outlive ScopedClipboardWriter.
+ base::AutoReset<bool> auto_reset(&event_originated_at_instance_, true);
+ ui::ScopedClipboardWriter writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
+
+ for (const auto& repr : clip_data->representations) {
+ const std::string& mime_type(repr->mime_type);
+ if (mime_type == ui::Clipboard::kMimeTypeHTML) {
+ ProcessHTML(repr.get(), &writer);
+ } else if (mime_type == ui::Clipboard::kMimeTypeText) {
+ ProcessPlainText(repr.get(), &writer);
+ }
+ }
+}
+
+void ArcClipboardBridge::GetClipContent(
+ const GetClipContentCallback& callback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ std::vector<base::string16> mime_types;
+ bool contains_files;
+ clipboard->ReadAvailableTypes(ui::CLIPBOARD_TYPE_COPY_PASTE, &mime_types,
+ &contains_files);
+
+ mojom::ClipDataPtr clip_data(mojom::ClipData::New());
+
+ // Populate ClipData with ClipRepresentation objects.
+ for (const auto& mime_type16 : mime_types) {
+ const std::string mime_type(base::UTF16ToUTF8(mime_type16));
+ if (mime_type == ui::Clipboard::kMimeTypeHTML) {
+ clip_data->representations.push_back(CreateHTML(clipboard));
+ } else if (mime_type == ui::Clipboard::kMimeTypeText) {
+ clip_data->representations.push_back(CreatePlainText(clipboard));
+ } else {
+ // TODO(ricardoq): Add other supported mime_types here.
+ DLOG(WARNING) << "Unsupported mime type: " << mime_type;
+ }
+ }
+
+ if (!DoesClipFitIntoInstance(clip_data)) {
+ clip_data->representations.clear();
+ clip_data->representations.push_back(mojom::ClipRepresentation::New(
+ kMimeTypeTextError,
+ mojom::ClipValue::NewText(kErrorSizeTooBigForBinder)));
+ }
+
+ // Invoke the |callback|, even if |clip_data| is empty, since Instance is
+ // waiting for a response.
+ callback.Run(std::move(clip_data));
}
} // namespace arc
diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.h b/chromium/components/arc/clipboard/arc_clipboard_bridge.h
index 4ac2e4dd1e0..29552559361 100644
--- a/chromium/components/arc/clipboard/arc_clipboard_bridge.h
+++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.h
@@ -8,10 +8,12 @@
#include <string>
#include "base/macros.h"
+#include "base/threading/thread_checker.h"
#include "components/arc/common/clipboard.mojom.h"
#include "components/arc/instance_holder.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/base/clipboard/clipboard_observer.h"
namespace content {
class BrowserContext;
@@ -23,6 +25,7 @@ class ArcBridgeService;
class ArcClipboardBridge
: public KeyedService,
+ public ui::ClipboardObserver,
public InstanceHolder<mojom::ClipboardInstance>::Observer,
public mojom::ClipboardHost {
public:
@@ -38,16 +41,23 @@ class ArcClipboardBridge
// InstanceHolder<mojom::ClipboardInstance>::Observer overrides.
void OnInstanceReady() override;
+ // ClipboardObserver overrides.
+ void OnClipboardDataChanged() override;
+
// mojom::ClipboardHost overrides.
- void SetTextContent(const std::string& text) override;
- void GetTextContent() override;
+ void SetTextContentDeprecated(const std::string& text) override;
+ void GetTextContentDeprecated() override;
+ void SetClipContent(mojom::ClipDataPtr clip_data) override;
+ void GetClipContent(const GetClipContentCallback& callback) override;
private:
- THREAD_CHECKER(thread_checker_);
-
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
mojo::Binding<mojom::ClipboardHost> binding_;
+ bool event_originated_at_instance_;
+
+ THREAD_CHECKER(thread_checker_);
+
DISALLOW_COPY_AND_ASSIGN(ArcClipboardBridge);
};
diff --git a/chromium/components/arc/common/ARC_SECURITY_OWNERS b/chromium/components/arc/common/ARC_SECURITY_OWNERS
new file mode 100644
index 00000000000..f3326cf1a52
--- /dev/null
+++ b/chromium/components/arc/common/ARC_SECURITY_OWNERS
@@ -0,0 +1,4 @@
+# Prefer ARC++ security owners for changes to ARC++ IPC.
+jorgelo@chromium.org
+kerrnel@chromium.org
+mnissler@chromium.org
diff --git a/chromium/components/arc/common/OWNERS b/chromium/components/arc/common/OWNERS
index 253d9465a02..539b2efbb79 100644
--- a/chromium/components/arc/common/OWNERS
+++ b/chromium/components/arc/common/OWNERS
@@ -1,8 +1,11 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *.mojom=file:ARC_SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
+per-file *.typemap=file:ARC_SECURITY_OWNERS
per-file *_struct_traits*.*=set noparent
per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=file:ARC_SECURITY_OWNERS
diff --git a/chromium/components/arc/common/accessibility_helper.mojom b/chromium/components/arc/common/accessibility_helper.mojom
index 4fdba278e07..2d73828028d 100644
--- a/chromium/components/arc/common/accessibility_helper.mojom
+++ b/chromium/components/arc/common/accessibility_helper.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: 4
+// Next MinVersion: 5
module arc.mojom;
@@ -210,7 +210,7 @@ interface AccessibilityHelperHost {
OnAccessibilityEvent@1(AccessibilityEventData event_data);
};
-// Next method ID: 4
+// Next method ID: 5
interface AccessibilityHelperInstance {
Init@0(AccessibilityHelperHost host);
@@ -219,6 +219,9 @@ interface AccessibilityHelperInstance {
// Set a filter on the event types received.
SetFilter@2(AccessibilityFilterType filter_type);
+ [MinVersion=3]PerformActionDeprecated2@3(AccessibilityActionData action_data);
+
// Perform an action on a node requested by a Chrome client.
- [MinVersion=3]PerformAction@3(AccessibilityActionData action_data);
+ [MinVersion=4]PerformAction@4(AccessibilityActionData action_data)
+ => (bool result);
};
diff --git a/chromium/components/arc/common/app.mojom b/chromium/components/arc/common/app.mojom
index bfdf4ecf507..48b66bb8baf 100644
--- a/chromium/components/arc/common/app.mojom
+++ b/chromium/components/arc/common/app.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: 23
+// Next MinVersion: 24
module arc.mojom;
@@ -186,16 +186,13 @@ interface AppHost {
};
// TODO(lhchavez): Migrate all request/response messages to Mojo.
-// Next method ID: 18
-// Deprecated method ID: 9
+// Next method ID: 21
interface AppInstance {
Init@0(AppHost host_ptr);
- // Query if a given resolution can be handled by the application. Returns true
- // if it can.
- [MinVersion=1] CanHandleResolution@4(string package_name, string activity,
- ScreenRect dimension) =>
- (bool can_handle);
+ [MinVersion=1] CanHandleResolutionDeprecated@4(
+ string package_name, string activity, ScreenRect dimension) =>
+ (bool can_handle);
// Closes the the given task.
[MinVersion=4] CloseTask@8(int32 task_id);
@@ -207,16 +204,20 @@ interface AppInstance {
// Sends a request to ARC to install package.
[MinVersion=8] InstallPackage@11(ArcPackageInfo arcPackageInfo);
+ LaunchAppDeprecated@1(string package_name, string activity,
+ [MinVersion=1] ScreenRect? dimension_on_screen);
+
// Sends a request to ARC to launch an ARC app defined by |package_name| and
- // |activity|, which cannot be empty. |dimension_on_screen| can be null to
- // indicate to use the entire screen.
- LaunchApp@1(string package_name, string activity,
- [MinVersion=1] ScreenRect? dimension_on_screen);
+ // |activity|, which cannot be empty.
+ [MinVersion=23] LaunchApp@18(string package_name, string activity,
+ int64 display_id);
- // Sends a reqeust to ARC to launch an intent. The intent is encoded as a
- // Uri string, see Intent.toUri().
- [MinVersion=9] LaunchIntent@12(string intent_uri,
- ScreenRect? dimension_on_screen);
+ [MinVersion=9] LaunchIntentDeprecated@12(string intent_uri,
+ ScreenRect? dimension_on_screen);
+
+ // Sends a request to ARC to launch an intent. The intent is encoded as a URI
+ // string. See Intent.toUri().
+ [MinVersion=23] LaunchIntent@19(string intent_uri, int64 display_id);
// Sends a request to ARC to refresh a list of ARC apps.
// OnRefreshAppsList is expected in response to this message. However,
@@ -242,15 +243,18 @@ interface AppInstance {
// Activates the given task and move it to foreground.
[MinVersion=4] SetTaskActive@7(int32 task_id);
- // Sends a request to ARC to show package info for given package.
[MinVersion=5] ShowPackageInfoDeprecated@9(string package_name,
ScreenRect dimension_on_screen);
+ [MinVersion=10] ShowPackageInfoOnPageDeprecated@15(string package_name,
+ ShowPackageInfoPage page,
+ ScreenRect dimension_on_screen);
+
// Sends a request to ARC to show package info for given package on the
// specified page.
- [MinVersion=10] ShowPackageInfoOnPage@15(string package_name,
+ [MinVersion=23] ShowPackageInfoOnPage@20(string package_name,
ShowPackageInfoPage page,
- ScreenRect dimension_on_screen);
+ int64 display_id);
// Sets notification setting for the package.
[MinVersion=6] SetNotificationsEnabled@10(string package_name, bool enabled);
diff --git a/chromium/components/arc/common/arc_bridge.mojom b/chromium/components/arc/common/arc_bridge.mojom
index c30c3ae2749..160c87bd06f 100644
--- a/chromium/components/arc/common/arc_bridge.mojom
+++ b/chromium/components/arc/common/arc_bridge.mojom
@@ -10,6 +10,7 @@ import "audio.mojom";
import "auth.mojom";
import "bluetooth.mojom";
import "boot_phase_monitor.mojom";
+import "cast_receiver.mojom";
import "clipboard.mojom";
import "crash_collector.mojom";
import "enterprise_reporting.mojom";
@@ -22,6 +23,7 @@ import "metrics.mojom";
import "net.mojom";
import "notifications.mojom";
import "obb_mounter.mojom";
+import "oemcrypto.mojom";
import "policy.mojom";
import "power.mojom";
import "print.mojom";
@@ -63,6 +65,10 @@ interface ArcBridgeHost {
[MinVersion=19] OnBootPhaseMonitorInstanceReady@125(
BootPhaseMonitorInstance instance_ptr);
+ // Notifies Chrome that the CastReceiverInstance interface is ready.
+ [MinVersion=27] OnCastReceiverInstanceReady@132(
+ CastReceiverInstance instance_ptr);
+
// Notifies Chrome that the ClipboardInstance interface is ready.
[MinVersion=2] OnClipboardInstanceReady@109(ClipboardInstance instance_ptr);
@@ -103,6 +109,9 @@ interface ArcBridgeHost {
// Notifies Chrome that the ObbMounter interface is ready.
[MinVersion=14] OnObbMounterInstanceReady@120(ObbMounterInstance instance_ptr);
+ // Notifies Chrome that the OemCryptoInstance interface is ready.
+ [MinVersion=28] OnOemCryptoInstanceReady@133(OemCryptoInstance instance_ptr);
+
// Notifies Chrome that the PolicyInstance interface is ready.
[MinVersion=7] OnPolicyInstanceReady@114(PolicyInstance instance_ptr);
diff --git a/chromium/components/arc/common/cast_receiver.mojom b/chromium/components/arc/common/cast_receiver.mojom
new file mode 100644
index 00000000000..3801a1fcb2a
--- /dev/null
+++ b/chromium/components/arc/common/cast_receiver.mojom
@@ -0,0 +1,29 @@
+// 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.
+
+// Next MinVersion: 1
+module arc.mojom;
+
+// Next Method ID: 3
+interface CastReceiverInstance {
+ [Extensible]
+ enum Result {
+ SUCCESS = 0,
+ FAILURE = 1,
+ UNKNOWN = 2, // E.g. the operation was interrupted.
+ CAST_NOT_FOUND = 3, // Retrying won't help.
+ CAST_UNAVAILABLE = 4, // Could be disconnected or claimed.
+ };
+
+ // Gets the receiver name.
+ GetName@3() => (Result result, string name);
+
+ // Sets whether the receiver is enabled or not. Enabling the receiver will
+ // start it if needed.
+ SetEnabled@1(bool enabled) => (Result result);
+
+ // Sets the receiver name. If the name is blank, the receiver name will be
+ // set to the device name.
+ SetName@2(string name) => (Result result);
+};
diff --git a/chromium/components/arc/common/clipboard.mojom b/chromium/components/arc/common/clipboard.mojom
index 47304d8507b..d10183e1a26 100644
--- a/chromium/components/arc/common/clipboard.mojom
+++ b/chromium/components/arc/common/clipboard.mojom
@@ -2,23 +2,75 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+
module arc.mojom;
+// |ClipData| contains one or more |ClipRepresentation| objects. Each
+// |ClipRepresentation| has a |mime_type| and a |ClipValue|. |ClipValue| is
+// either a |blob| or a |text|.
+
+// Value for |ClipRepresentation|.
+// Next MinVersion: 1
+// Next ID: 2
+union ClipValue {
+ // For images and other opaque structures.
+ array<uint8> blob@0;
+ // For html, text and other text-based representations.
+ string text@1;
+};
+
+// One possible representation of the |ClipData|: |mime_type| + its |value|.
+// Next MinVersion: 1
+// Next ID: 2
+struct ClipRepresentation {
+ // The mime type.
+ string mime_type@0;
+ // And its value.
+ ClipValue value@1;
+};
+
+// The |ClipData| to transfer.
+// Next MinVersion: 1
+// Next ID: 1
+struct ClipData {
+ // A |ClipData| could have multiple representations.
+ // Example: an image could be represented by an image/png and a text/html
+ array<ClipRepresentation> representations@0;
+};
+
+// Next MinVersion: 2
+// Next method ID: 4
+// IDs to be removed 18 weeks after being up revved: 0, 1
interface ClipboardHost {
// Tells the host to change its content, usually when the user initiates
// a 'copy' action.
- SetTextContent@0(string text);
+ SetTextContentDeprecated@0(string text);
// Tells the host to return its content, usually when the user initiates
// a 'paste' action or when the instance needs to re-sync its clipboard
// content with the host.
- GetTextContent@1();
+ GetTextContentDeprecated@1();
+
+ // Tells the host to update its clipboard content, usually when the user
+ // initiates a 'copy' action.
+ [MinVersion=1] SetClipContent@2(ClipData data);
+
+ // Tells the host to return its clipboard content, usually when the user
+ // initiates a 'paste' action or when the instance needs to re-sync its
+ // clipboard content with the host.
+ [MinVersion=1] GetClipContent@3() => (ClipData data);
};
+// Next MinVersion: 2
+// Next method ID: 3
+// IDs to be removed 18 weeks after being up revved: 1
interface ClipboardInstance {
// Establishes full-duplex communication with the host.
Init@0(ClipboardHost host_ptr);
- // Pass the result of ClipboardHost.GetTextContent().
- OnGetTextContent@1(string returnedText);
+ // Passes the result of ClipboardHost.GetTextContentDeprecated().
+ OnGetTextContentDeprecated@1(string returned_text);
+
+ // Tells that the Host clipboard has been updated.
+ [MinVersion=1] OnHostClipboardUpdated@2();
};
diff --git a/chromium/components/arc/common/oemcrypto.mojom b/chromium/components/arc/common/oemcrypto.mojom
new file mode 100644
index 00000000000..dd639c730fe
--- /dev/null
+++ b/chromium/components/arc/common/oemcrypto.mojom
@@ -0,0 +1,227 @@
+// 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.
+
+// The original version of this file lives in the Chrome OS repository at:
+// src/platform/arc-oemcrypto/mojo/oemcrypto.mojom
+
+// This file defines the mojo interface between Android, Chrome and the
+// Chrome OS daemon for the Widevine L1 OEMCrypto implementation used in ARC++.
+// This files matches what's in Widevine's OEMCryptoCENC.h file closely and all
+// methods are documented there.
+
+module arc.mojom;
+
+[Extensible]
+enum OemCryptoResult {
+ SUCCESS = 0,
+ ERROR_INIT_FAILED = 1,
+ ERROR_TERMINATE_FAILED = 2,
+ ERROR_OPEN_FAILURE = 3,
+ ERROR_CLOSE_FAILURE = 4,
+ ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5,
+ ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6,
+ ERROR_SHORT_BUFFER = 7,
+ ERROR_NO_DEVICE_KEY = 8,
+ ERROR_NO_ASSET_KEY = 9,
+ ERROR_KEYBOX_INVALID = 10,
+ ERROR_NO_KEYDATA = 11,
+ ERROR_NO_CW = 12,
+ ERROR_DECRYPT_FAILED = 13,
+ ERROR_WRITE_KEYBOX = 14,
+ ERROR_WRAP_KEYBOX = 15,
+ ERROR_BAD_MAGIC = 16,
+ ERROR_BAD_CRC = 17,
+ ERROR_NO_DEVICEID = 18,
+ ERROR_RNG_FAILED = 19,
+ ERROR_RNG_NOT_SUPPORTED = 20,
+ ERROR_SETUP = 21,
+ ERROR_OPEN_SESSION_FAILED = 22,
+ ERROR_CLOSE_SESSION_FAILED = 23,
+ ERROR_INVALID_SESSIONS = 24,
+ ERROR_NOT_IMPLEMENTED = 25,
+ ERROR_NO_CONTENT_KEY = 26,
+ ERROR_CONTROL_INVALID = 27,
+ ERROR_UNKNOWN_FAILURE = 28,
+ ERROR_INVALID_CONTEXT = 29,
+ ERROR_SIGNATURE_FAILURE = 30,
+ ERROR_TOO_MANY_SESSIONS = 31,
+ ERROR_INVALID_NONCE = 32,
+ ERROR_TOO_MANY_KEYS = 33,
+ ERROR_DEVICE_NOT_RSA_PROVISIONED = 34,
+ ERROR_INVALID_RSA_KEY = 35,
+ ERROR_KEY_EXPIRED = 36,
+ ERROR_INSUFFICIENT_RESOURCES = 37,
+ ERROR_INSUFFICIENT_HDCP = 38,
+};
+
+struct OemCryptoSecureBuffer {
+ // TODO(jkardatzke): Add a comment which explains what the buffer_handle
+ // means once the specific implementation is determined.
+ uint64 buffer_handle;
+ uint32 max_length;
+ uint32 offset;
+};
+
+[Extensible]
+enum OemCryptoCipherMode {
+ CIPHER_MODE_CTR = 0,
+ CIPHER_MODE_CBC = 1,
+};
+
+struct OemCryptoKeyObject {
+ uint32 key_id_offset;
+ uint32 key_id_length;
+ uint32 key_data_iv_offset;
+ uint32 key_data_offset;
+ uint32 key_data_length;
+ uint32 key_control_iv_offset;
+ uint32 key_control_offset;
+ OemCryptoCipherMode cipher_mode;
+};
+
+struct OemCryptoKeyRefreshObject {
+ uint32 key_id_offset;
+ uint32 key_id_length;
+ bool has_key_control_iv;
+ uint32 key_control_iv_offset;
+ uint32 key_control_offset;
+};
+
+[Extensible]
+enum OemCryptoAlgorithm {
+ AES_CBC_128_NO_PADDING = 0,
+ HMAC_SHA265 = 1,
+};
+
+struct OemCryptoCencEncryptPatternDesc {
+ uint32 encrypt;
+ uint32 skip;
+ uint32 offset;
+};
+
+struct OemCryptoPstReport {
+ array<uint8, 20> signature;
+ uint8 status;
+ uint8 clock_security_level;
+ uint64 seconds_since_license_received;
+ uint64 seconds_since_first_decrypt;
+ uint64 seconds_since_last_decrypt;
+};
+
+[Extensible]
+enum OemCryptoRsaPaddingScheme {
+ SIGN_RSASSA_PSS = 1,
+ SIGN_PKCS1_BLOCK1 = 2,
+};
+
+[Extensible]
+enum OemCryptoHdcpCapability {
+ HDCP_NONE = 0,
+ HDCP_V1 = 1,
+ HDCP_V2 = 2,
+ HDCP_V2_1 = 3,
+ HDCP_V2_2 = 4,
+ HDCP_NO_DIGITAL_OUTPUT = 0xFF,
+};
+
+// Next method ID: 36
+interface OemCryptoService {
+ Initialize@0() => (OemCryptoResult result);
+ Terminate@1() => (OemCryptoResult result);
+ OpenSession@2() => (OemCryptoResult result, uint32 session);
+ CloseSession@3(uint32 session) => (OemCryptoResult result);
+ GenerateDerivedKeys@4(uint32 session, array<uint8> mac_key_context,
+ array<uint8> enc_key_context)
+ => (OemCryptoResult result);
+ GenerateNonce@5(uint32 session) => (OemCryptoResult result, uint32 nonce);
+ GenerateSignature@6(uint32 session, array<uint8> message)
+ => (OemCryptoResult result, array<uint8>? signature);
+ // The offset values are offsets into the message parameter for those values.
+ // If they have a length and it's zero, then they are NULL; if there is no
+ // length param then a bool param is there to indicate presence.
+ LoadKeys@7(uint32 session, array<uint8> message, array<uint8> signature,
+ bool has_enc_mac_keys, uint32 enc_mac_keys_iv_offset,
+ uint32 enc_mac_keys_offset, array<OemCryptoKeyObject> key_array,
+ uint32 pst_offset, uint32 pst_length)
+ => (OemCryptoResult result);
+ RefreshKeys@8(uint32 session, array<uint8> message, array<uint8> signature,
+ array<OemCryptoKeyRefreshObject> key_array)
+ => (OemCryptoResult result);
+ QueryKeyControl@9(uint32 session, array<uint8> key_id)
+ => (OemCryptoResult result, array<uint8>? key_control_block);
+ SelectKey@10(uint32 session, array<uint8> key_id)
+ => (OemCryptoResult result);
+ // For decrypting to a secure buffer, pass in the secure_buffer parameter,
+ // otherwise it will return the contents decrypted into a clear buffer in the
+ // returned array. It will only do that if the drm policy allows it.
+ DecryptCenc@11(uint32 session, array<uint8> data, bool is_encrypted,
+ array<uint8, 16> iv, uint32 block_offset,
+ OemCryptoSecureBuffer? secure_buffer,
+ OemCryptoCencEncryptPatternDesc pattern)
+ => (OemCryptoResult result, array<uint8>? decrypted_data);
+ GenericEncrypt@12(uint32 session, array<uint8> data, array<uint8, 16> iv,
+ OemCryptoAlgorithm algorithm) =>
+ (OemCryptoResult result, array<uint8>? encrypted_data);
+ GenericDecrypt@13(uint32 session, array<uint8> data, array<uint8, 16> iv,
+ OemCryptoAlgorithm algorithm) =>
+ (OemCryptoResult result, array<uint8>? decrypted_data);
+ GenericSign@14(uint32 session, array<uint8> data,
+ OemCryptoAlgorithm algorithm) =>
+ (OemCryptoResult result, array<uint8>? signature);
+ GenericVerify@15(uint32 session, array<uint8> data,
+ OemCryptoAlgorithm algorithm, array<uint8> signature) =>
+ (OemCryptoResult result);
+ CopyBuffer@16(array<uint8> data, OemCryptoSecureBuffer out_buffer)
+ => (OemCryptoResult result);
+ LoadTestKeybox@17() => (OemCryptoResult result);
+ IsKeyboxValid@18() => (OemCryptoResult result);
+ GetDeviceId@19() => (OemCryptoResult result, array<uint8>? device_id);
+ GetKeyData@20() => (OemCryptoResult result, array<uint8>? key_data);
+ GetRandom@21(uint32 length) => (OemCryptoResult result, array<uint8>? data);
+ GetNumberOfOpenSessions@22() => (OemCryptoResult result, uint32 num);
+ GetMaxNumberOfSessions@23() => (OemCryptoResult result, uint32 max);
+ RewrapDeviceRsaKey@24(uint32 session, array<uint8> message,
+ array<uint8> signature, uint32 nonce_offset,
+ uint32 enc_rsa_key_offset, uint32 enc_rsa_key_length,
+ uint32 enc_rsa_key_iv_offset)
+ => (OemCryptoResult result, array<uint8>? wrapped_key);
+ LoadDeviceRsaKey@25(uint32 session, array<uint8> wrapped_rsa_key)
+ => (OemCryptoResult result);
+ GenerateRsaSignature@26(uint32 session, array<uint8> message,
+ OemCryptoRsaPaddingScheme padding_scheme)
+ => (OemCryptoResult result, array<uint8>? signature);
+ DeriveKeysFromSessionKey@27(uint32 session, array<uint8> enc_session_key,
+ array<uint8> mac_key_context,
+ array<uint8> enc_key_context)
+ => (OemCryptoResult result);
+ SecurityPatchLevel@28() => (uint8 security_patch_level);
+ GetHdcpCapability@29() => (OemCryptoResult result,
+ OemCryptoHdcpCapability current,
+ OemCryptoHdcpCapability maximum);
+ UpdateUsageTable@30() => (OemCryptoResult result);
+ DeactivateUsageEntry@31(array<uint8> pst) => (OemCryptoResult result);
+ ReportUsage@32(uint32 session, array<uint8> pst)
+ => (OemCryptoResult result, OemCryptoPstReport? report);
+ DeleteUsageEntry@33(uint32 session, uint32 pst_offset, uint32 pst_length,
+ array<uint8> message, array<uint8> signature) =>
+ (OemCryptoResult result);
+ ForceDeleteUsageEntry@34(array<uint8> pst) => (OemCryptoResult result);
+ DeleteUsageTable@35() => (OemCryptoResult result);
+};
+
+// OemCryptoService is implemented as another service outside of the Browser
+// process, so we need to proxy a connection to it through ArcBridge initially.
+// This interface is implemented in the Browser process and also in the daemon
+// that runs in Chrome OS.
+// Next Method ID: 1
+interface OemCryptoHost {
+ Connect@0(OemCryptoService& oemcryptor);
+};
+
+// OemCryptoInstance is implemented in the liboemcrypto.so library that runs in
+// Android and handles the Android side of the ArcBridge connection.
+// Next Method ID: 1
+interface OemCryptoInstance {
+ Init@0(OemCryptoHost host_ptr);
+};
diff --git a/chromium/components/arc/common/video_encode_accelerator.mojom b/chromium/components/arc/common/video_encode_accelerator.mojom
index 5f819a04d21..98fe048f710 100644
--- a/chromium/components/arc/common/video_encode_accelerator.mojom
+++ b/chromium/components/arc/common/video_encode_accelerator.mojom
@@ -99,8 +99,7 @@ interface VideoEncodeAccelerator {
GetSupportedProfiles@0() => (array<VideoEncodeProfile> profiles);
// Initializes the video encoder with specific configuration. Called once per
- // encoder construction. This call returns true iff initialization is
- // successful.
+ // encoder construction.
// Parameters:
// |input_format| is the pixel format of the input frames.
// |visible_size| is the resolution of the input frames.
@@ -110,6 +109,9 @@ interface VideoEncodeAccelerator {
// in bits per second.
// |client| is the client of this video encoder. The client must be valid
// during the lifetime of this accelerator.
+ // Callback:
+ // Called with true iff initialization is successful. The client should not
+ // invoke any other methods before the callback.
Initialize@1(VideoPixelFormat input_format,
Size visible_size,
StorageType input_storage,
@@ -125,24 +127,30 @@ interface VideoEncodeAccelerator {
// |planes| is arrays of offset and stride of planes in the video frame.
// |timestamp| the timestamp of the video frame(in microseconds).
// |force_keyframe| forces the encoding of a keyframe for this frame.
+ // Callback:
+ // Called when the frame has been processed and no longer used by this
+ // accelerator.
Encode@2(handle frame_fd,
array<VideoFramePlane> planes,
int64 timestamp,
- bool force_keyframe);
+ bool force_keyframe) => ();
- // Sends a bitstream buffer to the encoder for storing future encoded output.
- // Each call here will cause the shared memory buffer to be filled once, then
- // returned with VideoEncodeClient::BitstreamBufferReady().
+ // Sends a bitstream buffer to the encoder for storing encoded output. The
+ // shared memory buffer will be filled with the encoded bitstream, and the
+ // callback will be called.
// Parameters:
// |bitstream_buffer_id| is the id of the bitstream buffer. It is used to
// identify the bitstream in VideoEncodeClient::BitstreamBufferReady().
// |shmem_fd| is the file descriptor of the shared memory.
// |offset| and |size| define the region in the shared memory to be used
// as the bitstream buffer.
- UseOutputBitstreamBuffer@3(int32 bitstream_buffer_id,
- handle shmem_fd,
- uint32 offset,
- uint32 size);
+ // Callback:
+ // Called when the encoded data has been filled in the bitstream buffer.
+ // |payload_size| is the byte size of the used portion of the buffer.
+ // |key_frame| is true if this delivered frame is a keyframe.
+ // |timestamp| is the same timestamp as the one passed to Encode().
+ UseBitstreamBuffer@3(handle shmem_fd, uint32 offset, uint32 size)
+ => (uint32 payload_size, bool key_frame, int64 timestamp);
// Requests a change to the encoding parameters. This is only a request,
// fulfilled on a best-effort basis.
@@ -177,18 +185,6 @@ interface VideoEncodeClient {
Size input_coded_size,
uint32 output_buffer_size);
- // Callback to deliver encoded bitstream buffers. Ownership of the buffer is
- // transferred back to the VideoEncodeClient once this callback is made.
- // Parameters:
- // |bitstream_buffer_id| is the id of the buffer that is ready.
- // |payload_size| is the byte size of the used portion of the buffer.
- // |key_frame| is true if this delivered frame is a keyframe.
- // |timestamp| is the same timestamp as the one passed to Encode().
- BitstreamBufferReady@1(int32 bitstream_buffer_id,
- uint32 payload_size,
- bool key_frame,
- int64 timestamp);
-
// Error notification callback. Note that errors in
// VideoEncodeAccelerator::Initialize() will not be reported here, but will
// instead be indicated by a false return value there.
diff --git a/chromium/components/arc/common/voice_interaction_framework.mojom b/chromium/components/arc/common/voice_interaction_framework.mojom
index 7cfd385126c..f40540b4504 100644
--- a/chromium/components/arc/common/voice_interaction_framework.mojom
+++ b/chromium/components/arc/common/voice_interaction_framework.mojom
@@ -59,10 +59,12 @@ interface VoiceInteractionFrameworkInstance {
Init@0(VoiceInteractionFrameworkHost host_ptr);
// Starts the voice interaction session in container.
- StartVoiceInteractionSession@1();
+ // |homescreen_is_active| is true if the session was invoked when homescreen is active.
+ StartVoiceInteractionSession@1([MinVersion=11] bool homescreen_is_active);
// Starts or stops voice interaction session based on current state.
- [MinVersion=9] ToggleVoiceInteractionSession@8();
+ // |homescreen_is_active| is true if the session was invoked when homescreen is active.
+ [MinVersion=9] ToggleVoiceInteractionSession@8([MinVersion=11] bool homescreen_is_active);
// Starts the voice interaction session in container, with a screen region
// selected.
diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
index 109832b532d..90912eaf743 100644
--- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
+++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
@@ -28,11 +28,9 @@ void RunCrashReporter(const std::string& crash_type,
const std::string& board,
const std::string& cpu_abi,
mojo::edk::ScopedPlatformHandle pipe) {
- base::FileHandleMappingVector fd_map = {
- std::make_pair(pipe.get().handle, STDIN_FILENO)};
-
base::LaunchOptions options;
- options.fds_to_remap = &fd_map;
+ options.fds_to_remap.push_back(
+ std::make_pair(pipe.get().handle, STDIN_FILENO));
auto process =
base::LaunchProcess({kCrashReporterPath, "--arc_java_crash=" + crash_type,
@@ -88,12 +86,7 @@ ArcCrashCollectorBridge::ArcCrashCollectorBridge(
}
ArcCrashCollectorBridge::~ArcCrashCollectorBridge() {
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->crash_collector()->RemoveObserver(this);
+ arc_bridge_service_->crash_collector()->RemoveObserver(this);
}
void ArcCrashCollectorBridge::OnInstanceReady() {
diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.cc b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
index 4ede0f47ed4..304788b5ce1 100644
--- a/chromium/components/arc/ime/arc_ime_bridge_impl.cc
+++ b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
@@ -59,14 +59,14 @@ ui::TextInputType ConvertTextInputType(mojom::TextInputType ipc_type) {
std::vector<mojom::CompositionSegmentPtr> ConvertSegments(
const ui::CompositionText& composition) {
std::vector<mojom::CompositionSegmentPtr> segments;
- for (const ui::CompositionUnderline& underline : composition.underlines) {
+ for (const ui::ImeTextSpan& ime_text_span : composition.ime_text_spans) {
mojom::CompositionSegmentPtr segment = mojom::CompositionSegment::New();
- segment->start_offset = underline.start_offset;
- segment->end_offset = underline.end_offset;
+ segment->start_offset = ime_text_span.start_offset;
+ segment->end_offset = ime_text_span.end_offset;
segment->emphasized =
- (underline.thick ||
- (composition.selection.start() == underline.start_offset &&
- composition.selection.end() == underline.end_offset));
+ (ime_text_span.thick ||
+ (composition.selection.start() == ime_text_span.start_offset &&
+ composition.selection.end() == ime_text_span.end_offset));
segments.push_back(std::move(segment));
}
return segments;
@@ -81,12 +81,7 @@ ArcImeBridgeImpl::ArcImeBridgeImpl(Delegate* delegate,
}
ArcImeBridgeImpl::~ArcImeBridgeImpl() {
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- bridge_service_->ime()->RemoveObserver(this);
+ bridge_service_->ime()->RemoveObserver(this);
}
void ArcImeBridgeImpl::OnInstanceReady() {
diff --git a/chromium/components/arc/ime/arc_ime_service.cc b/chromium/components/arc/ime/arc_ime_service.cc
index a3297c4e315..775bea2d98d 100644
--- a/chromium/components/arc/ime/arc_ime_service.cc
+++ b/chromium/components/arc/ime/arc_ime_service.cc
@@ -52,6 +52,13 @@ class ArcWindowDelegateImpl : public ArcImeService::ArcWindowDelegate {
exo::WMHelper::GetInstance()->RemoveFocusObserver(ime_service_);
}
+ ui::InputMethod* GetInputMethodForWindow(
+ aura::Window* window) const override {
+ if (!window || !window->GetHost())
+ return nullptr;
+ return window->GetHost()->GetInputMethod();
+ }
+
private:
ArcImeService* const ime_service_;
@@ -95,7 +102,6 @@ ArcImeService::ArcImeService(content::BrowserContext* context,
ime_type_(ui::TEXT_INPUT_TYPE_NONE),
has_composition_text_(false),
keyboard_controller_(nullptr),
- test_input_method_(nullptr),
is_focus_observer_installed_(false) {
aura::Env* env = aura::Env::GetInstanceDontCreate();
if (env)
@@ -127,25 +133,28 @@ void ArcImeService::SetImeBridgeForTesting(
ime_bridge_ = std::move(test_ime_bridge);
}
-void ArcImeService::SetInputMethodForTesting(
- ui::InputMethod* test_input_method) {
- test_input_method_ = test_input_method;
-}
-
void ArcImeService::SetArcWindowDelegateForTesting(
std::unique_ptr<ArcWindowDelegate> delegate) {
arc_window_delegate_ = std::move(delegate);
}
ui::InputMethod* ArcImeService::GetInputMethod() {
- if (!focused_arc_window_)
- return nullptr;
+ return arc_window_delegate_->GetInputMethodForWindow(focused_arc_window_);
+}
- if (test_input_method_)
- return test_input_method_;
+void ArcImeService::ReattachInputMethod(aura::Window* old_window,
+ aura::Window* new_window) {
+ ui::InputMethod* const old_ime =
+ arc_window_delegate_->GetInputMethodForWindow(old_window);
+ ui::InputMethod* const new_ime =
+ arc_window_delegate_->GetInputMethodForWindow(new_window);
- DCHECK(focused_arc_window_->GetHost());
- return focused_arc_window_->GetHost()->GetInputMethod();
+ if (old_ime != new_ime) {
+ if (old_ime)
+ old_ime->DetachTextInputClient(this);
+ if (new_ime)
+ new_ime->SetFocusedTextInputClient(this);
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -181,7 +190,8 @@ void ArcImeService::OnWindowDestroying(aura::Window* window) {
void ArcImeService::OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) {
DCHECK_EQ(window, focused_arc_window_);
- OnWindowFocused(nullptr, focused_arc_window_);
+ // IMEs are associated with root windows, hence we may need to detach/attach.
+ ReattachInputMethod(focused_arc_window_, new_root);
}
////////////////////////////////////////////////////////////////////////////////
@@ -196,15 +206,6 @@ void ArcImeService::OnWindowFocused(aura::Window* gained_focus,
const bool attach =
(gained_focus && arc_window_delegate_->IsArcWindow(gained_focus));
- // TODO(kinaba): Implicit dependency in GetInputMethod as described below is
- // confusing. Consider getting InputMethod directly from lost_ or gained_focus
- // variables. For that, we need to change how to inject testing InputMethod.
- //
- // GetInputMethod() retrieves the input method associated to
- // |forcused_arc_window_|. Hence, to get the object we are detaching from, we
- // must call the method before updating the forcused ARC window.
- ui::InputMethod* const detaching_ime = detach ? GetInputMethod() : nullptr;
-
if (detach) {
focused_arc_window_->RemoveObserver(this);
focused_arc_window_ = nullptr;
@@ -215,17 +216,7 @@ void ArcImeService::OnWindowFocused(aura::Window* gained_focus,
focused_arc_window_->AddObserver(this);
}
- ui::InputMethod* const attaching_ime = attach ? GetInputMethod() : nullptr;
-
- // Notify to the input method, either when this service is detached or
- // attached. Do nothing when the focus is moving between ARC windows,
- // to avoid unpexpected context reset in ARC.
- if (detaching_ime != attaching_ime) {
- if (detaching_ime)
- detaching_ime->DetachTextInputClient(this);
- if (attaching_ime)
- attaching_ime->SetFocusedTextInputClient(this);
- }
+ ReattachInputMethod(detach ? lost_focus : nullptr, focused_arc_window_);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/components/arc/ime/arc_ime_service.h b/chromium/components/arc/ime/arc_ime_service.h
index 5826c24d19b..61b7ca3834c 100644
--- a/chromium/components/arc/ime/arc_ime_service.h
+++ b/chromium/components/arc/ime/arc_ime_service.h
@@ -60,14 +60,13 @@ class ArcImeService : public KeyedService,
virtual bool IsArcWindow(const aura::Window* window) const = 0;
virtual void RegisterFocusObserver() = 0;
virtual void UnregisterFocusObserver() = 0;
+ virtual ui::InputMethod* GetInputMethodForWindow(
+ aura::Window* window) const = 0;
};
// Injects the custom IPC bridge object for testing purpose only.
void SetImeBridgeForTesting(std::unique_ptr<ArcImeBridge> test_ime_bridge);
- // Injects the custom IME for testing purpose only.
- void SetInputMethodForTesting(ui::InputMethod* test_input_method);
-
// Injects the custom delegate for ARC windows, for testing purpose only.
void SetArcWindowDelegateForTesting(
std::unique_ptr<ArcWindowDelegate> delegate);
@@ -137,6 +136,12 @@ class ArcImeService : public KeyedService,
private:
ui::InputMethod* GetInputMethod();
+ // Detaches from the IME associated with the |old_window|, and attaches to the
+ // IME associated with |new_window|. Called when the focus status of ARC
+ // windows has changed, or when an ARC window moved to a different display.
+ // Do nothing if both windows are associated with the same IME.
+ void ReattachInputMethod(aura::Window* old_window, aura::Window* new_window);
+
void InvalidateSurroundingTextAndSelectionRange();
std::unique_ptr<ArcImeBridge> ime_bridge_;
@@ -152,7 +157,6 @@ class ArcImeService : public KeyedService,
keyboard::KeyboardController* keyboard_controller_;
- ui::InputMethod* test_input_method_;
bool is_focus_observer_installed_;
DISALLOW_COPY_AND_ASSIGN(ArcImeService);
diff --git a/chromium/components/arc/ime/arc_ime_service_unittest.cc b/chromium/components/arc/ime/arc_ime_service_unittest.cc
index 5a35fe7933f..c43e5ed147f 100644
--- a/chromium/components/arc/ime/arc_ime_service_unittest.cc
+++ b/chromium/components/arc/ime/arc_ime_service_unittest.cc
@@ -100,7 +100,8 @@ class FakeInputMethod : public ui::DummyInputMethod {
// not depending on the full setup of Exo and Ash.
class FakeArcWindowDelegate : public ArcImeService::ArcWindowDelegate {
public:
- FakeArcWindowDelegate() : next_id_(0) {}
+ explicit FakeArcWindowDelegate(ui::InputMethod* input_method)
+ : next_id_(0), test_input_method_(input_method) {}
bool IsArcWindow(const aura::Window* window) const override {
return arc_window_id_.count(window->id());
@@ -109,6 +110,11 @@ class FakeArcWindowDelegate : public ArcImeService::ArcWindowDelegate {
void RegisterFocusObserver() override {}
void UnregisterFocusObserver() override {}
+ ui::InputMethod* GetInputMethodForWindow(
+ aura::Window* window) const override {
+ return window ? test_input_method_ : nullptr;
+ }
+
std::unique_ptr<aura::Window> CreateFakeArcWindow() {
const int id = next_id_++;
arc_window_id_.insert(id);
@@ -126,6 +132,7 @@ class FakeArcWindowDelegate : public ArcImeService::ArcWindowDelegate {
aura::test::TestWindowDelegate dummy_delegate_;
int next_id_;
std::set<int> arc_window_id_;
+ ui::InputMethod* test_input_method_;
};
} // namespace
@@ -152,9 +159,8 @@ class ArcImeServiceTest : public testing::Test {
instance_->SetImeBridgeForTesting(base::WrapUnique(fake_arc_ime_bridge_));
fake_input_method_ = base::MakeUnique<FakeInputMethod>();
- instance_->SetInputMethodForTesting(fake_input_method_.get());
- fake_window_delegate_ = new FakeArcWindowDelegate();
+ fake_window_delegate_ = new FakeArcWindowDelegate(fake_input_method_.get());
instance_->SetArcWindowDelegateForTesting(
base::WrapUnique(fake_window_delegate_));
arc_win_ = fake_window_delegate_->CreateFakeArcWindow();
@@ -266,6 +272,26 @@ TEST_F(ArcImeServiceTest, WindowFocusTracking) {
EXPECT_EQ(2, fake_input_method_->count_set_focused_text_input_client());
}
+TEST_F(ArcImeServiceTest, RootWindowChange) {
+ std::unique_ptr<aura::Window> dummy_root =
+ fake_window_delegate_->CreateFakeNonArcWindow();
+
+ instance_->OnWindowFocused(arc_win_.get(), nullptr);
+ EXPECT_EQ(instance_.get(), fake_input_method_->GetTextInputClient());
+
+ // Moving to another root window with that shares the same input method.
+ // ArcImeService should keep attached to the IME.
+ instance_->OnWindowRemovingFromRootWindow(arc_win_.get(), dummy_root.get());
+ EXPECT_EQ(instance_.get(), fake_input_method_->GetTextInputClient());
+
+ // Removed from a root window. It should be detached.
+ instance_->OnWindowRemovingFromRootWindow(arc_win_.get(), nullptr);
+ EXPECT_NE(instance_.get(), fake_input_method_->GetTextInputClient());
+
+ // Unfocusing afterwards should not cause any trouble like crashing.
+ instance_->OnWindowFocused(nullptr, arc_win_.get());
+}
+
TEST_F(ArcImeServiceTest, GetTextFromRange) {
instance_->OnWindowFocused(arc_win_.get(), nullptr);
diff --git a/chromium/components/arc/intent_helper/DEPS b/chromium/components/arc/intent_helper/DEPS
index 4dbd757fa46..e2ab3722b4c 100644
--- a/chromium/components/arc/intent_helper/DEPS
+++ b/chromium/components/arc/intent_helper/DEPS
@@ -1,5 +1,10 @@
include_rules = [
- "+ash",
+ "+ash/link_handler_model.h",
+ "+ash/link_handler_model_factory.h",
+ "+ash/new_window_controller.h",
+ "+ash/shell.h",
+ "+ash/shell_delegate.h",
+ "+ash/wallpaper/wallpaper_controller.h",
"+components/google/core/browser",
"+ui/base",
"+ui/gfx",
diff --git a/chromium/components/arc/intent_helper/activity_icon_loader.h b/chromium/components/arc/intent_helper/activity_icon_loader.h
index 2b3c705db54..33ac3b70d72 100644
--- a/chromium/components/arc/intent_helper/activity_icon_loader.h
+++ b/chromium/components/arc/intent_helper/activity_icon_loader.h
@@ -15,7 +15,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
-#include "components/arc/arc_service.h"
#include "components/arc/common/intent_helper.mojom.h"
#include "ui/base/layout.h"
#include "ui/gfx/image/image.h"
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
index 5fa4f105980..e8d6290abba 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -16,7 +16,6 @@
#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "components/arc/arc_service_manager.h"
#include "components/arc/audio/arc_audio_bridge.h"
-#include "components/arc/intent_helper/link_handler_model_impl.h"
#include "ui/base/layout.h"
#include "url/gurl.h"
@@ -68,18 +67,11 @@ ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context,
ArcIntentHelperBridge::~ArcIntentHelperBridge() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->intent_helper()->RemoveObserver(this);
+ arc_bridge_service_->intent_helper()->RemoveObserver(this);
}
void ArcIntentHelperBridge::OnInstanceReady() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- ash::Shell::Get()->set_link_handler_model_factory(this);
auto* instance =
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->intent_helper(), Init);
DCHECK(instance);
@@ -90,7 +82,6 @@ void ArcIntentHelperBridge::OnInstanceReady() {
void ArcIntentHelperBridge::OnInstanceClosed() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- ash::Shell::Get()->set_link_handler_model_factory(nullptr);
}
void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) {
@@ -124,10 +115,7 @@ void ArcIntentHelperBridge::SetWallpaperDeprecated(
}
void ArcIntentHelperBridge::OpenVolumeControl() {
- // TODO(hidehiko): Use browser_context passed to this class's ctor, after
- // we migrate this into BrowserContextKeyedService.
- auto* audio = ArcAudioBridge::GetForBrowserContext(
- ArcServiceManager::Get()->browser_context());
+ auto* audio = ArcAudioBridge::GetForBrowserContext(context_);
DCHECK(audio);
audio->ShowVolumeControls();
}
@@ -167,15 +155,6 @@ bool ArcIntentHelperBridge::HasObserver(
return observer_list_.HasObserver(observer);
}
-std::unique_ptr<ash::LinkHandlerModel> ArcIntentHelperBridge::CreateModel(
- const GURL& url) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- auto impl = base::MakeUnique<LinkHandlerModelImpl>(context_);
- if (!impl->Init(url))
- return nullptr;
- return std::move(impl);
-}
-
// static
bool ArcIntentHelperBridge::IsIntentHelperPackage(
const std::string& package_name) {
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
index ac5dd705426..7fd1ede7a37 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
@@ -9,7 +9,6 @@
#include <string>
#include <vector>
-#include "ash/link_handler_model_factory.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
@@ -22,10 +21,6 @@
class KeyedServiceBaseFactory;
-namespace ash {
-class LinkHandlerModel;
-} // namespace ash
-
namespace content {
class BrowserContext;
} // namespace content
@@ -39,8 +34,7 @@ class IntentFilter;
class ArcIntentHelperBridge
: public KeyedService,
public InstanceHolder<mojom::IntentHelperInstance>::Observer,
- public mojom::IntentHelperHost,
- public ash::LinkHandlerModelFactory {
+ public mojom::IntentHelperHost {
public:
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
@@ -91,9 +85,6 @@ class ArcIntentHelperBridge
// without checking the filters.
bool ShouldChromeHandleUrl(const GURL& url);
- // ash::LinkHandlerModelFactory
- std::unique_ptr<ash::LinkHandlerModel> CreateModel(const GURL& url) override;
-
// Returns false if |package_name| is for the intent_helper apk.
static bool IsIntentHelperPackage(const std::string& package_name);
diff --git a/chromium/components/arc/intent_helper/intent_filter_struct_traits.h b/chromium/components/arc/intent_helper/intent_filter_struct_traits.h
index d6cb0cf83e6..a76ba40790c 100644
--- a/chromium/components/arc/intent_helper/intent_filter_struct_traits.h
+++ b/chromium/components/arc/intent_helper/intent_filter_struct_traits.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/containers/span.h"
#include "components/arc/common/intent_helper.mojom.h"
#include "components/arc/intent_helper/intent_filter.h"
@@ -15,19 +16,18 @@ namespace mojo {
template <>
struct StructTraits<arc::mojom::IntentFilterDataView, arc::IntentFilter> {
- static const mojo::CArray<std::string> actions(const arc::IntentFilter& r) {
+ static const base::span<std::string> actions(const arc::IntentFilter& r) {
// Returns an empty array.
- return mojo::CArray<std::string>();
+ return base::span<std::string>();
}
- static const mojo::CArray<std::string> categories(
- const arc::IntentFilter& r) {
+ static const base::span<std::string> categories(const arc::IntentFilter& r) {
// Returns an empty array.
- return mojo::CArray<std::string>();
+ return base::span<std::string>();
}
- static const mojo::CArray<std::string> data_schemes(
+ static const base::span<std::string> data_schemes(
const arc::IntentFilter& r) {
// Returns an empty array.
- return mojo::CArray<std::string>();
+ return base::span<std::string>();
}
static const std::vector<arc::IntentFilter::AuthorityEntry>& data_authorities(
const arc::IntentFilter& r) {
@@ -37,10 +37,10 @@ struct StructTraits<arc::mojom::IntentFilterDataView, arc::IntentFilter> {
const arc::IntentFilter& r) {
return r.paths();
}
- static const mojo::CArray<arc::IntentFilter::PatternMatcher>
+ static const base::span<arc::IntentFilter::PatternMatcher>
deprecated_data_scheme_specific_parts(const arc::IntentFilter& r) {
// Returns an empty array.
- return mojo::CArray<arc::IntentFilter::PatternMatcher>();
+ return base::span<arc::IntentFilter::PatternMatcher>();
}
static bool Read(arc::mojom::IntentFilterDataView data,
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl.cc b/chromium/components/arc/intent_helper/link_handler_model.cc
index ef863592e92..42002920f6f 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl.cc
+++ b/chromium/components/arc/intent_helper/link_handler_model.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/arc/intent_helper/link_handler_model_impl.h"
+#include "components/arc/intent_helper/link_handler_model.h"
#include <string>
#include <utility>
#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h"
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
@@ -47,12 +48,38 @@ bool GetQueryValue(const GURL& url,
} // namespace
-LinkHandlerModelImpl::LinkHandlerModelImpl(content::BrowserContext* context)
- : context_(context), weak_ptr_factory_(this) {}
+// static
+std::unique_ptr<LinkHandlerModel> LinkHandlerModel::Create(
+ content::BrowserContext* context,
+ const GURL& link_url) {
+ auto impl = base::WrapUnique(new LinkHandlerModel());
+ if (!impl->Init(context, link_url))
+ return nullptr;
+ return impl;
+}
+
+LinkHandlerModel::~LinkHandlerModel() = default;
+
+void LinkHandlerModel::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void LinkHandlerModel::OpenLinkWithHandler(uint32_t handler_id) {
+ auto* arc_service_manager = ArcServiceManager::Get();
+ if (!arc_service_manager)
+ return;
+ auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_service_manager->arc_bridge_service()->intent_helper(), HandleUrl);
+ if (!instance)
+ return;
+ if (handler_id >= handlers_.size())
+ return;
+ instance->HandleUrl(url_.spec(), handlers_[handler_id]->package_name);
+}
-LinkHandlerModelImpl::~LinkHandlerModelImpl() = default;
+LinkHandlerModel::LinkHandlerModel() = default;
-bool LinkHandlerModelImpl::Init(const GURL& url) {
+bool LinkHandlerModel::Init(content::BrowserContext* context, const GURL& url) {
auto* arc_service_manager = ArcServiceManager::Get();
if (!arc_service_manager)
return false;
@@ -62,37 +89,21 @@ bool LinkHandlerModelImpl::Init(const GURL& url) {
if (!instance)
return false;
+ DCHECK(context);
+ context_ = context;
+
// Check if ARC apps can handle the |url|. Since the information is held in
// a different (ARC) process, issue a mojo IPC request. Usually, the
// callback function, OnUrlHandlerList, is called within a few milliseconds
// even on the slowest Chromebook we support.
- const GURL rewritten(RewriteUrlFromQueryIfAvailable(url));
+ url_ = RewriteUrlFromQueryIfAvailable(url);
instance->RequestUrlHandlerList(
- rewritten.spec(), base::Bind(&LinkHandlerModelImpl::OnUrlHandlerList,
- weak_ptr_factory_.GetWeakPtr()));
+ url_.spec(), base::Bind(&LinkHandlerModel::OnUrlHandlerList,
+ weak_ptr_factory_.GetWeakPtr()));
return true;
}
-void LinkHandlerModelImpl::AddObserver(Observer* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void LinkHandlerModelImpl::OpenLinkWithHandler(const GURL& url,
- uint32_t handler_id) {
- auto* arc_service_manager = ArcServiceManager::Get();
- if (!arc_service_manager)
- return;
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(), HandleUrl);
- if (!instance)
- return;
- if (handler_id >= handlers_.size())
- return;
- const GURL rewritten(RewriteUrlFromQueryIfAvailable(url));
- instance->HandleUrl(rewritten.spec(), handlers_[handler_id]->package_name);
-}
-
-void LinkHandlerModelImpl::OnUrlHandlerList(
+void LinkHandlerModel::OnUrlHandlerList(
std::vector<mojom::IntentHandlerInfoPtr> handlers) {
handlers_ = ArcIntentHelperBridge::FilterOutIntentHelper(std::move(handlers));
@@ -107,7 +118,7 @@ void LinkHandlerModelImpl::OnUrlHandlerList(
}
const ArcIntentHelperBridge::GetResult result =
intent_helper_bridge->GetActivityIcons(
- activities, base::Bind(&LinkHandlerModelImpl::NotifyObserver,
+ activities, base::Bind(&LinkHandlerModel::NotifyObserver,
weak_ptr_factory_.GetWeakPtr()));
icon_info_notified =
internal::ActivityIconLoader::HasIconsReadyCallbackRun(result);
@@ -121,14 +132,14 @@ void LinkHandlerModelImpl::OnUrlHandlerList(
}
}
-void LinkHandlerModelImpl::NotifyObserver(
+void LinkHandlerModel::NotifyObserver(
std::unique_ptr<ArcIntentHelperBridge::ActivityToIconsMap> icons) {
if (icons) {
icons_.insert(icons->begin(), icons->end());
icons.reset();
}
- std::vector<ash::LinkHandlerInfo> handlers;
+ std::vector<LinkHandlerInfo> handlers;
for (size_t i = 0; i < handlers_.size(); ++i) {
gfx::Image icon;
const ArcIntentHelperBridge::ActivityName activity(
@@ -137,7 +148,7 @@ void LinkHandlerModelImpl::NotifyObserver(
if (it != icons_.end())
icon = it->second.icon16;
// Use the handler's index as an ID.
- ash::LinkHandlerInfo handler = {handlers_[i]->name, icon, i};
+ LinkHandlerInfo handler = {base::UTF8ToUTF16(handlers_[i]->name), icon, i};
handlers.push_back(handler);
}
for (auto& observer : observer_list_)
@@ -145,13 +156,13 @@ void LinkHandlerModelImpl::NotifyObserver(
}
// static
-GURL LinkHandlerModelImpl::RewriteUrlFromQueryIfAvailableForTesting(
+GURL LinkHandlerModel::RewriteUrlFromQueryIfAvailableForTesting(
const GURL& url) {
return RewriteUrlFromQueryIfAvailable(url);
}
// static
-GURL LinkHandlerModelImpl::RewriteUrlFromQueryIfAvailable(const GURL& url) {
+GURL LinkHandlerModel::RewriteUrlFromQueryIfAvailable(const GURL& url) {
static const char kPathToFind[] = "/url";
static const char kKeyToFind[] = "url";
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl.h b/chromium/components/arc/intent_helper/link_handler_model.h
index 2c080f75a39..556d0407be9 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl.h
+++ b/chromium/components/arc/intent_helper/link_handler_model.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_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_IMPL_H_
-#define COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_IMPL_H_
+#ifndef COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
+#define COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
#include <memory>
#include <vector>
-#include "ash/link_handler_model.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/strings/string16.h"
#include "components/arc/common/intent_helper.mojom.h"
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "url/gurl.h"
@@ -21,24 +21,43 @@ class BrowserContext;
namespace arc {
-class LinkHandlerModelImpl : public ash::LinkHandlerModel {
+// This struct describes the UI presentation of a single link handler.
+struct LinkHandlerInfo {
+ base::string16 name;
+ gfx::Image icon;
+ // An opaque identifier for this handler (which happens to correlate to the
+ // index in |handlers_|.
+ uint32_t id;
+};
+
+class LinkHandlerModel {
public:
- explicit LinkHandlerModelImpl(content::BrowserContext* context);
- ~LinkHandlerModelImpl() override;
+ class Observer {
+ public:
+ virtual void ModelChanged(const std::vector<LinkHandlerInfo>& handlers) = 0;
+ };
- // ash::LinkHandlerModel overrides:
- void AddObserver(Observer* observer) override;
- void OpenLinkWithHandler(const GURL& url, uint32_t handler_id) override;
+ // Creates and inits a model. Will return null if Init() fails.
+ static std::unique_ptr<LinkHandlerModel> Create(
+ content::BrowserContext* context,
+ const GURL& link_url);
- // Starts retrieving handler information for the |url| and returns true.
- // Returns false when the information cannot be retrieved. In that case,
- // the caller should delete |this| object.
- bool Init(const GURL& url);
+ ~LinkHandlerModel();
+
+ void AddObserver(Observer* observer);
+
+ void OpenLinkWithHandler(uint32_t handler_id);
static GURL RewriteUrlFromQueryIfAvailableForTesting(const GURL& url);
private:
- mojom::IntentHelperInstance* GetIntentHelper();
+ LinkHandlerModel();
+
+ // Starts retrieving handler information for the |url| and returns true.
+ // Returns false when the information cannot be retrieved. In that case,
+ // the caller should delete |this| object.
+ bool Init(content::BrowserContext* context, const GURL& url);
+
void OnUrlHandlerList(std::vector<mojom::IntentHandlerInfoPtr> handlers);
void NotifyObserver(
std::unique_ptr<ArcIntentHelperBridge::ActivityToIconsMap> icons);
@@ -49,7 +68,9 @@ class LinkHandlerModelImpl : public ash::LinkHandlerModel {
// Otherwise, returns the original |url| as-us.
static GURL RewriteUrlFromQueryIfAvailable(const GURL& url);
- content::BrowserContext* const context_;
+ content::BrowserContext* context_ = nullptr;
+
+ GURL url_;
base::ObserverList<Observer> observer_list_;
@@ -58,13 +79,11 @@ class LinkHandlerModelImpl : public ash::LinkHandlerModel {
// Activity icon info passed from ARC.
ArcIntentHelperBridge::ActivityToIconsMap icons_;
- // Always keep this the last member of this class to make sure it's the
- // first thing to be destructed.
- base::WeakPtrFactory<LinkHandlerModelImpl> weak_ptr_factory_;
+ base::WeakPtrFactory<LinkHandlerModel> weak_ptr_factory_{this};
- DISALLOW_COPY_AND_ASSIGN(LinkHandlerModelImpl);
+ DISALLOW_COPY_AND_ASSIGN(LinkHandlerModel);
};
} // namespace arc
-#endif // COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_IMPL_H_
+#endif // COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc b/chromium/components/arc/intent_helper/link_handler_model_unittest.cc
index 314b1ecbfca..56bb968ba55 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc
+++ b/chromium/components/arc/intent_helper/link_handler_model_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/arc/intent_helper/link_handler_model_impl.h"
+#include "components/arc/intent_helper/link_handler_model.h"
#include <string>
@@ -14,12 +14,12 @@ namespace arc {
namespace {
GURL Rewrite(const GURL& url) {
- return LinkHandlerModelImpl::RewriteUrlFromQueryIfAvailableForTesting(url);
+ return LinkHandlerModel::RewriteUrlFromQueryIfAvailableForTesting(url);
}
} // namespace
-TEST(LinkHandlerModelImplTest, TestRewriteUrlNoOp) {
+TEST(LinkHandlerModelTest, TestRewriteUrlNoOp) {
// Test an empty URL.
GURL original("");
EXPECT_EQ(original, Rewrite(original));
@@ -77,7 +77,7 @@ TEST(LinkHandlerModelImplTest, TestRewriteUrlNoOp) {
EXPECT_EQ(original, Rewrite(original));
}
-TEST(LinkHandlerModelImplTest, TestRewriteUrl) {
+TEST(LinkHandlerModelTest, TestRewriteUrl) {
// Test valid URLs.
GURL original(
"https://www.google.com/url?"
@@ -109,7 +109,7 @@ TEST(LinkHandlerModelImplTest, TestRewriteUrl) {
EXPECT_EQ("k=v", rewritten.query());
}
-TEST(LinkHandlerModelImplTest, TestRewriteUrlTooLong) {
+TEST(LinkHandlerModelTest, TestRewriteUrlTooLong) {
const std::string base =
"https://www.google.com/url?url="
"https%3A%2F%2Fwww.chromium.org%2F"; // 33 characters
diff --git a/chromium/components/arc/metrics/arc_metrics_service.cc b/chromium/components/arc/metrics/arc_metrics_service.cc
index ee6d25cc317..6dd0225eb64 100644
--- a/chromium/components/arc/metrics/arc_metrics_service.cc
+++ b/chromium/components/arc/metrics/arc_metrics_service.cc
@@ -85,15 +85,8 @@ ArcMetricsService::ArcMetricsService(content::BrowserContext* context,
ArcMetricsService::~ArcMetricsService() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get()) {
- arc_bridge_service_->process()->RemoveObserver(&process_observer_);
- arc_bridge_service_->metrics()->RemoveObserver(this);
- }
+ arc_bridge_service_->process()->RemoveObserver(&process_observer_);
+ arc_bridge_service_->metrics()->RemoveObserver(this);
}
void ArcMetricsService::OnInstanceReady() {
diff --git a/chromium/components/arc/net/arc_net_host_impl.cc b/chromium/components/arc/net/arc_net_host_impl.cc
index 38dd9a21c0b..fda90c28d63 100644
--- a/chromium/components/arc/net/arc_net_host_impl.cc
+++ b/chromium/components/arc/net/arc_net_host_impl.cc
@@ -347,13 +347,7 @@ ArcNetHostImpl::~ArcNetHostImpl() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (observing_network_state_)
GetStateHandler()->RemoveObserver(this, FROM_HERE);
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->net()->RemoveObserver(this);
+ arc_bridge_service_->net()->RemoveObserver(this);
}
void ArcNetHostImpl::OnInstanceReady() {
@@ -524,21 +518,18 @@ void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg,
return;
}
- properties->SetStringWithoutPathExpansion(onc::network_config::kType,
- onc::network_config::kWiFi);
- wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kHexSSID,
- cfg->hexssid.value());
- wifi_dict->SetBooleanWithoutPathExpansion(onc::wifi::kAutoConnect,
- details->autoconnect);
+ properties->SetKey(onc::network_config::kType,
+ base::Value(onc::network_config::kWiFi));
+ wifi_dict->SetKey(onc::wifi::kHexSSID, base::Value(cfg->hexssid.value()));
+ wifi_dict->SetKey(onc::wifi::kAutoConnect, base::Value(details->autoconnect));
if (cfg->security.empty()) {
- wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kSecurity,
- onc::wifi::kSecurityNone);
+ wifi_dict->SetKey(onc::wifi::kSecurity,
+ base::Value(onc::wifi::kSecurityNone));
} else {
- wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kSecurity,
- cfg->security);
+ wifi_dict->SetKey(onc::wifi::kSecurity, base::Value(cfg->security));
if (details->passphrase.has_value()) {
- wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kPassphrase,
- details->passphrase.value());
+ wifi_dict->SetKey(onc::wifi::kPassphrase,
+ base::Value(details->passphrase.value()));
}
}
properties->SetWithoutPathExpansion(onc::network_config::kWiFi,
@@ -660,7 +651,6 @@ void ArcNetHostImpl::GetDefaultNetwork(
const GetDefaultNetworkCallback& callback) {
const chromeos::NetworkState* default_network =
GetShillBackedNetwork(GetStateHandler()->DefaultNetwork());
-
if (!default_network) {
VLOG(1) << "GetDefaultNetwork: no default network";
callback.Run(nullptr, nullptr);
diff --git a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
index dd6f7c1aa0b..d2b8a6a9e85 100644
--- a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
+++ b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
@@ -57,12 +57,7 @@ ArcObbMounterBridge::ArcObbMounterBridge(content::BrowserContext* context,
}
ArcObbMounterBridge::~ArcObbMounterBridge() {
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->obb_mounter()->RemoveObserver(this);
+ arc_bridge_service_->obb_mounter()->RemoveObserver(this);
}
void ArcObbMounterBridge::OnInstanceReady() {
diff --git a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h
index 860d3da700c..d8a7ccec692 100644
--- a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h
+++ b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h
@@ -8,7 +8,6 @@
#include <string>
#include "base/macros.h"
-#include "components/arc/arc_service.h"
#include "components/arc/common/obb_mounter.mojom.h"
#include "components/arc/instance_holder.h"
#include "components/keyed_service/core/keyed_service.h"
diff --git a/chromium/components/arc/power/DEPS b/chromium/components/arc/power/DEPS
index aeeb7315233..ac7ae6d3982 100644
--- a/chromium/components/arc/power/DEPS
+++ b/chromium/components/arc/power/DEPS
@@ -1,4 +1,4 @@
include_rules = [
- "+ash",
+ "+ash/shell.h",
"+ui/display/manager/chromeos",
]
diff --git a/chromium/components/arc/power/arc_power_bridge.cc b/chromium/components/arc/power/arc_power_bridge.cc
index 72e99db62fe..bc71e9bd412 100644
--- a/chromium/components/arc/power/arc_power_bridge.cc
+++ b/chromium/components/arc/power/arc_power_bridge.cc
@@ -61,13 +61,7 @@ ArcPowerBridge::ArcPowerBridge(content::BrowserContext* context,
ArcPowerBridge::~ArcPowerBridge() {
ReleaseAllDisplayWakeLocks();
-
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->power()->RemoveObserver(this);
+ arc_bridge_service_->power()->RemoveObserver(this);
}
void ArcPowerBridge::OnInstanceReady() {
diff --git a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
index d34a0c2bf8c..ce6107a218e 100644
--- a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
+++ b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
@@ -64,12 +64,7 @@ ArcVolumeMounterBridge::ArcVolumeMounterBridge(content::BrowserContext* context,
ArcVolumeMounterBridge::~ArcVolumeMounterBridge() {
DiskMountManager::GetInstance()->RemoveObserver(this);
- // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
- // BrowserContextKeyedService is not nested.
- // If ArcServiceManager::Get() returns nullptr, it is already destructed,
- // so do not touch it.
- if (ArcServiceManager::Get())
- arc_bridge_service_->volume_mounter()->RemoveObserver(this);
+ arc_bridge_service_->volume_mounter()->RemoveObserver(this);
}
void ArcVolumeMounterBridge::OnInstanceReady() {
@@ -98,6 +93,13 @@ void ArcVolumeMounterBridge::OnFormatEvent(
// Ignored. ARC doesn't care about events other than Disk and Mount events.
}
+void ArcVolumeMounterBridge::OnRenameEvent(
+ chromeos::disks::DiskMountManager::RenameEvent event,
+ chromeos::RenameError error_code,
+ const std::string& device_path) {
+ // Ignored. ARC doesn't care about events other than Disk and Mount events.
+}
+
void ArcVolumeMounterBridge::OnMountEvent(
DiskMountManager::MountEvent event,
chromeos::MountError error_code,
diff --git a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h
index ae57e7a1a4c..2e54fe6f61e 100644
--- a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h
+++ b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h
@@ -54,6 +54,9 @@ class ArcVolumeMounterBridge
void OnFormatEvent(chromeos::disks::DiskMountManager::FormatEvent event,
chromeos::FormatError error_code,
const std::string& device_path) override;
+ void OnRenameEvent(chromeos::disks::DiskMountManager::RenameEvent event,
+ chromeos::RenameError error_code,
+ const std::string& device_path) override;
private:
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index 7515cb4c750..4b31a0dd70a 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -4,9 +4,62 @@
import("//build/config/android/rules.gni")
+java_strings_grd("autofill_strings_grd") {
+ grd_file = "java/strings/autofill_strings.grd"
+ outputs = [
+ "values-am/autofill_strings.xml",
+ "values-ar/autofill_strings.xml",
+ "values-bg/autofill_strings.xml",
+ "values-ca/autofill_strings.xml",
+ "values-cs/autofill_strings.xml",
+ "values-da/autofill_strings.xml",
+ "values-de/autofill_strings.xml",
+ "values-el/autofill_strings.xml",
+ "values/autofill_strings.xml",
+ "values-en-rGB/autofill_strings.xml",
+ "values-es/autofill_strings.xml",
+ "values-es-rUS/autofill_strings.xml",
+ "values-fa/autofill_strings.xml",
+ "values-fi/autofill_strings.xml",
+ "values-tl/autofill_strings.xml",
+ "values-fr/autofill_strings.xml",
+ "values-hi/autofill_strings.xml",
+ "values-hr/autofill_strings.xml",
+ "values-hu/autofill_strings.xml",
+ "values-in/autofill_strings.xml",
+ "values-it/autofill_strings.xml",
+ "values-iw/autofill_strings.xml",
+ "values-ja/autofill_strings.xml",
+ "values-ko/autofill_strings.xml",
+ "values-lt/autofill_strings.xml",
+ "values-lv/autofill_strings.xml",
+ "values-nl/autofill_strings.xml",
+ "values-nb/autofill_strings.xml",
+ "values-pl/autofill_strings.xml",
+ "values-pt-rBR/autofill_strings.xml",
+ "values-pt-rPT/autofill_strings.xml",
+ "values-ro/autofill_strings.xml",
+ "values-ru/autofill_strings.xml",
+ "values-sk/autofill_strings.xml",
+ "values-sl/autofill_strings.xml",
+ "values-sr/autofill_strings.xml",
+ "values-sv/autofill_strings.xml",
+ "values-sw/autofill_strings.xml",
+ "values-th/autofill_strings.xml",
+ "values-tr/autofill_strings.xml",
+ "values-uk/autofill_strings.xml",
+ "values-vi/autofill_strings.xml",
+ "values-zh-rCN/autofill_strings.xml",
+ "values-zh-rTW/autofill_strings.xml",
+ ]
+}
+
android_resources("autofill_java_resources") {
custom_package = "org.chromium.components.autofill"
resource_dirs = [ "java/res" ]
+ deps = [
+ ":autofill_strings_grd",
+ ]
}
android_library("autofill_java") {
diff --git a/chromium/components/autofill/android/autofill_provider_android.cc b/chromium/components/autofill/android/autofill_provider_android.cc
index c2d1fb3fe84..b4bf794bc29 100644
--- a/chromium/components/autofill/android/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/autofill_provider_android.cc
@@ -233,8 +233,4 @@ void AutofillProviderAndroid::Reset() {
id_ = kNoQueryId;
}
-bool RegisterAutofillProvider(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/android/autofill_provider_android.h b/chromium/components/autofill/android/autofill_provider_android.h
index f1af8ff7ee1..a26c432d292 100644
--- a/chromium/components/autofill/android/autofill_provider_android.h
+++ b/chromium/components/autofill/android/autofill_provider_android.h
@@ -73,9 +73,6 @@ class AutofillProviderAndroid : public AutofillProvider {
DISALLOW_COPY_AND_ASSIGN(AutofillProviderAndroid);
};
-
-bool RegisterAutofillProvider(JNIEnv* env);
-
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
diff --git a/chromium/components/autofill/android/form_data_android.cc b/chromium/components/autofill/android/form_data_android.cc
index 6cfb4f98058..b70302a3533 100644
--- a/chromium/components/autofill/android/form_data_android.cc
+++ b/chromium/components/autofill/android/form_data_android.cc
@@ -95,8 +95,4 @@ bool FormDataAndroid::SimilarFormAs(const FormData& form) {
return form_.SimilarFormAs(form);
}
-bool RegisterFormDataAndroid(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/android/form_data_android.h b/chromium/components/autofill/android/form_data_android.h
index 130995aad8c..adb2c0c82e0 100644
--- a/chromium/components/autofill/android/form_data_android.h
+++ b/chromium/components/autofill/android/form_data_android.h
@@ -56,8 +56,6 @@ class FormDataAndroid {
DISALLOW_COPY_AND_ASSIGN(FormDataAndroid);
};
-bool RegisterFormDataAndroid(JNIEnv* env);
-
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
diff --git a/chromium/components/autofill/android/java/strings/autofill_strings.grd b/chromium/components/autofill/android/java/strings/autofill_strings.grd
new file mode 100644
index 00000000000..3ad4a441540
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/autofill_strings.grd
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<grit latest_public_release="0" current_release="1"
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
+ <outputs>
+ <output filename="values-am/autofill_strings.xml" lang="am" type="android" />
+ <output filename="values-ar/autofill_strings.xml" lang="ar" type="android" />
+ <output filename="values-bg/autofill_strings.xml" lang="bg" type="android" />
+ <output filename="values-ca/autofill_strings.xml" lang="ca" type="android" />
+ <output filename="values-cs/autofill_strings.xml" lang="cs" type="android" />
+ <output filename="values-da/autofill_strings.xml" lang="da" type="android" />
+ <output filename="values-de/autofill_strings.xml" lang="de" type="android" />
+ <output filename="values-el/autofill_strings.xml" lang="el" type="android" />
+ <output filename="values/autofill_strings.xml" lang="en" type="android" />
+ <output filename="values-en-rGB/autofill_strings.xml" lang="en-GB" type="android" />
+ <output filename="values-es/autofill_strings.xml" lang="es" type="android" />
+ <output filename="values-es-rUS/autofill_strings.xml" lang="es-419" type="android" />
+ <output filename="values-fa/autofill_strings.xml" lang="fa" type="android" />
+ <output filename="values-fi/autofill_strings.xml" lang="fi" type="android" />
+ <output filename="values-tl/autofill_strings.xml" lang="fil" type="android" />
+ <output filename="values-fr/autofill_strings.xml" lang="fr" type="android" />
+ <output filename="values-hi/autofill_strings.xml" lang="hi" type="android" />
+ <output filename="values-hr/autofill_strings.xml" lang="hr" type="android" />
+ <output filename="values-hu/autofill_strings.xml" lang="hu" type="android" />
+ <output filename="values-in/autofill_strings.xml" lang="id" type="android" />
+ <output filename="values-it/autofill_strings.xml" lang="it" type="android" />
+ <output filename="values-iw/autofill_strings.xml" lang="he" type="android" />
+ <output filename="values-ja/autofill_strings.xml" lang="ja" type="android" />
+ <output filename="values-ko/autofill_strings.xml" lang="ko" type="android" />
+ <output filename="values-lt/autofill_strings.xml" lang="lt" type="android" />
+ <output filename="values-lv/autofill_strings.xml" lang="lv" type="android" />
+ <output filename="values-nl/autofill_strings.xml" lang="nl" type="android" />
+ <output filename="values-nb/autofill_strings.xml" lang="no" type="android" />
+ <output filename="values-pl/autofill_strings.xml" lang="pl" type="android" />
+ <output filename="values-pt-rBR/autofill_strings.xml" lang="pt-BR" type="android" />
+ <output filename="values-pt-rPT/autofill_strings.xml" lang="pt-PT" type="android" />
+ <output filename="values-ro/autofill_strings.xml" lang="ro" type="android" />
+ <output filename="values-ru/autofill_strings.xml" lang="ru" type="android" />
+ <output filename="values-sk/autofill_strings.xml" lang="sk" type="android" />
+ <output filename="values-sl/autofill_strings.xml" lang="sl" type="android" />
+ <output filename="values-sr/autofill_strings.xml" lang="sr" type="android" />
+ <output filename="values-sv/autofill_strings.xml" lang="sv" type="android" />
+ <output filename="values-sw/autofill_strings.xml" lang="sw" type="android" />
+ <output filename="values-th/autofill_strings.xml" lang="th" type="android" />
+ <output filename="values-tr/autofill_strings.xml" lang="tr" type="android" />
+ <output filename="values-uk/autofill_strings.xml" lang="uk" type="android" />
+ <output filename="values-vi/autofill_strings.xml" lang="vi" type="android" />
+ <output filename="values-zh-rCN/autofill_strings.xml" lang="zh-CN" type="android" />
+ <output filename="values-zh-rTW/autofill_strings.xml" lang="zh-TW" type="android" />
+ </outputs>
+ <translations>
+ <file lang="am" path="translations/autofill_strings_am.xtb" />
+ <file lang="ar" path="translations/autofill_strings_ar.xtb" />
+ <file lang="bg" path="translations/autofill_strings_bg.xtb" />
+ <file lang="ca" path="translations/autofill_strings_ca.xtb" />
+ <file lang="cs" path="translations/autofill_strings_cs.xtb" />
+ <file lang="da" path="translations/autofill_strings_da.xtb" />
+ <file lang="de" path="translations/autofill_strings_de.xtb" />
+ <file lang="el" path="translations/autofill_strings_el.xtb" />
+ <file lang="en-GB" path="translations/autofill_strings_en-GB.xtb" />
+ <file lang="es" path="translations/autofill_strings_es.xtb" />
+ <file lang="es-419" path="translations/autofill_strings_es-419.xtb" />
+ <file lang="fa" path="translations/autofill_strings_fa.xtb" />
+ <file lang="fi" path="translations/autofill_strings_fi.xtb" />
+ <file lang="fil" path="translations/autofill_strings_fil.xtb" />
+ <file lang="fr" path="translations/autofill_strings_fr.xtb" />
+ <file lang="hi" path="translations/autofill_strings_hi.xtb" />
+ <file lang="hr" path="translations/autofill_strings_hr.xtb" />
+ <file lang="hu" path="translations/autofill_strings_hu.xtb" />
+ <file lang="id" path="translations/autofill_strings_id.xtb" />
+ <file lang="it" path="translations/autofill_strings_it.xtb" />
+ <file lang="iw" path="translations/autofill_strings_iw.xtb" />
+ <file lang="ja" path="translations/autofill_strings_ja.xtb" />
+ <file lang="ko" path="translations/autofill_strings_ko.xtb" />
+ <file lang="lt" path="translations/autofill_strings_lt.xtb" />
+ <file lang="lv" path="translations/autofill_strings_lv.xtb" />
+ <file lang="nl" path="translations/autofill_strings_nl.xtb" />
+ <file lang="no" path="translations/autofill_strings_no.xtb" />
+ <file lang="pl" path="translations/autofill_strings_pl.xtb" />
+ <file lang="pt-BR" path="translations/autofill_strings_pt-BR.xtb" />
+ <file lang="pt-PT" path="translations/autofill_strings_pt-PT.xtb" />
+ <file lang="ro" path="translations/autofill_strings_ro.xtb" />
+ <file lang="ru" path="translations/autofill_strings_ru.xtb" />
+ <file lang="sk" path="translations/autofill_strings_sk.xtb" />
+ <file lang="sl" path="translations/autofill_strings_sl.xtb" />
+ <file lang="sr" path="translations/autofill_strings_sr.xtb" />
+ <file lang="sv" path="translations/autofill_strings_sv.xtb" />
+ <file lang="sw" path="translations/autofill_strings_sw.xtb" />
+ <file lang="th" path="translations/autofill_strings_th.xtb" />
+ <file lang="tr" path="translations/autofill_strings_tr.xtb" />
+ <file lang="uk" path="translations/autofill_strings_uk.xtb" />
+ <file lang="vi" path="translations/autofill_strings_vi.xtb" />
+ <file lang="zh-CN" path="translations/autofill_strings_zh-CN.xtb" />
+ <file lang="zh-TW" path="translations/autofill_strings_zh-TW.xtb" />
+ </translations>
+ <release allow_pseudo="false" seq="1">
+ <messages fallback_to_english="true">
+ <message name="IDS_AUTOFILL_POPUP_CONTENT_DESCRIPTION" desc="The text announced by the screen reader when the Autofill popup is shown.">
+ Showing Autofill popup
+ </message>
+ </messages>
+ </release>
+</grit>
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_am.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_am.xtb
new file mode 100644
index 00000000000..747bae046c8
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_am.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+<translation id="1112374155460533568">የራስ-ሙላ ብቅ-ባይን በማሳየት ላይ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ar.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ar.xtb
new file mode 100644
index 00000000000..ecf7b67234d
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ar.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+<translation id="1112374155460533568">عرض نافذة الملء التلقائي المنبثقة</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_bg.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_bg.xtb
new file mode 100644
index 00000000000..06e6038528f
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_bg.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+<translation id="1112374155460533568">Изскачащият прозорец за автоматично попълване е показан</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ca.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ca.xtb
new file mode 100644
index 00000000000..30bf2b66f2a
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ca.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+<translation id="1112374155460533568">S'està mostrant la finestra emergent d'Emplenament automàtic</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_cs.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_cs.xtb
new file mode 100644
index 00000000000..e0ed098112a
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_cs.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+<translation id="1112374155460533568">Je zobrazeno vyskakovací okno automatického vyplňování</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_da.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_da.xtb
new file mode 100644
index 00000000000..10f3ee91213
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_da.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+<translation id="1112374155460533568">Viser pop op for AutoFyld</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_de.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_de.xtb
new file mode 100644
index 00000000000..cc1f9241113
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_de.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+<translation id="1112374155460533568">Pop-up-Fenster für AutoFill-Daten wird angezeigt</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_el.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_el.xtb
new file mode 100644
index 00000000000..66a4b22f24a
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_el.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+<translation id="1112374155460533568">Εμφάνιση αναδυόμενου παραθύρου αυτόματης συμπλήρωσης</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_en-GB.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_en-GB.xtb
new file mode 100644
index 00000000000..5649da1e143
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_en-GB.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+<translation id="1112374155460533568">Showing AutoFill pop-up</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_es-419.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_es-419.xtb
new file mode 100644
index 00000000000..1779b173401
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_es-419.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+<translation id="1112374155460533568">Mostrando mensaje emergente de Autocompletar</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_es.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_es.xtb
new file mode 100644
index 00000000000..fe44d74360a
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_es.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+<translation id="1112374155460533568">Mostrando la ventana emergente de Autocompletar</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_fa.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fa.xtb
new file mode 100644
index 00000000000..faf764ce5e8
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fa.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fa">
+<translation id="1112374155460533568">درحال نمایش پنجره بازشوی «تکمیل خودکار»</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_fi.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fi.xtb
new file mode 100644
index 00000000000..81928996387
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fi.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+<translation id="1112374155460533568">Automaattisen täytön ponnahdusikkuna on näkyvissä.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_fil.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fil.xtb
new file mode 100644
index 00000000000..18c22ab5ca0
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fil.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+<translation id="1112374155460533568">Ipinapakita ang popup na Autofill</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_fr.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fr.xtb
new file mode 100644
index 00000000000..0fb5945e295
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_fr.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+<translation id="1112374155460533568">Affichage de la fenêtre pop-up de saisie automatique</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_hi.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hi.xtb
new file mode 100644
index 00000000000..c90f8c76941
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hi.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+<translation id="1112374155460533568">ऑटोमैटिक भरने का पॉपअप दिखाया जा रहा है</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_hr.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hr.xtb
new file mode 100644
index 00000000000..70816090a16
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hr.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+<translation id="1112374155460533568">Prikazuje se skočni prozor automatskog popunjavanja</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_hu.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hu.xtb
new file mode 100644
index 00000000000..43bb58cef00
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_hu.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+<translation id="1112374155460533568">Az automatikus kitöltés előugró ablakának megjelenítése</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_id.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_id.xtb
new file mode 100644
index 00000000000..8cb52901718
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_id.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+<translation id="1112374155460533568">Menampilkan pop-up IsiOtomatis</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_it.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_it.xtb
new file mode 100644
index 00000000000..daac7a20332
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_it.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+<translation id="1112374155460533568">È mostrato il popup di compilazione automatica</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_iw.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_iw.xtb
new file mode 100644
index 00000000000..61ffb7b1493
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_iw.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="iw">
+<translation id="1112374155460533568">המערכת מציגה את החלון הקופץ של מילוי אוטומטי</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ja.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ja.xtb
new file mode 100644
index 00000000000..718fd82397c
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ja.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+<translation id="1112374155460533568">自動入力のポップアップが表示されています</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ko.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ko.xtb
new file mode 100644
index 00000000000..cdc1519f95e
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ko.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+<translation id="1112374155460533568">자동완성 팝업 표시</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_lt.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_lt.xtb
new file mode 100644
index 00000000000..113e48dfa4f
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_lt.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+<translation id="1112374155460533568">Rodomas automatinio pildymo iššokantysis langas</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_lv.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_lv.xtb
new file mode 100644
index 00000000000..e3e741376ef
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_lv.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+<translation id="1112374155460533568">Tiek rādīts automātiskās aizpildes uznirstošais logs.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_nl.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_nl.xtb
new file mode 100644
index 00000000000..3aa16faa233
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_nl.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+<translation id="1112374155460533568">Pop-upvenster van automatisch aanvullen wordt weergegeven</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_no.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_no.xtb
new file mode 100644
index 00000000000..8b6364f2c98
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_no.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+<translation id="1112374155460533568">Viser forgrunnsvinduet for autofyll</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_pl.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pl.xtb
new file mode 100644
index 00000000000..22a85973025
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pl.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+<translation id="1112374155460533568">Pokazuję wyskakujące okienko autouzupełniania</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-BR.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-BR.xtb
new file mode 100644
index 00000000000..227fbf68fde
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-BR.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+<translation id="1112374155460533568">Mostrando pop-up do Preenchimento automático</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-PT.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-PT.xtb
new file mode 100644
index 00000000000..b42c5c12fe0
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_pt-PT.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+<translation id="1112374155460533568">A mostrar pop-up de preenchimento automático</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ro.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ro.xtb
new file mode 100644
index 00000000000..9555110d233
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ro.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+<translation id="1112374155460533568">Se afișează fereastra pop-up pentru completarea automată</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_ru.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ru.xtb
new file mode 100644
index 00000000000..bc2492d49e7
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_ru.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+<translation id="1112374155460533568">Открыто всплывающее окно автозаполнения</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_sk.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sk.xtb
new file mode 100644
index 00000000000..3fcc0500020
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sk.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+<translation id="1112374155460533568">Zobrazuje sa okno automatického dopĺňania</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_sl.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sl.xtb
new file mode 100644
index 00000000000..e79a7bdceb7
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sl.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+<translation id="1112374155460533568">Prikaz pojavnega okna za samodejno izpolnjevanje</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_sr.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sr.xtb
new file mode 100644
index 00000000000..e142eb46c22
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sr.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+<translation id="1112374155460533568">Приказује се искачући прозор за аутоматско попуњавање</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_sv.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sv.xtb
new file mode 100644
index 00000000000..89d0d3ddb93
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sv.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+<translation id="1112374155460533568">Visar popupfönster för autofyll</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_sw.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sw.xtb
new file mode 100644
index 00000000000..bdaf72ca922
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_sw.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sw">
+<translation id="1112374155460533568">Inaonyesha dirisha ibukizi la Kujaza Kiotomatiki</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_th.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_th.xtb
new file mode 100644
index 00000000000..2c36625311b
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_th.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+<translation id="1112374155460533568">กำลังแสดงป๊อปอัปการป้อนข้อความอัตโนมัติ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_tr.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_tr.xtb
new file mode 100644
index 00000000000..5758a718fda
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_tr.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+<translation id="1112374155460533568">Otomatik doldurma pop-up'ı gösteriliyor</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_uk.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_uk.xtb
new file mode 100644
index 00000000000..786fbdf71be
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_uk.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+<translation id="1112374155460533568">Показ спливаючих вікон автозаповнення</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_vi.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_vi.xtb
new file mode 100644
index 00000000000..83401028da5
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_vi.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+<translation id="1112374155460533568">Hiển thị cửa sổ bật lên Tự động điền</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-CN.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-CN.xtb
new file mode 100644
index 00000000000..085e64f79b0
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-CN.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+<translation id="1112374155460533568">目前显示的是“自动填充”弹出式窗口</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-TW.xtb b/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-TW.xtb
new file mode 100644
index 00000000000..09d0780fafe
--- /dev/null
+++ b/chromium/components/autofill/android/java/strings/translations/autofill_strings_zh-TW.xtb
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+<translation id="1112374155460533568">目前顯示的是自動填入彈出式視窗</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn
index 5fa6ea67efd..edecc7be4c1 100644
--- a/chromium/components/autofill/content/browser/BUILD.gn
+++ b/chromium/components/autofill/content/browser/BUILD.gn
@@ -31,19 +31,15 @@ static_library("browser") {
"//components/resources",
"//components/strings",
"//components/user_prefs",
- "//components/webdata/common",
"//content/public/browser",
"//content/public/common",
"//device/geolocation",
- "//google_apis",
"//gpu/config",
"//mojo/common:common_base",
"//net",
"//ppapi/features",
"//services/service_manager/public/cpp",
"//sql",
- "//third_party/icu",
- "//third_party/libphonenumber",
"//ui/base",
"//ui/display",
"//ui/gfx",
@@ -64,7 +60,6 @@ source_set("unit_tests") {
sources = [
"content_autofill_driver_unittest.cc",
"key_press_handler_manager_unittest.cc",
- "payments/payments_client_unittest.cc",
]
deps = [
@@ -77,10 +72,7 @@ source_set("unit_tests") {
"//content/public/browser",
"//content/public/common",
"//content/test:test_support",
- "//google_apis",
- "//google_apis:test_support",
"//mojo/common:common_base",
- "//net",
"//net:test_support",
"//services/service_manager/public/cpp",
"//testing/gmock",
diff --git a/chromium/components/autofill/content/browser/DEPS b/chromium/components/autofill/content/browser/DEPS
index 474cd74243e..302796c2b28 100644
--- a/chromium/components/autofill/content/browser/DEPS
+++ b/chromium/components/autofill/content/browser/DEPS
@@ -1,13 +1,8 @@
include_rules = [
- "+components/webdata/common",
"+content/public/browser",
"+crypto/random.h",
"+device/geolocation",
- "+google_apis/gaia",
- "+google_apis/google_api_keys.h",
"+gpu/config/gpu_info.h",
- "+sql",
- "+third_party/libphonenumber", # For phone number i18n.
"+third_party/WebKit/public/platform/WebRect.h",
]
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 0d37b7cac28..f4e1ecec6d4 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -247,12 +247,12 @@ void ContentAutofillDriver::SetDataList(
autofill_handler_->OnSetDataList(values, labels);
}
-void ContentAutofillDriver::DidNavigateFrame(
+void ContentAutofillDriver::DidNavigateMainFrame(
content::NavigationHandle* navigation_handle) {
- if (navigation_handle->IsInMainFrame() &&
- !navigation_handle->IsSameDocument()) {
- autofill_handler_->Reset();
- }
+ if (navigation_handle->IsSameDocument())
+ return;
+
+ autofill_handler_->Reset();
}
void ContentAutofillDriver::SetAutofillManager(
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index f35923673f8..61684b5f7d0 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -96,8 +96,9 @@ class ContentAutofillDriver : public AutofillDriver,
void SetDataList(const std::vector<base::string16>& values,
const std::vector<base::string16>& labels) override;
- // Called when the frame has navigated.
- void DidNavigateFrame(content::NavigationHandle* navigation_handle);
+ // Called when the main frame has navigated. Explicitely will not trigger for
+ // subframe navigations. See navigation_handle.h for details.
+ void DidNavigateMainFrame(content::NavigationHandle* navigation_handle);
AutofillExternalDelegate* autofill_external_delegate() {
return autofill_external_delegate_.get();
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
index e3d822a1a8f..b643b62b39d 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -134,12 +134,18 @@ void ContentAutofillDriverFactory::RenderFrameDeleted(
void ContentAutofillDriverFactory::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->HasCommitted())
+ // For the purposes of this code, a navigation is not important if it has not
+ // committed yet or if it's in a subframe.
+ if (!navigation_handle->HasCommitted() ||
+ !navigation_handle->IsInMainFrame()) {
return;
+ }
+ // A main frame navigation has occured. We suppress the autofill popup and
+ // tell the autofill driver.
NavigationFinished();
DriverForFrame(navigation_handle->GetRenderFrameHost())
- ->DidNavigateFrame(navigation_handle);
+ ->DidNavigateMainFrame(navigation_handle);
}
void ContentAutofillDriverFactory::WasHidden() {
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 3ae21b4f658..d12dd886b0f 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -29,6 +29,7 @@
#include "content/public/common/frame_navigate_params.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/base/net_errors.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -264,7 +265,7 @@ class TestContentAutofillDriver : public ContentAutofillDriver {
return static_cast<MockAutofillManager*>(autofill_manager());
}
- using ContentAutofillDriver::DidNavigateFrame;
+ using ContentAutofillDriver::DidNavigateMainFrame;
};
class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
@@ -294,16 +295,11 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
content::RenderViewHostTestHarness::TearDown();
}
- void Navigate(bool main_frame) {
- content::RenderFrameHost* rfh = main_rfh();
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(rfh);
- if (!main_frame)
- rfh = rfh_tester->AppendChild("subframe");
+ void Navigate(bool same_document) {
std::unique_ptr<content::NavigationHandle> navigation_handle =
content::NavigationHandle::CreateNavigationHandleForTesting(
- GURL(), rfh, true);
- driver_->DidNavigateFrame(navigation_handle.get());
+ GURL(), main_rfh(), /*committed=*/true, net::OK, same_document);
+ driver_->DidNavigateMainFrame(navigation_handle.get());
}
protected:
@@ -322,14 +318,14 @@ TEST_F(ContentAutofillDriverTest, GetURLRequestContext) {
EXPECT_EQ(request_context, expected_request_context);
}
-TEST_F(ContentAutofillDriverTest, NavigatedToDifferentPage) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
EXPECT_CALL(*driver_->mock_autofill_manager(), Reset());
- Navigate(true);
+ Navigate(/*same_document=*/false);
}
-TEST_F(ContentAutofillDriverTest, NavigatedWithinSamePage) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
EXPECT_CALL(*driver_->mock_autofill_manager(), Reset()).Times(0);
- Navigate(false);
+ Navigate(/*same_document=*/true);
}
TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
diff --git a/chromium/components/autofill/content/browser/payments/OWNERS b/chromium/components/autofill/content/browser/payments/OWNERS
deleted file mode 100644
index 6a806bd5dad..00000000000
--- a/chromium/components/autofill/content/browser/payments/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mahmadi@chromium.org
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index 302599f70cf..3f747d981d8 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -74,7 +74,8 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
available_screen_bounds_(0, 11, 101, 60),
unavailable_screen_bounds_(0, 0, 101, 11) {}
- void GetFingerprintTestCallback(std::unique_ptr<Fingerprint> fingerprint) {
+ void GetFingerprintTestCallback(base::OnceClosure continuation_callback,
+ std::unique_ptr<Fingerprint> fingerprint) {
// Verify that all fields Chrome can fill have been filled.
ASSERT_TRUE(fingerprint->has_machine_characteristics());
const Fingerprint::MachineCharacteristics& machine =
@@ -167,7 +168,7 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
EXPECT_EQ(kAccuracy, location.accuracy());
EXPECT_EQ(kGeolocationTime, location.time_in_ms());
- message_loop_.QuitWhenIdle();
+ std::move(continuation_callback).Run();
}
protected:
@@ -203,16 +204,17 @@ IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) {
screen_info.rect = screen_bounds_;
screen_info.available_rect = available_screen_bounds_;
+ base::RunLoop run_loop;
internal::GetFingerprintInternal(
kObfuscatedGaiaId, window_bounds_, content_bounds_, screen_info,
"25.0.0.123", kCharset, kAcceptLanguages, base::Time::Now(), kLocale,
kUserAgent,
base::TimeDelta::FromDays(1), // Ought to be longer than any test run.
base::Bind(&AutofillRiskFingerprintTest::GetFingerprintTestCallback,
- base::Unretained(this)));
+ base::Unretained(this), run_loop.QuitWhenIdleClosure()));
// Wait for the callback to be called.
- base::RunLoop().Run();
+ run_loop.Run();
}
} // namespace risk
diff --git a/chromium/components/autofill/content/common/autofill_agent.mojom b/chromium/components/autofill/content/common/autofill_agent.mojom
index 9dd9fa99bd8..21cef2037b1 100644
--- a/chromium/components/autofill/content/common/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/autofill_agent.mojom
@@ -89,6 +89,10 @@ interface PasswordAutofillAgent {
// Renderer is expected to return the found password form. If no password form
// is focused, the response will contain an empty |autofill::PasswordForm|.
FindFocusedPasswordForm() => (PasswordForm form);
+
+ // Notifies PasswordAutofillAgent that the matching blacklisted form was
+ // found.
+ BlacklistedFormFound();
};
// There is one instance of this interface per render frame in the render
diff --git a/chromium/components/autofill/content/common/autofill_driver.mojom b/chromium/components/autofill/content/common/autofill_driver.mojom
index 46e79777730..f04cf1af13a 100644
--- a/chromium/components/autofill/content/common/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/autofill_driver.mojom
@@ -77,6 +77,14 @@ interface PasswordManagerDriver {
// Notification that this password form was submitted by the user.
PasswordFormSubmitted(PasswordForm password_form);
+
+ // Notification that a user starts typing in password fields and the omnibox
+ // icon with anchored save/update prompt should be available.
+ ShowManualFallbackForSaving(PasswordForm password_form);
+
+ // Notification that there is no user input in password fields and the
+ // save/update prompt anchored to the omnibox icon should be removed.
+ HideManualFallbackForSaving();
// Notification that in-page navigation happened and at this moment we have
// filled password form. We use this as a signal for successful login.
@@ -107,6 +115,13 @@ interface PasswordManagerDriver {
ShowNotSecureWarning(mojo.common.mojom.TextDirection text_direction,
gfx.mojom.RectF bounds);
+
+ // Instructs the browser to show a suggestion, which will redirect the user to
+ // the list of all saved passwords. The popup will use |text_direction| for
+ // displaying text.
+ ShowManualFallbackSuggestion(mojo.common.mojom.TextDirection text_direction,
+ gfx.mojom.RectF bounds);
+
// Instructs the browser to presave the form with generated password.
PresaveGeneratedPassword(PasswordForm password_form);
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
index d76e5b05067..ed4c5c41ecb 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -604,24 +604,25 @@ bool StructTraits<mojom::PasswordFormDataView, PasswordForm>::Read(
}
// static
-void* StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
- PasswordFormFieldPredictionMap>::
- SetUpContext(const PasswordFormFieldPredictionMap& r) {
- // Extracts keys vector and values vector from the map, saves them as a pair.
- auto* pair = new KeysValuesPair();
- for (const auto& i : r) {
- pair->first.push_back(i.first);
- pair->second.push_back(i.second);
- }
-
- return pair;
+std::vector<autofill::FormFieldData> StructTraits<
+ mojom::PasswordFormFieldPredictionMapDataView,
+ PasswordFormFieldPredictionMap>::keys(const PasswordFormFieldPredictionMap&
+ r) {
+ std::vector<autofill::FormFieldData> data;
+ for (const auto& i : r)
+ data.push_back(i.first);
+ return data;
}
// static
-void StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
- PasswordFormFieldPredictionMap>::
- TearDownContext(const PasswordFormFieldPredictionMap& r, void* context) {
- delete static_cast<KeysValuesPair*>(context);
+std::vector<autofill::PasswordFormFieldPredictionType>
+StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+ PasswordFormFieldPredictionMap>::
+ values(const PasswordFormFieldPredictionMap& r) {
+ std::vector<autofill::PasswordFormFieldPredictionType> types;
+ for (const auto& i : r)
+ types.push_back(i.second);
+ return types;
}
// static
@@ -646,23 +647,23 @@ bool StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
}
// static
-void* StructTraits<mojom::FormsPredictionsMapDataView,
- FormsPredictionsMap>::SetUpContext(const FormsPredictionsMap&
- r) {
- // Extracts keys vector and values vector from the map, saves them as a pair.
- auto* pair = new KeysValuesPair();
- for (const auto& i : r) {
- pair->first.push_back(i.first);
- pair->second.push_back(i.second);
- }
-
- return pair;
+std::vector<autofill::FormData>
+StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::keys(
+ const FormsPredictionsMap& r) {
+ std::vector<autofill::FormData> data;
+ for (const auto& i : r)
+ data.push_back(i.first);
+ return data;
}
// static
-void StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::
- TearDownContext(const FormsPredictionsMap& r, void* context) {
- delete static_cast<KeysValuesPair*>(context);
+std::vector<autofill::PasswordFormFieldPredictionMap>
+StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::values(
+ const FormsPredictionsMap& r) {
+ std::vector<autofill::PasswordFormFieldPredictionMap> maps;
+ for (const auto& i : r)
+ maps.push_back(i.second);
+ return maps;
}
// static
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.h b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
index 0c51ed527ab..b98c9dcf208 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
@@ -519,26 +519,11 @@ struct StructTraits<autofill::mojom::PasswordFormDataView,
template <>
struct StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView,
autofill::PasswordFormFieldPredictionMap> {
- using KeysValuesPair =
- std::pair<std::vector<autofill::FormFieldData>,
- std::vector<autofill::PasswordFormFieldPredictionType>>;
+ static std::vector<autofill::FormFieldData> keys(
+ const autofill::PasswordFormFieldPredictionMap& r);
- static void* SetUpContext(const autofill::PasswordFormFieldPredictionMap& r);
-
- static void TearDownContext(const autofill::PasswordFormFieldPredictionMap& r,
- void* context);
-
- static const std::vector<autofill::FormFieldData>& keys(
- const autofill::PasswordFormFieldPredictionMap& r,
- void* context) {
- return static_cast<KeysValuesPair*>(context)->first;
- }
-
- static const std::vector<autofill::PasswordFormFieldPredictionType>& values(
- const autofill::PasswordFormFieldPredictionMap& r,
- void* context) {
- return static_cast<KeysValuesPair*>(context)->second;
- }
+ static std::vector<autofill::PasswordFormFieldPredictionType> values(
+ const autofill::PasswordFormFieldPredictionMap& r);
static bool Read(autofill::mojom::PasswordFormFieldPredictionMapDataView data,
autofill::PasswordFormFieldPredictionMap* out);
@@ -547,26 +532,11 @@ struct StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView,
template <>
struct StructTraits<autofill::mojom::FormsPredictionsMapDataView,
autofill::FormsPredictionsMap> {
- using KeysValuesPair =
- std::pair<std::vector<autofill::FormData>,
- std::vector<autofill::PasswordFormFieldPredictionMap>>;
+ static std::vector<autofill::FormData> keys(
+ const autofill::FormsPredictionsMap& r);
- static void* SetUpContext(const autofill::FormsPredictionsMap& r);
-
- static void TearDownContext(const autofill::FormsPredictionsMap& r,
- void* context);
-
- static const std::vector<autofill::FormData>& keys(
- const autofill::FormsPredictionsMap& r,
- void* context) {
- return static_cast<KeysValuesPair*>(context)->first;
- }
-
- static const std::vector<autofill::PasswordFormFieldPredictionMap>& values(
- const autofill::FormsPredictionsMap& r,
- void* context) {
- return static_cast<KeysValuesPair*>(context)->second;
- }
+ static std::vector<autofill::PasswordFormFieldPredictionMap> values(
+ const autofill::FormsPredictionsMap& r);
static bool Read(autofill::mojom::FormsPredictionsMapDataView data,
autofill::FormsPredictionsMap* out);
diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn
index e87dc92035c..79e6a0bb421 100644
--- a/chromium/components/autofill/content/renderer/BUILD.gn
+++ b/chromium/components/autofill/content/renderer/BUILD.gn
@@ -33,6 +33,10 @@ static_library("renderer") {
"//components/autofill/content/common:mojo_interfaces",
"//components/autofill/core/common",
+ # TODO(melandory): remove once manual fallbacks are launched
+ # https://crbug.com/739343
+ "//components/password_manager/core/common:common",
+
# TODO(elawrence): remove security_state/core when the Form-Not-Secure
# feature is fully launched. https://crbug.com/677295
"//components/security_state/core",
@@ -70,6 +74,7 @@ static_library("test_support") {
deps = [
"//components/autofill/content/renderer",
"//ipc",
+ "//services/service_manager/public/cpp",
"//skia",
"//third_party/WebKit/public:blink",
]
diff --git a/chromium/components/autofill/content/renderer/DEPS b/chromium/components/autofill/content/renderer/DEPS
index e8db31c4a1a..3dd93acea59 100644
--- a/chromium/components/autofill/content/renderer/DEPS
+++ b/chromium/components/autofill/content/renderer/DEPS
@@ -12,5 +12,6 @@ specific_include_rules = {
# launched. https://crbug.com/677295
"password_autofill_agent\.cc" : [
"+components/security_state/core",
+ "+components/password_manager/core/common",
],
}
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 98a96eacef1..2395f19d53d 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -42,12 +42,10 @@
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "net/cert/cert_status_flags.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
-#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElementCollection.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
@@ -143,7 +141,8 @@ AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions()
AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
PasswordAutofillAgent* password_autofill_agent,
- PasswordGenerationAgent* password_generation_agent)
+ PasswordGenerationAgent* password_generation_agent,
+ service_manager::BinderRegistry* registry)
: content::RenderFrameObserver(render_frame),
form_cache_(*render_frame->GetWebFrame()),
password_autofill_agent_(password_autofill_agent),
@@ -161,8 +160,7 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
render_frame->GetWebFrame()->SetAutofillClient(this);
password_autofill_agent->SetAutofillAgent(this);
- // AutofillAgent is guaranteed to outlive |render_frame|.
- render_frame->GetInterfaceRegistry()->AddInterface(
+ registry->AddInterface(
base::Bind(&AutofillAgent::BindRequest, base::Unretained(this)));
}
@@ -190,6 +188,16 @@ void AutofillAgent::DidCommitProvisionalLoad(bool is_new_navigation,
OnSameDocumentNavigationCompleted();
} else {
// Navigation to a new page or a page refresh.
+
+ // Do Finch testing to see how much regressions are caused by this leak fix
+ // (crbug/753071).
+ std::string group_name =
+ base::FieldTrialList::FindFullName("FixDocumentLeakInAutofillAgent");
+ if (base::StartsWith(group_name, "enabled",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ element_.Reset();
+ }
+
form_cache_.Reset();
submitted_forms_.clear();
last_interacted_form_.Reset();
@@ -591,6 +599,7 @@ void AutofillAgent::OnSameDocumentNavigationCompleted() {
last_interacted_form_.Reset();
formless_elements_user_edited_.clear();
+ submitted_forms_.clear();
}
bool AutofillAgent::CollectFormlessElements(FormData* output) {
@@ -696,14 +705,10 @@ void AutofillAgent::QueryAutofillSuggestions(
&field);
}
- // Check the form action attribute only if it is not empty, see
- // crbug.com/757895.
if (is_secure_context_required_ &&
- !(element.GetDocument().IsSecureContext() &&
- (form.action.is_empty() || content::IsOriginSecure(form.action)))) {
+ !(element.GetDocument().IsSecureContext())) {
LOG(WARNING) << "Autofill suggestions are disabled because the document "
- "isn't a secure context or the form's action attribute "
- "isn't secure.";
+ "isn't a secure context.";
return;
}
@@ -732,6 +737,7 @@ void AutofillAgent::DoFillFieldWithValue(const base::string16& value,
base::AutoReset<bool> auto_reset(&ignore_text_changes_, true);
node->SetEditingValue(
blink::WebString::FromUTF16(value.substr(0, node->MaxLength())));
+ password_autofill_agent_->UpdateStateForTextChange(*node);
}
void AutofillAgent::DoPreviewFieldWithValue(const base::string16& value,
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index 549ec8facf8..e242130e2be 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -20,6 +20,7 @@
#include "components/autofill/content/renderer/page_click_tracker.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
@@ -55,7 +56,8 @@ class AutofillAgent : public content::RenderFrameObserver,
// guaranteed to outlive AutofillAgent.
AutofillAgent(content::RenderFrame* render_frame,
PasswordAutofillAgent* password_autofill_manager,
- PasswordGenerationAgent* password_generation_agent);
+ PasswordGenerationAgent* password_generation_agent,
+ service_manager::BinderRegistry* registry);
~AutofillAgent() override;
void BindRequest(mojom::AutofillAgentRequest request);
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index 18a102240eb..3221ff658e6 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -310,28 +310,41 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) {
continue;
}
- static const size_t kMaxLabelSize = 100;
+ constexpr size_t kMaxLabelSize = 100;
const base::string16 truncated_label = field_data.label.substr(
0, std::min(field_data.label.length(), kMaxLabelSize));
const FormFieldDataPredictions& field = form.fields[i];
- std::vector<base::string16> replacements;
- base::string16 overall_type = base::UTF8ToUTF16(field.overall_type);
-
- replacements.push_back(overall_type);
- replacements.push_back(base::UTF8ToUTF16(field.server_type));
- replacements.push_back(base::UTF8ToUTF16(field.heuristic_type));
- replacements.push_back(truncated_label);
- replacements.push_back(base::UTF8ToUTF16(field.parseable_name));
- replacements.push_back(base::UTF8ToUTF16(field.signature));
- replacements.push_back(base::UTF8ToUTF16(form.signature));
- const base::string16 title = l10n_util::GetStringFUTF16(
- IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE, replacements, nullptr);
- element.SetAttribute("title", WebString::FromUTF16(title));
+ // A rough estimate of the maximum title size is:
+ // 7 field titles at <17 chars each
+ // + 6 values at <40 chars each
+ // + 1 truncated label at <kMaxLabelSize;
+ // = 459 chars, rounded up to the next multiple of 64 = 512
+ // A particularly large parseable name could blow through this and cause
+ // another allocation, but that's OK.
+ constexpr size_t kMaxTitleSize = 512;
+ std::string title;
+ title.reserve(kMaxTitleSize);
+ title += "overall type: ";
+ title += field.overall_type;
+ title += "\nserver type: ";
+ title += field.server_type;
+ title += "\nheuristic type: ";
+ title += field.heuristic_type;
+ title += "\nlabel: ";
+ title += base::UTF16ToUTF8(truncated_label);
+ title += "\nparseable name: ";
+ title += field.parseable_name;
+ title += "\nfield signature: ";
+ title += field.signature;
+ title += "\nform signature: ";
+ title += form.signature;
+
+ element.SetAttribute("title", WebString::FromUTF8(title));
element.SetAttribute("autofill-prediction",
- WebString::FromUTF16(overall_type));
+ WebString::FromUTF8(field.overall_type));
}
return true;
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index ca91a857579..6d9e69ad830 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -30,13 +30,13 @@
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/security_state/core/security_state.h"
#include "content/public/common/origin_util.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
@@ -655,6 +655,18 @@ blink::WebInputElement FindUsernameElementPrecedingPasswordElement(
return blink::WebInputElement();
}
+bool ShouldShowStandaloneManuallFallback(const blink::WebInputElement& element,
+ const GURL& url) {
+ return (
+ element.IsPasswordField() &&
+ !IsCreditCardVerificationPasswordField(element) &&
+ !HasCreditCardAutocompleteAttributes(element) &&
+ !base::StartsWith(url.scheme(), "chrome", base::CompareCase::SENSITIVE) &&
+ !url.SchemeIs(url::kAboutScheme) &&
+ base::FeatureList::IsEnabled(
+ password_manager::features::kEnableManualFallbacksFilling));
+}
+
} // namespace
class PasswordAutofillAgent::FormElementObserverCallback
@@ -678,8 +690,12 @@ class PasswordAutofillAgent::FormElementObserverCallback
////////////////////////////////////////////////////////////////////////////////
// PasswordAutofillAgent, public:
-PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame)
+PasswordAutofillAgent::PasswordAutofillAgent(
+ content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry)
: content::RenderFrameObserver(render_frame),
+ web_input_to_password_info_(),
+ last_supplied_password_info_iter_(web_input_to_password_info_.end()),
logging_state_active_(false),
was_username_autofilled_(false),
was_password_autofilled_(false),
@@ -687,8 +703,7 @@ PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame)
checked_safe_browsing_reputation_(false),
binding_(this),
form_element_observer_(nullptr) {
- // PasswordAutofillAgent is guaranteed to outlive |render_frame|.
- render_frame->GetInterfaceRegistry()->AddInterface(
+ registry->AddInterface(
base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this)));
}
@@ -943,9 +958,7 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement(
if (password_iter == password_to_username_.end()) {
if (web_input_to_password_info_.empty())
return false;
- // Now all PasswordInfo items refer to the same set of credentials for
- // fill, so it is ok to take any of them.
- iter = web_input_to_password_info_.begin();
+ iter = last_supplied_password_info_iter_;
} else {
*username_element = password_iter->second;
}
@@ -1028,6 +1041,8 @@ bool PasswordAutofillAgent::ShowSuggestions(
if (!FindPasswordInfoForElement(element, &username_element, &password_element,
&password_info)) {
if (IsUsernameOrPasswordField(element)) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ GURL frame_url = GURL(frame->GetDocument().Url());
#if defined(SAFE_BROWSING_DB_LOCAL)
if (!checked_safe_browsing_reputation_) {
checked_safe_browsing_reputation_ = true;
@@ -1035,12 +1050,16 @@ bool PasswordAutofillAgent::ShowSuggestions(
element.Form().IsNull()
? GURL()
: form_util::GetCanonicalActionForForm(element.Form());
- blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
- GURL frame_url = GURL(frame->GetDocument().Url());
GetPasswordManagerDriver()->CheckSafeBrowsingReputation(action_url,
frame_url);
}
#endif
+ if (!generation_popup_showing && !blacklisted_form_found_ &&
+ ShouldShowStandaloneManuallFallback(element, frame_url) &&
+ ShowManualFallbackSuggestion(element)) {
+ return true;
+ }
+
if (ShouldShowNotSecureWarning(element)) {
autofill_agent_->ShowNotSecureWarning(element);
return true;
@@ -1410,7 +1429,7 @@ void PasswordAutofillAgent::OnDestruct() {
}
void PasswordAutofillAgent::DidStartProvisionalLoad(
- blink::WebDataSource* data_source) {
+ blink::WebDocumentLoader* document_loader) {
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
logger.reset(new RendererSavePasswordProgressLogger(
@@ -1429,7 +1448,7 @@ void PasswordAutofillAgent::DidStartProvisionalLoad(
// the user is performing actions outside the page (e.g. typed url,
// history navigation). We don't want to trigger saving in these cases.
content::DocumentState* document_state =
- content::DocumentState::FromDataSource(data_source);
+ content::DocumentState::FromDocumentLoader(document_loader);
content::NavigationState* navigation_state =
document_state->navigation_state();
ui::PageTransition type = navigation_state->GetTransitionType();
@@ -1606,17 +1625,13 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
blink::WebInputElement main_element =
username_element.IsNull() ? password_element : username_element;
- // We might have already filled this form if there are two <form> elements
- // with identical markup.
- if (web_input_to_password_info_.find(main_element) !=
- web_input_to_password_info_.end())
- continue;
-
PasswordInfo password_info;
password_info.fill_data = form_data;
password_info.key = key;
password_info.password_field = password_element;
web_input_to_password_info_[main_element] = password_info;
+ last_supplied_password_info_iter_ =
+ web_input_to_password_info_.find(main_element);
if (!main_element.IsPasswordField())
password_to_username_[password_element] = username_element;
if (elements)
@@ -1634,6 +1649,7 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
password_info.fill_data = form_data;
password_info.key = key;
web_input_to_password_info_[blink::WebInputElement()] = password_info;
+ last_supplied_password_info_iter_ = web_input_to_password_info_.begin();
}
}
@@ -1695,6 +1711,10 @@ void PasswordAutofillAgent::FindFocusedPasswordForm(
std::move(callback).Run(*password_form);
}
+void PasswordAutofillAgent::BlacklistedFormFound() {
+ blacklisted_form_found_ = true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// PasswordAutofillAgent, private:
@@ -1739,6 +1759,22 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
return CanShowSuggestion(password_info.fill_data, username_string, show_all);
}
+bool PasswordAutofillAgent::ShowManualFallbackSuggestion(
+ const blink::WebInputElement& element) {
+ if (!element.Value().IsEmpty()) {
+ GetAutofillDriver()->HidePopup();
+ return false;
+ }
+
+ FormData form;
+ FormFieldData field;
+ form_util::FindFormAndFieldForFormControlElement(element, &form, &field);
+ GetPasswordManagerDriver()->ShowManualFallbackSuggestion(
+ field.text_direction,
+ render_frame()->GetRenderView()->ElementBoundsInWindow(element));
+ return true;
+}
+
void PasswordAutofillAgent::FrameClosing() {
for (auto const& iter : web_input_to_password_info_) {
password_to_username_.erase(iter.second.password_field);
@@ -1752,6 +1788,7 @@ void PasswordAutofillAgent::FrameClosing() {
field_value_and_properties_map_.clear();
sent_request_to_store_ = false;
checked_safe_browsing_reputation_ = false;
+ blacklisted_form_found_ = false;
}
void PasswordAutofillAgent::ClearPreview(
@@ -1774,13 +1811,25 @@ void PasswordAutofillAgent::ProvisionallySavePassword(
const blink::WebFormElement& form,
const blink::WebInputElement& input,
ProvisionallySaveRestriction restriction) {
- if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD &&
- password_form->password_value.empty() &&
- password_form->new_password_value.empty())) {
+ if (!password_form)
return;
- }
+ bool has_password = !password_form->password_value.empty() ||
+ !password_form->new_password_value.empty();
+ if (restriction == RESTRICTION_NON_EMPTY_PASSWORD && !has_password)
+ return;
+
DCHECK(password_form && (!form.IsNull() || !input.IsNull()));
provisionally_saved_form_.Set(std::move(password_form), form, input);
+
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kEnableManualSaving)) {
+ if (has_password) {
+ GetPasswordManagerDriver()->ShowManualFallbackForSaving(
+ provisionally_saved_form_.password_form());
+ } else {
+ GetPasswordManagerDriver()->HideManualFallbackForSaving();
+ }
+ }
}
const mojom::AutofillDriverPtr& PasswordAutofillAgent::GetAutofillDriver() {
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index a39e3d854fc..bc5db5db7de 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -22,6 +22,7 @@
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_view_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
namespace blink {
@@ -42,7 +43,8 @@ class RendererSavePasswordProgressLogger;
class PasswordAutofillAgent : public content::RenderFrameObserver,
public mojom::PasswordAutofillAgent {
public:
- explicit PasswordAutofillAgent(content::RenderFrame* render_frame);
+ PasswordAutofillAgent(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry);
~PasswordAutofillAgent() override;
void BindRequest(mojom::PasswordAutofillAgentRequest request);
@@ -59,6 +61,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
const FormsPredictionsMap& predictions) override;
void FindFocusedPasswordForm(
FindFocusedPasswordFormCallback callback) override;
+ void BlacklistedFormFound() override;
// WebFrameClient editor related calls forwarded by AutofillAgent.
// If they return true, it indicates the event was consumed and should not
@@ -113,6 +116,11 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// on a non-secure page.
void ShowNotSecureWarning(const blink::WebInputElement& element);
+ // Shows an Autofill-style popup with an option to go to settings and check
+ // all saved passwords. Returns true if the suggestion was shown, false
+ // otherwise.
+ bool ShowManualFallbackSuggestion(const blink::WebInputElement& element);
+
// Called when new form controls are inserted.
void OnDynamicFormsSeen();
@@ -204,7 +212,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void DidFinishDocumentLoad() override;
void DidFinishLoad() override;
void FrameDetached() override;
- void DidStartProvisionalLoad(blink::WebDataSource* data_source) override;
+ void DidStartProvisionalLoad(
+ blink::WebDocumentLoader* document_loader) override;
void WillCommitProvisionalLoad() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_document_navigation) override;
@@ -268,6 +277,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
WebInputToPasswordInfoMap web_input_to_password_info_;
// A (sort-of) reverse map to |web_input_to_password_info_|.
PasswordToLoginMap password_to_username_;
+ // The chronologically last insertion into |web_input_to_password_info_|.
+ WebInputToPasswordInfoMap::iterator last_supplied_password_info_iter_;
// Set if the user might be submitting a password form on the current page,
// but the submit may still fail (i.e. doesn't pass JavaScript validation).
@@ -312,6 +323,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
blink::WebFormElementObserver* form_element_observer_;
+ bool blacklisted_form_found_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
};
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 109439563f7..3d4fe6caf1b 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -371,7 +371,10 @@ void FindVisiblePasswordAndVisibleUsernameBeforePassword(
autofill::PossibleUsernamePair MakePossibleUsernamePair(
const blink::WebInputElement& input) {
- return autofill::PossibleUsernamePair(input.Value().Utf16(),
+ base::string16 trimmed_input_value, trimmed_input_autofill;
+ base::TrimString(input.Value().Utf16(), base::ASCIIToUTF16(" "),
+ &trimmed_input_value);
+ return autofill::PossibleUsernamePair(trimmed_input_value,
input.NameForAutofill().Utf16());
}
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index 210d4f514f7..9440e5d5a47 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -26,7 +26,6 @@
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "google_apis/gaia/gaia_urls.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h"
@@ -155,7 +154,8 @@ PasswordGenerationAgent::AccountCreationFormData::~AccountCreationFormData() {}
PasswordGenerationAgent::PasswordGenerationAgent(
content::RenderFrame* render_frame,
- PasswordAutofillAgent* password_agent)
+ PasswordAutofillAgent* password_agent,
+ service_manager::BinderRegistry* registry)
: content::RenderFrameObserver(render_frame),
password_is_generated_(false),
is_manually_triggered_(false),
@@ -167,9 +167,8 @@ PasswordGenerationAgent::PasswordGenerationAgent(
password_agent_(password_agent),
binding_(this) {
LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_);
- // PasswordGenerationAgent is guaranteed to outlive |render_frame|.
- render_frame->GetInterfaceRegistry()->AddInterface(base::Bind(
- &PasswordGenerationAgent::BindRequest, base::Unretained(this)));
+ registry->AddInterface(base::Bind(&PasswordGenerationAgent::BindRequest,
+ base::Unretained(this)));
}
PasswordGenerationAgent::~PasswordGenerationAgent() {}
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 2af62823a76..c925787dfea 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -19,6 +19,7 @@
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "url/gurl.h"
@@ -35,7 +36,8 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
public mojom::PasswordGenerationAgent {
public:
PasswordGenerationAgent(content::RenderFrame* render_frame,
- PasswordAutofillAgent* password_agent);
+ PasswordAutofillAgent* password_agent,
+ service_manager::BinderRegistry* registry);
~PasswordGenerationAgent() override;
void BindRequest(mojom::PasswordGenerationAgentRequest request);
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 b80e1c6cb7e..887c0cf0207 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
@@ -50,6 +50,11 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
void PasswordFormSubmitted(
const autofill::PasswordForm& password_form) override {}
+ void ShowManualFallbackForSaving(
+ const autofill::PasswordForm& password_form) override {}
+
+ void HideManualFallbackForSaving() override {}
+
void InPageNavigation(const autofill::PasswordForm& password_form) override {}
void PresaveGeneratedPassword(
@@ -67,6 +72,9 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) override {}
+ void ShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
+ const gfx::RectF& bounds) override {}
+
void RecordSavePasswordProgress(const std::string& log) override {
called_record_save_ = true;
log_ = log;
diff --git a/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc b/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc
index 394279fcf28..9fc1a4f642a 100644
--- a/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/test_password_autofill_agent.cc
@@ -7,9 +7,9 @@
namespace autofill {
TestPasswordAutofillAgent::TestPasswordAutofillAgent(
- content::RenderFrame* render_frame)
- : PasswordAutofillAgent(render_frame) {
-}
+ content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry)
+ : PasswordAutofillAgent(render_frame, registry) {}
TestPasswordAutofillAgent::~TestPasswordAutofillAgent() {}
diff --git a/chromium/components/autofill/content/renderer/test_password_autofill_agent.h b/chromium/components/autofill/content/renderer/test_password_autofill_agent.h
index afa8d7885e9..4e037de8088 100644
--- a/chromium/components/autofill/content/renderer/test_password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/test_password_autofill_agent.h
@@ -11,7 +11,8 @@ namespace autofill {
class TestPasswordAutofillAgent : public PasswordAutofillAgent {
public:
- explicit TestPasswordAutofillAgent(content::RenderFrame* render_frame);
+ TestPasswordAutofillAgent(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry);
~TestPasswordAutofillAgent() override;
private:
diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
index 84d937a7989..4076003b313 100644
--- a/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.cc
@@ -7,8 +7,10 @@
namespace autofill {
TestPasswordGenerationAgent::TestPasswordGenerationAgent(
- content::RenderFrame* render_frame, PasswordAutofillAgent* password_agent)
- : PasswordGenerationAgent(render_frame, password_agent) {
+ content::RenderFrame* render_frame,
+ PasswordAutofillAgent* password_agent,
+ service_manager::BinderRegistry* registry)
+ : PasswordGenerationAgent(render_frame, password_agent, registry) {
// Always enable when testing.
set_enabled(true);
}
diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.h b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
index 6ab5509db2b..f752803b7cc 100644
--- a/chromium/components/autofill/content/renderer/test_password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
@@ -9,13 +9,15 @@
#include "base/macros.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
namespace autofill {
class TestPasswordGenerationAgent : public PasswordGenerationAgent {
public:
TestPasswordGenerationAgent(content::RenderFrame* render_frame,
- PasswordAutofillAgent* password_agent);
+ PasswordAutofillAgent* password_agent,
+ service_manager::BinderRegistry* registry);
~TestPasswordGenerationAgent() override;
// PasswordGenreationAgent implementation:
diff --git a/chromium/components/autofill/core/DEPS b/chromium/components/autofill/core/DEPS
index 2ee4fb893c0..fb45023108f 100644
--- a/chromium/components/autofill/core/DEPS
+++ b/chromium/components/autofill/core/DEPS
@@ -1,5 +1,4 @@
include_rules = [
"+components/os_crypt",
"+components/pref_registry",
- "+components/rappor",
]
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 8df55338028..efd501528ef 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -17,6 +17,8 @@ static_library("browser") {
"address_rewriter.cc",
"address_rewriter.h",
"address_rewriter_rules.cc",
+ "address_validation_util.cc",
+ "address_validation_util.h",
"autocomplete_history_manager.cc",
"autocomplete_history_manager.h",
"autofill-inl.h",
@@ -56,6 +58,8 @@ static_library("browser") {
"autofill_profile.h",
"autofill_profile_comparator.cc",
"autofill_profile_comparator.h",
+ "autofill_profile_validator.cc",
+ "autofill_profile_validator.h",
"autofill_provider.cc",
"autofill_provider.h",
"autofill_scanner.cc",
@@ -78,9 +82,6 @@ static_library("browser") {
"credit_card.h",
"credit_card_field.cc",
"credit_card_field.h",
- "detail_input.cc",
- "detail_input.h",
- "dialog_section.h",
"email_field.cc",
"email_field.h",
"field_candidates.cc",
@@ -108,6 +109,8 @@ static_library("browser") {
"personal_data_manager.cc",
"personal_data_manager.h",
"personal_data_manager_observer.h",
+ "phone_email_validation_util.cc",
+ "phone_email_validation_util.h",
"phone_field.cc",
"phone_field.h",
"phone_number.cc",
@@ -121,8 +124,6 @@ static_library("browser") {
"region_data_loader_impl.cc",
"region_data_loader_impl.h",
"risk_data_loader.h",
- "server_field_types_util.cc",
- "server_field_types_util.h",
"state_names.cc",
"state_names.h",
"suggestion.cc",
@@ -209,18 +210,18 @@ static_library("browser") {
"//components/os_crypt",
"//components/pref_registry",
"//components/prefs",
- "//components/rappor",
"//components/security_state/core",
"//components/signin/core/browser",
"//components/signin/core/common",
"//components/strings",
"//components/sync",
- "//components/ukm",
"//components/variations/net",
"//components/version_info",
"//components/webdata/common",
"//google_apis",
"//net",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql",
"//third_party/fips181",
"//third_party/icu",
@@ -283,8 +284,6 @@ static_library("test_support") {
"//components/os_crypt:test_support",
"//components/pref_registry",
"//components/prefs:test_support",
- "//components/rappor",
- "//components/rappor:test_support",
"//components/signin/core/browser",
"//components/signin/core/common",
"//components/ukm",
@@ -329,6 +328,7 @@ source_set("unit_tests") {
"address_i18n_unittest.cc",
"address_rewriter_unittest.cc",
"address_unittest.cc",
+ "address_validation_util_unittest.cc",
"autocomplete_history_manager_unittest.cc",
"autofill_country_unittest.cc",
"autofill_data_model_unittest.cc",
@@ -343,6 +343,7 @@ source_set("unit_tests") {
"autofill_metrics_unittest.cc",
"autofill_profile_comparator_unittest.cc",
"autofill_profile_unittest.cc",
+ "autofill_profile_validator_unittest.cc",
"autofill_type_unittest.cc",
"contact_info_unittest.cc",
"country_combobox_model_unittest.cc",
@@ -356,8 +357,10 @@ source_set("unit_tests") {
"name_field_unittest.cc",
"password_generator_unittest.cc",
"payments/full_card_request_unittest.cc",
+ "payments/payments_client_unittest.cc",
"payments/payments_service_url_unittest.cc",
"personal_data_manager_unittest.cc",
+ "phone_email_validation_util_unittest.cc",
"phone_field_unittest.cc",
"phone_number_i18n_unittest.cc",
"phone_number_unittest.cc",
@@ -388,7 +391,6 @@ source_set("unit_tests") {
"//components/os_crypt",
"//components/os_crypt:test_support",
"//components/prefs:test_support",
- "//components/rappor:test_support",
"//components/resources",
"//components/security_state/core",
"//components/signin/core/browser",
@@ -407,6 +409,7 @@ source_set("unit_tests") {
"//google_apis",
"//google_apis:test_support",
"//net:test_support",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/autofill/core/browser/address.cc b/chromium/components/autofill/core/browser/address.cc
index c950f69c277..b279e873f83 100644
--- a/chromium/components/autofill/core/browser/address.cc
+++ b/chromium/components/autofill/core/browser/address.cc
@@ -160,8 +160,52 @@ void Address::SetRawInfo(ServerFieldType type, const base::string16& value) {
}
}
-base::string16 Address::GetInfo(const AutofillType& type,
- const std::string& app_locale) const {
+void Address::GetMatchingTypes(const base::string16& text,
+ const std::string& app_locale,
+ ServerFieldTypeSet* matching_types) const {
+ FormGroup::GetMatchingTypes(text, app_locale, matching_types);
+
+ // Check to see if the |text| canonicalized as a country name is a match.
+ std::string country_code = CountryNames::GetInstance()->GetCountryCode(text);
+ if (!country_code.empty() && country_code_ == country_code)
+ matching_types->insert(ADDRESS_HOME_COUNTRY);
+
+ AutofillProfileComparator comparator(app_locale);
+ // Check to see if the |text| could be the full name or abbreviation of a
+ // state.
+ base::string16 canon_text = comparator.NormalizeForComparison(text);
+ base::string16 state_name;
+ base::string16 state_abbreviation;
+ state_names::GetNameAndAbbreviation(canon_text, &state_name,
+ &state_abbreviation);
+ if (!state_name.empty() || !state_abbreviation.empty()) {
+ l10n::CaseInsensitiveCompare compare;
+ base::string16 canon_profile_state = comparator.NormalizeForComparison(
+ GetInfo(AutofillType(ADDRESS_HOME_STATE), app_locale));
+ if ((!state_name.empty() &&
+ compare.StringsEqual(state_name, canon_profile_state)) ||
+ (!state_abbreviation.empty() &&
+ compare.StringsEqual(state_abbreviation, canon_profile_state))) {
+ matching_types->insert(ADDRESS_HOME_STATE);
+ }
+ }
+}
+
+void Address::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
+ supported_types->insert(ADDRESS_HOME_LINE1);
+ supported_types->insert(ADDRESS_HOME_LINE2);
+ supported_types->insert(ADDRESS_HOME_LINE3);
+ supported_types->insert(ADDRESS_HOME_STREET_ADDRESS);
+ supported_types->insert(ADDRESS_HOME_DEPENDENT_LOCALITY);
+ supported_types->insert(ADDRESS_HOME_CITY);
+ supported_types->insert(ADDRESS_HOME_STATE);
+ supported_types->insert(ADDRESS_HOME_ZIP);
+ supported_types->insert(ADDRESS_HOME_SORTING_CODE);
+ supported_types->insert(ADDRESS_HOME_COUNTRY);
+}
+
+base::string16 Address::GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const {
if (type.html_type() == HTML_TYPE_COUNTRY_CODE)
return base::ASCIIToUTF16(country_code_);
@@ -172,9 +216,9 @@ base::string16 Address::GetInfo(const AutofillType& type,
return GetRawInfo(storable_type);
}
-bool Address::SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) {
+bool Address::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
if (!data_util::IsValidCountryCode(base::i18n::ToUpper(value))) {
country_code_ = std::string();
@@ -208,51 +252,6 @@ bool Address::SetInfo(const AutofillType& type,
return true;
}
-void Address::GetMatchingTypes(const base::string16& text,
- const std::string& app_locale,
- ServerFieldTypeSet* matching_types) const {
- FormGroup::GetMatchingTypes(text, app_locale, matching_types);
-
- // Check to see if the |text| canonicalized as a country name is a match.
- std::string country_code = CountryNames::GetInstance()->GetCountryCode(text);
- if (!country_code.empty() && country_code_ == country_code)
- matching_types->insert(ADDRESS_HOME_COUNTRY);
-
- AutofillProfileComparator comparator(app_locale);
- // Check to see if the |text| could be the full name or abbreviation of a
- // state.
- base::string16 canon_text = comparator.NormalizeForComparison(text);
- base::string16 state_name;
- base::string16 state_abbreviation;
- state_names::GetNameAndAbbreviation(canon_text, &state_name,
- &state_abbreviation);
- if (!state_name.empty() || !state_abbreviation.empty()) {
- l10n::CaseInsensitiveCompare compare;
- base::string16 canon_profile_state =
- comparator.NormalizeForComparison(
- GetInfo(AutofillType(ADDRESS_HOME_STATE), app_locale));
- if ((!state_name.empty() &&
- compare.StringsEqual(state_name, canon_profile_state)) ||
- (!state_abbreviation.empty() &&
- compare.StringsEqual(state_abbreviation, canon_profile_state))) {
- matching_types->insert(ADDRESS_HOME_STATE);
- }
- }
-}
-
-void Address::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
- supported_types->insert(ADDRESS_HOME_LINE1);
- supported_types->insert(ADDRESS_HOME_LINE2);
- supported_types->insert(ADDRESS_HOME_LINE3);
- supported_types->insert(ADDRESS_HOME_STREET_ADDRESS);
- supported_types->insert(ADDRESS_HOME_DEPENDENT_LOCALITY);
- supported_types->insert(ADDRESS_HOME_CITY);
- supported_types->insert(ADDRESS_HOME_STATE);
- supported_types->insert(ADDRESS_HOME_ZIP);
- supported_types->insert(ADDRESS_HOME_SORTING_CODE);
- supported_types->insert(ADDRESS_HOME_COUNTRY);
-}
-
void Address::TrimStreetAddress() {
while (!street_address_.empty() && street_address_.back().empty()) {
street_address_.pop_back();
diff --git a/chromium/components/autofill/core/browser/address.h b/chromium/components/autofill/core/browser/address.h
index a37d485f344..9c1721f9869 100644
--- a/chromium/components/autofill/core/browser/address.h
+++ b/chromium/components/autofill/core/browser/address.h
@@ -28,11 +28,7 @@ class Address : public FormGroup {
// FormGroup:
base::string16 GetRawInfo(ServerFieldType type) const override;
void SetRawInfo(ServerFieldType type, const base::string16& value) override;
- base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const override;
- bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) override;
+
void GetMatchingTypes(const base::string16& text,
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const override;
@@ -40,6 +36,11 @@ class Address : public FormGroup {
private:
// FormGroup:
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
+ base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const override;
+ bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) override;
// Trims any trailing newlines from |street_address_|.
void TrimStreetAddress();
diff --git a/chromium/components/autofill/core/browser/address_i18n.cc b/chromium/components/autofill/core/browser/address_i18n.cc
index a983e2533b3..abbde7aae1f 100644
--- a/chromium/components/autofill/core/browser/address_i18n.cc
+++ b/chromium/components/autofill/core/browser/address_i18n.cc
@@ -12,6 +12,7 @@
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h"
namespace autofill {
namespace i18n {
@@ -146,5 +147,14 @@ bool FieldForType(ServerFieldType server_type, AddressField* field) {
}
}
+bool IsFieldRequired(ServerFieldType server_type,
+ const std::string& country_code) {
+ ::i18n::addressinput::AddressField field_enum;
+ if (FieldForType(server_type, &field_enum)) {
+ return ::i18n::addressinput::IsFieldRequired(field_enum, country_code);
+ }
+ return false;
+}
+
} // namespace i18n
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_i18n.h b/chromium/components/autofill/core/browser/address_i18n.h
index 6473ee579d8..31fc25e4767 100644
--- a/chromium/components/autofill/core/browser/address_i18n.h
+++ b/chromium/components/autofill/core/browser/address_i18n.h
@@ -45,6 +45,11 @@ ServerFieldType TypeForField(::i18n::addressinput::AddressField field,
bool FieldForType(ServerFieldType server_type,
::i18n::addressinput::AddressField* field);
+// Returns whether the field specified by |server_type| is required for this
+// |country_code|, according to the libaddressinput metadata.
+bool IsFieldRequired(ServerFieldType server_type,
+ const std::string& country_code);
+
} // namespace i18n
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_i18n_unittest.cc b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
index 7b0a9a0da21..4765e88d932 100644
--- a/chromium/components/autofill/core/browser/address_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
@@ -157,5 +157,15 @@ TEST(AddressI18nTest, CreateAddressDataFromAutofillProfile) {
EXPECT_EQ(expected, *actual);
}
+TEST(AddressI18nTest, IsFieldRequired) {
+ EXPECT_TRUE(IsFieldRequired(ADDRESS_HOME_LINE1, "CA"));
+
+ EXPECT_FALSE(IsFieldRequired(ADDRESS_HOME_SORTING_CODE, "CA"));
+ EXPECT_FALSE(IsFieldRequired(ADDRESS_HOME_SORTING_CODE, "FR"));
+
+ EXPECT_TRUE(IsFieldRequired(ADDRESS_HOME_STATE, "AE"));
+ EXPECT_FALSE(IsFieldRequired(ADDRESS_HOME_STATE, "BS"));
+}
+
} // namespace i18n
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_validation_util.cc b/chromium/components/autofill/core/browser/address_validation_util.cc
new file mode 100644
index 00000000000..76b056dc178
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_validation_util.cc
@@ -0,0 +1,155 @@
+// 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/autofill/core/browser/address_validation_util.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/address_i18n.h"
+#include "components/autofill/core/browser/country_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
+
+namespace autofill {
+
+namespace {
+
+using ::i18n::addressinput::COUNTRY;
+using ::i18n::addressinput::ADMIN_AREA;
+using ::i18n::addressinput::LOCALITY;
+using ::i18n::addressinput::DEPENDENT_LOCALITY;
+using ::i18n::addressinput::SORTING_CODE;
+using ::i18n::addressinput::POSTAL_CODE;
+using ::i18n::addressinput::STREET_ADDRESS;
+using ::i18n::addressinput::RECIPIENT;
+
+using ::i18n::addressinput::AddressData;
+using ::i18n::addressinput::AddressField;
+using ::i18n::addressinput::AddressProblem;
+using ::i18n::addressinput::FieldProblemMap;
+
+using ::i18n::addressinput::INVALID_FORMAT;
+using ::i18n::addressinput::MISMATCHING_VALUE;
+using ::i18n::addressinput::MISSING_REQUIRED_FIELD;
+using ::i18n::addressinput::UNEXPECTED_FIELD;
+using ::i18n::addressinput::UNKNOWN_VALUE;
+
+const AddressField kFields[] = {COUNTRY, ADMIN_AREA, POSTAL_CODE};
+const AddressProblem kProblems[] = {UNEXPECTED_FIELD, MISSING_REQUIRED_FIELD,
+ UNKNOWN_VALUE, INVALID_FORMAT,
+ MISMATCHING_VALUE};
+
+// If the |address_field| is valid, set the validity state of the
+// |address_field| in the |profile| to the |state| and return true.
+// Otherwise, return false.
+bool SetValidityStateForAddressField(AutofillProfile* profile,
+ AddressField address_field,
+ AutofillProfile::ValidityState state) {
+ ServerFieldType server_field = i18n::TypeForField(address_field,
+ /*billing=*/false);
+ if (server_field == UNKNOWN_TYPE)
+ return false;
+ DCHECK(profile);
+ profile->SetValidityState(server_field, state);
+ return true;
+}
+
+// Set the validity state of all address fields in the |profile| to |state|.
+void SetAllValidityStates(AutofillProfile* profile,
+ AutofillProfile::ValidityState state) {
+ DCHECK(profile);
+ for (auto field : kFields)
+ SetValidityStateForAddressField(profile, field, state);
+}
+
+// Returns all relevant pairs of (field, problem), where field is in
+// |kFields|, and problem is in |kProblems|.
+FieldProblemMap* CreateFieldProblemMap() {
+ FieldProblemMap* filter = new FieldProblemMap();
+ for (auto field : kFields) {
+ for (auto problem : kProblems) {
+ filter->insert(std::make_pair(field, problem));
+ }
+ }
+ return filter;
+}
+
+// GetFilter() will make sure that the validation only returns problems that
+// are relevant.
+const FieldProblemMap* GetFilter() {
+ static const FieldProblemMap* const filter = CreateFieldProblemMap();
+ return filter;
+}
+
+// Initializes |address| data from the address info in the |profile|.
+void InitializeAddressFromProfile(const AutofillProfile& profile,
+ AddressData* address) {
+ address->region_code =
+ base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
+ address->administrative_area =
+ base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE));
+ address->postal_code =
+ base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP));
+}
+
+} // namespace
+
+namespace address_validation_util {
+
+AutofillProfile::ValidityState ValidateAddress(
+ AutofillProfile* profile,
+ AddressValidator* address_validator) {
+ DCHECK(address_validator);
+ if (!profile)
+ return AutofillProfile::UNVALIDATED;
+
+ if (!base::ContainsValue(
+ CountryDataMap::GetInstance()->country_codes(),
+ base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY)))) {
+ // If the country code is not in the database, the country code and the
+ // profile are invalid, and other fields cannot be validated, because it is
+ // unclear which, if any, rule should apply.
+ SetAllValidityStates(profile, AutofillProfile::UNVALIDATED);
+ SetValidityStateForAddressField(profile, COUNTRY, AutofillProfile::INVALID);
+ return AutofillProfile::INVALID;
+ }
+
+ AddressData address;
+ InitializeAddressFromProfile(*profile, &address);
+
+ AutofillProfile::ValidityState profile_validity;
+ FieldProblemMap problems;
+ // status denotes if the rule was successfully loaded before validation.
+ AddressValidator::Status status =
+ address_validator->ValidateAddress(address, GetFilter(), &problems);
+
+ if (status == AddressValidator::SUCCESS) {
+ // The rules were found and applied. Initialize all fields to VALID here and
+ // update the fields with problems below.
+ profile_validity = AutofillProfile::VALID;
+ SetAllValidityStates(profile, AutofillProfile::VALID);
+ } else {
+ // If the rules are not yet available, ValidateAddress can still check for
+ // MISSING_REQUIRED_FIELD. In this case, the address fields will be either
+ // UNVALIDATED or INVALID.
+ profile_validity = AutofillProfile::UNVALIDATED;
+ SetAllValidityStates(profile, AutofillProfile::UNVALIDATED);
+ SetValidityStateForAddressField(profile, COUNTRY, AutofillProfile::VALID);
+ }
+
+ for (auto problem : problems) {
+ if (SetValidityStateForAddressField(profile, problem.first,
+ AutofillProfile::INVALID)) {
+ profile_validity = AutofillProfile::INVALID;
+ }
+ }
+ return profile_validity;
+}
+
+} // namespace address_validation_util
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_validation_util.h b/chromium/components/autofill/core/browser/address_validation_util.h
new file mode 100644
index 00000000000..c58c6959966
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_validation_util.h
@@ -0,0 +1,23 @@
+// 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_AUTOFILL_CORE_BROWSER_ADDRESS_VALIDATION_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_VALIDATION_UTIL_H_
+
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
+
+namespace autofill {
+namespace address_validation_util {
+
+// Validates the address fields of the |profile|.
+// Returns the ValidityState of the |profile| according to its address fields.
+AutofillProfile::ValidityState ValidateAddress(
+ AutofillProfile* profile,
+ AddressValidator* address_validator);
+
+} // namespace address_validation_util
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_VALIDATION_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/address_validation_util_unittest.cc b/chromium/components/autofill/core/browser/address_validation_util_unittest.cc
new file mode 100644
index 00000000000..604995c8124
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_validation_util_unittest.cc
@@ -0,0 +1,232 @@
+// 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/autofill/core/browser/address_validation_util.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
+#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
+
+namespace autofill {
+
+using ::i18n::addressinput::Source;
+using ::i18n::addressinput::Storage;
+using ::i18n::addressinput::NullStorage;
+using ::i18n::addressinput::TestdataSource;
+
+// Used to load region rules for this test.
+class ValidationTestDataSource : public TestdataSource {
+ public:
+ ValidationTestDataSource() : TestdataSource(true) {}
+
+ ~ValidationTestDataSource() override {}
+
+ void Get(const std::string& key, const Callback& data_ready) const override {
+ data_ready(
+ true, key,
+ new std::string(
+ "{"
+ "\"data/CA\": "
+ "{\"lang\": \"en\", \"upper\": \"ACNOSZ\", "
+ "\"zipex\": \"H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0\", "
+ "\"name\": \"CANADA\", "
+ "\"fmt\": \"%N%n%O%n%A%n%C %S %Z\", \"id\": \"data/CA\", "
+ "\"languages\": \"en~fr\", \"sub_keys\": \"NB~QC\", \"key\": "
+ "\"CA\", "
+ "\"require\": \"ACSZ\", \"sub_names\": \"New Brunswick~Quebec\", "
+ "\"sub_zips\": \"E~G|H|J\"}, "
+ "\"data/CA--fr\": "
+ "{\"lang\": \"fr\", \"upper\": \"ACNOSZ\", "
+ "\"zipex\": \"H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0\", "
+ "\"name\": \"CANADA\", "
+ "\"fmt\": \"%N%n%O%n%A%n%C %S %Z\", \"require\": \"ACSZ\", "
+ "\"sub_keys\": \"NB~QC\", \"key\": \"CA\", "
+ "\"id\": \"data/CA--fr\", "
+ "\"sub_names\":\"Nouveau-Brunswick~Québec\","
+ "\"sub_zips\": \"E~G|H|J\"}, "
+ "\"data/CA/QC\": "
+ "{\"lang\": \"en\", \"key\": \"QC\", "
+ "\"id\": \"data/CA/QC\", \"zip\": \"G|H|J\", \"name\": \"Quebec\"},"
+ "\"data/CA/QC--fr\": "
+ "{\"lang\": \"fr\", \"key\": \"QC\", \"id\": \"data/CA/QC--fr\", "
+ "\"zip\": \"G|H|J\", \"name\": \"Québec\"}, "
+ "\"data/CA/NB\": "
+ "{\"lang\": \"en\", \"key\": \"NB\", \"id\": \"data/CA/NB\", "
+ "\"zip\": \"E\", \"name\": \"New Brunswick\"}, "
+ "\"data/CA/NB--fr\": "
+ "{\"lang\": \"fr\", \"key\": \"NB\", \"id\": \"data/CA/NB--fr\", "
+ "\"zip\": \"E\", \"name\": \"Nouveau-Brunswick\"}"
+ "}"));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValidationTestDataSource);
+};
+
+class AutofillAddressValidationTest : public testing::Test, LoadRulesListener {
+ public:
+ AutofillAddressValidationTest()
+ : validator_(std::unique_ptr<Source>(new ValidationTestDataSource()),
+ std::unique_ptr<Storage>(new NullStorage),
+ this) {
+ validator_.LoadRules("CA");
+ }
+
+ AutofillProfile::ValidityState ValidateAddressTest(AutofillProfile* profile) {
+ return address_validation_util::ValidateAddress(profile, &validator_);
+ }
+
+ ~AutofillAddressValidationTest() override {}
+
+ private:
+ AddressValidator validator_;
+
+ // LoadRulesListener implementation.
+ void OnAddressValidationRulesLoaded(const std::string& country_code,
+ bool success) override {}
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillAddressValidationTest);
+};
+
+TEST_F(AutofillAddressValidationTest, ValidateNULLProfile) {
+ EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidateAddressTest(nullptr));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateFullValidProfile) {
+ // This is a valid profile according to the rules in ValidationTestDataSource:
+ // Address Line 1: "666 Notre-Dame Ouest",
+ // Address Line 2: "Apt 8", City: "Montreal", Province: "QC",
+ // Postal Code: "H3B 2T9", Country Code: "CA",
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ EXPECT_EQ(AutofillProfile::VALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateFullProfile_CountryCodeNotExist) {
+ // This is a profile with invalid country code, therefore it cannot be
+ // validated according to ValidationTestDataSource.
+ const std::string country_code = "PP";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateFullProfile_RuleNotAvailable) {
+ // This is a profile with valid country code, but the rule is not available in
+ // the ValidationTestDataSource.
+ const std::string country_code = "US";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaNotExists) {
+ const std::string admin_area_code = "QQ";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area_code));
+
+ EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaFullName) {
+ const std::string admin_area = "Quebec";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
+
+ EXPECT_EQ(AutofillProfile::VALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaSmallCode) {
+ const std::string admin_area = "qc";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
+
+ EXPECT_EQ(AutofillProfile::VALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaSpecialLetter) {
+ const std::string admin_area = "Québec";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
+
+ EXPECT_EQ(AutofillProfile::VALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_ValidZipNoSpace) {
+ // TODO(crbug/752614): postal codes in lower case letters should also be
+ // considered as valid. Now, they are considered as INVALID.
+ const std::string postal_code = "H3C6S3";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
+
+ EXPECT_EQ(AutofillProfile::VALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+TEST_F(AutofillAddressValidationTest, ValidateAddress_InvalidZip) {
+ const std::string postal_code = "ABC 123";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
+
+ EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(ADDRESS_HOME_ZIP));
+}
+
+// TODO(crbug/754727): add tests for a non-default language.
+// Ex: Nouveau-Brunswick for Canada.
+
+// TODO(crbug/754729): Add tests for a country whose default language is a
+// non-Western one, such as China.
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_assistant.cc b/chromium/components/autofill/core/browser/autofill_assistant.cc
index 02b20bd98bf..7453cc19d0a 100644
--- a/chromium/components/autofill/core/browser/autofill_assistant.cc
+++ b/chromium/components/autofill/core/browser/autofill_assistant.cc
@@ -59,8 +59,10 @@ void AutofillAssistant::OnUserDidAcceptCreditCardFill(const CreditCard& card) {
autofill_manager_->GetAsFullCardRequestUIDelegate());
}
-void AutofillAssistant::OnFullCardRequestSucceeded(const CreditCard& card,
- const base::string16& cvc) {
+void AutofillAssistant::OnFullCardRequestSucceeded(
+ const payments::FullCardRequest& /* full_card_request */,
+ const CreditCard& card,
+ const base::string16& cvc) {
autofill_manager_->FillCreditCardForm(kNoQueryId, *credit_card_form_data_,
credit_card_form_data_->fields[0], card,
cvc);
diff --git a/chromium/components/autofill/core/browser/autofill_assistant.h b/chromium/components/autofill/core/browser/autofill_assistant.h
index b383faa6ae9..79f097f82b3 100644
--- a/chromium/components/autofill/core/browser/autofill_assistant.h
+++ b/chromium/components/autofill/core/browser/autofill_assistant.h
@@ -44,8 +44,10 @@ class AutofillAssistant : public payments::FullCardRequest::ResultDelegate {
void OnUserDidAcceptCreditCardFill(const CreditCard& card);
// payments::FullCardRequest::ResultDelegate:
- void OnFullCardRequestSucceeded(const CreditCard& card,
- const base::string16& cvc) override;
+ void OnFullCardRequestSucceeded(
+ const payments::FullCardRequest& full_card_request,
+ const CreditCard& card,
+ const base::string16& cvc) override;
void OnFullCardRequestFailed() override;
// Holds the FormData to be filled with a credit card.
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index 149b6685d0f..caee854be97 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -29,10 +29,6 @@ namespace gfx {
class RectF;
}
-namespace rappor {
-class RapporServiceImpl;
-}
-
namespace syncer {
class SyncService;
}
@@ -108,9 +104,6 @@ class AutofillClient : public RiskDataLoader {
// Gets the IdentityProvider associated with the client (for OAuth2).
virtual IdentityProvider* GetIdentityProvider() = 0;
- // Gets the RapporServiceImpl associated with the client (for metrics).
- virtual rappor::RapporServiceImpl* GetRapporServiceImpl() = 0;
-
// Gets the UKM service associated with this client (for metrics).
virtual ukm::UkmRecorder* GetUkmRecorder() = 0;
@@ -193,16 +186,12 @@ class AutofillClient : public RiskDataLoader {
// Whether it is appropriate to show a signin promo for this user.
virtual bool ShouldShowSigninPromo() = 0;
- // Starts the signin flow. Should not be called if ShouldShowSigninPromo()
- // returns false.
- virtual void StartSigninFlow() = 0;
-
- // Shows the explanation of http not secure warning message.
- virtual void ShowHttpNotSecureExplanation() = 0;
-
// Whether Autofill is currently supported by the client. If false, all
// features of Autofill are disabled, including Autocomplete.
virtual bool IsAutofillSupported() = 0;
+
+ // Handles simple actions for the autofill popups.
+ virtual void ExecuteCommand(int id) = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 8d7d72588f4..d2551b9c4f5 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -50,7 +50,7 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"You can enable or disable this feature via 'Enable autofill to "
"fill out web forms in a single click.' in Chromium's settings "
@@ -84,7 +84,7 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"You can enable or disable this feature via 'Enable autofill to "
"fill out web forms in a single click.' in Chromium's settings "
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory.h b/chromium/components/autofill/core/browser/autofill_driver_factory.h
index f5e21c68257..cfb7d05b855 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory.h
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory.h
@@ -28,7 +28,7 @@ class AutofillDriverFactory {
// null if there is none.
AutofillDriver* DriverForKey(void* key);
- // Handles finished navigation in any of the frames.
+ // Handles finished navigation in the main frame.
void NavigationFinished();
// Handles hiding of the corresponding tab.
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index 6466e071eee..e727dd6159e 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -38,10 +38,17 @@ const base::Feature kAutofillCreditCardLastUsedDateDisplay{
const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered{
"AutofillOfferLocalSaveIfServerCardManuallyEntered",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillRationalizeFieldTypePredictions{
+ "AutofillRationalizeFieldTypePredictions",
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kAutofillSuppressDisusedAddresses{
"AutofillSuppressDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillUpstreamRequestCvcIfMissing{
"AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamShowGoogleLogo{
+ "AutofillUpstreamShowGoogleLogo", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamShowNewUi{
+ "AutofillUpstreamShowNewUi", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillUpstreamUseAutofillProfileComparator{
"AutofillUpstreamUseAutofillProfileComparator",
base::FEATURE_ENABLED_BY_DEFAULT};
@@ -263,6 +270,22 @@ bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled() {
#endif
}
+bool IsAutofillUpstreamShowGoogleLogoExperimentEnabled() {
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return base::FeatureList::IsEnabled(kAutofillUpstreamShowGoogleLogo);
+#endif
+}
+
+bool IsAutofillUpstreamShowNewUiExperimentEnabled() {
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return base::FeatureList::IsEnabled(kAutofillUpstreamShowNewUi);
+#endif
+}
+
base::TimeDelta GetMaxTimeSinceAutofillProfileUseForCardUpload() {
int value;
const std::string param_value = variations::GetVariationParamValueByFeature(
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index 0ae7639e9a4..6fcc5168320 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -32,8 +32,11 @@ extern const base::Feature kAutofillCreditCardBankNameDisplay;
extern const base::Feature kAutofillCreditCardPopupLayout;
extern const base::Feature kAutofillCreditCardLastUsedDateDisplay;
extern const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered;
+extern const base::Feature kAutofillRationalizeFieldTypePredictions;
extern const base::Feature kAutofillSuppressDisusedAddresses;
extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
+extern const base::Feature kAutofillUpstreamShowGoogleLogo;
+extern const base::Feature kAutofillUpstreamShowNewUi;
extern const base::Feature kAutofillUpstreamUseAutofillProfileComparator;
extern const base::Feature kAutofillUpstreamUseNotRecentlyUsedAutofillProfile;
extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
@@ -125,6 +128,14 @@ bool IsAutofillOfferLocalSaveIfServerCardManuallyEnteredExperimentEnabled();
// in the offer to save bubble if it was not detected during the checkout flow.
bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled();
+// Returns whether the experiment is enabled where Chrome Upstream displays a
+// Google Logo in the save card bubble/infobar.
+bool IsAutofillUpstreamShowGoogleLogoExperimentEnabled();
+
+// Returns whether the experiment is enabled where Chrome Upstream displays a
+// new save card bubble/infobar design.
+bool IsAutofillUpstreamShowNewUiExperimentEnabled();
+
// Returns the maximum time that could have elapsed since an address profile's
// most recent use for the adress profile to be included in the candidate set
// for card upload. Returns 0 if the experiment is not enabled.
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index 27e046d10b6..329712ea425 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -227,11 +227,9 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
} else if (identifier == POPUP_ITEM_ID_SCAN_CREDIT_CARD) {
manager_->client()->ScanCreditCard(base::Bind(
&AutofillExternalDelegate::OnCreditCardScanned, GetWeakPtr()));
- } else if (identifier == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
- manager_->client()->StartSigninFlow();
- } else if (identifier == POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
- AutofillMetrics::LogShowedHttpNotSecureExplanation();
- manager_->client()->ShowHttpNotSecureExplanation();
+ } else if (identifier == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO ||
+ identifier == POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
+ manager_->client()->ExecuteCommand(identifier);
} else {
if (identifier > 0) // Denotes an Autofill suggestion.
AutofillMetrics::LogAutofillSuggestionAcceptedIndex(position);
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 11f7ce910e4..48d34db2443 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -78,9 +78,7 @@ class MockAutofillClient : public TestAutofillClient {
MOCK_METHOD0(HideAutofillPopup, void());
- MOCK_METHOD0(StartSigninFlow, void());
-
- MOCK_METHOD0(ShowHttpNotSecureExplanation, void());
+ MOCK_METHOD1(ExecuteCommand, void(int));
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
@@ -262,7 +260,8 @@ TEST_F(AutofillExternalDelegateUnitTest,
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Signin_Impression_FromAutofillDropdown"));
- EXPECT_CALL(autofill_client_, StartSigninFlow());
+ EXPECT_CALL(autofill_client_,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
EXPECT_CALL(autofill_client_, HideAutofillPopup());
// This should trigger a call to start the signin flow and hide the popup
@@ -667,7 +666,8 @@ TEST_F(AutofillExternalDelegateUnitTest, ScanCreditCardPromptMetricsTest) {
// Test that autofill client will start the signin flow after the user accepted
// the suggestion to sign in.
TEST_F(AutofillExternalDelegateUnitTest, SigninPromoMenuItem) {
- EXPECT_CALL(autofill_client_, StartSigninFlow());
+ EXPECT_CALL(autofill_client_,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
EXPECT_CALL(autofill_client_, HideAutofillPopup());
external_delegate_->DidAcceptSuggestion(
base::string16(), POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO, 0);
@@ -676,7 +676,9 @@ TEST_F(AutofillExternalDelegateUnitTest, SigninPromoMenuItem) {
// Test that autofill client will open the security indicator help center url
// after the user accepted the http warning message suggestion item.
TEST_F(AutofillExternalDelegateUnitTest, HttpWarningMessageItem) {
- EXPECT_CALL(autofill_client_, ShowHttpNotSecureExplanation());
+ EXPECT_CALL(
+ autofill_client_,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
EXPECT_CALL(autofill_client_, HideAutofillPopup());
external_delegate_->DidAcceptSuggestion(
base::string16(), POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE, 0);
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index 1f37285c510..af0cddb0fea 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -543,7 +543,9 @@ AutofillField::AutofillField()
credit_card_number_offset_(0),
previously_autofilled_(false),
generation_type_(AutofillUploadContents::Field::NO_GENERATION),
- form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME) {}
+ generated_password_changed_(false),
+ form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME),
+ username_vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
AutofillField::AutofillField(const FormFieldData& field,
const base::string16& unique_name)
@@ -558,7 +560,9 @@ AutofillField::AutofillField(const FormFieldData& field,
previously_autofilled_(false),
parseable_name_(field.name),
generation_type_(AutofillUploadContents::Field::NO_GENERATION),
- form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME) {}
+ generated_password_changed_(false),
+ form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME),
+ username_vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
AutofillField::~AutofillField() {}
@@ -594,6 +598,17 @@ void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) {
phone_part_ = IGNORED;
}
+void AutofillField::SetTypeTo(ServerFieldType type) {
+ if (type == UNKNOWN_TYPE || type == NO_SERVER_DATA) {
+ heuristic_type_ = UNKNOWN_TYPE;
+ server_type_ = NO_SERVER_DATA;
+ } else if (server_type_ == NO_SERVER_DATA) {
+ heuristic_type_ = type;
+ } else {
+ server_type_ = type;
+ }
+}
+
AutofillType AutofillField::Type() const {
// Use the html type specified by the website unless it is unrecognized and
// autofill predicts a credit card type.
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index ebe5d0b8c80..edfb606627b 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -59,6 +59,10 @@ class AutofillField : public FormFieldData {
parseable_name_ = parseable_name;
}
+ // Set the heuristic or server type, depending on whichever is currently
+ // assigned, to |type|.
+ void SetTypeTo(ServerFieldType type);
+
// This function automatically chooses between server and heuristic autofill
// type, depending on the data available.
AutofillType Type() const;
@@ -112,6 +116,14 @@ class AutofillField : public FormFieldData {
return form_classifier_outcome_;
}
+ void set_username_vote_type(
+ AutofillUploadContents::Field::UsernameVoteType type) {
+ username_vote_type_ = type;
+ }
+ AutofillUploadContents::Field::UsernameVoteType username_vote_type() const {
+ return username_vote_type_;
+ }
+
// Set |field_data|'s value to |value|. Uses |field|, |address_language_code|,
// and |app_locale| as hints when filling exceptional cases like phone number
// values and <select> fields. Returns |true| if the field has been filled,
@@ -189,6 +201,10 @@ class AutofillField : public FormFieldData {
// The outcome of HTML parsing based form classifier.
AutofillUploadContents::Field::FormClassifierOutcome form_classifier_outcome_;
+ // The username vote type, if the autofill type is USERNAME. Otherwise, the
+ // field is ignored.
+ AutofillUploadContents::Field::UsernameVoteType username_vote_type_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillField);
};
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 1c46141d75f..31143c2309a 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -68,8 +68,6 @@
#include "components/autofill/core/common/signatures_util.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
-#include "components/rappor/public/rappor_utils.h"
-#include "components/rappor/rappor_service_impl.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "google_apis/gaia/identity_provider.h"
@@ -528,7 +526,8 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
UpdatePendingForm(form);
if (!user_did_type_ || autofill_field->is_autofilled)
- form_interactions_ukm_logger_->LogTextFieldDidChange(*autofill_field);
+ form_interactions_ukm_logger_->LogTextFieldDidChange(
+ *autofill_field, form_structure->form_parsed_timestamp());
if (!user_did_type_) {
user_did_type_ = true;
@@ -736,6 +735,10 @@ void AutofillManager::FillOrPreviewCreditCardForm(
const FormData& form,
const FormFieldData& field,
const CreditCard& credit_card) {
+ FormStructure* form_structure = NULL;
+ AutofillField* autofill_field = NULL;
+ if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
+ return;
if (action == AutofillDriver::FORM_DATA_ACTION_FILL) {
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD &&
WillFillCreditCardNumber(form, field)) {
@@ -743,18 +746,22 @@ void AutofillManager::FillOrPreviewCreditCardForm(
unmasking_form_ = form;
unmasking_field_ = field;
masked_card_ = credit_card;
- GetOrCreateFullCardRequest()->GetFullCard(
+ payments::FullCardRequest* full_card_request =
+ CreateFullCardRequest(form_structure->form_parsed_timestamp());
+ full_card_request->GetFullCard(
masked_card_, AutofillClient::UNMASK_FOR_AUTOFILL,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr());
- credit_card_form_event_logger_->OnDidSelectMaskedServerCardSuggestion();
+ credit_card_form_event_logger_->OnDidSelectMaskedServerCardSuggestion(
+ form_structure->form_parsed_timestamp());
return;
}
- credit_card_form_event_logger_->OnDidFillSuggestion(credit_card);
+ credit_card_form_event_logger_->OnDidFillSuggestion(
+ credit_card, form_structure->form_parsed_timestamp());
}
- FillOrPreviewDataModelForm(action, query_id, form, field, credit_card,
- true /* is_credit_card */,
- base::string16() /* cvc */);
+ FillOrPreviewDataModelForm(
+ action, query_id, form, field, credit_card, true /* is_credit_card */,
+ base::string16() /* cvc */, form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewProfileForm(
@@ -763,12 +770,17 @@ void AutofillManager::FillOrPreviewProfileForm(
const FormData& form,
const FormFieldData& field,
const AutofillProfile& profile) {
+ FormStructure* form_structure = NULL;
+ AutofillField* autofill_field = NULL;
+ if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
+ return;
if (action == AutofillDriver::FORM_DATA_ACTION_FILL)
- address_form_event_logger_->OnDidFillSuggestion(profile);
+ address_form_event_logger_->OnDidFillSuggestion(
+ profile, form_structure->form_parsed_timestamp());
- FillOrPreviewDataModelForm(action, query_id, form, field, profile,
- false /* is_credit_card */,
- base::string16() /* cvc */);
+ FillOrPreviewDataModelForm(
+ action, query_id, form, field, profile, false /* is_credit_card */,
+ base::string16() /* cvc */, form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewForm(
@@ -858,9 +870,11 @@ void AutofillManager::DidShowSuggestions(bool is_new_popup,
}
if (autofill_field->Type().group() == CREDIT_CARD) {
- credit_card_form_event_logger_->OnDidShowSuggestions(*autofill_field);
+ credit_card_form_event_logger_->OnDidShowSuggestions(
+ *autofill_field, form_structure->form_parsed_timestamp());
} else {
- address_form_event_logger_->OnDidShowSuggestions(*autofill_field);
+ address_form_event_logger_->OnDidShowSuggestions(
+ *autofill_field, form_structure->form_parsed_timestamp());
}
}
}
@@ -970,7 +984,13 @@ payments::FullCardRequest* AutofillManager::GetOrCreateFullCardRequest() {
full_card_request_.reset(new payments::FullCardRequest(
client_, payments_client_.get(), personal_data_));
}
+ return full_card_request_.get();
+}
+payments::FullCardRequest* AutofillManager::CreateFullCardRequest(
+ const base::TimeTicks& form_parsed_timestamp) {
+ full_card_request_.reset(new payments::FullCardRequest(
+ client_, payments_client_.get(), personal_data_, form_parsed_timestamp));
return full_card_request_.get();
}
@@ -1011,8 +1031,7 @@ void AutofillManager::OnLoadedServerPredictions(
return;
// Parse and store the server predictions.
- FormStructure::ParseQueryResponse(std::move(response), queried_forms,
- client_->GetRapporServiceImpl());
+ FormStructure::ParseQueryResponse(std::move(response), queried_forms);
// Will log quality metrics for each FormStructure based on the presence of
// autocomplete attributes, if available.
@@ -1106,9 +1125,12 @@ void AutofillManager::OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
}
}
-void AutofillManager::OnFullCardRequestSucceeded(const CreditCard& card,
- const base::string16& cvc) {
- credit_card_form_event_logger_->OnDidFillSuggestion(masked_card_);
+void AutofillManager::OnFullCardRequestSucceeded(
+ const payments::FullCardRequest& full_card_request,
+ const CreditCard& card,
+ const base::string16& cvc) {
+ credit_card_form_event_logger_->OnDidFillSuggestion(
+ masked_card_, full_card_request.form_parsed_timestamp());
FillCreditCardForm(unmasking_query_id_, unmasking_form_, unmasking_field_,
card, cvc);
masked_card_ = CreditCard();
@@ -1281,9 +1303,8 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
// Upload requires that recently used or modified addresses meet the
// client-side validation rules.
- std::string rappor_metric_name;
- int upload_decision_metrics = SetProfilesForCreditCardUpload(
- *imported_credit_card, &upload_request_, &rappor_metric_name);
+ int upload_decision_metrics =
+ SetProfilesForCreditCardUpload(*imported_credit_card, &upload_request_);
pending_upload_request_url_ = GURL(submitted_form.source_url());
@@ -1297,18 +1318,23 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
kAutofillUpstreamRequestCvcIfMissing.name);
} else {
upload_decision_metrics |= GetCVCCardUploadDecisionMetric();
- rappor_metric_name = "Autofill.CardUploadNotOfferedNoCvc";
}
}
if (upload_decision_metrics) {
LogCardUploadDecisions(upload_decision_metrics);
pending_upload_request_url_ = GURL();
- if (!rappor_metric_name.empty()) {
- CollectRapporSample(submitted_form.source_url(), rappor_metric_name);
- }
return;
}
+ if (IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+ upload_request_.active_experiments.push_back(
+ kAutofillUpstreamShowNewUi.name);
+ }
+ if (IsAutofillUpstreamShowGoogleLogoExperimentEnabled()) {
+ upload_request_.active_experiments.push_back(
+ kAutofillUpstreamShowGoogleLogo.name);
+ }
+
// All required data is available, start the upload process.
payments_client_->GetUploadDetails(upload_request_.profiles,
upload_request_.active_experiments,
@@ -1329,8 +1355,7 @@ AutofillManager::GetCVCCardUploadDecisionMetric() const {
int AutofillManager::SetProfilesForCreditCardUpload(
const CreditCard& card,
- payments::PaymentsClient::UploadRequestDetails* upload_request,
- std::string* rappor_metric_name) const {
+ payments::PaymentsClient::UploadRequestDetails* upload_request) const {
std::vector<AutofillProfile> candidate_profiles;
const base::Time now = AutofillClock::Now();
const base::TimeDelta fifteen_minutes = base::TimeDelta::FromMinutes(15);
@@ -1374,7 +1399,6 @@ int AutofillManager::SetProfilesForCreditCardUpload(
has_profile
? AutofillMetrics::UPLOAD_NOT_OFFERED_NO_RECENTLY_USED_ADDRESS
: AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE;
- *rappor_metric_name = "Autofill.CardUploadNotOfferedNoAddress";
}
std::unique_ptr<AutofillProfileComparator> comparator;
@@ -1400,7 +1424,7 @@ int AutofillManager::SetProfilesForCreditCardUpload(
verified_name = comparator->NormalizeForComparison(card_name);
for (const AutofillProfile& profile : candidate_profiles) {
const base::string16 address_name = comparator->NormalizeForComparison(
- profile.GetInfo(AutofillType(NAME_FULL), app_locale_));
+ profile.GetInfo(NAME_FULL, app_locale_));
if (address_name.empty())
continue;
if (verified_name.empty() ||
@@ -1414,8 +1438,8 @@ int AutofillManager::SetProfilesForCreditCardUpload(
} else {
verified_name = RemoveMiddleInitial(card_name);
for (const AutofillProfile& profile : candidate_profiles) {
- const base::string16 address_name = RemoveMiddleInitial(
- profile.GetInfo(AutofillType(NAME_FULL), app_locale_));
+ const base::string16 address_name =
+ RemoveMiddleInitial(profile.GetInfo(NAME_FULL, app_locale_));
if (address_name.empty())
continue;
if (verified_name.empty()) {
@@ -1428,8 +1452,6 @@ int AutofillManager::SetProfilesForCreditCardUpload(
}
}
if (found_conflicting_names) {
- if (!upload_decision_metrics)
- *rappor_metric_name = "Autofill.CardUploadNotOfferedConflictingNames";
upload_decision_metrics |=
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES;
}
@@ -1438,8 +1460,6 @@ int AutofillManager::SetProfilesForCreditCardUpload(
// If neither the card nor any of the addresses have a name associated with
// them, the candidate set is invalid.
if (verified_name.empty()) {
- if (!upload_decision_metrics)
- *rappor_metric_name = "Autofill.CardUploadNotOfferedNoName";
upload_decision_metrics |= AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME;
}
@@ -1506,15 +1526,6 @@ int AutofillManager::SetProfilesForCreditCardUpload(
return upload_decision_metrics;
}
-void AutofillManager::CollectRapporSample(
- const GURL& source_url,
- const std::string& metric_name) const {
- if (source_url.is_valid() && client_->GetRapporServiceImpl()) {
- rappor::SampleDomainAndRegistryFromGURL(client_->GetRapporServiceImpl(),
- metric_name, source_url);
- }
-}
-
// Note that |submitted_form| is passed as a pointer rather than as a reference
// so that we can get memory management right across threads. Note also that we
// explicitly pass in all the time stamps of interest, as the cached ones might
@@ -1525,10 +1536,10 @@ void AutofillManager::UploadFormDataAsyncCallback(
const TimeTicks& interaction_time,
const TimeTicks& submission_time,
bool observed_submission) {
- submitted_form->LogQualityMetrics(
- load_time, interaction_time, submission_time,
- client_->GetRapporServiceImpl(), form_interactions_ukm_logger_.get(),
- did_show_suggestions_, observed_submission);
+ submitted_form->LogQualityMetrics(load_time, interaction_time,
+ submission_time,
+ form_interactions_ukm_logger_.get(),
+ did_show_suggestions_, observed_submission);
if (submitted_form->ShouldBeCrowdsourced())
UploadFormData(*submitted_form, observed_submission);
}
@@ -1714,7 +1725,21 @@ void AutofillManager::FillOrPreviewDataModelForm(
AutofillField* autofill_field = NULL;
if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
+ FillOrPreviewDataModelForm(action, query_id, form, field, data_model,
+ is_credit_card, cvc, form_structure,
+ autofill_field);
+}
+void AutofillManager::FillOrPreviewDataModelForm(
+ AutofillDriver::RendererFormDataAction action,
+ int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const AutofillDataModel& data_model,
+ bool is_credit_card,
+ const base::string16& cvc,
+ FormStructure* form_structure,
+ AutofillField* autofill_field) {
DCHECK(form_structure);
DCHECK(autofill_field);
@@ -2044,11 +2069,6 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
parse_form_start_time);
}
- if (!queryable_forms.empty() && download_manager_) {
- // Query the server if at least one of the forms was parsed.
- download_manager_->StartQueryRequest(queryable_forms);
- }
-
if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED);
@@ -2075,10 +2095,16 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
}
#endif
- // For the |non_queryable_forms|, we have all the field type info we're ever
- // going to get about them. For the other forms, we'll wait until we get a
- // response from the server.
+ // Send the current type predictions to the renderer. For non-queryable forms
+ // this is all the information about them that will ever be available. The
+ // queryable forms will be updated once the field type query is complete.
driver()->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
+ driver()->SendAutofillTypePredictionsToRenderer(queryable_forms);
+
+ if (!queryable_forms.empty() && download_manager_) {
+ // Query the server if at least one of the forms was parsed.
+ download_manager_->StartQueryRequest(queryable_forms);
+ }
}
bool AutofillManager::ParseForm(const FormData& form,
@@ -2095,6 +2121,7 @@ bool AutofillManager::ParseForm(const FormData& form,
// Ownership is transferred to |form_structures_| which maintains it until
// the manager is Reset() or destroyed. It is safe to use references below
// as long as receivers don't take ownership.
+ form_structure->set_form_parsed_timestamp(TimeTicks::Now());
form_structures_.push_back(std::move(form_structure));
*parsed_form_structure = form_structures_.back().get();
(*parsed_form_structure)->DetermineHeuristicTypes(client_->GetUkmRecorder());
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index f24f88559bc..ededde78f65 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_MANAGER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_MANAGER_H_
-#include <deque>
#include <map>
#include <memory>
#include <string>
@@ -13,6 +12,7 @@
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
+#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -150,6 +150,9 @@ class AutofillManager : public AutofillHandler,
payments::FullCardRequest* GetOrCreateFullCardRequest();
+ payments::FullCardRequest* CreateFullCardRequest(
+ const base::TimeTicks& form_parsed_timestamp);
+
base::WeakPtr<payments::FullCardRequest::UIDelegate>
GetAsFullCardRequestUIDelegate() {
return weak_ptr_factory_.GetWeakPtr();
@@ -297,8 +300,10 @@ class AutofillManager : public AutofillHandler,
std::unique_ptr<base::DictionaryValue> legal_message) override;
// payments::FullCardRequest::ResultDelegate:
- void OnFullCardRequestSucceeded(const CreditCard& card,
- const base::string16& cvc) override;
+ void OnFullCardRequestSucceeded(
+ const payments::FullCardRequest& full_card_request,
+ const CreditCard& card,
+ const base::string16& cvc) override;
void OnFullCardRequestFailed() override;
// payments::FullCardRequest::UIDelegate:
@@ -350,6 +355,9 @@ class AutofillManager : public AutofillHandler,
const FormFieldData& field,
const AutofillProfile& profile);
+ // TODO(rogerm) here to see if these can be merged. FormData should be a
+ // subset of the data in FormStructure and FormFieldData a subset of that in
+ // AutofillField.
// Fills or previews |data_model| in the |form|.
void FillOrPreviewDataModelForm(AutofillDriver::RendererFormDataAction action,
int query_id,
@@ -358,6 +366,15 @@ class AutofillManager : public AutofillHandler,
const AutofillDataModel& data_model,
bool is_credit_card,
const base::string16& cvc);
+ void FillOrPreviewDataModelForm(AutofillDriver::RendererFormDataAction action,
+ int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const AutofillDataModel& data_model,
+ bool is_credit_card,
+ const base::string16& cvc,
+ FormStructure* form_structure,
+ AutofillField* autofill_field);
// Creates a FormStructure using the FormData received from the renderer. Will
// return an empty scoped_ptr if the data should not be processed for upload
@@ -415,21 +432,15 @@ class AutofillManager : public AutofillHandler,
// Imports the form data, submitted by the user, into |personal_data_|.
void ImportFormData(const FormStructure& submitted_form);
- // Logs |metric_name| with RAPPOR, for the specific form |source_url|.
- void CollectRapporSample(const GURL& source_url,
- const std::string& metric_name) const;
-
// Examines |card| and the stored profiles and if a candidate set of profiles
// is found that matches the client-side validation rules, assigns the values
// to |upload_request.profiles| and returns 0. If no valid set can be found,
- // returns the failure reasons and, if applicable, the RAPPOR metric to log to
- // |rappor_metric_name|. Appends any experiments that were triggered to
+ // returns the failure reasons. Appends any experiments that were triggered to
// |upload_request.active_experiments|. The return value is a bitmask of
// |AutofillMetrics::CardUploadDecisionMetric|.
int SetProfilesForCreditCardUpload(
const CreditCard& card,
- payments::PaymentsClient::UploadRequestDetails* upload_request,
- std::string* rappor_metric_name) const;
+ payments::PaymentsClient::UploadRequestDetails* upload_request) const;
// Returns metric relevant to the CVC field based on values in
// |found_cvc_field_|, |found_value_in_cvc_field_| and
@@ -499,7 +510,7 @@ class AutofillManager : public AutofillHandler,
// May be NULL. NULL indicates OTR.
PersonalDataManager* personal_data_;
- std::deque<std::string> autofilled_form_signatures_;
+ base::circular_deque<std::string> autofilled_form_signatures_;
// Handles queries and uploads to Autofill servers. Will be NULL if
// the download manager functionality is disabled.
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 10e6ba75084..1280500a66e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -53,7 +53,6 @@
#include "components/autofill/core/common/form_field_data.h"
#include "components/metrics/proto/ukm/entry.pb.h"
#include "components/prefs/pref_service.h"
-#include "components/rappor/test_rappor_service.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "components/ukm/test_ukm_recorder.h"
@@ -63,6 +62,7 @@
#include "net/base/url_util.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
@@ -80,6 +80,9 @@ using testing::UnorderedElementsAre;
namespace autofill {
namespace {
+using UkmCardUploadDecisionType = ukm::builders::Autofill_CardUploadDecision;
+using UkmDeveloperEngagementType = ukm::builders::Autofill_DeveloperEngagement;
+
const int kDefaultPageID = 137;
const char kUTF8MidlineEllipsis[] =
@@ -534,6 +537,9 @@ class MockAutofillDriver : public TestAutofillDriver {
RendererFormDataAction action,
const FormData& data));
+ MOCK_METHOD1(SendAutofillTypePredictionsToRenderer,
+ void(const std::vector<FormStructure*>& forms));
+
void SetIsIncognito(bool is_incognito) { is_incognito_ = is_incognito; }
bool IsIncognito() const override { return is_incognito_; }
@@ -693,6 +699,7 @@ class TestAutofillManager : public AutofillManager {
}
void AddSeenForm(std::unique_ptr<FormStructure> form) {
+ form->set_form_parsed_timestamp(base::TimeTicks::Now());
form_structures()->push_back(std::move(form));
}
@@ -857,7 +864,7 @@ class AutofillManagerTest : public testing::Test {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
personal_data_.set_database(autofill_client_.GetDatabase());
personal_data_.SetPrefService(autofill_client_.GetPrefs());
- autofill_driver_.reset(new MockAutofillDriver());
+ autofill_driver_.reset(new testing::NiceMock<MockAutofillDriver>());
request_context_ = new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get());
autofill_driver_->SetURLRequestContext(request_context_.get());
@@ -1081,6 +1088,14 @@ class AutofillManagerTest : public testing::Test {
kAutofillUpstreamRequestCvcIfMissing);
}
+ void EnableAutofillUpstreamShowGoogleLogoExperiment() {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamShowGoogleLogo);
+ }
+
+ void EnableAutofillUpstreamShowNewUiExperiment() {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamShowNewUi);
+ }
+
void DisableAutofillUpstreamUseAutofillProfileComparator() {
scoped_feature_list_.InitAndDisableFeature(
kAutofillUpstreamUseAutofillProfileComparator);
@@ -1099,13 +1114,13 @@ class AutofillManagerTest : public testing::Test {
EXPECT_EQ(source->id(), entry->source_id);
// Check if there is an entry for developer engagement decision.
- EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
+ EXPECT_EQ(base::HashMetricName(UkmDeveloperEngagementType::kEntryName),
entry->event_hash);
EXPECT_EQ(1U, entry->metrics.size());
// Check that the expected developer engagement metric is logged.
const ukm::mojom::UkmMetric* metric = ukm::TestUkmRecorder::FindMetric(
- entry, internal::kUKMDeveloperEngagementMetricName);
+ entry, UkmDeveloperEngagementType::kDeveloperEngagementName);
ASSERT_NE(nullptr, metric);
EXPECT_EQ(1 << AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS,
metric->value);
@@ -1128,14 +1143,14 @@ class AutofillManagerTest : public testing::Test {
void ExpectCardUploadDecisionUkm(
AutofillMetrics::CardUploadDecisionMetric upload_decision) {
int expected_metric_value = upload_decision;
- ExpectMetric(internal::kUKMCardUploadDecisionMetricName,
- internal::kUKMCardUploadDecisionEntryName,
- expected_metric_value, 1 /* expected_num_matching_entries */);
+ ExpectMetric(UkmCardUploadDecisionType::kUploadDecisionName,
+ UkmCardUploadDecisionType::kEntryName, expected_metric_value,
+ 1 /* expected_num_matching_entries */);
}
void ExpectFillableFormParsedUkm(int num_fillable_forms_parsed) {
- ExpectMetric(internal::kUKMDeveloperEngagementMetricName,
- internal::kUKMDeveloperEngagementEntryName,
+ ExpectMetric(UkmDeveloperEngagementType::kDeveloperEngagementName,
+ UkmDeveloperEngagementType::kEntryName,
1 << AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS,
num_fillable_forms_parsed);
}
@@ -1266,6 +1281,31 @@ TEST_F(AutofillManagerTest, OnFormsSeen_DifferentFormStructures) {
download_manager_->VerifyLastQueriedForms(forms);
}
+// Test that when forms are seen, the renderer is updated with the predicted
+// field types
+TEST_F(AutofillManagerTest, OnFormsSeen_SendAutofillTypePredictionsToRenderer) {
+ // Set up a queryable form.
+ FormData form1;
+ test::CreateTestAddressFormData(&form1);
+
+ // Set up a non-queryable form.
+ FormData form2;
+ FormFieldData field;
+ test::CreateTestFormField("Querty", "qwerty", "", "text", &field);
+ form2.name = ASCIIToUTF16("NonQueryable");
+ form2.origin = form1.origin;
+ form2.action = GURL("https://myform.com/submit.html");
+ form2.fields.push_back(field);
+
+ // Package the forms for observation.
+ std::vector<FormData> forms{form1, form2};
+
+ // Setup expectations.
+ EXPECT_CALL(*autofill_driver_, SendAutofillTypePredictionsToRenderer(_))
+ .Times(2);
+ FormsSeen(forms);
+}
+
// Test that no autofill suggestions are returned for a field with an
// unrecognized autocomplete attribute.
TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) {
@@ -1473,28 +1513,28 @@ TEST_F(AutofillManagerTest,
std::unique_ptr<AutofillProfile> profile1 =
base::MakeUnique<AutofillProfile>();
profile1->set_guid("00000000-0000-0000-0000-000000000103");
- profile1->SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Robin"), "en-US");
- profile1->SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16("Grimes"), "en-US");
- profile1->SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16("1234 Smith Blvd."), "en-US");
+ profile1->SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
+ profile1->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+ profile1->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+ "en-US");
autofill_manager_->AddProfile(std::move(profile1));
std::unique_ptr<AutofillProfile> profile2 =
base::MakeUnique<AutofillProfile>();
profile2->set_guid("00000000-0000-0000-0000-000000000124");
- profile2->SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Carl"), "en-US");
- profile2->SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16("Grimes"), "en-US");
- profile2->SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16("1234 Smith Blvd."), "en-US");
+ profile2->SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
+ profile2->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+ profile2->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+ "en-US");
autofill_manager_->AddProfile(std::move(profile2));
std::unique_ptr<AutofillProfile> profile3 =
base::MakeUnique<AutofillProfile>();
profile3->set_guid("00000000-0000-0000-0000-000000000126");
- profile3->SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Aaron"), "en-US");
- profile3->SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16("Googler"), "en-US");
- profile3->SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16("1600 Amphitheater pkwy"), "en-US");
+ profile3->SetInfo(NAME_FIRST, ASCIIToUTF16("Aaron"), "en-US");
+ profile3->SetInfo(NAME_LAST, ASCIIToUTF16("Googler"), "en-US");
+ profile3->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1600 Amphitheater pkwy"),
+ "en-US");
autofill_manager_->AddProfile(std::move(profile3));
FormFieldData field;
@@ -2132,8 +2172,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_FancyPhone) {
std::unique_ptr<AutofillProfile> profile =
base::MakeUnique<AutofillProfile>();
profile->set_guid("00000000-0000-0000-0000-000000000103");
- profile->SetInfo(AutofillType(NAME_FULL), ASCIIToUTF16("Natty Bumppo"),
- "en-US");
+ profile->SetInfo(NAME_FULL, ASCIIToUTF16("Natty Bumppo"), "en-US");
profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800PRAIRIE"));
autofill_manager_->AddProfile(std::move(profile));
@@ -4846,16 +4885,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CvcUnavailable) {
AutofillMetrics::CVC_VALUE_NOT_FOUND);
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(AutofillMetrics::CVC_VALUE_NOT_FOUND);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_CvcInvalidLength) {
@@ -4894,16 +4923,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CvcInvalidLength) {
AutofillMetrics::INVALID_CVC_VALUE);
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(AutofillMetrics::INVALID_CVC_VALUE);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_MultipleCvcFields) {
@@ -5263,8 +5282,8 @@ TEST_F(AutofillManagerTest,
AutofillMetrics::CVC_FIELD_NOT_FOUND);
// Verify that the correct UKM was logged.
ExpectMetric(
- internal::kUKMCardUploadDecisionMetricName,
- internal::kUKMCardUploadDecisionEntryName,
+ UkmCardUploadDecisionType::kUploadDecisionName,
+ UkmCardUploadDecisionType::kEntryName,
AutofillMetrics::UPLOAD_OFFERED | AutofillMetrics::CVC_FIELD_NOT_FOUND,
1 /* expected_num_matching_entries */);
}
@@ -5321,18 +5340,162 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NoCvcFieldOnFormExperimentOff) {
AutofillMetrics::CVC_FIELD_NOT_FOUND);
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(AutofillMetrics::CVC_FIELD_NOT_FOUND);
+}
+
+// kAutofillUpstreamShowNewUi and kAutofillUpstreamShowGoogleLogo flags are
+// currently not available on Android.
+#if !defined(OS_ANDROID)
+TEST_F(AutofillManagerTest,
+ UploadCreditCard_AddNewUiFlagStateToRequestIfExperimentOn) {
+ EnableAutofillUpstreamShowNewUiExperiment();
+ personal_data_.ClearAutofillProfiles();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, true, false);
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+ credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+ base::HistogramTester histogram_tester;
+
+ // Confirm upload happened and the new UI flag was sent in the request.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+ EXPECT_THAT(
+ autofill_manager_->GetActiveExperiments(),
+ UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name,
+ kAutofillUpstreamShowNewUi.name));
+}
+
+TEST_F(AutofillManagerTest,
+ UploadCreditCard_DoNotAddNewUiFlagStateToRequestIfExperimentOff) {
+ personal_data_.ClearAutofillProfiles();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, true, false);
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+ credit_card_form.fields[4].value = ASCIIToUTF16("123");
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
+ base::HistogramTester histogram_tester;
+
+ // Confirm upload happened and the new UI flag was sent in the request.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+ EXPECT_THAT(
+ autofill_manager_->GetActiveExperiments(),
+ UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name));
}
+TEST_F(AutofillManagerTest,
+ UploadCreditCard_AddShowGoogleLogoFlagStateToRequestIfExperimentOn) {
+ EnableAutofillUpstreamShowGoogleLogoExperiment();
+ personal_data_.ClearAutofillProfiles();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, true, false);
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+ credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+ base::HistogramTester histogram_tester;
+
+ // Confirm upload happened and the show Google logo flag was sent in the
+ // request.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+ EXPECT_THAT(
+ autofill_manager_->GetActiveExperiments(),
+ UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name,
+ kAutofillUpstreamShowGoogleLogo.name));
+}
+
+TEST_F(AutofillManagerTest,
+ UploadCreditCard_DoNotAddShowGoogleLogoFlagStateToRequestIfExpOff) {
+ personal_data_.ClearAutofillProfiles();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, true, false);
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+ credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+ base::HistogramTester histogram_tester;
+
+ // Confirm upload happened and the show Google logo flag was sent in the
+ // request.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+ EXPECT_THAT(
+ autofill_manager_->GetActiveExperiments(),
+ UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name));
+}
+#endif
+
TEST_F(AutofillManagerTest, UploadCreditCard_NoProfileAvailable) {
personal_data_.ClearAutofillProfiles();
autofill_manager_->set_credit_card_upload_enabled(true);
@@ -5364,16 +5527,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NoProfileAvailable) {
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoAddress", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
@@ -5517,21 +5670,11 @@ TEST_F(AutofillManagerTest,
ExpectCardUploadDecision(
histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE);
// Verify that the correct UKM was logged.
- ExpectMetric(internal::kUKMCardUploadDecisionMetricName,
- internal::kUKMCardUploadDecisionEntryName,
+ ExpectMetric(UkmCardUploadDecisionType::kUploadDecisionName,
+ UkmCardUploadDecisionType::kEntryName,
AutofillMetrics::CVC_VALUE_NOT_FOUND |
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE,
+ AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE,
1 /* expected_num_matching_entries */);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_NoNameAvailable) {
@@ -5570,16 +5713,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NoNameAvailable) {
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedNoName", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_ZipCodesConflict) {
@@ -6138,16 +6271,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NamesHaveToMatch) {
// Verify that the correct UKM was logged.
ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES);
-
- rappor::TestRapporServiceImpl* rappor_service =
- autofill_client_.test_rappor_service();
- EXPECT_EQ(1, rappor_service->GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
- "Autofill.CardUploadNotOfferedConflictingNames", &sample, &type));
- EXPECT_EQ("myform.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
TEST_F(AutofillManagerTest, UploadCreditCard_IgnoreOldProfiles) {
@@ -6760,23 +6883,21 @@ TEST_F(AutofillManagerTest,
std::unique_ptr<AutofillProfile> profile1 =
base::MakeUnique<AutofillProfile>();
profile1->set_guid("00000000-0000-0000-0000-000000000103");
- profile1->SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Robin"), "en-US");
- profile1->SetInfo(AutofillType(NAME_MIDDLE), ASCIIToUTF16("Adam Smith"),
+ profile1->SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
+ profile1->SetInfo(NAME_MIDDLE, ASCIIToUTF16("Adam Smith"), "en-US");
+ profile1->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+ profile1->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
- profile1->SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16("Grimes"), "en-US");
- profile1->SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16("1234 Smith Blvd."), "en-US");
autofill_manager_->AddProfile(std::move(profile1));
std::unique_ptr<AutofillProfile> profile2 =
base::MakeUnique<AutofillProfile>();
profile2->set_guid("00000000-0000-0000-0000-000000000124");
- profile2->SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Carl"), "en-US");
- profile2->SetInfo(AutofillType(NAME_MIDDLE), ASCIIToUTF16("Shawn Smith"),
+ profile2->SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
+ profile2->SetInfo(NAME_MIDDLE, ASCIIToUTF16("Shawn Smith"), "en-US");
+ profile2->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+ profile2->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
- profile2->SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16("Grimes"), "en-US");
- profile2->SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16("1234 Smith Blvd."), "en-US");
autofill_manager_->AddProfile(std::move(profile2));
FormFieldData field;
@@ -7079,6 +7200,7 @@ TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) {
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
form_structure->set_is_signin_upload(true);
+ form_structure->set_form_parsed_timestamp(base::TimeTicks::Now());
form_structure->field(1)->set_possible_types({autofill::PASSWORD});
std::string signature = form_structure->FormSignatureAsStr();
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index 792546cc593..3499f11478a 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -21,48 +21,7 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/form_data.h"
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
-
-namespace internal {
-const char kUKMCardUploadDecisionEntryName[] = "Autofill.CardUploadDecision";
-const char kUKMCardUploadDecisionMetricName[] = "UploadDecision";
-const char kUKMDeveloperEngagementEntryName[] = "Autofill.DeveloperEngagement";
-const char kUKMDeveloperEngagementMetricName[] = "DeveloperEngagement";
-const char kUKMMillisecondsSinceFormParsedMetricName[] =
- "MillisecondsSinceFormParsed";
-const char kUKMInteractedWithFormEntryName[] = "Autofill.InteractedWithForm";
-const char kUKMIsForCreditCardMetricName[] = "IsForCreditCard";
-const char kUKMLocalRecordTypeCountMetricName[] = "LocalRecordTypeCount";
-const char kUKMServerRecordTypeCountMetricName[] = "ServerRecordTypeCount";
-const char kUKMSuggestionsShownEntryName[] = "Autofill.SuggestionsShown";
-const char kUKMSelectedMaskedServerCardEntryName[] =
- "Autofill.SelectedMaskedServerCard";
-const char kUKMSuggestionFilledEntryName[] = "Autofill.SuggestionFilled";
-const char kUKMRecordTypeMetricName[] = "RecordType";
-const char kUKMTextFieldDidChangeEntryName[] = "Autofill.TextFieldDidChange";
-const char kUKMFieldTypeGroupMetricName[] = "FieldTypeGroup";
-const char kUKMHeuristicTypeMetricName[] = "HeuristicType";
-const char kUKMServerTypeMetricName[] = "ServerType";
-const char kUKMHtmlFieldTypeMetricName[] = "HtmlFieldType";
-const char kUKMHtmlFieldModeMetricName[] = "HtmlFieldMode";
-const char kUKMIsAutofilledMetricName[] = "IsAutofilled";
-const char kUKMIsEmptyMetricName[] = "IsEmpty";
-const char kUKMFormSubmittedEntryName[] = "Autofill.AutofillFormSubmitted";
-const char kUKMAutofillFormSubmittedStateMetricName[] =
- "AutofillFormSubmittedState";
-// |UkmEntry| for capturing field type prediction quality.
-const char kUKMFieldTypeEntryName[] = "Autofill.FieldTypeValidation";
-const char kUKMFieldFillStatusEntryName[] = "Autofill.FieldFillStatus";
-const char kUKMFormSignatureMetricName[] = "FormSignature";
-const char kUKMFieldSignatureMetricName[] = "FieldSignature";
-const char kUKMValidationEventMetricName[] = "ValidationEvent";
-const char kUKMPredictionSourceMetricName[] = "PredictionSource";
-const char kUKMPredictedTypeMetricName[] = "PredictedType";
-const char kUKMActualTypeMetricName[] = "ActualType";
-const char kUKMWasSuggestionShownMetricName[] = "WasSuggestionShown";
-const char kUKMWasPreviouslyAutofilledMetricName[] = "WasPreviouslyAutofilled";
-
-} // namespace internal
+#include "services/metrics/public/cpp/ukm_builders.h"
namespace autofill {
@@ -116,6 +75,14 @@ std::string PreviousSaveCreditCardPromptUserDecisionToString(
return previous_response;
}
+ukm::SourceId NewUkmSourceWithUrl(ukm::UkmRecorder* ukm_recorder,
+ const GURL& url) {
+ ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID();
+ if (ukm_recorder)
+ ukm_recorder->UpdateSourceURL(source_id, url);
+ return source_id;
+}
+
} // namespace
// First, translates |field_type| to the corresponding logical |group| from
@@ -409,8 +376,9 @@ void LogPredictionQualityMetrics(
(predicted_type << 16) | actual_type);
form_interactions_ukm_logger->LogFieldType(
- form.form_signature(), field.GetFieldSignature(), prediction_source,
- metric_type, predicted_type, actual_type);
+ form.form_parsed_timestamp(), form.form_signature(),
+ field.GetFieldSignature(), prediction_source, metric_type, predicted_type,
+ actual_type);
// NO_SERVER_DATA is the equivalent of predicting UNKNOWN.
if (predicted_type == NO_SERVER_DATA)
@@ -915,6 +883,7 @@ void AutofillMetrics::LogProfileActionOnFormSubmitted(
// static
void AutofillMetrics::LogAutofillFormSubmittedState(
AutofillFormSubmittedState state,
+ const base::TimeTicks& form_parsed_timestamp,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
UMA_HISTOGRAM_ENUMERATION("Autofill.FormSubmittedState", state,
AUTOFILL_FORM_SUBMITTED_STATE_ENUM_SIZE);
@@ -949,7 +918,7 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
NOTREACHED();
break;
}
- form_interactions_ukm_logger->LogFormSubmitted(state);
+ form_interactions_ukm_logger->LogFormSubmitted(state, form_parsed_timestamp);
}
// static
@@ -1004,10 +973,12 @@ void AutofillMetrics::LogCardUploadDecisionsUkm(ukm::UkmRecorder* ukm_recorder,
int upload_decision_metrics) {
DCHECK(upload_decision_metrics);
DCHECK_LT(upload_decision_metrics, 1 << kNumCardUploadDecisionMetrics);
-
- const std::vector<std::pair<const char*, int>> metrics = {
- {internal::kUKMCardUploadDecisionMetricName, upload_decision_metrics}};
- LogUkm(ukm_recorder, url, internal::kUKMCardUploadDecisionEntryName, metrics);
+ if (!url.is_valid())
+ return;
+ ukm::SourceId source_id = NewUkmSourceWithUrl(ukm_recorder, url);
+ ukm::builders::Autofill_CardUploadDecision(source_id)
+ .SetUploadDecision(upload_decision_metrics)
+ .Record(ukm_recorder);
}
// static
@@ -1018,35 +989,12 @@ void AutofillMetrics::LogDeveloperEngagementUkm(
DCHECK(developer_engagement_metrics);
DCHECK_LT(developer_engagement_metrics,
1 << NUM_DEVELOPER_ENGAGEMENT_METRICS);
-
- const std::vector<std::pair<const char*, int>> metrics = {
- {internal::kUKMDeveloperEngagementMetricName,
- developer_engagement_metrics}};
-
- LogUkm(ukm_recorder, url, internal::kUKMDeveloperEngagementEntryName,
- metrics);
-}
-
-// static
-bool AutofillMetrics::LogUkm(
- ukm::UkmRecorder* ukm_recorder,
- const GURL& url,
- const std::string& ukm_entry_name,
- const std::vector<std::pair<const char*, int>>& metrics) {
- if (!ukm_recorder || !url.is_valid() || metrics.empty()) {
- return false;
- }
-
- ukm::SourceId source_id = ukm_recorder->GetNewSourceID();
- ukm_recorder->UpdateSourceURL(source_id, url);
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder->GetEntryBuilder(source_id, ukm_entry_name.c_str());
-
- for (auto it = metrics.begin(); it != metrics.end(); ++it) {
- builder->AddMetric(it->first, it->second);
- }
-
- return true;
+ if (!url.is_valid())
+ return;
+ ukm::SourceId source_id = NewUkmSourceWithUrl(ukm_recorder, url);
+ ukm::builders::Autofill_DeveloperEngagement(source_id)
+ .SetDeveloperEngagement(developer_engagement_metrics)
+ .Record(ukm_recorder);
}
AutofillMetrics::FormEventLogger::FormEventLogger(
@@ -1097,8 +1045,10 @@ void AutofillMetrics::FormEventLogger::OnDidPollSuggestions(
}
void AutofillMetrics::FormEventLogger::OnDidShowSuggestions(
- const AutofillField& field) {
- form_interactions_ukm_logger_->LogSuggestionsShown(field);
+ const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp) {
+ form_interactions_ukm_logger_->LogSuggestionsShown(field,
+ form_parsed_timestamp);
Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN);
if (!has_logged_suggestions_shown_) {
@@ -1119,9 +1069,11 @@ void AutofillMetrics::FormEventLogger::OnDidShowSuggestions(
}
}
-void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion() {
+void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion(
+ const base::TimeTicks& form_parsed_timestamp) {
DCHECK(is_for_credit_card_);
- form_interactions_ukm_logger_->LogSelectedMaskedServerCard();
+ form_interactions_ukm_logger_->LogSelectedMaskedServerCard(
+ form_parsed_timestamp);
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED);
if (!has_logged_masked_server_card_suggestion_selected_) {
@@ -1132,10 +1084,11 @@ void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion() {
}
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
- const CreditCard& credit_card) {
+ const CreditCard& credit_card,
+ const base::TimeTicks& form_parsed_timestamp) {
DCHECK(is_for_credit_card_);
form_interactions_ukm_logger_->LogDidFillSuggestion(
- static_cast<int>(credit_card.record_type()));
+ static_cast<int>(credit_card.record_type()), form_parsed_timestamp);
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD)
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED);
@@ -1170,10 +1123,11 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
}
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
- const AutofillProfile& profile) {
+ const AutofillProfile& profile,
+ const base::TimeTicks& form_parsed_timestamp) {
DCHECK(!is_for_credit_card_);
form_interactions_ukm_logger_->LogDidFillSuggestion(
- static_cast<int>(profile.record_type()));
+ static_cast<int>(profile.record_type()), form_parsed_timestamp);
if (profile.record_type() == AutofillProfile::SERVER_PROFILE)
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED);
@@ -1299,7 +1253,6 @@ void AutofillMetrics::FormInteractionsUkmLogger::OnFormsParsed(
return;
url_ = url;
- form_parsed_timestamp_ = base::TimeTicks::Now();
}
void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
@@ -1312,93 +1265,81 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMInteractedWithFormEntryName);
- builder->AddMetric(internal::kUKMIsForCreditCardMetricName,
- is_for_credit_card);
- builder->AddMetric(internal::kUKMLocalRecordTypeCountMetricName,
- local_record_type_count);
- builder->AddMetric(internal::kUKMServerRecordTypeCountMetricName,
- server_record_type_count);
+ ukm::builders::Autofill_InteractedWithForm(source_id_)
+ .SetIsForCreditCard(is_for_credit_card)
+ .SetLocalRecordTypeCount(local_record_type_count)
+ .SetServerRecordTypeCount(server_record_type_count)
+ .Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown(
- const AutofillField& field) {
+ const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMSuggestionsShownEntryName);
- builder->AddMetric(internal::kUKMHeuristicTypeMetricName,
- static_cast<int>(field.heuristic_type()));
- builder->AddMetric(internal::kUKMHtmlFieldTypeMetricName,
- static_cast<int>(field.html_type()));
- builder->AddMetric(internal::kUKMServerTypeMetricName,
- static_cast<int>(field.server_type()));
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
+ ukm::builders::Autofill_SuggestionsShown(source_id_)
+ .SetHeuristicType(static_cast<int>(field.heuristic_type()))
+ .SetHtmlFieldType(static_cast<int>(field.html_type()))
+ .SetServerType(static_cast<int>(field.server_type()))
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp))
+ .Record(ukm_recorder_);
}
-void AutofillMetrics::FormInteractionsUkmLogger::LogSelectedMaskedServerCard() {
+void AutofillMetrics::FormInteractionsUkmLogger::LogSelectedMaskedServerCard(
+ const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(
- source_id_, internal::kUKMSelectedMaskedServerCardEntryName);
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
+ ukm::builders::Autofill_SelectedMaskedServerCard(source_id_)
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp))
+ .Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
- int record_type) {
+ int record_type,
+ const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMSuggestionFilledEntryName);
- builder->AddMetric(internal::kUKMRecordTypeMetricName, record_type);
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
+ ukm::builders::Autofill_SuggestionFilled(source_id_)
+ .SetRecordType(record_type)
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp))
+ .Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange(
- const AutofillField& field) {
+ const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMTextFieldDidChangeEntryName);
- builder->AddMetric(internal::kUKMFieldTypeGroupMetricName,
- static_cast<int>(field.Type().group()));
- builder->AddMetric(internal::kUKMHeuristicTypeMetricName,
- static_cast<int>(field.heuristic_type()));
- builder->AddMetric(internal::kUKMServerTypeMetricName,
- static_cast<int>(field.server_type()));
- builder->AddMetric(internal::kUKMHtmlFieldTypeMetricName,
- static_cast<int>(field.html_type()));
- builder->AddMetric(internal::kUKMHtmlFieldModeMetricName,
- static_cast<int>(field.html_mode()));
- builder->AddMetric(internal::kUKMIsAutofilledMetricName, field.is_autofilled);
- builder->AddMetric(internal::kUKMIsEmptyMetricName, field.IsEmpty());
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
+ ukm::builders::Autofill_TextFieldDidChange(source_id_)
+ .SetFieldTypeGroup(static_cast<int>(field.Type().group()))
+ .SetHeuristicType(static_cast<int>(field.heuristic_type()))
+ .SetServerType(static_cast<int>(field.server_type()))
+ .SetHtmlFieldType(static_cast<int>(field.html_type()))
+ .SetHtmlFieldMode(static_cast<int>(field.html_mode()))
+ .SetIsAutofilled(field.is_autofilled)
+ .SetIsEmpty(field.IsEmpty())
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp))
+ .Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogFieldFillStatus(
@@ -1411,24 +1352,22 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFieldFillStatus(
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMFieldFillStatusEntryName);
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
- builder->AddMetric(internal::kUKMFormSignatureMetricName,
- static_cast<int64_t>(form.form_signature()));
- builder->AddMetric(internal::kUKMFieldSignatureMetricName,
- static_cast<int64_t>(field.GetFieldSignature()));
- builder->AddMetric(internal::kUKMValidationEventMetricName,
- static_cast<int64_t>(metric_type));
- builder->AddMetric(internal::kUKMIsAutofilledMetricName,
- static_cast<int64_t>(field.is_autofilled));
- builder->AddMetric(internal::kUKMWasPreviouslyAutofilledMetricName,
- static_cast<int64_t>(field.previously_autofilled()));
+ ukm::builders::Autofill_FieldFillStatus(source_id_)
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form.form_parsed_timestamp()))
+ .SetFormSignature(static_cast<int64_t>(form.form_signature()))
+ .SetFieldSignature(static_cast<int64_t>(field.GetFieldSignature()))
+ .SetValidationEvent(static_cast<int64_t>(metric_type))
+ .SetIsAutofilled(static_cast<int64_t>(field.is_autofilled))
+ .SetWasPreviouslyAutofilled(
+ static_cast<int64_t>(field.previously_autofilled()))
+ .Record(ukm_recorder_);
}
+// TODO(szhangcs): Take FormStructure and AutofillField and extract
+// FormSignature and TimeTicks inside the function.
void AutofillMetrics::FormInteractionsUkmLogger::LogFieldType(
+ const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature,
FieldSignature field_signature,
QualityMetricPredictionSource prediction_source,
@@ -1441,45 +1380,38 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFieldType(
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMFieldTypeEntryName);
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
- builder->AddMetric(internal::kUKMFormSignatureMetricName,
- static_cast<int64_t>(form_signature));
- builder->AddMetric(internal::kUKMFieldSignatureMetricName,
- static_cast<int64_t>(field_signature));
- builder->AddMetric(internal::kUKMValidationEventMetricName,
- static_cast<int64_t>(metric_type));
- builder->AddMetric(internal::kUKMPredictionSourceMetricName,
- static_cast<int64_t>(prediction_source));
- builder->AddMetric(internal::kUKMPredictedTypeMetricName,
- static_cast<int64_t>(predicted_type));
- builder->AddMetric(internal::kUKMActualTypeMetricName,
- static_cast<int64_t>(actual_type));
+ ukm::builders::Autofill_FieldTypeValidation(source_id_)
+ .SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp))
+ .SetFormSignature(static_cast<int64_t>(form_signature))
+ .SetFieldSignature(static_cast<int64_t>(field_signature))
+ .SetValidationEvent(static_cast<int64_t>(metric_type))
+ .SetPredictionSource(static_cast<int64_t>(prediction_source))
+ .SetPredictedType(static_cast<int64_t>(predicted_type))
+ .SetActualType(static_cast<int64_t>(actual_type))
+ .Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
- AutofillFormSubmittedState state) {
+ AutofillFormSubmittedState state,
+ const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
return;
if (source_id_ == -1)
GetNewSourceID();
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm_recorder_->GetEntryBuilder(source_id_,
- internal::kUKMFormSubmittedEntryName);
- builder->AddMetric(internal::kUKMAutofillFormSubmittedStateMetricName,
- static_cast<int>(state));
- if (form_parsed_timestamp_.is_null())
+ ukm::builders::Autofill_FormSubmitted builder(source_id_);
+ builder.SetAutofillFormSubmittedState(static_cast<int>(state));
+ if (form_parsed_timestamp.is_null())
DCHECK(state == NON_FILLABLE_FORM_OR_NEW_DATA ||
state == FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS)
<< state;
else
- builder->AddMetric(internal::kUKMMillisecondsSinceFormParsedMetricName,
- MillisecondsSinceFormParsed());
+ builder.SetMillisecondsSinceFormParsed(
+ MillisecondsSinceFormParsed(form_parsed_timestamp));
+
+ builder.Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::UpdateSourceURL(
@@ -1493,14 +1425,13 @@ bool AutofillMetrics::FormInteractionsUkmLogger::CanLog() const {
return ukm_recorder_ && url_.is_valid();
}
-int64_t
-AutofillMetrics::FormInteractionsUkmLogger::MillisecondsSinceFormParsed()
- const {
- DCHECK(!form_parsed_timestamp_.is_null());
+int64_t AutofillMetrics::FormInteractionsUkmLogger::MillisecondsSinceFormParsed(
+ const base::TimeTicks& form_parsed_timestamp) const {
+ DCHECK(!form_parsed_timestamp.is_null());
// Use the pinned timestamp as the current time if it's set.
base::TimeTicks now =
pinned_timestamp_.is_null() ? base::TimeTicks::Now() : pinned_timestamp_;
- return (now - form_parsed_timestamp_).InMilliseconds();
+ return (now - form_parsed_timestamp).InMilliseconds();
}
void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() {
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index ee4526fbfff..3d5f9bafd11 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -21,69 +21,6 @@
#include "components/autofill/core/common/signatures_util.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
-namespace internal {
-// Name constants are exposed here so they can be referenced from tests.
-extern const char kUKMCardUploadDecisionEntryName[];
-extern const char kUKMCardUploadDecisionMetricName[];
-extern const char kUKMDeveloperEngagementEntryName[];
-extern const char kUKMDeveloperEngagementMetricName[];
-
-// Each form interaction event has a separate |UkmEntry|.
-
-// The first form event |UkmEntry| contains metrics for metadata that apply
-// to all subsequent events.
-extern const char kUKMInteractedWithFormEntryName[];
-extern const char kUKMIsForCreditCardMetricName[];
-extern const char kUKMLocalRecordTypeCountMetricName[];
-extern const char kUKMServerRecordTypeCountMetricName[];
-
-// |UkmEntry| when we show suggestions and when user edits text field. See
-// |kUkmTextFieldDidChangeEntryName|.
-extern const char kUKMSuggestionsShownEntryName[];
-extern const char kUKMHeuristicTypeMetricName[];
-extern const char kUKMHtmlFieldTypeMetricName[];
-extern const char kUKMServerTypeMetricName[];
-
-// |UkmEntry| when user selects a masked server credit card.
-extern const char kUKMSelectedMaskedServerCardEntryName[];
-
-// Each |UkmEntry|, except the first interaction with the form, has a metric for
-// time elapsed, in milliseconds, since we loaded the form.
-extern const char kUKMMillisecondsSinceFormParsedMetricName[];
-
-// |FormEvent| for FORM_EVENT_*_SUGGESTION_FILLED in credit card forms include a
-// |CreditCard| |record_type()| to indicate if the suggestion was for a local
-// card, masked server card or full server card. Similarly, address/profile
-// forms include a |AutofillProfile| |record_type()| to indicate if the
-// profile was a local profile or server profile.
-extern const char kUKMSuggestionFilledEntryName[];
-extern const char kUKMRecordTypeMetricName[];
-
-// |UkmEntry| for user editing text field. Metrics contain field's attributes.
-extern const char kUKMTextFieldDidChangeEntryName[];
-extern const char kUKMFieldTypeGroupMetricName[];
-extern const char kUKMHtmlFieldModeMetricName[];
-extern const char kUKMIsAutofilledMetricName[];
-extern const char kUKMIsEmptyMetricName[];
-
-// |UkmEntry| for |AutofillFormSubmittedState|.
-extern const char kUKMFormSubmittedEntryName[];
-extern const char kUKMAutofillFormSubmittedStateMetricName[];
-
-// |UkmEntry| for capturing field fill status and type prediction quality.
-extern const char kUKMFieldTypeEntryName[];
-extern const char kUKMFieldFillStatusEntryName[];
-extern const char kUKMFormSignatureMetricName[];
-extern const char kUKMFieldSignatureMetricName[];
-extern const char kUKMValidationEventMetricName[];
-extern const char kUKMPredictionSourceMetricName[];
-extern const char kUKMPredictedTypeMetricName[];
-extern const char kUKMActualTypeMetricName[];
-extern const char kUKMWasSuggestionShownMetricName[];
-extern const char kUKMWasPreviouslyAutofilledMetricName[];
-
-} // namespace internal
-
namespace autofill {
class AutofillField;
@@ -166,129 +103,6 @@ class AutofillMetrics {
NUM_DEVELOPER_ENGAGEMENT_METRICS,
};
- // The action the user took to dismiss a dialog.
- enum DialogDismissalAction {
- DIALOG_ACCEPTED = 0, // The user accepted, i.e. submitted, the dialog.
- DIALOG_CANCELED, // The user canceled out of the dialog.
- };
-
- // The state of the Autofill dialog when it was dismissed.
- enum DialogDismissalState {
- // The user submitted with no data available to save.
- DEPRECATED_DIALOG_ACCEPTED_EXISTING_DATA,
- // The saved details to Online Wallet on submit.
- DIALOG_ACCEPTED_SAVE_TO_WALLET,
- // The saved details to the local Autofill database on submit.
- DIALOG_ACCEPTED_SAVE_TO_AUTOFILL,
- // The user submitted without saving any edited sections.
- DIALOG_ACCEPTED_NO_SAVE,
- // The user canceled with no edit UI showing.
- DIALOG_CANCELED_NO_EDITS,
- // The user canceled with edit UI showing, but no invalid fields.
- DIALOG_CANCELED_NO_INVALID_FIELDS,
- // The user canceled with at least one invalid field.
- DIALOG_CANCELED_WITH_INVALID_FIELDS,
- // The user canceled while the sign-in form was showing.
- DIALOG_CANCELED_DURING_SIGNIN,
- // The user submitted using data already stored in Wallet.
- DIALOG_ACCEPTED_EXISTING_WALLET_DATA,
- // The user submitted using data already stored in Autofill.
- DIALOG_ACCEPTED_EXISTING_AUTOFILL_DATA,
- NUM_DIALOG_DISMISSAL_STATES
- };
-
- // The initial state of user that's interacting with a freshly shown Autofill
- // dialog.
- enum DialogInitialUserStateMetric {
- // Could not determine the user's state due to failure to communicate with
- // the Wallet server.
- DIALOG_USER_STATE_UNKNOWN = 0,
- // Not signed in, no verified Autofill profiles.
- DIALOG_USER_NOT_SIGNED_IN_NO_AUTOFILL,
- // Not signed in, has verified Autofill profiles.
- DIALOG_USER_NOT_SIGNED_IN_HAS_AUTOFILL,
- // Signed in, no Wallet items, no verified Autofill profiles.
- DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL,
- // Signed in, no Wallet items, has verified Autofill profiles.
- DIALOG_USER_SIGNED_IN_NO_WALLET_HAS_AUTOFILL,
- // Signed in, has Wallet items, no verified Autofill profiles.
- DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL,
- // Signed in, has Wallet items, has verified Autofill profiles.
- DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL,
- NUM_DIALOG_INITIAL_USER_STATE_METRICS
- };
-
- // Events related to the Autofill popup shown in a requestAutocomplete
- // dialog.
- enum DialogPopupEvent {
- // An Autofill popup was shown.
- DIALOG_POPUP_SHOWN = 0,
- // The user chose to fill the form with a suggestion from the popup.
- DIALOG_POPUP_FORM_FILLED,
- NUM_DIALOG_POPUP_EVENTS
- };
-
- // For measuring the frequency of security warnings or errors that can come
- // up as part of the requestAutocomplete flow.
- enum DialogSecurityMetric {
- // Baseline metric: The dialog was shown.
- SECURITY_METRIC_DIALOG_SHOWN = 0,
- // Credit card requested over non-secure protocol.
- SECURITY_METRIC_CREDIT_CARD_OVER_HTTP,
- // Autocomplete data requested from a frame hosted on an origin not matching
- // the main frame's origin.
- SECURITY_METRIC_CROSS_ORIGIN_FRAME,
- NUM_DIALOG_SECURITY_METRICS
- };
-
- // For measuring how users are interacting with the Autofill dialog UI.
- enum DialogUiEvent {
- // Baseline metric: The dialog was shown.
- DIALOG_UI_SHOWN = 0,
-
- // Dialog dismissal actions:
- DIALOG_UI_ACCEPTED,
- DIALOG_UI_CANCELED,
-
- // Selections within the account switcher:
- // Switched from a Wallet account to local Autofill data.
- DIALOG_UI_ACCOUNT_CHOOSER_SWITCHED_TO_AUTOFILL,
- // Switched from local Autofill data to a Wallet account.
- DIALOG_UI_ACCOUNT_CHOOSER_SWITCHED_TO_WALLET,
- // Switched from one Wallet account to another one.
- DIALOG_UI_ACCOUNT_CHOOSER_SWITCHED_WALLET_ACCOUNT,
-
- // The sign-in UI was shown.
- DIALOG_UI_SIGNIN_SHOWN,
-
- // Selecting a different item from a suggestion menu dropdown:
- DEPRECATED_DIALOG_UI_EMAIL_SELECTED_SUGGESTION_CHANGED,
- DIALOG_UI_BILLING_SELECTED_SUGGESTION_CHANGED,
- DIALOG_UI_CC_BILLING_SELECTED_SUGGESTION_CHANGED,
- DIALOG_UI_SHIPPING_SELECTED_SUGGESTION_CHANGED,
- DIALOG_UI_CC_SELECTED_SUGGESTION_CHANGED,
-
- // Showing the editing UI for a section of the dialog:
- DEPRECATED_DIALOG_UI_EMAIL_EDIT_UI_SHOWN,
- DEPRECATED_DIALOG_UI_BILLING_EDIT_UI_SHOWN,
- DEPRECATED_DIALOG_UI_CC_BILLING_EDIT_UI_SHOWN,
- DEPRECATED_DIALOG_UI_SHIPPING_EDIT_UI_SHOWN,
- DEPRECATED_DIALOG_UI_CC_EDIT_UI_SHOWN,
-
- // Adding a new item in a section of the dialog:
- DEPRECATED_DIALOG_UI_EMAIL_ITEM_ADDED,
- DIALOG_UI_BILLING_ITEM_ADDED,
- DIALOG_UI_CC_BILLING_ITEM_ADDED,
- DIALOG_UI_SHIPPING_ITEM_ADDED,
- DIALOG_UI_CC_ITEM_ADDED,
-
- // Also an account switcher menu item. The user selected the
- // "add account" option.
- DIALOG_UI_ACCOUNT_CHOOSER_TRIED_TO_ADD_ACCOUNT,
-
- NUM_DIALOG_UI_EVENTS
- };
-
enum InfoBarMetric {
INFOBAR_SHOWN = 0, // We showed an infobar, e.g. prompting to save credit
// card info.
@@ -344,7 +158,7 @@ class AutofillMetrics {
// page that caused the prompt to be shown. The navigation occurred while
// the prompt was showing.
SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING,
- // The prompt and icon were removed because of navigation away from the
+ // The prompt and icon were removed because of navigation away from the
// page that caused the prompt to be shown. The navigation occurred while
// the prompt was hidden.
SAVE_CARD_PROMPT_END_NAVIGATION_HIDDEN,
@@ -353,6 +167,30 @@ class AutofillMetrics {
// The prompt was dismissed because the user clicked a legal message link.
SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
+ // The following _CVC_FIX_FLOW_ metrics are independent of the ones above.
+ // For instance, accepting the CVC fix flow will trigger both
+ // SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_ACCEPTED as well as
+ // SAVE_CARD_PROMPT_END_ACCEPTED. They are split apart in order to track
+ // acceptance/abandonment rates of the multi-stage dialog user experience.
+
+ // SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_DENIED is an impossible state because
+ // the CVC fix flow uses a close button instead of a cancel button.
+
+ // The prompt moved to a second stage that requested CVC from the user.
+ SAVE_CARD_PROMPT_CVC_FIX_FLOW_SHOWN,
+ // The user explicitly entered CVC and accepted the prompt.
+ SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_ACCEPTED,
+ // The prompt and icon were removed because of navigation away from the page
+ // that caused the prompt to be shown. The navigation occurred while the
+ // prompt was showing, at the CVC request stage.
+ SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_NAVIGATION_SHOWING,
+ // The prompt and icon were removed because of navigation away from the page
+ // that caused the prompt to be shown. The navigation occurred while the
+ // prompt was hidden, at the CVC request stage.
+ SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_NAVIGATION_HIDDEN,
+ // The prompt was dismissed because the user clicked a legal message link.
+ SAVE_CARD_PROMPT_CVC_FIX_FLOW_DISMISS_CLICK_LEGAL_MESSAGE,
+
NUM_SAVE_CARD_PROMPT_METRICS,
};
@@ -747,20 +585,26 @@ class AutofillMetrics {
void LogInteractedWithForm(bool is_for_credit_card,
size_t local_record_type_count,
size_t server_record_type_count);
- void LogSuggestionsShown(const AutofillField& field);
- void LogSelectedMaskedServerCard();
- void LogDidFillSuggestion(int record_type);
- void LogTextFieldDidChange(const AutofillField& field);
+ void LogSuggestionsShown(const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp);
+ void LogSelectedMaskedServerCard(
+ const base::TimeTicks& form_parsed_timestamp);
+ void LogDidFillSuggestion(int record_type,
+ const base::TimeTicks& form_parsed_timestamp);
+ void LogTextFieldDidChange(const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp);
void LogFieldFillStatus(const FormStructure& form,
const AutofillField& field,
QualityMetricType metric_type);
- void LogFieldType(FormSignature form_signature,
+ void LogFieldType(const base::TimeTicks& form_parsed_timestamp,
+ FormSignature form_signature,
FieldSignature field_signature,
QualityMetricPredictionSource prediction_source,
QualityMetricType metric_type,
ServerFieldType predicted_type,
ServerFieldType actual_type);
- void LogFormSubmitted(AutofillFormSubmittedState state);
+ void LogFormSubmitted(AutofillFormSubmittedState state,
+ const base::TimeTicks& form_parsed_timestamp);
// We initialize |url_| with the form's URL when we log the first form
// interaction. Later, we may update |url_| with the |source_url()| for the
@@ -769,13 +613,13 @@ class AutofillMetrics {
private:
bool CanLog() const;
- int64_t MillisecondsSinceFormParsed() const;
+ int64_t MillisecondsSinceFormParsed(
+ const base::TimeTicks& form_parsed_timestamp) const;
void GetNewSourceID();
ukm::UkmRecorder* ukm_recorder_; // Weak reference.
ukm::SourceId source_id_ = -1;
GURL url_;
- base::TimeTicks form_parsed_timestamp_;
base::TimeTicks pinned_timestamp_;
};
@@ -958,6 +802,7 @@ class AutofillMetrics {
// state of the form.
static void LogAutofillFormSubmittedState(
AutofillFormSubmittedState state,
+ const base::TimeTicks& form_parsed_timestamp,
FormInteractionsUkmLogger* form_interactions_ukm_logger);
// This should be called when determining the heuristic types for a form's
@@ -1028,15 +873,19 @@ class AutofillMetrics {
void OnDidPollSuggestions(const FormFieldData& field);
- void OnDidShowSuggestions(const AutofillField& field);
+ void OnDidShowSuggestions(const AutofillField& field,
+ const base::TimeTicks& form_parsed_timestamp);
- void OnDidSelectMaskedServerCardSuggestion();
+ void OnDidSelectMaskedServerCardSuggestion(
+ const base::TimeTicks& form_parsed_timestamp);
// In case of masked cards, caller must make sure this gets called before
// the card is upgraded to a full card.
- void OnDidFillSuggestion(const CreditCard& credit_card);
+ void OnDidFillSuggestion(const CreditCard& credit_card,
+ const base::TimeTicks& form_parsed_timestamp);
- void OnDidFillSuggestion(const AutofillProfile& profile);
+ void OnDidFillSuggestion(const AutofillProfile& profile,
+ const base::TimeTicks& form_parsed_timestamp);
void OnWillSubmitForm();
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index 7fe99a29c6e..86aec540f46 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -35,7 +35,6 @@
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/prefs/pref_service.h"
-#include "components/rappor/test_rappor_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/signin/core/browser/test_signin_client.h"
@@ -43,6 +42,7 @@
#include "components/ukm/test_ukm_recorder.h"
#include "components/ukm/ukm_source.h"
#include "components/webdata/common/web_data_results.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
@@ -51,7 +51,6 @@
using base::ASCIIToUTF16;
using base::Bucket;
using base::TimeTicks;
-using rappor::TestRapporServiceImpl;
using ::testing::ElementsAre;
using ::testing::Matcher;
using ::testing::UnorderedPointwise;
@@ -59,6 +58,18 @@ using ::testing::UnorderedPointwise;
namespace autofill {
namespace {
+using UkmCardUploadDecisionType = ukm::builders::Autofill_CardUploadDecision;
+using UkmDeveloperEngagementType = ukm::builders::Autofill_DeveloperEngagement;
+using UkmInteractedWithFormType = ukm::builders::Autofill_InteractedWithForm;
+using UkmSuggestionsShownType = ukm::builders::Autofill_SuggestionsShown;
+using UkmSelectedMaskedServerCardType =
+ ukm::builders::Autofill_SelectedMaskedServerCard;
+using UkmSuggestionFilledType = ukm::builders::Autofill_SuggestionFilled;
+using UkmTextFieldDidChangeType = ukm::builders::Autofill_TextFieldDidChange;
+using UkmFormSubmittedType = ukm::builders::Autofill_FormSubmitted;
+using UkmFieldTypeValidationType = ukm::builders::Autofill_FieldTypeValidation;
+using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus;
+
using ExpectedUkmMetrics =
std::vector<std::vector<std::pair<const char*, int64_t>>>;
@@ -179,6 +190,7 @@ class TestPersonalDataManager : public PersonalDataManager {
CreditCard::MASKED_SERVER_CARD, "server_id");
credit_card->set_guid("10000000-0000-0000-0000-000000000002");
credit_card->SetNetworkForMaskedCard(kDiscoverCard);
+ credit_card->SetNumber(ASCIIToUTF16("9424"));
server_credit_cards_.push_back(std::move(credit_card));
}
if (include_full_server_credit_card) {
@@ -293,6 +305,7 @@ class TestAutofillManager : public AutofillManager {
std::unique_ptr<TestFormStructure> form_structure =
base::MakeUnique<TestFormStructure>(empty_form);
form_structure->SetFieldTypes(heuristic_types, server_types);
+ form_structure->set_form_parsed_timestamp(TimeTicks::Now());
form_structures()->push_back(std::move(form_structure));
form_interactions_ukm_logger()->OnFormsParsed(form.origin);
@@ -349,8 +362,8 @@ void VerifyDeveloperEngagementUkm(
const ukm::TestAutoSetUkmRecorder& ukm_recorder,
const FormData& form,
const std::vector<int64_t>& expected_metric_values) {
- const ukm::mojom::UkmEntry* entry = ukm_recorder.GetEntryForEntryName(
- internal::kUKMDeveloperEngagementEntryName);
+ const ukm::mojom::UkmEntry* entry =
+ ukm_recorder.GetEntryForEntryName(UkmDeveloperEngagementType::kEntryName);
ASSERT_NE(nullptr, entry);
const ukm::UkmSource* source =
ukm_recorder.GetSourceForSourceId(entry->source_id);
@@ -362,7 +375,8 @@ void VerifyDeveloperEngagementUkm(
expected_metric_value |= 1 << it;
const std::vector<std::pair<const char*, int64_t>> expected_metrics{
- {internal::kUKMDeveloperEngagementMetricName, expected_metric_value}};
+ {UkmDeveloperEngagementType::kDeveloperEngagementName,
+ expected_metric_value}};
EXPECT_THAT(entry->metrics,
UnorderedPointwise(CompareMetrics(), expected_metrics));
@@ -374,7 +388,8 @@ MATCHER(CompareMetricsIgnoringMillisecondsSinceFormParsed, "") {
return lhs->metric_hash == base::HashMetricName(rhs.first) &&
(lhs->value == rhs.second ||
(lhs->value > 0 &&
- rhs.first == internal::kUKMMillisecondsSinceFormParsedMetricName));
+ rhs.first ==
+ UkmSuggestionFilledType::kMillisecondsSinceFormParsedName));
}
void VerifyFormInteractionUkm(const ukm::TestAutoSetUkmRecorder& ukm_recorder,
@@ -404,9 +419,9 @@ void VerifySubmitFormUkm(const ukm::TestAutoSetUkmRecorder& ukm_recorder,
const FormData& form,
AutofillMetrics::AutofillFormSubmittedState state) {
VerifyFormInteractionUkm(
- ukm_recorder, form, internal::kUKMFormSubmittedEntryName,
- {{{internal::kUKMAutofillFormSubmittedStateMetricName, state},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ ukm_recorder, form, UkmFormSubmittedType::kEntryName,
+ {{{UkmFormSubmittedType::kAutofillFormSubmittedStateName, state},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
void AppendFieldFillStatusUkm(const FormData& form,
@@ -417,12 +432,13 @@ void AppendFieldFillStatusUkm(const FormData& form,
int64_t field_signature =
static_cast<int64_t>(CalculateFieldSignatureForField(field));
expected_metrics->push_back(
- {{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMFormSignatureMetricName, form_signature},
- {internal::kUKMFieldSignatureMetricName, field_signature},
- {internal::kUKMValidationEventMetricName, metric_type},
- {internal::kUKMIsAutofilledMetricName, field.is_autofilled ? 1 : 0},
- {internal::kUKMWasPreviouslyAutofilledMetricName, 0}});
+ {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmFieldFillStatusType::kFormSignatureName, form_signature},
+ {UkmFieldFillStatusType::kFieldSignatureName, field_signature},
+ {UkmFieldFillStatusType::kValidationEventName, metric_type},
+ {UkmTextFieldDidChangeType::kIsAutofilledName,
+ field.is_autofilled ? 1 : 0},
+ {UkmFieldFillStatusType::kWasPreviouslyAutofilledName, 0}});
}
}
@@ -451,17 +467,23 @@ void AppendFieldTypeUkm(const FormData& form,
: heuristic_types)[i]);
int64_t actual_type = static_cast<int64_t>(actual_types[i]);
expected_metrics->push_back(
- {{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMFormSignatureMetricName, form_signature},
- {internal::kUKMFieldSignatureMetricName, field_signature},
- {internal::kUKMValidationEventMetricName, metric_type},
- {internal::kUKMPredictionSourceMetricName, source},
- {internal::kUKMPredictedTypeMetricName, predicted_type},
- {internal::kUKMActualTypeMetricName, actual_type}});
+ {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmFieldFillStatusType::kFormSignatureName, form_signature},
+ {UkmFieldFillStatusType::kFieldSignatureName, field_signature},
+ {UkmFieldFillStatusType::kValidationEventName, metric_type},
+ {UkmFieldTypeValidationType::kPredictionSourceName, source},
+ {UkmFieldTypeValidationType::kPredictedTypeName, predicted_type},
+ {UkmFieldTypeValidationType::kActualTypeName, actual_type}});
}
}
}
+class MockAutofillClient : public TestAutofillClient {
+ public:
+ MockAutofillClient() {}
+ MOCK_METHOD1(ExecuteCommand, void(int));
+};
+
} // namespace
// This is defined in the autofill_metrics.cc implementation file.
@@ -480,7 +502,7 @@ class AutofillMetricsTest : public testing::Test {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ukm::TestAutoSetUkmRecorder test_ukm_recorder_;
- TestAutofillClient autofill_client_;
+ MockAutofillClient autofill_client_;
std::unique_ptr<AccountTrackerService> account_tracker_;
std::unique_ptr<FakeSigninManagerBase> signin_manager_;
std::unique_ptr<TestSigninClient> signin_client_;
@@ -907,7 +929,7 @@ TEST_P(QualityMetricsTest, Classification) {
AppendFieldTypeUkm(form, heuristic_types, server_types, actual_types,
&expected_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldTypeEntryName,
+ UkmFieldTypeValidationType::kEntryName,
expected_ukm_metrics);
// Validate the total samples and the crossed (predicted-to-actual) samples.
@@ -2223,24 +2245,24 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
}
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, CREDIT_CARD_NAME_FULL},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, CREDIT_CARD_NAME_FULL}},
- {{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, CREDIT_CARD_NUMBER},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, CREDIT_CARD_NUMBER}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NAME_FULL},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NAME_FULL}},
+ {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
// Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
// call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
// |autofill_manager_->FillOrPreviewForm|.
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
// Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
// because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
VerifySubmitFormUkm(test_ukm_recorder_, form,
@@ -2334,24 +2356,26 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
}
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, ADDRESS_HOME_STATE},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, ADDRESS_HOME_STATE}},
- {{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, ADDRESS_HOME_CITY},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, ADDRESS_HOME_CITY}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, ADDRESS_HOME_STATE},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_STATE}},
+ {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, ADDRESS_HOME_CITY},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_CITY}}});
// Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
// call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
// |autofill_manager_->FillOrPreviewForm|.
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName,
+ AutofillProfile::LOCAL_PROFILE},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmSuggestionFilledType::kRecordTypeName,
+ AutofillProfile::LOCAL_PROFILE},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
// Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
// because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
VerifySubmitFormUkm(test_ukm_recorder_, form,
@@ -3089,11 +3113,49 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, CREDIT_CARD_NUMBER},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, CREDIT_CARD_NUMBER}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName,
+ HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
+ VerifySubmitFormUkm(test_ukm_recorder_, form,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
+ }
+
+ // Reset the autofill manager state and purge UKM logs.
+ autofill_manager_->Reset();
+ test_ukm_recorder_.Purge();
+
+ autofill_manager_->AddSeenForm(form, field_types, field_types);
+
+ {
+ // Simulating submission with suggestion shown. Form is submmitted and
+ // autofill manager is reset before UploadFormDataAsyncCallback is
+ // triggered.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
+ autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
+ autofill_manager_->ResetRunLoop();
+ autofill_manager_->OnWillSubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->Reset();
+ // Trigger UploadFormDataAsyncCallback.
+ autofill_manager_->RunRunLoop();
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.CreditCard",
+ AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.CreditCard",
+ AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName,
+ HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
@@ -3121,9 +3183,9 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE, 1);
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
@@ -3152,9 +3214,10 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 1);
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, CreditCard::FULL_SERVER_CARD},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName,
+ CreditCard::FULL_SERVER_CARD},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
@@ -3185,13 +3248,13 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
1);
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, CreditCard::MASKED_SERVER_CARD},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName,
+ CreditCard::MASKED_SERVER_CARD},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
VerifyFormInteractionUkm(
- test_ukm_recorder_, form,
- internal::kUKMSelectedMaskedServerCardEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSelectedMaskedServerCardType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
@@ -3218,21 +3281,21 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->SubmitForm(form, TimeTicks::Now());
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMFormSubmittedEntryName,
- {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
+ {{{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
autofill_manager_->SubmitForm(form, TimeTicks::Now());
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMFormSubmittedEntryName,
- {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
+ {{{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
@@ -3318,11 +3381,12 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
0);
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, CREDIT_CARD_NUMBER},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, CREDIT_CARD_NUMBER}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName,
+ HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
@@ -3809,6 +3873,35 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
+ // Simulating submission with no filled data. Form is submmitted and
+ // autofill manager is reset before UploadFormDataAsyncCallback is
+ // triggered.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
+ autofill_manager_->ResetRunLoop();
+ autofill_manager_->OnWillSubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->Reset();
+ // Trigger UploadFormDataAsyncCallback.
+ autofill_manager_->RunRunLoop();
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifySubmitFormUkm(test_ukm_recorder_, form,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
+ }
+
+ // Reset the autofill manager state and purge UKM logs.
+ autofill_manager_->Reset();
+ test_ukm_recorder_.Purge();
+
+ autofill_manager_->AddSeenForm(form, field_types, field_types);
+
+ {
// Simulating submission with suggestion shown.
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
@@ -4345,16 +4438,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_NonFillable"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4374,16 +4467,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_NonFillable"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4404,18 +4497,18 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_FilledNone_SuggestionsNotShown"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::
FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4432,23 +4525,25 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_FilledNone_SuggestionsShown"));
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, PHONE_HOME_WHOLE_NUMBER},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName,
+ PHONE_HOME_WHOLE_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName,
+ HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}});
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4468,16 +4563,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_FilledSome"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4498,16 +4593,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_FilledAll"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
@@ -4527,16 +4622,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
"Autofill_FormSubmitted_NonFillable"));
expected_form_submission_ukm_metrics.push_back(
- {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFormSubmittedEntryName,
+ UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
VerifyFormInteractionUkm(test_ukm_recorder_, form,
- internal::kUKMFieldFillStatusEntryName,
+ UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
}
@@ -4648,52 +4743,55 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
autofill_manager_->Reset();
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMInteractedWithFormEntryName,
- {{{internal::kUKMIsForCreditCardMetricName, false},
- {internal::kUKMLocalRecordTypeCountMetricName, 0},
- {internal::kUKMServerRecordTypeCountMetricName, 0}}});
+ test_ukm_recorder_, form, UkmInteractedWithFormType::kEntryName,
+ {{{UkmInteractedWithFormType::kIsForCreditCardName, false},
+ {UkmInteractedWithFormType::kLocalRecordTypeCountName, 0},
+ {UkmInteractedWithFormType::kServerRecordTypeCountName, 0}}});
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionsShownEntryName,
- {{{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, PHONE_HOME_WHOLE_NUMBER},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA}},
- {{internal::kUKMMillisecondsSinceFormParsedMetricName, 0},
- {internal::kUKMHeuristicTypeMetricName, EMAIL_ADDRESS},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA}}});
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName,
+ PHONE_HOME_WHOLE_NUMBER},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}},
+ {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, EMAIL_ADDRESS},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}});
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMSuggestionFilledEntryName,
- {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
+ {{{UkmSuggestionFilledType::kRecordTypeName,
+ AutofillProfile::LOCAL_PROFILE},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmSuggestionFilledType::kRecordTypeName,
+ AutofillProfile::LOCAL_PROFILE},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
VerifyFormInteractionUkm(
- test_ukm_recorder_, form, internal::kUKMTextFieldDidChangeEntryName,
- {{{internal::kUKMFieldTypeGroupMetricName, NAME},
- {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
- {internal::kUKMIsAutofilledMetricName, false},
- {internal::kUKMIsEmptyMetricName, true},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMFieldTypeGroupMetricName, NAME},
- {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
- {internal::kUKMIsAutofilledMetricName, true},
- {internal::kUKMIsEmptyMetricName, true},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}},
- {{internal::kUKMFieldTypeGroupMetricName, EMAIL},
- {internal::kUKMHeuristicTypeMetricName, EMAIL_ADDRESS},
- {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
- {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
- {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
- {internal::kUKMIsAutofilledMetricName, true},
- {internal::kUKMIsEmptyMetricName, true},
- {internal::kUKMMillisecondsSinceFormParsedMetricName, 0}}});
+ test_ukm_recorder_, form, UkmTextFieldDidChangeType::kEntryName,
+ {{{UkmTextFieldDidChangeType::kFieldTypeGroupName, NAME},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, NAME_FULL},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kHtmlFieldModeName, HTML_MODE_NONE},
+ {UkmTextFieldDidChangeType::kIsAutofilledName, false},
+ {UkmTextFieldDidChangeType::kIsEmptyName, true},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmTextFieldDidChangeType::kFieldTypeGroupName, NAME},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, NAME_FULL},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kHtmlFieldModeName, HTML_MODE_NONE},
+ {UkmTextFieldDidChangeType::kIsAutofilledName, true},
+ {UkmTextFieldDidChangeType::kIsEmptyName, true},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {{UkmTextFieldDidChangeType::kFieldTypeGroupName, EMAIL},
+ {UkmTextFieldDidChangeType::kHeuristicTypeName, EMAIL_ADDRESS},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmTextFieldDidChangeType::kHtmlFieldModeName, HTML_MODE_NONE},
+ {UkmTextFieldDidChangeType::kIsAutofilledName, true},
+ {UkmTextFieldDidChangeType::kIsEmptyName, true},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
}
// Verify that we correctly log metrics tracking the duration of form fill.
@@ -5043,7 +5141,6 @@ class AutofillMetricsParseQueryResponseTest : public testing::Test {
}
protected:
- TestRapporServiceImpl rappor_service_;
std::vector<std::unique_ptr<FormStructure>> owned_forms_;
std::vector<FormStructure*> forms_;
};
@@ -5059,17 +5156,13 @@ TEST_F(AutofillMetricsParseQueryResponseTest, ServerHasData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, &rappor_service_);
+ FormStructure::ParseQueryResponse(response_string, forms_);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(true, 2)));
-
- // No RAPPOR metrics are logged in the case there is server data available for
- // all forms.
- EXPECT_EQ(0, rappor_service_.GetReportsCount());
}
-// If the server returns NO_SERVER_DATA for one of the forms, expect RAPPOR
+// If the server returns NO_SERVER_DATA for one of the forms, expect proper
// logging.
TEST_F(AutofillMetricsParseQueryResponseTest, OneFormNoServerData) {
AutofillQueryResponseContents response;
@@ -5082,21 +5175,13 @@ TEST_F(AutofillMetricsParseQueryResponseTest, OneFormNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, &rappor_service_);
+ FormStructure::ParseQueryResponse(response_string, forms_);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(false, 1), Bucket(true, 1)));
-
- EXPECT_EQ(1, rappor_service_.GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service_.GetRecordedSampleForMetric(
- "Autofill.QueryResponseHasNoServerDataForForm", &sample, &type));
- EXPECT_EQ("foo.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
-// If the server returns NO_SERVER_DATA for both of the forms, expect RAPPOR
+// If the server returns NO_SERVER_DATA for both of the forms, expect proper
// logging.
TEST_F(AutofillMetricsParseQueryResponseTest, AllFormsNoServerData) {
AutofillQueryResponseContents response;
@@ -5108,24 +5193,14 @@ TEST_F(AutofillMetricsParseQueryResponseTest, AllFormsNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, &rappor_service_);
+ FormStructure::ParseQueryResponse(response_string, forms_);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(false, 2)));
-
- // Even though both forms are logging to RAPPOR, there is only one sample for
- // a given eTLD+1.
- EXPECT_EQ(1, rappor_service_.GetReportsCount());
- std::string sample;
- rappor::RapporType type;
- EXPECT_TRUE(rappor_service_.GetRecordedSampleForMetric(
- "Autofill.QueryResponseHasNoServerDataForForm", &sample, &type));
- EXPECT_EQ("foo.com", sample);
- EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
-// If the server returns NO_SERVER_DATA for only some of the fields, expect no
-// RAPPOR logging, and expect the UMA metric to say there is data.
+// If the server returns NO_SERVER_DATA for only some of the fields, expect the
+// UMA metric to say there is data.
TEST_F(AutofillMetricsParseQueryResponseTest, PartialNoServerData) {
AutofillQueryResponseContents response;
response.add_field()->set_autofill_type(0);
@@ -5137,23 +5212,18 @@ TEST_F(AutofillMetricsParseQueryResponseTest, PartialNoServerData) {
ASSERT_TRUE(response.SerializeToString(&response_string));
base::HistogramTester histogram_tester;
- FormStructure::ParseQueryResponse(response_string, forms_, &rappor_service_);
+ FormStructure::ParseQueryResponse(response_string, forms_);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ServerResponseHasDataForForm"),
ElementsAre(Bucket(true, 2)));
-
- // No RAPPOR metrics are logged in the case there is at least some server data
- // available for all forms.
- EXPECT_EQ(0, rappor_service_.GetReportsCount());
}
// Test that the Form-Not-Secure warning user action is recorded.
TEST_F(AutofillMetricsTest, ShowHttpNotSecureExplanationUserAction) {
- base::UserActionTester user_action_tester;
+ EXPECT_CALL(autofill_client_,
+ ExecuteCommand(POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
external_delegate_->DidAcceptSuggestion(
ASCIIToUTF16("Test"), POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE, 0);
- EXPECT_EQ(1, user_action_tester.GetActionCount(
- "Autofill_ShowedHttpNotSecureExplanation"));
}
// Tests that credit card form submissions are logged specially when the form is
@@ -5272,12 +5342,9 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
GURL url("https://www.google.com");
int upload_decision = 1;
- std::vector<std::pair<const char*, int>> metrics = {
- {internal::kUKMCardUploadDecisionMetricName, upload_decision}};
- EXPECT_TRUE(AutofillMetrics::LogUkm(&test_ukm_recorder_, url,
- internal::kUKMCardUploadDecisionEntryName,
- metrics));
+ AutofillMetrics::LogCardUploadDecisionsUkm(&test_ukm_recorder_, url,
+ upload_decision);
ASSERT_EQ(1U, test_ukm_recorder_.sources_count());
const ukm::UkmSource* source =
@@ -5289,13 +5356,13 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
// Make sure that a card upload decision entry was logged.
EXPECT_EQ(source->id(), entry->source_id);
- EXPECT_EQ(base::HashMetricName(internal::kUKMCardUploadDecisionEntryName),
+ EXPECT_EQ(base::HashMetricName(UkmCardUploadDecisionType::kEntryName),
entry->event_hash);
EXPECT_EQ(1U, entry->metrics.size());
// Make sure that the correct upload decision was logged.
const ukm::mojom::UkmMetric* metric = ukm::TestUkmRecorder::FindMetric(
- entry, internal::kUKMCardUploadDecisionMetricName);
+ entry, UkmCardUploadDecisionType::kUploadDecisionName);
ASSERT_NE(nullptr, metric);
EXPECT_EQ(upload_decision, metric->value);
}
@@ -5304,12 +5371,9 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
GURL url("https://www.google.com");
int form_structure_metric = 1;
- std::vector<std::pair<const char*, int>> metrics = {
- {internal::kUKMDeveloperEngagementMetricName, form_structure_metric}};
- EXPECT_TRUE(AutofillMetrics::LogUkm(
- &test_ukm_recorder_, url, internal::kUKMDeveloperEngagementEntryName,
- metrics));
+ AutofillMetrics::LogDeveloperEngagementUkm(&test_ukm_recorder_, url,
+ form_structure_metric);
ASSERT_EQ(1U, test_ukm_recorder_.sources_count());
const ukm::UkmSource* source =
@@ -5321,13 +5385,13 @@ TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
// Make sure that a developer engagement entry was logged.
EXPECT_EQ(source->id(), entry->source_id);
- EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
+ EXPECT_EQ(base::HashMetricName(UkmDeveloperEngagementType::kEntryName),
entry->event_hash);
EXPECT_EQ(1U, entry->metrics.size());
// Make sure that the correct developer engagement metric was logged.
const ukm::mojom::UkmMetric* metric = ukm::TestUkmRecorder::FindMetric(
- entry, internal::kUKMDeveloperEngagementMetricName);
+ entry, UkmDeveloperEngagementType::kDeveloperEngagementName);
ASSERT_NE(nullptr, metric);
EXPECT_EQ(form_structure_metric, metric->value);
}
@@ -5335,29 +5399,14 @@ TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
// Tests that no UKM is logged when the URL is not valid.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_InvalidUrl) {
GURL url("");
- std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
-
- EXPECT_FALSE(
- AutofillMetrics::LogUkm(&test_ukm_recorder_, url, "test_ukm", metrics));
- EXPECT_EQ(0U, test_ukm_recorder_.sources_count());
-}
-
-// Tests that no UKM is logged when the metrics map is empty.
-TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoMetrics) {
- GURL url("https://www.google.com");
- std::vector<std::pair<const char*, int>> metrics;
-
- EXPECT_FALSE(
- AutofillMetrics::LogUkm(&test_ukm_recorder_, url, "test_ukm", metrics));
+ AutofillMetrics::LogCardUploadDecisionsUkm(&test_ukm_recorder_, url, 1);
EXPECT_EQ(0U, test_ukm_recorder_.sources_count());
}
// Tests that no UKM is logged when the ukm service is null.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
GURL url("https://www.google.com");
- std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
-
- EXPECT_FALSE(AutofillMetrics::LogUkm(nullptr, url, "test_ukm", metrics));
+ AutofillMetrics::LogCardUploadDecisionsUkm(nullptr, url, 1);
ASSERT_EQ(0U, test_ukm_recorder_.sources_count());
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc
index 35bc5904680..0ad521f08f2 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile.cc
@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/sha1.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
@@ -190,6 +191,21 @@ void GetFieldsForDistinguishingProfiles(
}
}
+// Constants for the validity bitfield.
+static const size_t validity_bits_per_type = 2;
+static const size_t number_supported_types_for_validation = 7;
+// The order is important to ensure a consistent bitfield value. New values
+// should be added at the end NOT at the start or middle.
+static const ServerFieldType
+ supported_types_for_validation[number_supported_types_for_validation] = {
+ ADDRESS_HOME_COUNTRY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_DEPENDENT_LOCALITY,
+ EMAIL_ADDRESS,
+ PHONE_HOME_WHOLE_NUMBER};
+
} // namespace
AutofillProfile::AutofillProfile(const std::string& guid,
@@ -277,38 +293,6 @@ void AutofillProfile::SetRawInfo(ServerFieldType type,
form_group->SetRawInfo(type, value);
}
-base::string16 AutofillProfile::GetInfo(const AutofillType& type,
- const std::string& app_locale) const {
- if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
- std::unique_ptr<AddressData> address_data =
- i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
- if (!addressinput::HasAllRequiredFields(*address_data))
- return base::string16();
-
- std::vector<std::string> lines;
- ::i18n::addressinput::GetFormattedNationalAddress(*address_data, &lines);
- return base::UTF8ToUTF16(base::JoinString(lines, "\n"));
- }
-
- const FormGroup* form_group = FormGroupForType(type);
- if (!form_group)
- return base::string16();
-
- return form_group->GetInfo(type, app_locale);
-}
-
-bool AutofillProfile::SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) {
- FormGroup* form_group = MutableFormGroupForType(type);
- if (!form_group)
- return false;
-
- base::string16 trimmed_value;
- base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
- return form_group->SetInfo(type, trimmed_value, app_locale);
-}
-
void AutofillProfile::GetSupportedTypes(
ServerFieldTypeSet* supported_types) const {
FormGroupList info = FormGroups();
@@ -717,6 +701,87 @@ void AutofillProfile::RecordAndLogUse() {
RecordUse();
}
+AutofillProfile::ValidityState AutofillProfile::GetValidityState(
+ ServerFieldType type) {
+ // Return valid for types that autofill does not validate.
+ if (!IsValidationSupportedForType(type))
+ return UNSUPPORTED;
+
+ if (!base::ContainsKey(validity_states_, type))
+ return UNVALIDATED;
+
+ return validity_states_[type];
+}
+
+void AutofillProfile::SetValidityState(ServerFieldType type,
+ ValidityState validity) {
+ // Do not save validity of unsupported types.
+ if (!IsValidationSupportedForType(type))
+ return;
+
+ std::map<ServerFieldType, ValidityState>::iterator it =
+ validity_states_.find(type);
+
+ if (it != validity_states_.end()) {
+ it->second = validity;
+ } else {
+ validity_states_.insert(std::make_pair(type, validity));
+ }
+}
+
+bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) {
+ return std::find(supported_types_for_validation,
+ supported_types_for_validation +
+ number_supported_types_for_validation,
+ type) !=
+ supported_types_for_validation + number_supported_types_for_validation;
+}
+
+int AutofillProfile::GetValidityBitfieldValue() {
+ int validity_value = 0;
+ size_t field_type_shift = 0;
+ for (ServerFieldType supported_type : supported_types_for_validation) {
+ DCHECK(GetValidityState(supported_type) != UNSUPPORTED);
+ validity_value |= GetValidityState(supported_type) << field_type_shift;
+ field_type_shift += validity_bits_per_type;
+ }
+
+ return validity_value;
+}
+
+base::string16 AutofillProfile::GetInfoImpl(
+ const AutofillType& type,
+ const std::string& app_locale) const {
+ if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
+ std::unique_ptr<AddressData> address_data =
+ i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
+ if (!addressinput::HasAllRequiredFields(*address_data))
+ return base::string16();
+
+ std::vector<std::string> lines;
+ ::i18n::addressinput::GetFormattedNationalAddress(*address_data, &lines);
+ return base::UTF8ToUTF16(base::JoinString(lines, "\n"));
+ }
+
+ const FormGroup* form_group = FormGroupForType(type);
+ if (!form_group)
+ return base::string16();
+
+ return form_group->GetInfoImpl(type, app_locale);
+}
+
+bool AutofillProfile::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
+ FormGroup* form_group = MutableFormGroupForType(type);
+ if (!form_group)
+ return false;
+
+ base::string16 trimmed_value;
+ base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
+ return form_group->SetInfoImpl(type, trimmed_value, app_locale);
+}
+
// static
void AutofillProfile::CreateInferredLabelsHelper(
const std::vector<AutofillProfile*>& profiles,
diff --git a/chromium/components/autofill/core/browser/autofill_profile.h b/chromium/components/autofill/core/browser/autofill_profile.h
index de3311312f3..e9f7f803dfd 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.h
+++ b/chromium/components/autofill/core/browser/autofill_profile.h
@@ -32,14 +32,25 @@ class AutofillProfile : public AutofillDataModel {
enum RecordType {
// A profile stored and editable locally.
LOCAL_PROFILE,
-
// A profile synced down from the server. These are read-only locally.
SERVER_PROFILE,
-
// An auxiliary profile, such as a Mac address book entry.
AUXILIARY_PROFILE,
};
+ enum ValidityState {
+ // The field has not been validated.
+ UNVALIDATED = 0,
+ // The field is empty.
+ EMPTY = 1,
+ // The field is valid.
+ VALID = 2,
+ // The field is invalid.
+ INVALID = 3,
+ // The validation for the field is unsupported.
+ UNSUPPORTED = 4,
+ };
+
AutofillProfile(const std::string& guid, const std::string& origin);
// Server profile constructor. The type must be SERVER_PROFILE (this serves
@@ -60,11 +71,7 @@ class AutofillProfile : public AutofillDataModel {
ServerFieldTypeSet* matching_types) const override;
base::string16 GetRawInfo(ServerFieldType type) const override;
void SetRawInfo(ServerFieldType type, const base::string16& value) override;
- base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const override;
- bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) override;
+
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
// How this card is stored.
@@ -189,9 +196,28 @@ class AutofillProfile : public AutofillDataModel {
bool has_converted() const { return has_converted_; }
void set_has_converted(bool has_converted) { has_converted_ = has_converted; }
+ // Returns the validity state of the specified autofill type.
+ ValidityState GetValidityState(ServerFieldType type);
+
+ // Sets the validity state of the specified autofill type.
+ void SetValidityState(ServerFieldType type, ValidityState validity);
+
+ // Returns whether autofill does the validation of the specified |type|.
+ bool IsValidationSupportedForType(ServerFieldType type);
+
+ // Returns the bitfield value representing the validity state of this profile.
+ int GetValidityBitfieldValue();
+
private:
typedef std::vector<const FormGroup*> FormGroupList;
+ // FormGroup:
+ base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const override;
+ bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) override;
+
// Creates inferred labels for |profiles| at indices corresponding to
// |indices|, and stores the results to the corresponding elements of
// |labels|. These labels include enough fields to differentiate among the
@@ -236,6 +262,9 @@ class AutofillProfile : public AutofillDataModel {
// Only useful for SERVER_PROFILEs. Whether this server profile has been
// converted to a local profile.
bool has_converted_;
+
+ // A map identifying what fields are valid.
+ std::map<ServerFieldType, ValidityState> validity_states_;
};
// So we can compare AutofillProfiles with EXPECT_EQ().
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
index 9975f35a76f..d11ea10fef3 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
@@ -208,10 +208,8 @@ bool AutofillProfileComparator::MergeCJKNames(
const AutofillProfile& p1,
const AutofillProfile& p2,
NameInfo* info) const {
- DCHECK(data_util::IsCJKName(p1.GetInfo(AutofillType(NAME_FULL),
- app_locale_)));
- DCHECK(data_util::IsCJKName(p2.GetInfo(AutofillType(NAME_FULL),
- app_locale_)));
+ DCHECK(data_util::IsCJKName(p1.GetInfo(NAME_FULL, app_locale_)));
+ DCHECK(data_util::IsCJKName(p2.GetInfo(NAME_FULL, app_locale_)));
struct Name {
base::string16 given;
@@ -754,9 +752,9 @@ bool AutofillProfileComparator::HaveMergeableNames(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
base::string16 full_name_1 =
- NormalizeForComparison(p1.GetInfo(AutofillType(NAME_FULL), app_locale_));
+ NormalizeForComparison(p1.GetInfo(NAME_FULL, app_locale_));
base::string16 full_name_2 =
- NormalizeForComparison(p2.GetInfo(AutofillType(NAME_FULL), app_locale_));
+ NormalizeForComparison(p2.GetInfo(NAME_FULL, app_locale_));
if (full_name_1.empty() || full_name_2.empty() ||
full_name_1 == full_name_2) {
@@ -775,22 +773,18 @@ bool AutofillProfileComparator::HaveMergeableNames(
bool AutofillProfileComparator::HaveMergeableCJKNames(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
- base::string16 name_1 =
- NormalizeForComparison(p1.GetInfo(AutofillType(NAME_FULL), app_locale_),
- DISCARD_WHITESPACE);
- base::string16 name_2 =
- NormalizeForComparison(p2.GetInfo(AutofillType(NAME_FULL), app_locale_),
- DISCARD_WHITESPACE);
+ base::string16 name_1 = NormalizeForComparison(
+ p1.GetInfo(NAME_FULL, app_locale_), DISCARD_WHITESPACE);
+ base::string16 name_2 = NormalizeForComparison(
+ p2.GetInfo(NAME_FULL, app_locale_), DISCARD_WHITESPACE);
return name_1 == name_2;
}
bool AutofillProfileComparator::HaveMergeableEmailAddresses(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
- const base::string16& email_1 =
- p1.GetInfo(AutofillType(EMAIL_ADDRESS), app_locale_);
- const base::string16& email_2 =
- p2.GetInfo(AutofillType(EMAIL_ADDRESS), app_locale_);
+ const base::string16& email_1 = p1.GetInfo(EMAIL_ADDRESS, app_locale_);
+ const base::string16& email_2 = p2.GetInfo(EMAIL_ADDRESS, app_locale_);
return email_1.empty() || email_2.empty() ||
case_insensitive_compare_.StringsEqual(email_1, email_2);
}
@@ -798,10 +792,10 @@ bool AutofillProfileComparator::HaveMergeableEmailAddresses(
bool AutofillProfileComparator::HaveMergeableCompanyNames(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
- const base::string16& company_name_1 = NormalizeForComparison(
- p1.GetInfo(AutofillType(COMPANY_NAME), app_locale_));
- const base::string16& company_name_2 = NormalizeForComparison(
- p2.GetInfo(AutofillType(COMPANY_NAME), app_locale_));
+ const base::string16& company_name_1 =
+ NormalizeForComparison(p1.GetInfo(COMPANY_NAME, app_locale_));
+ const base::string16& company_name_2 =
+ NormalizeForComparison(p2.GetInfo(COMPANY_NAME, app_locale_));
return company_name_1.empty() || company_name_2.empty() ||
CompareTokens(company_name_1, company_name_2) != DIFFERENT_TOKENS;
}
@@ -946,9 +940,9 @@ bool AutofillProfileComparator::HaveMergeableAddresses(
// Heuristic: Street addresses are mergeable if one is a (possibly empty) bag
// of words subset of the other.
const base::string16& address1 = rewriter.Rewrite(NormalizeForComparison(
- p1.GetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), app_locale_)));
+ p1.GetInfo(ADDRESS_HOME_STREET_ADDRESS, app_locale_)));
const base::string16& address2 = rewriter.Rewrite(NormalizeForComparison(
- p2.GetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), app_locale_)));
+ p2.GetInfo(ADDRESS_HOME_STREET_ADDRESS, app_locale_)));
if (CompareTokens(address1, address2) == DIFFERENT_TOKENS) {
return false;
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
index ee55bc0857b..07883a8ed51 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -343,9 +343,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_KR) {
"Gangnam Finance Center", "152 Teheran-ro", "Gangnam-Gu",
"Seoul", "135-984", "KR", "+82-2-531-9000");
profiles.back()->set_language_code("ko_Latn");
- profiles.back()->SetInfo(AutofillType(ADDRESS_HOME_DEPENDENT_LOCALITY),
- UTF8ToUTF16("Yeoksam-Dong"),
- "en-US");
+ profiles.back()->SetInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ UTF8ToUTF16("Yeoksam-Dong"), "en-US");
static const char* kExpectedLabels[] = {
"",
"Park Jae-sang",
@@ -735,7 +734,7 @@ TEST(AutofillProfileTest, MergeDataFrom_DifferentProfile) {
EXPECT_EQ(kSettingsOrigin, a.origin());
EXPECT_EQ(ASCIIToUTF16("Unit 5, area 51"), a.GetRawInfo(ADDRESS_HOME_LINE2));
EXPECT_EQ(ASCIIToUTF16("Fox"), a.GetRawInfo(COMPANY_NAME));
- base::string16 name = a.GetInfo(AutofillType(NAME_FULL), "en-US");
+ base::string16 name = a.GetInfo(NAME_FULL, "en-US");
EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison"), name);
EXPECT_EQ("en", a.language_code());
}
@@ -917,7 +916,7 @@ TEST(AutofillProfileTest, SetRawInfoPreservesLineBreaks) {
TEST(AutofillProfileTest, SetInfoPreservesLineBreaks) {
AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
- profile.SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS),
+ profile.SetInfo(ADDRESS_HOME_STREET_ADDRESS,
ASCIIToUTF16("123 Super St.\n"
"Apt. #42"),
"en-US");
@@ -937,8 +936,7 @@ TEST(AutofillProfileTest, SetRawInfoDoesntTrimWhitespace) {
TEST(AutofillProfileTest, SetInfoTrimsWhitespace) {
AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
- profile.SetInfo(AutofillType(EMAIL_ADDRESS),
- ASCIIToUTF16("\tuser@example.com "),
+ profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("\tuser@example.com "),
"en-US");
EXPECT_EQ(ASCIIToUTF16("user@example.com"),
profile.GetRawInfo(EMAIL_ADDRESS));
@@ -964,12 +962,8 @@ TEST(AutofillProfileTest, FullAddress) {
EXPECT_EQ(formatted_address, profile.GetInfo(full_address, "en-US"));
// Some things can be missing...
- profile.SetInfo(AutofillType(ADDRESS_HOME_LINE2),
- base::string16(),
- "en-US");
- profile.SetInfo(AutofillType(EMAIL_ADDRESS),
- base::string16(),
- "en-US");
+ profile.SetInfo(ADDRESS_HOME_LINE2, base::string16(), "en-US");
+ profile.SetInfo(EMAIL_ADDRESS, base::string16(), "en-US");
EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison\n"
"Fox\n"
"123 Zoo St.\n"
@@ -977,17 +971,13 @@ TEST(AutofillProfileTest, FullAddress) {
profile.GetInfo(full_address, "en-US"));
// ...but nothing comes out if a required field is missing.
- profile.SetInfo(AutofillType(ADDRESS_HOME_STATE), base::string16(), "en-US");
+ profile.SetInfo(ADDRESS_HOME_STATE, base::string16(), "en-US");
EXPECT_TRUE(profile.GetInfo(full_address, "en-US").empty());
// Restore the state but remove country. This should also fail.
- profile.SetInfo(AutofillType(ADDRESS_HOME_STATE),
- ASCIIToUTF16("CA"),
- "en-US");
+ profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"), "en-US");
EXPECT_FALSE(profile.GetInfo(full_address, "en-US").empty());
- profile.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY),
- base::string16(),
- "en-US");
+ profile.SetInfo(ADDRESS_HOME_COUNTRY, base::string16(), "en-US");
EXPECT_TRUE(profile.GetInfo(full_address, "en-US").empty());
}
@@ -1100,4 +1090,216 @@ TEST(AutofillProfileTest, SaveAdditionalInfo_Name_ComplementaryInformation) {
a.GetRawInfo(NAME_FULL));
}
+TEST(AutofillProfileTest, ValidityStates) {
+ AutofillProfile profile;
+
+ // The default validity state should be UNVALIDATED.
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+
+ // Make sure setting the validity state works.
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::VALID);
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID);
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::EMPTY);
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(ADDRESS_HOME_CITY));
+ EXPECT_EQ(AutofillProfile::EMPTY,
+ profile.GetValidityState(ADDRESS_HOME_STATE));
+}
+
+TEST(AutofillProfileTest, ValidityStates_UnsupportedTypes) {
+ AutofillProfile profile;
+
+ // The validity state of unsupported types should be UNSUPPORTED.
+ EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+ profile.GetValidityState(ADDRESS_HOME_LINE1));
+
+ // Make sure setting the validity state of an unsupported type does nothing.
+ profile.SetValidityState(ADDRESS_HOME_LINE1, AutofillProfile::VALID);
+ profile.SetValidityState(ADDRESS_HOME_LINE2, AutofillProfile::INVALID);
+ profile.SetValidityState(PHONE_HOME_CITY_AND_NUMBER,
+ AutofillProfile::UNVALIDATED);
+ EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+ profile.GetValidityState(ADDRESS_HOME_LINE1));
+ EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+ profile.GetValidityState(ADDRESS_HOME_LINE2));
+ EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+ profile.GetValidityState(PHONE_HOME_CITY_AND_NUMBER));
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_Country) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::EMPTY);
+ // 0b01
+ EXPECT_EQ(1, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::VALID);
+ // 0b10
+ EXPECT_EQ(2, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::INVALID);
+ // 0b11
+ EXPECT_EQ(3, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_State) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::EMPTY);
+ // 0b0100
+ EXPECT_EQ(4, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::VALID);
+ // 0b1000
+ EXPECT_EQ(8, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID);
+ // 0b1100
+ EXPECT_EQ(12, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_Zip) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::EMPTY);
+ // 0b010000
+ EXPECT_EQ(16, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::VALID);
+ // 0b100000
+ EXPECT_EQ(32, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::INVALID);
+ // 0b110000
+ EXPECT_EQ(48, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_City) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::EMPTY);
+ // 0b01000000
+ EXPECT_EQ(64, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::VALID);
+ // 0b10000000
+ EXPECT_EQ(128, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID);
+ // 0b11000000
+ EXPECT_EQ(192, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_DependentLocality) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ AutofillProfile::EMPTY);
+ // 0b0100000000
+ EXPECT_EQ(256, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ AutofillProfile::VALID);
+ // 0b1000000000
+ EXPECT_EQ(512, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ AutofillProfile::INVALID);
+ // 0b1100000000
+ EXPECT_EQ(768, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_Email) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::EMPTY);
+ // 0b010000000000
+ EXPECT_EQ(1024, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::VALID);
+ // 0b100000000000
+ EXPECT_EQ(2048, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::INVALID);
+ // 0b110000000000
+ EXPECT_EQ(3072, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_Phone) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::EMPTY);
+ // 0b01000000000000
+ EXPECT_EQ(4096, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::VALID);
+ // 0b10000000000000
+ EXPECT_EQ(8192, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID);
+ // 0b11000000000000
+ EXPECT_EQ(12288, profile.GetValidityBitfieldValue());
+}
+
+TEST(AutofillProfileTest, GetValidityBitfieldValue_Mixed) {
+ AutofillProfile profile;
+
+ // By default all validity statuses should be set to UNVALIDATED, thus the
+ // bitfield value should be empty.
+ EXPECT_EQ(0, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::VALID);
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::UNVALIDATED);
+ profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::EMPTY);
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID);
+ profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ AutofillProfile::UNVALIDATED);
+ profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::INVALID);
+ profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::EMPTY);
+ // 0b01110011010010
+ EXPECT_EQ(7378, profile.GetValidityBitfieldValue());
+
+ profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::EMPTY);
+ profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID);
+ profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::VALID);
+ profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::VALID);
+ profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+ AutofillProfile::INVALID);
+ profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::UNVALIDATED);
+ profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID);
+ // 0b11001110101101
+ EXPECT_EQ(13229, profile.GetValidityBitfieldValue());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.cc b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
new file mode 100644
index 00000000000..9f5edc93ce4
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
@@ -0,0 +1,144 @@
+// 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/autofill/core/browser/autofill_profile_validator.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/cancelable_callback.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/address_validation_util.h"
+#include "components/autofill/core/browser/phone_email_validation_util.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
+
+namespace autofill {
+namespace {
+
+using ::i18n::addressinput::COUNTRY;
+using ::i18n::addressinput::ADMIN_AREA;
+using ::i18n::addressinput::LOCALITY;
+using ::i18n::addressinput::DEPENDENT_LOCALITY;
+using ::i18n::addressinput::SORTING_CODE;
+using ::i18n::addressinput::POSTAL_CODE;
+using ::i18n::addressinput::STREET_ADDRESS;
+using ::i18n::addressinput::RECIPIENT;
+
+const int kRulesLoadingTimeoutSeconds = 5;
+
+} // namespace
+
+AutofillProfileValidator::ValidationRequest::ValidationRequest(
+ AutofillProfile* profile,
+ autofill::AddressValidator* validator,
+ AutofillProfileValidatorCallback on_validated)
+ : profile_(profile),
+ validator_(validator),
+ on_validated_(std::move(on_validated)),
+ has_responded_(false),
+ on_timeout_(base::Bind(&ValidationRequest::OnRulesLoaded,
+ base::Unretained(this))) {
+ DCHECK(profile_);
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, on_timeout_.callback(),
+ base::TimeDelta::FromSeconds(kRulesLoadingTimeoutSeconds));
+}
+
+AutofillProfileValidator::ValidationRequest::~ValidationRequest() {
+ on_timeout_.Cancel();
+}
+
+void AutofillProfileValidator::ValidationRequest::OnRulesLoaded() {
+ on_timeout_.Cancel();
+ // Check if the timeout happened before the rules were loaded.
+ if (has_responded_)
+ return;
+ has_responded_ = true;
+ AutofillProfile::ValidityState profile_validity =
+ AutofillProfile::UNVALIDATED;
+ AutofillProfile::ValidityState address_validity =
+ address_validation_util::ValidateAddress(profile_, validator_);
+ AutofillProfile::ValidityState phone_email_validity =
+ phone_email_validation_util::ValidatePhoneAndEmail(profile_);
+
+ if (address_validity == AutofillProfile::INVALID ||
+ phone_email_validity == AutofillProfile::INVALID) {
+ profile_validity = AutofillProfile::INVALID;
+ } else if (address_validity == AutofillProfile::VALID &&
+ phone_email_validity == AutofillProfile::VALID) {
+ profile_validity = AutofillProfile::VALID;
+ }
+
+ std::move(on_validated_).Run(profile_validity);
+}
+
+AutofillProfileValidator::AutofillProfileValidator(
+ std::unique_ptr<Source> source,
+ std::unique_ptr<Storage> storage)
+ : address_validator_(std::move(source), std::move(storage), this) {}
+
+AutofillProfileValidator::~AutofillProfileValidator() {}
+
+void AutofillProfileValidator::ValidateProfile(
+ AutofillProfile* profile,
+ AutofillProfileValidatorCallback cb) {
+ if (!profile) {
+ // An null profile is an unvalidated profile.
+ std::move(cb).Run(AutofillProfile::UNVALIDATED);
+ return;
+ }
+ std::unique_ptr<ValidationRequest> request(
+ base::MakeUnique<ValidationRequest>(profile, &address_validator_,
+ std::move(cb)));
+
+ // If the |region_code| is not a valid code according to our source, calling
+ // LoadRules would result in calling OnAddressValidationRulesLoaded with
+ // success = false. Thus, we can handle illegitimate |region_code|'s as well.
+ std::string region_code =
+ base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY));
+ if (address_validator_.AreRulesLoadedForRegion(region_code)) {
+ request->OnRulesLoaded();
+ } else {
+ // Setup the variables to start validation when the rules are loaded.
+ pending_requests_[region_code].push_back(std::move(request));
+
+ // Start loading the rules for the region. If the rules were already in the
+ // process of being loaded, this call will do nothing.
+ address_validator_.LoadRules(region_code);
+ }
+}
+
+void AutofillProfileValidator::OnAddressValidationRulesLoaded(
+ const std::string& region_code,
+ bool success) {
+ // Even if success = false, we can still validate address partially. We can
+ // check for missing fields or unexpected fields. We can also validate
+ // non-address fields.
+
+ // Check if there is any request for that region code.
+ auto it = pending_requests_.find(region_code);
+ if (it != pending_requests_.end()) {
+ for (auto& request : it->second) {
+ request->OnRulesLoaded();
+ }
+ pending_requests_.erase(it);
+ }
+}
+
+bool AutofillProfileValidator::AreRulesLoadedForRegion(
+ const std::string& region_code) {
+ return address_validator_.AreRulesLoadedForRegion(region_code);
+}
+
+void AutofillProfileValidator::LoadRulesForRegion(
+ const std::string& region_code) {
+ address_validator_.LoadRules(region_code);
+}
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.h b/chromium/components/autofill/core/browser/autofill_profile_validator.h
new file mode 100644
index 00000000000..e1d4bab3334
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_profile_validator.h
@@ -0,0 +1,108 @@
+// 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_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "components/autofill/core/browser/address_i18n.h"
+#include "components/autofill/core/browser/address_validation_util.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+
+namespace autofill {
+
+using ::i18n::addressinput::BuildCallback;
+using ::i18n::addressinput::PreloadSupplier;
+using ::i18n::addressinput::Source;
+using ::i18n::addressinput::Storage;
+
+using AutofillProfileValidatorCallback =
+ base::OnceCallback<void(AutofillProfile::ValidityState)>;
+
+// AutofillProfileValidator Loads Rules from the server and validates an
+// autofill profile. For a given autofill profile, it will set the ValidityState
+// of several fields in the profile such as country, administrative area, etc.
+// See implementation for more details.
+class AutofillProfileValidator : public autofill::LoadRulesListener {
+ public:
+ // Takes ownership of |source| and |storage|.
+ AutofillProfileValidator(
+ std::unique_ptr<::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage);
+
+ ~AutofillProfileValidator() override;
+
+ // If the rule corresponding to the |profile| is loaded, this validates the
+ // profile, synchronously. If it is not loaded yet, it sets up a
+ // task to validate the profile when the rule is loaded (asynchronous). If the
+ // loading has not yet started, it will also start loading the rules.
+ void ValidateProfile(AutofillProfile* profile,
+ AutofillProfileValidatorCallback cb);
+
+ private:
+ // ValidationRequest loads Rules from the server and validates various fields
+ // in an autofill profile.
+ class ValidationRequest {
+ public:
+ ValidationRequest(AutofillProfile* profile,
+ autofill::AddressValidator* validator,
+ AutofillProfileValidatorCallback on_validated);
+
+ ~ValidationRequest();
+
+ // Validates various fields of the |profile_|, and calls |on_validated_|.
+ void OnRulesLoaded();
+
+ private:
+ // Not owned. Not Null. Outlives this object.
+ AutofillProfile* profile_;
+ // Not owned. Outlives this object.
+ autofill::AddressValidator* validator_;
+
+ AutofillProfileValidatorCallback on_validated_;
+
+ bool has_responded_ = false;
+ base::CancelableCallback<void()> on_timeout_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValidationRequest);
+ };
+
+ friend class AutofillProfileValidatorTest;
+
+ // Returns whether the rules for the specified |region_code| is loaded.
+ bool AreRulesLoadedForRegion(const std::string& region_code);
+
+ // Starts loading the rules for the specified |region_code|.
+ void LoadRulesForRegion(const std::string& region_code);
+
+ // Implementation of the LoadRulesListener interface. Called when the address
+ // rules for the |region_code| have finished loading.
+ void OnAddressValidationRulesLoaded(const std::string& region_code,
+ bool success) override;
+
+ // A map of the region code and the pending requests for that region code.
+ std::map<std::string, std::vector<std::unique_ptr<ValidationRequest>>>
+ pending_requests_;
+
+ // The address validator used to load rules.
+ autofill::AddressValidator address_validator_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillProfileValidator);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc
new file mode 100644
index 00000000000..52328bd1f6e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc
@@ -0,0 +1,243 @@
+// 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/autofill/core/browser/autofill_profile_validator.h"
+
+#include <stddef.h>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
+#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
+
+namespace autofill {
+
+using ::i18n::addressinput::NullStorage;
+using ::i18n::addressinput::TestdataSource;
+
+using ::i18n::addressinput::COUNTRY;
+using ::i18n::addressinput::ADMIN_AREA;
+using ::i18n::addressinput::LOCALITY;
+using ::i18n::addressinput::DEPENDENT_LOCALITY;
+using ::i18n::addressinput::SORTING_CODE;
+using ::i18n::addressinput::POSTAL_CODE;
+using ::i18n::addressinput::STREET_ADDRESS;
+using ::i18n::addressinput::RECIPIENT;
+
+// Used to load region rules for this test.
+class ValidationTestDataSource : public TestdataSource {
+ public:
+ ValidationTestDataSource() : TestdataSource(true) {}
+
+ ~ValidationTestDataSource() override {}
+
+ void Get(const std::string& key, const Callback& data_ready) const override {
+ data_ready(
+ true, key,
+ new std::string(
+ "{"
+ "\"data/CA\": "
+ "{\"lang\": \"en\", \"upper\": \"ACNOSZ\", "
+ "\"zipex\": \"H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0\", "
+ "\"name\": \"CANADA\", "
+ "\"fmt\": \"%N%n%O%n%A%n%C %S %Z\", \"id\": \"data/CA\", "
+ "\"languages\": \"en\", \"sub_keys\": \"QC\", \"key\": "
+ "\"CA\", "
+ "\"require\": \"ACSZ\", \"sub_names\": \"Quebec\", "
+ "\"sub_zips\": \"G|H|J\"}, "
+ "\"data/CA/QC\": "
+ "{\"lang\": \"en\", \"key\": \"QC\", "
+ "\"id\": \"data/CA/QC\", \"zip\": \"G|H|J\", \"name\": \"Quebec\"}"
+ "}"));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValidationTestDataSource);
+};
+
+class AutofillProfileValidatorTest : public testing::Test {
+ public:
+ AutofillProfileValidatorTest()
+ : validator_(new AutofillProfileValidator(
+ std::unique_ptr<Source>(new ValidationTestDataSource()),
+ std::unique_ptr<Storage>(new NullStorage))),
+ onvalidated_cb_(
+ base::BindOnce(&AutofillProfileValidatorTest::OnValidated,
+ base::Unretained(this))) {}
+
+ protected:
+ const std::unique_ptr<AutofillProfileValidator> validator_;
+
+ ~AutofillProfileValidatorTest() override {}
+
+ void OnValidated(AutofillProfile::ValidityState profile_valid) {
+ EXPECT_EQ(expected_validity_state_, profile_valid);
+ }
+
+ void set_expected_status(AutofillProfile::ValidityState profile_valid) {
+ expected_validity_state_ = profile_valid;
+ }
+
+ bool AreRulesLoadedForRegion(std::string region_code) {
+ return validator_->AreRulesLoadedForRegion(region_code);
+ }
+
+ void LoadRulesForRegion(std::string region_code) {
+ validator_->LoadRulesForRegion(region_code);
+ }
+
+ AutofillProfileValidatorCallback onvalidated_cb_;
+
+ private:
+ AutofillProfile::ValidityState expected_validity_state_;
+
+ base::test::ScopedTaskEnvironment scoped_task_scheduler;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillProfileValidatorTest);
+};
+
+// Validate a Null profile.
+TEST_F(AutofillProfileValidatorTest, ValidateNullProfile) {
+ set_expected_status(AutofillProfile::UNVALIDATED);
+ validator_->ValidateProfile(nullptr, std::move(onvalidated_cb_));
+}
+// Validate a valid profile, for which the rules are not loaded, yet.
+TEST_F(AutofillProfileValidatorTest, ValidateFullValidProfile_RulesNotLoaded) {
+ // This is a valid profile, and the rules are loaded in the constructors
+ // Province: "QC", Country: "CA"
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ set_expected_status(AutofillProfile::VALID);
+
+ std::string country_code =
+ base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
+ EXPECT_EQ(false, AreRulesLoadedForRegion(country_code));
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a Full Profile, for which the rules are already loaded.
+TEST_F(AutofillProfileValidatorTest, ValidateAddress_RulesLoaded) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ set_expected_status(AutofillProfile::VALID);
+
+ std::string country_code =
+ base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
+ LoadRulesForRegion(country_code);
+ EXPECT_EQ(true, AreRulesLoadedForRegion(country_code));
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// When country code is invalid, the profile is invalid.
+TEST_F(AutofillProfileValidatorTest, ValidateProfile_CountryCodeNotExists) {
+ const std::string country_code = "PP";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ set_expected_status(AutofillProfile::INVALID);
+
+ EXPECT_EQ(false, AreRulesLoadedForRegion(country_code));
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// When country code is valid, but the rule is not in the source, the profile
+// is unvalidated.
+TEST_F(AutofillProfileValidatorTest, ValidateAddress_RuleNotExists) {
+ const std::string country_code = "US";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ set_expected_status(AutofillProfile::UNVALIDATED);
+
+ EXPECT_EQ(false, AreRulesLoadedForRegion(country_code));
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with an invalid phone, valid email and valid address.
+TEST_F(AutofillProfileValidatorTest, ValidateProfile_InvalidPhone) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+
+ set_expected_status(AutofillProfile::INVALID);
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with a valid phone, valid email and invalid address.
+TEST_F(AutofillProfileValidatorTest, ValidateProfile_InvalidAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ // QQ is an invalid admin area, thus an invalid address.
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("QQ"));
+
+ set_expected_status(AutofillProfile::INVALID);
+
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with an invalid phone, invalid email and invalid address.
+TEST_F(AutofillProfileValidatorTest,
+ ValidateProfile_InvalidPhone_InvalidAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+ // QQ is an invalid admin area, thus an invalid address.
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("QQ"));
+
+ set_expected_status(AutofillProfile::INVALID);
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with a valid phone, invalid email and invalid address.
+TEST_F(AutofillProfileValidatorTest,
+ ValidateProfile_InvalidEmail_InvalidAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Invalid Email."));
+ // QQ is an invalid admin area, thus an invalid address.
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("QQ"));
+
+ set_expected_status(AutofillProfile::INVALID);
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with a valid phone, invalid email and invalid address.
+TEST_F(AutofillProfileValidatorTest,
+ ValidateProfile_InvalidEmail_InvalidPhone) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Invalid Email."));
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+
+ set_expected_status(AutofillProfile::INVALID);
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with a valid phone, invalid email and valid address.
+TEST_F(AutofillProfileValidatorTest, ValidateProfile_InvalidEmail) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Invalid Email."));
+
+ set_expected_status(AutofillProfile::VALID);
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+// Validate a profile with a invalid phone, invalid email and invalid address.
+TEST_F(AutofillProfileValidatorTest,
+ ValidateProfile_InvalidEmail_InvalidPhone_InvalidAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Invalid Email."));
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+ // QQ is an invalid admin area, thus an invalid address.
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("QQ"));
+
+ set_expected_status(AutofillProfile::INVALID);
+ validator_->ValidateProfile(&profile, std::move(onvalidated_cb_));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index 6ca9deb0ead..aa3b5952e4b 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -183,6 +183,14 @@ inline void check_and_set(
profile->SetRawInfo(type, base::UTF8ToUTF16(value));
}
+AutofillProfile GetFullValidProfile() {
+ AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ SetProfileInfo(&profile, "Alice", "", "Wonderland", "alice@wonderland.ca",
+ "Fiction", "666 Notre-Dame Ouest", "Apt 8", "Montreal", "QC",
+ "H3B 2T9", "CA", "15141112233");
+ return profile;
+}
+
AutofillProfile GetFullProfile() {
AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
SetProfileInfo(&profile,
@@ -334,7 +342,7 @@ void SetCreditCardInfo(CreditCard* credit_card,
void DisableSystemServices(PrefService* prefs) {
// Use a mock Keychain rather than the OS one to store credit card data.
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
}
void ReenableSystemServices() {
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index 65817d8d9dc..708f3a640be 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -65,6 +65,9 @@ void CreateTestAddressFormData(FormData* form);
void CreateTestAddressFormData(FormData* form,
std::vector<ServerFieldTypeSet>* types);
+// Returns a full profile with valid info.
+AutofillProfile GetFullValidProfile();
+
// Returns a profile full of dummy info.
AutofillProfile GetFullProfile();
diff --git a/chromium/components/autofill/core/browser/contact_info.cc b/chromium/components/autofill/core/browser/contact_info.cc
index ec4399495be..7d54216de31 100644
--- a/chromium/components/autofill/core/browser/contact_info.cc
+++ b/chromium/components/autofill/core/browser/contact_info.cc
@@ -69,14 +69,6 @@ bool NameInfo::NamePartsAreEmpty() const {
return given_.empty() && middle_.empty() && family_.empty();
}
-void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
- supported_types->insert(NAME_FIRST);
- supported_types->insert(NAME_MIDDLE);
- supported_types->insert(NAME_LAST);
- supported_types->insert(NAME_MIDDLE_INITIAL);
- supported_types->insert(NAME_FULL);
-}
-
base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
DCHECK_EQ(NAME, AutofillType(type).group());
switch (type) {
@@ -102,7 +94,6 @@ base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
DCHECK_EQ(NAME, AutofillType(type).group());
-
switch (type) {
case NAME_FIRST:
given_ = value;
@@ -126,17 +117,25 @@ void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
}
}
-base::string16 NameInfo::GetInfo(const AutofillType& type,
- const std::string& app_locale) const {
+void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
+ supported_types->insert(NAME_FIRST);
+ supported_types->insert(NAME_MIDDLE);
+ supported_types->insert(NAME_LAST);
+ supported_types->insert(NAME_MIDDLE_INITIAL);
+ supported_types->insert(NAME_FULL);
+}
+
+base::string16 NameInfo::GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const {
if (type.GetStorableType() == NAME_FULL)
return FullName();
return GetRawInfo(type.GetStorableType());
}
-bool NameInfo::SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) {
+bool NameInfo::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
// Always clear out the full name if we're making a change.
if (value != GetInfo(type, app_locale))
full_.clear();
@@ -146,7 +145,7 @@ bool NameInfo::SetInfo(const AutofillType& type,
return true;
}
- return FormGroup::SetInfo(type, value, app_locale);
+ return FormGroup::SetInfoImpl(type, value, app_locale);
}
base::string16 NameInfo::FullName() const {
diff --git a/chromium/components/autofill/core/browser/contact_info.h b/chromium/components/autofill/core/browser/contact_info.h
index edadcab2d1f..3c5e451a73c 100644
--- a/chromium/components/autofill/core/browser/contact_info.h
+++ b/chromium/components/autofill/core/browser/contact_info.h
@@ -39,15 +39,15 @@ class NameInfo : public FormGroup {
// FormGroup:
base::string16 GetRawInfo(ServerFieldType type) const override;
void SetRawInfo(ServerFieldType type, const base::string16& value) override;
- base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const override;
- bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) override;
private:
// FormGroup:
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
+ base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const override;
+ bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) override;
// Returns the full name, which is either |full_|, or if |full_| is empty,
// is composed of given, middle and family.
diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc
index aeda42b6da3..76ea54a319f 100644
--- a/chromium/components/autofill/core/browser/credit_card.cc
+++ b/chromium/components/autofill/core/browser/credit_card.cc
@@ -98,6 +98,18 @@ base::string16 NetworkForFill(const std::string& network) {
return base::string16();
}
+// Returns the last four digits of the credit card |number| (fewer if there are
+// not enough characters in |number|).
+base::string16 GetLastFourDigits(const base::string16& number) {
+ static const size_t kNumLastDigits = 4;
+
+ base::string16 stripped = CreditCard::StripSeparators(number);
+ if (stripped.size() <= kNumLastDigits)
+ return stripped;
+
+ return stripped.substr(stripped.size() - kNumLastDigits, kNumLastDigits);
+}
+
} // namespace
CreditCard::CreditCard(const std::string& guid, const std::string& origin)
@@ -394,35 +406,6 @@ void CreditCard::SetRawInfo(ServerFieldType type,
}
}
-base::string16 CreditCard::GetInfo(const AutofillType& type,
- const std::string& app_locale) const {
- ServerFieldType storable_type = type.GetStorableType();
- if (storable_type == CREDIT_CARD_NUMBER) {
- // Web pages should never actually be filled by a masked server card,
- // but this function is used at the preview stage.
- if (record_type() == MASKED_SERVER_CARD)
- return NetworkAndLastFourDigits();
-
- return StripSeparators(number_);
- }
-
- return GetRawInfo(storable_type);
-}
-
-bool CreditCard::SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) {
- ServerFieldType storable_type = type.GetStorableType();
- if (storable_type == CREDIT_CARD_NUMBER)
- SetRawInfo(storable_type, StripSeparators(value));
- else if (storable_type == CREDIT_CARD_EXP_MONTH)
- return SetExpirationMonthFromString(value, app_locale);
- else
- SetRawInfo(storable_type, value);
-
- return true;
-}
-
void CreditCard::GetMatchingTypes(const base::string16& text,
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const {
@@ -430,8 +413,15 @@ void CreditCard::GetMatchingTypes(const base::string16& text,
base::string16 card_number =
GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale);
- if (!card_number.empty() && StripSeparators(text) == card_number)
- matching_types->insert(CREDIT_CARD_NUMBER);
+ if (!card_number.empty()) {
+ // We only have the last four digits for masked cards, so match against
+ // that if |this| is a masked card.
+ bool numbers_match = record_type_ == MASKED_SERVER_CARD
+ ? GetLastFourDigits(text) == LastFourDigits()
+ : StripSeparators(text) == card_number;
+ if (numbers_match)
+ matching_types->insert(CREDIT_CARD_NUMBER);
+ }
int month;
if (ConvertMonth(text, app_locale, &month) &&
@@ -731,13 +721,7 @@ const base::string16 CreditCard::Label() const {
}
base::string16 CreditCard::LastFourDigits() const {
- static const size_t kNumLastDigits = 4;
-
- base::string16 number = StripSeparators(number_);
- if (number.size() <= kNumLastDigits)
- return number;
-
- return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
+ return GetLastFourDigits(number_);
}
base::string16 CreditCard::NetworkForDisplay() const {
@@ -869,6 +853,35 @@ void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
}
+base::string16 CreditCard::GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const {
+ ServerFieldType storable_type = type.GetStorableType();
+ if (storable_type == CREDIT_CARD_NUMBER) {
+ // Web pages should never actually be filled by a masked server card,
+ // but this function is used at the preview stage.
+ if (record_type() == MASKED_SERVER_CARD)
+ return NetworkAndLastFourDigits();
+
+ return StripSeparators(number_);
+ }
+
+ return GetRawInfo(storable_type);
+}
+
+bool CreditCard::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
+ ServerFieldType storable_type = type.GetStorableType();
+ if (storable_type == CREDIT_CARD_NUMBER)
+ SetRawInfo(storable_type, StripSeparators(value));
+ else if (storable_type == CREDIT_CARD_EXP_MONTH)
+ return SetExpirationMonthFromString(value, app_locale);
+ else
+ SetRawInfo(storable_type, value);
+
+ return true;
+}
+
base::string16 CreditCard::NetworkForFill() const {
return ::autofill::NetworkForFill(network_);
}
diff --git a/chromium/components/autofill/core/browser/credit_card.h b/chromium/components/autofill/core/browser/credit_card.h
index 4a58dab6b49..f4d373da17b 100644
--- a/chromium/components/autofill/core/browser/credit_card.h
+++ b/chromium/components/autofill/core/browser/credit_card.h
@@ -101,11 +101,6 @@ class CreditCard : public AutofillDataModel {
ServerFieldTypeSet* matching_types) const override;
base::string16 GetRawInfo(ServerFieldType type) const override;
void SetRawInfo(ServerFieldType type, const base::string16& value) override;
- base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const override;
- bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) override;
// Special method to set value for HTML5 month input type.
void SetInfoForMonthInputType(const base::string16& value);
@@ -248,6 +243,11 @@ class CreditCard : public AutofillDataModel {
// FormGroup:
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
+ base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const override;
+ bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) override;
// The issuer network of the card to fill in to the page, e.g. 'Mastercard'.
base::string16 NetworkForFill() const;
diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc
index 91a195d433f..93e5f128678 100644
--- a/chromium/components/autofill/core/browser/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc
@@ -681,6 +681,172 @@ TEST(CreditCardTest, CreditCardVerificationCode) {
EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE));
}
+struct MatchingTypesCase {
+ MatchingTypesCase(const char* value,
+ const char* card_exp_month,
+ const char* card_exp_year,
+ CreditCard::RecordType record_type,
+ ServerFieldTypeSet expected_matched_types,
+ const char* locale = "US")
+ : value(value),
+ card_exp_month(card_exp_month),
+ card_exp_year(card_exp_year),
+ record_type(record_type),
+ expected_matched_types(expected_matched_types),
+ locale(locale) {}
+
+ // The value entered by the user.
+ const std::string value;
+ // Some values for an already saved card. Card number will be fixed to
+ // 4012888888881881.
+ const char* card_exp_month;
+ const char* card_exp_year;
+ const CreditCard::RecordType record_type;
+ // The types that are expected to match.
+ const ServerFieldTypeSet expected_matched_types;
+
+ const std::string locale;
+};
+
+class GetMatchingTypesTest : public testing::TestWithParam<MatchingTypesCase> {
+};
+
+TEST_P(GetMatchingTypesTest, Cases) {
+ auto test_case = GetParam();
+ CreditCard card(base::GenerateGUID(), "https://www.example.com/");
+ card.set_record_type(test_case.record_type);
+ card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4012888888881881"));
+ card.SetRawInfo(CREDIT_CARD_EXP_MONTH,
+ ASCIIToUTF16(test_case.card_exp_month));
+ card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ ASCIIToUTF16(test_case.card_exp_year));
+
+ ServerFieldTypeSet matching_types;
+ card.GetMatchingTypes(UTF8ToUTF16(test_case.value), test_case.locale,
+ &matching_types);
+ EXPECT_EQ(test_case.expected_matched_types, matching_types);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetMatchingTypesTest,
+ testing::Values(
+ // If comparing against a masked card, last four digits are checked.
+ MatchingTypesCase{"1881",
+ "01",
+ "2020",
+ MASKED_SERVER_CARD,
+ {CREDIT_CARD_NUMBER}},
+ MatchingTypesCase{"4012888888881881",
+ "01",
+ "2020",
+ MASKED_SERVER_CARD,
+ {CREDIT_CARD_NUMBER}},
+ MatchingTypesCase{"4111111111111111", "01", "2020",
+ CreditCard::MASKED_SERVER_CARD, ServerFieldTypeSet()},
+ // Same value will not match a local card or full server card since we
+ // have the full number for those. However the full number will.
+ MatchingTypesCase{"1881", "01", "2020", LOCAL_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"1881", "01", "2020", FULL_SERVER_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"4012888888881881",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_NUMBER}},
+ MatchingTypesCase{"4012888888881881",
+ "01",
+ "2020",
+ FULL_SERVER_CARD,
+ {CREDIT_CARD_NUMBER}},
+
+ // Wrong last four digits.
+ MatchingTypesCase{"1111", "01", "2020", MASKED_SERVER_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"1111", "01", "2020", LOCAL_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"1111", "01", "2020", FULL_SERVER_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"4111111111111111", "01", "2020", MASKED_SERVER_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"4111111111111111", "01", "2020", LOCAL_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"4111111111111111", "01", "2020", FULL_SERVER_CARD,
+ ServerFieldTypeSet()},
+
+ // Matching the expiration month.
+ MatchingTypesCase{"01",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH}},
+ MatchingTypesCase{"1",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH}},
+ MatchingTypesCase{"jan",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH},
+ "US"},
+ // Locale-specific interpretations.
+ MatchingTypesCase{"janv",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH},
+ "FR"},
+ MatchingTypesCase{"janv.",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH},
+ "FR"},
+ MatchingTypesCase{"janvier",
+ "01",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH},
+ "FR"},
+ MatchingTypesCase{"février",
+ "02",
+ "2020",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_MONTH},
+ "FR"},
+ MatchingTypesCase{"mars", "01", "2020", LOCAL_CARD,
+ ServerFieldTypeSet(), "FR"},
+
+ // Matching the expiration year.
+ MatchingTypesCase{"2019",
+ "01",
+ "2019",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
+ MatchingTypesCase{"19",
+ "01",
+ "2019",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
+ MatchingTypesCase{"01/2019",
+ "01",
+ "2019",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+ MatchingTypesCase{"01-2019",
+ "01",
+ "2019",
+ LOCAL_CARD,
+ {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+ MatchingTypesCase{"01/2020", "01", "2019", LOCAL_CARD,
+ ServerFieldTypeSet()},
+ MatchingTypesCase{"20", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+ MatchingTypesCase{"2021", "01", "2019", LOCAL_CARD,
+ ServerFieldTypeSet()}));
+
struct GetCardNetworkTestCase {
std::string card_number;
std::string issuer_network;
diff --git a/chromium/components/autofill/core/browser/detail_input.cc b/chromium/components/autofill/core/browser/detail_input.cc
deleted file mode 100644
index 4d36d7502dc..00000000000
--- a/chromium/components/autofill/core/browser/detail_input.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/autofill/core/browser/detail_input.h"
-
-namespace autofill {
-
-// Street address is multi-line, except in countries where it shares a line
-// with other inputs (such as Coite d'Ivoire).
-bool DetailInput::IsMultiline() const {
- return (type == ADDRESS_HOME_STREET_ADDRESS ||
- type == ADDRESS_BILLING_STREET_ADDRESS) &&
- length == DetailInput::LONG;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/detail_input.h b/chromium/components/autofill/core/browser/detail_input.h
deleted file mode 100644
index f5037c69516..00000000000
--- a/chromium/components/autofill/core/browser/detail_input.h
+++ /dev/null
@@ -1,50 +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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DETAIL_INPUT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_DETAIL_INPUT_H_
-
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "components/autofill/core/browser/field_types.h"
-
-namespace autofill {
-
-// This struct describes a single input control for the imperative autocomplete
-// dialog.
-struct DetailInput {
- enum Length {
- SHORT, // Shares a line with other short inputs, like display: inline.
- SHORT_EOL, // Like SHORT but starts a new line directly afterward. Used to
- // separate groups of short inputs into different lines.
- LONG, // Will be given its own full line, like display: block.
- NONE, // Input will not be shown.
- };
-
- // Returns whether this input can spread across multiple lines.
- bool IsMultiline() const;
-
- // Used to determine which inputs share lines when laying out.
- Length length;
-
- ServerFieldType type;
-
- // Text shown when the input is at its default state (e.g. empty).
- base::string16 placeholder_text;
-
- // A number between 0 and 1.0 that describes how much of the horizontal space
- // in the row should be allotted to this input. 0 is equivalent to 1.
- float expand_weight;
-
- // When non-empty, indicates the starting value for this input. This will be
- // used when the user is editing existing data.
- base::string16 initial_value;
-};
-
-typedef std::vector<DetailInput> DetailInputs;
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DETAIL_INPUT_H_
diff --git a/chromium/components/autofill/core/browser/dialog_section.h b/chromium/components/autofill/core/browser/dialog_section.h
deleted file mode 100644
index 7aabafbfa2b..00000000000
--- a/chromium/components/autofill/core/browser/dialog_section.h
+++ /dev/null
@@ -1,27 +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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DIALOG_SECTION_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_DIALOG_SECTION_H_
-
-namespace autofill {
-
-// Sections of the dialog --- all fields that may be shown to the user fit under
-// one of these sections.
-enum DialogSection {
- // Lower boundary value for looping over all sections.
- SECTION_MIN,
-
- // The Autofill-backed dialog uses separate CC and billing sections.
- SECTION_CC = SECTION_MIN,
- SECTION_BILLING,
- SECTION_SHIPPING,
-
- // Upper boundary value for looping over all sections.
- SECTION_MAX = SECTION_SHIPPING,
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DIALOG_SECTION_H_
diff --git a/chromium/components/autofill/core/browser/form_group.cc b/chromium/components/autofill/core/browser/form_group.cc
index 1f248ccf94e..1caf414bc8a 100644
--- a/chromium/components/autofill/core/browser/form_group.cc
+++ b/chromium/components/autofill/core/browser/form_group.cc
@@ -45,16 +45,26 @@ void FormGroup::GetNonEmptyTypes(const std::string& app_locale,
}
}
+base::string16 FormGroup::GetInfo(ServerFieldType type,
+ const std::string& app_locale) const {
+ return GetInfoImpl(AutofillType(type), app_locale);
+}
+
base::string16 FormGroup::GetInfo(const AutofillType& type,
const std::string& app_locale) const {
- return GetRawInfo(type.GetStorableType());
+ return GetInfoImpl(type, app_locale);
+}
+
+bool FormGroup::SetInfo(ServerFieldType type,
+ const base::string16& value,
+ const std::string& app_locale) {
+ return SetInfoImpl(AutofillType(type), value, app_locale);
}
bool FormGroup::SetInfo(const AutofillType& type,
const base::string16& value,
const std::string& app_locale) {
- SetRawInfo(type.GetStorableType(), value);
- return true;
+ return SetInfoImpl(type, value, app_locale);
}
bool FormGroup::HasInfo(ServerFieldType type) const {
@@ -67,4 +77,16 @@ bool FormGroup::HasInfo(const AutofillType& type) const {
return !GetInfo(type, "en-US").empty();
}
+base::string16 FormGroup::GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const {
+ return GetRawInfo(type.GetStorableType());
+}
+
+bool FormGroup::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
+ SetRawInfo(type.GetStorableType(), value);
+ return true;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_group.h b/chromium/components/autofill/core/browser/form_group.h
index c3d9cd14e2d..ea00c32c24b 100644
--- a/chromium/components/autofill/core/browser/form_group.h
+++ b/chromium/components/autofill/core/browser/form_group.h
@@ -44,14 +44,19 @@ class FormGroup {
// Returns the string that should be auto-filled into a text field given the
// type of that field, localized to the given |app_locale| if appropriate.
- virtual base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const;
+ base::string16 GetInfo(ServerFieldType type,
+ const std::string& app_locale) const;
+ base::string16 GetInfo(const AutofillType& type,
+ const std::string& app_locale) const;
- // Used to populate this FormGroup object with data. Canonicalizes the data
+ // Used to populate this FormGroup object with data. Canonicalizes the data
// according to the specified |app_locale| prior to storing, if appropriate.
- virtual bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale);
+ bool SetInfo(ServerFieldType type,
+ const base::string16& value,
+ const std::string& app_locale);
+ bool SetInfo(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale);
// Returns true iff the string associated with |type| is nonempty.
bool HasInfo(ServerFieldType type) const;
@@ -65,6 +70,17 @@ class FormGroup {
// Returns a set of server field types for which this FormGroup can store
// data. This method is additive on |supported_types|.
virtual void GetSupportedTypes(ServerFieldTypeSet* supported_types) const = 0;
+
+ // Returns the string that should be auto-filled into a text field given the
+ // type of that field, localized to the given |app_locale| if appropriate.
+ virtual base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const;
+
+ // Used to populate this FormGroup object with data. Canonicalizes the data
+ // according to the specified |app_locale| prior to storing, if appropriate.
+ virtual bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale);
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index a18ae1bd40d..531a20758c1 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -23,6 +23,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_candidates.h"
@@ -36,8 +37,6 @@
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
#include "components/autofill/core/common/signatures_util.h"
-#include "components/rappor/public/rappor_utils.h"
-#include "components/rappor/rappor_service_impl.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
namespace autofill {
@@ -395,6 +394,9 @@ void FormStructure::DetermineHeuristicTypes(ukm::UkmRecorder* ukm_recorder) {
AutofillMetrics::LogDeveloperEngagementUkm(ukm_recorder, source_url(),
developer_engagement_metrics);
+ if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions))
+ RationalizeFieldTypePredictions();
+
AutofillMetrics::LogDetermineHeuristicTypesTiming(
base::TimeTicks::Now() - determine_heuristic_types_start_time);
}
@@ -466,8 +468,7 @@ bool FormStructure::EncodeQueryRequest(
// static
void FormStructure::ParseQueryResponse(
std::string payload,
- const std::vector<FormStructure*>& forms,
- rappor::RapporServiceImpl* rappor_service) {
+ const std::vector<FormStructure*>& forms) {
AutofillMetrics::LogServerQueryMetric(
AutofillMetrics::QUERY_RESPONSE_RECEIVED);
@@ -519,14 +520,12 @@ void FormStructure::ParseQueryResponse(
AutofillMetrics::LogServerResponseHasDataForForm(
!query_response_has_no_server_data);
- if (query_response_has_no_server_data && form->source_url().is_valid()) {
- rappor::SampleDomainAndRegistryFromGURL(
- rappor_service, "Autofill.QueryResponseHasNoServerDataForForm",
- form->source_url());
- }
form->UpdateAutofillCount();
form->IdentifySections(false);
+
+ if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions))
+ form->RationalizeFieldTypePredictions();
}
AutofillMetrics::ServerQueryMetric metric;
@@ -680,6 +679,9 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form,
UpdateAutofillCount();
+ // Update form parsed timestamp
+ set_form_parsed_timestamp(cached_form.form_parsed_timestamp());
+
// The form signature should match between query and upload requests to the
// server. On many websites, form elements are dynamically added, removed, or
// rearranged via JavaScript between page load and form submission, so we
@@ -692,7 +694,6 @@ void FormStructure::LogQualityMetrics(
const base::TimeTicks& load_time,
const base::TimeTicks& interaction_time,
const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
bool did_show_suggestions,
bool observed_submission) const {
@@ -803,7 +804,7 @@ void FormStructure::LogQualityMetrics(
if (form_interactions_ukm_logger->url() != source_url())
form_interactions_ukm_logger->UpdateSourceURL(source_url());
AutofillMetrics::LogAutofillFormSubmittedState(
- state, form_interactions_ukm_logger);
+ state, form_parsed_timestamp_, form_interactions_ukm_logger);
}
}
@@ -1050,6 +1051,148 @@ bool FormStructure::operator!=(const FormData& form) const {
return !operator==(form);
}
+void FormStructure::RationalizeFieldTypePredictions() {
+ bool cc_first_name_found = false;
+ bool cc_last_name_found = false;
+ bool cc_num_found = false;
+ bool cc_month_found = false;
+ bool cc_year_found = false;
+ bool cc_type_found = false;
+ bool cc_cvc_found = false;
+ size_t num_months_found = 0;
+ size_t num_other_fields_found = 0;
+ for (const auto& field : fields_) {
+ ServerFieldType current_field_type = field->Type().GetStorableType();
+ switch (current_field_type) {
+ case CREDIT_CARD_NAME_FIRST:
+ cc_first_name_found = true;
+ break;
+ case CREDIT_CARD_NAME_LAST:
+ cc_last_name_found = true;
+ break;
+ case CREDIT_CARD_NAME_FULL:
+ cc_first_name_found = true;
+ cc_last_name_found = true;
+ break;
+ case CREDIT_CARD_NUMBER:
+ cc_num_found = true;
+ break;
+ case CREDIT_CARD_EXP_MONTH:
+ cc_month_found = true;
+ ++num_months_found;
+ break;
+ case CREDIT_CARD_EXP_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_4_DIGIT_YEAR:
+ cc_year_found = true;
+ break;
+ case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+ cc_month_found = true;
+ cc_year_found = true;
+ ++num_months_found;
+ break;
+ case CREDIT_CARD_TYPE:
+ cc_type_found = true;
+ break;
+ case CREDIT_CARD_VERIFICATION_CODE:
+ cc_cvc_found = true;
+ break;
+ case ADDRESS_HOME_ZIP:
+ case ADDRESS_BILLING_ZIP:
+ // Zip/Postal code often appears as part of a Credit Card form. Do
+ // not count it as a non-cc-related field.
+ break;
+ default:
+ ++num_other_fields_found;
+ }
+ }
+
+ // A partial CC name is unlikely. Prefer to consider these profile names
+ // when partial.
+ bool cc_name_found = cc_first_name_found && cc_last_name_found;
+
+ // A partial CC expiry date should not be filled. These are often confused
+ // with quantity/height fields and/or generic year fields.
+ bool cc_date_found = cc_month_found && cc_year_found;
+
+ // Count the credit card related fields in the form.
+ size_t num_cc_fields_found =
+ static_cast<int>(cc_name_found) + static_cast<int>(cc_num_found) +
+ static_cast<int>(cc_date_found) + static_cast<int>(cc_type_found) +
+ static_cast<int>(cc_cvc_found);
+
+ // Retain credit card related fields if the form has multiple fields or has
+ // no unrelated fields (useful for single cc-field forms). Credit card number
+ // is permitted to be alone in an otherwise unrelated form because some
+ // dynamic forms reveal the remainder of the fields only after the credit
+ // card number is entered and identified as a credit card by the site.
+ bool keep_cc_fields =
+ cc_num_found || num_cc_fields_found >= 3 || num_other_fields_found == 0;
+
+ // Do an update pass over the fields to rewrite the types if credit card
+ // fields are not to be retained. Some special handling is given to expiry
+ // dates if the full date is not found or multiple expiry date fields are
+ // found. See comments inline below.
+ for (auto it = fields_.begin(); it != fields_.end(); ++it) {
+ auto& field = *it;
+ ServerFieldType current_field_type = field->Type().GetStorableType();
+ switch (current_field_type) {
+ case CREDIT_CARD_NAME_FIRST:
+ if (!keep_cc_fields)
+ field->SetTypeTo(NAME_FIRST);
+ break;
+ case CREDIT_CARD_NAME_LAST:
+ if (!keep_cc_fields)
+ field->SetTypeTo(NAME_LAST);
+ break;
+ case CREDIT_CARD_NAME_FULL:
+ if (!keep_cc_fields)
+ field->SetTypeTo(NAME_FULL);
+ break;
+ case CREDIT_CARD_NUMBER:
+ case CREDIT_CARD_TYPE:
+ case CREDIT_CARD_VERIFICATION_CODE:
+ case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+ if (!keep_cc_fields)
+ field->SetTypeTo(UNKNOWN_TYPE);
+ break;
+ case CREDIT_CARD_EXP_MONTH:
+ // Do not preserve an expiry month prediction if any of the following
+ // are true:
+ // (1) the form is determined to be be non-cc related, so all cc
+ // field predictions are to be discarded
+ // (2) the expiry month was found without a corresponding year
+ // (3) multiple month fields were found in a form having a full
+ // expiry date. This usually means the form is a checkout form
+ // that also has one or more quantity fields. Suppress the expiry
+ // month field(s) not immediately preceding an expiry year field.
+ if (!keep_cc_fields || !cc_date_found) {
+ field->SetTypeTo(UNKNOWN_TYPE);
+ } else if (num_months_found > 1) {
+ auto it2 = it + 1;
+ if (it2 == fields_.end()) {
+ field->SetTypeTo(UNKNOWN_TYPE);
+ } else {
+ ServerFieldType next_field_type = (*it2)->Type().GetStorableType();
+ if (next_field_type != CREDIT_CARD_EXP_2_DIGIT_YEAR &&
+ next_field_type != CREDIT_CARD_EXP_4_DIGIT_YEAR) {
+ field->SetTypeTo(UNKNOWN_TYPE);
+ }
+ }
+ }
+ break;
+ case CREDIT_CARD_EXP_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_4_DIGIT_YEAR:
+ if (!keep_cc_fields || !cc_date_found)
+ field->SetTypeTo(UNKNOWN_TYPE);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
void FormStructure::EncodeFormForQuery(
AutofillQueryContents::Form* query_form) const {
DCHECK(!IsMalformed());
@@ -1100,6 +1243,9 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
field->form_classifier_outcome());
}
+ if (field->username_vote_type())
+ added_field->set_username_vote_type(field->username_vote_type());
+
added_field->set_signature(field->GetFieldSignature());
if (IsAutofillFieldMetadataEnabled()) {
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index c70a23a8c73..a1094eb7d95 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -34,10 +34,6 @@ namespace base {
class TimeTicks;
}
-namespace rappor {
-class RapporServiceImpl;
-}
-
namespace ukm {
class UkmRecorder;
}
@@ -78,10 +74,8 @@ class FormStructure {
// Parses the field types from the server query response. |forms| must be the
// same as the one passed to EncodeQueryRequest when constructing the query.
- // |rappor_service| may be null.
static void ParseQueryResponse(std::string response,
- const std::vector<FormStructure*>& forms,
- rappor::RapporServiceImpl* rappor_service);
+ const std::vector<FormStructure*>& forms);
// Returns predictions using the details from the given |form_structures| and
// their fields' predicted types.
@@ -139,7 +133,6 @@ class FormStructure {
const base::TimeTicks& load_time,
const base::TimeTicks& interaction_time,
const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
bool did_show_suggestions,
bool observed_submission) const;
@@ -231,6 +224,13 @@ class FormStructure {
}
UploadRequired upload_required() const { return upload_required_; }
+ void set_form_parsed_timestamp(const base::TimeTicks form_parsed_timestamp) {
+ form_parsed_timestamp_ = form_parsed_timestamp;
+ }
+ base::TimeTicks form_parsed_timestamp() const {
+ return form_parsed_timestamp_;
+ }
+
bool all_fields_are_passwords() const { return all_fields_are_passwords_; }
bool is_signin_upload() const { return is_signin_upload_; }
@@ -252,6 +252,11 @@ class FormStructure {
FRIEND_TEST_ALL_PREFIXES(AutofillDownloadTest, QueryAndUploadTest);
FRIEND_TEST_ALL_PREFIXES(FormStructureTest, FindLongestCommonPrefix);
+ // A helper function to avoid suggesting field types in cases where they are
+ // highly unlikely. For example: lone credit card fields in an otherwise
+ // non-credit-card related form.
+ void RationalizeFieldTypePredictions();
+
// Encodes information about this form and its fields into |query_form|.
void EncodeFormForQuery(
autofill::AutofillQueryContents::Form* query_form) const;
@@ -345,6 +350,9 @@ class FormStructure {
// the form name, and the form field names in a 64-bit hash.
FormSignature form_signature_;
+ // When a form is parsed on this page.
+ base::TimeTicks form_parsed_timestamp_;
+
DISALLOW_COPY_AND_ASSIGN(FormStructure);
};
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 3a161b5f1cd..ff6cd263868 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -9,11 +9,14 @@
#include <memory>
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#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_experiments.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
@@ -2377,6 +2380,10 @@ TEST_F(FormStructureTest,
form_structure->field(i)->properties_mask =
FieldPropertiesFlags::HAD_FOCUS | FieldPropertiesFlags::USER_TYPED;
}
+ if (form_structure->field(i)->name == ASCIIToUTF16("username")) {
+ form_structure->field(i)->set_username_vote_type(
+ AutofillUploadContents::Field::CREDENTIALS_REUSED);
+ }
}
ServerFieldTypeSet available_field_types;
@@ -2426,6 +2433,8 @@ TEST_F(FormStructureTest,
AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
upload_username_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS |
FieldPropertiesFlags::USER_TYPED);
+ upload_username_field->set_username_vote_type(
+ AutofillUploadContents::Field::CREDENTIALS_REUSED);
AutofillUploadContents::Field* upload_password_field = upload.add_field();
test::FillUploadField(upload_password_field, 2051817934U, "password",
@@ -3766,7 +3775,7 @@ TEST_F(FormStructureTest, ParseQueryResponse) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_GE(forms[0]->field_count(), 2U);
ASSERT_GE(forms[1]->field_count(), 2U);
@@ -3804,7 +3813,7 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- FormStructure::ParseQueryResponse(response_string, forms, nullptr);
+ FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_GE(forms[0]->field_count(), 2U);
// Server type is parsed from the response and is the end result type.
@@ -3816,6 +3825,270 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) {
EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(1)->Type().GetStorableType());
}
+TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) {
+ FormData form;
+ form.origin = GURL("http://foo.com");
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("fullname");
+ field.name = ASCIIToUTF16("fullname");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("address");
+ field.name = ASCIIToUTF16("address");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("height");
+ field.name = ASCIIToUTF16("height");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("email");
+ field.name = ASCIIToUTF16("email");
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ std::vector<FormStructure*> forms;
+ forms.push_back(&form_structure);
+
+ AutofillQueryResponseContents response;
+ response.add_field()->set_autofill_type(NAME_FULL);
+ response.add_field()->set_autofill_type(ADDRESS_HOME_LINE1);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh!
+ response.add_field()->set_autofill_type(EMAIL_ADDRESS);
+
+ std::string response_string;
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ // Test that the expiry month field is rationalized away when enabled.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(4U, forms[0]->field_count());
+ EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(2)->server_type());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->server_type());
+ }
+
+ // Sanity check that the enable/disabled works.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(4U, forms[0]->field_count());
+ EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->server_type());
+ }
+}
+
+TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) {
+ FormData form;
+ form.origin = GURL("http://foo.com");
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("First Name");
+ field.name = ASCIIToUTF16("fname");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Last Name");
+ field.name = ASCIIToUTF16("lname");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("email");
+ field.name = ASCIIToUTF16("email");
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ std::vector<FormStructure*> forms;
+ forms.push_back(&form_structure);
+
+ AutofillQueryResponseContents response;
+ response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FIRST);
+ response.add_field()->set_autofill_type(CREDIT_CARD_NAME_LAST);
+ response.add_field()->set_autofill_type(EMAIL_ADDRESS);
+
+ std::string response_string;
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ // Test that the name fields are rationalized when enabled.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(3U, forms[0]->field_count());
+ EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->server_type());
+ EXPECT_EQ(NAME_LAST, forms[0]->field(1)->server_type());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->server_type());
+ }
+
+ // Sanity check that the enable/disabled works.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(3U, forms[0]->field_count());
+ EXPECT_EQ(CREDIT_CARD_NAME_FIRST, forms[0]->field(0)->server_type());
+ EXPECT_EQ(CREDIT_CARD_NAME_LAST, forms[0]->field(1)->server_type());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->server_type());
+ }
+}
+
+TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) {
+ FormData form;
+ form.origin = GURL("http://foo.com");
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Cardholder");
+ field.name = ASCIIToUTF16("fullname");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("address");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Month)");
+ field.name = ASCIIToUTF16("expiry_month");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Year");
+ field.name = ASCIIToUTF16("expiry_year");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Quantity");
+ field.name = ASCIIToUTF16("quantity");
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ std::vector<FormStructure*> forms;
+ forms.push_back(&form_structure);
+
+ AutofillQueryResponseContents response;
+ response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FULL);
+ response.add_field()->set_autofill_type(CREDIT_CARD_NUMBER);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_2_DIGIT_YEAR);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh!
+
+ std::string response_string;
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ // Test that the extra month field is rationalized away when enabled.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(5U, forms[0]->field_count());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, forms[0]->field(3)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(4)->server_type());
+ }
+
+ // Sanity check that the enable/disabled works.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(5U, forms[0]->field_count());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, forms[0]->field(3)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(4)->server_type());
+ }
+}
+
+TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) {
+ FormData form;
+ form.origin = GURL("http://foo.com");
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Cardholder");
+ field.name = ASCIIToUTF16("fullname");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("address");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Expiry Date (MMYY)");
+ field.name = ASCIIToUTF16("expiry");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Quantity");
+ field.name = ASCIIToUTF16("quantity");
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ std::vector<FormStructure*> forms;
+ forms.push_back(&form_structure);
+
+ AutofillQueryResponseContents response;
+ response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FULL);
+ response.add_field()->set_autofill_type(CREDIT_CARD_NUMBER);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
+ response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh!
+
+ std::string response_string;
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ // Test that the extra month field is rationalized away when enabled.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(4U, forms[0]->field_count());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+ forms[0]->field(2)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(3)->server_type());
+ }
+
+ // Sanity check that the enable/disabled works.
+ {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ autofill::kAutofillRationalizeFieldTypePredictions);
+ FormStructure::ParseQueryResponse(response_string, forms);
+ ASSERT_EQ(1U, forms.size());
+ ASSERT_EQ(4U, forms[0]->field_count());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+ forms[0]->field(2)->server_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(3)->server_type());
+ }
+}
+
TEST_F(FormStructureTest, FindLongestCommonPrefix) {
// Normal case: All strings are longer than threshold; some are common.
std::vector<base::string16> strings;
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc
index 68177a70329..9bc55f4b404 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -19,12 +19,22 @@ namespace payments {
FullCardRequest::FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager)
+ : FullCardRequest(risk_data_loader,
+ payments_client,
+ personal_data_manager,
+ base::TimeTicks()) {}
+
+FullCardRequest::FullCardRequest(RiskDataLoader* risk_data_loader,
+ payments::PaymentsClient* payments_client,
+ PersonalDataManager* personal_data_manager,
+ base::TimeTicks form_parsed_timestamp)
: risk_data_loader_(risk_data_loader),
payments_client_(payments_client),
personal_data_manager_(personal_data_manager),
result_delegate_(nullptr),
ui_delegate_(nullptr),
should_unmask_card_(false),
+ form_parsed_timestamp_(form_parsed_timestamp),
weak_ptr_factory_(this) {
DCHECK(risk_data_loader_);
DCHECK(payments_client_);
@@ -87,7 +97,7 @@ void FullCardRequest::OnUnmaskResponse(const UnmaskResponse& response) {
if (!should_unmask_card_) {
if (result_delegate_)
- result_delegate_->OnFullCardRequestSucceeded(request_->card,
+ result_delegate_->OnFullCardRequestSucceeded(*this, request_->card,
response.cvc);
if (ui_delegate_)
ui_delegate_->OnUnmaskVerificationResult(AutofillClient::SUCCESS);
@@ -152,7 +162,7 @@ void FullCardRequest::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
if (result_delegate_)
result_delegate_->OnFullCardRequestSucceeded(
- request_->card, request_->user_response.cvc);
+ *this, request_->card, request_->user_response.cvc);
Reset();
break;
}
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h
index 9db61fd5ad3..15b0b09d525 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -24,14 +24,16 @@ class PersonalDataManager;
namespace payments {
// Retrieves the full card details, including the pan and the cvc.
-class FullCardRequest : public CardUnmaskDelegate {
+class FullCardRequest final : public CardUnmaskDelegate {
public:
// The interface for receiving the full card details.
class ResultDelegate {
public:
virtual ~ResultDelegate() = default;
- virtual void OnFullCardRequestSucceeded(const CreditCard& card,
- const base::string16& cvc) = 0;
+ virtual void OnFullCardRequestSucceeded(
+ const payments::FullCardRequest& full_card_request,
+ const CreditCard& card,
+ const base::string16& cvc) = 0;
virtual void OnFullCardRequestFailed() = 0;
};
@@ -51,6 +53,10 @@ class FullCardRequest : public CardUnmaskDelegate {
FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager);
+ FullCardRequest(RiskDataLoader* risk_data_loader,
+ payments::PaymentsClient* payments_client,
+ PersonalDataManager* personal_data_manager,
+ base::TimeTicks form_parsed_timestamp);
~FullCardRequest();
// Retrieves the pan and cvc for |card| and invokes
@@ -72,6 +78,11 @@ class FullCardRequest : public CardUnmaskDelegate {
// Called by the payments client when a card has been unmasked.
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan);
+
+ base::TimeTicks form_parsed_timestamp() const {
+ return form_parsed_timestamp_;
+ }
+
private:
// CardUnmaskDelegate:
void OnUnmaskResponse(const UnmaskResponse& response) override;
@@ -108,6 +119,9 @@ class FullCardRequest : public CardUnmaskDelegate {
// histograms.
base::Time real_pan_request_timestamp_;
+ // The timestamp when the form is parsed. For histograms.
+ base::TimeTicks form_parsed_timestamp_;
+
// Enables destroying FullCardRequest while CVC prompt is showing or a server
// communication is pending.
base::WeakPtrFactory<FullCardRequest> weak_ptr_factory_;
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 5d01e9b84e1..9498dc583b3 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -20,7 +20,6 @@
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-
namespace autofill {
namespace payments {
@@ -30,8 +29,10 @@ using testing::_;
class MockResultDelegate : public FullCardRequest::ResultDelegate,
public base::SupportsWeakPtr<MockResultDelegate> {
public:
- MOCK_METHOD2(OnFullCardRequestSucceeded,
- void(const CreditCard&, const base::string16&));
+ MOCK_METHOD3(OnFullCardRequestSucceeded,
+ void(const payments::FullCardRequest&,
+ const CreditCard&,
+ const base::string16&));
MOCK_METHOD0(OnFullCardRequestFailed, void());
};
@@ -139,6 +140,7 @@ MATCHER_P4(CardMatches, record_type, number, month, year, "") {
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCard) {
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -160,7 +162,8 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCard) {
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForLocalCard) {
EXPECT_CALL(
*result_delegate(),
- OnFullCardRequestSucceeded(CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ OnFullCardRequestSucceeded(testing::Ref(*request()),
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(),
@@ -181,6 +184,7 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForLocalCard) {
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForFullServerCard) {
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -204,6 +208,7 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForFullServerCard) {
TEST_F(FullCardRequestTest,
GetFullCardPanAndCvcForFullServerCardInExpiredStatus) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD,
"4111", "12", "2051"),
base::ASCIIToUTF16("123")));
@@ -232,6 +237,7 @@ TEST_F(FullCardRequestTest,
// expiration date in the past.
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForExpiredFullServerCard) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD,
"4111", "12", "2051"),
base::ASCIIToUTF16("123")));
@@ -280,7 +286,8 @@ TEST_F(FullCardRequestTest, SecondRequestOkAfterFirstFinished) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
EXPECT_CALL(
*result_delegate(),
- OnFullCardRequestSucceeded(CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ OnFullCardRequestSucceeded(testing::Ref(*request()),
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
base::ASCIIToUTF16("123")))
.Times(2);
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _)).Times(2);
@@ -382,6 +389,7 @@ TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestFailed()).Times(0);
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -407,6 +415,7 @@ TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
// Verify updating expiration date for a masked server card.
TEST_F(FullCardRequestTest, UpdateExpDateForMaskedServerCard) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD,
"4111", "12", "2050"),
base::ASCIIToUTF16("123")));
@@ -430,6 +439,7 @@ TEST_F(FullCardRequestTest, UpdateExpDateForMaskedServerCard) {
// Verify updating expiration date for an unmasked server card.
TEST_F(FullCardRequestTest, UpdateExpDateForFullServerCard) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD,
"4111", "12", "2050"),
base::ASCIIToUTF16("123")));
@@ -456,6 +466,7 @@ TEST_F(FullCardRequestTest, UpdateExpDateForFullServerCard) {
TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) {
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::LOCAL_CARD, "4111", "12", "2051"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -485,6 +496,7 @@ TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) {
// Verify saving full PAN on disk.
TEST_F(FullCardRequestTest, SaveRealPan) {
EXPECT_CALL(*result_delegate(), OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD,
"4111", "12", "2050"),
base::ASCIIToUTF16("123")));
@@ -513,6 +525,7 @@ TEST_F(FullCardRequestTest, SaveRealPan) {
TEST_F(FullCardRequestTest, UnmaskForPaymentRequest) {
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -535,6 +548,7 @@ TEST_F(FullCardRequestTest, UnmaskForPaymentRequest) {
TEST_F(FullCardRequestTest, IsGettingFullCardForMaskedServerCard) {
EXPECT_CALL(*result_delegate(),
OnFullCardRequestSucceeded(
+ testing::Ref(*request()),
CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
@@ -570,7 +584,8 @@ TEST_F(FullCardRequestTest, IsGettingFullCardForMaskedServerCard) {
TEST_F(FullCardRequestTest, IsGettingFullCardForLocalCard) {
EXPECT_CALL(
*result_delegate(),
- OnFullCardRequestSucceeded(CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ OnFullCardRequestSucceeded(testing::Ref(*request()),
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
base::ASCIIToUTF16("123")));
EXPECT_CALL(*ui_delegate(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*ui_delegate(),
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 683a2f5449f..cb22fc84eb4 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -107,7 +107,7 @@ void AppendStringIfNotEmpty(const AutofillProfile& profile,
const ServerFieldType& type,
const std::string& app_locale,
base::ListValue* list) {
- const base::string16 value = profile.GetInfo(AutofillType(type), app_locale);
+ const base::string16 value = profile.GetInfo(type, app_locale);
if (!value.empty())
list->AppendString(value);
}
@@ -466,7 +466,7 @@ void PaymentsClient::InitializeUrlFetcher() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature in Chromium settings by "
"toggling 'Credit cards and addresses using Google Payments', "
diff --git a/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index f6e48e83064..7dfebb0d533 100644
--- a/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -8,12 +8,12 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/common/autofill_switches.h"
-#include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/gaia/fake_identity_provider.h"
#include "google_apis/gaia/fake_oauth2_token_service.h"
#include "net/url_request/test_url_fetcher_factory.h"
@@ -138,7 +138,7 @@ class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
std::string real_pan_;
std::unique_ptr<base::DictionaryValue> legal_message_;
- content::TestBrowserThreadBundle thread_bundle_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
net::TestURLFetcherFactory factory_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
std::unique_ptr<FakeOAuth2TokenService> token_service_;
@@ -166,18 +166,14 @@ class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
base::StringPiece phone_number) {
AutofillProfile profile;
- profile.SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16(first_name),
+ profile.SetInfo(NAME_FIRST, ASCIIToUTF16(first_name), "en-US");
+ profile.SetInfo(NAME_LAST, ASCIIToUTF16(last_name), "en-US");
+ profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16(address_line), "en-US");
+ profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16(city), "en-US");
+ profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16(state), "en-US");
+ profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16(zip), "en-US");
+ profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16(phone_number),
"en-US");
- profile.SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16(last_name), "en-US");
- profile.SetInfo(AutofillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16(address_line), "en-US");
- profile.SetInfo(AutofillType(ADDRESS_HOME_CITY), ASCIIToUTF16(city),
- "en-US");
- profile.SetInfo(AutofillType(ADDRESS_HOME_STATE), ASCIIToUTF16(state),
- "en-US");
- profile.SetInfo(AutofillType(ADDRESS_HOME_ZIP), ASCIIToUTF16(zip), "en-US");
- profile.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER),
- ASCIIToUTF16(phone_number), "en-US");
return profile;
}
@@ -381,5 +377,5 @@ TEST_F(PaymentsClientTest, OtherError) {
EXPECT_EQ("", real_pan_);
}
-} // namespace autofill
} // namespace payments
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index f8566fa5773..f2af614cd3c 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -881,7 +881,7 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
// If enabled, suppress disused address profiles when triggered from an empty
// field.
- if (field_contents.empty() &&
+ if (field_contents_canon.empty() &&
base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) {
const base::Time min_last_used =
AutofillClock::Now() - kDisusedProfileTimeDelta;
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index 444ba13f4c4..a28c4f24a2f 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -63,7 +63,7 @@ extern const char kFrecencyFieldTrialLimitParam[];
// Autofill.
class PersonalDataManager : public KeyedService,
public WebDataServiceConsumer,
- public AutofillWebDataServiceObserverOnUIThread {
+ public AutofillWebDataServiceObserverOnUISequence {
public:
explicit PersonalDataManager(const std::string& app_locale);
~PersonalDataManager() override;
@@ -87,7 +87,7 @@ class PersonalDataManager : public KeyedService,
WebDataServiceBase::Handle h,
std::unique_ptr<WDTypedResult> result) override;
- // AutofillWebDataServiceObserverOnUIThread:
+ // AutofillWebDataServiceObserverOnUISequence:
void AutofillMultipleChanged() override;
void SyncStarted(syncer::ModelType model_type) override;
@@ -457,7 +457,7 @@ class PersonalDataManager : public KeyedService,
mutable std::vector<CreditCard*> credit_cards_;
// When the manager makes a request from WebDataServiceBase, the database
- // is queried on another thread, we record the query handle until we
+ // is queried on another sequence, we record the query handle until we
// get called back. We store handles for both profile and credit card queries
// so they can be loaded at the same time.
WebDataServiceBase::Handle pending_profiles_query_;
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 990fe2a6b65..3974e1e5678 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -73,7 +73,7 @@ const base::Time kSomeLaterTime = base::Time::FromDoubleT(1000);
const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000);
ACTION(QuitMainMessageLoop) {
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
@@ -156,7 +156,7 @@ class PersonalDataManagerTestBase {
personal_data_->is_autofill_profile_cleanup_pending_ = true;
}
- void SetupReferenceProfile() {
+ void SetUpReferenceProfile() {
ASSERT_EQ(0U, personal_data_->GetProfiles().size());
AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
@@ -206,14 +206,14 @@ class PersonalDataManagerTestBase {
// different: two are from different companies and the third doesn't have a
// number. All three have different owners and credit card number. This allows
// to test the suggestions based on name as well as on credit card number.
- void SetupReferenceLocalCreditCards() {
+ void SetUpReferenceLocalCreditCards() {
ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
credit_card0.set_use_count(3);
credit_card0.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -225,7 +225,7 @@ class PersonalDataManagerTestBase {
credit_card1.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(10));
test::SetCreditCardInfo(&credit_card1, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
personal_data_->AddCreditCard(credit_card1);
CreditCard credit_card2("002149C1-EE28-4213-A3B9-DA243FFF021B",
@@ -234,7 +234,8 @@ class PersonalDataManagerTestBase {
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
test::SetCreditCardInfo(&credit_card2, "Bonnie Parker",
- "518765432109" /* Mastercard */, "12", "2999", "1");
+ "5105105105105100" /* Mastercard */, "12", "2999",
+ "1");
personal_data_->AddCreditCard(credit_card2);
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
@@ -290,6 +291,13 @@ class PersonalDataManagerTestBase {
EXPECT_EQ(0, expected.Compare(*results[0]));
}
+ // Verifies that the web database has been updated and the notification sent.
+ void WaitForOnPersonalDataChanged() {
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .WillOnce(QuitMainMessageLoop());
+ base::RunLoop().Run();
+ }
+
// The temporary directory should be deleted at the end to ensure that
// files are not used anymore and deletion succeeds.
base::ScopedTempDir temp_dir_;
@@ -310,7 +318,7 @@ class PersonalDataManagerTestBase {
class PersonalDataManagerTest : public PersonalDataManagerTestBase,
public testing::Test {
void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
prefs_ = test::PrefServiceForTesting();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
@@ -318,7 +326,7 @@ class PersonalDataManagerTest : public PersonalDataManagerTestBase,
new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
- // Setup account tracker.
+ // Set up account tracker.
signin_client_.reset(new TestSigninClient(prefs_.get()));
account_tracker_.reset(new AccountTrackerService());
account_tracker_->Initialize(signin_client_.get());
@@ -356,7 +364,7 @@ class PersonalDataManagerTest : public PersonalDataManagerTestBase,
account_tracker_.reset();
signin_client_.reset();
- test::DisableSystemServices(prefs_.get());
+ test::ReenableSystemServices();
OSCryptMocker::TearDown();
}
};
@@ -468,10 +476,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
personal_data_->AddProfile(profile0);
personal_data_->AddProfile(profile1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles;
profiles.push_back(&profile0);
@@ -484,10 +489,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
personal_data_->RemoveByGUID(profile1.guid());
personal_data_->AddProfile(profile2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
profiles.clear();
profiles.push_back(&profile0);
@@ -507,25 +509,23 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
EnableWalletCardImport();
CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
- "518765432109" /* Mastercard */, "12", "2999", "1");
+ "5105105105105100" /* Mastercard */, "12", "2999",
+ "1");
CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card2, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
// Add two test credit cards to the database.
personal_data_->AddCreditCard(credit_card0);
personal_data_->AddCreditCard(credit_card1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<CreditCard*> cards;
cards.push_back(&credit_card0);
@@ -538,10 +538,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
personal_data_->RemoveByGUID(credit_card1.guid());
personal_data_->AddCreditCard(credit_card2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
cards.clear();
cards.push_back(&credit_card0);
@@ -566,10 +563,12 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
credit_card3.set_record_type(CreditCard::FULL_SERVER_CARD);
credit_card3.set_server_id("server_id");
+ // Verify that the web database has been updated and the notification sent.
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
personal_data_->AddFullServerCreditCard(credit_card3);
+
base::RunLoop().Run();
cards.push_back(&credit_card3);
@@ -602,7 +601,7 @@ TEST_F(PersonalDataManagerTest, AddCreditCard_BasicInformation) {
// Add a credit card to the database.
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
personal_data_->AddCreditCard(credit_card);
// Reload the database.
@@ -630,17 +629,14 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) {
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
EXPECT_FALSE(credit_card.IsVerified());
// Add the data to the database.
personal_data_->AddProfile(profile);
personal_data_->AddCreditCard(credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& profiles1 =
personal_data_->GetProfiles();
@@ -681,10 +677,7 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) {
personal_data_->UpdateProfile(profile);
personal_data_->UpdateCreditCard(credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& profiles3 =
personal_data_->GetProfiles();
@@ -712,14 +705,12 @@ TEST_F(PersonalDataManagerTest, RefuseToStoreFullCard) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
EXPECT_EQ(CreditCard::MASKED_SERVER_CARD,
@@ -741,9 +732,10 @@ TEST_F(PersonalDataManagerTest, AddFullCardAsMaskedCard) {
CreditCard server_card(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&server_card, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
+ // Verify that the web database has been updated and the notification sent.
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
@@ -773,25 +765,23 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "9012" /* Visa */, "01", "2999", "1");
+ "3456" /* Visa */, "01", "2999", "1");
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456"));
test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker",
- "2109" /* Mastercard */, "12", "2999", "1");
+ "5100" /* Mastercard */, "12", "2999", "1");
server_cards.back().SetNetworkForMaskedCard(kMasterCard);
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
@@ -810,28 +800,24 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCards) {
CreditCard* unmasked_card = &server_cards.front();
unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasked_card->SetNumber(base::ASCIIToUTF16("423456789012"));
+ unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456"));
EXPECT_NE(0, server_cards.front().Compare(
*personal_data_->GetCreditCards().front()));
personal_data_->UpdateServerCreditCard(*unmasked_card);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
for (size_t i = 0; i < 3; ++i)
EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
CreditCard* remasked_card = &server_cards.back();
remasked_card->set_record_type(CreditCard::MASKED_SERVER_CARD);
- remasked_card->SetNumber(base::ASCIIToUTF16("8555"));
+ remasked_card->SetNumber(base::ASCIIToUTF16("0005"));
EXPECT_NE(
0, server_cards.back().Compare(*personal_data_->GetCreditCards().back()));
personal_data_->UpdateServerCreditCard(*remasked_card);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
for (size_t i = 0; i < 3; ++i)
EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
@@ -842,16 +828,14 @@ TEST_F(PersonalDataManagerTest, SavesServerCardType) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "9012" /* Visa */, "01", "2999", "1");
+ "3456" /* Visa */, "01", "2999", "1");
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
server_cards.back().set_card_type(CreditCard::CARD_TYPE_DEBIT);
test::SetServerCreditCards(autofill_table_, server_cards);
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
auto cards = personal_data_->GetCreditCards();
ASSERT_EQ(1U, cards.size());
@@ -873,20 +857,18 @@ TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
- "518765432109" /* Mastercard */, "12", "2999", "1");
+ "5105105105105100" /* Mastercard */, "12", "2999",
+ "1");
// Add two test profiles to the database.
personal_data_->AddProfile(profile0);
personal_data_->AddProfile(profile1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles;
profiles.push_back(&profile0);
@@ -897,10 +879,7 @@ TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
personal_data_->AddCreditCard(credit_card0);
personal_data_->AddCreditCard(credit_card1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<CreditCard*> cards;
cards.push_back(&credit_card0);
@@ -927,10 +906,7 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
// Add the profile0 to the db.
personal_data_->AddProfile(profile0);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Verify that we've loaded the profiles from the web database.
const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -943,10 +919,7 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
"z", "", "", "", "", "", "", "", "", "", "", "");
personal_data_->AddProfile(profile1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Make sure the two profiles have different GUIDs, both valid.
const std::vector<AutofillProfile*>& results3 = personal_data_->GetProfiles();
@@ -1009,8 +982,7 @@ TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
ResetPersonalDataManager(USER_MODE_NORMAL);
// Verify that we've loaded the profiles from the web database.
- const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
- ASSERT_EQ(0U, results2.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
}
TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
@@ -1028,8 +1000,7 @@ TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
ResetPersonalDataManager(USER_MODE_NORMAL);
// Verify that we've loaded the credit cards from the web database.
- const std::vector<CreditCard*>& results2 = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, results2.size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
TEST_F(PersonalDataManagerTest, Refresh) {
@@ -1049,10 +1020,7 @@ TEST_F(PersonalDataManagerTest, Refresh) {
personal_data_->AddProfile(profile0);
personal_data_->AddProfile(profile1);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles;
profiles.push_back(&profile0);
@@ -1069,10 +1037,7 @@ TEST_F(PersonalDataManagerTest, Refresh) {
personal_data_->Refresh();
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
profiles.clear();
profiles.push_back(&profile0);
@@ -1094,10 +1059,7 @@ TEST_F(PersonalDataManagerTest, Refresh) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(1U, results.size());
@@ -1131,10 +1093,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles) {
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1169,8 +1128,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_BadEmail) {
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
- ASSERT_EQ(0U, results.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
}
// Tests that a 'confirm email' field does not block profile import.
@@ -1198,8 +1156,10 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
- ASSERT_EQ(1U, results.size());
+
+ WaitForOnPersonalDataChanged();
+
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
}
// Tests two email fields containing different values blocks profile import.
@@ -1227,8 +1187,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
- ASSERT_EQ(0U, results.size());
+
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
}
// Tests that not enough filled fields will result in not importing an address.
@@ -1248,10 +1208,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_NotEnoughFilledFields) {
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(0U, profiles.size());
- const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, cards.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressUSA) {
@@ -1275,8 +1233,10 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressUSA) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
+
+ WaitForOnPersonalDataChanged();
+
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
}
TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGB) {
@@ -1300,8 +1260,10 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGB) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
+
+ WaitForOnPersonalDataChanged();
+
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
}
TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGI) {
@@ -1320,8 +1282,10 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGI) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
+
+ WaitForOnPersonalDataChanged();
+
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
}
TEST_F(PersonalDataManagerTest,
@@ -1359,10 +1323,7 @@ TEST_F(PersonalDataManagerTest,
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1403,10 +1364,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MultilineAddress) {
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1444,10 +1402,7 @@ TEST_F(PersonalDataManagerTest,
form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1482,10 +1437,7 @@ TEST_F(PersonalDataManagerTest,
form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected2, "John", NULL,
@@ -1543,10 +1495,7 @@ TEST_F(PersonalDataManagerTest,
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL, "Washington",
@@ -1598,12 +1547,10 @@ TEST_F(PersonalDataManagerTest,
test::CreateTestFormField("Last name:", "last_name", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
- test::CreateTestFormField("Email:", "email", "", "text",
- &field);
+ test::CreateTestFormField("Email:", "email", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
- test::CreateTestFormField("Address:", "address1", "", "text",
- &field);
+ test::CreateTestFormField("Address:", "address1", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
test::CreateTestFormField("City:", "city", "", "text", &field);
@@ -1621,10 +1568,7 @@ TEST_F(PersonalDataManagerTest,
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL, "Washington",
@@ -1705,10 +1649,7 @@ TEST_F(PersonalDataManagerTest,
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Only two are saved.
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
@@ -1760,10 +1701,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -1808,10 +1746,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -1847,10 +1782,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1885,10 +1817,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -1930,10 +1859,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", NULL,
@@ -1969,10 +1895,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -2011,10 +1934,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_InsufficientAddress) {
// sure no changes were written out.
ResetPersonalDataManager(USER_MODE_NORMAL);
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(0U, profiles.size());
- const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, cards.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
// Ensure that if a verified profile already exists, aggregated profiles cannot
@@ -2033,10 +1954,7 @@ TEST_F(PersonalDataManagerTest,
// Add the profile to the database.
personal_data_->AddProfile(profile);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Simulate a form submission with conflicting info.
FormData form;
@@ -2065,9 +1983,7 @@ TEST_F(PersonalDataManagerTest,
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Wait for the refresh, which in this case is a no-op.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that no new profile is saved.
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
@@ -2086,9 +2002,7 @@ TEST_F(PersonalDataManagerTest,
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Wait for the refresh, which in this case is a no-op.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that no new profile is saved.
const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -2130,10 +2044,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_UnrecognizedCountry) {
// sure no changes were written out.
ResetPersonalDataManager(USER_MODE_NORMAL);
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(0U, profiles.size());
- const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, cards.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
// Tests that a profile is created for countries with composed names.
@@ -2167,10 +2079,7 @@ TEST_F(PersonalDataManagerTest,
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
@@ -2220,10 +2129,8 @@ TEST_F(PersonalDataManagerTest,
// sure no changes were written out.
ResetPersonalDataManager(USER_MODE_NORMAL);
- const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
- ASSERT_EQ(0U, profiles.size());
- const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, cards.size());
+ ASSERT_EQ(0U, personal_data_->GetProfiles().size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
// ImportCreditCard tests.
@@ -2246,14 +2153,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Valid) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
- "2999", ""); // Imported cards have not billing info.
+ "2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2278,8 +2182,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Invalid) {
// sure no changes were written out.
ResetPersonalDataManager(USER_MODE_NORMAL);
- const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
- ASSERT_EQ(0U, results.size());
+ ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
}
// Tests that a valid credit card is extracted when the option text for month
@@ -2313,15 +2216,12 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MonthSelectInvalidText) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// See that the invalid option text was converted to the right value.
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "02",
- "2999", ""); // Imported cards have not billing info.
+ "2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2344,14 +2244,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
- "2999", ""); // Imported cards have not billing info.
+ "2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2370,14 +2267,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected2, "", "5500000000000004", "02", "2999",
- ""); // Imported cards have not billing info.
+ ""); // Imported cards have no billing info.
std::vector<CreditCard*> cards;
cards.push_back(&expected);
cards.push_back(&expected2);
@@ -2460,10 +2354,56 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_2DigitYear) {
"4111111111111111", "05", "2045");
}
-// Tests that a credit card is extracted because it only matches a masked server
-// card.
+// Tests that a credit card is not extracted because the
+// kAutofillOfferLocalSaveIfServerCardManuallyEntered feature flag is off even
+// though the card matches a masked server card.
+TEST_F(PersonalDataManagerTest,
+ ImportCreditCard_DuplicateServerCards_MaskedCard_ExperimentOff) {
+ // Ensure feature flag is off.
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndDisableFeature(
+ kAutofillOfferLocalSaveIfServerCardManuallyEntered);
+
+ // Add a masked server card.
+ std::vector<CreditCard> server_cards;
+ server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
+ test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
+ "1111" /* Visa */, "01", "2999", "");
+ server_cards.back().SetNetworkForMaskedCard(kVisaCard);
+ test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
+
+ // Type the same data as the masked card into a form.
+ FormData form;
+ AddFullCreditCardForm(&form, "John Dillinger", "4111111111111111", "01",
+ "2999");
+
+ // The card should not be offered to be saved locally because the feature flag
+ // is disabled.
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
+ std::unique_ptr<CreditCard> imported_credit_card;
+ bool imported_credit_card_matches_masked_server_credit_card;
+ EXPECT_FALSE(ImportCreditCard(
+ form_structure, false, &imported_credit_card,
+ &imported_credit_card_matches_masked_server_credit_card));
+ ASSERT_FALSE(imported_credit_card);
+}
+
+// Tests that a credit card is extracted because it matches a masked server card
+// and the kAutofillOfferLocalSaveIfServerCardManuallyEntered feature flag is
+// enabled.
TEST_F(PersonalDataManagerTest,
- ImportCreditCard_DuplicateServerCards_MaskedCard) {
+ ImportCreditCard_DuplicateServerCards_MaskedCard_ExperimentOn) {
+ // Enable feature flag.
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(
+ kAutofillOfferLocalSaveIfServerCardManuallyEntered);
+
// Add a masked server card.
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
@@ -2472,12 +2412,17 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
test::SetServerCreditCards(autofill_table_, server_cards);
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
+
// Type the same data as the masked card into a form.
FormData form;
AddFullCreditCardForm(&form, "John Dillinger", "4111111111111111", "01",
"2999");
- // The card should be offered to be saved locally because it only matches the
+ // The card should be offered to be saved locally because it matches the
// masked server card.
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
@@ -2487,13 +2432,10 @@ TEST_F(PersonalDataManagerTest,
form_structure, false, &imported_credit_card,
&imported_credit_card_matches_masked_server_credit_card));
ASSERT_TRUE(imported_credit_card);
- EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
+ EXPECT_TRUE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
}
// Tests that a credit card is not extracted because it matches a full server
@@ -2504,13 +2446,18 @@ TEST_F(PersonalDataManagerTest,
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- ""); // Imported cards have not billing info.
+ "378282246310005" /* American Express */, "04",
+ "2999", ""); // Imported cards have no billing info.
test::SetServerCreditCards(autofill_table_, server_cards);
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
+
// Type the same data as the unmasked card into a form.
FormData form;
- AddFullCreditCardForm(&form, "Clyde Barrow", "347666888555", "04", "2999");
+ AddFullCreditCardForm(&form, "Clyde Barrow", "378282246310005", "04", "2999");
// The card should not be offered to be saved locally because it only matches
// the full server card.
@@ -2541,14 +2488,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
- "2998", ""); // Imported cards have not billing info.
+ "2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2567,16 +2511,13 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
&imported_credit_card_matches_masked_server_credit_card));
EXPECT_FALSE(imported_credit_card2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that the newer information is saved. In this case the year is
// updated to "2999".
CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
- "2999", ""); // Imported cards have not billing info.
+ "2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results2 = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results2.size());
EXPECT_EQ(0, expected2.Compare(*results2[0]));
@@ -2599,14 +2540,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
- "2998", ""); // Imported cards have not billing info.
+ "2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2628,16 +2566,13 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
EXPECT_TRUE(imported_credit_card2);
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that the newer information is saved. In this case the year is
// updated to "2999".
CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
- "2999", ""); // Imported cards have not billing info.
+ "2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results2 = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results2.size());
EXPECT_EQ(0, expected2.Compare(*results2[0]));
@@ -2660,14 +2595,11 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_EmptyCardWithConflict) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
- "2998", ""); // Imported cards have not billing info.
+ "2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results.size());
EXPECT_EQ(0, expected.Compare(*results[0]));
@@ -2715,10 +2647,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
@@ -2788,10 +2717,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInOld) {
"01", "2998", "1");
personal_data_->AddCreditCard(saved_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<CreditCard*>& results1 = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results1.size());
@@ -2812,10 +2738,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInOld) {
&imported_credit_card_matches_masked_server_credit_card));
EXPECT_FALSE(imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that the newer information is saved. In this case the year is
// added to the existing credit card.
@@ -2837,10 +2760,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCardWithSeparators) {
"4111 1111 1111 1111" /* Visa */, "01", "2999", "");
personal_data_->AddCreditCard(saved_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<CreditCard*>& results1 = personal_data_->GetCreditCards();
ASSERT_EQ(1U, results1.size());
@@ -2883,10 +2803,10 @@ TEST_F(PersonalDataManagerTest,
// Add the credit card to the database.
personal_data_->AddCreditCard(credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// Simulate a form submission with conflicting expiration year.
FormData form;
@@ -2954,10 +2874,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_OneAddressOneCreditCard) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Test that the address has been saved.
AutofillProfile expected_address(base::GenerateGUID(),
@@ -3036,10 +2953,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_TwoAddressesOneCreditCard) {
EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Test that both addresses have been saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -3067,10 +2981,9 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) {
// Add the profile to the database.
personal_data_->AddProfile(profile);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetProfiles().size());
AutofillProfile new_verified_profile = profile;
new_verified_profile.set_guid(base::GenerateGUID());
@@ -3081,10 +2994,7 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) {
personal_data_->SaveImportedProfile(new_verified_profile);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The new profile should be merged into the existing one.
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
@@ -3109,10 +3019,9 @@ TEST_F(PersonalDataManagerTest, SaveImportedCreditCardWithVerifiedData) {
// Add the credit card to the database.
personal_data_->AddCreditCard(credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
CreditCard new_verified_card = credit_card;
new_verified_card.set_guid(base::GenerateGUID());
@@ -3122,10 +3031,7 @@ TEST_F(PersonalDataManagerTest, SaveImportedCreditCardWithVerifiedData) {
personal_data_->SaveImportedCreditCard(new_verified_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Expect that the saved credit card is updated.
const std::vector<CreditCard*>& results = personal_data_->GetCreditCards();
@@ -3149,10 +3055,9 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
personal_data_->AddProfile(profile0);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetProfiles().size());
personal_data_->GetNonEmptyTypes(&non_empty_types);
EXPECT_EQ(15U, non_empty_types.size());
@@ -3188,10 +3093,8 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
personal_data_->GetNonEmptyTypes(&non_empty_types);
EXPECT_EQ(19U, non_empty_types.size());
@@ -3218,13 +3121,11 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
// Test with credit card information also stored.
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "");
+ "4234567890123456" /* Visa */, "01", "2999", "");
personal_data_->AddCreditCard(credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
personal_data_->GetNonEmptyTypes(&non_empty_types);
EXPECT_EQ(29U, non_empty_types.size());
@@ -3345,9 +3246,11 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) {
"", "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2",
"CA", "(800) 555-9000");
personal_data_->AddProfile(moose);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetProfiles().size());
+
// The value is cached and doesn't change even after adding an address.
EXPECT_EQ(default_country,
personal_data_->GetDefaultCountryCodeForNewAddress());
@@ -3429,16 +3332,15 @@ TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) {
"91601", "US", "12345678910");
personal_data_->AddProfile(profile);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->web_profiles().size());
+ EXPECT_EQ(1U, personal_data_->GetProfiles().size());
profile.set_language_code("en");
personal_data_->UpdateProfile(profile);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(1U, results.size());
@@ -3672,6 +3574,14 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(1U, suggestions.size());
}
+ // Query with non-alpha-numeric string only returns profile2.
+ {
+ std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
+ AutofillType(ADDRESS_HOME_STREET_ADDRESS), base::ASCIIToUTF16("--"),
+ false, std::vector<ServerFieldType>());
+ EXPECT_EQ(1U, suggestions.size());
+ }
+
// Query with prefix for profile1 returns profile1.
{
std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
@@ -3709,10 +3619,11 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(AutofillType(CREDIT_CARD_NUMBER),
@@ -3724,7 +3635,7 @@ TEST_F(PersonalDataManagerTest,
// Test that local credit cards are ordered as expected.
TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_LocalCardsRanking) {
- SetupReferenceLocalCreditCards();
+ SetUpReferenceLocalCreditCards();
// Sublabel is card number when filling name (exact format depends on
// the platform, but the last 4 digits should appear).
@@ -3736,13 +3647,13 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_LocalCardsRanking) {
// Ordered as expected.
EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[0].value);
- EXPECT_TRUE(suggestions[0].label.find(base::ASCIIToUTF16("9012")) !=
+ EXPECT_TRUE(suggestions[0].label.find(base::ASCIIToUTF16("3456")) !=
base::string16::npos);
EXPECT_EQ(base::ASCIIToUTF16("Clyde Barrow"), suggestions[1].value);
- EXPECT_TRUE(suggestions[1].label.find(base::ASCIIToUTF16("8555")) !=
+ EXPECT_TRUE(suggestions[1].label.find(base::ASCIIToUTF16("0005")) !=
base::string16::npos);
EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[2].value);
- EXPECT_TRUE(suggestions[2].label.find(base::ASCIIToUTF16("2109")) !=
+ EXPECT_TRUE(suggestions[2].label.find(base::ASCIIToUTF16("5100")) !=
base::string16::npos);
}
@@ -3750,7 +3661,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_LocalCardsRanking) {
TEST_F(PersonalDataManagerTest,
GetCreditCardSuggestions_LocalAndServerCardsRanking) {
EnableWalletCardImport();
- SetupReferenceLocalCreditCards();
+ SetUpReferenceLocalCreditCards();
// Add some server cards.
std::vector<CreditCard> server_cards;
@@ -3770,10 +3681,11 @@ TEST_F(PersonalDataManagerTest,
base::TimeDelta::FromDays(1));
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(5U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
@@ -3798,15 +3710,16 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B",
"https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "Bonnie Parker",
- "518765432109" /* Mastercard */, "04", "2999", "1");
+ "5105105105105100" /* Mastercard */, "04", "2999",
+ "1");
personal_data_->AddCreditCard(credit_card0);
// Add an expired card with a higher frecency score.
CreditCard credit_card1("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "1999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "1999", "1");
credit_card1.set_use_count(300);
credit_card1.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(10));
@@ -3819,13 +3732,11 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
- "423456789012" /* Visa */, "01", "1998", "1");
+ "4234567890123456" /* Visa */, "01", "1998", "1");
personal_data_->AddCreditCard(credit_card2);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
-
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
@@ -3851,8 +3762,8 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
credit_card0.set_use_count(3);
credit_card0.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -3867,10 +3778,8 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
"1");
personal_data_->AddCreditCard(credit_card1);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
-
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(2U, personal_data_->GetCreditCards().size());
// Sublabel is expiration date when filling card number. The second card
@@ -3881,7 +3790,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
/* field_contents= */ base::string16());
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "8555"),
+ base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
suggestions[0].value);
EXPECT_EQ(base::ASCIIToUTF16("04/99"), suggestions[0].label);
}
@@ -3889,7 +3798,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
// Tests the suggestions of duplicate local and server credit cards.
TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
EnableWalletCardImport();
- SetupReferenceLocalCreditCards();
+ SetUpReferenceLocalCreditCards();
// Add some server cards. If there are local dupes, the locals should be
// hidden.
@@ -3899,7 +3808,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
// suggestions since the locally saved card takes precedence.
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "9012" /* Visa */, "01", "2999", "1");
+ "3456" /* Visa */, "01", "2999", "1");
server_cards.back().set_use_count(2);
server_cards.back().set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
@@ -3908,7 +3817,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
// This server card is identical to a local card, but has a different
// card type. Not a dupe and therefore both should appear in the suggestions.
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456"));
- test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker", "2109", "12",
+ test::SetCreditCardInfo(&server_cards.back(), "Bonnie Parker", "5100", "12",
"2999", "1");
server_cards.back().set_use_count(3);
server_cards.back().set_use_date(AutofillClock::Now() -
@@ -3920,17 +3829,18 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
// precedence over local cards.
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
server_cards.back().set_use_count(1);
server_cards.back().set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(6U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
@@ -3946,16 +3856,16 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
AutofillType(CREDIT_CARD_NUMBER), /* field_contents= */ base::string16());
ASSERT_EQ(4U, suggestions.size());
EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "9012"),
+ base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "3456"),
suggestions[0].value);
EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "8555"),
+ base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
suggestions[1].value);
EXPECT_EQ(base::UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis +
- "2109"),
+ "5100"),
suggestions[2].value);
EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "2109"),
+ base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "5100"),
suggestions[3].value);
}
@@ -3963,7 +3873,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
TEST_F(PersonalDataManagerTest,
GetCreditCardSuggestions_ServerCardDuplicateOfMultipleLocalCards) {
EnableWalletCardImport();
- SetupReferenceLocalCreditCards();
+ SetUpReferenceLocalCreditCards();
// Add a duplicate server card.
std::vector<CreditCard> server_cards;
@@ -3971,14 +3881,15 @@ TEST_F(PersonalDataManagerTest,
// the local card should appear in the suggestions.
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(4U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
@@ -3993,9 +3904,7 @@ TEST_F(PersonalDataManagerTest,
test::SetCreditCardInfo(&credit_card3, "Clyde Barrow", "", "04", "", "");
personal_data_->AddCreditCard(credit_card3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
suggestions = personal_data_->GetCreditCardSuggestions(
AutofillType(CREDIT_CARD_NAME_FULL),
@@ -4003,7 +3912,7 @@ TEST_F(PersonalDataManagerTest,
ASSERT_EQ(3U, suggestions.size());
}
-// Tests that server cards will shown bank name when bank name available and
+// Tests that server cards will show bank name when bank name is available and
// feature flag on.
TEST_F(PersonalDataManagerTest,
GetCreditCardSuggestions_ShowBankNameOfServerCards) {
@@ -4017,8 +3926,8 @@ TEST_F(PersonalDataManagerTest,
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
credit_card0.set_use_count(3);
credit_card0.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -4047,9 +3956,10 @@ TEST_F(PersonalDataManagerTest,
test::SetServerCreditCards(autofill_table_, server_cards);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
std::vector<Suggestion> suggestions =
personal_data_->GetCreditCardSuggestions(
@@ -4059,7 +3969,7 @@ TEST_F(PersonalDataManagerTest,
// Local cards will show network.
EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "8555"),
+ base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
suggestions[0].value);
// Server card without bank name will show network.
EXPECT_EQ(
@@ -4081,7 +3991,7 @@ TEST_F(PersonalDataManagerTest,
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&local_card, "Homer Simpson",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
local_card.set_use_count(3);
local_card.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
credit_cards.push_back(&local_card);
@@ -4089,7 +3999,7 @@ TEST_F(PersonalDataManagerTest,
// Create a full server card that is a duplicate of one of the local cards.
CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&full_server_card, "Homer Simpson",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
full_server_card.set_use_count(1);
full_server_card.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
@@ -4112,12 +4022,12 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_LocalShadowsMasked) {
local_card.set_use_count(300);
local_card.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(10));
test::SetCreditCardInfo(&local_card, "Homer Simpson",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
credit_cards.push_back(&local_card);
// Create a masked server card that is a duplicate of a local card.
CreditCard masked_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&masked_card, "Homer Simpson", "9012" /* Visa */,
+ test::SetCreditCardInfo(&masked_card, "Homer Simpson", "3456" /* Visa */,
"01", "2999", "1");
masked_card.set_use_count(2);
masked_card.set_use_date(AutofillClock::Now() -
@@ -4139,7 +4049,7 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_FullServerAndMasked) {
// Create a full server card that is a duplicate of one of the local cards.
CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&full_server_card, "Homer Simpson",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
full_server_card.set_use_count(1);
full_server_card.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
@@ -4147,7 +4057,7 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_FullServerAndMasked) {
// Create a masked server card that is a duplicate of a local card.
CreditCard masked_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&masked_card, "Homer Simpson", "9012" /* Visa */,
+ test::SetCreditCardInfo(&masked_card, "Homer Simpson", "3456" /* Visa */,
"01", "2999", "1");
masked_card.set_use_count(2);
masked_card.set_use_date(AutofillClock::Now() -
@@ -4170,12 +4080,12 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_DifferentCards) {
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
test::SetCreditCardInfo(&credit_card2, "Homer Simpson",
- "518765432109" /* Mastercard */, "", "", "");
+ "5105105105105100" /* Mastercard */, "", "", "");
credit_cards.push_back(&credit_card2);
// Create a masked server card that is slightly different of the local card.
CreditCard credit_card4(CreditCard::MASKED_SERVER_CARD, "b456");
- test::SetCreditCardInfo(&credit_card4, "Homer Simpson", "2109", "12", "2999",
+ test::SetCreditCardInfo(&credit_card4, "Homer Simpson", "5100", "12", "2999",
"1");
credit_card4.set_use_count(3);
credit_card4.set_use_date(AutofillClock::Now() -
@@ -4187,8 +4097,8 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_DifferentCards) {
// cards.
CreditCard credit_card5(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&credit_card5, "Homer Simpson",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
credit_card5.set_use_count(1);
credit_card5.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
@@ -4211,15 +4121,15 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
EXPECT_EQ(1U, credit_card.use_count());
EXPECT_EQ(kArbitraryTime, credit_card.use_date());
EXPECT_EQ(kArbitraryTime, credit_card.modification_date());
personal_data_->AddCreditCard(credit_card);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ // Make sure everything is set up correctly.
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// Set the current time to another value.
test_clock.SetNow(kSomeLaterTime);
@@ -4243,9 +4153,7 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
EXPECT_EQ(kArbitraryTime, added_card->modification_date());
personal_data_->RecordUseOf(credit_card);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Verify usage stats are updated.
added_profile = personal_data_->GetProfileByGUID(profile.guid());
@@ -4267,7 +4175,7 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "9012" /* Visa */, "01", "2999", "1");
+ "3456" /* Visa */, "01", "2999", "1");
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b456"));
@@ -4277,21 +4185,19 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
// Create the test clock and set the time to a specific value.
TestAutofillClock test_clock;
test_clock.SetNow(kArbitraryTime);
test::SetServerCreditCards(autofill_table_, server_cards);
- personal_data_->Refresh();
-
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
+ // Make sure everything is set up correctly.
+ personal_data_->Refresh();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
if (!OfferStoreUnmaskedCards()) {
for (CreditCard* card : personal_data_->GetCreditCards()) {
@@ -4308,14 +4214,12 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
CreditCard* unmasked_card = &server_cards.front();
unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD);
- unmasked_card->SetNumber(base::ASCIIToUTF16("423456789012"));
+ unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456"));
EXPECT_NE(0, unmasked_card->Compare(
*personal_data_->GetCreditCards().front()));
personal_data_->UpdateServerCreditCard(*unmasked_card);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
for (size_t i = 0; i < 3; ++i)
@@ -4340,11 +4244,9 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
server_cards.back().set_guid(personal_data_->GetCreditCards()[2]->guid());
personal_data_->RecordUseOf(server_cards.back());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
- ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards()[0]->use_count());
EXPECT_EQ(kArbitraryTime, personal_data_->GetCreditCards()[0]->use_date());
@@ -4359,9 +4261,8 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
// Can record usage stats on masked cards.
server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid());
personal_data_->RecordUseOf(server_cards[1]);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards()[1]->use_count());
EXPECT_EQ(kSomeLaterTime, personal_data_->GetCreditCards()[1]->use_date());
@@ -4377,9 +4278,8 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) {
server_cards[1].set_guid(personal_data_->GetCreditCards()[1]->guid());
personal_data_->RecordUseOf(server_cards[1]);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
EXPECT_EQ(3U, personal_data_->GetCreditCards()[1]->use_count());
EXPECT_EQ(kMuchLaterTime, personal_data_->GetCreditCards()[1]->use_date());
@@ -4390,7 +4290,7 @@ TEST_F(PersonalDataManagerTest, ClearAllServerData) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
- "9012" /* Visa */, "01", "2999", "1");
+ "3456" /* Visa */, "01", "2999", "1");
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
test::SetServerCreditCards(autofill_table_, server_cards);
personal_data_->Refresh();
@@ -4424,14 +4324,15 @@ TEST_F(PersonalDataManagerTest, AllowDuplicateMaskedServerCardIfFlagEnabled) {
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "");
+ "378282246310005" /* American Express */, "04",
+ "2999", "");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
// A valid credit card form. A user re-enters one of their masked cards.
// We should offer to save locally so that user can fill future credit card
@@ -4460,10 +4361,7 @@ TEST_F(PersonalDataManagerTest, AllowDuplicateMaskedServerCardIfFlagEnabled) {
EXPECT_TRUE(imported_credit_card_matches_masked_server_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
- // Verify that the web database has been updated and the notification sent.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
CreditCard local_card(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&local_card, "John Dillinger", "4012888888881881",
@@ -4486,14 +4384,15 @@ TEST_F(PersonalDataManagerTest, DontDuplicateMaskedServerCard) {
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "");
+ "378282246310005" /* American Express */, "04",
+ "2999", "");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
// A valid credit card form. A user re-enters one of their masked cards.
// We should not offer to save locally because the
@@ -4533,14 +4432,15 @@ TEST_F(PersonalDataManagerTest, DontDuplicateFullServerCard) {
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
// A user re-types (or fills with) an unmasked card. Don't offer to save
// here, either. Since it's unmasked, we know for certain that it's the same
@@ -4550,7 +4450,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateFullServerCard) {
test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow",
"text", &field);
form.fields.push_back(field);
- test::CreateTestFormField("Card Number:", "card_number", "347666888555",
+ test::CreateTestFormField("Card Number:", "card_number", "378282246310005",
"text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Exp Month:", "exp_month", "04", "text", &field);
@@ -4579,10 +4479,11 @@ TEST_F(PersonalDataManagerTest,
"4444333322221111" /* Visa */, "04", "2111", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// A user fills/enters the card's information on a checkout form. Ensure that
// an expiration date match is recorded.
@@ -4624,10 +4525,11 @@ TEST_F(PersonalDataManagerTest,
"4444333322221111" /* Visa */, "04", "2111", "1");
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// A user fills/enters the card's information on a checkout form but changes
// the expiration date of the card. Ensure that an expiration date mismatch
@@ -4671,10 +4573,11 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// A user fills/enters the card's information on a checkout form. Ensure that
// an expiration date match is recorded.
@@ -4717,10 +4620,11 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().SetNetworkForMaskedCard(kVisaCard);
test::SetServerCreditCards(autofill_table_, server_cards);
+
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// A user fills/enters the card's information on a checkout form but changes
// the expiration date of the card. Ensure that an expiration date mismatch
@@ -4782,7 +4686,7 @@ class SaveImportedProfileTest
~SaveImportedProfileTest() override {}
void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
prefs_ = test::PrefServiceForTesting();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
@@ -4790,7 +4694,7 @@ class SaveImportedProfileTest
new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
- // Setup account tracker.
+ // Set up account tracker.
signin_client_.reset(new TestSigninClient(prefs_.get()));
account_tracker_.reset(new AccountTrackerService());
account_tracker_->Initialize(signin_client_.get());
@@ -4840,7 +4744,7 @@ TEST_P(SaveImportedProfileTest, SaveImportedProfile) {
// Set the time to a specific value.
test_clock.SetNow(kArbitraryTime);
- SetupReferenceProfile();
+ SetUpReferenceProfile();
const std::vector<AutofillProfile*>& initial_profiles =
personal_data_->GetProfiles();
@@ -5539,18 +5443,19 @@ TEST_F(PersonalDataManagerTest,
// verifying results.
CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
credit_card1.set_use_count(10);
CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
- "423456789012" /* Visa */, "01", "2999", "1");
+ "4234567890123456" /* Visa */, "01", "2999", "1");
credit_card2.set_use_count(5);
CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&credit_card3, "Bonnie Parker",
- "518765432109" /* Mastercard */, "12", "2999", "1");
+ "5105105105105100" /* Mastercard */, "12", "2999",
+ "1");
credit_card3.set_use_count(1);
// Associate the first card with profile1.
@@ -5569,9 +5474,8 @@ TEST_F(PersonalDataManagerTest,
personal_data_->AddCreditCard(credit_card1);
personal_data_->AddCreditCard(credit_card2);
personal_data_->AddCreditCard(credit_card3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 6 profiles and 3 credit cards were saved.
EXPECT_EQ(6U, personal_data_->GetProfiles().size());
@@ -5582,9 +5486,7 @@ TEST_F(PersonalDataManagerTest,
EnableAutofillProfileCleanup();
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Get the profiles and cards sorted by frecency to have a deterministic
// order.
@@ -5645,9 +5547,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
personal_data_->AddProfile(profile3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 3 profiles were saved;
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -5659,9 +5560,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
base::HistogramTester histogram_tester;
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5738,9 +5637,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
personal_data_->AddProfile(profile3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -5752,9 +5650,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
base::HistogramTester histogram_tester;
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5807,9 +5703,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
personal_data_->AddProfile(profile3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -5821,9 +5716,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
base::HistogramTester histogram_tester;
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5875,9 +5768,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
personal_data_->AddProfile(profile3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 3 profiles were saved.
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -5889,9 +5781,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
base::HistogramTester histogram_tester;
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Get the profiles, sorted by frecency to have a deterministic order.
std::vector<AutofillProfile*> profiles =
@@ -5946,9 +5836,9 @@ TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(2U, personal_data_->GetProfiles().size());
// Get a sorted list of profiles. |profile1| will be first and |profile2| will
// be second.
@@ -5970,9 +5860,7 @@ TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix) {
test_clock.SetNow(kSomeLaterTime);
personal_data_->ApplyProfileUseDatesFix();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Get a sorted list of profiles.
saved_profiles = personal_data_->GetProfilesToSuggest();
@@ -6009,9 +5897,8 @@ TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix_NotAppliedTwice) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(2U, personal_data_->GetProfiles().size());
// Get a sorted list of profiles. |profile1| will be first and |profile2| will
// be second.
@@ -6097,9 +5984,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
personal_data_->AddProfile(Marge1);
personal_data_->AddProfile(Marge2);
personal_data_->AddProfile(Barney);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+
+ WaitForOnPersonalDataChanged();
// Make sure the 7 profiles were saved;
EXPECT_EQ(7U, personal_data_->GetProfiles().size());
@@ -6114,9 +6000,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// |Homer3|. |Marge2| should be discarded in favor of |Marge1| which is
// verified. |Homer4| and |Barney| should not be deduped at all.
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Get the profiles, sorted by frecency to have a deterministic order.
std::vector<AutofillProfile*> profiles =
@@ -6187,9 +6071,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Make sure both profiles were saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -6215,10 +6097,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
"", "Springfield", "IL", "91601", "US", "");
personal_data_->AddProfile(profile);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->GetProfiles().size());
// Enable the profile cleanup now. Otherwise it would be triggered by the
@@ -6244,10 +6124,8 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
personal_data_->AddProfile(profile1);
personal_data_->AddProfile(profile2);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
// Enable the profile cleanup now. Otherwise it would be triggered by the
@@ -6256,9 +6134,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
// The deduping routine should be run a first time.
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -6272,9 +6148,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
"", "Springfield", "IL", "91601", "", "");
personal_data_->AddProfile(profile3);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Make sure |profile3| was saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -6331,8 +6205,8 @@ TEST_F(PersonalDataManagerTest,
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
local_card.set_billing_address_id(kServerAddressId);
personal_data_->AddCreditCard(local_card);
@@ -6345,11 +6219,9 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().set_billing_address_id(kServerAddressId);
test::SetServerCreditCards(autofill_table_, server_cards);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->web_profiles().size());
EXPECT_EQ(1U, personal_data_->GetServerProfiles().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
@@ -6362,9 +6234,7 @@ TEST_F(PersonalDataManagerTest,
///////////////////////////////////////////////////////////////////////
// Validation.
///////////////////////////////////////////////////////////////////////
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The Wallet address should have been added as a new local profile.
EXPECT_EQ(2U, personal_data_->web_profiles().size());
@@ -6440,8 +6310,8 @@ TEST_F(PersonalDataManagerTest,
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
local_card.set_billing_address_id(kServerAddressId);
personal_data_->AddCreditCard(local_card);
@@ -6454,11 +6324,9 @@ TEST_F(PersonalDataManagerTest,
server_cards.back().set_billing_address_id(kServerAddressId);
test::SetServerCreditCards(autofill_table_, server_cards);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->web_profiles().size());
EXPECT_EQ(1U, personal_data_->GetServerProfiles().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
@@ -6471,9 +6339,7 @@ TEST_F(PersonalDataManagerTest,
///////////////////////////////////////////////////////////////////////
// Validation.
///////////////////////////////////////////////////////////////////////
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The Wallet address should have been merged with the existing local profile.
EXPECT_EQ(1U, personal_data_->web_profiles().size());
@@ -6530,11 +6396,9 @@ TEST_F(PersonalDataManagerTest,
// will be ignored when the profile is written to the DB.
autofill_table_->SetServerProfiles(GetServerProfiles);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(0U, personal_data_->web_profiles().size());
EXPECT_EQ(1U, personal_data_->GetServerProfiles().size());
@@ -6551,9 +6415,7 @@ TEST_F(PersonalDataManagerTest,
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(0);
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// There should be no local profiles added.
EXPECT_EQ(0U, personal_data_->web_profiles().size());
@@ -6616,8 +6478,8 @@ TEST_F(
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
"https://www.example.com");
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
- "347666888555" /* American Express */, "04", "2999",
- "1");
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
local_card.set_billing_address_id(kServerAddressId);
personal_data_->AddCreditCard(local_card);
@@ -6630,11 +6492,9 @@ TEST_F(
server_cards.back().set_billing_address_id(kServerAddressId2);
test::SetServerCreditCards(autofill_table_, server_cards);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->web_profiles().size());
EXPECT_EQ(2U, personal_data_->GetServerProfiles().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
@@ -6647,9 +6507,7 @@ TEST_F(
///////////////////////////////////////////////////////////////////////
// Validation.
///////////////////////////////////////////////////////////////////////
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The first Wallet address should have been added as a new local profile and
// the second one should have merged with the first.
@@ -6727,20 +6585,16 @@ TEST_F(
server_cards.back().set_billing_address_id(kServerAddressId);
test::SetServerCreditCards(autofill_table_, server_cards);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->GetServerProfiles().size());
EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
// Run the conversion.
personal_data_->ConvertWalletAddressesAndUpdateWalletCards();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The Wallet address should have been converted to a new local profile.
EXPECT_EQ(1U, personal_data_->web_profiles().size());
@@ -6765,11 +6619,9 @@ TEST_F(
server_cards.back().set_billing_address_id(kServerAddressId);
test::SetServerCreditCards(autofill_table_, server_cards);
- // Make sure everything is setup correctly.
+ // Make sure everything is set up correctly.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->web_profiles().size());
EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
@@ -6781,9 +6633,7 @@ TEST_F(
///////////////////////////////////////////////////////////////////////
// Validation.
///////////////////////////////////////////////////////////////////////
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// The conversion should still be recorded in the Wallet address.
EXPECT_TRUE(personal_data_->GetServerProfiles().back()->has_converted());
@@ -6827,8 +6677,8 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
profile0.guid());
CreditCard server_card0(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&server_card0, "John Barrow",
- "347666888555" /* American Express */, "04", "2999",
- profile0.guid());
+ "378282246310005" /* American Express */, "04",
+ "2999", profile0.guid());
server_cards.push_back(server_card0);
// Do the same but for profile1.
@@ -6838,8 +6688,8 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
profile1.guid());
CreditCard server_card1(CreditCard::FULL_SERVER_CARD, "c789");
test::SetCreditCardInfo(&server_card1, "John Barrow",
- "347666888555" /* American Express */, "04", "2999",
- profile1.guid());
+ "378282246310005" /* American Express */, "04",
+ "2999", profile1.guid());
server_cards.push_back(server_card1);
// Add the data to the database.
@@ -6849,10 +6699,9 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
personal_data_->AddCreditCard(local_card1);
test::SetServerCreditCards(autofill_table_, server_cards);
+ // Verify that the web database has been updated and the notification sent.
personal_data_->Refresh();
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Make sure everything was saved properly.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -6868,9 +6717,7 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
///////////////////////////////////////////////////////////////////////
// Wait for the data to be refreshed.
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .WillOnce(QuitMainMessageLoop());
- base::RunLoop().Run();
+ WaitForOnPersonalDataChanged();
// Make sure only profile0 was deleted.
ASSERT_EQ(1U, personal_data_->GetProfiles().size());
@@ -6943,7 +6790,7 @@ TEST_F(PersonalDataManagerTest, RemoveProfilesNotUsedSinceTimestamp) {
const base::Time kNow = AutofillClock::Now();
constexpr size_t kNumProfiles = 10;
- // Setup the profile vectors with last use dates ranging from |now| to 270
+ // Set up the profile vectors with last use dates ranging from |now| to 270
// days ago, in 30 day increments. Note that the profiles are sorted by
// decreasing last use date.
std::vector<AutofillProfile> all_profile_data;
@@ -7043,6 +6890,38 @@ TEST_F(PersonalDataManagerTest, RemoveProfilesNotUsedSinceTimestamp) {
histogram_tester.ExpectTotalCount(kHistogramName, 1);
histogram_tester.ExpectBucketCount(kHistogramName, 6, 1);
}
+
+ // Verify all profiles are removed if they're all disused.
+ {
+ // Create a working copy of the profile pointers.
+ std::vector<AutofillProfile*> profiles(all_profile_ptrs);
+
+ // Filter the profiles while capturing histograms.
+ base::HistogramTester histogram_tester;
+ PersonalDataManager::RemoveProfilesNotUsedSinceTimestamp(
+ kNow + base::TimeDelta::FromDays(1), &profiles);
+
+ // Validate that we get the expected filtered profiles and histograms.
+ EXPECT_TRUE(profiles.empty());
+ histogram_tester.ExpectTotalCount(kHistogramName, 1);
+ histogram_tester.ExpectBucketCount(kHistogramName, kNumProfiles, 1);
+ }
+
+ // Verify all profiles are retained if they're sufficiently recently used.
+ {
+ // Create a working copy of the profile pointers.
+ std::vector<AutofillProfile*> profiles(all_profile_ptrs);
+
+ // Filter the profiles while capturing histograms.
+ base::HistogramTester histogram_tester;
+ PersonalDataManager::RemoveProfilesNotUsedSinceTimestamp(
+ kNow - base::TimeDelta::FromDays(720), &profiles);
+
+ // Validate that we get the expected filtered profiles and histograms.
+ EXPECT_EQ(all_profile_ptrs, profiles);
+ histogram_tester.ExpectTotalCount(kHistogramName, 1);
+ histogram_tester.ExpectBucketCount(kHistogramName, 0, 1);
+ }
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/phone_email_validation_util.cc b/chromium/components/autofill/core/browser/phone_email_validation_util.cc
new file mode 100644
index 00000000000..72d0b2781ac
--- /dev/null
+++ b/chromium/components/autofill/core/browser/phone_email_validation_util.cc
@@ -0,0 +1,70 @@
+// 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/autofill/core/browser/phone_email_validation_util.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/country_data.h"
+#include "components/autofill/core/browser/validation.h"
+#include "third_party/libphonenumber/dist/cpp/src/phonenumbers/phonenumberutil.h"
+
+namespace autofill {
+
+namespace {
+using ::i18n::phonenumbers::PhoneNumberUtil;
+} // namespace
+
+namespace phone_email_validation_util {
+
+AutofillProfile::ValidityState ValidateEmailAddress(
+ const base::string16& email) {
+ if (email.empty()) {
+ // Not every profile needs an email address.
+ return AutofillProfile::VALID;
+ }
+ return (autofill::IsValidEmailAddress(email) ? AutofillProfile::VALID
+ : AutofillProfile::INVALID);
+}
+
+AutofillProfile::ValidityState ValidatePhoneNumber(
+ const std::string& phone_number,
+ const std::string& country_code) {
+ if (phone_number.empty()) {
+ // Every profile needs a phone number.
+ return AutofillProfile::INVALID;
+ }
+ if (!base::ContainsValue(CountryDataMap::GetInstance()->country_codes(),
+ country_code)) {
+ // If the country code is not in the database, the phone number cannot be
+ // validated.
+ return AutofillProfile::UNVALIDATED;
+ }
+ PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
+ return phone_util->IsPossibleNumberForString(phone_number, country_code)
+ ? AutofillProfile::VALID
+ : AutofillProfile::INVALID;
+}
+
+AutofillProfile::ValidityState ValidatePhoneAndEmail(AutofillProfile* profile) {
+ if (!profile)
+ return AutofillProfile::UNVALIDATED;
+
+ AutofillProfile::ValidityState phone_validity = ValidatePhoneNumber(
+ base::UTF16ToUTF8(profile->GetRawInfo(PHONE_HOME_WHOLE_NUMBER)),
+ base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY)));
+
+ profile->SetValidityState(PHONE_HOME_WHOLE_NUMBER, phone_validity);
+
+ profile->SetValidityState(
+ EMAIL_ADDRESS, ValidateEmailAddress(profile->GetRawInfo(EMAIL_ADDRESS)));
+
+ return phone_validity; // payment request doesn't care about email1 validity.
+}
+
+} // namespace phone_email_validation_util
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/phone_email_validation_util.h b/chromium/components/autofill/core/browser/phone_email_validation_util.h
new file mode 100644
index 00000000000..2f1be0d48d5
--- /dev/null
+++ b/chromium/components/autofill/core/browser/phone_email_validation_util.h
@@ -0,0 +1,20 @@
+// 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_AUTOFILL_CORE_BROWSER_PHONE_EMAIL_VALIDATION_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PHONE_EMAIL_VALIDATION_UTIL_H_
+
+#include "components/autofill/core/browser/autofill_profile.h"
+
+namespace autofill {
+namespace phone_email_validation_util {
+
+// Validates the phone number and email field of the |profile|.
+// Returns the ValidityState of the |profile| according to its phone fields.
+AutofillProfile::ValidityState ValidatePhoneAndEmail(AutofillProfile* profile);
+
+} // namespace phone_email_validation_util
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PHONE_EMAIL_VALIDATION_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc b/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc
new file mode 100644
index 00000000000..0060acc79c3
--- /dev/null
+++ b/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc
@@ -0,0 +1,211 @@
+// 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/autofill/core/browser/phone_email_validation_util.h"
+
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class AutofillPhoneValidationTest : public testing::Test {
+ public:
+ AutofillPhoneValidationTest() {}
+
+ AutofillProfile::ValidityState ValidatePhoneAndEmailTest(
+ AutofillProfile* profile) {
+ return phone_email_validation_util::ValidatePhoneAndEmail(profile);
+ }
+
+ ~AutofillPhoneValidationTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutofillPhoneValidationTest);
+};
+
+TEST_F(AutofillPhoneValidationTest, ValidateNULLProfile) {
+ EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidatePhoneAndEmailTest(nullptr));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateFullValidProfile) {
+ // This is a full valid profile:
+ // Country Code: "CA", Phone Number: "15141112233",
+ // Email: "alice@wonderland.ca"
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateEmptyPhoneNumber) {
+ // This is a profile with empty phone number. Since phone number field is
+ // always required, it is considered as invalid.
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateValidPhone_CountryCodeNotExist) {
+ // This is a profile with invalid country code, therefore the phone number
+ // cannot be validated.
+ const std::string country_code = "PP";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateEmptyPhone_CountryCodeNotExist) {
+ // This is a profile with invalid country code, but a missing phone number.
+ // Therefore, it's an invalid phone number.
+ const std::string country_code = "PP";
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16());
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateInvalidPhoneNumber) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::ASCIIToUTF16("33"));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("151411122334"));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("1(514)111-22-334"));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("251411122334"));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::ASCIIToUTF16("Hello!"));
+ EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateValidPhoneNumber) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::ASCIIToUTF16("5141112233"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("514-111-2233"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("1(514)111-22-33"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("+1 514 111 22 33"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("+1 (514)-111-22-33"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("(514)-111-22-33"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("+1 650 GOO OGLE"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+
+ profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+ base::ASCIIToUTF16("778 111 22 33"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateEmptyEmailAddress) {
+ // This is a profile with empty email address. Since email field is
+ // not required, it is considered as valid.
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::string16());
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID,
+ profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateInvalidEmailAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Hello!"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS));
+
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice.wonderland"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS));
+
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice@"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS));
+
+ profile.SetRawInfo(EMAIL_ADDRESS,
+ base::ASCIIToUTF16("alice@=wonderland.com"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+TEST_F(AutofillPhoneValidationTest, ValidateValidEmailAddress) {
+ AutofillProfile profile(autofill::test::GetFullValidProfile());
+
+ profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice@wonderland"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+
+ profile.SetRawInfo(EMAIL_ADDRESS,
+ base::ASCIIToUTF16("alice@wonderland.fiction"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+
+ profile.SetRawInfo(EMAIL_ADDRESS,
+ base::ASCIIToUTF16("alice+cat@wonderland.fiction.book"));
+ EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile));
+ EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/phone_number.cc b/chromium/components/autofill/core/browser/phone_number.cc
index 7dde9375f36..d10ab79d83a 100644
--- a/chromium/components/autofill/core/browser/phone_number.cc
+++ b/chromium/components/autofill/core/browser/phone_number.cc
@@ -93,12 +93,54 @@ void PhoneNumber::SetRawInfo(ServerFieldType type,
cached_parsed_phone_ = i18n::PhoneObject();
}
+void PhoneNumber::GetMatchingTypes(const base::string16& text,
+ const std::string& app_locale,
+ ServerFieldTypeSet* matching_types) const {
+ // Strip the common phone number non numerical characters before calling the
+ // base matching type function. For example, the |text| "(514) 121-1523"
+ // would become the stripped text "5141211523". Since the base matching
+ // function only does simple canonicalization to match against the stored
+ // data, some domain specific cases will be covered below.
+ base::string16 stripped_text = text;
+ base::RemoveChars(stripped_text, base::ASCIIToUTF16(" .()-"), &stripped_text);
+ FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
+
+ // For US numbers, also compare to the three-digit prefix and the four-digit
+ // suffix, since web sites often split numbers into these two fields.
+ base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
+ if (GetRegion(*profile_, app_locale) == "US" &&
+ number.size() == (kPrefixLength + kSuffixLength)) {
+ base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
+ base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
+ if (text == prefix || text == suffix)
+ matching_types->insert(PHONE_HOME_NUMBER);
+ }
+
+ // TODO(crbug.com/581391): Investigate the use of PhoneNumberUtil when
+ // matching phone numbers for upload.
+ // If there is not already a match for PHONE_HOME_WHOLE_NUMBER, normalize the
+ // |text| based on the app_locale before comparing it to the whole number. For
+ // example, the France number "33 2 49 19 70 70" would be normalized to
+ // "+33249197070" whereas the US number "+1 (234) 567-8901" would be
+ // normalized to "12345678901".
+ if (matching_types->find(PHONE_HOME_WHOLE_NUMBER) == matching_types->end()) {
+ base::string16 whole_number =
+ GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
+ if (!whole_number.empty()) {
+ base::string16 normalized_number =
+ i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
+ if (normalized_number == whole_number)
+ matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
+ }
+ }
+}
+
// Normalize phones if |type| is a whole number:
// (650)2345678 -> 6502345678
// 1-800-FLOWERS -> 18003569377
// If the phone cannot be normalized, returns the stored value verbatim.
-base::string16 PhoneNumber::GetInfo(const AutofillType& type,
- const std::string& app_locale) const {
+base::string16 PhoneNumber::GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const {
ServerFieldType storable_type = type.GetStorableType();
UpdateCacheIfNeeded(app_locale);
@@ -135,9 +177,9 @@ base::string16 PhoneNumber::GetInfo(const AutofillType& type,
}
}
-bool PhoneNumber::SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) {
+bool PhoneNumber::SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) {
SetRawInfo(type.GetStorableType(), value);
if (number_.empty())
@@ -156,47 +198,6 @@ bool PhoneNumber::SetInfo(const AutofillType& type,
return !number_.empty();
}
-void PhoneNumber::GetMatchingTypes(const base::string16& text,
- const std::string& app_locale,
- ServerFieldTypeSet* matching_types) const {
- // Strip the common phone number non numerical characters before calling the
- // base matching type function. For example, the |text| "(514) 121-1523"
- // would become the stripped text "5141211523". Since the base matching
- // function only does simple canonicalization to match against the stored
- // data, some domain specific cases will be covered below.
- base::string16 stripped_text = text;
- base::RemoveChars(stripped_text, base::ASCIIToUTF16(" .()-"), &stripped_text);
- FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
-
- // For US numbers, also compare to the three-digit prefix and the four-digit
- // suffix, since web sites often split numbers into these two fields.
- base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
- if (GetRegion(*profile_, app_locale) == "US" &&
- number.size() == (kPrefixLength + kSuffixLength)) {
- base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
- base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
- if (text == prefix || text == suffix)
- matching_types->insert(PHONE_HOME_NUMBER);
- }
-
- // TODO(crbug.com/581391): Investigate the use of PhoneNumberUtil when
- // matching phone numbers for upload.
- // If there is not already a match for PHONE_HOME_WHOLE_NUMBER, normalize the
- // |text| based on the app_locale before comparing it to the whole number. For
- // example, the France number "33 2 49 19 70 70" would be normalized to
- // "+33249197070" whereas the US number "+1 (234) 567-8901" would be
- // normalized to "12345678901".
- if (matching_types->find(PHONE_HOME_WHOLE_NUMBER) == matching_types->end()) {
- base::string16 whole_number =
- GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
- if (!whole_number.empty()) {
- base::string16 normalized_number =
- i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
- if (normalized_number == whole_number)
- matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
- }
- }
-}
void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const {
std::string region = GetRegion(*profile_, app_locale);
diff --git a/chromium/components/autofill/core/browser/phone_number.h b/chromium/components/autofill/core/browser/phone_number.h
index 333bbae909a..4773e8cb34c 100644
--- a/chromium/components/autofill/core/browser/phone_number.h
+++ b/chromium/components/autofill/core/browser/phone_number.h
@@ -37,11 +37,6 @@ class PhoneNumber : public FormGroup {
ServerFieldTypeSet* matching_types) const override;
base::string16 GetRawInfo(ServerFieldType type) const override;
void SetRawInfo(ServerFieldType type, const base::string16& value) override;
- base::string16 GetInfo(const AutofillType& type,
- const std::string& app_locale) const override;
- bool SetInfo(const AutofillType& type,
- const base::string16& value,
- const std::string& app_locale) override;
// Size and offset of the prefix and suffix portions of phone numbers.
static const size_t kPrefixOffset = 0;
@@ -80,6 +75,11 @@ class PhoneNumber : public FormGroup {
private:
// FormGroup:
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
+ base::string16 GetInfoImpl(const AutofillType& type,
+ const std::string& app_locale) const override;
+ bool SetInfoImpl(const AutofillType& type,
+ const base::string16& value,
+ const std::string& app_locale) override;
// Updates the cached parsed number if the profile's region has changed
// since the last time the cache was updated.
diff --git a/chromium/components/autofill/core/browser/popup_item_ids.h b/chromium/components/autofill/core/browser/popup_item_ids.h
index cbdd295c519..4859fa266a8 100644
--- a/chromium/components/autofill/core/browser/popup_item_ids.h
+++ b/chromium/components/autofill/core/browser/popup_item_ids.h
@@ -23,6 +23,7 @@ enum PopupItemId {
POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE = -10,
POPUP_ITEM_ID_USERNAME_ENTRY = -11,
POPUP_ITEM_ID_CREATE_HINT = -12,
+ POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY = -13,
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index ee556e5b174..ad92f3768df 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -33,7 +33,7 @@ message AutofillQueryResponseContents {
// This message contains information about the field types in a single form.
// It is sent by the toolbar to contribute to the field type statistics.
-// Next available id: 23
+// Next available id: 24
message AutofillUploadContents {
required string client_version = 1;
required fixed64 form_signature = 2;
@@ -102,6 +102,18 @@ message AutofillUploadContents {
// True iff the user changed generated password. If there was no generation,
// the field is absent.
optional bool generated_password_changed = 22;
+
+ enum UsernameVoteType {
+ NO_INFORMATION = 0;
+ CREDENTIALS_REUSED = 1;
+ USERNAME_OVERWRITTEN = 2;
+ USERNAME_EDITED = 3;
+ BASE_HEURISTIC = 4;
+ HTML_CLASSIFIER = 5;
+ }
+ // The type of username vote. If |autofill_type| != USERNAME, then the field
+ // is missed.
+ optional UsernameVoteType username_vote_type = 23;
}
// Signature of the form action host (e.g. Hash64Bit("example.com")).
optional fixed64 action_signature = 13;
diff --git a/chromium/components/autofill/core/browser/server_field_types_util.cc b/chromium/components/autofill/core/browser/server_field_types_util.cc
deleted file mode 100644
index 6d27d3e576a..00000000000
--- a/chromium/components/autofill/core/browser/server_field_types_util.cc
+++ /dev/null
@@ -1,83 +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/autofill/core/browser/server_field_types_util.h"
-
-#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_type.h"
-
-namespace autofill {
-
-bool ServerTypeEncompassesFieldType(ServerFieldType type,
- const AutofillType& field_type) {
- // If any credit card expiration info is asked for, show both month and year
- // inputs.
- ServerFieldType server_type = field_type.GetStorableType();
- if (server_type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
- server_type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
- server_type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR ||
- server_type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
- server_type == CREDIT_CARD_EXP_MONTH) {
- return type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
- type == CREDIT_CARD_EXP_MONTH;
- }
-
- if (server_type == CREDIT_CARD_TYPE)
- return type == CREDIT_CARD_NUMBER;
-
- // Check the groups to distinguish billing types from shipping ones.
- AutofillType autofill_type = AutofillType(type);
- if (autofill_type.group() != field_type.group())
- return false;
-
- // The page may ask for individual address lines; this roughly matches the
- // street address blob.
- if (server_type == ADDRESS_HOME_LINE1 || server_type == ADDRESS_HOME_LINE2 ||
- server_type == ADDRESS_HOME_LINE3) {
- return autofill_type.GetStorableType() == ADDRESS_HOME_STREET_ADDRESS;
- }
-
- // First, middle and last name are parsed from full name.
- if (field_type.group() == NAME || field_type.group() == NAME_BILLING)
- return autofill_type.GetStorableType() == NAME_FULL;
-
- return autofill_type.GetStorableType() == server_type;
-}
-
-bool ServerTypeMatchesField(DialogSection section,
- ServerFieldType type,
- const AutofillField& field) {
- AutofillType field_type = field.Type();
-
- // The credit card name is filled from the billing section's data.
- if (field_type.GetStorableType() == CREDIT_CARD_NAME_FULL &&
- section == SECTION_BILLING) {
- return type == NAME_BILLING_FULL;
- }
-
- return ServerTypeEncompassesFieldType(type, field_type);
-}
-
-bool IsCreditCardType(ServerFieldType type) {
- return AutofillType(type).group() == CREDIT_CARD;
-}
-
-void BuildInputs(const DetailInput* input_template,
- size_t template_size,
- DetailInputs* inputs) {
- for (size_t i = 0; i < template_size; ++i) {
- const DetailInput* input = &input_template[i];
- inputs->push_back(*input);
- }
-}
-
-std::vector<ServerFieldType> TypesFromInputs(const DetailInputs& inputs) {
- std::vector<ServerFieldType> types;
- for (size_t i = 0; i < inputs.size(); ++i) {
- types.push_back(inputs[i].type);
- }
- return types;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/server_field_types_util.h b/chromium/components/autofill/core/browser/server_field_types_util.h
deleted file mode 100644
index 73cc3631bc3..00000000000
--- a/chromium/components/autofill/core/browser/server_field_types_util.h
+++ /dev/null
@@ -1,48 +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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_SERVER_FIELD_TYPES_UTIL_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_SERVER_FIELD_TYPES_UTIL_H_
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "components/autofill/core/browser/detail_input.h"
-#include "components/autofill/core/browser/dialog_section.h"
-#include "components/autofill/core/browser/field_types.h"
-
-namespace autofill {
-
-class AutofillField;
-class AutofillType;
-
-// Returns true if |type| should be shown when |field_type| has been requested.
-// This filters the types that we fill into the page to match the ones the
-// dialog actually cares about, preventing rAc from giving away data that an
-// AutofillProfile or other data source might know about the user which isn't
-// represented in the dialog.
-bool ServerTypeEncompassesFieldType(ServerFieldType type,
- const AutofillType& field_type);
-
-// Returns true if |type| in the given |section| should be used for a
-// site-requested |field|.
-bool ServerTypeMatchesField(DialogSection section,
- ServerFieldType type,
- const AutofillField& field);
-
-// Returns true if the |type| belongs to the CREDIT_CARD field type group.
-bool IsCreditCardType(ServerFieldType type);
-
-// Constructs |inputs| from the array of inputs in |input_template|.
-void BuildInputs(const DetailInput input_template[],
- size_t template_size,
- DetailInputs* inputs);
-
-// Gets just the |type| attributes from each DetailInput.
-std::vector<ServerFieldType> TypesFromInputs(const DetailInputs& inputs);
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_SERVER_FIELD_TYPES_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/state_names.cc b/chromium/components/autofill/core/browser/state_names.cc
index a62f925680f..8f1d892162d 100644
--- a/chromium/components/autofill/core/browser/state_names.cc
+++ b/chromium/components/autofill/core/browser/state_names.cc
@@ -22,59 +22,59 @@ struct StateData {
const char abbreviation[3];
};
-StateData kStateData[] = {
- { "alabama", "al" },
- { "alaska", "ak" },
- { "arizona", "az" },
- { "arkansas", "ar" },
- { "california", "ca" },
- { "colorado", "co" },
- { "connecticut", "ct" },
- { "delaware", "de" },
- { "district of columbia", "dc" },
- { "florida", "fl" },
- { "georgia", "ga" },
- { "hawaii", "hi" },
- { "idaho", "id" },
- { "illinois", "il" },
- { "indiana", "in" },
- { "iowa", "ia" },
- { "kansas", "ks" },
- { "kentucky", "ky" },
- { "louisiana", "la" },
- { "maine", "me" },
- { "maryland", "md" },
- { "massachusetts", "ma" },
- { "michigan", "mi" },
- { "minnesota", "mn" },
- { "mississippi", "ms" },
- { "missouri", "mo" },
- { "montana", "mt" },
- { "nebraska", "ne" },
- { "nevada", "nv" },
- { "new hampshire", "nh" },
- { "new jersey", "nj" },
- { "new mexico", "nm" },
- { "new york", "ny" },
- { "north carolina", "nc" },
- { "north dakota", "nd" },
- { "ohio", "oh" },
- { "oklahoma", "ok" },
- { "oregon", "or" },
- { "pennsylvania", "pa" },
- { "puerto rico", "pr" },
- { "rhode island", "ri" },
- { "south carolina", "sc" },
- { "south dakota", "sd" },
- { "tennessee", "tn" },
- { "texas", "tx" },
- { "utah", "ut" },
- { "vermont", "vt" },
- { "virginia", "va" },
- { "washington", "wa" },
- { "west virginia", "wv" },
- { "wisconsin", "wi" },
- { "wyoming", "wy" },
+const StateData kStateData[] = {
+ {"alabama", "al"},
+ {"alaska", "ak"},
+ {"arizona", "az"},
+ {"arkansas", "ar"},
+ {"california", "ca"},
+ {"colorado", "co"},
+ {"connecticut", "ct"},
+ {"delaware", "de"},
+ {"district of columbia", "dc"},
+ {"florida", "fl"},
+ {"georgia", "ga"},
+ {"hawaii", "hi"},
+ {"idaho", "id"},
+ {"illinois", "il"},
+ {"indiana", "in"},
+ {"iowa", "ia"},
+ {"kansas", "ks"},
+ {"kentucky", "ky"},
+ {"louisiana", "la"},
+ {"maine", "me"},
+ {"maryland", "md"},
+ {"massachusetts", "ma"},
+ {"michigan", "mi"},
+ {"minnesota", "mn"},
+ {"mississippi", "ms"},
+ {"missouri", "mo"},
+ {"montana", "mt"},
+ {"nebraska", "ne"},
+ {"nevada", "nv"},
+ {"new hampshire", "nh"},
+ {"new jersey", "nj"},
+ {"new mexico", "nm"},
+ {"new york", "ny"},
+ {"north carolina", "nc"},
+ {"north dakota", "nd"},
+ {"ohio", "oh"},
+ {"oklahoma", "ok"},
+ {"oregon", "or"},
+ {"pennsylvania", "pa"},
+ {"puerto rico", "pr"},
+ {"rhode island", "ri"},
+ {"south carolina", "sc"},
+ {"south dakota", "sd"},
+ {"tennessee", "tn"},
+ {"texas", "tx"},
+ {"utah", "ut"},
+ {"vermont", "vt"},
+ {"virginia", "va"},
+ {"washington", "wa"},
+ {"west virginia", "wv"},
+ {"wisconsin", "wi"},
+ {"wyoming", "wy"},
};
} // namespace
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 8dde20e85cc..14c28312b24 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -14,7 +14,6 @@ namespace autofill {
TestAutofillClient::TestAutofillClient()
: token_service_(new FakeOAuth2TokenService()),
identity_provider_(new FakeIdentityProvider(token_service_.get())),
- rappor_service_(new rappor::TestRapporServiceImpl()),
#if !defined(OS_ANDROID)
save_card_bubble_controller_(new MockSaveCardBubbleController()),
#endif
@@ -43,10 +42,6 @@ IdentityProvider* TestAutofillClient::GetIdentityProvider() {
return identity_provider_.get();
}
-rappor::RapporServiceImpl* TestAutofillClient::GetRapporServiceImpl() {
- return rappor_service_.get();
-}
-
ukm::UkmRecorder* TestAutofillClient::GetUkmRecorder() {
return ukm::UkmRecorder::Get();
}
@@ -141,9 +136,7 @@ bool TestAutofillClient::ShouldShowSigninPromo() {
return false;
}
-void TestAutofillClient::StartSigninFlow() {}
-
-void TestAutofillClient::ShowHttpNotSecureExplanation() {}
+void TestAutofillClient::ExecuteCommand(int id) {}
bool TestAutofillClient::IsAutofillSupported() {
return true;
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index a0bd9cbdeb4..ae1652a5e3f 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -15,7 +15,6 @@
#include "base/macros.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/prefs/pref_service.h"
-#include "components/rappor/test_rappor_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "google_apis/gaia/fake_identity_provider.h"
#include "google_apis/gaia/fake_oauth2_token_service.h"
@@ -34,7 +33,6 @@ class TestAutofillClient : public AutofillClient {
PrefService* GetPrefs() override;
syncer::SyncService* GetSyncService() override;
IdentityProvider* GetIdentityProvider() override;
- rappor::RapporServiceImpl* GetRapporServiceImpl() override;
ukm::UkmRecorder* GetUkmRecorder() override;
SaveCardBubbleController* GetSaveCardBubbleController() override;
void ShowAutofillSettings() override;
@@ -75,18 +73,13 @@ class TestAutofillClient : public AutofillClient {
// http:// URL.
bool IsContextSecure() override;
bool ShouldShowSigninPromo() override;
- void StartSigninFlow() override;
- void ShowHttpNotSecureExplanation() override;
bool IsAutofillSupported() override;
+ void ExecuteCommand(int id) override;
void SetPrefs(std::unique_ptr<PrefService> prefs) {
prefs_ = std::move(prefs);
}
- rappor::TestRapporServiceImpl* test_rappor_service() {
- return rappor_service_.get();
- }
-
void set_form_origin(const GURL& url) { form_origin_ = url; }
private:
@@ -94,7 +87,6 @@ class TestAutofillClient : public AutofillClient {
std::unique_ptr<PrefService> prefs_;
std::unique_ptr<FakeOAuth2TokenService> token_service_;
std::unique_ptr<FakeIdentityProvider> identity_provider_;
- std::unique_ptr<rappor::TestRapporServiceImpl> rappor_service_;
#if !defined(OS_ANDROID)
std::unique_ptr<SaveCardBubbleController> save_card_bubble_controller_;
#endif
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
index ce040ae2008..48e790d9b85 100644
--- a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
+++ b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
@@ -26,6 +26,7 @@ class MockSaveCardBubbleController : public SaveCardBubbleController {
MOCK_METHOD1(OnLegalMessageLinkClicked, void(const GURL& url));
MOCK_METHOD0(OnBubbleClosed, void());
MOCK_CONST_METHOD0(GetLegalMessageLines, const LegalMessageLines&());
+ MOCK_METHOD0(ContinueToRequestCvcStage, void());
MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
base::string16 GetCvcEnteredByUser() const override;
diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
index f01cac3f220..751a6048a6e 100644
--- a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
+++ b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
@@ -58,6 +58,10 @@ class SaveCardBubbleController {
// Returns empty vector if no legal message should be shown.
virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
+ // Called when the upload save version of the UI needs to request CVC in order
+ // to save, and has user has clicked [Next] in order to surface that UI.
+ virtual void ContinueToRequestCvcStage() = 0;
+
// Utilities.
virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index 60726b8e610..c09ea989d26 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -48,7 +48,7 @@ bool IsValidCreditCardNumber(const base::string16& text) {
// Credit card numbers are at most 19 digits in length, 12 digits seems to
// be a fairly safe lower-bound [1]. Specific card issuers have more rigidly
- // defined sizes.
+ // defined sizes.
// (Last updated: May 29, 2017)
// [1] https://en.wikipedia.org/wiki/Payment_card_number.
// CardEditor.isCardNumberLengthMaxium() needs to be kept in sync.
@@ -176,6 +176,23 @@ base::string16 GetCompletionMessageForCard(CreditCardCompletionStatus status) {
}
}
+base::string16 GetEditDialogTitleForCard(CreditCardCompletionStatus status) {
+ switch (status) {
+ case CREDIT_CARD_COMPLETE:
+ case CREDIT_CARD_EXPIRED:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_EDIT_CARD);
+ case CREDIT_CARD_NO_CARDHOLDER:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_NAME_ON_CARD);
+ case CREDIT_CARD_NO_NUMBER:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_VALID_CARD_NUMBER);
+ case CREDIT_CARD_NO_BILLING_ADDRESS:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_BILLING_ADDRESS);
+ default:
+ // Multiple things are missing
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_MORE_INFORMATION);
+ }
+}
+
bool IsValidEmailAddress(const base::string16& text) {
// E-Mail pattern as defined by the WhatWG. (4.10.7.1.5 E-Mail state)
const base::string16 kEmailPattern = base::ASCIIToUTF16(
diff --git a/chromium/components/autofill/core/browser/validation.h b/chromium/components/autofill/core/browser/validation.h
index 531cf273d7c..ebcf5db5377 100644
--- a/chromium/components/autofill/core/browser/validation.h
+++ b/chromium/components/autofill/core/browser/validation.h
@@ -69,6 +69,11 @@ CreditCardCompletionStatus GetCompletionStatusForCard(
// missing, the message will be a generic "more information required".
base::string16 GetCompletionMessageForCard(CreditCardCompletionStatus status);
+// Returns the title string for a card edit dialog. The title string will
+// mention what needs to be added/fixed to make the card valid if it is not
+// valid. Otherwise, it will be "Edit card".
+base::string16 GetEditDialogTitleForCard(CreditCardCompletionStatus status);
+
// Returns true if |text| looks like a valid e-mail address.
bool IsValidEmailAddress(const base::string16& text);
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 48e362f18ee..ebdef7139ef 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -479,7 +479,6 @@ std::string AutocompleteSyncBridge::GetStorageKey(
return BuildSerializedStorageKey(specifics.name(), specifics.value());
}
-// AutofillWebDataServiceObserverOnDBThread implementation.
void AutocompleteSyncBridge::AutofillEntriesChanged(
const AutofillChangeList& changes) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
index 75b978d9f59..ee568fb5e75 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -25,9 +25,10 @@ class AutofillTable;
class AutofillWebDataBackend;
class AutofillWebDataService;
-class AutocompleteSyncBridge : public base::SupportsUserData::Data,
- public syncer::ModelTypeSyncBridge,
- public AutofillWebDataServiceObserverOnDBThread {
+class AutocompleteSyncBridge
+ : public base::SupportsUserData::Data,
+ public syncer::ModelTypeSyncBridge,
+ public AutofillWebDataServiceObserverOnDBSequence {
public:
AutocompleteSyncBridge();
AutocompleteSyncBridge(
@@ -56,7 +57,7 @@ class AutocompleteSyncBridge : public base::SupportsUserData::Data,
std::string GetClientTag(const syncer::EntityData& entity_data) override;
std::string GetStorageKey(const syncer::EntityData& entity_data) override;
- // AutofillWebDataServiceObserverOnDBThread implementation.
+ // AutofillWebDataServiceObserverOnDBSequence implementation.
void AutofillEntriesChanged(const AutofillChangeList& changes) override;
private:
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 18a81d558d1..f07355860ac 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
@@ -114,9 +114,11 @@ class FakeAutofillBackend : public AutofillWebDataBackend {
~FakeAutofillBackend() override {}
WebDatabase* GetDatabase() override { return db_; }
void AddObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveExpiredFormElements() override {}
void NotifyOfMultipleAutofillChanges() override {}
void NotifyThatSyncHasStarted(ModelType model_type) override {}
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
index c94383b7286..9d603cc19d2 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
@@ -49,7 +49,7 @@ class AutofillTable;
class AutocompleteSyncableService
: public base::SupportsUserData::Data,
public syncer::SyncableService,
- public AutofillWebDataServiceObserverOnDBThread {
+ public AutofillWebDataServiceObserverOnDBSequence {
public:
~AutocompleteSyncableService() override;
@@ -77,7 +77,7 @@ class AutocompleteSyncableService
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) override;
- // AutofillWebDataServiceObserverOnDBThread:
+ // AutofillWebDataServiceObserverOnDBSequence:
void AutofillEntriesChanged(const AutofillChangeList& changes) override;
// Provides a StartSyncFlare to the SyncableService. See sync_start_util for
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
index 90aa68b77d8..04c5542c402 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
@@ -42,9 +42,11 @@ class NoOpAutofillBackend : public AutofillWebDataBackend {
~NoOpAutofillBackend() override {}
WebDatabase* GetDatabase() override { return NULL; }
void AddObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveExpiredFormElements() override {}
void NotifyOfMultipleAutofillChanges() override {}
void NotifyThatSyncHasStarted(syncer::ModelType /* model_type */) override {}
@@ -83,7 +85,7 @@ class FakeWebDataService : public AutofillWebDataService {
void StartSyncableService() {
// The |autofill_profile_syncable_service_| must be constructed on the DB
- // thread.
+ // sequence.
base::RunLoop run_loop;
db_task_runner_->PostTaskAndReply(
FROM_HERE, base::Bind(&FakeWebDataService::CreateSyncableService,
@@ -96,7 +98,7 @@ class FakeWebDataService : public AutofillWebDataService {
~FakeWebDataService() override {}
void CreateSyncableService() {
- ASSERT_TRUE(db_task_runner_->BelongsToCurrentThread());
+ ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
// These services are deleted in DestroySyncableService().
autofill::AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
this, &autofill_backend_);
@@ -128,7 +130,7 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
}
void TearDown() override {
- web_data_service_->ShutdownOnUIThread();
+ web_data_service_->ShutdownOnUISequence();
// Make sure WebDataService is shutdown properly on DB thread before we
// destroy it.
@@ -171,9 +173,8 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
base::WeakPtrFactory<SyncAutofillDataTypeControllerTest> weak_ptr_factory_;
};
-// Load the WDS's database, then start the Autofill DTC. It should
-// immediately try to start association and fail (due to missing DB
-// thread).
+// Load the WDS's database, then start the Autofill DTC. It should immediately
+// try to start association and fail (due to missing DB thread).
TEST_F(SyncAutofillDataTypeControllerTest, StartWDSReady) {
web_data_service_->LoadDatabase();
autofill_dtc_->LoadModels(
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 897204829cd..9ab95866032 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -48,13 +48,13 @@ extern const char kAutofillProfileTag[];
class AutofillProfileSyncableService
: public base::SupportsUserData::Data,
public syncer::SyncableService,
- public AutofillWebDataServiceObserverOnDBThread {
+ public AutofillWebDataServiceObserverOnDBSequence {
public:
~AutofillProfileSyncableService() override;
// Creates a new AutofillProfileSyncableService and hangs it off of
// |web_data_service|, which takes ownership. This method should only be
- // called on |web_data_service|'s DB thread.
+ // called on |web_data_service|'s DB sequence.
static void CreateForWebDataServiceAndBackend(
AutofillWebDataService* web_data_service,
AutofillWebDataBackend* webdata_backend,
@@ -78,7 +78,7 @@ class AutofillProfileSyncableService
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) override;
- // AutofillWebDataServiceObserverOnDBThread implementation.
+ // AutofillWebDataServiceObserverOnDBSequence implementation.
void AutofillProfileChanged(const AutofillProfileChange& change) override;
// Provides a StartSyncFlare to the SyncableService. See
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index cba036d2383..92ce2201c1a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -996,9 +996,8 @@ bool AutofillTable::GetServerProfiles(
// SetInfo instead of SetRawInfo so the constituent pieces will be parsed
// for these data types.
- profile->SetInfo(AutofillType(NAME_FULL), recipient_name,
- profile->language_code());
- profile->SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), phone_number,
+ profile->SetInfo(NAME_FULL, recipient_name, profile->language_code());
+ profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, phone_number,
profile->language_code());
profiles->push_back(std::move(profile));
@@ -2444,9 +2443,8 @@ bool AutofillTable::MigrateToVersion65AddServerMetadataTables() {
profile.SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++));
base::string16 phone_number = s.ColumnString16(index++);
profile.set_language_code(s.ColumnString(index++));
- profile.SetInfo(AutofillType(NAME_FULL), recipient_name,
- profile.language_code());
- profile.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), phone_number,
+ profile.SetInfo(NAME_FULL, recipient_name, profile.language_code());
+ profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, phone_number,
profile.language_code());
profile.GenerateServerProfileIdentifier();
profiles.push_back(profile);
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 931f8b48243..298a2c3c422 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -128,7 +128,7 @@ class AutofillTableTest : public testing::Test {
protected:
void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
@@ -2009,7 +2009,7 @@ class GetFormValuesTest : public testing::TestWithParam<GetFormValuesTestCase> {
protected:
void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
index 23edced9e32..5e16997bdf3 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
@@ -47,7 +47,7 @@ class CreditCard;
class AutofillWalletMetadataSyncableService
: public base::SupportsUserData::Data,
public syncer::SyncableService,
- public AutofillWebDataServiceObserverOnDBThread {
+ public AutofillWebDataServiceObserverOnDBSequence {
public:
~AutofillWalletMetadataSyncableService() override;
@@ -63,15 +63,15 @@ class AutofillWalletMetadataSyncableService
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& changes_from_sync) override;
- // AutofillWebDataServiceObserverOnDBThread implementation.
+ // AutofillWebDataServiceObserverOnDBSequence implementation.
void AutofillProfileChanged(const AutofillProfileChange& change) override;
void CreditCardChanged(const CreditCardChange& change) override;
void AutofillMultipleChanged() override;
// Creates a new AutofillWalletMetadataSyncableService and hangs it off of
// |web_data_service|, which takes ownership. This method should only be
- // called on |web_data_service|'s DB thread. |web_data_backend| is expected to
- // outlive this object.
+ // called on |web_data_service|'s DB sequence. |web_data_backend| is expected
+ // to outlive this object.
static void CreateForWebDataServiceAndBackend(
AutofillWebDataService* web_data_service,
AutofillWebDataBackend* web_data_backend,
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
index b24fec6e158..c6ab087d27a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
@@ -154,9 +154,9 @@ class NoOpWebData : public AutofillWebDataBackend {
// AutofillWebDataBackend implementation.
WebDatabase* GetDatabase() override { return nullptr; }
void AddObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ AutofillWebDataServiceObserverOnDBSequence* observer) override {}
void RemoveObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ AutofillWebDataServiceObserverOnDBSequence* observer) override {}
void RemoveExpiredFormElements() override {}
void NotifyOfMultipleAutofillChanges() override {}
void NotifyThatSyncHasStarted(syncer::ModelType /* model_type */) override {}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index bbbdba8db9f..39382970d7a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -128,10 +128,9 @@ AutofillProfile ProfileFromSpecifics(
// SetInfo instead of SetRawInfo so the constituent pieces will be parsed
// for these data types.
- profile.SetInfo(AutofillType(NAME_FULL),
- base::UTF8ToUTF16(address.recipient_name()),
+ profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()),
profile.language_code());
- profile.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER),
+ profile.SetInfo(PHONE_HOME_WHOLE_NUMBER,
base::UTF8ToUTF16(address.phone_number()),
profile.language_code());
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
index 8885a58f224..7017c0f8845 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
@@ -11,9 +11,9 @@ class WebDatabase;
namespace autofill {
-class AutofillWebDataServiceObserverOnDBThread;
+class AutofillWebDataServiceObserverOnDBSequence;
-// Interface for doing Autofill work directly on the DB thread (used by
+// Interface for doing Autofill work directly on the DB sequence (used by
// Sync, mostly), without fully exposing the AutofillWebDataBackend to clients.
class AutofillWebDataBackend {
public:
@@ -22,26 +22,27 @@ class AutofillWebDataBackend {
// Get a raw pointer to the WebDatabase.
virtual WebDatabase* GetDatabase() = 0;
- // Add an observer to be notified of changes on the DB thread.
+ // Add an observer to be notified of changes on the DB sequence.
virtual void AddObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) = 0;
+ AutofillWebDataServiceObserverOnDBSequence* observer) = 0;
// Remove an observer.
virtual void RemoveObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) = 0;
+ AutofillWebDataServiceObserverOnDBSequence* observer) = 0;
// Remove expired elements from the database and commit if needed.
virtual void RemoveExpiredFormElements() = 0;
- // Notifies listeners on both DB and UI threads that multiple changes have
+ // Notifies listeners on both DB and UI sequences that multiple changes have
// been made to to Autofill records of the database.
- // NOTE: This method is intended to be called from the DB thread. The UI
- // thread notifications are asynchronous.
+ // NOTE: This method is intended to be called from the DB sequence. The UI
+ // sequence notifications are asynchronous.
virtual void NotifyOfMultipleAutofillChanges() = 0;
- // Notifies listeners on the UI thread that sync has started for |model_type|.
- // NOTE: This method is intended to be called from the DB thread. The UI
- // thread notifications are asynchronous.
+ // Notifies listeners on the UI sequence that sync has started for
+ // |model_type|.
+ // NOTE: This method is intended to be called from the DB sequence. The UI
+ // sequence notifications are asynchronous.
virtual void NotifyThatSyncHasStarted(syncer::ModelType model_type) = 0;
};
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 85bc2f308de..647258bc545 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -25,26 +25,27 @@ namespace autofill {
AutofillWebDataBackendImpl::AutofillWebDataBackendImpl(
scoped_refptr<WebDatabaseBackend> web_database_backend,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const base::Closure& on_changed_callback,
const base::Callback<void(syncer::ModelType)>& on_sync_started_callback)
- : base::RefCountedDeleteOnSequence<AutofillWebDataBackendImpl>(db_thread),
- ui_thread_(ui_thread),
- db_thread_(db_thread),
+ : base::RefCountedDeleteOnSequence<AutofillWebDataBackendImpl>(
+ db_task_runner),
+ ui_task_runner_(ui_task_runner),
+ db_task_runner_(db_task_runner),
web_database_backend_(web_database_backend),
on_changed_callback_(on_changed_callback),
on_sync_started_callback_(on_sync_started_callback) {}
void AutofillWebDataBackendImpl::AddObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnDBSequence* observer) {
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
db_observer_list_.AddObserver(observer);
}
void AutofillWebDataBackendImpl::RemoveObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnDBSequence* observer) {
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
db_observer_list_.RemoveObserver(observer);
}
@@ -53,7 +54,7 @@ AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
}
WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
return web_database_backend_->database();
}
@@ -64,30 +65,30 @@ void AutofillWebDataBackendImpl::RemoveExpiredFormElements() {
}
void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
- // DB thread notification.
+ // DB sequence notification.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillMultipleChanged();
- // UI thread notification.
- ui_thread_->PostTask(FROM_HERE, on_changed_callback_);
+ // UI sequence notification.
+ ui_task_runner_->PostTask(FROM_HERE, on_changed_callback_);
}
void AutofillWebDataBackendImpl::NotifyThatSyncHasStarted(
syncer::ModelType model_type) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (on_sync_started_callback_.is_null())
return;
- // UI thread notification.
- ui_thread_->PostTask(FROM_HERE,
- base::Bind(on_sync_started_callback_, model_type));
+ // UI sequence notification.
+ ui_task_runner_->PostTask(FROM_HERE,
+ base::Bind(on_sync_started_callback_, model_type));
}
base::SupportsUserData* AutofillWebDataBackendImpl::GetDBUserData() {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!user_data_)
user_data_.reset(new SupportsUserDataAggregatable());
return user_data_.get();
@@ -99,7 +100,7 @@ void AutofillWebDataBackendImpl::ResetUserData() {
WebDatabase::State AutofillWebDataBackendImpl::AddFormElements(
const std::vector<FormFieldData>& fields, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (!AutofillTable::FromWebDatabase(db)->AddFormFieldValues(
fields, &changes)) {
@@ -109,7 +110,7 @@ WebDatabase::State AutofillWebDataBackendImpl::AddFormElements(
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification will be
- // done on the DB thread, and not the UI thread.
+ // done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
@@ -122,7 +123,7 @@ AutofillWebDataBackendImpl::GetFormValuesForElementName(
const base::string16& prefix,
int limit,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<base::string16> values;
AutofillTable::FromWebDatabase(db)->GetFormValuesForElementName(
name, prefix, &values, limit);
@@ -134,7 +135,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween(
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (AutofillTable::FromWebDatabase(db)->RemoveFormElementsAddedBetween(
@@ -142,7 +143,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween(
if (!changes.empty()) {
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification
- // will be done on the DB thread, and not the UI thread.
+ // will be done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
}
@@ -153,7 +154,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormElementsAddedBetween(
WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName(
const base::string16& name, const base::string16& value, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->RemoveFormElement(name, value)) {
AutofillChangeList changes;
@@ -171,7 +172,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveFormValueForElementName(
WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile(
const AutofillProfile& profile, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddAutofillProfile(profile)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -188,7 +189,7 @@ WebDatabase::State AutofillWebDataBackendImpl::AddAutofillProfile(
WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile(
const AutofillProfile& profile, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
// Only perform the update if the profile exists. It is currently
// valid to try to update a missing profile. We simply drop the write and
// the caller will detect this on the next refresh.
@@ -213,7 +214,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillProfile(
WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile(
const std::string& guid, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::unique_ptr<AutofillProfile> profile =
AutofillTable::FromWebDatabase(db)->GetAutofillProfile(guid);
if (!profile) {
@@ -236,7 +237,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile(
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetAutofillProfiles(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
AutofillTable::FromWebDatabase(db)->GetAutofillProfiles(&profiles);
return std::unique_ptr<WDTypedResult>(
@@ -246,7 +247,7 @@ std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetAutofillProfiles(
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerProfiles(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
AutofillTable::FromWebDatabase(db)->GetServerProfiles(&profiles);
return std::unique_ptr<WDTypedResult>(
@@ -259,7 +260,7 @@ AutofillWebDataBackendImpl::GetCountOfValuesContainedBetween(
const base::Time& begin,
const base::Time& end,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
int value = AutofillTable::FromWebDatabase(db)
->GetCountOfValuesContainedBetween(begin, end);
return std::unique_ptr<WDTypedResult>(
@@ -269,7 +270,7 @@ AutofillWebDataBackendImpl::GetCountOfValuesContainedBetween(
WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillEntries(
const std::vector<AutofillEntry>& autofill_entries,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)
->UpdateAutofillEntries(autofill_entries))
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -279,7 +280,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateAutofillEntries(
WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard(
const CreditCard& credit_card, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddCreditCard(credit_card)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -294,7 +295,7 @@ WebDatabase::State AutofillWebDataBackendImpl::AddCreditCard(
WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard(
const CreditCard& credit_card, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
// It is currently valid to try to update a missing profile. We simply drop
// the write and the caller will detect this on the next refresh.
std::unique_ptr<CreditCard> original_credit_card =
@@ -316,7 +317,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard(
WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard(
const std::string& guid, WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->RemoveCreditCard(guid)) {
NOTREACHED();
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -332,7 +333,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard(
WebDatabase::State AutofillWebDataBackendImpl::AddFullServerCreditCard(
const CreditCard& credit_card,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->AddFullServerCreditCard(
credit_card)) {
NOTREACHED();
@@ -348,7 +349,7 @@ WebDatabase::State AutofillWebDataBackendImpl::AddFullServerCreditCard(
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCreditCards(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<CreditCard>> credit_cards;
AutofillTable::FromWebDatabase(db)->GetCreditCards(&credit_cards);
return std::unique_ptr<WDTypedResult>(
@@ -358,7 +359,7 @@ std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCreditCards(
std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerCreditCards(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<CreditCard>> credit_cards;
AutofillTable::FromWebDatabase(db)->GetServerCreditCards(&credit_cards);
return std::unique_ptr<WDTypedResult>(
@@ -370,7 +371,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UnmaskServerCreditCard(
const CreditCard& card,
const base::string16& full_number,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->UnmaskServerCreditCard(
card, full_number))
return WebDatabase::COMMIT_NEEDED;
@@ -381,7 +382,7 @@ WebDatabase::State
AutofillWebDataBackendImpl::MaskServerCreditCard(
const std::string& id,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->MaskServerCreditCard(id))
return WebDatabase::COMMIT_NEEDED;
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -390,7 +391,7 @@ WebDatabase::State
WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardMetadata(
const CreditCard& card,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->UpdateServerCardMetadata(card))
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -405,7 +406,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardMetadata(
WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata(
const AutofillProfile& profile,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!AutofillTable::FromWebDatabase(db)->UpdateServerAddressMetadata(
profile)) {
return WebDatabase::COMMIT_NOT_NEEDED;
@@ -421,7 +422,7 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata(
WebDatabase::State AutofillWebDataBackendImpl::ClearAllServerData(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (AutofillTable::FromWebDatabase(db)->ClearAllServerData()) {
NotifyOfMultipleAutofillChanges();
return WebDatabase::COMMIT_NEEDED;
@@ -434,7 +435,7 @@ WebDatabase::State
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::string> profile_guids;
std::vector<std::string> credit_card_guids;
if (AutofillTable::FromWebDatabase(db)->RemoveAutofillDataModifiedBetween(
@@ -465,7 +466,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveOriginURLsModifiedBetween(
const base::Time& delete_begin,
const base::Time& delete_end,
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<AutofillProfile>> profiles;
if (!AutofillTable::FromWebDatabase(db)->RemoveOriginURLsModifiedBetween(
delete_begin, delete_end, &profiles)) {
@@ -485,14 +486,14 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveOriginURLsModifiedBetween(
WebDatabase::State AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl(
WebDatabase* db) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
AutofillChangeList changes;
if (AutofillTable::FromWebDatabase(db)->RemoveExpiredFormElements(&changes)) {
if (!changes.empty()) {
// Post the notifications including the list of affected keys.
// This is sent here so that work resulting from this notification
- // will be done on the DB thread, and not the UI thread.
+ // will be done on the DB sequence, and not the UI sequence.
for (auto& db_observer : db_observer_list_)
db_observer.AutofillEntriesChanged(changes);
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
index 4a995a4689c..3720bd72214 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
@@ -29,45 +29,46 @@ class WebDatabaseBackend;
namespace autofill {
class AutofillProfile;
-class AutofillWebDataServiceObserverOnDBThread;
+class AutofillWebDataServiceObserverOnDBSequence;
class CreditCard;
// Backend implentation for the AutofillWebDataService. This class runs on the
-// DB thread, as it handles reads and writes to the WebDatabase, and functions
-// in it should only be called from that thread. Most functions here are just
+// DB sequence, as it handles reads and writes to the WebDatabase, and functions
+// in it should only be called from that sequence. Most functions here are just
// the implementations of the corresponding functions in the Autofill
// WebDataService.
-// This class is destroyed on the DB thread.
+// This class is destroyed on the DB sequence.
class AutofillWebDataBackendImpl
: public base::RefCountedDeleteOnSequence<AutofillWebDataBackendImpl>,
public AutofillWebDataBackend {
public:
// |web_database_backend| is used to access the WebDatabase directly for
- // Sync-related operations. |ui_thread| and |db_thread| are the threads that
- // this class uses as its UI and DB threads respectively.
+ // Sync-related operations. |ui_task_runner| and |db_task_runner| are the task
+ // runners that this class uses for UI and DB tasks respectively.
// |on_changed_callback| is a closure which can be used to notify the UI
- // thread of changes initiated by Sync (this callback may be called multiple
+ // sequence of changes initiated by Sync (this callback may be called multiple
// times).
AutofillWebDataBackendImpl(
scoped_refptr<WebDatabaseBackend> web_database_backend,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const base::Closure& on_changed_callback,
const base::Callback<void(syncer::ModelType)>& on_sync_started_callback);
// AutofillWebDataBackend implementation.
- void AddObserver(AutofillWebDataServiceObserverOnDBThread* observer) override;
+ void AddObserver(
+ AutofillWebDataServiceObserverOnDBSequence* observer) override;
void RemoveObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) override;
+ AutofillWebDataServiceObserverOnDBSequence* observer) override;
WebDatabase* GetDatabase() override;
void RemoveExpiredFormElements() override;
void NotifyOfMultipleAutofillChanges() override;
void NotifyThatSyncHasStarted(syncer::ModelType model_type) override;
- // Returns a SupportsUserData objects that may be used to store data
- // owned by the DB thread on this object. Should be called only from
- // the DB thread, and will be destroyed on the DB thread soon after
- // |ShutdownOnUIThread()| is called.
+ // Returns a SupportsUserData object that may be used to store data accessible
+ // from the DB sequence. Should be called only from the DB sequence, and will
+ // be destroyed on the DB sequence soon after ShutdownOnUISequence() is
+ // called.
base::SupportsUserData* GetDBUserData();
void ResetUserData();
@@ -198,20 +199,20 @@ class AutofillWebDataBackendImpl
DISALLOW_COPY_AND_ASSIGN(SupportsUserDataAggregatable);
};
- // The task runner that this class uses as its UI thread.
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
+ // The task runner that this class uses for its UI tasks.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
- // The task runner that this class uses as its DB thread.
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ // The task runner that this class uses for its DB tasks.
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
- // Storage for user data to be accessed only on the DB thread. May
+ // Storage for user data to be accessed only on the DB sequence. May
// be used e.g. for SyncableService subclasses that need to be owned
// by this object. Is created on first call to |GetDBUserData()|.
std::unique_ptr<SupportsUserDataAggregatable> user_data_;
WebDatabase::State RemoveExpiredFormElementsImpl(WebDatabase* db);
- base::ObserverList<AutofillWebDataServiceObserverOnDBThread>
+ base::ObserverList<AutofillWebDataServiceObserverOnDBSequence>
db_observer_list_;
// WebDatabaseBackend allows direct access to DB.
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 dcb9c831216..2752366cbe6 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -28,46 +28,47 @@ namespace autofill {
AutofillWebDataService::AutofillWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const ProfileErrorCallback& callback)
- : WebDataServiceBase(wdbs, callback, ui_thread),
- ui_thread_(ui_thread),
- db_thread_(db_thread),
+ : WebDataServiceBase(wdbs, callback, ui_task_runner),
+ ui_task_runner_(ui_task_runner),
+ db_task_runner_(db_task_runner),
autofill_backend_(nullptr),
weak_ptr_factory_(this) {
- base::Closure on_changed_callback = Bind(
- &AutofillWebDataService::NotifyAutofillMultipleChangedOnUIThread,
- weak_ptr_factory_.GetWeakPtr());
- base::Callback<void(syncer::ModelType)> on_sync_started_callback = Bind(
- &AutofillWebDataService::NotifySyncStartedOnUIThread,
- weak_ptr_factory_.GetWeakPtr());
+ base::Closure on_changed_callback =
+ Bind(&AutofillWebDataService::NotifyAutofillMultipleChangedOnUISequence,
+ weak_ptr_factory_.GetWeakPtr());
+ base::Callback<void(syncer::ModelType)> on_sync_started_callback =
+ Bind(&AutofillWebDataService::NotifySyncStartedOnUISequence,
+ weak_ptr_factory_.GetWeakPtr());
autofill_backend_ = new AutofillWebDataBackendImpl(
- wdbs_->GetBackend(), ui_thread_, db_thread_, on_changed_callback,
- on_sync_started_callback);
+ wdbs_->GetBackend(), ui_task_runner_, db_task_runner_,
+ on_changed_callback, on_sync_started_callback);
}
AutofillWebDataService::AutofillWebDataService(
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread)
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner)
: WebDataServiceBase(nullptr,
WebDataServiceBase::ProfileErrorCallback(),
- ui_thread),
- ui_thread_(ui_thread),
- db_thread_(db_thread),
+ ui_task_runner),
+ ui_task_runner_(ui_task_runner),
+ db_task_runner_(db_task_runner),
autofill_backend_(new AutofillWebDataBackendImpl(
nullptr,
- ui_thread_,
- db_thread_,
+ ui_task_runner_,
+ db_task_runner_,
base::Closure(),
base::Callback<void(syncer::ModelType)>())),
weak_ptr_factory_(this) {}
-void AutofillWebDataService::ShutdownOnUIThread() {
+void AutofillWebDataService::ShutdownOnUISequence() {
weak_ptr_factory_.InvalidateWeakPtrs();
- db_thread_->PostTask(FROM_HERE,
+ db_task_runner_->PostTask(
+ FROM_HERE,
Bind(&AutofillWebDataBackendImpl::ResetUserData, autofill_backend_));
- WebDataServiceBase::ShutdownOnUIThread();
+ WebDataServiceBase::ShutdownOnUISequence();
}
void AutofillWebDataService::AddFormFields(
@@ -251,54 +252,58 @@ void AutofillWebDataService::RemoveOriginURLsModifiedBetween(
}
void AutofillWebDataService::AddObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnDBSequence* observer) {
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (autofill_backend_.get())
autofill_backend_->AddObserver(observer);
}
void AutofillWebDataService::RemoveObserver(
- AutofillWebDataServiceObserverOnDBThread* observer) {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnDBSequence* observer) {
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (autofill_backend_.get())
autofill_backend_->RemoveObserver(observer);
}
void AutofillWebDataService::AddObserver(
- AutofillWebDataServiceObserverOnUIThread* observer) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnUISequence* observer) {
+ DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
ui_observer_list_.AddObserver(observer);
}
void AutofillWebDataService::RemoveObserver(
- AutofillWebDataServiceObserverOnUIThread* observer) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ AutofillWebDataServiceObserverOnUISequence* observer) {
+ DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
ui_observer_list_.RemoveObserver(observer);
}
base::SupportsUserData* AutofillWebDataService::GetDBUserData() {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
return autofill_backend_->GetDBUserData();
}
void AutofillWebDataService::GetAutofillBackend(
const base::Callback<void(AutofillWebDataBackend*)>& callback) {
- db_thread_->PostTask(
+ db_task_runner_->PostTask(
FROM_HERE, base::Bind(callback, base::RetainedRef(autofill_backend_)));
}
+base::SingleThreadTaskRunner* AutofillWebDataService::GetDBTaskRunner() {
+ return db_task_runner_.get();
+}
+
AutofillWebDataService::~AutofillWebDataService() {
}
-void AutofillWebDataService::NotifyAutofillMultipleChangedOnUIThread() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+void AutofillWebDataService::NotifyAutofillMultipleChangedOnUISequence() {
+ DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
for (auto& ui_observer : ui_observer_list_)
ui_observer.AutofillMultipleChanged();
}
-void AutofillWebDataService::NotifySyncStartedOnUIThread(
+void AutofillWebDataService::NotifySyncStartedOnUISequence(
syncer::ModelType model_type) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
for (auto& ui_observer : ui_observer_list_)
ui_observer.SyncStarted(model_type);
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
index 810af1b7dd7..f6d265b36ec 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -32,23 +32,25 @@ class AutofillEntry;
class AutofillProfile;
class AutofillWebDataBackend;
class AutofillWebDataBackendImpl;
-class AutofillWebDataServiceObserverOnDBThread;
-class AutofillWebDataServiceObserverOnUIThread;
+class AutofillWebDataServiceObserverOnDBSequence;
+class AutofillWebDataServiceObserverOnUISequence;
class CreditCard;
// API for Autofill web data.
class AutofillWebDataService : public AutofillWebData,
public WebDataServiceBase {
public:
- AutofillWebDataService(scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread);
- AutofillWebDataService(scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
- const ProfileErrorCallback& callback);
+ AutofillWebDataService(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner);
+ AutofillWebDataService(
+ scoped_refptr<WebDatabaseService> wdbs,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
+ const ProfileErrorCallback& callback);
// WebDataServiceBase implementation.
- void ShutdownOnUIThread() override;
+ void ShutdownOnUISequence() override;
// AutofillWebData implementation.
void AddFormFields(const std::vector<FormFieldData>& fields) override;
@@ -106,49 +108,53 @@ class AutofillWebDataService : public AutofillWebData,
void RemoveOriginURLsModifiedBetween(const base::Time& delete_begin,
const base::Time& delete_end) override;
- void AddObserver(AutofillWebDataServiceObserverOnDBThread* observer);
- void RemoveObserver(AutofillWebDataServiceObserverOnDBThread* observer);
+ void AddObserver(AutofillWebDataServiceObserverOnDBSequence* observer);
+ void RemoveObserver(AutofillWebDataServiceObserverOnDBSequence* observer);
- void AddObserver(AutofillWebDataServiceObserverOnUIThread* observer);
- void RemoveObserver(AutofillWebDataServiceObserverOnUIThread* observer);
+ void AddObserver(AutofillWebDataServiceObserverOnUISequence* observer);
+ void RemoveObserver(AutofillWebDataServiceObserverOnUISequence* observer);
- // Returns a SupportsUserData objects that may be used to store data
- // owned by the DB thread on this object. Should be called only from
- // the DB thread, and will be destroyed on the DB thread soon after
- // |ShutdownOnUIThread()| is called.
+ // Returns a SupportsUserData object that may be used to store data accessible
+ // from the DB sequence. Should be called only from the DB sequence, and will
+ // be destroyed on the DB sequence soon after ShutdownOnUISequence() is
+ // called.
base::SupportsUserData* GetDBUserData();
- // Takes a callback which will be called on the DB thread with a pointer to an
- // |AutofillWebdataBackend|. This backend can be used to access or update the
- // WebDatabase directly on the DB thread.
+ // Takes a callback which will be called on the DB sequence with a pointer to
+ // an AutofillWebdataBackend. This backend can be used to access or update the
+ // WebDatabase directly on the DB sequence.
void GetAutofillBackend(
const base::Callback<void(AutofillWebDataBackend*)>& callback);
+ // Returns a task runner that can be used to schedule tasks on the DB
+ // sequence.
+ base::SingleThreadTaskRunner* GetDBTaskRunner();
+
protected:
~AutofillWebDataService() override;
- virtual void NotifyAutofillMultipleChangedOnUIThread();
+ virtual void NotifyAutofillMultipleChangedOnUISequence();
- virtual void NotifySyncStartedOnUIThread(syncer::ModelType model_type);
+ virtual void NotifySyncStartedOnUISequence(syncer::ModelType model_type);
base::WeakPtr<AutofillWebDataService> AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
- base::ObserverList<AutofillWebDataServiceObserverOnUIThread>
+ base::ObserverList<AutofillWebDataServiceObserverOnUISequence>
ui_observer_list_;
- // The task runner that this class uses as its UI thread.
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
+ // The task runner that this class uses for UI tasks.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
- // The task runner that this class uses as its DB thread.
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ // The task runner that this class uses for DB tasks.
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
scoped_refptr<AutofillWebDataBackendImpl> autofill_backend_;
- // This factory is used on the UI thread. All vended weak pointers are
- // invalidated in ShutdownOnUIThread().
+ // This factory is used on the UI sequence. All vended weak pointers are
+ // invalidated in ShutdownOnUISequence().
base::WeakPtrFactory<AutofillWebDataService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AutofillWebDataService);
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
index f5d0605ebb0..94805a9a999 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
@@ -10,38 +10,38 @@
namespace autofill {
-class AutofillWebDataServiceObserverOnDBThread {
+class AutofillWebDataServiceObserverOnDBSequence {
public:
- // Called on DB thread whenever Autofill entries are changed.
+ // Called on DB sequence whenever Autofill entries are changed.
virtual void AutofillEntriesChanged(const AutofillChangeList& changes) {}
- // Called on DB thread when an AutofillProfile has been added/removed/updated
- // in the WebDatabase.
+ // Called on DB sequence when an AutofillProfile has been
+ // added/removed/updated in the WebDatabase.
virtual void AutofillProfileChanged(const AutofillProfileChange& change) {}
- // Called on DB thread when a CreditCard has been added/removed/updated in the
- // WebDatabase.
+ // Called on DB sequence when a CreditCard has been added/removed/updated in
+ // the WebDatabase.
virtual void CreditCardChanged(const CreditCardChange& change) {}
- // Called on DB thread when multiple Autofill entries have been modified by
+ // Called on DB sequence when multiple Autofill entries have been modified by
// Sync.
virtual void AutofillMultipleChanged() {}
protected:
- virtual ~AutofillWebDataServiceObserverOnDBThread() {}
+ virtual ~AutofillWebDataServiceObserverOnDBSequence() {}
};
-class AutofillWebDataServiceObserverOnUIThread {
+class AutofillWebDataServiceObserverOnUISequence {
public:
- // Called on UI thread when multiple Autofill entries have been modified by
+ // Called on UI sequence when multiple Autofill entries have been modified by
// Sync.
virtual void AutofillMultipleChanged() {}
- // Called on UI thread when sync has started for |model_type|.
+ // Called on UI sequence when sync has started for |model_type|.
virtual void SyncStarted(syncer::ModelType /* model_type */) {}
protected:
- virtual ~AutofillWebDataServiceObserverOnUIThread() {}
+ virtual ~AutofillWebDataServiceObserverOnUISequence() {}
};
} // namespace autofill
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 f0abd6f94fa..03dc2e3234a 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
@@ -12,15 +12,13 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_scheduler.h"
#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_country.h"
@@ -60,8 +58,6 @@ class AutofillWebDataServiceConsumer: public WebDataServiceConsumer {
std::unique_ptr<WDTypedResult> result) {
handle_ = handle;
result_ = std::move(static_cast<WDResult<T>*>(result.get())->GetValue());
-
- base::MessageLoop::current()->QuitWhenIdle();
}
WebDataServiceBase::Handle handle() { return handle_; }
@@ -84,7 +80,7 @@ ACTION_P(SignalEvent, event) {
}
class MockAutofillWebDataServiceObserver
- : public AutofillWebDataServiceObserverOnDBThread {
+ : public AutofillWebDataServiceObserverOnDBSequence {
public:
MOCK_METHOD1(AutofillEntriesChanged,
void(const AutofillChangeList& changes));
@@ -96,51 +92,38 @@ class WebDataServiceTest : public testing::Test {
public:
WebDataServiceTest()
: scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI),
- db_thread_("DBThread") {}
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
protected:
void SetUp() override {
- db_thread_.Start();
-
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ // TODO(pkasting): http://crbug.com/740773 This should likely be sequenced,
+ // not single-threaded; it's also possible the various uses of this below
+ // should each use their own sequences instead of sharing this one.
+ auto db_task_runner =
+ base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()});
wdbs_ = new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
- db_thread_.task_runner());
+ db_task_runner);
wdbs_->AddTable(base::WrapUnique(new AutofillTable));
wdbs_->LoadDatabase();
wds_ = new AutofillWebDataService(
- wdbs_, base::ThreadTaskRunnerHandle::Get(), db_thread_.task_runner(),
+ wdbs_, base::ThreadTaskRunnerHandle::Get(), db_task_runner,
WebDataServiceBase::ProfileErrorCallback());
wds_->Init();
}
void TearDown() override {
- wds_->ShutdownOnUIThread();
+ wds_->ShutdownOnUISequence();
wdbs_->ShutdownDatabase();
wds_ = NULL;
wdbs_ = NULL;
- WaitForDatabaseThread();
-
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
- base::RunLoop().Run();
- db_thread_.Stop();
- }
-
- void WaitForDatabaseThread() {
- base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- db_thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
- done.Wait();
+ scoped_task_environment_.RunUntilIdle();
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
- base::Thread db_thread_;
base::FilePath profile_dir_;
scoped_refptr<AutofillWebDataService> wds_;
scoped_refptr<WebDatabaseService> wdbs_;
@@ -165,21 +148,20 @@ class WebDataServiceAutofillTest : public WebDataServiceTest {
value1_ = ASCIIToUTF16("value1");
value2_ = ASCIIToUTF16("value2");
- void(AutofillWebDataService::*add_observer_func)(
- AutofillWebDataServiceObserverOnDBThread*) =
+ void (AutofillWebDataService::*add_observer_func)(
+ AutofillWebDataServiceObserverOnDBSequence*) =
&AutofillWebDataService::AddObserver;
- db_thread_.task_runner()->PostTask(
+ wds_->GetDBTaskRunner()->PostTask(
FROM_HERE, base::Bind(add_observer_func, wds_, &observer_));
- WaitForDatabaseThread();
+ base::TaskScheduler::GetInstance()->FlushForTesting();
}
virtual void TearDown() {
- void(AutofillWebDataService::*remove_observer_func)(
- AutofillWebDataServiceObserverOnDBThread*) =
+ void (AutofillWebDataService::*remove_observer_func)(
+ AutofillWebDataServiceObserverOnDBSequence*) =
&AutofillWebDataService::RemoveObserver;
- db_thread_.task_runner()->PostTask(
+ wds_->GetDBTaskRunner()->PostTask(
FROM_HERE, base::Bind(remove_observer_func, wds_, &observer_));
- WaitForDatabaseThread();
WebDataServiceTest::TearDown();
}
@@ -228,10 +210,7 @@ TEST_F(WebDataServiceAutofillTest, FormFillAdd) {
static const int limit = 10;
handle = wds_->GetFormValuesForElementName(
name1_, base::string16(), limit, &consumer);
-
- // The message loop will exit when the consumer is called.
- base::RunLoop().Run();
-
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(value1_, consumer.result()[0]);
@@ -308,7 +287,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileAdd) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
@@ -327,7 +306,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
@@ -346,7 +325,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(0U, consumer2.result().size());
}
@@ -372,7 +351,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(profile2, *consumer.result()[0]);
@@ -394,7 +373,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(2U, consumer2.result().size());
EXPECT_EQ(profile2_changed, *consumer2.result()[0]);
@@ -405,13 +384,12 @@ TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
TEST_F(WebDataServiceAutofillTest, CreditAdd) {
CreditCard card;
wds_->AddCreditCard(card);
- WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(card, *consumer.result()[0]);
@@ -422,26 +400,24 @@ TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
// Add a credit card.
wds_->AddCreditCard(credit_card);
- WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(credit_card, *consumer.result()[0]);
// Remove the credit card.
wds_->RemoveCreditCard(credit_card.guid());
- WaitForDatabaseThread();
// Check that it was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(0U, consumer2.result().size());
}
@@ -456,13 +432,12 @@ TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
wds_->AddCreditCard(card1);
wds_->AddCreditCard(card2);
- WaitForDatabaseThread();
// Check that they got added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(card2, *consumer.result()[0]);
@@ -472,13 +447,12 @@ TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
card2_changed.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Bill"));
wds_->UpdateCreditCard(card2_changed);
- WaitForDatabaseThread();
// Check that the updates were made.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(2U, consumer2.result().size());
EXPECT_NE(card2, *consumer2.result()[0]);
@@ -499,7 +473,7 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
profile_consumer;
WebDataServiceBase::Handle handle =
wds_->GetAutofillProfiles(&profile_consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, profile_consumer.handle());
ASSERT_EQ(1U, profile_consumer.result().size());
EXPECT_EQ(profile, *profile_consumer.result()[0]);
@@ -507,13 +481,12 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
// Add a credit card.
CreditCard credit_card;
wds_->AddCreditCard(credit_card);
- WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
card_consumer;
handle = wds_->GetCreditCards(&card_consumer);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle, card_consumer.handle());
ASSERT_EQ(1U, card_consumer.result().size());
EXPECT_EQ(credit_card, *card_consumer.result()[0]);
@@ -527,14 +500,13 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
// Remove the profile using time range of "all time".
wds_->RemoveAutofillDataModifiedBetween(Time(), Time());
done_event_.TimedWait(test_timeout_);
- WaitForDatabaseThread();
// Check that the profile was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
profile_consumer2;
WebDataServiceBase::Handle handle2 =
wds_->GetAutofillProfiles(&profile_consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, profile_consumer2.handle());
ASSERT_EQ(0U, profile_consumer2.result().size());
@@ -542,7 +514,7 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
card_consumer2;
handle2 = wds_->GetCreditCards(&card_consumer2);
- base::RunLoop().Run();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(handle2, card_consumer2.handle());
ASSERT_EQ(0U, card_consumer2.result().size());
}
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc
index e53c160b3be..5143e3f65f9 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data.cc
@@ -89,9 +89,14 @@ void InitPasswordFormFillData(
}
PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data) {
+ // In case when there is a username on a page (for example in a hidden field),
+ // credentials from |additional_logins| could be used for filling on load. So
+ // in case of filling on load nor |password_field| nor |additional_logins|
+ // can't be cleared
+ if (!data.wait_for_username)
+ return data;
PasswordFormFillData result(data);
- if (result.wait_for_username)
- result.password_field.value.clear();
+ result.password_field.value.clear();
for (auto& credentials : result.additional_logins)
credentials.second.password.clear();
return result;
diff --git a/chromium/components/autofill_strings.grdp b/chromium/components/autofill_strings.grdp
index 16fd55452af..919fb970cb6 100644
--- a/chromium/components/autofill_strings.grdp
+++ b/chromium/components/autofill_strings.grdp
@@ -63,7 +63,7 @@
<message name="IDS_AUTOFILL_CC_DISCOVER" desc="Discover credit card name." formatter_data="android_java">
Discover
</message>
- <message name="IDS_AUTOFILL_CC_ELO" desc="Elo credit card name." formatter_data="android_java">
+ <message name="IDS_AUTOFILL_CC_ELO" desc="Elo credit card name.">
Elo
</message>
<message name="IDS_AUTOFILL_CC_JCB" desc="JCB credit card name." formatter_data="android_java">
@@ -128,16 +128,6 @@
Postal code
</message>
- <message translateable="false" name="IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE" desc="The title for form elements when annotated with Autofill predictions.">
- overall type: <ph name="OVERALL_TYPE">$1<ex>NAME_FIRST</ex></ph>
- server type: <ph name="SERVER_TYPE">$2<ex>NAME_FIRST</ex></ph>
- heuristic type: <ph name="HEURISTIC_TYPE">$3<ex>NAME_FIRST</ex></ph>
- label: <ph name="LABEL">$4<ex>SOME LABEL</ex></ph>
- parseable name: <ph name="PARSEABLE_NAME">$5<ex>SOME_NAME</ex></ph>
- field signature: <ph name="FIELD_SIGNATURE">$6<ex>12345678</ex></ph>
- form signature: <ph name="FORM_SIGNATURE">$7<ex>1234567812345678</ex></ph>
- </message>
-
<if expr="_google_chrome">
<message name="IDS_AUTOFILL_OPTIONS_POPUP" desc="The text displayed in the Autofill popup to direct the user to the Autofill settings UI.">
Chrome Autofill settings...
@@ -176,6 +166,10 @@
Login not secure
</message>
+ <message name="IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK" desc="The text shown as an option in the suggestion drop down when a password field is clicked">
+ Show all saved passwords...
+ </message>
+
<!-- Autofill Credit Card Assisted Filling Infobar -->
<if expr="is_android">
<message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE" desc="Title text for the Autofill Credit Card Assisted Filling Infobar">
@@ -197,6 +191,12 @@
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT" desc="Text to show for the Autofill save credit card prompt accept button. The prompt can be either a bubble or an infobar.">
Save
</message>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_NEXT" desc="Text to show for the Autofill upload save credit card prompt accept button when more information (e.g., CVC) is needed in order to save the card.">
+ Next
+ </message>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CONFIRM" desc="Text to show for the Autofill upload save credit card prompt accept button when more information (e.g., CVC) was needed in order to save the card and was entered.">
+ Confirm
+ </message>
<if expr="_google_chrome">
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
Do you want Chrome to save this card?
@@ -207,24 +207,41 @@
Do you want Chromium to save this card?
</message>
</if>
- <if expr="is_linux and not is_chromeos">
+ <if expr="is_linux and not chromeos">
<then>
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
Do you want to save this card to your Google Account?
</message>
</then>
<else>
- <!-- TODO(crbug/714920): Rename IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD to IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_AND_LOCAL -->
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
Do you want to save this card to your Google Account and on this device?
</message>
</else>
</if>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V2" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to June 2017 UI guidelines. The prompt can be either a bubble or an infobar.">
+ Save card to Google?
+ </message>
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
Pay quickly on sites and apps across devices using cards you have saved with Google.
</message>
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC" desc="Text displayed in the Autofill save credit card prompt explaining that the card needs additional CVC information in order to be saved to Google Payments.">
- Please verify your CVC
+ <if expr="is_linux and not chromeos">
+ <then>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to June 2017 UI guidelines. The prompt will be shown in a bubble below the omnibox.">
+ To pay faster next time, save this card to your Google Account.
+ </message>
+ </then>
+ <else>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally, according to June 2017 UI guidelines. The prompt can be either a bubble or an infobar.">
+ To pay faster next time, save this card to your Google Account and to this device.
+ </message>
+ </else>
+ </if>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_TITLE" desc="Title text to show for the Autofill upload save credit card prompt when more information (e.g., CVC) is needed in order to save the card.">
+ Confirm security code
+ </message>
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_EXPLANATION" desc="Text displayed in the Autofill save credit card prompt requesting the additional CVC information needed in order to save the card to Google Payments. It will display the network and last four digits of the card to be saved.">
+ Enter the security code for <ph name="CREDIT_CARD">$1<ex>Visa ****5678</ex></ph>. This code won't be saved.
</message>
<!-- Autofill credit card suggestion popup -->
@@ -328,12 +345,12 @@
</if>
<if expr="is_ios">
<if expr="_google_chrome">
- <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP" desc="Text that provides further explanation on iOS for the option in the card unmasking dialog that allows user to store a Wallet card on their local device." formatter_data="android_java">
+ <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP" desc="Text that provides further explanation on iOS for the option in the card unmasking dialog that allows user to store a Wallet card on their local device.">
If enabled, Chrome will store a copy of your card on this device for faster form filling.
</message>
</if>
<if expr="not _google_chrome">
- <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP" desc="Text that provides further explanation on iOS for the option in the card unmasking dialog that allows user to store a Wallet card on their local device." formatter_data="android_java">
+ <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP" desc="Text that provides further explanation on iOS for the option in the card unmasking dialog that allows user to store a Wallet card on their local device.">
If enabled, Chromium will store a copy of your card on this device for faster form filling.
</message>
</if>
diff --git a/chromium/components/background_task_scheduler/BUILD.gn b/chromium/components/background_task_scheduler/BUILD.gn
index f77a15cc244..cbf1271e80c 100644
--- a/chromium/components/background_task_scheduler/BUILD.gn
+++ b/chromium/components/background_task_scheduler/BUILD.gn
@@ -25,10 +25,12 @@ if (is_android) {
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTask.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java",
+ "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskReflection.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java",
+ "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefs.java",
"android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java",
@@ -39,9 +41,12 @@ if (is_android) {
]
deps = [
+ "$google_play_services_package:google_play_services_base_java",
+ "$google_play_services_package:google_play_services_basement_java",
+ "$google_play_services_package:google_play_services_gcm_java",
+ "$google_play_services_package:google_play_services_tasks_java",
"//base:base_java",
"//third_party/android_tools:android_support_annotations_java",
- google_play_services_library,
]
}
@@ -55,11 +60,14 @@ if (is_android) {
deps = [
":background_task_scheduler_java",
+ "$google_play_services_package:google_play_services_base_java",
+ "$google_play_services_package:google_play_services_basement_java",
+ "$google_play_services_package:google_play_services_gcm_java",
+ "$google_play_services_package:google_play_services_tasks_java",
"//base:base_java",
"//base:base_java_test_support",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit",
- google_play_services_library,
]
}
@@ -67,8 +75,8 @@ if (is_android) {
java_files = [
"android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManagerTest.java",
"android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskServiceTest.java",
+ "android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplTest.java",
"android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefsTest.java",
- "android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerTest.java",
"android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java",
"android/junit/src/org/chromium/components/background_task_scheduler/ShadowGcmNetworkManager.java",
"android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTask.java",
@@ -76,10 +84,14 @@ if (is_android) {
deps = [
":background_task_scheduler_java",
+ "$google_play_services_package:google_play_services_auth_base_java",
+ "$google_play_services_package:google_play_services_base_java",
+ "$google_play_services_package:google_play_services_basement_java",
+ "$google_play_services_package:google_play_services_gcm_java",
+ "$google_play_services_package:google_play_services_tasks_java",
"//base:base_java",
"//base:base_java_test_support",
"//third_party/junit",
- google_play_services_library,
]
srcjar_deps = [ "//base:base_build_config_gen" ]
}
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.cc b/chromium/components/bookmarks/browser/bookmark_codec.cc
index 97ede4fda55..830c55150c2 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec.cc
@@ -158,7 +158,7 @@ std::unique_ptr<base::Value> BookmarkCodec::EncodeMetaInfo(
auto meta_info = base::MakeUnique<base::DictionaryValue>();
for (BookmarkNode::MetaInfoMap::const_iterator it = meta_info_map.begin();
it != meta_info_map.end(); ++it) {
- meta_info->SetStringWithoutPathExpansion(it->first, it->second);
+ meta_info->SetKey(it->first, base::Value(it->second));
}
return std::move(meta_info);
}
diff --git a/chromium/components/bookmarks/common/android/bookmark_id.cc b/chromium/components/bookmarks/common/android/bookmark_id.cc
index 2f00de64afa..8595708ce0b 100644
--- a/chromium/components/bookmarks/common/android/bookmark_id.cc
+++ b/chromium/components/bookmarks/common/android/bookmark_id.cc
@@ -9,11 +9,13 @@
namespace bookmarks {
namespace android {
-long JavaBookmarkIdGetId(JNIEnv* env, jobject obj) {
+long JavaBookmarkIdGetId(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj) {
return Java_BookmarkId_getId(env, obj);
}
-int JavaBookmarkIdGetType(JNIEnv* env, jobject obj) {
+int JavaBookmarkIdGetType(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj) {
return Java_BookmarkId_getType(env, obj);
}
diff --git a/chromium/components/bookmarks/common/android/bookmark_id.h b/chromium/components/bookmarks/common/android/bookmark_id.h
index dc9bada7f41..e07da9a4348 100644
--- a/chromium/components/bookmarks/common/android/bookmark_id.h
+++ b/chromium/components/bookmarks/common/android/bookmark_id.h
@@ -13,10 +13,12 @@ namespace bookmarks {
namespace android {
// See BookmarkId#getId
-long JavaBookmarkIdGetId(JNIEnv* env, jobject obj);
+long JavaBookmarkIdGetId(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
// See BookmarkId#getType
-int JavaBookmarkIdGetType(JNIEnv* env, jobject obj);
+int JavaBookmarkIdGetType(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
// See BookmarkId#createBookmarkId
base::android::ScopedJavaLocalRef<jobject> JavaBookmarkIdCreateBookmarkId(
diff --git a/chromium/components/browser_sync/abstract_profile_sync_service_test.cc b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
index d0346007328..94f81f7a8a3 100644
--- a/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -10,7 +10,6 @@
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/browser_sync/test_http_bridge_factory.h"
@@ -34,7 +33,7 @@ namespace {
std::unique_ptr<syncer::HttpPostProviderFactory> GetHttpPostProviderFactory(
syncer::CancelationSignal* signal) {
- return base::MakeUnique<TestHttpBridgeFactory>();
+ return std::make_unique<TestHttpBridgeFactory>();
}
class SyncEngineForProfileSyncTest : public SyncBackendHostImpl {
@@ -79,7 +78,7 @@ SyncEngineForProfileSyncTest::~SyncEngineForProfileSyncTest() {}
void SyncEngineForProfileSyncTest::Initialize(InitParams params) {
params.http_factory_getter = base::Bind(&GetHttpPostProviderFactory);
params.sync_manager_factory =
- base::MakeUnique<syncer::SyncManagerFactoryForProfileSyncTest>(callback_);
+ std::make_unique<syncer::SyncManagerFactoryForProfileSyncTest>(callback_);
params.credentials.email = "testuser@gmail.com";
params.credentials.sync_token = "token";
params.credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
@@ -91,7 +90,7 @@ void SyncEngineForProfileSyncTest::Initialize(InitParams params) {
syncer::EngineComponentsFactory::Switches factory_switches =
params.engine_components_factory->GetSwitches();
params.engine_components_factory =
- base::MakeUnique<syncer::TestEngineComponentsFactory>(
+ std::make_unique<syncer::TestEngineComponentsFactory>(
factory_switches, syncer::EngineComponentsFactory::STORAGE_IN_MEMORY,
nullptr);
@@ -167,7 +166,7 @@ void AbstractProfileSyncServiceTest::CreateSyncService(
profile_sync_service_bundle_.CreateBasicInitParams(
ProfileSyncService::AUTO_START, std::move(sync_client));
sync_service_ =
- base::MakeUnique<TestProfileSyncService>(std::move(init_params));
+ std::make_unique<TestProfileSyncService>(std::move(init_params));
syncer::SyncApiComponentFactoryMock* components =
profile_sync_service_bundle_.component_factory();
diff --git a/chromium/components/browser_sync/abstract_profile_sync_service_test.h b/chromium/components/browser_sync/abstract_profile_sync_service_test.h
index f7d3d12a294..2171b687c18 100644
--- a/chromium/components/browser_sync/abstract_profile_sync_service_test.h
+++ b/chromium/components/browser_sync/abstract_profile_sync_service_test.h
@@ -13,7 +13,7 @@
#include "base/callback.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/test/test_message_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "components/browser_sync/profile_sync_test_util.h"
#include "components/sync/base/model_type.h"
#include "components/sync/syncable/change_record.h"
@@ -72,7 +72,7 @@ class AbstractProfileSyncServiceTest : public testing::Test {
// Use |data_type_thread_| for code disallowed on the UI thread.
base::Thread data_type_thread_;
- base::TestMessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
ProfileSyncServiceBundle profile_sync_service_bundle_;
std::unique_ptr<TestProfileSyncService> sync_service_;
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 03f74739635..2832a752c68 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
@@ -45,6 +44,7 @@
#include "components/sync_bookmarks/bookmark_change_processor.h"
#include "components/sync_bookmarks/bookmark_data_type_controller.h"
#include "components/sync_bookmarks/bookmark_model_associator.h"
+#include "components/sync_bookmarks/bookmark_model_type_controller.h"
#include "components/sync_sessions/session_data_type_controller.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "google_apis/gaia/oauth2_token_service_request.h"
@@ -145,11 +145,11 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// Use an error callback that always uploads a stacktrace if it can to help
// get USS as stable as possible.
sync_service->RegisterDataTypeController(
- base::MakeUnique<ModelTypeController>(syncer::DEVICE_INFO, sync_client_,
+ std::make_unique<ModelTypeController>(syncer::DEVICE_INFO, sync_client_,
ui_thread_));
} else {
sync_service->RegisterDataTypeController(
- base::MakeUnique<DeviceInfoDataTypeController>(
+ std::make_unique<DeviceInfoDataTypeController>(
error_callback, sync_client_,
sync_service->GetLocalDeviceInfoProvider()));
}
@@ -161,13 +161,13 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!disabled_types.Has(syncer::AUTOFILL)) {
if (FeatureList::IsEnabled(switches::kSyncUSSAutocomplete)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<autofill::WebDataModelTypeController>(
+ std::make_unique<autofill::WebDataModelTypeController>(
syncer::AUTOFILL, sync_client_, db_thread_, web_data_service_,
base::Bind(
&autofill::AutocompleteSyncBridge::FromWebDataService)));
} else {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AutofillDataTypeController>(
+ std::make_unique<AutofillDataTypeController>(
db_thread_, error_callback, sync_client_, web_data_service_));
}
}
@@ -176,7 +176,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// disabled.
if (!disabled_types.Has(syncer::AUTOFILL_PROFILE)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AutofillProfileDataTypeController>(
+ std::make_unique<AutofillProfileDataTypeController>(
db_thread_, error_callback, sync_client_, web_data_service_));
}
@@ -185,7 +185,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
bool wallet_disabled = disabled_types.Has(syncer::AUTOFILL_WALLET_DATA);
if (!wallet_disabled) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AutofillWalletDataTypeController>(
+ std::make_unique<AutofillWalletDataTypeController>(
syncer::AUTOFILL_WALLET_DATA, db_thread_, error_callback,
sync_client_, web_data_service_));
}
@@ -195,7 +195,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!wallet_disabled &&
!disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AutofillWalletDataTypeController>(
+ std::make_unique<AutofillWalletDataTypeController>(
syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback,
sync_client_, web_data_service_));
}
@@ -204,9 +204,15 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// Bookmark sync is enabled by default. Register unless explicitly
// disabled.
if (!disabled_types.Has(syncer::BOOKMARKS)) {
- sync_service->RegisterDataTypeController(
- base::MakeUnique<BookmarkDataTypeController>(error_callback,
- sync_client_));
+ if (FeatureList::IsEnabled(switches::kSyncUSSBookmarks)) {
+ sync_service->RegisterDataTypeController(
+ std::make_unique<sync_bookmarks::BookmarkModelTypeController>(
+ sync_client_));
+ } else {
+ sync_service->RegisterDataTypeController(
+ std::make_unique<BookmarkDataTypeController>(error_callback,
+ sync_client_));
+ }
}
// These features are enabled only if history is not disabled.
@@ -219,7 +225,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// implemented.
} else {
sync_service->RegisterDataTypeController(
- base::MakeUnique<TypedUrlDataTypeController>(
+ std::make_unique<TypedUrlDataTypeController>(
error_callback, sync_client_, history_disabled_pref_));
}
}
@@ -227,7 +233,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// Delete directive sync is enabled by default.
if (!disabled_types.Has(syncer::HISTORY_DELETE_DIRECTIVES)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<HistoryDeleteDirectivesDataTypeController>(
+ std::make_unique<HistoryDeleteDirectivesDataTypeController>(
error_callback, sync_client_));
}
@@ -236,9 +242,9 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// server.
if (!disabled_types.Has(syncer::PROXY_TABS)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<ProxyDataTypeController>(syncer::PROXY_TABS));
+ std::make_unique<ProxyDataTypeController>(syncer::PROXY_TABS));
sync_service->RegisterDataTypeController(
- base::MakeUnique<SessionDataTypeController>(
+ std::make_unique<SessionDataTypeController>(
error_callback, sync_client_,
sync_service->GetLocalDeviceInfoProvider(),
history_disabled_pref_));
@@ -249,11 +255,11 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
!disabled_types.Has(syncer::FAVICON_TRACKING)) {
// crbug/384552. We disable error uploading for this data types for now.
sync_service->RegisterDataTypeController(
- base::MakeUnique<AsyncDirectoryTypeController>(
+ std::make_unique<AsyncDirectoryTypeController>(
syncer::FAVICON_IMAGES, base::Closure(), sync_client_,
syncer::GROUP_UI, ui_thread_));
sync_service->RegisterDataTypeController(
- base::MakeUnique<AsyncDirectoryTypeController>(
+ std::make_unique<AsyncDirectoryTypeController>(
syncer::FAVICON_TRACKING, base::Closure(), sync_client_,
syncer::GROUP_UI, ui_thread_));
}
@@ -263,7 +269,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// disabled.
if (!disabled_types.Has(syncer::PASSWORDS)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<PasswordDataTypeController>(
+ std::make_unique<PasswordDataTypeController>(
error_callback, sync_client_,
sync_client_->GetPasswordStateChangedCallback(), password_store_));
}
@@ -271,19 +277,19 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!disabled_types.Has(syncer::PREFERENCES)) {
if (!override_prefs_controller_to_uss_for_test_) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AsyncDirectoryTypeController>(
+ std::make_unique<AsyncDirectoryTypeController>(
syncer::PREFERENCES, error_callback, sync_client_,
syncer::GROUP_UI, ui_thread_));
} else {
sync_service->RegisterDataTypeController(
- base::MakeUnique<ModelTypeController>(syncer::PREFERENCES,
+ std::make_unique<ModelTypeController>(syncer::PREFERENCES,
sync_client_, ui_thread_));
}
}
if (!disabled_types.Has(syncer::PRIORITY_PREFERENCES)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AsyncDirectoryTypeController>(
+ std::make_unique<AsyncDirectoryTypeController>(
syncer::PRIORITY_PREFERENCES, error_callback, sync_client_,
syncer::GROUP_UI, ui_thread_));
}
@@ -291,7 +297,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
// Article sync is disabled by default. Register only if explicitly enabled.
if (dom_distiller::IsEnableSyncArticlesSet()) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<AsyncDirectoryTypeController>(
+ std::make_unique<AsyncDirectoryTypeController>(
syncer::ARTICLES, error_callback, sync_client_, syncer::GROUP_UI,
ui_thread_));
}
@@ -299,7 +305,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
#if defined(OS_CHROMEOS)
if (!disabled_types.Has(syncer::PRINTERS)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<ModelTypeController>(syncer::PRINTERS, sync_client_,
+ std::make_unique<ModelTypeController>(syncer::PRINTERS, sync_client_,
ui_thread_));
}
#endif
@@ -309,14 +315,14 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!disabled_types.Has(syncer::READING_LIST) &&
reading_list::switches::IsReadingListEnabled()) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<ModelTypeController>(syncer::READING_LIST,
+ std::make_unique<ModelTypeController>(syncer::READING_LIST,
sync_client_, ui_thread_));
}
if (!disabled_types.Has(syncer::USER_EVENTS) &&
FeatureList::IsEnabled(switches::kSyncUserEvents)) {
sync_service->RegisterDataTypeController(
- base::MakeUnique<ModelTypeController>(syncer::USER_EVENTS, sync_client_,
+ std::make_unique<ModelTypeController>(syncer::USER_EVENTS, sync_client_,
ui_thread_));
}
}
@@ -345,7 +351,7 @@ syncer::SyncEngine* ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
std::unique_ptr<syncer::LocalDeviceInfoProvider>
ProfileSyncComponentsFactoryImpl::CreateLocalDeviceInfoProvider() {
- return base::MakeUnique<syncer::LocalDeviceInfoProviderImpl>(
+ return std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
channel_, version_, is_tablet_);
}
diff --git a/chromium/components/browser_sync/profile_sync_service.cc b/chromium/components/browser_sync/profile_sync_service.cc
index 513e27529ac..b468810bb14 100644
--- a/chromium/components/browser_sync/profile_sync_service.cc
+++ b/chromium/components/browser_sync/profile_sync_service.cc
@@ -17,7 +17,6 @@
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/profiler/scoped_tracker.h"
@@ -221,7 +220,7 @@ void ProfileSyncService::Initialize() {
// We don't pass StartupController an Unretained reference to future-proof
// against the controller impl changing to post tasks.
- startup_controller_ = base::MakeUnique<syncer::StartupController>(
+ startup_controller_ = std::make_unique<syncer::StartupController>(
&sync_prefs_,
base::Bind(&ProfileSyncService::CanEngineStart, base::Unretained(this)),
base::Bind(&ProfileSyncService::StartUpSlowEngineComponents,
@@ -230,10 +229,10 @@ void ProfileSyncService::Initialize() {
sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter();
local_device_ = sync_client_->GetSyncApiComponentFactory()
->CreateLocalDeviceInfoProvider();
- sync_stopped_reporter_ = base::MakeUnique<syncer::SyncStoppedReporter>(
+ sync_stopped_reporter_ = std::make_unique<syncer::SyncStoppedReporter>(
sync_service_url_, local_device_->GetSyncUserAgent(),
url_request_context_, syncer::SyncStoppedReporter::ResultCallback());
- sessions_sync_manager_ = base::MakeUnique<SessionsSyncManager>(
+ sessions_sync_manager_ = std::make_unique<SessionsSyncManager>(
sync_client_->GetSyncSessionsClient(), &sync_prefs_, local_device_.get(),
router,
base::Bind(&ProfileSyncService::NotifyForeignSessionUpdated,
@@ -245,14 +244,14 @@ void ProfileSyncService::Initialize() {
if (base::FeatureList::IsEnabled(switches::kSyncUSSDeviceInfo)) {
const syncer::ModelTypeStoreFactory& store_factory =
GetModelTypeStoreFactory(syncer::DEVICE_INFO, base_directory_);
- device_info_sync_bridge_ = base::MakeUnique<DeviceInfoSyncBridge>(
+ device_info_sync_bridge_ = std::make_unique<DeviceInfoSyncBridge>(
local_device_.get(), store_factory,
base::BindRepeating(
&ModelTypeChangeProcessor::Create,
base::BindRepeating(&syncer::ReportUnrecoverableError, channel_)));
} else {
device_info_sync_service_ =
- base::MakeUnique<DeviceInfoSyncService>(local_device_.get());
+ std::make_unique<DeviceInfoSyncService>(local_device_.get());
}
syncer::SyncApiComponentFactory::RegisterDataTypesMethod
@@ -319,11 +318,11 @@ void ProfileSyncService::Initialize() {
#if !defined(OS_ANDROID)
DCHECK(sync_error_controller_ == nullptr)
<< "Initialize() called more than once.";
- sync_error_controller_ = base::MakeUnique<syncer::SyncErrorController>(this);
+ sync_error_controller_ = std::make_unique<syncer::SyncErrorController>(this);
AddObserver(sync_error_controller_.get());
#endif
- memory_pressure_listener_ = base::MakeUnique<base::MemoryPressureListener>(
+ memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
base::Bind(&ProfileSyncService::OnMemoryPressure,
sync_enabled_weak_factory_.GetWeakPtr()));
startup_controller_->Reset(GetRegisteredDataTypes());
@@ -1145,9 +1144,11 @@ void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
#if !defined(OS_CHROMEOS)
// On every platform except ChromeOS, sign out the user after a dashboard
// clear.
- static_cast<SigninManager*>(signin_->GetOriginal())
- ->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
+ if (!IsLocalSyncEnabled()) {
+ static_cast<SigninManager*>(signin_->GetOriginal())
+ ->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ }
#endif
break;
case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
@@ -1685,7 +1686,7 @@ void ProfileSyncService::ConfigureDataTypeManager() {
restart = true;
// We create the migrator at the same time.
- migrator_ = base::MakeUnique<BackendMigrator>(
+ migrator_ = std::make_unique<BackendMigrator>(
debug_identifier_, GetUserShare(), this, data_type_manager_.get(),
base::Bind(&ProfileSyncService::StartSyncingWithServer,
base::Unretained(this)));
@@ -1749,7 +1750,7 @@ void ProfileSyncService::GetModelSafeRoutingInfo(
std::unique_ptr<base::Value> ProfileSyncService::GetTypeStatusMap() {
DCHECK(thread_checker_.CalledOnValidThread());
- auto result = base::MakeUnique<base::ListValue>();
+ auto result = std::make_unique<base::ListValue>();
if (!engine_ || !engine_initialized_) {
return std::move(result);
@@ -1778,7 +1779,7 @@ std::unique_ptr<base::Value> ProfileSyncService::GetTypeStatusMap() {
for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
ModelType type = it.Get();
- auto type_status = base::MakeUnique<base::DictionaryValue>();
+ auto type_status = std::make_unique<base::DictionaryValue>();
type_status->SetString("name", ModelTypeToString(type));
type_status->SetString("group_type",
ModelSafeGroupToString(routing_info[type]));
@@ -1926,7 +1927,7 @@ void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
is_auth_in_progress_ = true;
}
- if (switches::IsAccountConsistencyDiceEnabled() &&
+ if (signin::IsAccountConsistencyDiceEnabled() &&
oauth2_token_service_->RefreshTokenIsAvailable(account_id)) {
// When Dice is enabled, the refresh token may be available before the user
// enables sync. Start sync if the refresh token is already available in the
@@ -2113,7 +2114,7 @@ void ProfileSyncService::GetAllNodes(
// If there's no engine available to fulfill the request, handle it here.
for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
helper->OnReceivedNodesForType(it.Get(),
- base::MakeUnique<base::ListValue>());
+ std::make_unique<base::ListValue>());
}
return;
}
@@ -2133,6 +2134,10 @@ void ProfileSyncService::GetAllNodes(
}
}
+syncer::GlobalIdMapper* ProfileSyncService::GetGlobalIdMapper() const {
+ return sessions_sync_manager_.get();
+}
+
base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
DCHECK(thread_checker_.CalledOnValidThread());
return sync_js_controller_.AsWeakPtr();
diff --git a/chromium/components/browser_sync/profile_sync_service.h b/chromium/components/browser_sync/profile_sync_service.h
index d9c8da9b83b..58ad6d37a9e 100644
--- a/chromium/components/browser_sync/profile_sync_service.h
+++ b/chromium/components/browser_sync/profile_sync_service.h
@@ -313,6 +313,7 @@ class ProfileSyncService : public syncer::SyncServiceBase,
base::WeakPtr<syncer::JsController> GetJsController() override;
void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
callback) override;
+ syncer::GlobalIdMapper* GetGlobalIdMapper() const override;
// Add a sync type preference provider. Each provider may only be added once.
void AddPreferenceProvider(syncer::SyncTypePreferenceProvider* provider);
diff --git a/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
index 54135dd7702..94ddc3e6499 100644
--- a/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -16,7 +16,6 @@
#include "base/callback.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
@@ -182,33 +181,36 @@ class MockAutofillBackend : public autofill::AutofillWebDataBackend {
WebDatabase* web_database,
const base::Closure& on_changed,
const base::Callback<void(syncer::ModelType)>& on_sync_started,
- const scoped_refptr<base::SequencedTaskRunner>& ui_thread)
+ const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner)
: web_database_(web_database),
on_changed_(on_changed),
on_sync_started_(on_sync_started),
- ui_thread_(ui_thread) {}
+ ui_task_runner_(ui_task_runner) {}
~MockAutofillBackend() override {}
WebDatabase* GetDatabase() override { return web_database_; }
void AddObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+ }
void RemoveExpiredFormElements() override {}
void NotifyOfMultipleAutofillChanges() override {
- DCHECK(!ui_thread_->RunsTasksInCurrentSequence());
- ui_thread_->PostTask(FROM_HERE, on_changed_);
+ DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
+ ui_task_runner_->PostTask(FROM_HERE, on_changed_);
}
void NotifyThatSyncHasStarted(syncer::ModelType model_type) override {
- DCHECK(!ui_thread_->RunsTasksInCurrentSequence());
- ui_thread_->PostTask(FROM_HERE, base::Bind(on_sync_started_, model_type));
+ DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
+ ui_task_runner_->PostTask(FROM_HERE,
+ base::Bind(on_sync_started_, model_type));
}
private:
WebDatabase* web_database_;
base::Closure on_changed_;
base::Callback<void(syncer::ModelType)> on_sync_started_;
- const scoped_refptr<base::SequencedTaskRunner> ui_thread_;
+ const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
};
class ProfileSyncServiceAutofillTest;
@@ -231,9 +233,9 @@ syncer::ModelType GetModelType<AutofillProfile>() {
class TokenWebDataServiceFake : public TokenWebData {
public:
TokenWebDataServiceFake(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
- : TokenWebData(ui_thread, db_thread) {}
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
+ : TokenWebData(ui_task_runner, db_task_runner) {}
bool IsDatabaseLoaded() override { return true; }
@@ -258,43 +260,43 @@ class TokenWebDataServiceFake : public TokenWebData {
class WebDataServiceFake : public AutofillWebDataService {
public:
WebDataServiceFake(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
- : AutofillWebDataService(ui_thread, db_thread),
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
+ : AutofillWebDataService(ui_task_runner, db_task_runner),
web_database_(nullptr),
autocomplete_syncable_service_(nullptr),
autofill_profile_syncable_service_(nullptr),
syncable_service_created_or_destroyed_(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED),
- db_thread_(db_thread),
- ui_thread_(ui_thread) {}
+ db_task_runner_(db_task_runner),
+ ui_task_runner_(ui_task_runner) {}
void SetDatabase(WebDatabase* web_database) { web_database_ = web_database; }
void StartSyncableService() {
// The |autofill_profile_syncable_service_| must be constructed on the DB
- // thread.
- const base::Closure& on_changed_callback =
- base::Bind(&WebDataServiceFake::NotifyAutofillMultipleChangedOnUIThread,
- AsWeakPtr());
+ // sequence.
+ const base::Closure& on_changed_callback = base::Bind(
+ &WebDataServiceFake::NotifyAutofillMultipleChangedOnUISequence,
+ AsWeakPtr());
const base::Callback<void(syncer::ModelType)> on_sync_started_callback =
- base::Bind(&WebDataServiceFake::NotifySyncStartedOnUIThread,
+ base::Bind(&WebDataServiceFake::NotifySyncStartedOnUISequence,
AsWeakPtr());
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&WebDataServiceFake::CreateSyncableService,
- base::Unretained(this), on_changed_callback,
- on_sync_started_callback));
+ db_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WebDataServiceFake::CreateSyncableService,
+ base::Unretained(this), on_changed_callback,
+ on_sync_started_callback));
syncable_service_created_or_destroyed_.Wait();
}
void ShutdownSyncableService() {
// The |autofill_profile_syncable_service_| must be destructed on the DB
- // thread.
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&WebDataServiceFake::DestroySyncableService,
- base::Unretained(this)));
+ // sequence.
+ db_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WebDataServiceFake::DestroySyncableService,
+ base::Unretained(this)));
syncable_service_created_or_destroyed_.Wait();
}
@@ -309,8 +311,8 @@ class WebDataServiceFake : public AutofillWebDataService {
base::Closure notify_cb =
base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged,
base::Unretained(autocomplete_syncable_service_), changes);
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&RunAndSignal, notify_cb, &event));
+ db_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&RunAndSignal, notify_cb, &event));
event.Wait();
}
@@ -321,8 +323,8 @@ class WebDataServiceFake : public AutofillWebDataService {
base::Closure notify_cb = base::Bind(
&AutocompleteSyncableService::AutofillProfileChanged,
base::Unretained(autofill_profile_syncable_service_), changes);
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&RunAndSignal, notify_cb, &event));
+ db_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&RunAndSignal, notify_cb, &event));
event.Wait();
}
@@ -332,10 +334,11 @@ class WebDataServiceFake : public AutofillWebDataService {
void CreateSyncableService(
const base::Closure& on_changed_callback,
const base::Callback<void(syncer::ModelType)>& on_sync_started) {
- ASSERT_TRUE(db_thread_->RunsTasksInCurrentSequence());
+ ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
// These services are deleted in DestroySyncableService().
- backend_ = base::MakeUnique<MockAutofillBackend>(
- GetDatabase(), on_changed_callback, on_sync_started, ui_thread_.get());
+ backend_ = std::make_unique<MockAutofillBackend>(
+ GetDatabase(), on_changed_callback, on_sync_started,
+ ui_task_runner_.get());
AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
this, backend_.get());
AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
@@ -350,7 +353,7 @@ class WebDataServiceFake : public AutofillWebDataService {
}
void DestroySyncableService() {
- ASSERT_TRUE(db_thread_->RunsTasksInCurrentSequence());
+ ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
autocomplete_syncable_service_ = nullptr;
autofill_profile_syncable_service_ = nullptr;
backend_.reset();
@@ -364,8 +367,8 @@ class WebDataServiceFake : public AutofillWebDataService {
WaitableEvent syncable_service_created_or_destroyed_;
- const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
+ const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
+ const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
};
@@ -411,8 +414,8 @@ class ProfileSyncServiceAutofillTest
profile_sync_service_bundle()->set_db_thread(
data_type_thread()->task_runner());
- web_database_ = base::MakeUnique<WebDatabaseFake>(&autofill_table_);
- web_data_wrapper_ = base::MakeUnique<MockWebDataServiceWrapper>(
+ web_database_ = std::make_unique<WebDatabaseFake>(&autofill_table_);
+ web_data_wrapper_ = std::make_unique<MockWebDataServiceWrapper>(
new WebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
data_type_thread()->task_runner()),
new TokenWebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
@@ -421,7 +424,7 @@ class ProfileSyncServiceAutofillTest
web_data_wrapper_->GetAutofillWebData().get());
web_data_service_->SetDatabase(web_database_.get());
- personal_data_manager_ = base::MakeUnique<MockPersonalDataManager>();
+ personal_data_manager_ = std::make_unique<MockPersonalDataManager>();
EXPECT_CALL(personal_data_manager(), LoadProfiles());
EXPECT_CALL(personal_data_manager(), LoadCreditCards());
@@ -452,7 +455,7 @@ class ProfileSyncServiceAutofillTest
}
~ProfileSyncServiceAutofillTest() override {
- web_data_service_->ShutdownOnUIThread();
+ web_data_service_->ShutdownOnUISequence();
web_data_service_->ShutdownSyncableService();
web_data_wrapper_->Shutdown();
web_data_service_ = nullptr;
@@ -617,11 +620,11 @@ class ProfileSyncServiceAutofillTest
syncer::ModelType type) {
DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
if (type == AUTOFILL) {
- return base::MakeUnique<AutofillDataTypeController>(
+ return std::make_unique<AutofillDataTypeController>(
data_type_thread()->task_runner(), base::Bind(&base::DoNothing),
sync_client_, web_data_service_);
} else {
- return base::MakeUnique<AutofillProfileDataTypeController>(
+ return std::make_unique<AutofillProfileDataTypeController>(
data_type_thread()->task_runner(), base::Bind(&base::DoNothing),
sync_client_, web_data_service_);
}
@@ -729,18 +732,18 @@ class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
FakeServerUpdater(TestProfileSyncService* service,
WaitableEvent* wait_for_start,
WaitableEvent* wait_for_syncapi,
- scoped_refptr<base::SequencedTaskRunner> db_thread)
+ scoped_refptr<base::SequencedTaskRunner> db_task_runner)
: entry_(MakeAutofillEntry("0", "0", 0)),
service_(service),
wait_for_start_(wait_for_start),
wait_for_syncapi_(wait_for_syncapi),
is_finished_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED),
- db_thread_(db_thread) {}
+ db_task_runner_(db_task_runner) {}
void Update() {
// This gets called in a modelsafeworker thread.
- ASSERT_TRUE(db_thread_->RunsTasksInCurrentSequence());
+ ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
syncer::UserShare* user_share = service_->GetUserShare();
syncer::syncable::Directory* directory = user_share->directory.get();
@@ -789,10 +792,10 @@ class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
void CreateNewEntry(const AutofillEntry& entry) {
entry_ = entry;
- ASSERT_FALSE(db_thread_->RunsTasksInCurrentSequence());
- if (!db_thread_->PostTask(FROM_HERE,
- base::Bind(&FakeServerUpdater::Update, this))) {
- NOTREACHED() << "Failed to post task to the db thread.";
+ ASSERT_FALSE(db_task_runner_->RunsTasksInCurrentSequence());
+ if (!db_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&FakeServerUpdater::Update, this))) {
+ NOTREACHED() << "Failed to post task to the db sequence.";
return;
}
}
@@ -809,7 +812,7 @@ class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
WaitableEvent* const wait_for_syncapi_;
WaitableEvent is_finished_;
syncer::syncable::Id parent_id_;
- scoped_refptr<base::SequencedTaskRunner> db_thread_;
+ scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
DISALLOW_COPY_AND_ASSIGN(FakeServerUpdater);
};
@@ -861,7 +864,7 @@ TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
std::vector<AutofillProfile> expected_profiles;
std::unique_ptr<AutofillProfile> profile0 =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
profile0.get(), "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
@@ -1024,7 +1027,7 @@ TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
"unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
@@ -1072,7 +1075,7 @@ TEST_F(
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
@@ -1136,7 +1139,7 @@ TEST_F(ProfileSyncServiceAutofillTest,
sync_profile.set_use_date(base::Time::FromTimeT(1234));
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
@@ -1203,7 +1206,7 @@ TEST_F(ProfileSyncServiceAutofillTest,
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
@@ -1265,7 +1268,7 @@ TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSync_DifferentPrimaryInfo) {
sync_profile.set_use_date(base::Time::FromTimeT(4321));
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
"John", "Smith", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
@@ -1312,7 +1315,7 @@ TEST_F(ProfileSyncServiceAutofillTest, MergeProfileWithDifferentGuid) {
std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), native_guid.c_str(), "Billing", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
@@ -1470,7 +1473,7 @@ TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
std::unique_ptr<AutofillProfile> native_profile =
- base::MakeUnique<AutofillProfile>();
+ std::make_unique<AutofillProfile>();
autofill::test::SetProfileInfoWithGuid(
native_profile.get(), "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
"Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
@@ -1545,7 +1548,7 @@ TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) {
updater->CreateNewEntry(MakeAutofillEntry("server2", "entry2", 3));
updater->WaitForUpdateCompletion();
- // Let callbacks posted on UI thread execute.
+ // Let callbacks posted on UI sequence execute.
base::RunLoop().RunUntilIdle();
std::vector<AutofillEntry> sync_entries;
diff --git a/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc b/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc
index 33af2eb9464..1554454e43c 100644
--- a/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc
@@ -441,7 +441,7 @@ class ProfileSyncServiceBookmarkTest : public testing::Test {
// will be deleted before starting up the BookmarkModel.
std::unique_ptr<BookmarkModel> CreateBookmarkModel(bool delete_bookmarks) {
const base::FilePath& data_path = data_dir_.GetPath();
- auto model = base::MakeUnique<BookmarkModel>(
+ auto model = std::make_unique<BookmarkModel>(
base::WrapUnique(new bookmarks::TestBookmarkClient()));
managed_bookmark_service_->BookmarkModelCreated(model.get());
int64_t next_id = 0;
@@ -547,9 +547,9 @@ class ProfileSyncServiceBookmarkTest : public testing::Test {
DCHECK(!model_associator_);
// Set up model associator.
- model_associator_ = base::MakeUnique<BookmarkModelAssociator>(
+ model_associator_ = std::make_unique<BookmarkModelAssociator>(
model_.get(), sync_client_.get(), test_user_share_.user_share(),
- base::MakeUnique<syncer::DataTypeErrorHandlerMock>(),
+ std::make_unique<syncer::DataTypeErrorHandlerMock>(),
kExpectMobileBookmarks);
local_merge_result_ = syncer::SyncMergeResult(syncer::BOOKMARKS);
@@ -793,9 +793,9 @@ class ProfileSyncServiceBookmarkTest : public testing::Test {
void ResetChangeProcessor() {
std::unique_ptr<syncer::DataTypeErrorHandlerMock> error_handler =
- base::MakeUnique<syncer::DataTypeErrorHandlerMock>();
+ std::make_unique<syncer::DataTypeErrorHandlerMock>();
mock_error_handler_ = error_handler.get();
- change_processor_ = base::MakeUnique<BookmarkChangeProcessor>(
+ change_processor_ = std::make_unique<BookmarkChangeProcessor>(
sync_client_.get(), model_associator_.get(), std::move(error_handler));
}
diff --git a/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
index 2b603cc3ab5..a120cbba887 100644
--- a/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -5,9 +5,8 @@
#include "components/browser_sync/profile_sync_service.h"
#include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/browser_sync/profile_sync_test_util.h"
#include "components/prefs/pref_service.h"
@@ -92,9 +91,9 @@ class ProfileSyncServiceStartupTest : public testing::Test {
builder.Build());
sync_service_ =
- base::MakeUnique<ProfileSyncService>(std::move(init_params));
+ std::make_unique<ProfileSyncService>(std::move(init_params));
sync_service_->RegisterDataTypeController(
- base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+ std::make_unique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
sync_service_->AddObserver(&observer_);
}
@@ -148,7 +147,7 @@ class ProfileSyncServiceStartupTest : public testing::Test {
return profile_sync_service_bundle_.pref_service();
}
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
ProfileSyncServiceBundle profile_sync_service_bundle_;
std::unique_ptr<ProfileSyncService> sync_service_;
SyncServiceObserverMock observer_;
diff --git a/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
index 50906f1460b..964ae968ab8 100644
--- a/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
@@ -17,7 +17,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
@@ -203,7 +202,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
void CreateHistoryService() {
history_backend_ = new HistoryBackendMock();
syncable_service_ =
- base::MakeUnique<TestTypedUrlSyncableService>(history_backend_.get());
+ std::make_unique<TestTypedUrlSyncableService>(history_backend_.get());
}
void DeleteSyncableService() {
@@ -259,7 +258,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
account_id, "oauth2_login_token");
sync_service()->RegisterDataTypeController(
- base::MakeUnique<TypedUrlDataTypeController>(
+ std::make_unique<TypedUrlDataTypeController>(
base::Bind(&base::DoNothing), sync_service()->GetSyncClient(),
kDummySavingBrowserHistoryDisabled));
@@ -308,9 +307,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
void SendNotification(const base::Closure& task) {
data_type_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE, task,
- base::Bind(&base::MessageLoop::QuitNow,
- base::Unretained(base::MessageLoop::current())));
+ FROM_HERE, task, base::Bind(&base::RunLoop::QuitCurrentDeprecated));
base::RunLoop().Run();
}
diff --git a/chromium/components/browser_sync/profile_sync_service_unittest.cc b/chromium/components/browser_sync/profile_sync_service_unittest.cc
index d5aa12bb29d..09ab57d4de5 100644
--- a/chromium/components/browser_sync/profile_sync_service_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_unittest.cc
@@ -9,7 +9,6 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
@@ -206,9 +205,9 @@ class ProfileSyncServiceTest : public ::testing::Test {
profile_sync_service_bundle_.CreateBasicInitParams(behavior,
builder.Build());
- service_ = base::MakeUnique<ProfileSyncService>(std::move(init_params));
+ service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
service_->RegisterDataTypeController(
- base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+ std::make_unique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
}
void CreateServiceWithLocalSyncBackend() {
@@ -224,9 +223,9 @@ class ProfileSyncServiceTest : public ::testing::Test {
init_params.gaia_cookie_manager_service = nullptr;
init_params.signin_wrapper.reset();
- service_ = base::MakeUnique<ProfileSyncService>(std::move(init_params));
+ service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
service_->RegisterDataTypeController(
- base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+ std::make_unique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
}
void ShutdownAndDeleteService() {
@@ -373,7 +372,7 @@ TEST_F(ProfileSyncServiceTest, InitialState) {
// Verify a successful initialization.
TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(false));
+ std::make_unique<base::Value>(false));
IssueTestTokens();
CreateService(ProfileSyncService::AUTO_START);
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
@@ -386,7 +385,7 @@ TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
// Verify a successful initialization.
TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) {
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(false));
+ std::make_unique<base::Value>(false));
CreateServiceWithLocalSyncBackend();
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
ExpectSyncEngineCreation(1);
@@ -400,7 +399,7 @@ TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) {
// start up the backend.
TEST_F(ProfileSyncServiceTest, NeedsConfirmation) {
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(false));
+ std::make_unique<base::Value>(false));
IssueTestTokens();
CreateService(ProfileSyncService::MANUAL_START);
@@ -438,7 +437,7 @@ TEST_F(ProfileSyncServiceTest, SetupInProgress) {
// Verify that disable by enterprise policy works.
TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(true));
+ std::make_unique<base::Value>(true));
IssueTestTokens();
CreateService(ProfileSyncService::AUTO_START);
InitializeForNthSync();
@@ -459,7 +458,7 @@ TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
EXPECT_TRUE(service()->IsSyncActive());
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(true));
+ std::make_unique<base::Value>(true));
EXPECT_TRUE(service()->IsManaged());
EXPECT_FALSE(service()->IsSyncActive());
@@ -949,7 +948,7 @@ TEST_F(ProfileSyncServiceTest, DisableSyncOnClient) {
// Verify a that local sync mode resumes after the policy is lifted.
TEST_F(ProfileSyncServiceTest, LocalBackendDisabledByPolicy) {
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(false));
+ std::make_unique<base::Value>(false));
CreateServiceWithLocalSyncBackend();
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
ExpectSyncEngineCreation(1);
@@ -958,13 +957,13 @@ TEST_F(ProfileSyncServiceTest, LocalBackendDisabledByPolicy) {
EXPECT_TRUE(service()->IsSyncActive());
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(true));
+ std::make_unique<base::Value>(true));
EXPECT_TRUE(service()->IsManaged());
EXPECT_FALSE(service()->IsSyncActive());
prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
- base::MakeUnique<base::Value>(false));
+ std::make_unique<base::Value>(false));
ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
ExpectSyncEngineCreation(1);
@@ -991,7 +990,7 @@ TEST_F(ProfileSyncServiceTest, GetOpenTabsUIDelegate) {
EXPECT_EQ(nullptr, service()->GetOpenTabsUIDelegate());
auto controller =
- base::MakeUnique<syncer::FakeDataTypeController>(syncer::PROXY_TABS);
+ std::make_unique<syncer::FakeDataTypeController>(syncer::PROXY_TABS);
// Progress the controller to RUNNING first, which is how the service
// determines whether a type is enabled.
controller->StartAssociating(base::Bind(&DoNothing));
diff --git a/chromium/components/browser_sync/profile_sync_test_util.cc b/chromium/components/browser_sync/profile_sync_test_util.cc
index c482bfbeb64..c4f61875341 100644
--- a/chromium/components/browser_sync/profile_sync_test_util.cc
+++ b/chromium/components/browser_sync/profile_sync_test_util.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/bookmarks/browser/bookmark_model.h"
@@ -213,7 +212,7 @@ void ProfileSyncServiceBundle::SyncClientBuilder::SetBookmarkModelCallback(
std::unique_ptr<syncer::FakeSyncClient>
ProfileSyncServiceBundle::SyncClientBuilder::Build() {
- return base::MakeUnique<BundleSyncClient>(
+ return std::make_unique<BundleSyncClient>(
bundle_->component_factory(), bundle_->pref_service(),
bundle_->sync_sessions_client(), personal_data_manager_,
get_syncable_service_callback_, get_sync_service_callback_,
@@ -253,11 +252,12 @@ ProfileSyncService::InitParams ProfileSyncServiceBundle::CreateBasicInitParams(
init_params.start_behavior = start_behavior;
init_params.sync_client = std::move(sync_client);
init_params.signin_wrapper =
- base::MakeUnique<SigninManagerWrapper>(signin_manager());
+ std::make_unique<SigninManagerWrapper>(signin_manager());
init_params.oauth2_token_service = auth_service();
init_params.network_time_update_callback =
base::Bind(&EmptyNetworkTimeUpdate);
- init_params.base_directory = base::FilePath(FILE_PATH_LITERAL("dummyPath"));
+ CHECK(base_directory_.CreateUniqueTempDir());
+ init_params.base_directory = base_directory_.GetPath();
init_params.url_request_context = url_request_context();
init_params.debug_identifier = "dummyDebugName";
init_params.channel = version_info::Channel::UNKNOWN;
diff --git a/chromium/components/browser_sync/profile_sync_test_util.h b/chromium/components/browser_sync/profile_sync_test_util.h
index 3ca1498c864..63252044d6d 100644
--- a/chromium/components/browser_sync/profile_sync_test_util.h
+++ b/chromium/components/browser_sync/profile_sync_test_util.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/callback.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
@@ -178,6 +179,7 @@ class ProfileSyncServiceBundle {
sync_sessions::FakeSyncSessionsClient sync_sessions_client_;
invalidation::FakeInvalidationService fake_invalidation_service_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+ base::ScopedTempDir base_directory_;
DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBundle);
};
diff --git a/chromium/components/browser_sync/test_profile_sync_service.cc b/chromium/components/browser_sync/test_profile_sync_service.cc
index 9eab474c7b8..5d88d3a0fad 100644
--- a/chromium/components/browser_sync/test_profile_sync_service.cc
+++ b/chromium/components/browser_sync/test_profile_sync_service.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
namespace browser_sync {
@@ -28,7 +28,7 @@ TestProfileSyncService::~TestProfileSyncService() {}
void TestProfileSyncService::OnConfigureDone(
const syncer::DataTypeManager::ConfigureResult& result) {
ProfileSyncService::OnConfigureDone(result);
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
syncer::UserShare* TestProfileSyncService::GetUserShare() const {
diff --git a/chromium/components/browser_watcher/BUILD.gn b/chromium/components/browser_watcher/BUILD.gn
index 9b16d7f3413..ac30cf6414f 100644
--- a/chromium/components/browser_watcher/BUILD.gn
+++ b/chromium/components/browser_watcher/BUILD.gn
@@ -66,8 +66,27 @@ if (is_win) {
ldflags = [ "/DELAYLOAD:wevtapi.dll" ] # Only used after unclean shutdowns.
}
+ static_library("crash_stability") {
+ sources = [
+ "stability_report_user_stream_data_source.cc",
+ "stability_report_user_stream_data_source.h",
+ ]
+ deps = [
+ ":stability_client",
+ ":stability_common",
+ ":stability_report_proto",
+ "//base",
+ "//third_party/crashpad/crashpad/client",
+ "//third_party/crashpad/crashpad/compat",
+ "//third_party/crashpad/crashpad/handler:handler_lib",
+ "//third_party/crashpad/crashpad/minidump",
+ "//third_party/crashpad/crashpad/snapshot",
+ ]
+ }
+
static_library("stability_common") {
sources = [
+ "minidump_user_streams.h",
"stability_report_extractor.cc",
"stability_report_extractor.h",
]
diff --git a/chromium/components/browser_watcher/dump_stability_report_main_win.cc b/chromium/components/browser_watcher/dump_stability_report_main_win.cc
index 2b3be12eb24..bc3940ad8a0 100644
--- a/chromium/components/browser_watcher/dump_stability_report_main_win.cc
+++ b/chromium/components/browser_watcher/dump_stability_report_main_win.cc
@@ -140,18 +140,72 @@ void PrintActivity(FILE* out,
void PrintProcessState(FILE* out,
const browser_watcher::ProcessState& process) {
- fprintf(out, "Process %lld (%d threads)\n", process.process_id(),
- process.threads_size());
+ std::string process_type;
+ switch (process.process_type()) {
+ case browser_watcher::ProcessState::UNKNOWN_PROCESS:
+ process_type = "unknown type";
+ break;
+ case browser_watcher::ProcessState::BROWSER_PROCESS:
+ process_type = "browser";
+ break;
+ case browser_watcher::ProcessState::WATCHER_PROCESS:
+ process_type = "watcher";
+ break;
+ default:
+ base::SStringPrintf(&process_type, "process type %d",
+ process.process_type());
+ break;
+ }
+
+ fprintf(out, "Process %lld (%s, %d threads)\n", process.process_id(),
+ process_type.c_str(), process.threads_size());
+
+ if (process.has_memory_state() &&
+ process.memory_state().has_windows_memory()) {
+ const auto& windows_memory = process.memory_state().windows_memory();
+ if (windows_memory.has_process_private_usage()) {
+ fprintf(out, "process_private_usage: %u pages\n",
+ windows_memory.process_private_usage());
+ }
+ if (windows_memory.has_process_peak_workingset_size()) {
+ fprintf(out, "process_peak_workingset_size: %u pages\n",
+ windows_memory.process_peak_workingset_size());
+ }
+ if (windows_memory.has_process_peak_pagefile_usage()) {
+ fprintf(out, "process_peak_pagefile_usage: %u pages\n",
+ windows_memory.process_peak_pagefile_usage());
+ }
+ if (windows_memory.has_process_allocation_attempt()) {
+ fprintf(out, "process_allocation_attempt: %u bytes\n",
+ windows_memory.process_allocation_attempt());
+ }
+ }
+
for (const browser_watcher::ThreadState& thread : process.threads()) {
fprintf(out, "Thread %lld (%s) : %d activities\n", thread.thread_id(),
thread.thread_name().c_str(), thread.activity_count());
for (const browser_watcher::Activity& activity : thread.activities())
PrintActivity(out, 1, activity);
}
+
+ PrintUserData(out, 1, process.data());
}
// TODO(manzagop): flesh out as StabilityReport gets fleshed out.
void PrintReport(FILE* out, const browser_watcher::StabilityReport& report) {
+ if (report.has_system_memory_state() &&
+ report.system_memory_state().has_windows_memory()) {
+ const auto& windows_memory = report.system_memory_state().windows_memory();
+
+ if (windows_memory.has_system_commit_limit()) {
+ fprintf(out, "system_commit_limit: %u pages\n",
+ windows_memory.system_commit_limit());
+ }
+ if (windows_memory.has_system_commit_remaining()) {
+ fprintf(out, "system_commit_remaining: %u pages\n",
+ windows_memory.system_commit_remaining());
+ }
+ }
PrintUserData(out, 0, report.global_data());
for (int i = 0; i < report.process_states_size(); ++i) {
const browser_watcher::ProcessState process = report.process_states(i);
diff --git a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
index 1d5badfb0cf..9c1a0741b94 100644
--- a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
+++ b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
@@ -41,37 +41,36 @@ class ScopedSleeperProcess {
}
~ScopedSleeperProcess() {
- if (spawn_child_.process.IsValid()) {
- spawn_child_.process.Terminate(-1, false);
- EXPECT_TRUE(spawn_child_.process.WaitForExit(nullptr));
+ if (process_.IsValid()) {
+ process_.Terminate(-1, false);
+ EXPECT_TRUE(process_.WaitForExit(nullptr));
}
}
void Launch() {
- ASSERT_FALSE(spawn_child_.process.IsValid());
+ ASSERT_FALSE(process_.IsValid());
base::CommandLine cmd_line(base::GetMultiProcessTestChildBaseCommandLine());
base::LaunchOptions options;
options.start_hidden = true;
- spawn_child_ =
- base::SpawnMultiProcessTestChild("Sleeper", cmd_line, options);
- ASSERT_TRUE(spawn_child_.process.IsValid());
+ process_ = base::SpawnMultiProcessTestChild("Sleeper", cmd_line, options);
+ ASSERT_TRUE(process_.IsValid());
}
void Kill(int exit_code, bool wait) {
- ASSERT_TRUE(spawn_child_.process.IsValid());
+ ASSERT_TRUE(process_.IsValid());
ASSERT_FALSE(is_killed_);
- spawn_child_.process.Terminate(exit_code, false);
+ process_.Terminate(exit_code, false);
int seen_exit_code = 0;
- EXPECT_TRUE(spawn_child_.process.WaitForExit(&seen_exit_code));
+ EXPECT_TRUE(process_.WaitForExit(&seen_exit_code));
EXPECT_EQ(exit_code, seen_exit_code);
is_killed_ = true;
}
- const base::Process& process() const { return spawn_child_.process; }
+ const base::Process& process() const { return process_; }
private:
- base::SpawnChildResult spawn_child_;
+ base::Process process_;
bool is_killed_;
};
diff --git a/chromium/components/browser_watcher/minidump_user_streams.h b/chromium/components/browser_watcher/minidump_user_streams.h
new file mode 100644
index 00000000000..a6c6ecf3123
--- /dev/null
+++ b/chromium/components/browser_watcher/minidump_user_streams.h
@@ -0,0 +1,18 @@
+// 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_BROWSER_WATCHER_MINIDUMP_USER_STREAMS_H_
+#define COMPONENTS_BROWSER_WATCHER_MINIDUMP_USER_STREAMS_H_
+
+namespace browser_watcher {
+
+// The stream type assigned to the minidump stream that holds the serialized
+// stability report.
+// Note: the value was obtained by adding 1 to the stream type used for holding
+// the SyzyAsan proto.
+constexpr uint32_t kStabilityReportStreamType = 0x4B6B0002;
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_MINIDUMP_USER_STREAMS_H_
diff --git a/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc b/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc
index f22827ff598..30222db2ce9 100644
--- a/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc
+++ b/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc
@@ -22,6 +22,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_math.h"
#include "base/strings/string_piece.h"
+#include "components/browser_watcher/minidump_user_streams.h"
#include "components/browser_watcher/stability_data_names.h"
#include "third_party/crashpad/crashpad/minidump/minidump_extensions.h"
@@ -29,13 +30,6 @@ namespace browser_watcher {
namespace {
-// The stream type assigned to the minidump stream that holds the serialized
-// stability report.
-// Note: the value was obtained by adding 1 to the stream type used for holding
-// the SyzyAsan proto.
-// TODO(manzagop): centralize the stream type definitions to avoid issues.
-const uint32_t kStabilityReportStreamType = 0x4B6B0002;
-
struct ProductDetails {
std::string product;
std::string channel;
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.cc b/chromium/components/browser_watcher/postmortem_report_collector.cc
index 80ce8c75d98..d59b526cddd 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector.cc
+++ b/chromium/components/browser_watcher/postmortem_report_collector.cc
@@ -59,16 +59,9 @@ void LogCollectionStatus(CollectionStatus status) {
} // namespace
-void PostmortemDeleter::Process(
- const std::vector<base::FilePath>& stability_files) {
- for (const FilePath& file : stability_files) {
- if (base::DeleteFile(file, false))
- LogCollectionStatus(UNCLEAN_SHUTDOWN);
- else
- LogCollectionStatus(DEBUG_FILE_DELETION_FAILED);
- }
-}
-
+PostmortemReportCollector::PostmortemReportCollector(
+ SystemSessionAnalyzer* analyzer)
+ : report_database_(nullptr), system_session_analyzer_(analyzer) {}
PostmortemReportCollector::PostmortemReportCollector(
const std::string& product_name,
const std::string& version_number,
@@ -80,6 +73,9 @@ PostmortemReportCollector::PostmortemReportCollector(
channel_name_(channel_name),
report_database_(report_database),
system_session_analyzer_(analyzer) {
+ DCHECK(!product_name_.empty());
+ DCHECK(!version_number.empty());
+ DCHECK(!channel_name.empty());
DCHECK_NE(nullptr, report_database);
}
@@ -89,22 +85,23 @@ void PostmortemReportCollector::Process(
const std::vector<base::FilePath>& stability_files) {
// Determine the crashpad client id.
crashpad::UUID client_id;
- crashpad::Settings* settings = report_database_->GetSettings();
- if (settings) {
- // If GetSettings() or GetClientID() fails client_id will be left at its
- // default value, all zeroes, which is appropriate.
- settings->GetClientID(&client_id);
+ if (report_database_) {
+ crashpad::Settings* settings = report_database_->GetSettings();
+ if (settings) {
+ // If GetSettings() or GetClientID() fails client_id will be left at its
+ // default value, all zeroes, which is appropriate.
+ settings->GetClientID(&client_id);
+ }
}
for (const FilePath& file : stability_files) {
- CollectAndSubmitOneReport(client_id, file);
+ ProcessOneReport(client_id, file);
}
}
-void PostmortemReportCollector::CollectAndSubmitOneReport(
+void PostmortemReportCollector::ProcessOneReport(
const crashpad::UUID& client_id,
const FilePath& file) {
- DCHECK_NE(nullptr, report_database_);
LogCollectionStatus(COLLECTION_ATTEMPT);
// Note: the code below involves two notions of report: chrome internal state
@@ -114,11 +111,12 @@ void PostmortemReportCollector::CollectAndSubmitOneReport(
StabilityReport report_proto;
CollectionStatus status = CollectOneReport(file, &report_proto);
if (status != SUCCESS) {
- // The file was empty, or there was an error collecting the data. Detailed
- // logging happens within the Collect function.
- if (!base::DeleteFile(file, false))
- DLOG(ERROR) << "Failed to delete " << file.value();
+ // The file was empty, or there was an error collecting the data. This is
+ // not deemed an unclean shutdown. Detailed logging happens within the
+ // Collect function.
LogCollectionStatus(status);
+ if (!base::DeleteFile(file, false))
+ LogCollectionStatus(DEBUG_FILE_DELETION_FAILED);
return;
}
@@ -138,37 +136,8 @@ void PostmortemReportCollector::CollectAndSubmitOneReport(
if (report_proto.system_state().session_state() == SystemState::UNCLEAN)
LogCollectionStatus(UNCLEAN_SESSION);
- // Prepare a crashpad report.
- CrashReportDatabase::NewReport* new_report = nullptr;
- CrashReportDatabase::OperationStatus database_status =
- report_database_->PrepareNewCrashReport(&new_report);
- if (database_status != CrashReportDatabase::kNoError) {
- LogCollectionStatus(PREPARE_NEW_CRASH_REPORT_FAILED);
- return;
- }
- CrashReportDatabase::CallErrorWritingCrashReport
- call_error_writing_crash_report(report_database_, new_report);
-
- // Write the report to a minidump.
- if (!WriteReportToMinidump(&report_proto, client_id, new_report->uuid,
- reinterpret_cast<FILE*>(new_report->handle))) {
- LogCollectionStatus(WRITE_TO_MINIDUMP_FAILED);
- return;
- }
-
- // Finalize the report wrt the report database. Note that this doesn't trigger
- // an immediate upload, but Crashpad will eventually upload the report (as of
- // writing, the delay is on the order of up to 15 minutes).
- call_error_writing_crash_report.Disarm();
- crashpad::UUID unused_report_id;
- database_status = report_database_->FinishedWritingCrashReport(
- new_report, &unused_report_id);
- if (database_status != CrashReportDatabase::kNoError) {
- LogCollectionStatus(FINISHED_WRITING_CRASH_REPORT_FAILED);
- return;
- }
-
- LogCollectionStatus(SUCCESS);
+ if (report_database_)
+ GenerateCrashReport(client_id, &report_proto);
}
CollectionStatus PostmortemReportCollector::CollectOneReport(
@@ -248,6 +217,45 @@ void PostmortemReportCollector::RecordSystemShutdownState(
SYSTEM_SESSION_ANALYSIS_STATUS_MAX);
}
+void PostmortemReportCollector::GenerateCrashReport(
+ const crashpad::UUID& client_id,
+ StabilityReport* report_proto) {
+ DCHECK_NE(nullptr, report_database_);
+ DCHECK(report_proto);
+
+ // Prepare a crashpad report.
+ CrashReportDatabase::NewReport* new_report = nullptr;
+ CrashReportDatabase::OperationStatus database_status =
+ report_database_->PrepareNewCrashReport(&new_report);
+ if (database_status != CrashReportDatabase::kNoError) {
+ LogCollectionStatus(PREPARE_NEW_CRASH_REPORT_FAILED);
+ return;
+ }
+ CrashReportDatabase::CallErrorWritingCrashReport
+ call_error_writing_crash_report(report_database_, new_report);
+
+ // Write the report to a minidump.
+ if (!WriteReportToMinidump(report_proto, client_id, new_report->uuid,
+ reinterpret_cast<FILE*>(new_report->handle))) {
+ LogCollectionStatus(WRITE_TO_MINIDUMP_FAILED);
+ return;
+ }
+
+ // Finalize the report wrt the report database. Note that this doesn't trigger
+ // an immediate upload, but Crashpad will eventually upload the report (as of
+ // writing, the delay is on the order of up to 15 minutes).
+ call_error_writing_crash_report.Disarm();
+ crashpad::UUID unused_report_id;
+ database_status = report_database_->FinishedWritingCrashReport(
+ new_report, &unused_report_id);
+ if (database_status != CrashReportDatabase::kNoError) {
+ LogCollectionStatus(FINISHED_WRITING_CRASH_REPORT_FAILED);
+ return;
+ }
+
+ LogCollectionStatus(SUCCESS);
+}
+
bool PostmortemReportCollector::WriteReportToMinidump(
StabilityReport* report,
const crashpad::UUID& client_id,
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.h b/chromium/components/browser_watcher/postmortem_report_collector.h
index 436c16d49f0..09a32845eb4 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector.h
+++ b/chromium/components/browser_watcher/postmortem_report_collector.h
@@ -28,23 +28,18 @@
namespace browser_watcher {
-// Deletes stability files.
-class PostmortemDeleter {
- public:
- PostmortemDeleter() = default;
- ~PostmortemDeleter() = default;
-
- void Process(const std::vector<base::FilePath>& stability_files);
-};
-
-// Handles postmortem report collection by establishing the set of stability
-// files to collect, then for each file:
-// - extracting a report protocol buffer
-// - registering a crash report with the crash database
-// - writing a minidump file for the report
-// TODO(manzagop): throttling, graceful handling of accumulating data.
+// Performs postmortem stability data collection and analysis. The data is then
+// reported as user metrics (e.g. to estimate the number of unclean shutdowns,
+// or those attributable to the system) and, optionally, as crash reports for
+// a more detailed view.
class PostmortemReportCollector {
public:
+ // Creates a postmortem report collector. The |product_name|, |version_number|
+ // and |channel_name| are used to set reporter information in postmortem
+ // crash reports. If |report_database| is set, postmortem crash reports are
+ // generated and registered against it. If |analyzer| is set, it used to
+ // analyze the containing system session.
+ PostmortemReportCollector(SystemSessionAnalyzer* analyzer);
PostmortemReportCollector(const std::string& product_name,
const std::string& version_number,
const std::string& channel_name,
@@ -52,8 +47,8 @@ class PostmortemReportCollector {
SystemSessionAnalyzer* analyzer);
~PostmortemReportCollector();
- // Collects postmortem stability reports from |stability_files|. Reports are
- // then wrapped in Crashpad reports and registered with the crash database.
+ // Analyzes |stability_files|, logs postmortem user metrics and optionally
+ // generates postmortem crash reports.
void Process(const std::vector<base::FilePath>& stability_files);
const std::string& product_name() const { return product_name_; }
@@ -83,10 +78,10 @@ class PostmortemReportCollector {
PostmortemReportCollectorCollectionFromGlobalTrackerTest,
SystemStateTest);
- // Collects a stability file, generates a report and registers it with the
- // database.
- void CollectAndSubmitOneReport(const crashpad::UUID& client_id,
- const base::FilePath& file);
+ // Processes a stability file, reports user metrics and optionally generates a
+ // crash report.
+ void ProcessOneReport(const crashpad::UUID& client_id,
+ const base::FilePath& file);
virtual CollectionStatus CollectOneReport(
const base::FilePath& stability_file,
@@ -96,6 +91,9 @@ class PostmortemReportCollector {
void RecordSystemShutdownState(StabilityReport* report) const;
+ void GenerateCrashReport(const crashpad::UUID& client_id,
+ StabilityReport* report_proto);
+
virtual bool WriteReportToMinidump(StabilityReport* report,
const crashpad::UUID& client_id,
const crashpad::UUID& report_id,
diff --git a/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
index 9214b6f8801..9192551a55d 100644
--- a/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
+++ b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
@@ -55,58 +55,6 @@ using testing::SetArgPointee;
namespace {
-TEST(PostmortemDeleterTest, BasicTest) {
- base::HistogramTester histogram_tester;
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- // Create three files.
- FilePath path_one = temp_dir.GetPath().AppendASCII("a.pma");
- FilePath path_two = temp_dir.GetPath().AppendASCII("b.pma");
- FilePath path_three = temp_dir.GetPath().AppendASCII("c.pma");
-
- std::vector<FilePath> stability_files = {path_one, path_two, path_three};
-
- for (const FilePath& path : stability_files) {
- {
- base::ScopedFILE file(base::OpenFile(path, "w"));
- ASSERT_NE(file.get(), nullptr);
- }
- ASSERT_TRUE(base::PathExists(path));
- }
-
- // Open one stability file to prevent its deletion.
- base::ScopedFILE file(base::OpenFile(path_two, "w"));
- ASSERT_NE(file.get(), nullptr);
-
- // Validate deletion and metrics.
- PostmortemDeleter deleter;
- deleter.Process(stability_files);
-
- ASSERT_FALSE(base::PathExists(path_one));
- ASSERT_FALSE(base::PathExists(path_three));
- histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status",
- UNCLEAN_SHUTDOWN, 2);
-
- ASSERT_TRUE(base::PathExists(path_two));
- histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status",
- DEBUG_FILE_DELETION_FAILED, 1);
-
- std::vector<CollectionStatus> unexpected_statuses = {
- NONE,
- SUCCESS,
- ANALYZER_CREATION_FAILED,
- DEBUG_FILE_NO_DATA,
- PREPARE_NEW_CRASH_REPORT_FAILED,
- WRITE_TO_MINIDUMP_FAILED,
- FINISHED_WRITING_CRASH_REPORT_FAILED,
- COLLECTION_ATTEMPT};
- for (CollectionStatus status : unexpected_statuses) {
- histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", status,
- 0);
- }
-}
-
const char kProductName[] = "TestProduct";
const char kVersionNumber[] = "TestVersionNumber";
const char kChannelName[] = "TestChannel";
@@ -153,7 +101,7 @@ class MockCrashReportDatabase : public CrashReportDatabase {
CrashReportDatabase::OperationStatus(const UUID& uuid));
};
-class MockPostmortemReportCollector : public PostmortemReportCollector {
+class MockPostmortemReportCollector final : public PostmortemReportCollector {
public:
explicit MockPostmortemReportCollector(CrashReportDatabase* crash_database)
: PostmortemReportCollector(kProductName,
@@ -198,10 +146,14 @@ MATCHER_P(EqualsProto, message, "") {
} // namespace
-class PostmortemReportCollectorProcessTest : public testing::Test {
+class PostmortemReportCollectorProcessTest
+ : public ::testing::TestWithParam<bool> {
public:
- void SetUpTest(bool system_session_clean, bool expect_write_dump) {
- collector_.reset(new MockPostmortemReportCollector(&database_));
+ void SetUpTest(bool system_session_clean,
+ bool expect_write_dump,
+ bool provide_crash_db) {
+ collector_.reset(new MockPostmortemReportCollector(
+ provide_crash_db ? &database_ : nullptr));
// Create a dummy debug file.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -212,7 +164,8 @@ class PostmortemReportCollectorProcessTest : public testing::Test {
}
ASSERT_TRUE(base::PathExists(debug_file_));
- EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr));
+ if (provide_crash_db)
+ EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr));
// Expect a single collection call.
StabilityReport report;
@@ -251,12 +204,14 @@ class PostmortemReportCollectorProcessTest : public testing::Test {
histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status",
UNCLEAN_SESSION, unclean_system_cnt);
}
- void CollectReports(bool is_session_clean) {
- SetUpTest(is_session_clean, true);
+ void CollectReports(bool is_session_clean, bool provide_crash_db) {
+ SetUpTest(is_session_clean, provide_crash_db, provide_crash_db);
- EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _))
- .Times(1)
- .WillOnce(Return(CrashReportDatabase::kNoError));
+ if (provide_crash_db) {
+ EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _))
+ .Times(1)
+ .WillOnce(Return(CrashReportDatabase::kNoError));
+ }
// Run the test.
std::vector<FilePath> debug_files{debug_file_};
@@ -273,24 +228,27 @@ class PostmortemReportCollectorProcessTest : public testing::Test {
CrashReportDatabase::NewReport crashpad_report_;
};
-TEST_F(PostmortemReportCollectorProcessTest, ProcessCleanSession) {
- CollectReports(true);
+TEST_P(PostmortemReportCollectorProcessTest, ProcessCleanSession) {
+ bool provide_crash_db = GetParam();
+ CollectReports(true, provide_crash_db);
int expected_unclean = 1;
int expected_system_unclean = 0;
ValidateHistograms(expected_unclean, expected_system_unclean);
}
-TEST_F(PostmortemReportCollectorProcessTest, ProcessUncleanSession) {
- CollectReports(false);
+TEST_P(PostmortemReportCollectorProcessTest, ProcessUncleanSession) {
+ bool provide_crash_db = GetParam();
+ CollectReports(false, provide_crash_db);
int expected_unclean = 1;
int expected_system_unclean = 1;
ValidateHistograms(expected_unclean, expected_system_unclean);
}
-TEST_F(PostmortemReportCollectorProcessTest, ProcessStuckFile) {
+TEST_P(PostmortemReportCollectorProcessTest, ProcessStuckFile) {
+ bool provide_crash_db = GetParam();
bool system_session_clean = true;
bool expect_write_dump = false;
- SetUpTest(system_session_clean, expect_write_dump);
+ SetUpTest(system_session_clean, expect_write_dump, provide_crash_db);
// Open the stability debug file to prevent its deletion.
base::ScopedFILE file(base::OpenFile(debug_file_, "w"));
@@ -308,6 +266,13 @@ TEST_F(PostmortemReportCollectorProcessTest, ProcessStuckFile) {
ValidateHistograms(expected_unclean, expected_system_unclean);
}
+INSTANTIATE_TEST_CASE_P(WithCrashDatabase,
+ PostmortemReportCollectorProcessTest,
+ ::testing::Values(true));
+INSTANTIATE_TEST_CASE_P(WithoutCrashDatabase,
+ PostmortemReportCollectorProcessTest,
+ ::testing::Values(true));
+
TEST(PostmortemReportCollectorTest, CollectEmptyFile) {
// Create an empty file.
base::ScopedTempDir temp_dir;
diff --git a/chromium/components/browser_watcher/stability_data_names.cc b/chromium/components/browser_watcher/stability_data_names.cc
index 98efb8cfa01..13144a5e1bc 100644
--- a/chromium/components/browser_watcher/stability_data_names.cc
+++ b/chromium/components/browser_watcher/stability_data_names.cc
@@ -10,6 +10,7 @@ const char kStabilityChannel[] = "channel";
const char kStabilityExecutionPhase[] = "stability-execution-phase";
const char kStabilityKeepAlive[] = "keep-alive";
const char kStabilityPlatform[] = "platform";
+const char kStabilityProcessType[] = "ptype";
const char kStabilityProduct[] = "product";
const char kStabilityReporterChannel[] = "reporter-channel";
const char kStabilityReporterPlatform[] = "reporter-platform";
diff --git a/chromium/components/browser_watcher/stability_data_names.h b/chromium/components/browser_watcher/stability_data_names.h
index 9ea312f551b..33dea50d411 100644
--- a/chromium/components/browser_watcher/stability_data_names.h
+++ b/chromium/components/browser_watcher/stability_data_names.h
@@ -12,6 +12,7 @@ extern const char kStabilityChannel[];
extern const char kStabilityExecutionPhase[];
extern const char kStabilityKeepAlive[];
extern const char kStabilityPlatform[];
+extern const char kStabilityProcessType[];
extern const char kStabilityProduct[];
extern const char kStabilityReporterChannel[];
extern const char kStabilityReporterPlatform[];
diff --git a/chromium/components/browser_watcher/stability_paths.cc b/chromium/components/browser_watcher/stability_paths.cc
index a8164dffbf2..70dc55ea06c 100644
--- a/chromium/components/browser_watcher/stability_paths.cc
+++ b/chromium/components/browser_watcher/stability_paths.cc
@@ -72,7 +72,8 @@ FilePath GetStabilityFileForProcess(base::ProcessId pid,
int64_t creation_time_us =
creation_time.tv_sec * kMicrosecondsPerSecond + creation_time.tv_usec;
- std::string file_name = base::StringPrintf("%u-%lld", pid, creation_time_us);
+ std::string file_name =
+ base::StringPrintf("%" CrPRIdPid "-%lld", pid, creation_time_us);
return stability_dir.AppendASCII(file_name).AddExtension(
base::PersistentMemoryAllocator::kFileExtension);
}
diff --git a/chromium/components/browser_watcher/stability_paths_unittest.cc b/chromium/components/browser_watcher/stability_paths_unittest.cc
index 7a8f6ceb281..5d198fa52f4 100644
--- a/chromium/components/browser_watcher/stability_paths_unittest.cc
+++ b/chromium/components/browser_watcher/stability_paths_unittest.cc
@@ -38,10 +38,10 @@ TEST_F(StabilityPathsMultiProcTest, GetStabilityFileForProcessTest) {
EXPECT_EQ(stability_path, stability_path_two);
// Ensure a different process has a different stability path.
- base::SpawnChildResult spawn_result = SpawnChild("DummyProcess");
+ base::Process process = SpawnChild("DummyProcess");
base::FilePath stability_path_other;
- ASSERT_TRUE(GetStabilityFileForProcess(spawn_result.process, empty_path,
- &stability_path_other));
+ ASSERT_TRUE(
+ GetStabilityFileForProcess(process, empty_path, &stability_path_other));
EXPECT_NE(stability_path, stability_path_other);
}
diff --git a/chromium/components/browser_watcher/stability_report.proto b/chromium/components/browser_watcher/stability_report.proto
index af0dae3c950..9d659b5c22f 100644
--- a/chromium/components/browser_watcher/stability_report.proto
+++ b/chromium/components/browser_watcher/stability_report.proto
@@ -87,7 +87,7 @@ message TypedValue {
}
// An activity represents information about something of interest on a thread.
-// Next id: 14
+// Next id: 18
message Activity {
enum Type {
UNKNOWN = 0;
@@ -136,7 +136,7 @@ message Activity {
// An arbitrary value used for information purposes.
optional int32 generic_data = 13;
- // Tag id 10 is reserved for server side augmentation.
+ // Tag ids 10 and 14-17 are reserved for server side augmentation.
// A key-value store.
map<string, TypedValue> user_data = 9;
@@ -171,16 +171,42 @@ message ThreadState {
}
// The state of a process.
-// Next id: 4
+// Next id: 7
message ProcessState {
+ enum Type {
+ UNKNOWN_PROCESS = 0;
+ BROWSER_PROCESS = 1;
+ WATCHER_PROCESS = 2;
+ }
+
+ message MemoryState {
+ message WindowsMemory {
+ // The private byte usage of the process. Unit is 4K pages.
+ optional uint32 process_private_usage = 1;
+ // The peak working set usage of the process. Unit is 4K pages.
+ optional uint32 process_peak_workingset_size = 2;
+ // The peak pagefile usage of the process. Unit is 4K pages.
+ optional uint32 process_peak_pagefile_usage = 3;
+ // The allocation request that caused OOM, bytes.
+ optional uint32 process_allocation_attempt = 4;
+ }
+
+ optional WindowsMemory windows_memory = 1;
+ }
+
// The identifier of the process.
optional int64 process_id = 3;
+ optional Type process_type = 5;
// Note: likely only a subset of modules of interest (e.g. Chromium's own
// modules).
repeated CodeModule modules = 1;
repeated ThreadState threads = 2;
- // TODO(manzagop): add experiment state.
+
+ optional MemoryState memory_state = 4;
+
+ // A key-value store global to the process.
+ map<string, TypedValue> data = 6;
}
// Description of a field trial or experiment that the user is currently
@@ -197,27 +223,46 @@ message FieldTrial {
optional fixed32 group_id = 2;
}
+// Records the state of system memory at the time of crash.
+// Next id: 2
+message SystemMemoryState {
+ message WindowsMemory {
+ // The system commit limit. Unit is number of 4K pages.
+ optional uint32 system_commit_limit = 1;
+ // The amount of system commit remaining. Unit is number of 4K pages.
+ optional uint32 system_commit_remaining = 2;
+ }
+
+ optional WindowsMemory windows_memory = 1;
+}
+
// A stability report contains information pertaining to the execution of a
// single logical instance of a "chrome browser". It is comprised of information
// about the system state and about the chrome browser's processes.
-// Next id: 7
+// Next id: 9
message StabilityReport {
// Whether the report is complete. Reports can be incomplete when the
// recording size quota is hit.
optional bool is_complete = 6;
+ // The process identifier of the crashed process.
+ optional int64 crashed_process_id = 8;
+
+ // State pertaining to the system.
optional SystemState system_state = 1;
- // TODO(manzagop): revisit whether a single repeated field should contain all
- // processes, or whether it's preferable to have separate fields per type.
- // TODO(manzagop): add information about the type of process, pid, process
- // times (e.g. start time), hierarchical relationships (e.g. parent pid),
- // command line, etc.
+
+ // State pertaining to Chrome's processes.
repeated ProcessState process_states = 2;
- // TODO(manzagop): if/when reports contain multiple processes, attribute and
- // relocate these to their process (and perhaps thread).
+
+ // Log messages. This is empty on official builds.
+ // TODO(manzagop): attribute messages to their process.
repeated string log_messages = 3;
+
+ // A global key-value store.
map<string, TypedValue> global_data = 4;
// The field trials the user is currently enrolled in.
repeated FieldTrial field_trials = 5;
+
+ optional SystemMemoryState system_memory_state = 7;
}
diff --git a/chromium/components/browser_watcher/stability_report_extractor.cc b/chromium/components/browser_watcher/stability_report_extractor.cc
index 156c68f6598..c9859c5e824 100644
--- a/chromium/components/browser_watcher/stability_report_extractor.cc
+++ b/chromium/components/browser_watcher/stability_report_extractor.cc
@@ -11,7 +11,6 @@
#include "base/debug/activity_analyzer.h"
#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -80,6 +79,18 @@ void CollectUserData(
}
collected_value.set_string_value(value.data(), value.size());
+
+ // Promote version information to the global key value store.
+ if (report) {
+ bool should_promote =
+ key == kStabilityProduct || key == kStabilityChannel ||
+ key == kStabilityPlatform || key == kStabilityVersion;
+ if (should_promote) {
+ (*report->mutable_global_data())[key].Swap(&collected_value);
+ continue;
+ }
+ }
+
break;
}
case ActivityUserData::STRING_VALUE_REFERENCE: {
@@ -101,6 +112,13 @@ void CollectUserData(
break;
case ActivityUserData::SIGNED_VALUE:
collected_value.set_signed_value(recorded_value.GetInt());
+
+ // Promote the execution timestamp to the global key value store.
+ if (report && key == kStabilityStartTimestamp) {
+ (*report->mutable_global_data())[key].Swap(&collected_value);
+ continue;
+ }
+
break;
case ActivityUserData::UNSIGNED_VALUE:
collected_value.set_unsigned_value(recorded_value.GetUint());
@@ -217,51 +235,37 @@ void CollectThread(
}
}
-} // namespace
-
-CollectionStatus Extract(const base::FilePath& stability_file,
- StabilityReport* report) {
- DCHECK(report);
-
- // Create a global analyzer.
- std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
- GlobalActivityAnalyzer::CreateWithFile(stability_file);
- if (!global_analyzer)
- return ANALYZER_CREATION_FAILED;
-
- // Extract data for only the first process.
- // TODO(manzagop): Extend this to all processes.
- int64_t pid = global_analyzer->GetFirstProcess();
+bool SetProcessType(ProcessState* process_state) {
+ DCHECK(process_state);
+ google::protobuf::Map<std::string, TypedValue>* process_data =
+ process_state->mutable_data();
- // Early exit if there is no data.
- std::vector<std::string> log_messages = global_analyzer->GetLogMessages();
- ActivityUserData::Snapshot process_data_snapshot =
- global_analyzer->GetProcessDataSnapshot(pid);
+ const auto it = process_data->find(kStabilityProcessType);
+ if (it == process_data->end())
+ return false;
- ThreadActivityAnalyzer* thread_analyzer =
- global_analyzer->GetFirstAnalyzer(pid);
- if (log_messages.empty() && process_data_snapshot.empty() &&
- !thread_analyzer) {
- return DEBUG_FILE_NO_DATA;
- }
+ const TypedValue& value = it->second;
+ if (value.value_case() != TypedValue::kSignedValue)
+ return false;
- report->set_is_complete(global_analyzer->IsDataComplete());
+ process_state->set_process_type(
+ static_cast<browser_watcher::ProcessState_Type>(value.signed_value()));
+ process_data->erase(it);
+ return true;
+}
- // Collect log messages.
- for (const std::string& message : log_messages) {
- report->add_log_messages(message);
- }
+void CollectProcess(int64_t pid,
+ GlobalActivityAnalyzer* analyzer,
+ StabilityReport* report) {
+ DCHECK(analyzer);
+ DCHECK(report);
- // Collect global user data.
- google::protobuf::Map<std::string, TypedValue>& global_data =
- *(report->mutable_global_data());
- CollectUserData(process_data_snapshot, &global_data, report);
+ ProcessState* process_state = report->add_process_states();
// Collect thread activity data.
- // Note: a single process is instrumented.
- ProcessState* process_state = report->add_process_states();
+ ThreadActivityAnalyzer* thread_analyzer = analyzer->GetFirstAnalyzer(pid);
for (; thread_analyzer != nullptr;
- thread_analyzer = global_analyzer->GetNextAnalyzer()) {
+ thread_analyzer = analyzer->GetNextAnalyzer()) {
// Only valid analyzers are expected per contract of GetFirstAnalyzer /
// GetNextAnalyzer.
DCHECK(thread_analyzer->IsValid());
@@ -277,8 +281,40 @@ CollectionStatus Extract(const base::FilePath& stability_file,
CollectThread(thread_analyzer->activity_snapshot(), thread_state);
}
+ // Collect global user data.
+ ActivityUserData::Snapshot process_data_snapshot =
+ analyzer->GetProcessDataSnapshot(pid);
+ CollectUserData(process_data_snapshot, process_state->mutable_data(), report);
+ SetProcessType(process_state);
+
// Collect module information.
- CollectModuleInformation(global_analyzer->GetModules(), process_state);
+ CollectModuleInformation(analyzer->GetModules(pid), process_state);
+}
+
+} // namespace
+
+CollectionStatus Extract(const base::FilePath& stability_file,
+ StabilityReport* report) {
+ DCHECK(report);
+
+ // Create a global analyzer.
+ std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
+ GlobalActivityAnalyzer::CreateWithFile(stability_file);
+ if (!global_analyzer)
+ return ANALYZER_CREATION_FAILED;
+ report->set_is_complete(global_analyzer->IsDataComplete());
+
+ // Collect process data.
+ for (int64_t pid = global_analyzer->GetFirstProcess(); pid != 0;
+ pid = global_analyzer->GetNextProcess()) {
+ CollectProcess(pid, global_analyzer.get(), report);
+ }
+
+ // Collect log messages.
+ std::vector<std::string> log_messages = global_analyzer->GetLogMessages();
+ for (const std::string& message : log_messages) {
+ report->add_log_messages(message);
+ }
return SUCCESS;
}
diff --git a/chromium/components/browser_watcher/stability_report_extractor_unittest.cc b/chromium/components/browser_watcher/stability_report_extractor_unittest.cc
index d5f50b631b8..1c3b5298779 100644
--- a/chromium/components/browser_watcher/stability_report_extractor_unittest.cc
+++ b/chromium/components/browser_watcher/stability_report_extractor_unittest.cc
@@ -341,8 +341,11 @@ TEST_F(StabilityReportExtractorTest, ProcessUserDataCollection) {
StabilityReport report;
ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report));
- // Validate the report's user data.
- const auto& collected_data = report.global_data();
+ // We expect a single process.
+ ASSERT_EQ(1, report.process_states_size());
+
+ // Validate the report contains the process' data.
+ const auto& collected_data = report.process_states(0).data();
ASSERT_EQ(kInternalProcessDatums + 8U, collected_data.size());
ASSERT_TRUE(base::ContainsKey(collected_data, "raw"));
@@ -396,6 +399,7 @@ TEST_F(StabilityReportExtractorTest, FieldTrialCollection) {
// Collect the stability report.
StabilityReport report;
ASSERT_EQ(SUCCESS, Extract(debug_file_path(), &report));
+ ASSERT_EQ(1, report.process_states_size());
// Validate the report's experiment and global data.
ASSERT_EQ(2, report.field_trials_size());
@@ -406,7 +410,7 @@ TEST_F(StabilityReportExtractorTest, FieldTrialCollection) {
report.field_trials(1).group_id());
// Expect 1 key/value pair.
- const auto& collected_data = report.global_data();
+ const auto& collected_data = report.process_states(0).data();
EXPECT_EQ(kInternalProcessDatums + 1U, collected_data.size());
EXPECT_TRUE(base::ContainsKey(collected_data, "string"));
}
diff --git a/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc b/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc
new file mode 100644
index 00000000000..913a10b54a1
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc
@@ -0,0 +1,212 @@
+// 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/browser_watcher/stability_report_user_stream_data_source.h"
+
+#include <string>
+#include <utility>
+
+#include <windows.h>
+
+// Must be included after windows.h.
+#include <psapi.h>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/process/memory.h"
+#include "base/process/process.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/browser_watcher/minidump_user_streams.h"
+#include "components/browser_watcher/stability_metrics.h"
+#include "components/browser_watcher/stability_paths.h"
+#include "components/browser_watcher/stability_report_extractor.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_user_extension_stream_data_source.h"
+#include "third_party/crashpad/crashpad/snapshot/exception_snapshot.h"
+#include "third_party/crashpad/crashpad/snapshot/process_snapshot.h"
+
+namespace browser_watcher {
+
+namespace {
+
+base::FilePath GetStabilityFileName(
+ const base::FilePath& user_data_dir,
+ crashpad::ProcessSnapshot* process_snapshot) {
+ DCHECK(process_snapshot);
+
+ timeval creation_time = {};
+ process_snapshot->ProcessStartTime(&creation_time);
+
+ return GetStabilityFileForProcess(process_snapshot->ProcessID(),
+ creation_time, user_data_dir);
+}
+
+class BufferExtensionStreamDataSource final
+ : public crashpad::MinidumpUserExtensionStreamDataSource {
+ public:
+ explicit BufferExtensionStreamDataSource(uint32_t stream_type);
+
+ bool Init(const StabilityReport& report);
+
+ size_t StreamDataSize() override;
+ bool ReadStreamData(Delegate* delegate) override;
+
+ private:
+ std::string data_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferExtensionStreamDataSource);
+};
+
+BufferExtensionStreamDataSource::BufferExtensionStreamDataSource(
+ uint32_t stream_type)
+ : crashpad::MinidumpUserExtensionStreamDataSource(stream_type) {}
+
+bool BufferExtensionStreamDataSource::Init(const StabilityReport& report) {
+ if (report.SerializeToString(&data_))
+ return true;
+ data_.clear();
+ return false;
+}
+
+size_t BufferExtensionStreamDataSource::StreamDataSize() {
+ DCHECK(!data_.empty());
+ return data_.size();
+}
+
+bool BufferExtensionStreamDataSource::ReadStreamData(Delegate* delegate) {
+ DCHECK(!data_.empty());
+ return delegate->ExtensionStreamDataSourceRead(
+ data_.size() ? data_.data() : nullptr, data_.size());
+}
+
+// TODO(manzagop): Collection should factor in whether this is a true crash or
+// dump without crashing.
+bool CollectStabilityReport(const base::FilePath& path,
+ StabilityReport* report) {
+ CollectionStatus status = Extract(path, report);
+ UMA_HISTOGRAM_ENUMERATION("ActivityTracker.CollectCrash.Status", status,
+ COLLECTION_STATUS_MAX);
+ if (status != SUCCESS)
+ return false;
+
+ LogCollectOnCrashEvent(CollectOnCrashEvent::kReportExtractionSuccess);
+ MarkStabilityFileDeletedOnCrash(path);
+
+ return true;
+}
+
+void CollectSystemMemoryMetrics(StabilityReport* report) {
+ // Grab system commit memory. Also best effort.
+ PERFORMANCE_INFORMATION perf_info = {sizeof(perf_info)};
+ if (GetPerformanceInfo(&perf_info, sizeof(perf_info))) {
+ auto* memory_state =
+ report->mutable_system_memory_state()->mutable_windows_memory();
+
+ memory_state->set_system_commit_limit(perf_info.CommitLimit);
+ memory_state->set_system_commit_remaining(perf_info.CommitLimit -
+ perf_info.CommitTotal);
+ }
+}
+
+void CollectProcessMemoryMetrics(crashpad::ProcessSnapshot* process_snapshot,
+ StabilityReport* report) {
+ const crashpad::ExceptionSnapshot* exception = process_snapshot->Exception();
+
+ if (!exception)
+ return;
+
+ // Find or create the ProcessState for the process in question.
+ base::ProcessId pid = process_snapshot->ProcessID();
+ ProcessState* process_state = nullptr;
+ for (int i = 0; i < report->process_states_size(); ++i) {
+ ProcessState* temp = report->mutable_process_states(i);
+
+ if (temp->has_process_id() && temp->process_id() == pid) {
+ process_state = temp;
+ break;
+ }
+ }
+
+ if (!process_state) {
+ process_state = report->add_process_states();
+ process_state->set_process_id(pid);
+ }
+
+ auto* memory_state =
+ process_state->mutable_memory_state()->mutable_windows_memory();
+
+ // Grab the requested allocation size in case of OOM exception.
+ if (exception->Exception() == base::win::kOomExceptionCode) {
+ const auto& codes = exception->Codes();
+ if (codes.size()) {
+ // The first parameter, if present, is the size of the allocation attempt.
+ memory_state->set_process_allocation_attempt(codes[0]);
+ }
+ }
+
+ base::Process process(base::Process::OpenWithAccess(
+ pid, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ));
+
+ if (process.IsValid()) {
+ PROCESS_MEMORY_COUNTERS_EX process_memory = {sizeof(process_memory)};
+ if (GetProcessMemoryInfo(
+ process.Handle(),
+ reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&process_memory),
+ sizeof(process_memory))) {
+ // This is in units of bytes, re-scale to pages for consistency with
+ // system metrics.
+ const uint64_t kPageSize = 4096;
+ memory_state->set_process_private_usage(process_memory.PrivateUsage /
+ kPageSize);
+ memory_state->set_process_peak_workingset_size(
+ process_memory.PeakWorkingSetSize / kPageSize);
+ memory_state->set_process_peak_pagefile_usage(
+ process_memory.PeakPagefileUsage / kPageSize);
+ }
+ }
+}
+
+} // namespace
+
+StabilityReportUserStreamDataSource::StabilityReportUserStreamDataSource(
+ const base::FilePath& user_data_dir)
+ : user_data_dir_(user_data_dir) {}
+
+std::unique_ptr<crashpad::MinidumpUserExtensionStreamDataSource>
+StabilityReportUserStreamDataSource::ProduceStreamData(
+ crashpad::ProcessSnapshot* process_snapshot) {
+ DCHECK(process_snapshot);
+ LogCollectOnCrashEvent(CollectOnCrashEvent::kCollectAttempt);
+
+ StabilityReport report;
+ bool collected_report = false;
+ if (!user_data_dir_.empty()) {
+ LogCollectOnCrashEvent(CollectOnCrashEvent::kUserDataDirNotEmpty);
+
+ base::FilePath stability_file =
+ GetStabilityFileName(user_data_dir_, process_snapshot);
+ if (PathExists(stability_file)) {
+ LogCollectOnCrashEvent(CollectOnCrashEvent::kPathExists);
+
+ collected_report = CollectStabilityReport(stability_file, &report);
+ }
+ }
+
+ CollectSystemMemoryMetrics(&report);
+ CollectProcessMemoryMetrics(process_snapshot, &report);
+
+ std::unique_ptr<BufferExtensionStreamDataSource> source(
+ new BufferExtensionStreamDataSource(kStabilityReportStreamType));
+ if (!source->Init(report))
+ return nullptr;
+
+ if (collected_report)
+ LogCollectOnCrashEvent(CollectOnCrashEvent::kSuccess);
+
+ return source;
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_report_user_stream_data_source.h b/chromium/components/browser_watcher/stability_report_user_stream_data_source.h
new file mode 100644
index 00000000000..c3bce63753d
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_report_user_stream_data_source.h
@@ -0,0 +1,40 @@
+// 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_BROWSER_WATCHER_STABILITY_REPORT_USER_STREAM_DATA_SOURCE_H_
+#define COMPONENTS_BROWSER_WATCHER_STABILITY_REPORT_USER_STREAM_DATA_SOURCE_H_
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "third_party/crashpad/crashpad/handler/user_stream_data_source.h"
+
+namespace crashpad {
+class MinidumpUserExtensionStreamDataSource;
+class ProcessSnapshot;
+} // namespace crashpad
+
+namespace browser_watcher {
+
+// Collects stability instrumentation corresponding to a ProcessSnapshot and
+// makes it available to the crash handler.
+class StabilityReportUserStreamDataSource
+ : public crashpad::UserStreamDataSource {
+ public:
+ explicit StabilityReportUserStreamDataSource(
+ const base::FilePath& user_data_dir);
+
+ std::unique_ptr<crashpad::MinidumpUserExtensionStreamDataSource>
+ ProduceStreamData(crashpad::ProcessSnapshot* process_snapshot) override;
+
+ private:
+ base::FilePath user_data_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(StabilityReportUserStreamDataSource);
+};
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_STABILITY_REPORT_USER_STREAM_DATA_SOURCE_H_
diff --git a/chromium/components/browser_watcher/watcher_client_win.cc b/chromium/components/browser_watcher/watcher_client_win.cc
index d411a2cf653..b236d5c0a7c 100644
--- a/chromium/components/browser_watcher/watcher_client_win.cc
+++ b/chromium/components/browser_watcher/watcher_client_win.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/process/launch.h"
-#include "base/win/windows_version.h"
namespace browser_watcher {
@@ -25,10 +24,8 @@ base::Process OpenOwnProcessInheritable() {
} // namespace
WatcherClient::WatcherClient(const CommandLineGenerator& command_line_generator)
- : use_legacy_launch_(base::win::GetVersion() < base::win::VERSION_VISTA),
- command_line_generator_(command_line_generator),
- process_(base::kNullProcessHandle) {
-}
+ : command_line_generator_(command_line_generator),
+ process_(base::kNullProcessHandle) {}
WatcherClient::~WatcherClient() {
}
@@ -41,20 +38,14 @@ void WatcherClient::LaunchWatcher() {
DCHECK(self.IsValid());
base::CommandLine cmd_line(command_line_generator_.Run(self.Handle()));
- base::HandlesToInheritVector to_inherit;
base::LaunchOptions options;
options.start_hidden = true;
- if (use_legacy_launch_) {
- // Launch the child process inheriting all handles on XP.
- options.inherit_handles = true;
- } else {
- // Launch the child process inheriting only |self| on
- // Vista and better.
- to_inherit.push_back(self.Handle());
- to_inherit.insert(to_inherit.end(), inherited_handles_.begin(),
- inherited_handles_.end());
- options.handles_to_inherit = &to_inherit;
- }
+
+ // Launch the child process inheriting only |self|.
+ options.handles_to_inherit.push_back(self.Handle());
+ options.handles_to_inherit.insert(options.handles_to_inherit.end(),
+ inherited_handles_.begin(),
+ inherited_handles_.end());
process_ = base::LaunchProcess(cmd_line, options);
if (!process_.IsValid())
diff --git a/chromium/components/browser_watcher/watcher_client_win.h b/chromium/components/browser_watcher/watcher_client_win.h
index 0a6cee0a88b..3964d8307d1 100644
--- a/chromium/components/browser_watcher/watcher_client_win.h
+++ b/chromium/components/browser_watcher/watcher_client_win.h
@@ -30,8 +30,7 @@ class WatcherClient {
~WatcherClient();
// Launches the watcher process such that the child process is able to inherit
- // a handle to the current process. If use_legacy_launch() is true, this uses
- // a non-threadsafe legacy launch mode that's compatible with Windows XP.
+ // a handle to the current process.
void LaunchWatcher();
// Ensures that |handle| may be inherited by the watcher process. |handle|
@@ -42,18 +41,7 @@ class WatcherClient {
// Returns the launched process.
const base::Process& process() const { return process_; }
- // Accessors, exposed only for testing.
- bool use_legacy_launch() const { return use_legacy_launch_; }
- void set_use_legacy_launch(bool use_legacy_launch) {
- use_legacy_launch_ = use_legacy_launch;
- }
-
private:
- // If true, the watcher process will be launched with XP legacy handle
- // inheritance. This is not thread safe and can leak random handles into the
- // child process, but it's the best we can do on XP.
- bool use_legacy_launch_;
-
// The CommandLineGenerator passed to the constructor.
CommandLineGenerator command_line_generator_;
diff --git a/chromium/components/browser_watcher/watcher_client_win_unittest.cc b/chromium/components/browser_watcher/watcher_client_win_unittest.cc
index c801494e888..ae9323df18e 100644
--- a/chromium/components/browser_watcher/watcher_client_win_unittest.cc
+++ b/chromium/components/browser_watcher/watcher_client_win_unittest.cc
@@ -20,7 +20,6 @@
#include "base/test/multiprocess_test.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/scoped_handle.h"
-#include "base/win/windows_version.h"
#include "components/browser_watcher/exit_code_watcher_win.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -29,10 +28,8 @@ namespace browser_watcher {
namespace {
-// Command line switches used to communiate to the child test.
+// Command line switch used to communiate to the child test.
const char kParentHandle[] = "parent-handle";
-const char kLeakHandle[] = "leak-handle";
-const char kNoLeakHandle[] = "no-leak-handle";
bool IsValidParentProcessHandle(base::CommandLine& cmd_line,
const char* switch_name) {
@@ -78,23 +75,6 @@ MULTIPROCESS_TEST_MAIN(VerifyParentHandle) {
return 1;
}
- // If in the legacy mode, we expect this second handle will leak into the
- // child process. This mainly serves to verify that the legacy mode is
- // getting tested.
- if (cmd_line->HasSwitch(kLeakHandle) &&
- !IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
- LOG(ERROR) << "Parent process handle unexpectedly didn't leak.";
- return 1;
- }
-
- // If not in the legacy mode, this second handle should not leak into the
- // child process.
- if (cmd_line->HasSwitch(kNoLeakHandle) &&
- IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
- LOG(ERROR) << "Parent process handle unexpectedly leaked.";
- return 1;
- }
-
return 0;
}
@@ -109,39 +89,19 @@ class WatcherClientTest : public base::MultiProcessTest {
ASSERT_TRUE(self_.IsValid());
}
- enum HandlePolicy {
- LEAK_HANDLE,
- NO_LEAK_HANDLE
- };
-
// Get a base command line to launch back into this test fixture.
- base::CommandLine GetBaseCommandLine(HandlePolicy handle_policy,
- HANDLE parent_handle) {
+ base::CommandLine GetBaseCommandLine(HANDLE parent_handle) {
base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
ret.AppendSwitchASCII(switches::kTestChildProcess, "VerifyParentHandle");
ret.AppendSwitchASCII(kParentHandle, HandleToString(parent_handle));
- switch (handle_policy) {
- case LEAK_HANDLE:
- ret.AppendSwitchASCII(kLeakHandle, HandleToString(self_.Get()));
- break;
-
- case NO_LEAK_HANDLE:
- ret.AppendSwitchASCII(kNoLeakHandle, HandleToString(self_.Get()));
- break;
-
- default:
- ADD_FAILURE() << "Impossible handle_policy";
- }
-
return ret;
}
- WatcherClient::CommandLineGenerator GetBaseCommandLineGenerator(
- HandlePolicy handle_policy) {
+ WatcherClient::CommandLineGenerator GetBaseCommandLineGenerator() {
return base::Bind(&WatcherClientTest::GetBaseCommandLine,
- base::Unretained(this), handle_policy);
+ base::Unretained(this));
}
void AssertSuccessfulExitCode(base::Process process) {
@@ -161,42 +121,7 @@ class WatcherClientTest : public base::MultiProcessTest {
// TODO(siggi): More testing - test WatcherClient base implementation.
TEST_F(WatcherClientTest, LaunchWatcherSucceeds) {
- // We can only use the non-legacy launch method on Windows Vista or better.
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
- return;
-
- WatcherClient client(GetBaseCommandLineGenerator(NO_LEAK_HANDLE));
- ASSERT_FALSE(client.use_legacy_launch());
-
- client.LaunchWatcher();
-
- ASSERT_NO_FATAL_FAILURE(
- AssertSuccessfulExitCode(client.process().Duplicate()));
-}
-
-TEST_F(WatcherClientTest, LaunchWatcherLegacyModeSucceeds) {
- // Test the XP-compatible legacy launch mode. This is expected to leak
- // a handle to the child process.
- WatcherClient client(GetBaseCommandLineGenerator(LEAK_HANDLE));
-
- // Use the legacy launch mode.
- client.set_use_legacy_launch(true);
-
- client.LaunchWatcher();
-
- ASSERT_NO_FATAL_FAILURE(
- AssertSuccessfulExitCode(client.process().Duplicate()));
-}
-
-TEST_F(WatcherClientTest, LegacyModeDetectedOnXP) {
- // This test only works on Windows XP.
- if (base::win::GetVersion() > base::win::VERSION_XP)
- return;
-
- // Test that the client detects the need to use legacy launch mode, and that
- // it works on Windows XP.
- WatcherClient client(GetBaseCommandLineGenerator(LEAK_HANDLE));
- ASSERT_TRUE(client.use_legacy_launch());
+ WatcherClient client(GetBaseCommandLineGenerator());
client.LaunchWatcher();
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
index a95e63a8bc1..2e842e33f3f 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
@@ -222,8 +222,7 @@ void WatcherMetricsProviderWin::ProvideStabilityMetrics(
RecordExitCodes(registry_path_);
}
-void WatcherMetricsProviderWin::CollectPostmortemReports(
- const base::Closure& done_callback) {
+void WatcherMetricsProviderWin::AsyncInit(const base::Closure& done_callback) {
task_runner_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(&WatcherMetricsProviderWin::CollectPostmortemReportsImpl,
@@ -268,34 +267,37 @@ void WatcherMetricsProviderWin::CollectPostmortemReportsImpl() {
const bool should_collect = base::GetFieldTrialParamByFeatureAsBool(
browser_watcher::kStabilityDebuggingFeature,
browser_watcher::kCollectPostmortemParam, false);
- if (!should_collect) {
- PostmortemDeleter deleter;
- deleter.Process(stability_files);
- return;
- }
// Create a database. Note: Chrome already has a g_database in crashpad.cc but
// it has internal linkage. Create a new one.
- std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database =
- crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_);
- if (!crashpad_database) {
- LOG(ERROR) << "Failed to initialize a CrashPad database.";
- LogCollectionInitStatus(CRASHPAD_DATABASE_INIT_FAILED);
- return;
+ std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database;
+ if (should_collect) {
+ crashpad_database =
+ crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_);
+ if (!crashpad_database) {
+ LOG(ERROR) << "Failed to initialize a CrashPad database.";
+ LogCollectionInitStatus(CRASHPAD_DATABASE_INIT_FAILED);
+ // Note: continue to processing the files anyway.
+ }
}
+ // Note: this is logged even when Crashpad database initialization fails.
LogCollectionInitStatus(INIT_SUCCESS);
- // Get the reporter's version details.
- base::string16 product_name, version_number, channel_name;
- exe_details_cb_.Run(&product_name, &version_number, &channel_name);
-
const size_t kSystemSessionsToInspect = 5U;
SystemSessionAnalyzer analyzer(kSystemSessionsToInspect);
- PostmortemReportCollector collector(
- base::UTF16ToUTF8(product_name), base::UTF16ToUTF8(version_number),
- base::UTF16ToUTF8(channel_name), crashpad_database.get(), &analyzer);
- collector.Process(stability_files);
+
+ if (should_collect) {
+ base::string16 product_name, version_number, channel_name;
+ exe_details_cb_.Run(&product_name, &version_number, &channel_name);
+ PostmortemReportCollector collector(
+ base::UTF16ToUTF8(product_name), base::UTF16ToUTF8(version_number),
+ base::UTF16ToUTF8(channel_name), crashpad_database.get(), &analyzer);
+ collector.Process(stability_files);
+ } else {
+ PostmortemReportCollector collector(&analyzer);
+ collector.Process(stability_files);
+ }
}
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win.h b/chromium/components/browser_watcher/watcher_metrics_provider_win.h
index fbd408233c0..df792c9d68c 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win.h
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win.h
@@ -33,6 +33,7 @@ class WatcherMetricsProviderWin : public metrics::MetricsProvider {
~WatcherMetricsProviderWin() override;
// metrics::MetricsProvider implementation.
+ void AsyncInit(const base::Closure& done_callback) override;
void OnRecordingEnabled() override;
void OnRecordingDisabled() override;
// Note: this function collects metrics, some of which are related to the
@@ -48,10 +49,6 @@ class WatcherMetricsProviderWin : public metrics::MetricsProvider {
void ProvideStabilityMetrics(
metrics::SystemProfileProto* system_profile_proto) override;
- // Collects postmortem reports asynchronously and calls |done_callback| when
- // done.
- void CollectPostmortemReports(const base::Closure& done_callback);
-
private:
// TODO(manzagop): avoid collecting reports for clean exits from the fast exit
// path.
diff --git a/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc b/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
index 2df2a7b5a1c..e5a31bf2fe2 100644
--- a/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
+++ b/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
@@ -362,7 +362,8 @@ class WindowHangMonitorTest : public testing::Test {
AppendSwitchHandle(&command_line, kChildWritePipeSwitch, child_write_pipe);
base::LaunchOptions options = {};
- options.inherit_handles = true;
+ // TODO(brettw) bug 748258: Share only explicit handles.
+ options.inherit_mode = base::LaunchOptions::Inherit::kAll;
monitored_process_ = base::LaunchProcess(command_line, options);
if (!monitored_process_.IsValid())
return false;
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.cc b/chromium/components/browsing_data/core/browsing_data_utils.cc
index 5e04932b640..973d2e4d339 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils.cc
+++ b/chromium/components/browsing_data/core/browsing_data_utils.cc
@@ -4,6 +4,7 @@
#include "components/browsing_data/core/browsing_data_utils.h"
+#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "components/browsing_data/core/counters/autofill_counter.h"
@@ -231,8 +232,16 @@ bool GetDeletionPreferenceFromDataType(
case BrowsingDataType::COOKIES:
*out_pref = prefs::kDeleteCookiesBasic;
return true;
- default:
- // This is not a valid type for the basic tab.
+ case BrowsingDataType::PASSWORDS:
+ case BrowsingDataType::FORM_DATA:
+ case BrowsingDataType::BOOKMARKS:
+ case BrowsingDataType::SITE_SETTINGS:
+ case BrowsingDataType::DOWNLOADS:
+ case BrowsingDataType::MEDIA_LICENSES:
+ case BrowsingDataType::HOSTED_APPS_DATA:
+ return false; // No corresponding preference on basic tab.
+ case BrowsingDataType::NUM_TYPES:
+ // This is not an actual type.
NOTREACHED();
return false;
}
@@ -255,20 +264,56 @@ bool GetDeletionPreferenceFromDataType(
return true;
case BrowsingDataType::BOOKMARKS:
// Bookmarks are deleted on the Android side. No corresponding deletion
- // preference.
+ // preference. Not implemented on Desktop.
return false;
case BrowsingDataType::SITE_SETTINGS:
*out_pref = prefs::kDeleteSiteSettings;
return true;
+ case BrowsingDataType::DOWNLOADS:
+ *out_pref = prefs::kDeleteDownloadHistory;
+ return true;
+ case BrowsingDataType::MEDIA_LICENSES:
+ *out_pref = prefs::kDeleteMediaLicenses;
+ return true;
+ case BrowsingDataType::HOSTED_APPS_DATA:
+ *out_pref = prefs::kDeleteHostedAppsData;
+ return true;
case BrowsingDataType::NUM_TYPES:
- // This is not an actual type.
- NOTREACHED();
+ NOTREACHED(); // This is not an actual type.
return false;
}
NOTREACHED();
return false;
}
+BrowsingDataType GetDataTypeFromDeletionPreference(
+ const std::string& pref_name) {
+ using DataTypeMap = base::flat_map<std::string, BrowsingDataType>;
+ CR_DEFINE_STATIC_LOCAL(
+ DataTypeMap, preference_to_datatype,
+ (
+ {
+ {prefs::kDeleteBrowsingHistory, BrowsingDataType::HISTORY},
+ {prefs::kDeleteBrowsingHistoryBasic, BrowsingDataType::HISTORY},
+ {prefs::kDeleteCache, BrowsingDataType::CACHE},
+ {prefs::kDeleteCacheBasic, BrowsingDataType::CACHE},
+ {prefs::kDeleteCookies, BrowsingDataType::COOKIES},
+ {prefs::kDeleteCookiesBasic, BrowsingDataType::COOKIES},
+ {prefs::kDeletePasswords, BrowsingDataType::PASSWORDS},
+ {prefs::kDeleteFormData, BrowsingDataType::FORM_DATA},
+ {prefs::kDeleteSiteSettings, BrowsingDataType::SITE_SETTINGS},
+ {prefs::kDeleteDownloadHistory, BrowsingDataType::DOWNLOADS},
+ {prefs::kDeleteMediaLicenses, BrowsingDataType::MEDIA_LICENSES},
+ {prefs::kDeleteHostedAppsData,
+ BrowsingDataType::HOSTED_APPS_DATA},
+ },
+ base::KEEP_FIRST_OF_DUPES));
+
+ auto iter = preference_to_datatype.find(pref_name);
+ DCHECK(iter != preference_to_datatype.end());
+ return iter->second;
+}
+
void MigratePreferencesToBasic(PrefService* prefs) {
if (!prefs->GetBoolean(prefs::kPreferencesMigratedToBasic)) {
prefs->SetBoolean(prefs::kDeleteBrowsingHistoryBasic,
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.h b/chromium/components/browsing_data/core/browsing_data_utils.h
index d97e68cd69d..dff3ccd7b0d 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils.h
+++ b/chromium/components/browsing_data/core/browsing_data_utils.h
@@ -7,14 +7,13 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/browsing_data/core/clear_browsing_data_tab.h"
#include "components/browsing_data/core/counters/browsing_data_counter.h"
namespace browsing_data {
-// Browsing data types as seen in the Android UI.
-// TODO(msramek): Reuse this enum as the canonical representation of the
-// user-facing browsing data types in the Desktop UI as well.
+// Browsing data types as seen in the Android and Desktop UI.
//
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
@@ -24,8 +23,13 @@ enum class BrowsingDataType {
COOKIES,
PASSWORDS,
FORM_DATA,
+ // Only for Android:
BOOKMARKS,
SITE_SETTINGS,
+ // Only for Desktop:
+ DOWNLOADS,
+ MEDIA_LICENSES,
+ HOSTED_APPS_DATA,
NUM_TYPES
};
@@ -71,6 +75,9 @@ bool GetDeletionPreferenceFromDataType(
ClearBrowsingDataTab clear_browsing_data_tab,
std::string* out_pref);
+BrowsingDataType GetDataTypeFromDeletionPreference(
+ const std::string& pref_name);
+
// Copies the deletion preferences for timeperiod, cache, history and cookies
// to a separate preferences that are used to on the basic CBD tab.
// This only happens the first time this method is called.
diff --git a/chromium/components/captive_portal/BUILD.gn b/chromium/components/captive_portal/BUILD.gn
index 12551f9009a..5966edde4ab 100644
--- a/chromium/components/captive_portal/BUILD.gn
+++ b/chromium/components/captive_portal/BUILD.gn
@@ -7,6 +7,8 @@ component("captive_portal") {
"captive_portal_detector.cc",
"captive_portal_detector.h",
"captive_portal_export.h",
+ "captive_portal_metrics.cc",
+ "captive_portal_metrics.h",
"captive_portal_types.cc",
"captive_portal_types.h",
]
diff --git a/chromium/components/captive_portal/captive_portal_metrics.cc b/chromium/components/captive_portal/captive_portal_metrics.cc
new file mode 100644
index 00000000000..8b9de27ca14
--- /dev/null
+++ b/chromium/components/captive_portal/captive_portal_metrics.cc
@@ -0,0 +1,17 @@
+// 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/captive_portal/captive_portal_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace captive_portal {
+
+void CaptivePortalMetrics::LogCaptivePortalBlockingPageEvent(
+ CaptivePortalBlockingPageEvent event) {
+ UMA_HISTOGRAM_ENUMERATION("interstitial.captive_portal", event,
+ CAPTIVE_PORTAL_BLOCKING_PAGE_EVENT_COUNT);
+}
+
+} // namespace captive_portal
diff --git a/chromium/components/captive_portal/captive_portal_metrics.h b/chromium/components/captive_portal/captive_portal_metrics.h
new file mode 100644
index 00000000000..90f1adeb824
--- /dev/null
+++ b/chromium/components/captive_portal/captive_portal_metrics.h
@@ -0,0 +1,33 @@
+// 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_CAPTIVE_PORTAL_CAPTIVE_PORTAL_METRICS_H_
+#define COMPONENTS_CAPTIVE_PORTAL_CAPTIVE_PORTAL_METRICS_H_
+
+#include "base/macros.h"
+#include "components/captive_portal/captive_portal_export.h"
+
+namespace captive_portal {
+
+// Class which defines metrics used for tracking user interaction with captive
+// portals.
+class CAPTIVE_PORTAL_EXPORT CaptivePortalMetrics {
+ public:
+ // User action when the user is shown a captive portal error page.
+ enum CaptivePortalBlockingPageEvent {
+ SHOW_ALL,
+ OPEN_LOGIN_PAGE,
+ CAPTIVE_PORTAL_BLOCKING_PAGE_EVENT_COUNT
+ };
+
+ // Logs a user action when the user is shown a captive portal error page.
+ static void LogCaptivePortalBlockingPageEvent(
+ CaptivePortalBlockingPageEvent event);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CaptivePortalMetrics);
+};
+
+} // namespace captive_portal
+
+#endif // COMPONENTS_CAPTIVE_PORTAL_CAPTIVE_PORTAL_METRICS_H_
diff --git a/chromium/components/cast_certificate/cast_cert_validator.cc b/chromium/components/cast_certificate/cast_cert_validator.cc
index 608f7a747e9..7dc6cb532b9 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator.cc
@@ -17,13 +17,14 @@
#include "components/cast_certificate/cast_crl.h"
#include "net/cert/internal/cert_issuer_source_static.h"
#include "net/cert/internal/certificate_policies.h"
+#include "net/cert/internal/common_cert_errors.h"
#include "net/cert/internal/extended_key_usage.h"
#include "net/cert/internal/parse_certificate.h"
#include "net/cert/internal/parse_name.h"
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/path_builder.h"
#include "net/cert/internal/signature_algorithm.h"
-#include "net/cert/internal/signature_policy.h"
+#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/x509_util.h"
@@ -92,19 +93,17 @@ net::der::Input AudioOnlyPolicyOid() {
// Cast certificates rely on RSASSA-PKCS#1 v1.5 with SHA-1 for signatures.
//
-// The following signature policy specifies which signature algorithms (and key
-// sizes) are acceptable. It is used when verifying a chain of certificates, as
-// well as when verifying digital signature using the target certificate's
-// SPKI.
+// The following delegate will allow signature algorithms of:
//
-// This particular policy allows for:
// * ECDSA, RSA-SSA, and RSA-PSS
// * Supported EC curves: P-256, P-384, P-521.
// * Hashes: All SHA hashes including SHA-1 (despite being known weak).
-// * RSA keys must have a modulus at least 2048-bits long.
-std::unique_ptr<net::SignaturePolicy> CreateCastSignaturePolicy() {
- return base::MakeUnique<net::SimpleSignaturePolicy>(2048);
-}
+//
+// It will also require RSA keys have a modulus at least 2048-bits long.
+class CastPathBuilderDelegate : public net::SimplePathBuilderDelegate {
+ public:
+ CastPathBuilderDelegate() : SimplePathBuilderDelegate(2048) {}
+};
class CertVerificationContextImpl : public CertVerificationContext {
public:
@@ -113,24 +112,19 @@ class CertVerificationContextImpl : public CertVerificationContext {
const base::StringPiece& common_name)
: spki_(spki.AsString()), common_name_(common_name.as_string()) {}
- bool VerifySignatureOverData(const base::StringPiece& signature,
- const base::StringPiece& data) const override {
+ bool VerifySignatureOverData(
+ const base::StringPiece& signature,
+ const base::StringPiece& data,
+ net::DigestAlgorithm digest_algorithm) const override {
// This code assumes the signature algorithm was RSASSA PKCS#1 v1.5 with
- // SHA-1.
- // TODO(eroman): Is it possible to use other hash algorithms?
+ // |digest_algorithm|.
auto signature_algorithm =
- net::SignatureAlgorithm::CreateRsaPkcs1(net::DigestAlgorithm::Sha1);
+ net::SignatureAlgorithm::CreateRsaPkcs1(digest_algorithm);
- // Use the same policy as was used for verifying signatures in
- // certificates. This will ensure for instance that the key used is at
- // least 2048-bits long.
- auto signature_policy = CreateCastSignaturePolicy();
-
- net::CertErrors errors;
return net::VerifySignedData(
*signature_algorithm, net::der::Input(data),
net::der::BitString(net::der::Input(signature), 0),
- net::der::Input(&spki_), signature_policy.get(), &errors);
+ net::der::Input(&spki_));
}
std::string GetCommonName() const override { return common_name_; }
@@ -234,19 +228,35 @@ net::ParseCertificateOptions GetCertParsingOptions() {
return options;
}
+// Returns the CastCertError for the failed path building.
+// This function must only be called if path building failed.
+CastCertError MapToCastError(const net::CertPathBuilder::Result& result) {
+ DCHECK(!result.HasValidPath());
+ if (result.paths.empty())
+ return CastCertError::ERR_CERTS_VERIFY_GENERIC;
+ const net::CertPathErrors& path_errors =
+ result.paths.at(result.best_result_index)->errors;
+ if (path_errors.ContainsError(net::cert_errors::kValidityFailedNotAfter) ||
+ path_errors.ContainsError(net::cert_errors::kValidityFailedNotBefore)) {
+ return CastCertError::ERR_CERTS_DATE_INVALID;
+ }
+ return CastCertError::ERR_CERTS_VERIFY_GENERIC;
+}
+
} // namespace
-bool VerifyDeviceCert(const std::vector<std::string>& certs,
- const base::Time& time,
- std::unique_ptr<CertVerificationContext>* context,
- CastDeviceCertPolicy* policy,
- const CastCRL* crl,
- CRLPolicy crl_policy) {
+CastCertError VerifyDeviceCert(
+ const std::vector<std::string>& certs,
+ const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy) {
return VerifyDeviceCertUsingCustomTrustStore(
certs, time, context, policy, crl, crl_policy, &CastTrustStore::Get());
}
-bool VerifyDeviceCertUsingCustomTrustStore(
+CastCertError VerifyDeviceCertUsingCustomTrustStore(
const std::vector<std::string>& certs,
const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
@@ -258,7 +268,11 @@ bool VerifyDeviceCertUsingCustomTrustStore(
return VerifyDeviceCert(certs, time, context, policy, crl, crl_policy);
if (certs.empty())
- return false;
+ return CastCertError::ERR_CERTS_MISSING;
+
+ // Fail early if CRL is required but not provided.
+ if (!crl && crl_policy == CRLPolicy::CRL_REQUIRED)
+ return CastCertError::ERR_CRL_INVALID;
net::CertErrors errors;
scoped_refptr<net::ParsedCertificate> target_cert;
@@ -267,9 +281,8 @@ bool VerifyDeviceCertUsingCustomTrustStore(
scoped_refptr<net::ParsedCertificate> cert(net::ParsedCertificate::Create(
net::x509_util::CreateCryptoBuffer(certs[i]), GetCertParsingOptions(),
&errors));
- // TODO(eroman): Propagate/log these parsing errors.
if (!cert)
- return false;
+ return CastCertError::ERR_CERTS_PARSE;
if (i == 0)
target_cert = std::move(cert);
@@ -277,26 +290,23 @@ bool VerifyDeviceCertUsingCustomTrustStore(
intermediate_cert_issuer_source.AddCert(std::move(cert));
}
- // Use a signature policy compatible with Cast's PKI.
- auto signature_policy = CreateCastSignaturePolicy();
+ CastPathBuilderDelegate path_builder_delegate;
// Do path building and RFC 5280 compatible certificate verification using the
// two Cast trust anchors and Cast signature policy.
net::der::GeneralizedTime verification_time;
if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time))
- return false;
+ return CastCertError::ERR_UNEXPECTED;
net::CertPathBuilder::Result result;
net::CertPathBuilder path_builder(
- target_cert.get(), trust_store, signature_policy.get(), verification_time,
+ target_cert.get(), trust_store, &path_builder_delegate, verification_time,
net::KeyPurpose::CLIENT_AUTH, net::InitialExplicitPolicy::kFalse,
{net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
net::InitialAnyPolicyInhibit::kFalse, &result);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
path_builder.Run();
- if (!result.HasValidPath()) {
- // TODO(crbug.com/634443): Log error information.
- return false;
- }
+ if (!result.HasValidPath())
+ return MapToCastError(result);
// Determine whether this device certificate is restricted to audio-only.
DetermineDeviceCertificatePolicy(result.GetBestValidPath(), policy);
@@ -305,19 +315,13 @@ bool VerifyDeviceCertUsingCustomTrustStore(
// building (key usage), and construct a CertVerificationContext that uses
// its public key.
if (!CheckTargetCertificate(target_cert.get(), context))
- return false;
+ return CastCertError::ERR_CERTS_RESTRICTIONS;
- // Check if a CRL is available.
- if (!crl) {
- if (crl_policy == CRLPolicy::CRL_REQUIRED) {
- return false;
- }
- } else {
- if (!crl->CheckRevocation(result.GetBestValidPath()->path, time)) {
- return false;
- }
- }
- return true;
+ // Check for revocation.
+ if (crl && !crl->CheckRevocation(result.GetBestValidPath()->path, time))
+ return CastCertError::ERR_CERTS_REVOKED;
+
+ return CastCertError::OK;
}
std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
diff --git a/chromium/components/cast_certificate/cast_cert_validator.h b/chromium/components/cast_certificate/cast_cert_validator.h
index 1ef400d31bc..a98e11a8ca8 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.h
+++ b/chromium/components/cast_certificate/cast_cert_validator.h
@@ -16,6 +16,7 @@
namespace net {
class TrustStore;
+enum class DigestAlgorithm;
}
namespace cast_certificate {
@@ -38,6 +39,27 @@ enum class CRLPolicy {
CRL_REQUIRED,
};
+enum class CastCertError {
+ OK,
+ // Certificates were not provided for verification.
+ ERR_CERTS_MISSING,
+ // The certificates provided could not be parsed.
+ ERR_CERTS_PARSE,
+ // Key usage is missing or is not set to Digital Signature.
+ // This error could also be thrown if the CN is missing.
+ ERR_CERTS_RESTRICTIONS,
+ // The current date is before the notBefore date or after the notAfter date.
+ ERR_CERTS_DATE_INVALID,
+ // The certificate failed to chain to a trusted root.
+ ERR_CERTS_VERIFY_GENERIC,
+ // The CRL is missing or failed to verify.
+ ERR_CRL_INVALID,
+ // One of the certificates in the chain is revoked.
+ ERR_CERTS_REVOKED,
+ // An internal coding error.
+ ERR_UNEXPECTED,
+};
+
// An object of this type is returned by the VerifyDeviceCert function, and can
// be used for additional certificate-related operations, using the verified
// certificate.
@@ -47,11 +69,13 @@ class CertVerificationContext {
virtual ~CertVerificationContext() {}
// Use the public key from the verified certificate to verify a
- // sha1WithRSAEncryption |signature| over arbitrary |data|. Both |signature|
- // and |data| hold raw binary data. Returns true if the signature was
- // correct.
- virtual bool VerifySignatureOverData(const base::StringPiece& signature,
- const base::StringPiece& data) const = 0;
+ // |digest_algorithm|WithRSAEncryption |signature| over arbitrary |data|.
+ // Both |signature| and |data| hold raw binary data. Returns true if the
+ // signature was correct.
+ virtual bool VerifySignatureOverData(
+ const base::StringPiece& signature,
+ const base::StringPiece& data,
+ net::DigestAlgorithm digest_algorithm) const = 0;
// Retrieve the Common Name attribute of the subject's distinguished name from
// the verified certificate, if present. Returns an empty string if no Common
@@ -84,27 +108,29 @@ class CertVerificationContext {
//
// Outputs:
//
-// Returns true on success, false on failure. On success the output
-// parameters are filled with more details:
+// Returns CastCertError::OK on success. Otherwise, the corresponding
+// CastCertError. On success, the output parameters are filled with more
+// details:
//
// * |context| is filled with an object that can be used to verify signatures
// using the device certificate's public key, as well as to extract other
// properties from the device certificate (Common Name).
// * |policy| is filled with an indication of the device certificate's policy
// (i.e. is it for audio-only devices or is it unrestricted?)
-bool VerifyDeviceCert(const std::vector<std::string>& certs,
- const base::Time& time,
- std::unique_ptr<CertVerificationContext>* context,
- CastDeviceCertPolicy* policy,
- const CastCRL* crl,
- CRLPolicy crl_policy) WARN_UNUSED_RESULT;
+CastCertError VerifyDeviceCert(
+ const std::vector<std::string>& certs,
+ const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy) WARN_UNUSED_RESULT;
// This is an overloaded version of VerifyDeviceCert that allows
// the input of a custom TrustStore.
//
// For production use pass |trust_store| as nullptr to use the production trust
// store.
-bool VerifyDeviceCertUsingCustomTrustStore(
+CastCertError VerifyDeviceCertUsingCustomTrustStore(
const std::vector<std::string>& certs,
const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
diff --git a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
index 7a8d1e55970..9fe86979475 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
@@ -7,6 +7,7 @@
#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "net/cert/x509_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,12 +22,6 @@ std::string CreateString(const uint8_t (&data)[N]) {
return std::string(reinterpret_cast<const char*>(data), N);
}
-// Indicates the expected result of test verification.
-enum TestResult {
- RESULT_SUCCESS,
- RESULT_FAIL,
-};
-
enum TrustStoreDependency {
// Uses the built-in trust store for Cast. This is how certificates are
// verified in production.
@@ -59,7 +54,7 @@ enum TrustStoreDependency {
// * |optional_signed_data_file_name| - optional path to a PEM file containing
// a valid signature generated by the device certificate.
//
-void RunTest(TestResult expected_result,
+void RunTest(CastCertError expected_result,
const std::string& expected_common_name,
CastDeviceCertPolicy expected_policy,
const std::string& certs_file_name,
@@ -107,16 +102,14 @@ void RunTest(TestResult expected_result,
std::unique_ptr<CertVerificationContext> context;
CastDeviceCertPolicy policy;
- bool result = VerifyDeviceCertUsingCustomTrustStore(
+ CastCertError result = VerifyDeviceCertUsingCustomTrustStore(
certs, time, &context, &policy, nullptr, CRLPolicy::CRL_OPTIONAL,
trust_store.get());
- if (expected_result == RESULT_FAIL) {
- ASSERT_FALSE(result);
+ ASSERT_EQ(expected_result, result);
+ if (expected_result != CastCertError::OK)
return;
- }
- ASSERT_TRUE(result);
EXPECT_EQ(expected_policy, policy);
ASSERT_TRUE(context.get());
@@ -126,10 +119,12 @@ void RunTest(TestResult expected_result,
ASSERT_TRUE(context);
// Test verification of some invalid signatures.
+ EXPECT_FALSE(context->VerifySignatureOverData("bogus signature", "bogus data",
+ net::DigestAlgorithm::Sha256));
+ EXPECT_FALSE(context->VerifySignatureOverData("", "bogus data",
+ net::DigestAlgorithm::Sha256));
EXPECT_FALSE(
- context->VerifySignatureOverData("bogus signature", "bogus data"));
- EXPECT_FALSE(context->VerifySignatureOverData("", "bogus data"));
- EXPECT_FALSE(context->VerifySignatureOverData("", ""));
+ context->VerifySignatureOverData("", "", net::DigestAlgorithm::Sha256));
// If valid signatures are known for this device certificate, test them.
if (!optional_signed_data_file_name.empty()) {
@@ -138,16 +133,13 @@ void RunTest(TestResult expected_result,
// Test verification of a valid SHA1 signature.
EXPECT_TRUE(context->VerifySignatureOverData(signature_data.signature_sha1,
- signature_data.message));
-
- // Test verification of a valid SHA256
- //
- // TODO(eroman): This fails because there isn't currently support
- // for specifying a signature algorithm other than RSASSA PKCS#1 v1.5 with
- // SHA1. Once support for different algorithms is added to the API this
- // should be changed to expect success.
- EXPECT_FALSE(context->VerifySignatureOverData(
- signature_data.signature_sha256, signature_data.message));
+ signature_data.message,
+ net::DigestAlgorithm::Sha1));
+
+ // Test verification of a valid SHA256 signature.
+ EXPECT_TRUE(context->VerifySignatureOverData(
+ signature_data.signature_sha256, signature_data.message,
+ net::DigestAlgorithm::Sha256));
}
}
@@ -195,7 +187,7 @@ base::Time MarchFirst2037() {
// Chains to trust anchor:
// Eureka Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
- RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1.pem", AprilFirst2016(),
TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
@@ -208,7 +200,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
// Chains to trust anchor:
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
- RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1_reissue.pem", AprilFirst2016(),
TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
@@ -221,7 +213,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
// Chains to trust anchor:
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
- RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen2.pem", AprilFirst2016(),
TRUST_STORE_BUILTIN, "");
}
@@ -235,7 +227,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
// Chains to trust anchor:
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Fugu) {
- RunTest(RESULT_SUCCESS, "-6394818897508095075", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "-6394818897508095075", CastDeviceCertPolicy::NONE,
"certificates/fugu.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
@@ -248,9 +240,9 @@ TEST(VerifyCastDeviceCertTest, Fugu) {
//
// This is invalid because it does not chain to a trust anchor.
TEST(VerifyCastDeviceCertTest, Unchained) {
- RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/unchained.pem", AprilFirst2016(), TRUST_STORE_BUILTIN,
- "");
+ RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "",
+ CastDeviceCertPolicy::NONE, "certificates/unchained.pem",
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying one of the self-signed trust anchors (chain of length 1):
@@ -264,9 +256,9 @@ TEST(VerifyCastDeviceCertTest, Unchained) {
// trust anchors after all) it fails the test as it is not a *device
// certificate*.
TEST(VerifyCastDeviceCertTest, CastRootCa) {
- RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/cast_root_ca.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "");
+ RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "",
+ CastDeviceCertPolicy::NONE, "certificates/cast_root_ca.pem",
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -280,7 +272,7 @@ TEST(VerifyCastDeviceCertTest, CastRootCa) {
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
- RunTest(RESULT_SUCCESS, "4ZZDZJ FA8FCA7EFE3C",
+ RunTest(CastCertError::OK, "4ZZDZJ FA8FCA7EFE3C",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/chromecast_audio.pem",
AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
@@ -297,7 +289,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
- RunTest(RESULT_SUCCESS, "MediaTek Audio Dev Test",
+ RunTest(CastCertError::OK, "MediaTek Audio Dev Test",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/mtk_audio_dev.pem",
JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
}
@@ -310,8 +302,9 @@ TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
// Chains to trust anchor:
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Vizio) {
- RunTest(RESULT_SUCCESS, "9V0000VB FA8FCA784D01", CastDeviceCertPolicy::NONE,
- "certificates/vizio.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+ RunTest(CastCertError::OK, "9V0000VB FA8FCA784D01",
+ CastDeviceCertPolicy::NONE, "certificates/vizio.pem",
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2 using expired
@@ -321,16 +314,16 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// Control test - certificate should be valid at some time otherwise
// this test is pointless.
- RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
kCertsFile, AprilFirst2016(), TRUST_STORE_BUILTIN, "");
// Use a time before notBefore.
- RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
+ RunTest(CastCertError::ERR_CERTS_DATE_INVALID, "", CastDeviceCertPolicy::NONE,
+ kCertsFile, JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
// Use a time after notAfter.
- RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- MarchFirst2037(), TRUST_STORE_BUILTIN, "");
+ RunTest(CastCertError::ERR_CERTS_DATE_INVALID, "", CastDeviceCertPolicy::NONE,
+ kCertsFile, MarchFirst2037(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -345,7 +338,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
- RunTest(RESULT_SUCCESS, "Audio Reference Dev Test",
+ 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");
@@ -366,7 +359,7 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, IntermediateSerialNumberTooLong) {
- RunTest(RESULT_SUCCESS, "8C579B806FFC8A9DFFFF F8:8F:CA:6B:E6:DA",
+ RunTest(CastCertError::OK, "8C579B806FFC8A9DFFFF F8:8F:CA:6B:E6:DA",
CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/intermediate_serialnumber_toolong.pem",
AprilFirst2016(), TRUST_STORE_BUILTIN, "");
@@ -384,7 +377,7 @@ TEST(VerifyCastDeviceCertTest, IntermediateSerialNumberTooLong) {
TEST(VerifyCastDeviceCertTest, ExpiredTrustAnchor) {
// The root certificate is only valid in 2015, so validating with a time in
// 2016 means it is expired.
- RunTest(RESULT_SUCCESS, "CastDevice", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "CastDevice", CastDeviceCertPolicy::NONE,
"certificates/expired_root.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -405,13 +398,14 @@ TEST(VerifyCastDeviceCertTest, ExpiredTrustAnchor) {
TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
// First do a control test -- when anchor constraints are NOT enforced this
// chain should validate just fine.
- RunTest(RESULT_SUCCESS, "Target", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Target", CastDeviceCertPolicy::NONE,
"certificates/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(RESULT_FAIL, "Target", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "Target",
+ CastDeviceCertPolicy::NONE,
"certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -422,7 +416,7 @@ TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
// Intermediate: policies={anyPolicy}
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAnypolicy) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_anypolicy_leaf_anypolicy.pem",
AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -433,7 +427,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAnypolicy) {
// Intermediate: policies={anyPolicy}
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAudioonly) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_anypolicy_leaf_audioonly.pem",
AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -444,7 +438,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAudioonly) {
// Intermediate: policies={anyPolicy}
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafFoo) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_anypolicy_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -455,7 +449,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafFoo) {
// Intermediate: policies={anyPolicy}
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafNone) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_anypolicy_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -466,7 +460,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafNone) {
// Intermediate: policies={audioOnly}
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAnypolicy) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_audioonly_leaf_anypolicy.pem",
AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -477,7 +471,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAnypolicy) {
// Intermediate: policies={audioOnly}
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAudioonly) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_audioonly_leaf_audioonly.pem",
AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -488,7 +482,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAudioonly) {
// Intermediate: policies={audioOnly}
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafFoo) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_audioonly_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -499,7 +493,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafFoo) {
// Intermediate: policies={audioOnly}
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafNone) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_audioonly_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -510,7 +504,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafNone) {
// Intermediate: policies={}
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAnypolicy) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_none_leaf_anypolicy.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -521,7 +515,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAnypolicy) {
// Intermediate: policies={}
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAudioonly) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/policies_ica_none_leaf_audioonly.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -532,7 +526,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAudioonly) {
// Intermediate: policies={}
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafFoo) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_none_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -543,141 +537,28 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafFoo) {
// Intermediate: policies={}
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafNone) {
- RunTest(RESULT_SUCCESS, "Leaf", CastDeviceCertPolicy::NONE,
+ RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
"certificates/policies_ica_none_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
-// ------------------------------------------------------
-// Valid signature using 1024-bit RSA key
-// ------------------------------------------------------
-
-// This test vector comes from the NIST test vectors (pkcs1v15sign-vectors.txt),
-// PKCS#1 v1.5 Signature Example 1.2.
-//
-// It is a valid signature using a 1024 bit key and SHA-1.
-
-const uint8_t kEx1Message[] = {
- 0x85, 0x13, 0x84, 0xcd, 0xfe, 0x81, 0x9c, 0x22, 0xed, 0x6c, 0x4c,
- 0xcb, 0x30, 0xda, 0xeb, 0x5c, 0xf0, 0x59, 0xbc, 0x8e, 0x11, 0x66,
- 0xb7, 0xe3, 0x53, 0x0c, 0x4c, 0x23, 0x3e, 0x2b, 0x5f, 0x8f, 0x71,
- 0xa1, 0xcc, 0xa5, 0x82, 0xd4, 0x3e, 0xcc, 0x72, 0xb1, 0xbc, 0xa1,
- 0x6d, 0xfc, 0x70, 0x13, 0x22, 0x6b, 0x9e,
-};
-
-const uint8_t kEx1Signature[] = {
- 0x84, 0xfd, 0x2c, 0xe7, 0x34, 0xec, 0x1d, 0xa8, 0x28, 0xd0, 0xf1, 0x5b,
- 0xf4, 0x9a, 0x87, 0x07, 0xc1, 0x5d, 0x05, 0x94, 0x81, 0x36, 0xde, 0x53,
- 0x7a, 0x3d, 0xb4, 0x21, 0x38, 0x41, 0x67, 0xc8, 0x6f, 0xae, 0x02, 0x25,
- 0x87, 0xee, 0x9e, 0x13, 0x7d, 0xae, 0xe7, 0x54, 0x73, 0x82, 0x62, 0x93,
- 0x2d, 0x27, 0x1c, 0x74, 0x4c, 0x6d, 0x3a, 0x18, 0x9a, 0xd4, 0x31, 0x1b,
- 0xdb, 0x02, 0x04, 0x92, 0xe3, 0x22, 0xfb, 0xdd, 0xc4, 0x04, 0x06, 0xea,
- 0x86, 0x0d, 0x4e, 0x8e, 0xa2, 0xa4, 0x08, 0x4a, 0xa9, 0x8b, 0x96, 0x22,
- 0xa4, 0x46, 0x75, 0x6f, 0xdb, 0x74, 0x0d, 0xdb, 0x3d, 0x91, 0xdb, 0x76,
- 0x70, 0xe2, 0x11, 0x66, 0x1b, 0xbf, 0x87, 0x09, 0xb1, 0x1c, 0x08, 0xa7,
- 0x07, 0x71, 0x42, 0x2d, 0x1a, 0x12, 0xde, 0xf2, 0x9f, 0x06, 0x88, 0xa1,
- 0x92, 0xae, 0xbd, 0x89, 0xe0, 0xf8, 0x96, 0xf8,
-};
-
-const uint8_t kEx1PublicKeySpki[] = {
- 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
- 0x89, 0x02, 0x81, 0x81, 0x00, 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17,
- 0x58, 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, 0x56, 0xf2, 0xec,
- 0x0e, 0x36, 0xad, 0x52, 0xa4, 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9,
- 0x91, 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, 0xb4, 0xc0, 0xf2,
- 0x83, 0xa1, 0x2a, 0x88, 0xa3, 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91,
- 0xcb, 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, 0xd5, 0xcd, 0x95,
- 0x08, 0x09, 0x6d, 0x5b, 0x2b, 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63,
- 0x77, 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, 0xe2, 0x59, 0x8e,
- 0x6f, 0xf8, 0x9d, 0x19, 0xf1, 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35,
- 0xf2, 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, 0xef, 0x22, 0xe1,
- 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21,
- 0x37, 0x02, 0x03, 0x01, 0x00, 0x01,
-};
-
-// Tests that a valid signature fails, because it uses a 1024-bit RSA key (too
-// weak).
-TEST(VerifyCastDeviceCertTest, VerifySignature1024BitRsa) {
- auto context =
- CertVerificationContextImplForTest(CreateString(kEx1PublicKeySpki));
-
- EXPECT_FALSE(context->VerifySignatureOverData(CreateString(kEx1Signature),
- CreateString(kEx1Message)));
+// Tests verifying a certificate chain where the leaf certificate has a
+// 1024-bit RSA key. Verification should fail since the target's key is
+// too weak.
+TEST(VerifyCastDeviceCertTest, DeviceCertHas1024BitRsaKey) {
+ RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "RSA 1024 Device Cert",
+ CastDeviceCertPolicy::NONE, "certificates/rsa1024_device_cert.pem",
+ AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
-// ------------------------------------------------------
-// Valid signature using 2048-bit RSA key
-// ------------------------------------------------------
-
-// This test vector was generated (using WebCrypto). It is a valid signature
-// using a 2048-bit RSA key, RSASSA PKCS#1 v1.5 with SHA-1.
-
-const uint8_t kEx2Message[] = {
- // "hello"
- 0x68, 0x65, 0x6c, 0x6c, 0x6f,
-};
-
-const uint8_t kEx2Signature[] = {
- 0xc1, 0x21, 0x84, 0xe1, 0x62, 0x0e, 0x59, 0x52, 0x5b, 0xa4, 0x10, 0x1e,
- 0x11, 0x80, 0x5b, 0x9e, 0xcb, 0xa0, 0x20, 0x78, 0x29, 0xfc, 0xc0, 0x9a,
- 0xd9, 0x48, 0x90, 0x81, 0x03, 0xa9, 0xc0, 0x2f, 0x0a, 0xc4, 0x20, 0x34,
- 0xb5, 0xdb, 0x19, 0x04, 0xec, 0x94, 0x9b, 0xba, 0x48, 0x43, 0xf3, 0x5a,
- 0x15, 0x56, 0xfc, 0x4a, 0x87, 0x79, 0xf8, 0x50, 0xff, 0x5d, 0x66, 0x25,
- 0xdc, 0xa5, 0xd8, 0xe8, 0x9f, 0x5a, 0x73, 0x79, 0x6f, 0x5d, 0x99, 0xe0,
- 0xd5, 0xa5, 0x84, 0x49, 0x20, 0x3c, 0xe2, 0xa3, 0xd0, 0x69, 0x31, 0x2c,
- 0x13, 0xaf, 0x15, 0xd9, 0x10, 0x0d, 0x6f, 0xdd, 0x9d, 0x62, 0x5d, 0x7b,
- 0xe1, 0x1a, 0x48, 0x59, 0xaf, 0xf7, 0xbe, 0x87, 0x92, 0x60, 0x5d, 0x1a,
- 0xb5, 0xfe, 0x27, 0x38, 0x02, 0x20, 0xe9, 0xaf, 0x04, 0x57, 0xd3, 0x3b,
- 0x70, 0x04, 0x63, 0x5b, 0xc6, 0x5d, 0x83, 0xe2, 0xaf, 0x02, 0xb4, 0xef,
- 0x1c, 0x33, 0x54, 0x38, 0xf8, 0xb5, 0x19, 0xa8, 0x88, 0xdd, 0x1d, 0x96,
- 0x1c, 0x5e, 0x54, 0x80, 0xde, 0x7b, 0xb6, 0x29, 0xb8, 0x6b, 0xea, 0x47,
- 0xe5, 0xf1, 0x7e, 0xed, 0xe1, 0x91, 0xc8, 0xb8, 0x54, 0xd9, 0x1e, 0xfd,
- 0x07, 0x10, 0xbd, 0xa9, 0xd4, 0x93, 0x5e, 0x65, 0x8b, 0x6b, 0x46, 0x93,
- 0x4b, 0x60, 0x2a, 0x26, 0xf0, 0x1b, 0x4e, 0xca, 0x04, 0x82, 0xc0, 0x8d,
- 0xb1, 0xa5, 0xa8, 0x70, 0xdd, 0x66, 0x68, 0x95, 0x09, 0xb4, 0x85, 0x62,
- 0xf5, 0x17, 0x04, 0x48, 0xb4, 0x9d, 0x66, 0x2b, 0x25, 0x82, 0x7e, 0x99,
- 0x3e, 0xa1, 0x11, 0x63, 0xc3, 0xdf, 0x10, 0x20, 0x52, 0x56, 0x32, 0x35,
- 0xa9, 0x36, 0xde, 0x2a, 0xac, 0x10, 0x0d, 0x75, 0x21, 0xed, 0x5b, 0x38,
- 0xb6, 0xb5, 0x1e, 0xb5, 0x5b, 0x9a, 0x72, 0xd5, 0xf8, 0x1a, 0xd3, 0x91,
- 0xb8, 0x29, 0x0e, 0x58,
-};
-
-const uint8_t kEx2PublicKeySpki[] = {
- 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
- 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xcf, 0xde, 0xa5,
- 0x2e, 0x9d, 0x38, 0x62, 0x72, 0x47, 0x84, 0x8f, 0x2e, 0xa5, 0xe3, 0xd6,
- 0x34, 0xb0, 0xf9, 0x79, 0xa9, 0x10, 0x63, 0xa9, 0x93, 0x5a, 0xa1, 0xb9,
- 0xa3, 0x03, 0xd3, 0xcd, 0x9d, 0x84, 0x7d, 0xb6, 0x92, 0x47, 0xb4, 0x7d,
- 0x4a, 0xe8, 0x3a, 0x4b, 0xc5, 0xf6, 0x35, 0x6f, 0x18, 0x72, 0xf3, 0xbc,
- 0xd2, 0x1c, 0x7a, 0xd2, 0xe5, 0xdf, 0xcf, 0xb9, 0xac, 0x28, 0xd3, 0x49,
- 0x2a, 0x4f, 0x08, 0x62, 0xb9, 0xf1, 0xaa, 0x3d, 0x76, 0xe3, 0xa9, 0x96,
- 0x32, 0x24, 0x94, 0x9e, 0x88, 0xf8, 0x5e, 0xc3, 0x3c, 0x14, 0x32, 0x86,
- 0x72, 0xa2, 0x34, 0x3d, 0x41, 0xd0, 0xb2, 0x01, 0x99, 0x01, 0xf3, 0x93,
- 0xa3, 0x76, 0x5a, 0xff, 0x42, 0x28, 0x54, 0xe0, 0xcc, 0x4c, 0xcd, 0x2d,
- 0x3b, 0x0b, 0x47, 0xcc, 0xc2, 0x75, 0x02, 0xc1, 0xb7, 0x0b, 0x37, 0x65,
- 0xe6, 0x0d, 0xe4, 0xc3, 0x85, 0x86, 0x29, 0x3c, 0x77, 0xce, 0xb0, 0x34,
- 0xa9, 0x03, 0xe9, 0x13, 0xbe, 0x97, 0x1e, 0xfd, 0xeb, 0x0d, 0x60, 0xc2,
- 0xb3, 0x19, 0xa1, 0x75, 0x72, 0x57, 0x3f, 0x5d, 0x0e, 0x75, 0xac, 0x10,
- 0x96, 0xad, 0x95, 0x67, 0x9f, 0xa2, 0x84, 0x15, 0x6a, 0x61, 0xb1, 0x47,
- 0xd1, 0x24, 0x78, 0xb4, 0x40, 0x2b, 0xc3, 0x5c, 0x73, 0xd4, 0xc1, 0x8d,
- 0x12, 0xf1, 0x3f, 0xb4, 0x93, 0x17, 0xfe, 0x5d, 0xbf, 0x39, 0xf2, 0x45,
- 0xf9, 0xcf, 0x38, 0x44, 0x40, 0x5b, 0x47, 0x2a, 0xbf, 0xb9, 0xac, 0xa6,
- 0x14, 0xb6, 0x1b, 0xe3, 0xa8, 0x14, 0xf8, 0xfe, 0x47, 0x67, 0xea, 0x90,
- 0x51, 0x12, 0xcf, 0x5e, 0x28, 0xec, 0x92, 0x83, 0x7c, 0xc6, 0x29, 0x9f,
- 0x12, 0x29, 0x88, 0x49, 0xf7, 0xb7, 0xed, 0x5e, 0x3a, 0x78, 0xd6, 0x8a,
- 0xba, 0x42, 0x6e, 0x0a, 0xf4, 0x0d, 0xc1, 0xc0, 0x8f, 0xdb, 0x26, 0x41,
- 0x57, 0x02, 0x03, 0x01, 0x00, 0x01,
-};
-
-// Tests that a valid signature using 2048-bit key succeeds.
-TEST(VerifyCastDeviceCertTest, VerifySignature2048BitRsa) {
- auto context =
- CertVerificationContextImplForTest(CreateString(kEx2PublicKeySpki));
-
- EXPECT_TRUE(context->VerifySignatureOverData(CreateString(kEx2Signature),
- CreateString(kEx2Message)));
+// Tests verifying a certificate chain where the leaf certificate has a
+// 2048-bit RSA key, and then verifying signed data (both SHA1 and SHA256)
+// for it.
+TEST(VerifyCastDeviceCertTest, DeviceCertHas2048BitRsaKey) {
+ RunTest(CastCertError::OK, "RSA 2048 Device Cert", CastDeviceCertPolicy::NONE,
+ "certificates/rsa2048_device_cert.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE,
+ "signeddata/rsa2048_device_cert_data.pem");
}
} // namespace
diff --git a/chromium/components/cast_certificate/cast_crl.cc b/chromium/components/cast_certificate/cast_crl.cc
index 4f57a9059e3..9401d7f9ead 100644
--- a/chromium/components/cast_certificate/cast_crl.cc
+++ b/chromium/components/cast_certificate/cast_crl.cc
@@ -17,7 +17,7 @@
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/path_builder.h"
#include "net/cert/internal/signature_algorithm.h"
-#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/simple_path_builder_delegate.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "net/cert/internal/verify_certificate_chain.h"
#include "net/cert/internal/verify_signed_data.h"
@@ -87,13 +87,6 @@ bool ConvertTimeSeconds(uint64_t seconds,
generalized_time);
}
-// Specifies the signature verification policy.
-// The required algorithms are:
-// RSASSA PKCS#1 v1.5 with SHA-256, using RSA keys 2048-bits or longer.
-std::unique_ptr<net::SignaturePolicy> CreateCastSignaturePolicy() {
- return base::MakeUnique<net::SimpleSignaturePolicy>(2048);
-}
-
// Verifies the CRL is signed by a trusted CRL authority at the time the CRL
// was issued. Verifies the signature of |tbs_crl| is valid based on the
// certificate and signature in |crl|. The validity of |tbs_crl| is verified
@@ -122,16 +115,12 @@ bool VerifyCRL(const Crl& crl,
net::der::Input(base::StringPiece(crl.signature())), 0);
// Verify the signature.
- auto signature_policy = CreateCastSignaturePolicy();
std::unique_ptr<net::SignatureAlgorithm> signature_algorithm_type =
net::SignatureAlgorithm::CreateRsaPkcs1(net::DigestAlgorithm::Sha256);
- net::CertErrors verify_errors;
- if (!VerifySignedData(*signature_algorithm_type,
- net::der::Input(&crl.tbs_crl()),
- signature_value_bit_string, parsed_cert->tbs().spki_tlv,
- signature_policy.get(), &verify_errors)) {
- VLOG(2) << "CRL - Signature verification failed:\n"
- << verify_errors.ToDebugString();
+ if (!VerifySignedData(
+ *signature_algorithm_type, net::der::Input(&crl.tbs_crl()),
+ signature_value_bit_string, parsed_cert->tbs().spki_tlv)) {
+ VLOG(2) << "CRL - Signature verification failed";
return false;
}
@@ -141,9 +130,14 @@ bool VerifyCRL(const Crl& crl,
VLOG(2) << "CRL - Unable to parse verification time.";
return false;
}
+
+ // SimplePathBuilderDelegate will enforce required signature algorithms of
+ // RSASSA PKCS#1 v1.5 with SHA-256, and RSA keys 2048-bits or longer.
+ net::SimplePathBuilderDelegate path_builder_delegate(2048);
+
net::CertPathBuilder::Result result;
net::CertPathBuilder path_builder(
- parsed_cert.get(), trust_store, signature_policy.get(), verification_time,
+ parsed_cert.get(), trust_store, &path_builder_delegate, verification_time,
net::KeyPurpose::ANY_EKU, net::InitialExplicitPolicy::kFalse,
{net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
net::InitialAnyPolicyInhibit::kFalse, &result);
diff --git a/chromium/components/cast_certificate/cast_crl_unittest.cc b/chromium/components/cast_certificate/cast_crl_unittest.cc
index 171f3369ff2..c06640bdc0e 100644
--- a/chromium/components/cast_certificate/cast_crl_unittest.cc
+++ b/chromium/components/cast_certificate/cast_crl_unittest.cc
@@ -28,15 +28,15 @@ bool TestVerifyCertificate(TestStepResult expected_result,
net::TrustStore* cast_trust_store) {
std::unique_ptr<CertVerificationContext> context;
CastDeviceCertPolicy policy;
- int result = VerifyDeviceCertUsingCustomTrustStore(
+ CastCertError result = VerifyDeviceCertUsingCustomTrustStore(
certificate_chain, time, &context, &policy, nullptr,
CRLPolicy::CRL_OPTIONAL, cast_trust_store);
+ bool success = result == CastCertError::OK;
if (expected_result != RESULT_SUCCESS) {
- EXPECT_FALSE(result);
- return !result;
+ success = !success;
}
- EXPECT_TRUE(result);
- return result;
+ EXPECT_TRUE(success);
+ return success;
}
// Verifies that the provided Cast CRL is signed by a trusted issuer
@@ -49,12 +49,12 @@ bool TestVerifyCRL(TestStepResult expected_result,
std::unique_ptr<CastCRL> crl =
ParseAndVerifyCRLUsingCustomTrustStore(crl_bundle, time, crl_trust_store);
+ bool success = crl != nullptr;
if (expected_result != RESULT_SUCCESS) {
- EXPECT_EQ(crl, nullptr);
- return crl == nullptr;
+ success = !success;
}
- EXPECT_NE(crl, nullptr);
- return crl != nullptr;
+ EXPECT_TRUE(success);
+ return success;
}
// Verifies that the certificate chain provided is not revoked according to
@@ -62,7 +62,7 @@ bool TestVerifyCRL(TestStepResult expected_result,
// The provided CRL is verified at |crl_time|.
// If |crl_required| is set, then a valid Cast CRL must be provided.
// Otherwise, a missing CRL is be ignored.
-bool TestVerifyRevocation(TestStepResult expected_result,
+bool TestVerifyRevocation(CastCertError expected_result,
const std::vector<std::string>& certificate_chain,
const std::string& crl_bundle,
const base::Time& crl_time,
@@ -82,15 +82,11 @@ bool TestVerifyRevocation(TestStepResult expected_result,
CRLPolicy crl_policy = CRLPolicy::CRL_REQUIRED;
if (!crl_required)
crl_policy = CRLPolicy::CRL_OPTIONAL;
- int result = VerifyDeviceCertUsingCustomTrustStore(
+ CastCertError result = VerifyDeviceCertUsingCustomTrustStore(
certificate_chain, cert_time, &context, &policy, crl.get(), crl_policy,
cast_trust_store);
- if (expected_result != RESULT_SUCCESS) {
- EXPECT_FALSE(result);
- return !result;
- }
- EXPECT_TRUE(result);
- return result;
+ EXPECT_EQ(expected_result, result);
+ return expected_result == result;
}
// Runs a single test case.
@@ -136,10 +132,10 @@ bool RunTest(const DeviceCertTest& test_case) {
cast_trust_store.get()) &&
TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time,
crl_trust_store.get()) &&
- TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
- crl_verification_time, cert_verification_time,
- true, cast_trust_store.get(),
- crl_trust_store.get());
+ TestVerifyRevocation(
+ CastCertError::ERR_CRL_INVALID, certificate_chain, crl_bundle,
+ crl_verification_time, cert_verification_time, true,
+ cast_trust_store.get(), crl_trust_store.get());
case CRL_EXPIRED_AFTER_INITIAL_VERIFICATION:
// Fall-through intended.
case REVOCATION_CHECK_FAILED:
@@ -148,10 +144,10 @@ bool RunTest(const DeviceCertTest& test_case) {
cast_trust_store.get()) &&
TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
crl_trust_store.get()) &&
- TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
- crl_verification_time, cert_verification_time,
- false, cast_trust_store.get(),
- crl_trust_store.get());
+ TestVerifyRevocation(
+ CastCertError::ERR_CERTS_REVOKED, certificate_chain,
+ crl_bundle, crl_verification_time, cert_verification_time,
+ false, cast_trust_store.get(), crl_trust_store.get());
case SUCCESS:
return (crl_bundle.empty() ||
TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
@@ -159,9 +155,10 @@ bool RunTest(const DeviceCertTest& test_case) {
TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
cert_verification_time,
cast_trust_store.get()) &&
- TestVerifyRevocation(RESULT_SUCCESS, certificate_chain, crl_bundle,
- crl_verification_time, cert_verification_time,
- !crl_bundle.empty(), cast_trust_store.get(),
+ TestVerifyRevocation(CastCertError::OK, certificate_chain,
+ crl_bundle, crl_verification_time,
+ cert_verification_time, !crl_bundle.empty(),
+ cast_trust_store.get(),
crl_trust_store.get());
case UNSPECIFIED:
return false;
diff --git a/chromium/components/cast_channel/cast_auth_util.cc b/chromium/components/cast_channel/cast_auth_util.cc
index 809d839262c..1b6b75d50b3 100644
--- a/chromium/components/cast_channel/cast_auth_util.cc
+++ b/chromium/components/cast_channel/cast_auth_util.cc
@@ -20,6 +20,7 @@
#include "components/cast_channel/cast_channel_enum.h"
#include "components/cast_channel/cast_message_util.h"
#include "crypto/random.h"
+#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/x509_certificate.h"
#include "net/der/parse_values.h"
@@ -51,10 +52,16 @@ const base::Feature kEnforceRevocationChecking{
// the one sent to the device. As a result, the nonce can be empty and omitted
// from the signature. This allows backwards compatibility with legacy Cast
// receivers.
-
const base::Feature kEnforceNonceChecking{"CastNonceEnforced",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enforce the use of SHA256 digest for signatures.
+// If disabled, the device may respond with a signature with SHA1 digest even
+// though a signature with SHA256 digest was requested in the challenge. This
+// allows for backwards compatibility with legacy Cast receivers.
+const base::Feature kEnforceSHA256Checking{"CastSHA256Enforced",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
namespace cast_crypto = ::cast_certificate;
// Extracts an embedded DeviceAuthMessage payload from an auth challenge reply
@@ -136,6 +143,12 @@ enum CertVerificationStatus {
CERT_STATUS_INVALID_CRL,
CERT_STATUS_VERIFICATION_FAILED,
CERT_STATUS_REVOKED,
+ CERT_STATUS_MISSING_CRL,
+ CERT_STATUS_PARSE_FAILED,
+ CERT_STATUS_DATE_INVALID,
+ CERT_STATUS_RESTRICTIONS_FAILED,
+ CERT_STATUS_MISSING_CERTS,
+ CERT_STATUS_UNEXPECTED_FAILED,
CERT_STATUS_COUNT,
};
@@ -148,6 +161,16 @@ enum NonceVerificationStatus {
NONCE_COUNT,
};
+// Must match with the histogram enum CastSignature.
+// This should never be reordered.
+enum SignatureStatus {
+ SIGNATURE_OK,
+ SIGNATURE_EMPTY,
+ SIGNATURE_VERIFY_FAILED,
+ SIGNATURE_ALGORITHM_UNSUPPORTED,
+ SIGNATURE_COUNT,
+};
+
// Record certificate verification histogram events.
void RecordCertificateEvent(CertVerificationStatus event) {
UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Certificate", event,
@@ -159,6 +182,61 @@ void RecordNonceEvent(NonceVerificationStatus event) {
UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Nonce", event, NONCE_COUNT);
}
+// Record signature verification histogram events.
+void RecordSignatureEvent(SignatureStatus event) {
+ UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Signature", event, SIGNATURE_COUNT);
+}
+
+// Maps CastCertError to AuthResult.
+// If crl_required is set to false, all revocation related errors are ignored.
+AuthResult MapToAuthResult(cast_certificate::CastCertError error,
+ bool crl_required) {
+ switch (error) {
+ case cast_certificate::CastCertError::ERR_CERTS_MISSING:
+ RecordCertificateEvent(CERT_STATUS_MISSING_CERTS);
+ return AuthResult("Failed to locate certificates.",
+ AuthResult::ERROR_PEER_CERT_EMPTY);
+ case cast_certificate::CastCertError::ERR_CERTS_PARSE:
+ RecordCertificateEvent(CERT_STATUS_PARSE_FAILED);
+ return AuthResult("Failed to parse certificates.",
+ AuthResult::ERROR_CERT_PARSING_FAILED);
+ case cast_certificate::CastCertError::ERR_CERTS_DATE_INVALID:
+ RecordCertificateEvent(CERT_STATUS_DATE_INVALID);
+ return AuthResult("Failed date validity check.",
+ AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
+ case cast_certificate::CastCertError::ERR_CERTS_VERIFY_GENERIC:
+ RecordCertificateEvent(CERT_STATUS_VERIFICATION_FAILED);
+ return AuthResult("Failed with a generic certificate verification error.",
+ AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
+ case cast_certificate::CastCertError::ERR_CERTS_RESTRICTIONS:
+ RecordCertificateEvent(CERT_STATUS_RESTRICTIONS_FAILED);
+ return AuthResult("Failed certificate restrictions.",
+ AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
+ case cast_certificate::CastCertError::ERR_CRL_INVALID:
+ // Histogram events are recorded during CRL verification.
+ // This error is only encountered if |crl_required| is true.
+ DCHECK(crl_required);
+ return AuthResult("Failed to provide a valid CRL.",
+ AuthResult::ERROR_CRL_INVALID);
+ case cast_certificate::CastCertError::ERR_CERTS_REVOKED:
+ RecordCertificateEvent(CERT_STATUS_REVOKED);
+ // Revocation check is the last step of Cast certificate verification.
+ // If this error is encountered, the rest of certificate verification has
+ // succeeded.
+ if (!crl_required)
+ return AuthResult();
+ return AuthResult("Failed certificate revocation check.",
+ AuthResult::ERROR_CERT_REVOKED);
+ case cast_certificate::CastCertError::ERR_UNEXPECTED:
+ RecordCertificateEvent(CERT_STATUS_UNEXPECTED_FAILED);
+ return AuthResult("Failed verifying cast device certificate.",
+ AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
+ case cast_certificate::CastCertError::OK:
+ return AuthResult();
+ }
+ return AuthResult();
+}
+
} // namespace
AuthResult::AuthResult()
@@ -202,6 +280,24 @@ AuthResult AuthContext::VerifySenderNonce(
return AuthResult();
}
+AuthResult VerifyAndMapDigestAlgorithm(HashAlgorithm response_digest_algorithm,
+ net::DigestAlgorithm* digest_algorithm) {
+ switch (response_digest_algorithm) {
+ case SHA1:
+ RecordSignatureEvent(SIGNATURE_ALGORITHM_UNSUPPORTED);
+ *digest_algorithm = net::DigestAlgorithm::Sha1;
+ if (base::FeatureList::IsEnabled(kEnforceSHA256Checking)) {
+ return AuthResult("Unsupported digest algorithm.",
+ AuthResult::ERROR_DIGEST_UNSUPPORTED);
+ }
+ break;
+ case SHA256:
+ *digest_algorithm = net::DigestAlgorithm::Sha256;
+ break;
+ }
+ return AuthResult();
+}
+
// Verifies the peer certificate and populates |peer_cert_der| with the DER
// encoded certificate.
AuthResult VerifyTLSCertificate(const net::X509Certificate& peer_cert,
@@ -304,55 +400,50 @@ AuthResult VerifyCredentialsImpl(const AuthResponse& response,
response.intermediate_certificate().end());
// Parse the CRL.
- std::unique_ptr<cast_crypto::CastCRL> crl =
- cast_crypto::ParseAndVerifyCRLUsingCustomTrustStore(
- response.crl(), verification_time, crl_trust_store);
- if (!crl) {
- // CRL is invalid.
- RecordCertificateEvent(CERT_STATUS_INVALID_CRL);
- if (crl_policy == cast_crypto::CRLPolicy::CRL_REQUIRED) {
- return AuthResult("Failed verifying Cast CRL.",
- AuthResult::ERROR_CRL_INVALID);
+ std::unique_ptr<cast_crypto::CastCRL> crl;
+ if (response.crl().empty()) {
+ RecordCertificateEvent(CERT_STATUS_MISSING_CRL);
+ } else {
+ crl = cast_crypto::ParseAndVerifyCRLUsingCustomTrustStore(
+ response.crl(), verification_time, crl_trust_store);
+ if (!crl) {
+ RecordCertificateEvent(CERT_STATUS_INVALID_CRL);
}
}
+ // Perform certificate verification.
cast_crypto::CastDeviceCertPolicy device_policy;
- bool verification_success =
+ cast_crypto::CastCertError verify_result =
cast_crypto::VerifyDeviceCertUsingCustomTrustStore(
cert_chain, verification_time, &verification_context, &device_policy,
crl.get(), crl_policy, cast_trust_store);
- if (!verification_success) {
- // TODO(ryanchung): Once this feature is completely rolled-out, remove the
- // reverification step and use error reporting to get verification errors
- // for metrics.
- bool verification_no_crl_success =
- cast_crypto::VerifyDeviceCertUsingCustomTrustStore(
- cert_chain, verification_time, &verification_context,
- &device_policy, nullptr, cast_crypto::CRLPolicy::CRL_OPTIONAL,
- cast_trust_store);
- if (!verification_no_crl_success) {
- // TODO(eroman): The error information was lost; this error is ambiguous.
- RecordCertificateEvent(CERT_STATUS_VERIFICATION_FAILED);
- return AuthResult("Failed verifying cast device certificate",
- AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
- }
- if (crl) {
- // If CRL was not present, it should've been recorded as such.
- RecordCertificateEvent(CERT_STATUS_REVOKED);
- }
- if (crl_policy == cast_crypto::CRLPolicy::CRL_REQUIRED) {
- // Device is revoked.
- return AuthResult("Failed certificate revocation check.",
- AuthResult::ERROR_CERT_REVOKED);
- }
- }
+
+ // Handle and report errors.
+ AuthResult result = MapToAuthResult(
+ verify_result, crl_policy == cast_crypto::CRLPolicy::CRL_REQUIRED);
+ if (!result.success())
+ return result;
+
// The certificate is verified at this point.
RecordCertificateEvent(CERT_STATUS_OK);
- if (!verification_context->VerifySignatureOverData(response.signature(),
- signature_input)) {
- return AuthResult("Failed verifying signature over data",
+
+ if (response.signature().empty() && !signature_input.empty()) {
+ RecordSignatureEvent(SIGNATURE_EMPTY);
+ return AuthResult("Signature is empty.", AuthResult::ERROR_SIGNATURE_EMPTY);
+ }
+ net::DigestAlgorithm digest_algorithm;
+ AuthResult digest_result =
+ VerifyAndMapDigestAlgorithm(response.hash_algorithm(), &digest_algorithm);
+ if (!digest_result.success())
+ return digest_result;
+
+ if (!verification_context->VerifySignatureOverData(
+ response.signature(), signature_input, digest_algorithm)) {
+ RecordSignatureEvent(SIGNATURE_VERIFY_FAILED);
+ return AuthResult("Failed verifying signature over data.",
AuthResult::ERROR_SIGNED_BLOBS_MISMATCH);
}
+ RecordSignatureEvent(SIGNATURE_OK);
AuthResult success;
diff --git a/chromium/components/cast_channel/cast_auth_util.h b/chromium/components/cast_channel/cast_auth_util.h
index 114dee20f57..e0cc89ebdfd 100644
--- a/chromium/components/cast_channel/cast_auth_util.h
+++ b/chromium/components/cast_channel/cast_auth_util.h
@@ -46,6 +46,8 @@ struct AuthResult {
ERROR_CRL_INVALID,
ERROR_CERT_REVOKED,
ERROR_SENDER_NONCE_MISMATCH,
+ ERROR_DIGEST_UNSUPPORTED,
+ ERROR_SIGNATURE_EMPTY,
};
enum PolicyType { POLICY_NONE = 0, POLICY_AUDIO_ONLY = 1 << 0 };
diff --git a/chromium/components/cast_channel/cast_auth_util_unittest.cc b/chromium/components/cast_channel/cast_auth_util_unittest.cc
index fba22eb1301..d7e28972456 100644
--- a/chromium/components/cast_channel/cast_auth_util_unittest.cc
+++ b/chromium/components/cast_channel/cast_auth_util_unittest.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/logging.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
@@ -29,7 +30,8 @@ class CastAuthUtilTest : public testing::Test {
void SetUp() override {}
protected:
- static AuthResponse CreateAuthResponse(std::string* signed_data) {
+ static AuthResponse CreateAuthResponse(std::string* signed_data,
+ HashAlgorithm digest_algorithm) {
auto chain = cast_certificate::testing::ReadCertificateChainFromFile(
"certificates/chromecast_gen1.pem");
CHECK(!chain.empty());
@@ -43,7 +45,15 @@ class CastAuthUtilTest : public testing::Test {
for (size_t i = 1; i < chain.size(); ++i)
response.add_intermediate_certificate(chain[i]);
- response.set_signature(signature_data.signature_sha1);
+ response.set_hash_algorithm(digest_algorithm);
+ switch (digest_algorithm) {
+ case SHA1:
+ response.set_signature(signature_data.signature_sha1);
+ break;
+ case SHA256:
+ response.set_signature(signature_data.signature_sha256);
+ break;
+ }
*signed_data = signature_data.message;
return response;
@@ -58,7 +68,7 @@ class CastAuthUtilTest : public testing::Test {
// being verified doesn't expire until 2032!
TEST_F(CastAuthUtilTest, VerifySuccess) {
std::string signed_data;
- AuthResponse auth_response = CreateAuthResponse(&signed_data);
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
base::Time now = base::Time::Now();
AuthResult result = VerifyCredentialsForTest(
auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
@@ -69,35 +79,68 @@ TEST_F(CastAuthUtilTest, VerifySuccess) {
TEST_F(CastAuthUtilTest, VerifyBadCA) {
std::string signed_data;
- AuthResponse auth_response = CreateAuthResponse(&signed_data);
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
MangleString(auth_response.mutable_intermediate_certificate(0));
AuthResult result = VerifyCredentials(auth_response, signed_data);
EXPECT_FALSE(result.success());
- EXPECT_EQ(AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA, result.error_type);
+ EXPECT_EQ(AuthResult::ERROR_CERT_PARSING_FAILED, result.error_type);
}
TEST_F(CastAuthUtilTest, VerifyBadClientAuthCert) {
std::string signed_data;
- AuthResponse auth_response = CreateAuthResponse(&signed_data);
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
MangleString(auth_response.mutable_client_auth_certificate());
AuthResult result = VerifyCredentials(auth_response, signed_data);
EXPECT_FALSE(result.success());
// TODO(eroman): Not quite right of an error.
- EXPECT_EQ(AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA, result.error_type);
+ EXPECT_EQ(AuthResult::ERROR_CERT_PARSING_FAILED, result.error_type);
}
TEST_F(CastAuthUtilTest, VerifyBadSignature) {
std::string signed_data;
- AuthResponse auth_response = CreateAuthResponse(&signed_data);
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
MangleString(auth_response.mutable_signature());
AuthResult result = VerifyCredentials(auth_response, signed_data);
EXPECT_FALSE(result.success());
EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type);
}
+TEST_F(CastAuthUtilTest, VerifyEmptySignature) {
+ std::string signed_data;
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
+ auth_response.mutable_signature()->clear();
+ AuthResult result = VerifyCredentials(auth_response, signed_data);
+ EXPECT_FALSE(result.success());
+ EXPECT_EQ(AuthResult::ERROR_SIGNATURE_EMPTY, result.error_type);
+}
+
+TEST_F(CastAuthUtilTest, VerifyUnsupportedDigest) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ base::Feature{"CastSHA256Enforced", base::FEATURE_DISABLED_BY_DEFAULT});
+ std::string signed_data;
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA1);
+ base::Time now = base::Time::Now();
+ AuthResult result = VerifyCredentialsForTest(
+ auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
+ nullptr, nullptr, now);
+ EXPECT_FALSE(result.success());
+ EXPECT_EQ(AuthResult::ERROR_DIGEST_UNSUPPORTED, result.error_type);
+}
+
+TEST_F(CastAuthUtilTest, VerifyBackwardsCompatibleDigest) {
+ std::string signed_data;
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA1);
+ base::Time now = base::Time::Now();
+ AuthResult result = VerifyCredentialsForTest(
+ auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
+ nullptr, nullptr, now);
+ EXPECT_TRUE(result.success());
+}
+
TEST_F(CastAuthUtilTest, VerifyBadPeerCert) {
std::string signed_data;
- AuthResponse auth_response = CreateAuthResponse(&signed_data);
+ AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
MangleString(&signed_data);
AuthResult result = VerifyCredentials(auth_response, signed_data);
EXPECT_FALSE(result.success());
diff --git a/chromium/components/cast_channel/cast_channel_enum.h b/chromium/components/cast_channel/cast_channel_enum.h
index c1f7f2bb734..6c436df76c7 100644
--- a/chromium/components/cast_channel/cast_channel_enum.h
+++ b/chromium/components/cast_channel/cast_channel_enum.h
@@ -97,6 +97,8 @@ enum class ChallengeReplyError {
CRL_INVALID,
CERT_REVOKED,
SENDER_NONCE_MISMATCH,
+ SIGNATURE_EMPTY,
+ DIGEST_UNSUPPORTED,
};
// Used by CastSocket/CastTransport to track connection state.
diff --git a/chromium/components/cast_channel/cast_message_util.cc b/chromium/components/cast_channel/cast_message_util.cc
index 50c4be1c858..79658107857 100644
--- a/chromium/components/cast_channel/cast_message_util.cc
+++ b/chromium/components/cast_channel/cast_message_util.cc
@@ -68,7 +68,12 @@ void CreateAuthChallengeMessage(CastMessage* message_proto,
const AuthContext& auth_context) {
CHECK(message_proto);
DeviceAuthMessage auth_message;
- auth_message.mutable_challenge()->set_sender_nonce(auth_context.nonce());
+
+ AuthChallenge* challenge = auth_message.mutable_challenge();
+ DCHECK(challenge);
+ challenge->set_sender_nonce(auth_context.nonce());
+ challenge->set_hash_algorithm(SHA256);
+
std::string auth_message_string;
auth_message.SerializeToString(&auth_message_string);
diff --git a/chromium/components/cast_channel/cast_socket.cc b/chromium/components/cast_channel/cast_socket.cc
index 20effac80fc..676ece01858 100644
--- a/chromium/components/cast_channel/cast_socket.cc
+++ b/chromium/components/cast_channel/cast_socket.cc
@@ -51,8 +51,8 @@
// Helper for logging data with remote host IP and authentication state.
// Assumes |ip_endpoint_| of type net::IPEndPoint and |channel_auth_| of enum
// type ChannelAuthType are available in the current scope.
-#define CONNECTION_INFO() \
- "[" << ip_endpoint_.ToString() << ", auth=SSL_VERIFIED" \
+#define CONNECTION_INFO() \
+ "[" << open_params_.ip_endpoint.ToString() << ", auth=SSL_VERIFIED" \
<< "] "
#define VLOG_WITH_CONNECTION(level) VLOG(level) << CONNECTION_INFO()
#define LOG_WITH_CONNECTION(level) LOG(level) << CONNECTION_INFO()
@@ -86,49 +86,28 @@ class FakeCertVerifier : public net::CertVerifier {
} // namespace
-CastSocketImpl::CastSocketImpl(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- base::TimeDelta timeout,
- base::TimeDelta liveness_timeout,
- base::TimeDelta ping_interval,
- const scoped_refptr<Logger>& logger,
- uint64_t device_capabilities)
- : CastSocketImpl(ip_endpoint,
- net_log,
- timeout,
- liveness_timeout,
- ping_interval,
- logger,
- device_capabilities,
- AuthContext::Create()) {}
-
-CastSocketImpl::CastSocketImpl(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- base::TimeDelta timeout,
- base::TimeDelta liveness_timeout,
- base::TimeDelta ping_interval,
+CastSocketImpl::CastSocketImpl(const CastSocketOpenParams& open_params,
+ const scoped_refptr<Logger>& logger)
+ : CastSocketImpl(open_params, logger, AuthContext::Create()) {}
+
+CastSocketImpl::CastSocketImpl(const CastSocketOpenParams& open_params,
const scoped_refptr<Logger>& logger,
- uint64_t device_capabilities,
const AuthContext& auth_context)
: channel_id_(0),
- ip_endpoint_(ip_endpoint),
- net_log_(net_log),
- liveness_timeout_(liveness_timeout),
- ping_interval_(ping_interval),
+ open_params_(open_params),
logger_(logger),
auth_context_(auth_context),
- connect_timeout_(timeout),
connect_timeout_timer_(new base::OneShotTimer),
is_canceled_(false),
- device_capabilities_(device_capabilities),
audio_only_(false),
connect_state_(ConnectionState::START_CONNECT),
error_state_(ChannelError::NONE),
ready_state_(ReadyState::NONE),
auth_delegate_(nullptr) {
- DCHECK(net_log_);
+ DCHECK(open_params.ip_endpoint.address().IsValid());
+ DCHECK(open_params_.net_log);
net_log_source_.type = net::NetLogSourceType::SOCKET;
- net_log_source_.id = net_log_->NextID();
+ net_log_source_.id = open_params_.net_log->NextID();
}
CastSocketImpl::~CastSocketImpl() {
@@ -136,8 +115,9 @@ CastSocketImpl::~CastSocketImpl() {
// would result in re-entrancy.
CloseInternal();
+ error_state_ = ChannelError::UNKNOWN;
for (auto& connect_callback : connect_callbacks_)
- std::move(connect_callback).Run(channel_id_, ChannelError::UNKNOWN);
+ std::move(connect_callback).Run(this);
connect_callbacks_.clear();
}
@@ -150,7 +130,7 @@ ChannelError CastSocketImpl::error_state() const {
}
const net::IPEndPoint& CastSocketImpl::ip_endpoint() const {
- return ip_endpoint_;
+ return open_params_.ip_endpoint;
}
int CastSocketImpl::id() const {
@@ -162,7 +142,7 @@ void CastSocketImpl::set_id(int id) {
}
bool CastSocketImpl::keep_alive() const {
- return liveness_timeout_ > base::TimeDelta();
+ return open_params_.liveness_timeout > base::TimeDelta();
}
bool CastSocketImpl::audio_only() const {
@@ -170,9 +150,9 @@ bool CastSocketImpl::audio_only() const {
}
std::unique_ptr<net::TCPClientSocket> CastSocketImpl::CreateTcpSocket() {
- net::AddressList addresses(ip_endpoint_);
- return std::unique_ptr<net::TCPClientSocket>(
- new net::TCPClientSocket(addresses, nullptr, net_log_, net_log_source_));
+ net::AddressList addresses(open_params_.ip_endpoint);
+ return std::unique_ptr<net::TCPClientSocket>(new net::TCPClientSocket(
+ addresses, nullptr, open_params_.net_log, net_log_source_));
// Options cannot be set on the TCPClientSocket yet, because the
// underlying platform socket will not be created until Bind()
// or Connect() is called.
@@ -197,7 +177,7 @@ std::unique_ptr<net::SSLClientSocket> CastSocketImpl::CreateSslSocket(
new net::ClientSocketHandle);
connection->SetSocket(std::move(socket));
net::HostPortPair host_and_port =
- net::HostPortPair::FromIPEndPoint(ip_endpoint_);
+ net::HostPortPair::FromIPEndPoint(open_params_.ip_endpoint);
return net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
std::move(connection), host_and_port, ssl_config, context);
@@ -213,8 +193,8 @@ scoped_refptr<net::X509Certificate> CastSocketImpl::ExtractPeerCert() {
bool CastSocketImpl::VerifyChannelPolicy(const AuthResult& result) {
audio_only_ = (result.channel_policies & AuthResult::POLICY_AUDIO_ONLY) != 0;
- if (audio_only_ &&
- (device_capabilities_ & CastDeviceCapability::VIDEO_OUT) != 0) {
+ if (audio_only_ && (open_params_.device_capabilities &
+ CastDeviceCapability::VIDEO_OUT) != 0) {
LOG_WITH_CONNECTION(ERROR)
<< "Audio only channel policy enforced for video out capable device";
return false;
@@ -251,10 +231,12 @@ void CastSocketImpl::Connect(OnOpenCallback callback) {
connect_callbacks_.push_back(std::move(callback));
break;
case ReadyState::OPEN:
- std::move(callback).Run(channel_id_, ChannelError::NONE);
+ error_state_ = ChannelError::NONE;
+ std::move(callback).Run(this);
break;
case ReadyState::CLOSED:
- std::move(callback).Run(channel_id_, ChannelError::CONNECT_ERROR);
+ error_state_ = ChannelError::CONNECT_ERROR;
+ std::move(callback).Run(this);
break;
default:
NOTREACHED() << "Unknown ReadyState: "
@@ -275,11 +257,11 @@ void CastSocketImpl::Connect() {
SetConnectState(ConnectionState::TCP_CONNECT);
// Set up connection timeout.
- if (connect_timeout_.InMicroseconds() > 0) {
+ if (open_params_.connect_timeout.InMicroseconds() > 0) {
DCHECK(connect_timeout_callback_.IsCancelled());
connect_timeout_callback_.Reset(
base::Bind(&CastSocketImpl::OnConnectTimeout, base::Unretained(this)));
- GetTimer()->Start(FROM_HERE, connect_timeout_,
+ GetTimer()->Start(FROM_HERE, open_params_.connect_timeout,
connect_timeout_callback_.callback());
}
@@ -447,8 +429,8 @@ int CastSocketImpl::DoSslConnectComplete(int result) {
if (!transport_.get()) {
// Create a channel transport if one wasn't already set (e.g. by test
// code).
- transport_.reset(new CastTransportImpl(this->socket_.get(), channel_id_,
- ip_endpoint_, logger_));
+ transport_.reset(new CastTransportImpl(
+ this->socket_.get(), channel_id_, open_params_.ip_endpoint, logger_));
}
auth_delegate_ = new AuthTransportDelegate(this);
transport_->SetReadDelegate(base::WrapUnique(auth_delegate_));
@@ -562,9 +544,9 @@ void CastSocketImpl::DoConnectCallback() {
if (error_state_ == ChannelError::NONE) {
SetReadyState(ReadyState::OPEN);
if (keep_alive()) {
- auto* keep_alive_delegate =
- new KeepAliveDelegate(this, logger_, std::move(delegate_),
- ping_interval_, liveness_timeout_);
+ auto* keep_alive_delegate = new KeepAliveDelegate(
+ this, logger_, std::move(delegate_), open_params_.ping_interval,
+ open_params_.liveness_timeout);
delegate_.reset(keep_alive_delegate);
}
transport_->SetReadDelegate(std::move(delegate_));
@@ -573,7 +555,7 @@ void CastSocketImpl::DoConnectCallback() {
}
for (auto& connect_callback : connect_callbacks_)
- std::move(connect_callback).Run(channel_id_, error_state_);
+ std::move(connect_callback).Run(this);
connect_callbacks_.clear();
}
@@ -655,5 +637,26 @@ void CastSocketImpl::CastSocketMessageDelegate::OnMessage(
void CastSocketImpl::CastSocketMessageDelegate::Start() {}
+CastSocketOpenParams::CastSocketOpenParams(const net::IPEndPoint& ip_endpoint,
+ net::NetLog* net_log,
+ base::TimeDelta connect_timeout)
+ : ip_endpoint(ip_endpoint),
+ net_log(net_log),
+ connect_timeout(connect_timeout),
+ device_capabilities(cast_channel::CastDeviceCapability::NONE) {}
+
+CastSocketOpenParams::CastSocketOpenParams(const net::IPEndPoint& ip_endpoint,
+ net::NetLog* net_log,
+ base::TimeDelta connect_timeout,
+ base::TimeDelta liveness_timeout,
+ base::TimeDelta ping_interval,
+ uint64_t device_capabilities)
+ : ip_endpoint(ip_endpoint),
+ net_log(net_log),
+ connect_timeout(connect_timeout),
+ liveness_timeout(liveness_timeout),
+ ping_interval(ping_interval),
+ device_capabilities(device_capabilities) {}
+
} // namespace cast_channel
#undef VLOG_WITH_CONNECTION
diff --git a/chromium/components/cast_channel/cast_socket.h b/chromium/components/cast_channel/cast_socket.h
index de1792b3ca7..3b3721e778f 100644
--- a/chromium/components/cast_channel/cast_socket.h
+++ b/chromium/components/cast_channel/cast_socket.h
@@ -56,8 +56,10 @@ enum CastDeviceCapability {
// Public interface of the CastSocket class.
class CastSocket {
public:
- using OnOpenCallback =
- base::OnceCallback<void(int channel_id, ChannelError error_state)>;
+ // Invoked when CastSocket opens.
+ // |socket|: raw pointer of opened socket (this pointer). Guaranteed to be
+ // valid in callback function. Do not pass |socket| around.
+ using OnOpenCallback = base::OnceCallback<void(CastSocket* socket)>;
class Observer {
public:
@@ -134,6 +136,47 @@ class CastSocket {
virtual void RemoveObserver(Observer* observer) = 0;
};
+// Holds parameters necessary to open a Cast channel (CastSocket) to a Cast
+// device.
+struct CastSocketOpenParams {
+ // IP endpoint of the Cast device.
+ net::IPEndPoint ip_endpoint;
+
+ // Log of socket events.
+ net::NetLog* net_log;
+
+ // Connection timeout interval. If this value is not set, Cast socket will not
+ // report CONNECT_TIMEOUT error and may hang when connecting to a Cast device.
+ base::TimeDelta connect_timeout;
+
+ // Amount of idle time to wait before disconnecting. Cast socket will ping
+ // Cast device periodically at |ping_interval| to check liveness. If it does
+ // not receive response in |liveness_timeout|, it reports PING_TIMEOUT error.
+ // |liveness_timeout| should always be larger than or equal to
+ // |ping_interval|.
+ // If this value is not set, there is not periodic ping and Cast socket is
+ // always assumed alive.
+ base::TimeDelta liveness_timeout;
+
+ // Amount of idle time to wait before pinging the Cast device. See comments
+ // for |liveness_timeout|.
+ base::TimeDelta ping_interval;
+
+ // A bit vector representing the capabilities of the sink. The values are
+ // defined in components/cast_channel/cast_socket.h.
+ uint64_t device_capabilities;
+
+ CastSocketOpenParams(const net::IPEndPoint& ip_endpoint,
+ net::NetLog* net_log,
+ base::TimeDelta connect_timeout);
+ CastSocketOpenParams(const net::IPEndPoint& ip_endpoint,
+ net::NetLog* net_log,
+ base::TimeDelta connect_timeout,
+ base::TimeDelta liveness_timeout,
+ base::TimeDelta ping_interval,
+ uint64_t device_capabilities);
+};
+
// This class implements a channel between Chrome and a Cast device using a TCP
// socket with SSL. The channel may authenticate that the receiver is a genuine
// Cast device. All CastSocketImpl objects must be used only on the IO thread.
@@ -142,31 +185,11 @@ class CastSocket {
// code.
class CastSocketImpl : public CastSocket {
public:
- // Creates a new CastSocket that connects to |ip_endpoint|.
- // Parameters:
- // |ip_endpoint|: IP address of the remote host.
- // |net_log|: Log of socket events.
- // |connect_timeout|: Connection timeout interval.
- // |liveness_timeout|: Amount of idle time to wait before disconnecting.
- // |ping_interval|: Amount of idle time to wait before pinging the receiver.
- // |logger|: Log of cast channel events.
- CastSocketImpl(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- base::TimeDelta connect_timeout,
- base::TimeDelta liveness_timeout,
- base::TimeDelta ping_interval,
- const scoped_refptr<Logger>& logger,
- uint64_t device_capabilities);
-
- // For test-only.
- // This constructor allows for setting a custom AuthContext.
- CastSocketImpl(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- base::TimeDelta connect_timeout,
- base::TimeDelta liveness_timeout,
- base::TimeDelta ping_interval,
+ CastSocketImpl(const CastSocketOpenParams& open_params,
+ const scoped_refptr<Logger>& logger);
+
+ CastSocketImpl(const CastSocketOpenParams& open_params,
const scoped_refptr<Logger>& logger,
- uint64_t device_capabilities,
const AuthContext& auth_context);
// Ensures that the socket is closed.
@@ -313,20 +336,12 @@ class CastSocketImpl : public CastSocket {
// The id of the channel.
int channel_id_;
- // The IP endpoint that the the channel is connected to.
- net::IPEndPoint ip_endpoint_;
- // The NetLog for this service.
- net::NetLog* net_log_;
+
// The NetLog source for this service.
net::NetLogSource net_log_source_;
- // Amount of idle time to wait before disconnecting. If |liveness_timeout_| is
- // set, wraps |delegate_| with a KeepAliveDelegate.
- base::TimeDelta liveness_timeout_;
-
- // Amount of idle time to wait before pinging the receiver, used to create
- // KeepAliveDelegate.
- base::TimeDelta ping_interval_;
+ // Cast socket related settings.
+ CastSocketOpenParams open_params_;
// Shared logging object, used to log CastSocket events for diagnostics.
scoped_refptr<Logger> logger_;
@@ -361,9 +376,6 @@ class CastSocketImpl : public CastSocket {
// Callback invoked by |connect_timeout_timer_| to cancel the connection.
base::CancelableClosure connect_timeout_callback_;
- // Duration to wait before timing out.
- base::TimeDelta connect_timeout_;
-
// Timer invoked when the connection has timed out.
std::unique_ptr<base::Timer> connect_timeout_timer_;
@@ -371,9 +383,6 @@ class CastSocketImpl : public CastSocket {
// canceled.
bool is_canceled_;
- // Capabilities declared by the cast device.
- uint64_t device_capabilities_;
-
// Whether the channel is audio only as identified by the device
// certificate during channel authentication.
bool audio_only_;
diff --git a/chromium/components/cast_channel/cast_socket_service.cc b/chromium/components/cast_channel/cast_socket_service.cc
index 478dd55407a..c0d528790a8 100644
--- a/chromium/components/cast_channel/cast_socket_service.cc
+++ b/chromium/components/cast_channel/cast_socket_service.cc
@@ -88,26 +88,19 @@ CastSocket* CastSocketService::GetSocket(
return it == sockets_.end() ? nullptr : it->second.get();
}
-int CastSocketService::OpenSocket(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- const base::TimeDelta& connect_timeout,
- const base::TimeDelta& liveness_timeout,
- const base::TimeDelta& ping_interval,
- uint64_t device_capabilities,
+int CastSocketService::OpenSocket(const CastSocketOpenParams& open_params,
CastSocket::OnOpenCallback open_cb,
CastSocket::Observer* observer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(observer);
- auto* socket = GetSocket(ip_endpoint);
+ auto* socket = GetSocket(open_params.ip_endpoint);
if (!socket) {
// If cast socket does not exist.
if (socket_for_test_) {
socket = AddSocket(std::move(socket_for_test_));
} else {
- socket = new CastSocketImpl(ip_endpoint, net_log, connect_timeout,
- liveness_timeout, ping_interval, logger_,
- device_capabilities);
+ socket = new CastSocketImpl(open_params, logger_);
AddSocket(base::WrapUnique(socket));
}
}
@@ -125,9 +118,11 @@ int CastSocketService::OpenSocket(const net::IPEndPoint& ip_endpoint,
auto ping_interval = base::TimeDelta::FromSeconds(kPingIntervalInSecs);
auto liveness_timeout =
base::TimeDelta::FromSeconds(kConnectLivenessTimeoutSecs);
- return OpenSocket(ip_endpoint, net_log, connect_timeout, liveness_timeout,
- ping_interval, CastDeviceCapability::NONE,
- std::move(open_cb), observer);
+ CastSocketOpenParams open_params(ip_endpoint, net_log, connect_timeout,
+ liveness_timeout, ping_interval,
+ CastDeviceCapability::NONE);
+
+ return OpenSocket(open_params, std::move(open_cb), observer);
}
void CastSocketService::RemoveObserver(CastSocket::Observer* observer) {
diff --git a/chromium/components/cast_channel/cast_socket_service.h b/chromium/components/cast_channel/cast_socket_service.h
index e93ead0f670..b0aa9462a49 100644
--- a/chromium/components/cast_channel/cast_socket_service.h
+++ b/chromium/components/cast_channel/cast_socket_service.h
@@ -45,22 +45,11 @@ class CastSocketService {
// operation finishes. If cast socket with |ip_endpoint| already exists,
// invoke |open_cb| directly with existing socket's channel ID.
// Parameters:
- // |ip_endpoint|: IP address and port of the remote host.
- // |net_log|: Log of socket events.
- // |connect_timeout|: Connection timeout interval.
- // |liveness_timeout|: Liveness timeout for connect calls.
- // |ping_interval|: Ping interval.
- // |logger|: Log of cast channel events.
- // |device_capabilities|: Device capabilities.
+ // |open_params|: Parameters necessary to open a Cast channel.
// |open_cb|: OnOpenCallback invoked when cast socket is opened.
// |observer|: Observer handles messages and errors on newly opened socket.
// Does not take ownership of |observer|.
- int OpenSocket(const net::IPEndPoint& ip_endpoint,
- net::NetLog* net_log,
- const base::TimeDelta& connect_timeout,
- const base::TimeDelta& liveness_timeout,
- const base::TimeDelta& ping_interval,
- uint64_t device_capabilities,
+ int OpenSocket(const CastSocketOpenParams& open_params,
CastSocket::OnOpenCallback open_cb,
CastSocket::Observer* observer);
diff --git a/chromium/components/cast_channel/cast_socket_service_unittest.cc b/chromium/components/cast_channel/cast_socket_service_unittest.cc
index f2c0ce02b1f..c888a610a5e 100644
--- a/chromium/components/cast_channel/cast_socket_service_unittest.cc
+++ b/chromium/components/cast_channel/cast_socket_service_unittest.cc
@@ -83,9 +83,9 @@ TEST_F(CastSocketServiceTest, TestOpenChannel) {
EXPECT_CALL(*mock_socket, ConnectInternal(_))
.WillOnce(WithArgs<0>(
Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
- callback.Run(mock_socket->id(), ChannelError::NONE);
+ callback.Run(mock_socket);
})));
- EXPECT_CALL(mock_on_open_callback_, Run(_, ChannelError::NONE));
+ EXPECT_CALL(mock_on_open_callback_, Run(mock_socket));
EXPECT_CALL(*mock_socket, AddObserver(_));
cast_socket_service_->OpenSocket(ip_endpoint, nullptr /* net_log */,
diff --git a/chromium/components/cast_channel/cast_socket_unittest.cc b/chromium/components/cast_channel/cast_socket_unittest.cc
index dc40a4320dc..b4f2adbfa11 100644
--- a/chromium/components/cast_channel/cast_socket_unittest.cc
+++ b/chromium/components/cast_channel/cast_socket_unittest.cc
@@ -166,8 +166,7 @@ class CompleteHandler {
public:
CompleteHandler() {}
MOCK_METHOD1(OnCloseComplete, void(int result));
- MOCK_METHOD2(OnConnectComplete,
- void(int channel_id, ChannelError error_state));
+ MOCK_METHOD1(OnConnectComplete, void(CastSocket* socket));
MOCK_METHOD1(OnWriteComplete, void(int result));
MOCK_METHOD1(OnReadComplete, void(int result));
@@ -177,31 +176,9 @@ class CompleteHandler {
class TestCastSocketBase : public CastSocketImpl {
public:
- TestCastSocketBase(const net::IPEndPoint& ip_endpoint,
- int64_t timeout_ms,
- Logger* logger,
- uint64_t device_capabilities)
- : TestCastSocketBase(ip_endpoint,
- timeout_ms,
- logger,
- new net::TestNetLog(),
- device_capabilities) {}
-
- TestCastSocketBase(const net::IPEndPoint& ip_endpoint,
- int64_t timeout_ms,
- Logger* logger,
- net::TestNetLog* capturing_net_log,
- uint64_t device_capabilities)
- : CastSocketImpl(ip_endpoint,
- capturing_net_log,
- base::TimeDelta::FromMilliseconds(timeout_ms),
- base::TimeDelta(),
- base::TimeDelta(),
- logger,
- device_capabilities,
- AuthContext::Create()),
- capturing_net_log_(capturing_net_log),
- ip_(ip_endpoint),
+ TestCastSocketBase(const CastSocketOpenParams& open_params, Logger* logger)
+ : CastSocketImpl(open_params, logger, AuthContext::Create()),
+ ip_(open_params.ip_endpoint),
extract_cert_result_(true),
verify_challenge_result_(true),
verify_challenge_disallow_(false),
@@ -239,7 +216,6 @@ class TestCastSocketBase : public CastSocketImpl {
base::Timer* GetTimer() override { return mock_timer_.get(); }
- std::unique_ptr<net::TestNetLog> capturing_net_log_;
net::IPEndPoint ip_;
// Simulated result of peer cert extraction.
bool extract_cert_result_;
@@ -255,15 +231,18 @@ class TestCastSocketBase : public CastSocketImpl {
class MockTestCastSocket : public TestCastSocketBase {
public:
static std::unique_ptr<MockTestCastSocket> CreateSecure(
- Logger* logger,
- uint64_t device_capabilities = cast_channel::CastDeviceCapability::NONE) {
+ const CastSocketOpenParams& open_params,
+ Logger* logger) {
return std::unique_ptr<MockTestCastSocket>(
- new MockTestCastSocket(CreateIPEndPointForTest(), kDistantTimeoutMillis,
- logger, device_capabilities));
+ new MockTestCastSocket(open_params, logger));
}
using TestCastSocketBase::TestCastSocketBase;
+ MockTestCastSocket(const CastSocketOpenParams& open_params, Logger* logger)
+ : TestCastSocketBase(open_params, logger),
+ mock_net_log_(open_params.net_log) {}
+
~MockTestCastSocket() override {}
void SetupMockTransport() {
@@ -324,9 +303,10 @@ class MockTestCastSocket : public TestCastSocketBase {
ssl_data_.reset(new net::StaticSocketDataProvider(
reads_.data(), reads_.size(), writes_.data(), writes_.size()));
ssl_data_->set_connect_data(*ssl_connect_data_);
+
// NOTE: net::MockTCPClientSocket inherits from net::SSLClientSocket !!
return std::unique_ptr<net::SSLClientSocket>(new net::MockTCPClientSocket(
- net::AddressList(), capturing_net_log_.get(), ssl_data_.get()));
+ net::AddressList(), mock_net_log_, ssl_data_.get()));
}
// Simulated connect data
@@ -339,6 +319,7 @@ class MockTestCastSocket : public TestCastSocketBase {
// If true, makes TCP connection process stall. For timeout testing.
bool tcp_unresponsive_ = false;
MockCastTransport* mock_transport_ = nullptr;
+ net::NetLog* mock_net_log_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MockTestCastSocket);
};
@@ -346,11 +327,10 @@ class MockTestCastSocket : public TestCastSocketBase {
class SslTestCastSocket : public TestCastSocketBase {
public:
static std::unique_ptr<SslTestCastSocket> CreateSecure(
- Logger* logger,
- uint64_t device_capabilities = cast_channel::CastDeviceCapability::NONE) {
+ const CastSocketOpenParams& open_params,
+ Logger* logger) {
return std::unique_ptr<SslTestCastSocket>(
- new SslTestCastSocket(CreateIPEndPointForTest(), kDistantTimeoutMillis,
- logger, device_capabilities));
+ new SslTestCastSocket(open_params, logger));
}
using TestCastSocketBase::TestCastSocketBase;
@@ -372,7 +352,12 @@ class CastSocketTestBase : public testing::Test {
CastSocketTestBase()
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
logger_(new Logger()),
- observer_(new MockCastSocketObserver()) {}
+ observer_(new MockCastSocketObserver()),
+ capturing_net_log_(new net::TestNetLog()),
+ socket_open_params_(
+ CreateIPEndPointForTest(),
+ capturing_net_log_.get(),
+ base::TimeDelta::FromMilliseconds(kDistantTimeoutMillis)) {}
~CastSocketTestBase() override {}
void SetUp() override { EXPECT_CALL(*observer_, OnMessage(_, _)).Times(0); }
@@ -387,6 +372,8 @@ class CastSocketTestBase : public testing::Test {
Logger* logger_;
CompleteHandler handler_;
std::unique_ptr<MockCastSocketObserver> observer_;
+ std::unique_ptr<net::TestNetLog> capturing_net_log_;
+ CastSocketOpenParams socket_open_params_;
private:
DISALLOW_COPY_AND_ASSIGN(CastSocketTestBase);
@@ -405,7 +392,7 @@ class MockCastSocketTest : public CastSocketTestBase {
}
void CreateCastSocketSecure() {
- socket_ = MockTestCastSocket::CreateSecure(logger_);
+ socket_ = MockTestCastSocket::CreateSecure(socket_open_params_, logger_);
}
void HandleAuthHandshake() {
@@ -415,7 +402,7 @@ class MockCastSocketTest : public CastSocketTestBase {
SendMessage(EqualsProto(challenge_proto), _))
.WillOnce(PostCompletionCallbackTask<1>(net::OK));
EXPECT_CALL(*socket_->GetMockTransport(), Start());
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->AddObserver(observer_.get());
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
@@ -444,7 +431,7 @@ class SslCastSocketTest : public CastSocketTestBase {
}
void CreateSockets() {
- socket_ = SslTestCastSocket::CreateSecure(logger_);
+ socket_ = SslTestCastSocket::CreateSecure(socket_open_params_, logger_);
server_cert_ =
net::ImportCertFromFile(GetTestCertsDirectory(), "self_signed.pem");
@@ -630,7 +617,7 @@ TEST_F(MockCastSocketTest, TestConnectAuthMessageCorrupted) {
SendMessage(EqualsProto(challenge_proto), _))
.WillOnce(PostCompletionCallbackTask<1>(net::OK));
EXPECT_CALL(*socket_->GetMockTransport(), Start());
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::TRANSPORT_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -655,7 +642,7 @@ TEST_F(MockCastSocketTest, TestConnectTcpConnectErrorAsync) {
socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -670,7 +657,7 @@ TEST_F(MockCastSocketTest, TestConnectTcpConnectErrorSync) {
socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_FAILED);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -683,7 +670,7 @@ TEST_F(MockCastSocketTest, TestConnectTcpConnectErrorSync) {
TEST_F(MockCastSocketTest, TestConnectTcpTimeoutError) {
CreateCastSocketSecure();
socket_->SetupTcpConnectUnresponsive();
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
EXPECT_CALL(*observer_, OnError(_, ChannelError::CONNECT_TIMEOUT));
socket_->AddObserver(observer_.get());
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -703,7 +690,7 @@ TEST_F(MockCastSocketTest, TestConnectTcpTimeoutError) {
TEST_F(MockCastSocketTest, TestConnectTcpSocketTimeoutError) {
CreateCastSocketSecure();
socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
EXPECT_CALL(*observer_, OnError(_, ChannelError::CONNECT_TIMEOUT));
socket_->AddObserver(observer_.get());
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -723,8 +710,7 @@ TEST_F(MockCastSocketTest, TestConnectSslConnectErrorAsync) {
socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
- EXPECT_CALL(handler_,
- OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -740,8 +726,7 @@ TEST_F(MockCastSocketTest, TestConnectSslConnectErrorSync) {
socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
- EXPECT_CALL(handler_,
- OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -759,7 +744,7 @@ TEST_F(MockCastSocketTest, TestConnectSslConnectTimeoutSync) {
socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -777,7 +762,7 @@ TEST_F(MockCastSocketTest, TestConnectSslConnectTimeoutAsync) {
socket_->SetupTcpConnect(net::ASYNC, net::OK);
socket_->SetupSslConnect(net::ASYNC, net::ERR_CONNECTION_TIMED_OUT);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -797,7 +782,7 @@ TEST_F(MockCastSocketTest, TestConnectChallengeSendError) {
SendMessage(EqualsProto(CreateAuthChallenge()), _))
.WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CAST_SOCKET_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -834,7 +819,7 @@ TEST_F(MockCastSocketTest, TestConnectChallengeReplyReceiveError) {
.WillOnce(PostCompletionCallbackTask<1>(net::OK));
socket_->AddReadResult(net::SYNCHRONOUS, net::ERR_FAILED);
EXPECT_CALL(*observer_, OnError(_, ChannelError::CAST_SOCKET_ERROR));
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CAST_SOCKET_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
EXPECT_CALL(*socket_->GetMockTransport(), Start());
socket_->AddObserver(observer_.get());
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -860,8 +845,7 @@ TEST_F(MockCastSocketTest, TestConnectChallengeVerificationFails) {
EXPECT_CALL(*socket_->GetMockTransport(),
SendMessage(EqualsProto(challenge_proto), _))
.WillOnce(PostCompletionCallbackTask<1>(net::OK));
- EXPECT_CALL(handler_,
- OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
EXPECT_CALL(*socket_->GetMockTransport(), Start());
socket_->AddObserver(observer_.get());
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -899,7 +883,7 @@ TEST_F(MockCastSocketTest, TestConnectEndToEndWithRealTransportAsync) {
EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
socket_->AddWriteResultForData(net::ASYNC, test_message_str);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -941,7 +925,7 @@ TEST_F(MockCastSocketTest, TestConnectEndToEndWithRealTransportSync) {
EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
socket_->AddWriteResultForData(net::SYNCHRONOUS, test_message_str);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
@@ -983,8 +967,7 @@ TEST_F(MockCastSocketTest, TestOpenChannelConnectingSocket) {
base::Unretained(&handler_)));
RunPendingTasks();
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT))
- .Times(2);
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get())).Times(2);
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
socket_->TriggerTimeout();
@@ -998,7 +981,7 @@ TEST_F(MockCastSocketTest, TestOpenChannelConnectedSocket) {
HandleAuthHandshake();
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
}
@@ -1007,12 +990,12 @@ TEST_F(MockCastSocketTest, TestOpenChannelClosedSocket) {
CreateCastSocketSecure();
socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
RunPendingTasks();
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
base::Unretained(&handler_)));
}
@@ -1049,7 +1032,7 @@ TEST_F(SslCastSocketTest, TestConnectEndToEndWithRealSSL) {
server_socket_.get());
EXPECT_EQ(reply_buffer->size(), written);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
RunPendingTasks();
EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
@@ -1089,7 +1072,7 @@ TEST_F(SslCastSocketTest, TestMessageEndToEndWithRealSSL) {
server_socket_.get());
EXPECT_EQ(reply_buffer->size(), written);
- EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+ EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
RunPendingTasks();
EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
diff --git a/chromium/components/cast_channel/cast_test_util.h b/chromium/components/cast_channel/cast_test_util.h
index fbf0cc7ff76..fb0cffd52e4 100644
--- a/chromium/components/cast_channel/cast_test_util.h
+++ b/chromium/components/cast_channel/cast_test_util.h
@@ -84,15 +84,14 @@ class MockCastSocketService : public CastSocketService {
MOCK_METHOD4(OpenSocketInternal,
int(const net::IPEndPoint& ip_endpoint,
net::NetLog* net_log,
- const base::Callback<void(int, ChannelError)>& open_cb,
+ const base::Callback<void(CastSocket*)>& open_cb,
CastSocket::Observer* observer));
MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
};
class MockCastSocket : public CastSocket {
public:
- using MockOnOpenCallback =
- base::Callback<void(int channel_id, ChannelError error_state)>;
+ using MockOnOpenCallback = base::Callback<void(CastSocket* socket)>;
MockCastSocket();
~MockCastSocket() override;
diff --git a/chromium/components/cast_channel/logger.cc b/chromium/components/cast_channel/logger.cc
index 49641fa994e..50ccc8599e7 100644
--- a/chromium/components/cast_channel/logger.cc
+++ b/chromium/components/cast_channel/logger.cc
@@ -60,6 +60,10 @@ ChallengeReplyError AuthErrorToChallengeReplyError(
return ChallengeReplyError::CERT_REVOKED;
case AuthResult::ERROR_SENDER_NONCE_MISMATCH:
return ChallengeReplyError::SENDER_NONCE_MISMATCH;
+ case AuthResult::ERROR_SIGNATURE_EMPTY:
+ return ChallengeReplyError::SIGNATURE_EMPTY;
+ case AuthResult::ERROR_DIGEST_UNSUPPORTED:
+ return ChallengeReplyError::DIGEST_UNSUPPORTED;
default:
NOTREACHED();
return ChallengeReplyError::NONE;
diff --git a/chromium/components/cdm/browser/cdm_message_filter_android.cc b/chromium/components/cdm/browser/cdm_message_filter_android.cc
index 7840ea64ad3..91e5f6cf967 100644
--- a/chromium/components/cdm/browser/cdm_message_filter_android.cc
+++ b/chromium/components/cdm/browser/cdm_message_filter_android.cc
@@ -11,9 +11,9 @@
#include "base/feature_list.h"
#include "base/macros.h"
+#include "base/task_scheduler/post_task.h"
#include "components/cdm/common/cdm_messages_android.h"
#include "content/public/browser/android/android_overlay_provider.h"
-#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_message_macros.h"
#include "media/base/android/media_codec_util.h"
#include "media/base/android/media_drm_bridge.h"
@@ -22,7 +22,6 @@
#include "media/base/video_codecs.h"
#include "media/media_features.h"
-using content::BrowserThread;
using media::MediaDrmBridge;
using media::SupportedCodecs;
@@ -55,6 +54,7 @@ const CodecInfo<media::VideoCodec> kVideoCodecsToQuery[] = {
};
const CodecInfo<media::AudioCodec> kAudioCodecsToQuery[] = {
+ // FLAC is not supported. See https://crbug.com/747050 for details.
// Vorbis is not supported. See http://crbug.com/710924 for details.
{media::EME_CODEC_WEBM_OPUS, media::kCodecOpus, "video/webm"},
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -93,9 +93,14 @@ static SupportedCodecs GetSupportedCodecs(
return supported_codecs;
}
-CdmMessageFilterAndroid::CdmMessageFilterAndroid(bool can_use_secure_codecs)
+CdmMessageFilterAndroid::CdmMessageFilterAndroid(
+ bool can_persist_data,
+ bool force_to_support_secure_codecs)
: BrowserMessageFilter(EncryptedMediaMsgStart),
- force_to_support_secure_codecs_(can_use_secure_codecs) {}
+ task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND})),
+ can_persist_data_(can_persist_data),
+ force_to_support_secure_codecs_(force_to_support_secure_codecs) {}
CdmMessageFilterAndroid::~CdmMessageFilterAndroid() {}
@@ -111,11 +116,13 @@ bool CdmMessageFilterAndroid::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void CdmMessageFilterAndroid::OverrideThreadForMessage(
- const IPC::Message& message, BrowserThread::ID* thread) {
+base::TaskRunner* CdmMessageFilterAndroid::OverrideTaskRunnerForMessage(
+ const IPC::Message& message) {
// Move the IPC handling to FILE thread as it is not very cheap.
if (message.type() == ChromeViewHostMsg_QueryKeySystemSupport::ID)
- *thread = BrowserThread::FILE;
+ return task_runner_.get();
+
+ return nullptr;
}
void CdmMessageFilterAndroid::OnQueryKeySystemSupport(
@@ -134,6 +141,15 @@ void CdmMessageFilterAndroid::OnQueryKeySystemSupport(
if (!MediaDrmBridge::IsKeySystemSupported(request.key_system))
return;
+ // When using MediaDrm, we assume it'll always try to persist some data. If
+ // |can_persist_data_| is false and MediaDrm were to persist data on the
+ // Android system, we are somewhat violating the incognito assumption.
+ // This cannot be used detect incognito mode easily because the result is the
+ // same when |can_persist_data_| is false, and when user blocks the "protected
+ // media identifier" permission prompt.
+ if (!can_persist_data_)
+ return;
+
DCHECK(request.codecs & media::EME_CODEC_ALL) << "unrecognized codec";
response->key_system = request.key_system;
response->non_secure_codecs = GetSupportedCodecs(request, false);
diff --git a/chromium/components/cdm/browser/cdm_message_filter_android.h b/chromium/components/cdm/browser/cdm_message_filter_android.h
index 763bb85cc4f..3c0e3b76c10 100644
--- a/chromium/components/cdm/browser/cdm_message_filter_android.h
+++ b/chromium/components/cdm/browser/cdm_message_filter_android.h
@@ -11,6 +11,10 @@
struct SupportedKeySystemRequest;
struct SupportedKeySystemResponse;
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace cdm {
// Message filter for EME on Android. It is responsible for getting the
@@ -19,15 +23,16 @@ namespace cdm {
// desktop Chromium's IsPepperCdmAvailable() path.
class CdmMessageFilterAndroid : public content::BrowserMessageFilter {
public:
- explicit CdmMessageFilterAndroid(bool can_use_secure_codecs = false);
+ CdmMessageFilterAndroid(bool can_persist_data,
+ bool force_to_support_secure_codecs);
private:
~CdmMessageFilterAndroid() override;
// BrowserMessageFilter implementation.
bool OnMessageReceived(const IPC::Message& message) override;
- void OverrideThreadForMessage(const IPC::Message& message,
- content::BrowserThread::ID* thread) override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
// Query the key system information.
void OnQueryKeySystemSupport(const SupportedKeySystemRequest& request,
@@ -35,6 +40,12 @@ class CdmMessageFilterAndroid : public content::BrowserMessageFilter {
void OnGetPlatformKeySystemNames(std::vector<std::string>* key_systems);
+ const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ // Whether any data can be persisted by Chromium or by MediaDrm (e.g. false in
+ // incognito mode).
+ const bool can_persist_data_;
+
// By default, rendering of secure codecs is supported when AndroidOverlay is
// enabled. However, on platforms like Cast on Android, secure codecs are
// always supported. This flag is used to force secure codecs support on such
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.cc b/chromium/components/cdm/browser/media_drm_storage_impl.cc
index 2f9ee4f4253..39cabf5d201 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl.cc
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.cc
@@ -4,8 +4,11 @@
#include "components/cdm/browser/media_drm_storage_impl.h"
+#include <memory>
+
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/value_conversions.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -17,7 +20,7 @@
//
// {
// $origin: {
-// "origin_id": $origin_id
+// "origin_id": $unguessable_origin_id
// "creation_time": $creation_time
// "sessions" : {
// $session_id: {
@@ -40,40 +43,178 @@ const char kCreationTime[] = "creation_time";
const char kSessions[] = "sessions";
const char kKeySetId[] = "key_set_id";
const char kMimeType[] = "mime_type";
+const char kOriginId[] = "origin_id";
-std::unique_ptr<base::DictionaryValue> CreateOriginDictionary() {
- auto dict = base::MakeUnique<base::DictionaryValue>();
- // TODO(xhwang): Create |origin_id|.
- dict->SetDouble(kCreationTime, base::Time::Now().ToDoubleT());
- return dict;
-}
-
-std::unique_ptr<base::DictionaryValue> CreateSessionDictionary(
- const std::vector<uint8_t>& key_set_id,
- const std::string& mime_type) {
- auto dict = base::MakeUnique<base::DictionaryValue>();
- dict->SetString(kKeySetId,
- std::string(reinterpret_cast<const char*>(key_set_id.data()),
- key_set_id.size()));
- dict->SetString(kMimeType, mime_type);
- dict->SetDouble(kCreationTime, base::Time::Now().ToDoubleT());
- return dict;
-}
+// Extract base::Time from |dict| with key kCreationTime. Returns true if |dict|
+// contains a valid time value.
+bool GetTimeFromDict(const base::DictionaryValue& dict, base::Time* time) {
+ DCHECK(time);
-bool GetSessionData(const base::DictionaryValue* sesssion_dict,
- std::vector<uint8_t>* key_set_id,
- std::string* mime_type) {
- std::string key_set_id_string;
- if (!sesssion_dict->GetString(kKeySetId, &key_set_id_string))
+ double time_double = 0.;
+ if (!dict.GetDouble(kCreationTime, &time_double))
return false;
- if (!sesssion_dict->GetString(kMimeType, mime_type))
+ base::Time time_maybe_null = base::Time::FromDoubleT(time_double);
+ if (time_maybe_null.is_null())
return false;
- key_set_id->assign(key_set_id_string.begin(), key_set_id_string.end());
+ *time = time_maybe_null;
return true;
}
+// Data in origin dict without sessions dict.
+class OriginData {
+ public:
+ explicit OriginData(const base::UnguessableToken& origin_id)
+ : OriginData(origin_id, base::Time::Now()) {
+ DCHECK(origin_id_);
+ }
+
+ const base::UnguessableToken& origin_id() const { return origin_id_; }
+
+ base::Time provision_time() const { return provision_time_; }
+
+ std::unique_ptr<base::DictionaryValue> ToDictValue() const {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+
+ dict->Set(kOriginId, base::CreateUnguessableTokenValue(origin_id_));
+ dict->SetDouble(kCreationTime, provision_time_.ToDoubleT());
+
+ return dict;
+ }
+
+ // Convert |origin_dict| to OriginData. |origin_dict| contains information
+ // related to origin provision. Return nullptr if |origin_dict| has any
+ // corruption, e.g. format error, missing fields, invalid value.
+ static std::unique_ptr<OriginData> FromDictValue(
+ const base::DictionaryValue& origin_dict) {
+ const base::Value* origin_id_value = nullptr;
+ if (!origin_dict.Get(kOriginId, &origin_id_value))
+ return nullptr;
+
+ base::UnguessableToken origin_id;
+ if (!base::GetValueAsUnguessableToken(*origin_id_value, &origin_id))
+ return nullptr;
+
+ base::Time time;
+ if (!GetTimeFromDict(origin_dict, &time))
+ return nullptr;
+
+ return base::WrapUnique(new OriginData(origin_id, time));
+ }
+
+ private:
+ OriginData(const base::UnguessableToken& origin_id, base::Time time)
+ : origin_id_(origin_id), provision_time_(time) {}
+
+ base::UnguessableToken origin_id_;
+ base::Time provision_time_;
+};
+
+// Data in session dict.
+class SessionData {
+ public:
+ SessionData(const std::vector<uint8_t>& key_set_id,
+ const std::string& mime_type)
+ : SessionData(key_set_id, mime_type, base::Time::Now()) {}
+
+ base::Time creation_time() const { return creation_time_; }
+
+ std::unique_ptr<base::DictionaryValue> ToDictValue() const {
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+
+ dict->SetString(
+ kKeySetId,
+ std::string(reinterpret_cast<const char*>(key_set_id_.data()),
+ key_set_id_.size()));
+ dict->SetString(kMimeType, mime_type_);
+ dict->SetDouble(kCreationTime, creation_time_.ToDoubleT());
+
+ return dict;
+ }
+
+ media::mojom::SessionDataPtr ToMojo() const {
+ return media::mojom::SessionData::New(key_set_id_, mime_type_);
+ }
+
+ // Convert |session_dict| to SessionData. |session_dict| contains information
+ // for an offline license session. Return nullptr if |session_dict| has any
+ // corruption, e.g. format error, missing fields, invalid data.
+ static std::unique_ptr<SessionData> FromDictValue(
+ const base::DictionaryValue& session_dict) {
+ std::string key_set_id_string;
+ if (!session_dict.GetString(kKeySetId, &key_set_id_string))
+ return nullptr;
+
+ std::string mime_type;
+ if (!session_dict.GetString(kMimeType, &mime_type))
+ return nullptr;
+
+ base::Time time;
+ if (!GetTimeFromDict(session_dict, &time))
+ return nullptr;
+
+ return base::WrapUnique(
+ new SessionData(std::vector<uint8_t>(key_set_id_string.begin(),
+ key_set_id_string.end()),
+ std::move(mime_type), time));
+ }
+
+ private:
+ SessionData(std::vector<uint8_t> key_set_id,
+ std::string mime_type,
+ base::Time time)
+ : key_set_id_(std::move(key_set_id)),
+ mime_type_(std::move(mime_type)),
+ creation_time_(time) {}
+
+ std::vector<uint8_t> key_set_id_;
+ std::string mime_type_;
+ base::Time creation_time_;
+};
+
+// Get sessions dict for |origin_string| in |storage_dict|. This is a helper
+// function that works for both const and non const access.
+template <typename DictValue>
+DictValue* GetSessionsDictFromStorageDict(DictValue* storage_dict,
+ const std::string& origin_string) {
+ if (storage_dict == nullptr) {
+ DVLOG(1) << __func__ << ": No storage dict for origin " << origin_string;
+ return nullptr;
+ }
+
+ DictValue* origin_dict = nullptr;
+ // The origin string may contain dots. Do not use path expansion.
+ storage_dict->GetDictionaryWithoutPathExpansion(origin_string, &origin_dict);
+ if (!origin_dict) {
+ DVLOG(1) << __func__ << ": No entry for origin " << origin_string;
+ return nullptr;
+ }
+
+ DictValue* sessions_dict = nullptr;
+ if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
+ DVLOG(1) << __func__ << ": No sessions entry for origin " << origin_string;
+ return nullptr;
+ }
+
+ return sessions_dict;
+}
+
+// Create origin dict with empty sessions dict. It returns the sessions dict for
+// caller to write session information.
+base::DictionaryValue* CreateOriginDictAndReturnSessionsDict(
+ base::DictionaryValue* storage_dict,
+ const std::string& origin,
+ const base::UnguessableToken& origin_id) {
+ DCHECK(storage_dict);
+
+ // TODO(yucliu): Change to base::Value::SetKey.
+ return storage_dict
+ ->SetDictionaryWithoutPathExpansion(origin,
+ OriginData(origin_id).ToDictValue())
+ ->SetDictionary(kSessions, base::MakeUnique<base::DictionaryValue>());
+}
+
#if DCHECK_IS_ON()
// Returns whether |dict| has a value assocaited with the |key|.
bool HasEntry(const base::DictionaryValue& dict, const std::string& key) {
@@ -81,6 +222,107 @@ bool HasEntry(const base::DictionaryValue& dict, const std::string& key) {
}
#endif
+// Clear sessions whose creation time falls in [start, end] from
+// |sessions_dict|. This function also cleans corruption data and should never
+// fail.
+void ClearSessionDataForTimePeriod(base::DictionaryValue* sessions_dict,
+ base::Time start,
+ base::Time end) {
+ std::vector<std::string> sessions_to_clear;
+ for (const auto& key_value : *sessions_dict) {
+ const std::string& session_id = key_value.first;
+
+ base::DictionaryValue* session_dict;
+ if (!key_value.second->GetAsDictionary(&session_dict)) {
+ DLOG(WARNING) << "Session dict for " << session_id
+ << " is corrupted, removing.";
+ sessions_to_clear.push_back(session_id);
+ continue;
+ }
+
+ std::unique_ptr<SessionData> session_data =
+ SessionData::FromDictValue(*session_dict);
+ if (!session_data) {
+ DLOG(WARNING) << "Session data for " << session_id
+ << " is corrupted, removing.";
+ sessions_to_clear.push_back(session_id);
+ continue;
+ }
+
+ if (session_data->creation_time() >= start &&
+ session_data->creation_time() <= end) {
+ sessions_to_clear.push_back(session_id);
+ continue;
+ }
+ }
+
+ // Remove session data.
+ for (const auto& session_id : sessions_to_clear)
+ sessions_dict->RemoveWithoutPathExpansion(session_id, nullptr);
+}
+
+// 1. Removes the session data from origin dict if the session's creation time
+// falls in [|start|, |end|] and |filter| returns true on its origin.
+// 2. Removes the origin data if all of the sessions are removed.
+// 3. Returns a list of origin IDs to unprovision.
+std::vector<base::UnguessableToken> ClearMatchingLicenseData(
+ base::DictionaryValue* storage_dict,
+ base::Time start,
+ base::Time end,
+ const base::RepeatingCallback<bool(const GURL&)>& filter) {
+ std::vector<std::string> origins_to_delete;
+ std::vector<base::UnguessableToken> origin_ids_to_unprovision;
+
+ for (const auto& key_value : *storage_dict) {
+ const std::string& origin_str = key_value.first;
+
+ if (filter && !filter.Run(GURL(origin_str)))
+ continue;
+
+ base::DictionaryValue* origin_dict;
+ if (!key_value.second->GetAsDictionary(&origin_dict)) {
+ DLOG(WARNING) << "Origin dict for " << origin_str
+ << " is corrupted, removing.";
+ origins_to_delete.push_back(origin_str);
+ continue;
+ }
+
+ std::unique_ptr<OriginData> origin_data =
+ OriginData::FromDictValue(*origin_dict);
+ if (!origin_data) {
+ DLOG(WARNING) << "Origin data for " << origin_str
+ << " is corrupted, removing.";
+ origins_to_delete.push_back(origin_str);
+ continue;
+ }
+
+ if (origin_data->provision_time() > end)
+ continue;
+
+ base::DictionaryValue* sessions;
+ if (!origin_dict->GetDictionary(kSessions, &sessions)) {
+ // The origin is provisioned, but no persistent license is installed.
+ origins_to_delete.push_back(origin_str);
+ origin_ids_to_unprovision.push_back(origin_data->origin_id());
+ continue;
+ }
+
+ ClearSessionDataForTimePeriod(sessions, start, end);
+
+ if (sessions->empty()) {
+ // Session data will be removed when removing origin data.
+ origins_to_delete.push_back(origin_str);
+ origin_ids_to_unprovision.push_back(origin_data->origin_id());
+ }
+ }
+
+ // Remove origin data.
+ for (const auto& origin_str : origins_to_delete)
+ storage_dict->RemoveWithoutPathExpansion(origin_str, nullptr);
+
+ return origin_ids_to_unprovision;
+}
+
} // namespace
// static
@@ -88,6 +330,39 @@ void MediaDrmStorageImpl::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(kMediaDrmStorage);
}
+// static
+std::set<GURL> MediaDrmStorageImpl::GetAllOrigins(
+ const PrefService* pref_service) {
+ DCHECK(pref_service);
+
+ const base::DictionaryValue* storage_dict =
+ pref_service->GetDictionary(kMediaDrmStorage);
+ if (!storage_dict)
+ return std::set<GURL>();
+
+ std::set<GURL> origin_set;
+ for (const auto& key_value : *storage_dict) {
+ GURL origin(key_value.first);
+ if (origin.is_valid())
+ origin_set.insert(origin);
+ }
+
+ return origin_set;
+}
+
+// static
+std::vector<base::UnguessableToken> MediaDrmStorageImpl::ClearMatchingLicenses(
+ PrefService* pref_service,
+ base::Time start,
+ base::Time end,
+ const base::RepeatingCallback<bool(const GURL&)>& filter) {
+ DVLOG(1) << __func__ << ": Clear licenses [" << start << ", " << end << "]";
+
+ DictionaryPrefUpdate update(pref_service, kMediaDrmStorage);
+
+ return ClearMatchingLicenseData(update.Get(), start, end, filter);
+}
+
MediaDrmStorageImpl::MediaDrmStorageImpl(
content::RenderFrameHost* render_frame_host,
PrefService* pref_service,
@@ -95,7 +370,6 @@ MediaDrmStorageImpl::MediaDrmStorageImpl(
media::mojom::MediaDrmStorageRequest request)
: render_frame_host_(render_frame_host),
pref_service_(pref_service),
- origin_(origin),
origin_string_(origin.Serialize()),
binding_(this, std::move(request)) {
DVLOG(1) << __func__ << ": origin = " << origin;
@@ -113,21 +387,45 @@ MediaDrmStorageImpl::~MediaDrmStorageImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
}
-// TODO(xhwang): Update this function to return an origin ID. If the origin is
-// not the same as |origin_|, return an empty origin ID.
-void MediaDrmStorageImpl::Initialize(const url::Origin& origin) {
- DVLOG(1) << __func__ << ": origin = " << origin;
+void MediaDrmStorageImpl::Initialize(InitializeCallback callback) {
+ DVLOG(1) << __func__ << ": origin = " << origin_string_;
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!initialized_);
+ DCHECK(!origin_id_);
+
+ const base::DictionaryValue* storage_dict =
+ pref_service_->GetDictionary(kMediaDrmStorage);
+
+ const base::DictionaryValue* origin_dict = nullptr;
+ // The origin string may contain dots. Do not use path expansion.
+ bool exist = storage_dict && storage_dict->GetDictionaryWithoutPathExpansion(
+ origin_string_, &origin_dict);
+
+ base::UnguessableToken origin_id;
+ if (exist) {
+ DCHECK(origin_dict);
+
+ std::unique_ptr<OriginData> origin_data =
+ OriginData::FromDictValue(*origin_dict);
+ if (origin_data)
+ origin_id = origin_data->origin_id();
+ }
+
+ // |origin_id| can be empty even if |origin_dict| exists. This can happen if
+ // |origin_dict| is created with an old version app.
+ if (origin_id.is_empty())
+ origin_id = base::UnguessableToken::Create();
+
+ origin_id_ = origin_id;
- initialized_ = true;
+ DCHECK(origin_id);
+ std::move(callback).Run(origin_id);
}
void MediaDrmStorageImpl::OnProvisioned(OnProvisionedCallback callback) {
DVLOG(1) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ if (!IsInitialized()) {
DVLOG(1) << __func__ << ": Not initialized.";
std::move(callback).Run(false);
return;
@@ -142,8 +440,8 @@ void MediaDrmStorageImpl::OnProvisioned(OnProvisionedCallback callback) {
<< __func__ << ": Entry for origin " << origin_string_
<< " already exists and will be cleared";
- storage_dict->SetWithoutPathExpansion(origin_string_,
- CreateOriginDictionary());
+ CreateOriginDictAndReturnSessionsDict(storage_dict, origin_string_,
+ origin_id_);
std::move(callback).Run(true);
}
@@ -154,7 +452,7 @@ void MediaDrmStorageImpl::SavePersistentSession(
DVLOG(2) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ if (!IsInitialized()) {
DVLOG(1) << __func__ << ": Not initialized.";
std::move(callback).Run(false);
return;
@@ -164,28 +462,18 @@ void MediaDrmStorageImpl::SavePersistentSession(
base::DictionaryValue* storage_dict = update.Get();
DCHECK(storage_dict);
- base::DictionaryValue* origin_dict = nullptr;
- // The origin string may contain dots. Do not use path expansion.
- storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
+ base::DictionaryValue* sessions_dict =
+ GetSessionsDictFromStorageDict<base::DictionaryValue>(storage_dict,
+ origin_string_);
// This could happen if the profile is removed, but the device is still
// provisioned for the origin. In this case, just create a new entry.
- if (!origin_dict) {
-
- DVLOG(1) << __func__ << ": Entry for origin " << origin_string_
- << " does not exist; create a new one.";
- storage_dict->SetWithoutPathExpansion(origin_string_,
- CreateOriginDictionary());
- storage_dict->GetDictionaryWithoutPathExpansion(origin_string_,
- &origin_dict);
- DCHECK(origin_dict);
- }
-
- base::DictionaryValue* sessions_dict = nullptr;
- if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
- DVLOG(2) << __func__ << ": No session exists; creating a new dict.";
- origin_dict->Set(kSessions, base::MakeUnique<base::DictionaryValue>());
- origin_dict->GetDictionary(kSessions, &sessions_dict);
+ // Since we're using random origin ID in MediaDrm, it's rare to enter the if
+ // branch. Deleting the profile causes reprovisioning of the origin.
+ if (!sessions_dict) {
+ DVLOG(1) << __func__ << ": No entry for origin " << origin_string_;
+ sessions_dict = CreateOriginDictAndReturnSessionsDict(
+ storage_dict, origin_string_, origin_id_);
DCHECK(sessions_dict);
}
@@ -193,8 +481,8 @@ void MediaDrmStorageImpl::SavePersistentSession(
<< __func__ << ": Session ID already exists and will be replaced.";
sessions_dict->SetWithoutPathExpansion(
- session_id, CreateSessionDictionary(session_data->key_set_id,
- session_data->mime_type));
+ session_id, SessionData(session_data->key_set_id, session_data->mime_type)
+ .ToDictValue());
std::move(callback).Run(true);
}
@@ -205,29 +493,16 @@ void MediaDrmStorageImpl::LoadPersistentSession(
DVLOG(2) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ if (!IsInitialized()) {
DVLOG(1) << __func__ << ": Not initialized.";
std::move(callback).Run(nullptr);
return;
}
- const base::DictionaryValue* storage_dict =
- pref_service_->GetDictionary(kMediaDrmStorage);
-
- const base::DictionaryValue* origin_dict = nullptr;
- // The origin string may contain dots. Do not use path expansion.
- storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
- if (!origin_dict) {
- DVLOG(1) << __func__
- << ": Failed to save persistent session data; entry for origin "
- << origin_ << " does not exist.";
- std::move(callback).Run(nullptr);
- return;
- }
-
- const base::DictionaryValue* sessions_dict = nullptr;
- if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
- DVLOG(2) << __func__ << ": Sessions dictionary does not exist.";
+ const base::DictionaryValue* sessions_dict =
+ GetSessionsDictFromStorageDict<const base::DictionaryValue>(
+ pref_service_->GetDictionary(kMediaDrmStorage), origin_string_);
+ if (!sessions_dict) {
std::move(callback).Run(nullptr);
return;
}
@@ -235,21 +510,21 @@ void MediaDrmStorageImpl::LoadPersistentSession(
const base::DictionaryValue* session_dict = nullptr;
if (!sessions_dict->GetDictionaryWithoutPathExpansion(session_id,
&session_dict)) {
- DVLOG(2) << __func__ << ": Session dictionary does not exist.";
+ DVLOG(1) << __func__ << ": No session " << session_id << " for origin "
+ << origin_string_;
std::move(callback).Run(nullptr);
return;
}
- std::vector<uint8_t> key_set_id;
- std::string mime_type;
- if (!GetSessionData(session_dict, &key_set_id, &mime_type)) {
- DVLOG(2) << __func__ << ": Failed to read session data.";
+ std::unique_ptr<SessionData> session_data =
+ SessionData::FromDictValue(*session_dict);
+ if (!session_data) {
+ DLOG(WARNING) << __func__ << ": Failed to read session data.";
std::move(callback).Run(nullptr);
return;
}
- std::move(callback).Run(
- media::mojom::SessionData::New(key_set_id, mime_type));
+ std::move(callback).Run(session_data->ToMojo());
}
void MediaDrmStorageImpl::RemovePersistentSession(
@@ -258,29 +533,19 @@ void MediaDrmStorageImpl::RemovePersistentSession(
DVLOG(2) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
- if (!initialized_) {
+ if (!IsInitialized()) {
DVLOG(1) << __func__ << ": Not initialized.";
std::move(callback).Run(false);
return;
}
DictionaryPrefUpdate update(pref_service_, kMediaDrmStorage);
- base::DictionaryValue* storage_dict = update.Get();
- DCHECK(storage_dict);
- base::DictionaryValue* origin_dict = nullptr;
- // The origin string may contain dots. Do not use path expansion.
- storage_dict->GetDictionaryWithoutPathExpansion(origin_string_, &origin_dict);
- if (!origin_dict) {
- DVLOG(1) << __func__ << ": Entry for rigin " << origin_string_
- << " does not exist.";
- std::move(callback).Run(true);
- return;
- }
+ base::DictionaryValue* sessions_dict =
+ GetSessionsDictFromStorageDict<base::DictionaryValue>(update.Get(),
+ origin_string_);
- base::DictionaryValue* sessions_dict = nullptr;
- if (!origin_dict->GetDictionary(kSessions, &sessions_dict)) {
- DVLOG(2) << __func__ << ": Sessions dictionary does not exist.";
+ if (!sessions_dict) {
std::move(callback).Run(true);
return;
}
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.h b/chromium/components/cdm/browser/media_drm_storage_impl.h
index f6970f650ca..1b7fd60b62e 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl.h
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.h
@@ -5,11 +5,18 @@
#ifndef COMPONENTS_CDM_BROWSER_MEDIA_DRM_STORAGE_IMPL_H_
#define COMPONENTS_CDM_BROWSER_MEDIA_DRM_STORAGE_IMPL_H_
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "media/mojo/interfaces/media_drm_storage.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "url/gurl.h"
#include "url/origin.h"
class PrefRegistrySimple;
@@ -29,6 +36,23 @@ class MediaDrmStorageImpl final : public media::mojom::MediaDrmStorage,
public:
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+ // Get a list of origins that have persistent storage on the device.
+ static std::set<GURL> GetAllOrigins(const PrefService* pref_service);
+
+ // Clear licenses if:
+ // 1. The license creation time falls in [|start|, |end|], and
+ // 2. |filter| returns true on the media license's origin.
+ //
+ // Return a list of origin IDs that have no licenses remaining so that the
+ // origin can be unprovisioned.
+ //
+ // TODO(yucliu): Add unit test.
+ static std::vector<base::UnguessableToken> ClearMatchingLicenses(
+ PrefService* pref_service,
+ base::Time start,
+ base::Time end,
+ const base::RepeatingCallback<bool(const GURL&)>& filter);
+
MediaDrmStorageImpl(content::RenderFrameHost* render_frame_host,
PrefService* pref_service,
const url::Origin& origin,
@@ -36,7 +60,7 @@ class MediaDrmStorageImpl final : public media::mojom::MediaDrmStorage,
~MediaDrmStorageImpl() final;
// media::mojom::MediaDrmStorage implementation.
- void Initialize(const url::Origin& origin) final;
+ void Initialize(InitializeCallback callback) final;
void OnProvisioned(OnProvisionedCallback callback) final;
void SavePersistentSession(const std::string& session_id,
media::mojom::SessionDataPtr session_data,
@@ -50,6 +74,8 @@ class MediaDrmStorageImpl final : public media::mojom::MediaDrmStorage,
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) final;
void DidFinishNavigation(content::NavigationHandle* navigation_handle) final;
+ bool IsInitialized() const { return !!origin_id_; }
+
private:
base::ThreadChecker thread_checker_;
@@ -58,9 +84,14 @@ class MediaDrmStorageImpl final : public media::mojom::MediaDrmStorage,
content::RenderFrameHost* const render_frame_host_ = nullptr;
PrefService* const pref_service_ = nullptr;
- const url::Origin origin_;
+
+ // String for the current origin. It will be used as a key in storage
+ // dictionary.
const std::string origin_string_;
- bool initialized_ = false;
+
+ // ID for the current origin. Per EME spec on individualization,
+ // implementation should not expose application-specific information.
+ base::UnguessableToken origin_id_;
mojo::Binding<media::mojom::MediaDrmStorage> binding_;
};
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
index daf0c8f6f86..840437ebcce 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
+++ b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
@@ -8,6 +8,7 @@
#include "base/run_loop.h"
#include "base/test/test_message_loop.h"
+#include "base/unguessable_token.h"
#include "components/prefs/testing_pref_service.h"
#include "media/mojo/services/mojo_media_drm_storage.h"
#include "mojo/public/cpp/bindings/interface_request.h"
@@ -30,27 +31,45 @@ class MediaDrmStorageImplTest : public ::testing::Test {
PrefRegistrySimple* registry = pref_service_->registry();
MediaDrmStorageImpl::RegisterProfilePrefs(registry);
+ media_drm_storage_ = CreateAndInitMediaDrmStorage(&origin_id_);
+ }
+
+ void TearDown() override {
+ media_drm_storage_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ protected:
+ using SessionData = media::MediaDrmStorage::SessionData;
+
+ std::unique_ptr<media::MediaDrmStorage> CreateAndInitMediaDrmStorage(
+ base::UnguessableToken* origin_id) {
+ DCHECK(origin_id);
+
media::mojom::MediaDrmStoragePtr media_drm_storage_ptr;
auto request = mojo::MakeRequest(&media_drm_storage_ptr);
- media_drm_storage_.reset(
- new media::MojoMediaDrmStorage(std::move(media_drm_storage_ptr)));
+ auto media_drm_storage = base::MakeUnique<media::MojoMediaDrmStorage>(
+ std::move(media_drm_storage_ptr));
// The created object will be destroyed on connection error.
new MediaDrmStorageImpl(nullptr, // Use null RenderFrameHost for testing.
pref_service_.get(), url::Origin(GURL(kTestOrigin)),
std::move(request));
- media_drm_storage_->Initialize(url::Origin(GURL(kTestOrigin)));
- }
+ media_drm_storage->Initialize(base::BindOnce(
+ [](base::UnguessableToken* out_origin_id,
+ const base::UnguessableToken& origin_id) {
+ DCHECK(origin_id);
+ *out_origin_id = origin_id;
+ },
+ origin_id));
- void TearDown() override {
- media_drm_storage_.reset();
base::RunLoop().RunUntilIdle();
- }
- protected:
- using SessionData = media::MediaDrmStorage::SessionData;
+ DCHECK(*origin_id);
+ return media_drm_storage;
+ }
void OnProvisioned() {
media_drm_storage_->OnProvisioned(ExpectResult(true));
@@ -120,8 +139,20 @@ class MediaDrmStorageImplTest : public ::testing::Test {
base::TestMessageLoop message_loop_;
std::unique_ptr<TestingPrefServiceSimple> pref_service_;
std::unique_ptr<media::MediaDrmStorage> media_drm_storage_;
+ base::UnguessableToken origin_id_;
};
+// TODO(yucliu): Test origin ID is re-generated after clearing licenses.
+TEST_F(MediaDrmStorageImplTest, Initialize_OriginIdNotChanged) {
+ OnProvisioned();
+ base::RunLoop().RunUntilIdle();
+
+ base::UnguessableToken origin_id;
+ std::unique_ptr<media::MediaDrmStorage> storage =
+ CreateAndInitMediaDrmStorage(&origin_id);
+ EXPECT_EQ(origin_id, origin_id_);
+}
+
TEST_F(MediaDrmStorageImplTest, OnProvisioned) {
OnProvisioned();
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/cdm/renderer/BUILD.gn b/chromium/components/cdm/renderer/BUILD.gn
index d7dceadcbfb..c14dd74f07c 100644
--- a/chromium/components/cdm/renderer/BUILD.gn
+++ b/chromium/components/cdm/renderer/BUILD.gn
@@ -22,7 +22,7 @@ static_library("renderer") {
"//components/cdm/common",
"//content/public/renderer",
"//media",
- "//ppapi/features",
+ "//media:media_features",
"//third_party/widevine/cdm:headers",
]
}
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
index b43b5c682a8..e50b76a8ea3 100644
--- a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
@@ -7,11 +7,10 @@
#include "base/logging.h"
#include "media/base/eme_constants.h"
#include "media/media_features.h"
-#include "ppapi/features/features.h"
namespace cdm {
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const char kExternalClearKeyPepperType[] = "application/x-ppapi-clearkey-cdm";
#endif
@@ -82,7 +81,7 @@ ExternalClearKeyProperties::GetDistinctiveIdentifierSupport() const {
return media::EmeFeatureSupport::NOT_SUPPORTED;
}
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
std::string ExternalClearKeyProperties::GetPepperType() const {
return kExternalClearKeyPepperType;
}
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
index 9b50b1a98e8..a8f8e035171 100644
--- a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
@@ -9,11 +9,11 @@
#include "build/build_config.h"
#include "media/base/key_system_properties.h"
-#include "ppapi/features/features.h"
+#include "media/media_features.h"
namespace cdm {
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
extern const char kExternalClearKeyPepperType[];
#endif
@@ -36,7 +36,7 @@ class ExternalClearKeyProperties : public media::KeySystemProperties {
const override;
media::EmeFeatureSupport GetPersistentStateSupport() const override;
media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override;
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
std::string GetPepperType() const override;
#endif
diff --git a/chromium/components/cdm/renderer/widevine_key_system_properties.cc b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
index c16e8e7828f..e2b8d57138d 100644
--- a/chromium/components/cdm/renderer/widevine_key_system_properties.cc
+++ b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
@@ -5,7 +5,6 @@
#include "components/cdm/renderer/widevine_key_system_properties.h"
#include "media/media_features.h"
-#include "ppapi/features/features.h"
#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
#if defined(WIDEVINE_CDM_AVAILABLE)
@@ -163,7 +162,7 @@ EmeFeatureSupport WidevineKeySystemProperties::GetDistinctiveIdentifierSupport()
return distinctive_identifier_support_;
}
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
std::string WidevineKeySystemProperties::GetPepperType() const {
return kWidevineCdmPluginMimeType;
}
diff --git a/chromium/components/cdm/renderer/widevine_key_system_properties.h b/chromium/components/cdm/renderer/widevine_key_system_properties.h
index c61ce2efbe7..0f8fcaf77c2 100644
--- a/chromium/components/cdm/renderer/widevine_key_system_properties.h
+++ b/chromium/components/cdm/renderer/widevine_key_system_properties.h
@@ -7,7 +7,7 @@
#include "build/build_config.h"
#include "media/base/key_system_properties.h"
-#include "ppapi/features/features.h"
+#include "media/media_features.h"
namespace cdm {
@@ -57,7 +57,7 @@ class WidevineKeySystemProperties : public media::KeySystemProperties {
media::EmeFeatureSupport GetPersistentStateSupport() const override;
media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override;
-#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
std::string GetPepperType() const override;
#endif
diff --git a/chromium/components/certificate_reporting/error_reporter.cc b/chromium/components/certificate_reporting/error_reporter.cc
index e189a4f49a6..80acdbff489 100644
--- a/chromium/components/certificate_reporting/error_reporter.cc
+++ b/chromium/components/certificate_reporting/error_reporter.cc
@@ -123,7 +123,7 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can control this feature via the 'Automatically report "
"details of possible security incidents to Google' setting under "
diff --git a/chromium/components/chrome_cleaner/public/typemaps/DEPS b/chromium/components/chrome_cleaner/public/typemaps/DEPS
index e9aaaf9ce4c..ecb7fab450c 100644
--- a/chromium/components/chrome_cleaner/public/typemaps/DEPS
+++ b/chromium/components/chrome_cleaner/public/typemaps/DEPS
@@ -1,4 +1,5 @@
# Allow the typemaps to access their dependencies.
include_rules = [
+ '+base/containers/span.h',
'+base/files/file_path.h',
]
diff --git a/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc b/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
index d15c172ebef..bf6c9634a57 100644
--- a/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
+++ b/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
@@ -7,16 +7,16 @@
namespace mojo {
// static
-ConstCArray<uint16_t>
+base::span<const uint16_t>
StructTraits<chrome_cleaner::mojom::FilePathDataView, base::FilePath>::value(
const base::FilePath& file_path) {
#if defined(OS_WIN)
- return ConstCArray<uint16_t>(
- file_path.value().size(),
- reinterpret_cast<const uint16_t*>(file_path.value().data()));
+ return base::make_span(
+ reinterpret_cast<const uint16_t*>(file_path.value().data()),
+ file_path.value().size());
#else
NOTREACHED();
- return ConstCArray<uint16_t>();
+ return base::span<const uint16_t>();
#endif
}
diff --git a/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.h b/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.h
index 76d123f9336..06c1f5889e5 100644
--- a/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.h
+++ b/chromium/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_CHROME_CLEANER_PUBLIC_TYPEMAPS_CHROME_CLEANER_STRUCT_TRAITS_H_
#define COMPONENTS_CHROME_CLEANER_PUBLIC_TYPEMAPS_CHROME_CLEANER_STRUCT_TRAITS_H_
+#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
@@ -12,7 +13,7 @@ namespace mojo {
template <>
struct StructTraits<chrome_cleaner::mojom::FilePathDataView, base::FilePath> {
- static ConstCArray<uint16_t> value(const base::FilePath& file_path);
+ static base::span<const uint16_t> value(const base::FilePath& file_path);
static bool Read(chrome_cleaner::mojom::FilePathDataView path_view,
base::FilePath* out);
};
diff --git a/chromium/components/component_updater/component_updater_service.cc b/chromium/components/component_updater/component_updater_service.cc
index 9be0f5c3494..12426113df2 100644
--- a/chromium/components/component_updater/component_updater_service.cc
+++ b/chromium/components/component_updater/component_updater_service.cc
@@ -19,10 +19,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -51,17 +48,19 @@ enum UpdateType {
namespace component_updater {
-ComponentInfo::ComponentInfo(const std::string& id, const base::string16& name,
+ComponentInfo::ComponentInfo(const std::string& id,
+ const std::string& fingerprint,
+ const base::string16& name,
const base::Version& version)
- : id(id), name(name), version(version) {}
+ : id(id), fingerprint(fingerprint), name(name), version(version) {}
+ComponentInfo::ComponentInfo(const ComponentInfo& other) = default;
+ComponentInfo::ComponentInfo(ComponentInfo&& other) = default;
ComponentInfo::~ComponentInfo() {}
CrxUpdateService::CrxUpdateService(
const scoped_refptr<Configurator>& config,
const scoped_refptr<UpdateClient>& update_client)
- : config_(config),
- update_client_(update_client),
- blocking_task_runner_(config->GetSequencedTaskRunner()) {
+ : config_(config), update_client_(update_client) {
AddObserver(this);
}
@@ -203,9 +202,20 @@ std::unique_ptr<ComponentInfo> CrxUpdateService::GetComponentForMimeType(
auto* const component = GetComponent(it->second);
if (!component)
return nullptr;
- return base::MakeUnique<ComponentInfo>(GetCrxComponentID(*component),
- base::UTF8ToUTF16(component->name),
- component->version);
+ return base::MakeUnique<ComponentInfo>(
+ GetCrxComponentID(*component), component->fingerprint,
+ base::UTF8ToUTF16(component->name), component->version);
+}
+
+std::vector<ComponentInfo> CrxUpdateService::GetComponents() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ std::vector<ComponentInfo> result;
+ for (const auto& it : components_) {
+ result.push_back(ComponentInfo(it.first, it.second.fingerprint,
+ base::UTF8ToUTF16(it.second.name),
+ it.second.version));
+ }
+ return result;
}
OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
@@ -250,7 +260,7 @@ void CrxUpdateService::OnDemandUpdate(const std::string& id,
if (!callback.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(callback, update_client::Error::INVALID_ARGUMENT));
+ base::BindOnce(callback, update_client::Error::INVALID_ARGUMENT));
}
return;
}
@@ -325,12 +335,6 @@ bool CrxUpdateService::CheckForUpdates() {
return true;
}
-scoped_refptr<base::SequencedTaskRunner>
-CrxUpdateService::GetSequencedTaskRunner() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return blocking_task_runner_;
-}
-
bool CrxUpdateService::GetComponentDetails(const std::string& id,
CrxUpdateItem* item) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -383,8 +387,8 @@ void CrxUpdateService::OnUpdateComplete(Callback callback,
}
if (!callback.is_null()) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, error));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback, error));
}
}
diff --git a/chromium/components/component_updater/component_updater_service.h b/chromium/components/component_updater/component_updater_service.h
index 0701e9cac0b..72f293e9f1e 100644
--- a/chromium/components/component_updater/component_updater_service.h
+++ b/chromium/components/component_updater/component_updater_service.h
@@ -22,10 +22,6 @@
class ComponentsUI;
class PluginObserver;
-namespace base {
-class SequencedTaskRunner;
-}
-
namespace policy {
class ComponentUpdaterPolicyTest;
}
@@ -49,11 +45,16 @@ using CrxComponent = update_client::CrxComponent;
using CrxUpdateItem = update_client::CrxUpdateItem;
struct ComponentInfo {
- ComponentInfo(const std::string& id, const base::string16& name,
+ ComponentInfo(const std::string& id,
+ const std::string& fingerprint,
+ const base::string16& name,
const base::Version& version);
+ ComponentInfo(const ComponentInfo& other);
+ ComponentInfo(ComponentInfo&& other);
~ComponentInfo();
const std::string id;
+ const std::string fingerprint;
const base::string16 name;
const base::Version version;
};
@@ -110,6 +111,10 @@ class ComponentUpdateService {
virtual std::unique_ptr<ComponentInfo> GetComponentForMimeType(
const std::string& mime_type) const = 0;
+ // Returns a list of ComponentInfo objects describing all registered
+ // components.
+ virtual std::vector<ComponentInfo> GetComponents() const = 0;
+
// Returns an interface for on-demand updates. On-demand updates are
// proactively triggered outside the normal component update service schedule.
virtual OnDemandUpdater& GetOnDemandUpdater() = 0;
@@ -129,9 +134,6 @@ class ComponentUpdateService {
virtual void MaybeThrottle(const std::string& id,
const base::Closure& callback) = 0;
- // Returns a task runner suitable for use by component installers.
- virtual scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() = 0;
-
virtual ~ComponentUpdateService() {}
private:
diff --git a/chromium/components/component_updater/component_updater_service_internal.h b/chromium/components/component_updater/component_updater_service_internal.h
index f25bbc973ef..84fc82c6c50 100644
--- a/chromium/components/component_updater/component_updater_service_internal.h
+++ b/chromium/components/component_updater/component_updater_service_internal.h
@@ -12,8 +12,6 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "components/component_updater/timer.h"
@@ -50,10 +48,10 @@ class CrxUpdateService : public ComponentUpdateService,
std::vector<std::string> GetComponentIDs() const override;
std::unique_ptr<ComponentInfo> GetComponentForMimeType(
const std::string& id) const override;
+ std::vector<ComponentInfo> GetComponents() const override;
OnDemandUpdater& GetOnDemandUpdater() override;
void MaybeThrottle(const std::string& id,
const base::Closure& callback) override;
- scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() override;
bool GetComponentDetails(const std::string& id,
CrxUpdateItem* item) const override;
@@ -121,8 +119,6 @@ class CrxUpdateService : public ComponentUpdateService,
// tracked. May include the IDs of un-registered components.
std::map<std::string, std::string> component_ids_by_mime_type_;
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
};
diff --git a/chromium/components/component_updater/component_updater_service_unittest.cc b/chromium/components/component_updater/component_updater_service_unittest.cc
index 7d703c4370b..2d885ca48ac 100644
--- a/chromium/components/component_updater/component_updater_service_unittest.cc
+++ b/chromium/components/component_updater/component_updater_service_unittest.cc
@@ -16,7 +16,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/histogram_tester.h"
@@ -126,10 +125,12 @@ class ComponentUpdaterTest : public testing::Test {
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::RunLoop runloop_;
- base::Closure quit_closure_;
+ const base::Closure quit_closure_ = runloop_.QuitClosure();
- scoped_refptr<TestConfigurator> config_;
- scoped_refptr<MockUpdateClient> update_client_;
+ scoped_refptr<TestConfigurator> config_ =
+ base::MakeRefCounted<TestConfigurator>();
+ scoped_refptr<MockUpdateClient> update_client_ =
+ base::MakeRefCounted<MockUpdateClient>();
std::unique_ptr<ComponentUpdateService> component_updater_;
DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterTest);
@@ -181,18 +182,10 @@ std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
return base::MakeUnique<CrxUpdateService>(config, new MockUpdateClient());
}
-ComponentUpdaterTest::ComponentUpdaterTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI) {
- quit_closure_ = runloop_.QuitClosure();
-
- config_ = new TestConfigurator(
- base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
- base::ThreadTaskRunnerHandle::Get());
-
- update_client_ = new MockUpdateClient();
+ComponentUpdaterTest::ComponentUpdaterTest() {
EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
- component_updater_.reset(new CrxUpdateService(config_, update_client_));
+ component_updater_ =
+ base::MakeUnique<CrxUpdateService>(config_, update_client_);
}
ComponentUpdaterTest::~ComponentUpdaterTest() {
@@ -305,12 +298,13 @@ TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
++cnt;
if (cnt >= max_cnt_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&LoopHandler::Quit, base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&LoopHandler::Quit, base::Unretained(this)));
}
}
private:
- void Quit() { base::MessageLoop::current()->QuitWhenIdle(); }
+ void Quit() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
const int max_cnt_;
};
diff --git a/chromium/components/component_updater/default_component_installer.cc b/chromium/components/component_updater/default_component_installer.cc
index c06c10c903b..a526212726e 100644
--- a/chromium/components/component_updater/default_component_installer.cc
+++ b/chromium/components/component_updater/default_component_installer.cc
@@ -17,6 +17,8 @@
#include "base/path_service.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "base/version.h"
@@ -62,7 +64,9 @@ void DefaultComponentInstaller::Register(
ComponentUpdateService* cus,
const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- task_runner_ = cus->GetSequencedTaskRunner();
+ task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
if (!installer_traits_) {
LOG(ERROR) << "A DefaultComponentInstaller has been created but "
diff --git a/chromium/components/component_updater/default_component_installer.h b/chromium/components/component_updater/default_component_installer.h
index 392186ed9ba..59ce39bb097 100644
--- a/chromium/components/component_updater/default_component_installer.h
+++ b/chromium/components/component_updater/default_component_installer.h
@@ -171,8 +171,7 @@ class DefaultComponentInstaller : public update_client::CrxInstaller {
std::unique_ptr<ComponentInstallerTraits> installer_traits_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- // Used to post responses back to the main thread. Initialized on the main
- // loop but accessed from the task runner.
+ // Posts responses back to the main thread.
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/component_updater/default_component_installer_unittest.cc b/chromium/components/component_updater/default_component_installer_unittest.cc
index 70780726b23..4fa8646b83c 100644
--- a/chromium/components/component_updater/default_component_installer_unittest.cc
+++ b/chromium/components/component_updater/default_component_installer_unittest.cc
@@ -167,24 +167,17 @@ class DefaultComponentInstallerTest : public testing::Test {
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_ =
base::ThreadTaskRunnerHandle::Get();
base::RunLoop runloop_;
- base::Closure quit_closure_;
+ base::Closure quit_closure_ = runloop_.QuitClosure();
- scoped_refptr<TestConfigurator> config_;
- scoped_refptr<MockUpdateClient> update_client_;
+ scoped_refptr<TestConfigurator> config_ =
+ base::MakeRefCounted<TestConfigurator>();
+ scoped_refptr<MockUpdateClient> update_client_ =
+ base::MakeRefCounted<MockUpdateClient>();
std::unique_ptr<ComponentUpdateService> component_updater_;
ComponentUnpacker::Result result_;
};
-DefaultComponentInstallerTest::DefaultComponentInstallerTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI) {
- quit_closure_ = runloop_.QuitClosure();
-
- config_ = base::MakeRefCounted<TestConfigurator>(
- base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
- base::ThreadTaskRunnerHandle::Get());
-
- update_client_ = base::MakeRefCounted<MockUpdateClient>();
+DefaultComponentInstallerTest::DefaultComponentInstallerTest() {
EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
component_updater_ =
base::MakeUnique<CrxUpdateService>(config_, update_client_);
@@ -202,7 +195,7 @@ void DefaultComponentInstallerTest::RunThreads() {
void DefaultComponentInstallerTest::Unpack(const base::FilePath& crx_path) {
auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
std::vector<uint8_t>(std::begin(kSha256Hash), std::end(kSha256Hash)),
- crx_path, nullptr, nullptr, config_->GetSequencedTaskRunner());
+ crx_path, nullptr, nullptr);
component_unpacker->Unpack(base::Bind(
&DefaultComponentInstallerTest::UnpackComplete, base::Unretained(this)));
RunThreads();
diff --git a/chromium/components/component_updater/mock_component_updater_service.h b/chromium/components/component_updater/mock_component_updater_service.h
index 7d1ad245256..3393656fc3c 100644
--- a/chromium/components/component_updater/mock_component_updater_service.h
+++ b/chromium/components/component_updater/mock_component_updater_service.h
@@ -11,6 +11,7 @@
#ifndef COMPONENTS_COMPONENT_UPDATER_MOCK_COMPONENT_UPDATER_SERVICE_H_
#define COMPONENTS_COMPONENT_UPDATER_MOCK_COMPONENT_UPDATER_SERVICE_H_
+#include <memory>
#include <string>
#include <vector>
@@ -39,6 +40,7 @@ class MockComponentUpdateService : public ComponentUpdateService {
MOCK_CONST_METHOD1(
GetComponentForMimeType,
std::unique_ptr<ComponentInfo>(const std::string& mime_type));
+ MOCK_CONST_METHOD0(GetComponents, std::vector<ComponentInfo>());
MOCK_METHOD0(GetOnDemandUpdater,
OnDemandUpdater&());
MOCK_METHOD2(MaybeThrottle,
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index d29cca930b1..37567249caf 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -215,7 +215,6 @@
<part file="translate_strings.grdp" />
<part file="undo_strings.grdp" />
<part file="version_ui_strings.grdp" />
- <part file="web_contents_delegate_android_strings.grdp" />
<!-- Generic terms -->
<message name="IDS_CANCEL" desc="Used for Cancel on buttons">
diff --git a/chromium/components/content_settings/core/browser/BUILD.gn b/chromium/components/content_settings/core/browser/BUILD.gn
index 2a1becd0f34..97df967f8df 100644
--- a/chromium/components/content_settings/core/browser/BUILD.gn
+++ b/chromium/components/content_settings/core/browser/BUILD.gn
@@ -39,6 +39,7 @@ static_library("browser") {
"cookie_settings.h",
"host_content_settings_map.cc",
"host_content_settings_map.h",
+ "user_modifiable_provider.h",
"website_settings_info.cc",
"website_settings_info.h",
"website_settings_registry.cc",
@@ -58,10 +59,6 @@ static_library("browser") {
"//url",
]
- if (!is_ios) {
- deps += [ "//media" ]
- }
-
configs += [
"//build/config/compiler:no_size_t_to_int_warning",
"//build/config/compiler:wexit_time_destructors",
diff --git a/chromium/components/content_settings/core/browser/DEPS b/chromium/components/content_settings/core/browser/DEPS
index aea66d24de1..01dbe2ae6df 100644
--- a/chromium/components/content_settings/core/browser/DEPS
+++ b/chromium/components/content_settings/core/browser/DEPS
@@ -6,7 +6,6 @@ include_rules = [
"+components/sync_preferences",
"+components/url_formatter",
"+extensions/features",
- "+media/base/media_switches.h",
"+net/base",
"+net/cookies",
"+services/preferences/public",
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 d0cb24cc4cb..8636b48b225 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
@@ -382,6 +382,14 @@ void DefaultProvider::DiscardObsoletePreferences() {
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(CONTENT_SETTINGS_TYPE_PLUGINS);
+ if (IntToContentSetting(prefs_->GetInteger(plugins_pref)) ==
+ ContentSetting::CONTENT_SETTING_ALLOW) {
+ prefs_->ClearPref(plugins_pref);
+ }
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
}
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 49c2112bd3d..8c53fe485e2 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.cc
@@ -402,9 +402,9 @@ void ContentSettingsPref::UpdatePref(
resource_dictionary->SetWithoutPathExpansion(resource_identifier,
value->CreateDeepCopy());
// Update timestamp for whole resource dictionary.
- settings_dictionary->SetStringWithoutPathExpansion(
- kLastModifiedPath,
- base::Int64ToString(last_modified.ToInternalValue()));
+ settings_dictionary->SetKey(kLastModifiedPath,
+ base::Value(base::Int64ToString(
+ last_modified.ToInternalValue())));
}
} else {
// Update settings dictionary.
@@ -416,9 +416,9 @@ void ContentSettingsPref::UpdatePref(
} else {
settings_dictionary->SetWithoutPathExpansion(kSettingPath,
value->CreateDeepCopy());
- settings_dictionary->SetStringWithoutPathExpansion(
- kLastModifiedPath,
- base::Int64ToString(last_modified.ToInternalValue()));
+ settings_dictionary->SetKey(kLastModifiedPath,
+ base::Value(base::Int64ToString(
+ last_modified.ToInternalValue())));
}
}
// Remove the settings dictionary if it is empty.
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 124ac9b840f..0518cc7cbeb 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
@@ -12,8 +12,8 @@
#include <vector>
#include "base/macros.h"
-#include "components/content_settings/core/browser/content_settings_observable_provider.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
+#include "components/content_settings/core/browser/user_modifiable_provider.h"
#include "components/prefs/pref_change_registrar.h"
class PrefService;
@@ -32,35 +32,30 @@ class ContentSettingsPref;
// Content settings provider that provides content settings from the user
// preference.
-class PrefProvider : public ObservableProvider {
+class PrefProvider : public UserModifiableProvider {
public:
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
PrefProvider(PrefService* prefs, bool incognito, bool store_last_modified);
~PrefProvider() override;
- // ProviderInterface implementations.
+ // 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,
base::Value* value) override;
-
- // Returns the |last_modified| date of a setting.
+ void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
+ void ShutdownOnUIThread() override;
base::Time GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier);
-
- void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
-
- void ShutdownOnUIThread() override;
+ const ResourceIdentifier& resource_identifier) override;
void ClearPrefs();
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 9413166bcf6..fe84151f52d 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.cc
@@ -317,6 +317,24 @@ void ContentSettingsRegistry::Init() {
WebsiteSettingsRegistry::DESKTOP |
WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
+
+ Register(CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS, "accessibility-events",
+ CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
+ WhitelistedSchemes(),
+ ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
+ CONTENT_SETTING_ASK),
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
+ WebsiteSettingsRegistry::DESKTOP |
+ WebsiteSettingsRegistry::PLATFORM_ANDROID,
+ ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
+
+ Register(CONTENT_SETTINGS_TYPE_SENSORS, "sensors", CONTENT_SETTING_ALLOW,
+ WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ WebsiteSettingsRegistry::DESKTOP |
+ WebsiteSettingsRegistry::PLATFORM_ANDROID,
+ ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
}
void ContentSettingsRegistry::Register(
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 2efa8f774ed..991543e4c6f 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.cc
@@ -69,9 +69,7 @@ std::string ContentSettingToString(ContentSetting setting) {
bool ContentSettingFromString(const std::string& name,
ContentSetting* setting) {
- // We are starting the index from 1, as |CONTENT_SETTING_DEFAULT| is not
- // a recognized content setting.
- for (size_t i = 1; i < arraysize(kContentSettingsStringMapping); ++i) {
+ for (size_t i = 0; i < arraysize(kContentSettingsStringMapping); ++i) {
if (name == kContentSettingsStringMapping[i].content_setting_str) {
*setting = kContentSettingsStringMapping[i].content_setting;
return true;
@@ -142,6 +140,9 @@ void GetRendererContentSettingRules(const HostContentSettingsMap* map,
CONTENT_SETTINGS_TYPE_AUTOPLAY,
ResourceIdentifier(),
&(rules->autoplay_rules));
+ map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
+ ResourceIdentifier(),
+ &(rules->client_hints_rules));
}
bool IsMorePermissive(ContentSetting a, ContentSetting b) {
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_utils_unittest.cc
index f38264b8b9a..8860b2b7af4 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils_unittest.cc
@@ -74,13 +74,8 @@ TEST(ContentSettingsUtilsTest, ContentSettingsStringMap) {
EXPECT_EQ(kContentSettingNames[i], setting_string);
ContentSetting converted_setting;
- if (i == 0) {
- EXPECT_FALSE(ContentSettingFromString(
- kContentSettingNames[i], &converted_setting));
- } else {
- EXPECT_TRUE(ContentSettingFromString(
- kContentSettingNames[i], &converted_setting));
- }
+ EXPECT_TRUE(
+ ContentSettingFromString(kContentSettingNames[i], &converted_setting));
EXPECT_EQ(setting, converted_setting);
}
}
@@ -138,4 +133,4 @@ TEST(ContentSettingsUtilsTest, IsMorePermissive) {
}
}
-} // namespace content_settings \ No newline at end of file
+} // namespace content_settings
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 19483f291ca..a0d868c3335 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
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <algorithm>
#include <utility>
#include "base/command_line.h"
@@ -28,6 +29,7 @@
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_rule.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/browser/website_settings_registry.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_utils.h"
@@ -60,6 +62,8 @@ const ProviderNamesSourceMapEntry kProviderNamesSourceMap[] = {
{"notification_android", content_settings::SETTING_SOURCE_USER},
{"preference", content_settings::SETTING_SOURCE_USER},
{"default", content_settings::SETTING_SOURCE_USER},
+ {"tests", content_settings::SETTING_SOURCE_USER},
+ {"tests_other", content_settings::SETTING_SOURCE_USER},
};
// Enum describing the status of domain to origin migration of content settings.
@@ -202,6 +206,7 @@ HostContentSettingsMap::HostContentSettingsMap(PrefService* prefs,
pref_provider_ = new content_settings::PrefProvider(prefs_, is_incognito_,
store_last_modified_);
content_settings_providers_[PREF_PROVIDER] = base::WrapUnique(pref_provider_);
+ user_modifiable_providers_.push_back(pref_provider_);
pref_provider_->AddObserver(this);
// This ensures that content settings are cleared for the guest profile. This
@@ -235,6 +240,13 @@ void HostContentSettingsMap::RegisterProfilePrefs(
content_settings::PolicyProvider::RegisterProfilePrefs(registry);
}
+void HostContentSettingsMap::RegisterUserModifiableProvider(
+ ProviderType type,
+ std::unique_ptr<content_settings::UserModifiableProvider> provider) {
+ user_modifiable_providers_.push_back(provider.get());
+ RegisterProvider(type, std::move(provider));
+}
+
void HostContentSettingsMap::RegisterProvider(
ProviderType type,
std::unique_ptr<content_settings::ObservableProvider> provider) {
@@ -669,8 +681,13 @@ base::Time HostContentSettingsMap::GetSettingLastModifiedDate(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) const {
- return pref_provider_->GetWebsiteSettingLastModified(
- primary_pattern, secondary_pattern, content_type, std::string());
+ base::Time most_recent_time;
+ for (auto* provider : user_modifiable_providers_) {
+ base::Time time = provider->GetWebsiteSettingLastModified(
+ primary_pattern, secondary_pattern, content_type, std::string());
+ most_recent_time = std::max(time, most_recent_time);
+ }
+ return most_recent_time;
}
void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
@@ -688,13 +705,15 @@ void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
if (pattern_predicate.is_null() ||
pattern_predicate.Run(setting.primary_pattern,
setting.secondary_pattern)) {
- base::Time last_modified = pref_provider_->GetWebsiteSettingLastModified(
- setting.primary_pattern, setting.secondary_pattern, content_type,
- std::string());
- if (last_modified >= begin_time) {
- pref_provider_->SetWebsiteSetting(setting.primary_pattern,
- setting.secondary_pattern,
- content_type, std::string(), nullptr);
+ for (auto* provider : user_modifiable_providers_) {
+ base::Time last_modified = provider->GetWebsiteSettingLastModified(
+ setting.primary_pattern, setting.secondary_pattern, content_type,
+ std::string());
+ if (last_modified >= begin_time) {
+ provider->SetWebsiteSetting(setting.primary_pattern,
+ setting.secondary_pattern, content_type,
+ std::string(), nullptr);
+ }
}
}
}
@@ -738,22 +757,9 @@ void HostContentSettingsMap::AddSettingsForOneType(
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
- std::unique_ptr<base::Value> setting_value;
- // TODO(bauerb): Return rules as a list of values, not content settings.
- // Handle the case using base::Values for its exceptions and default
- // setting. Here we assume all the exceptions are granted as
- // |CONTENT_SETTING_ALLOW|.
- if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
- content_type) &&
- rule.value.get() &&
- rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
- setting_value =
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW);
- } else {
- setting_value = base::MakeUnique<base::Value>(*(rule.value));
- }
settings->push_back(ContentSettingPatternSource(
- rule.primary_pattern, rule.secondary_pattern, std::move(setting_value),
+ rule.primary_pattern, rule.secondary_pattern,
+ base::MakeUnique<base::Value>(rule.value->Clone()),
kProviderNamesSourceMap[provider_type].provider_name, incognito));
}
}
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 b9f4bfb3689..5de5b0ef056 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
@@ -20,6 +20,7 @@
#include "base/threading/thread_checker.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_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
@@ -60,6 +61,11 @@ class HostContentSettingsMap : public content_settings::Observer,
NOTIFICATION_ANDROID_PROVIDER,
PREF_PROVIDER,
DEFAULT_PROVIDER,
+
+ // The following providers are for tests only.
+ PROVIDER_FOR_TESTS,
+ OTHER_PROVIDER_FOR_TESTS,
+
NUM_PROVIDER_TYPES
};
@@ -73,6 +79,16 @@ class HostContentSettingsMap : public content_settings::Observer,
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+ // Adds a new provider for |type|. This should be used instead of
+ // |RegisterProvider|, not in addition.
+ //
+ // Providers added via this method will be queried when
+ // |GetSettingLastModifiedDate| is called and their settings may be cleared by
+ // |ClearSettingsForOneTypeWithPredicate| if they were recently modified.
+ void RegisterUserModifiableProvider(
+ ProviderType type,
+ std::unique_ptr<content_settings::UserModifiableProvider> provider);
+
// Adds a new provider for |type|.
void RegisterProvider(
ProviderType type,
@@ -285,6 +301,11 @@ class HostContentSettingsMap : public content_settings::Observer,
// |last_modified| timestamp.
void SetClockForTesting(std::unique_ptr<base::Clock> clock);
+ // Returns the provider that contains content settings from user preferences.
+ content_settings::PrefProvider* GetPrefProvider() const {
+ return pref_provider_;
+ }
+
private:
friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
@@ -386,6 +407,12 @@ class HostContentSettingsMap : public content_settings::Observer,
std::map<ProviderType, std::unique_ptr<content_settings::ProviderInterface>>
content_settings_providers_;
+ // List of content settings providers containing settings which can be
+ // modified by the user. Members are owned by the
+ // |content_settings_providers_| map above.
+ std::vector<content_settings::UserModifiableProvider*>
+ user_modifiable_providers_;
+
// content_settings_providers_[PREF_PROVIDER] but specialized.
content_settings::PrefProvider* pref_provider_ = nullptr;
diff --git a/chromium/components/content_settings/core/browser/user_modifiable_provider.h b/chromium/components/content_settings/core/browser/user_modifiable_provider.h
new file mode 100644
index 00000000000..900778d318a
--- /dev/null
+++ b/chromium/components/content_settings/core/browser/user_modifiable_provider.h
@@ -0,0 +1,30 @@
+// 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_CONTENT_SETTINGS_CORE_BROWSER_USER_MODIFIABLE_PROVIDER_H_
+#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_USER_MODIFIABLE_PROVIDER_H_
+
+#include "components/content_settings/core/browser/content_settings_observable_provider.h"
+#include "components/content_settings/core/common/content_settings.h"
+
+class ContentSettingsPattern;
+
+namespace content_settings {
+
+// Content settings provider that provides settings which may be modified by the
+// user.
+class UserModifiableProvider : public ObservableProvider {
+ public:
+ ~UserModifiableProvider() override {}
+ // Returns the timestamp that a particular setting was last modified.
+ virtual base::Time GetWebsiteSettingLastModified(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type,
+ const ResourceIdentifier& resource_identifier) = 0;
+};
+
+} // namespace content_settings
+
+#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_USER_MODIFIABLE_PROVIDER_H_
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 b04fff48149..7d62b4d1d53 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.cc
@@ -8,13 +8,8 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings.h"
-#if !defined(OS_IOS)
-#include "media/base/media_switches.h"
-#endif // !defined(OS_IOS)
-
namespace {
base::LazyInstance<content_settings::WebsiteSettingsRegistry>::DestructorAtExit
@@ -178,15 +173,16 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
-#if !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(media::kRecordMediaEngagementScores)) {
- Register(CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, "media-engagement",
- nullptr, WebsiteSettingsInfo::SYNCABLE, WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
- DESKTOP | PLATFORM_ANDROID,
- WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- }
-#endif //! defined(OS_IOS)
+ Register(CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, "media-engagement", nullptr,
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ DESKTOP | PLATFORM_ANDROID,
+ WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, "client-hints", nullptr,
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ DESKTOP | PLATFORM_ANDROID,
+ WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/content_settings.cc b/chromium/components/content_settings/core/common/content_settings.cc
index 4b32cb96c3e..de1df5442a3 100644
--- a/chromium/components/content_settings/core/common/content_settings.cc
+++ b/chromium/components/content_settings/core/common/content_settings.cc
@@ -20,7 +20,7 @@ struct HistogramValue {
};
// WARNING: The value specified here for a type should match exactly the value
-// specified in the ContentType enum in histograms.xml. Since these values are
+// specified in the ContentType enum in enums.xml. Since these values are
// used for histograms, please do not reuse the same value for a different
// content setting. Always append to the end and increment.
//
@@ -28,7 +28,7 @@ struct HistogramValue {
// content settings type name instead.
//
// The array size must be explicit for the static_asserts below.
-constexpr size_t kNumHistogramValues = 30;
+constexpr size_t kNumHistogramValues = 33;
constexpr HistogramValue kHistogramValue[kNumHistogramValues] = {
{CONTENT_SETTINGS_TYPE_COOKIES, 0},
{CONTENT_SETTINGS_TYPE_IMAGES, 1},
@@ -60,6 +60,9 @@ constexpr HistogramValue kHistogramValue[kNumHistogramValues] = {
{CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, 34},
{CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, 35},
{CONTENT_SETTINGS_TYPE_SOUND, 36},
+ {CONTENT_SETTINGS_TYPE_CLIENT_HINTS, 37},
+ {CONTENT_SETTINGS_TYPE_SENSORS, 38},
+ {CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS, 39},
};
} // namespace
@@ -119,7 +122,7 @@ ContentSettingPatternSource& ContentSettingPatternSource::operator=(
primary_pattern = other.primary_pattern;
secondary_pattern = other.secondary_pattern;
if (other.setting_value)
- setting_value = base::MakeUnique<base::Value>(*(other.setting_value));
+ setting_value = base::MakeUnique<base::Value>(other.setting_value->Clone());
source = other.source;
incognito = other.incognito;
return *this;
diff --git a/chromium/components/content_settings/core/common/content_settings.h b/chromium/components/content_settings/core/common/content_settings.h
index e28e51eed34..8fa4e4bef9b 100644
--- a/chromium/components/content_settings/core/common/content_settings.h
+++ b/chromium/components/content_settings/core/common/content_settings.h
@@ -71,6 +71,7 @@ struct RendererContentSettingRules {
ContentSettingsForOneType image_rules;
ContentSettingsForOneType script_rules;
ContentSettingsForOneType autoplay_rules;
+ ContentSettingsForOneType client_hints_rules;
};
namespace content_settings {
diff --git a/chromium/components/content_settings/core/common/content_settings.mojom b/chromium/components/content_settings/core/common/content_settings.mojom
index 3669aec081a..6766c161ab2 100644
--- a/chromium/components/content_settings/core/common/content_settings.mojom
+++ b/chromium/components/content_settings/core/common/content_settings.mojom
@@ -71,4 +71,5 @@ struct RendererContentSettingRules {
array<ContentSettingPatternSource> image_rules;
array<ContentSettingPatternSource> script_rules;
array<ContentSettingPatternSource> autoplay_rules;
+ array<ContentSettingPatternSource> client_hints_rules;
};
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern.cc b/chromium/components/content_settings/core/common/content_settings_pattern.cc
index e88351a5d0b..fed851c4b53 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern.cc
@@ -19,18 +19,17 @@
namespace {
-// The component supports only one scheme for simplicity.
-const char* non_port_non_domain_wildcard_scheme = NULL;
+// Array of non domain wildcard and non-port scheme names, and their count.
+const char* const* g_non_domain_wildcard_non_port_schemes = nullptr;
+size_t g_non_domain_wildcard_non_port_schemes_count = 0;
// Keep it consistent with enum SchemeType in content_settings_pattern.h.
-const char* const kSchemeNames[] = {
- "wildcard",
- "other",
- url::kHttpScheme,
- url::kHttpsScheme,
- url::kFileScheme,
- "chrome-extension",
-};
+// TODO(msramek): Layering violation: assemble this array from hardcoded
+// schemes and those injected via |SetNonWildcardDomainNonPortSchemes()|.
+const char* const kSchemeNames[] = {"wildcard", "other",
+ url::kHttpScheme, url::kHttpsScheme,
+ url::kFileScheme, "chrome-extension",
+ "chrome-search"};
static_assert(arraysize(kSchemeNames) == ContentSettingsPattern::SCHEME_MAX,
"kSchemeNames should have SCHEME_MAX elements");
@@ -264,7 +263,8 @@ bool ContentSettingsPattern::Builder::Validate(const PatternParts& parts) {
parts.path.find("*") == std::string::npos);
}
- // If the pattern is for an extension URL test if it is valid.
+ // If the pattern is for a URL with a non-wildcard domain without a port,
+ // test if it is valid.
if (IsNonWildcardDomainNonPortScheme(parts.scheme) &&
parts.port.empty() &&
!parts.is_port_wildcard) {
@@ -454,19 +454,32 @@ bool ContentSettingsPattern::MigrateFromDomainToOrigin(
}
// static
-void ContentSettingsPattern::SetNonWildcardDomainNonPortScheme(
- const char* scheme) {
- DCHECK(scheme);
- DCHECK(!non_port_non_domain_wildcard_scheme ||
- non_port_non_domain_wildcard_scheme == scheme);
- non_port_non_domain_wildcard_scheme = scheme;
+void ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
+ const char* const* schemes,
+ size_t count) {
+ DCHECK(schemes || count == 0);
+ if (g_non_domain_wildcard_non_port_schemes) {
+ DCHECK_EQ(g_non_domain_wildcard_non_port_schemes_count, count);
+ for (size_t i = 0; i < count; ++i) {
+ DCHECK_EQ(g_non_domain_wildcard_non_port_schemes[i], schemes[i]);
+ }
+ }
+
+ g_non_domain_wildcard_non_port_schemes = schemes;
+ g_non_domain_wildcard_non_port_schemes_count = count;
}
// static
bool ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(
const std::string& scheme) {
- DCHECK(non_port_non_domain_wildcard_scheme);
- return scheme == non_port_non_domain_wildcard_scheme;
+ DCHECK(g_non_domain_wildcard_non_port_schemes ||
+ g_non_domain_wildcard_non_port_schemes_count == 0);
+ for (size_t i = 0; i < g_non_domain_wildcard_non_port_schemes_count; ++i) {
+ if (g_non_domain_wildcard_non_port_schemes[i] == scheme) {
+ return true;
+ }
+ }
+ return false;
}
ContentSettingsPattern::ContentSettingsPattern()
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern.h b/chromium/components/content_settings/core/common/content_settings_pattern.h
index fe292d53d47..6a55d3b723d 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern.h
+++ b/chromium/components/content_settings/core/common/content_settings_pattern.h
@@ -60,8 +60,10 @@ class ContentSettingsPattern {
};
// This enum is used to back an UMA histogram, the order of existing values
- // should not be changed. New values should only append before SCHEME_MAX.
- // Also keep it consistent with kSchemeNames in content_settings_pattern.cc.
+ // should not be changed.
+ // New values should only be appended before SCHEME_MAX.
+ // Also keep it consistent with kSchemeNames in content_settings_pattern.cc,
+ // and the ContentSettingScheme enum in histograms/enums.xml.
enum SchemeType {
SCHEME_WILDCARD,
SCHEME_OTHER,
@@ -69,6 +71,7 @@ class ContentSettingsPattern {
SCHEME_HTTPS,
SCHEME_FILE,
SCHEME_CHROMEEXTENSION,
+ SCHEME_CHROMESEARCH,
SCHEME_MAX,
};
@@ -88,7 +91,7 @@ class ContentSettingsPattern {
// - IPv4 or IPv6
// - hostname
// - domain
- // - empty string if the |is_host_wildcard flag is set.
+ // - empty string if the |is_host_wildcard| flag is set.
std::string host;
// True if the domain wildcard is set.
@@ -172,13 +175,18 @@ class ContentSettingsPattern {
const ContentSettingsPattern& domain_pattern,
ContentSettingsPattern* origin_pattern);
- // Sets the scheme that doesn't support domain wildcard and port.
+ // Sets schemes that do not support domain wildcards and ports.
// Needs to be called by the embedder before using ContentSettingsPattern.
- // |scheme| can't be NULL, and the pointed string must remain alive until the
- // app terminates.
- static void SetNonWildcardDomainNonPortScheme(const char* scheme);
-
- // Compares |scheme| against the scheme set by the embedder.
+ // |schemes| can't be NULL, and the pointed to strings must remain alive
+ // until the app terminates.
+ // The method should only be called once. If called again, the parameters
+ // must have values equal to the parameter values of the first call.
+ // The |count| parameter represents the number of strings that
+ // |schemes| points to.
+ static void SetNonWildcardDomainNonPortSchemes(const char* const* schemes,
+ size_t count);
+
+ // Compares |scheme| against the schemes set by the embedder.
static bool IsNonWildcardDomainNonPortScheme(const std::string& scheme);
// Constructs an empty pattern. Empty patterns are invalid patterns. Invalid
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern_parser.cc b/chromium/components/content_settings/core/common/content_settings_pattern_parser.cc
index 723c9eb7835..0e0f2c574f0 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern_parser.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern_parser.cc
@@ -131,9 +131,19 @@ void PatternParser::Parse(const std::string& pattern_spec,
std::string host = pattern_spec.substr(host_component.start,
host_component.len);
if (host == kHostWildcard) {
+ if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) {
+ builder->Invalid();
+ return;
+ }
+
builder->WithDomainWildcard();
} else if (base::StartsWith(host, kDomainWildcard,
base::CompareCase::SENSITIVE)) {
+ if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) {
+ builder->Invalid();
+ return;
+ }
+
host = host.substr(kDomainWildcardLength);
builder->WithDomainWildcard();
builder->WithHost(host);
@@ -148,6 +158,11 @@ void PatternParser::Parse(const std::string& pattern_spec,
}
if (port_component.IsNonEmpty()) {
+ if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) {
+ builder->Invalid();
+ return;
+ }
+
const std::string port = pattern_spec.substr(port_component.start,
port_component.len);
if (port == kPortWildcard) {
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc b/chromium/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc
index b35b7000752..4587a06131c 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc
@@ -208,6 +208,114 @@ TEST(ContentSettingsPatternParserTest, ParseFilePatterns) {
::testing::Mock::VerifyAndClear(&builder);
}
+TEST(ContentSettingsPatternParserTest, ParseChromePatterns) {
+ // The schemes chrome-extension:// and chrome-search:// are valid,
+ // and chrome-not-search:// is not, because the former two are registered
+ // as non-domain wildcard non-port schemes in components_test_suite.cc,
+ // and the last one isn't.
+ ::testing::StrictMock<MockBuilder> builder;
+
+ // Valid chrome-extension:// URL.
+ EXPECT_CALL(builder, WithScheme("chrome-extension"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithHost("peoadpeiejnhkmpaakpnompolbglelel"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithPath("/"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+
+ // Valid chrome-search:// URL.
+ EXPECT_CALL(builder, WithScheme("chrome-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithHost("local-ntp"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithPath("/local-ntp.html"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-search://local-ntp/local-ntp.html", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+
+ // Not a non-domain wildcard non-port scheme implies a port is parsed.
+ EXPECT_CALL(builder, WithScheme("chrome-not-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithHost("local-ntp"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithPath("/local-ntp.html"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithPortWildcard())
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-not-search://local-ntp/local-ntp.html", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+}
+
+TEST(ContentSettingsPatternParserTest,
+ ParseInvalidNonDomainWildcardNonPortPatterns) {
+ ::testing::StrictMock<MockBuilder> builder;
+
+ // Domain wildcard for scheme without domain wildcards.
+ EXPECT_CALL(builder, WithScheme("chrome-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, Invalid())
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse("chrome-search://*/local-ntp.html",
+ &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+
+ // Domain wildcard for scheme without domain wildcards.
+ EXPECT_CALL(builder, WithScheme("chrome-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, Invalid())
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-search://*local-ntp/local-ntp.html", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+
+ // Port for scheme without ports.
+ EXPECT_CALL(builder, WithScheme("chrome-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithHost("local-ntp"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, Invalid())
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-search://local-ntp:65535/local-ntp.html", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+
+ // Port wildcard for scheme without ports.
+ EXPECT_CALL(builder, WithScheme("chrome-search"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, WithHost("local-ntp"))
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ EXPECT_CALL(builder, Invalid())
+ .Times(1)
+ .WillOnce(::testing::Return(&builder));
+ content_settings::PatternParser::Parse(
+ "chrome-search://local-ntp:*/local-ntp.html", &builder);
+ ::testing::Mock::VerifyAndClear(&builder);
+}
+
TEST(ContentSettingsPatternParserTest, SerializePatterns) {
ContentSettingsPattern::PatternParts parts;
parts.scheme = "http";
@@ -227,4 +335,16 @@ TEST(ContentSettingsPatternParserTest, SerializePatterns) {
parts.path = "";
parts.is_path_wildcard = true;
EXPECT_EQ("file:///*", content_settings::PatternParser::ToString(parts));
+
+ parts = ContentSettingsPattern::PatternParts();
+ parts.scheme = "chrome-search";
+ parts.host = "local-ntp";
+ EXPECT_EQ("chrome-search://local-ntp/",
+ content_settings::PatternParser::ToString(parts));
+
+ parts = ContentSettingsPattern::PatternParts();
+ parts.scheme = "chrome-extension";
+ parts.host = "peoadpeiejnhkmpaakpnompolbglelel";
+ EXPECT_EQ("chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/",
+ content_settings::PatternParser::ToString(parts));
}
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc b/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
index 0a3938488c8..90fe5974166 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -327,6 +327,14 @@ TEST(ContentSettingsPatternTest, FromString_ExtensionPatterns) {
.Matches(GURL("chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/")));
}
+TEST(ContentSettingsPatternTest, FromString_SearchPatterns) {
+ EXPECT_TRUE(Pattern("chrome-search://local-ntp/").IsValid());
+ EXPECT_EQ("chrome-search://local-ntp/",
+ Pattern("chrome-search://local-ntp/").ToString());
+ EXPECT_TRUE(Pattern("chrome-search://local-ntp/")
+ .Matches(GURL("chrome-search://local-ntp/")));
+}
+
TEST(ContentSettingsPatternTest, FromString_WithIPAdresses) {
// IPv4
EXPECT_TRUE(Pattern("192.168.0.1").IsValid());
@@ -799,6 +807,9 @@ TEST(ContentSettingsPatternTest, MigrateFromDomainToOrigin) {
ContentSettingsPattern::FromString(
"chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/"),
&origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("chrome-search://local-ntp/"),
+ &origin_pattern));
// These are pattern styles which might be generated using FromURL().
EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
@@ -831,6 +842,8 @@ TEST(ContentSettingsPatternTest, Schemes) {
EXPECT_EQ(ContentSettingsPattern::SCHEME_CHROMEEXTENSION,
Pattern("chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/")
.GetScheme());
+ EXPECT_EQ(ContentSettingsPattern::SCHEME_CHROMESEARCH,
+ Pattern("chrome-search://local-ntp/").GetScheme());
EXPECT_EQ(ContentSettingsPattern::SCHEME_WILDCARD,
Pattern("192.168.0.1").GetScheme());
EXPECT_EQ(ContentSettingsPattern::SCHEME_WILDCARD,
diff --git a/chromium/components/content_settings/core/common/content_settings_struct_traits.cc b/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
index b5bac4a40d9..f3426ddeea0 100644
--- a/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
+++ b/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
@@ -99,7 +99,8 @@ bool StructTraits<content_settings::mojom::RendererContentSettingRulesDataView,
RendererContentSettingRules* out) {
return data.ReadImageRules(&out->image_rules) &&
data.ReadScriptRules(&out->script_rules) &&
- data.ReadAutoplayRules(&out->autoplay_rules);
+ data.ReadAutoplayRules(&out->autoplay_rules) &&
+ data.ReadClientHintsRules(&out->client_hints_rules);
}
} // namespace mojo
diff --git a/chromium/components/content_settings/core/common/content_settings_struct_traits.h b/chromium/components/content_settings/core/common/content_settings_struct_traits.h
index ab3fee43862..f36bdde91be 100644
--- a/chromium/components/content_settings/core/common/content_settings_struct_traits.h
+++ b/chromium/components/content_settings/core/common/content_settings_struct_traits.h
@@ -136,6 +136,11 @@ struct StructTraits<
return r.autoplay_rules;
}
+ static const std::vector<ContentSettingPatternSource>& client_hints_rules(
+ const RendererContentSettingRules& r) {
+ return r.client_hints_rules;
+ }
+
static bool Read(
content_settings::mojom::RendererContentSettingRulesDataView data,
RendererContentSettingRules* out);
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 e752e9e96e4..6781f841198 100644
--- a/chromium/components/content_settings/core/common/content_settings_types.h
+++ b/chromium/components/content_settings/core/common/content_settings_types.h
@@ -71,10 +71,34 @@ enum ContentSettingsType {
// specific origin.
CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT,
- // Website setting which stores whether or not the site can play audible
+ // Content setting which stores whether or not the site can play audible
// sound. This will not block playback but instead the user will not hear it.
CONTENT_SETTINGS_TYPE_SOUND,
+ // Website setting which stores the list of client hints (and the preference
+ // expiration time for each of the client hints) that the origin requested
+ // the browser to remember. Spec:
+ // http://httpwg.org/http-extensions/client-hints.html#accept-ch-lifetime.
+ // The setting is stored as a dictionary that includes the mapping from
+ // different client hints to their respective expiration times (seconds since
+ // epoch). The browser is expected to send all the unexpired client hints in
+ // the HTTP request headers for every resource requested from that origin.
+ CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
+
+ // Generic Sensor API covering ambient-light-sensor, accelerometer, gyroscope
+ // and magnetometer are all mapped to a single content_settings_type.
+ // Setting for the Generic Sensor API covering ambient-light-sensor,
+ // accelerometer, gyroscope and magnetometer. These are all mapped to a single
+ // ContentSettingsType.
+ CONTENT_SETTINGS_TYPE_SENSORS,
+
+ // Content setting which stores whether or not the user has granted the site
+ // permission to respond to accessibility events, which can be used to
+ // provide a custom accessibility experience. Requires explicit user consent
+ // because some users may not want sites to know they're using assistive
+ // technology.
+ CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS,
+
CONTENT_SETTINGS_NUM_TYPES,
};
diff --git a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
index c2cd286f561..a2b5c19c40a 100644
--- a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
+++ b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
@@ -18,26 +18,27 @@
namespace contextual_search {
OverlayJsRenderFrameObserver::OverlayJsRenderFrameObserver(
- content::RenderFrame* render_frame)
+ content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry)
: RenderFrameObserver(render_frame),
is_contextual_search_overlay_(false),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ registry->AddInterface(base::Bind(
+ &OverlayJsRenderFrameObserver::CreateOverlayPageNotifierService,
+ weak_factory_.GetWeakPtr()));
+}
OverlayJsRenderFrameObserver::~OverlayJsRenderFrameObserver() {}
void OverlayJsRenderFrameObserver::DidStartProvisionalLoad(
- blink::WebDataSource* data_source) {
- RegisterMojoInterface();
-}
-
-void OverlayJsRenderFrameObserver::RegisterMojoInterface() {
- render_frame()->GetInterfaceRegistry()->AddInterface(base::Bind(
- &OverlayJsRenderFrameObserver::CreateOverlayPageNotifierService,
- weak_factory_.GetWeakPtr()));
+ blink::WebDocumentLoader* document_loader) {
+ can_bind_requests_ = true;
}
void OverlayJsRenderFrameObserver::CreateOverlayPageNotifierService(
mojom::OverlayPageNotifierServiceRequest request) {
+ if (!can_bind_requests_)
+ return;
mojo::MakeStrongBinding(
base::MakeUnique<OverlayPageNotifierServiceImpl>(
weak_factory_.GetWeakPtr()),
@@ -62,11 +63,7 @@ void OverlayJsRenderFrameObserver::DidFinishLoad() {
}
void OverlayJsRenderFrameObserver::DestroyOverlayPageNotifierService() {
- if (render_frame()) {
- render_frame()
- ->GetInterfaceRegistry()
- ->RemoveInterface<mojom::OverlayPageNotifierService>();
- }
+ can_bind_requests_ = false;
}
void OverlayJsRenderFrameObserver::OnDestruct() {
diff --git a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
index 2bdc547406d..f55275af341 100644
--- a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
+++ b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
@@ -10,6 +10,7 @@
#include "components/contextual_search/common/overlay_page_notifier_service.mojom.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "v8/include/v8.h"
@@ -21,11 +22,13 @@ namespace contextual_search {
// in an overlay panel.
class OverlayJsRenderFrameObserver : public content::RenderFrameObserver {
public:
- explicit OverlayJsRenderFrameObserver(content::RenderFrame* render_frame);
+ OverlayJsRenderFrameObserver(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry);
~OverlayJsRenderFrameObserver() override;
// RenderFrameObserver implementation.
- void DidStartProvisionalLoad(blink::WebDataSource* data_source) override;
+ void DidStartProvisionalLoad(
+ blink::WebDocumentLoader* document_loader) override;
void DidClearWindowObject() override;
void DidFinishLoad() override;
@@ -36,9 +39,6 @@ class OverlayJsRenderFrameObserver : public content::RenderFrameObserver {
// RenderFrameObserver implementation.
void OnDestruct() override;
- // Add the mojo interface to a RenderFrame's
- // service_manager::InterfaceRegistry.
- void RegisterMojoInterface();
// Creates the OverlayPageNotifierService connecting the browser to this
// observer.
void CreateOverlayPageNotifierService(
@@ -49,6 +49,10 @@ class OverlayJsRenderFrameObserver : public content::RenderFrameObserver {
// Track if the current page is presented in the contextual search overlay.
bool is_contextual_search_overlay_;
+ // Requests for mojom::OverlayPageNotifierService are only bound while
+ // a load is active.
+ bool can_bind_requests_ = false;
+
base::WeakPtrFactory<OverlayJsRenderFrameObserver> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(OverlayJsRenderFrameObserver);
diff --git a/chromium/components/crash/content/app/BUILD.gn b/chromium/components/crash/content/app/BUILD.gn
index 308a8b5e442..5b68bc7926a 100644
--- a/chromium/components/crash/content/app/BUILD.gn
+++ b/chromium/components/crash/content/app/BUILD.gn
@@ -7,7 +7,7 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-static_library("lib") {
+source_set("lib") {
sources = [
"crash_keys_win.cc",
"crash_keys_win.h",
@@ -28,6 +28,7 @@ static_library("lib") {
static_library("app") {
sources = [
+ "crash_export_thunks.h",
"crash_switches.cc",
"crash_switches.h",
"crashpad.h",
@@ -77,12 +78,74 @@ if (is_win) {
deps = [
"//base",
- "//chrome/install_static:install_static_util",
+ "//components/browser_watcher:crash_stability",
"//third_party/crashpad/crashpad/client",
"//third_party/crashpad/crashpad/handler:handler_lib",
"//third_party/crashpad/crashpad/minidump",
]
}
+
+ # This source set contains the include file that declares the export thunks.
+ # Any target that gets compiled into both test and release code needs to
+ # depend on this for the include alone. The binary it's linked into then needs
+ # to depend on either :crash_export_thunks or :test_support, or in the case of
+ # release binaries, on //chrome_elf, which re-exports the thunks.
+ source_set("crash_export_thunk_include") {
+ sources = [
+ "crash_export_thunks.h",
+ ]
+ }
+
+ # This source set contains a set of functions that allow using the crashpad
+ # handler across a module boundary. The intent is for these functions to be
+ # built into a dynamic library, which the user of the crashpad handler then
+ # has a link-time dependency on. This will result in an import dependency
+ # from the user to the dynamic library that will be bound at load time.
+ # In a single-module project, this source set can alternatively be included in
+ # the sole module, in which case the implementation will be bound at link
+ # time.
+ source_set("crash_export_thunks") {
+ sources = [
+ "crash_export_thunks.cc",
+ "crash_export_thunks.h",
+ ]
+
+ deps = [
+ ":app",
+ "//base",
+ "//third_party/crashpad/crashpad/client",
+ ]
+ }
+
+ # This source set contains a set of test stubs for the functions above.
+ # time.
+ source_set("crash_export_stubs") {
+ testonly = true
+
+ sources = [
+ "crash_export_stubs.cc",
+ "crash_export_thunks.h",
+ ]
+
+ deps = [
+ ":app",
+ "//base",
+ ]
+ }
+}
+
+# This source set provides the functionality required for tests, which on Windows
+# link the export thunks directly into the test binary.
+source_set("test_support") {
+ testonly = true
+
+ deps = [
+ ":lib",
+ ]
+
+ if (is_win) {
+ deps += [ ":crash_export_stubs" ]
+ }
}
# TODO(mark): https://crbug.com/466890: merge this target with
diff --git a/chromium/components/crash/content/app/DEPS b/chromium/components/crash/content/app/DEPS
index dc5e932073f..9f77331a15a 100644
--- a/chromium/components/crash/content/app/DEPS
+++ b/chromium/components/crash/content/app/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+sandbox",
+ "+components/browser_watcher/stability_report_user_stream_data_source.h",
"+content/public/common/content_descriptors.h",
"+content/public/common/result_codes.h",
"+third_party/crashpad",
diff --git a/chromium/components/crash/content/app/crash_export_stubs.cc b/chromium/components/crash/content/app/crash_export_stubs.cc
new file mode 100644
index 00000000000..6babd352b70
--- /dev/null
+++ b/chromium/components/crash/content/app/crash_export_stubs.cc
@@ -0,0 +1,52 @@
+// 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.
+//
+// This file has no-op stub implementation for the functions declared in
+// crash_export_thunks.h. This is solely for linking into tests, where
+// crash reporting is unwanted and never initialized.
+
+#include <windows.h>
+
+#include "build/build_config.h"
+#include "components/crash/content/app/crash_export_thunks.h"
+#include "components/crash/content/app/crashpad.h"
+
+void RequestSingleCrashUploadThunk(const char* local_id) {}
+
+size_t GetCrashReportsImpl(crash_reporter::Report* reports,
+ size_t reports_size) {
+ return 0;
+}
+
+int CrashForException(EXCEPTION_POINTERS* info) {
+ // Make sure to properly crash the process by dispatching directly to the
+ // Windows unhandled exception filter.
+ return UnhandledExceptionFilter(info);
+}
+
+void SetUploadConsentImpl(bool consent) {}
+
+void SetCrashKeyValueImpl(const wchar_t* key, const wchar_t* value) {}
+
+void ClearCrashKeyValueImpl(const wchar_t* key) {}
+
+void SetCrashKeyValueImplEx(const char* key, const char* value) {}
+
+void ClearCrashKeyValueImplEx(const char* key) {}
+
+HANDLE InjectDumpForHungInput(HANDLE process, void* serialized_crash_keys) {
+ return nullptr;
+}
+
+HANDLE InjectDumpForHungInputNoCrashKeys(HANDLE process, int reason) {
+ return nullptr;
+}
+
+#if defined(ARCH_CPU_X86_64)
+
+void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {}
+
+void UnregisterNonABICompliantCodeRange(void* start) {}
+
+#endif // defined(ARCH_CPU_X86_64)
diff --git a/chromium/components/crash/content/app/crash_export_thunks.cc b/chromium/components/crash/content/app/crash_export_thunks.cc
new file mode 100644
index 00000000000..28c40a9fb89
--- /dev/null
+++ b/chromium/components/crash/content/app/crash_export_thunks.cc
@@ -0,0 +1,101 @@
+// 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/crash/content/app/crash_export_thunks.h"
+
+#include <algorithm>
+#include <type_traits>
+
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/crash/content/app/crashpad.h"
+#include "third_party/crashpad/crashpad/client/crashpad_client.h"
+
+void RequestSingleCrashUploadImpl(const char* local_id) {
+ crash_reporter::RequestSingleCrashUploadImpl(local_id);
+}
+
+size_t GetCrashReportsImpl(crash_reporter::Report* reports,
+ size_t reports_size) {
+ static_assert(std::is_pod<crash_reporter::Report>::value,
+ "crash_reporter::Report must be POD");
+ // Since this could be called across module boundaries, retrieve the full
+ // list of reports into this vector, and then manually copy however much fits
+ // into the caller's copy.
+ std::vector<crash_reporter::Report> crash_reports;
+
+ // The crash_reporter::GetReports function thunks here, here is delegation to
+ // the actual implementation.
+ crash_reporter::GetReportsImpl(&crash_reports);
+
+ size_t to_copy = std::min(reports_size, crash_reports.size());
+ for (size_t i = 0; i < to_copy; ++i)
+ reports[i] = crash_reports[i];
+
+ return crash_reports.size();
+}
+
+int CrashForException(EXCEPTION_POINTERS* info) {
+ crash_reporter::GetCrashpadClient().DumpAndCrash(info);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// This function is used in chrome_metrics_services_manager_client.cc to trigger
+// changes to the upload-enabled state. This is done when the metrics services
+// are initialized, and when the user changes their consent for uploads. See
+// crash_reporter::SetUploadConsent for effects. The given consent value should
+// be consistent with
+// crash_reporter::GetCrashReporterClient()->GetCollectStatsConsent(), but it's
+// not enforced to avoid blocking startup code on synchronizing them.
+void SetUploadConsentImpl(bool consent) {
+ crash_reporter::SetUploadConsent(consent);
+}
+
+// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
+// change the name or signature of this function you will break SyzyASAN
+// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
+// before doing so! See also http://crbug.com/567781.
+void SetCrashKeyValueImpl(const wchar_t* key, const wchar_t* value) {
+ crash_reporter::SetCrashKeyValue(base::UTF16ToUTF8(key),
+ base::UTF16ToUTF8(value));
+}
+
+void ClearCrashKeyValueImpl(const wchar_t* key) {
+ crash_reporter::ClearCrashKey(base::UTF16ToUTF8(key));
+}
+
+void SetCrashKeyValueImplEx(const char* key, const char* value) {
+ crash_reporter::SetCrashKeyValue(key, value);
+}
+
+void ClearCrashKeyValueImplEx(const char* key) {
+ crash_reporter::ClearCrashKey(key);
+}
+
+HANDLE InjectDumpForHungInput(HANDLE process, void* serialized_crash_keys) {
+ return CreateRemoteThread(
+ process, nullptr, 0,
+ crash_reporter::internal::DumpProcessForHungInputThread,
+ serialized_crash_keys, 0, nullptr);
+}
+
+HANDLE InjectDumpForHungInputNoCrashKeys(HANDLE process, int reason) {
+ return CreateRemoteThread(
+ process, nullptr, 0,
+ crash_reporter::internal::DumpProcessForHungInputNoCrashKeysThread,
+ reinterpret_cast<void*>(reason), 0, nullptr);
+}
+
+#if defined(ARCH_CPU_X86_64)
+
+void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
+ crash_reporter::internal::RegisterNonABICompliantCodeRangeImpl(start,
+ size_in_bytes);
+}
+
+void UnregisterNonABICompliantCodeRange(void* start) {
+ crash_reporter::internal::UnregisterNonABICompliantCodeRangeImpl(start);
+}
+
+#endif // ARCH_CPU_X86_64
diff --git a/chromium/components/crash/content/app/crash_export_thunks.h b/chromium/components/crash/content/app/crash_export_thunks.h
new file mode 100644
index 00000000000..5fe49fc5179
--- /dev/null
+++ b/chromium/components/crash/content/app/crash_export_thunks.h
@@ -0,0 +1,83 @@
+// 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_CRASH_CONTENT_APP_CRASH_EXPORT_THUNKS_H_
+#define COMPONENTS_CRASH_CONTENT_APP_CRASH_EXPORT_THUNKS_H_
+
+#include <stddef.h>
+#include <windows.h>
+
+#include "build/build_config.h"
+
+namespace crash_reporter {
+struct Report;
+}
+
+extern "C" {
+
+// TODO(siggi): Rename these functions to something descriptive and unique,
+// once all the thunks have been converted to import binding.
+
+// This function may be invoked across module boundaries to request a single
+// crash report upload. See CrashUploadListCrashpad.
+void RequestSingleCrashUploadImpl(const char* local_id);
+
+// This function may be invoked across module boundaries to retrieve the crash
+// list. It copies up to |report_count| reports into |reports| and returns the
+// number of reports available. If the return value is less than or equal to
+// |reports_size|, then |reports| contains all the available reports.
+size_t GetCrashReportsImpl(crash_reporter::Report* reports,
+ size_t reports_size);
+
+// Crashes the process after generating a dump for the provided exception. Note
+// that the crash reporter should be initialized before calling this function
+// for it to do anything.
+// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
+// the name or signature of this function you will break SyzyASAN instrumented
+// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
+int CrashForException(EXCEPTION_POINTERS* info);
+
+// This function is used in chrome_metrics_services_manager_client.cc to trigger
+// changes to the upload-enabled state. This is done when the metrics services
+// are initialized, and when the user changes their consent for uploads. See
+// crash_reporter::SetUploadConsent for effects. The given consent value should
+// be consistent with
+// crash_reporter::GetCrashReporterClient()->GetCollectStatsConsent(), but it's
+// not enforced to avoid blocking startup code on synchronizing them.
+void SetUploadConsentImpl(bool consent);
+
+// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
+// change the name or signature of this function you will break SyzyASAN
+// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
+// before doing so! See also http://crbug.com/567781.
+void SetCrashKeyValueImpl(const wchar_t* key, const wchar_t* value);
+
+void ClearCrashKeyValueImpl(const wchar_t* key);
+
+void SetCrashKeyValueImplEx(const char* key, const char* value);
+
+void ClearCrashKeyValueImplEx(const char* key);
+
+// Injects a thread into a remote process to dump state when there is no crash.
+// |serialized_crash_keys| is a nul terminated string in the address space of
+// |process| that represents serialized crash keys sent from the browser.
+// Keys and values are separated by ':', and key/value pairs are separated by
+// ','. All keys should be previously registered as crash keys.
+// This method is used solely to classify hung input.
+HANDLE InjectDumpForHungInput(HANDLE process, void* serialized_crash_keys);
+
+// Injects a thread into a remote process to dump state when there is no crash.
+// This method provides |reason| which will interpreted as an integer and logged
+// as a crash key.
+HANDLE InjectDumpForHungInputNoCrashKeys(HANDLE process, int reason);
+
+#if defined(ARCH_CPU_X86_64)
+// V8 support functions.
+void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes);
+void UnregisterNonABICompliantCodeRange(void* start);
+#endif // defined(ARCH_CPU_X86_64)
+
+} // extern "C"
+
+#endif // COMPONENTS_CRASH_CONTENT_APP_CRASH_EXPORT_THUNKS_H_
diff --git a/chromium/components/crash/content/app/crashpad.cc b/chromium/components/crash/content/app/crashpad.cc
index aabb8de5ac8..aface8de549 100644
--- a/chromium/components/crash/content/app/crashpad.cc
+++ b/chromium/components/crash/content/app/crashpad.cc
@@ -20,6 +20,7 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -36,6 +37,10 @@
#include <unistd.h>
#endif // OS_POSIX
+#if defined(OS_WIN)
+#include "components/crash/content/app/crash_export_thunks.h"
+#endif
+
namespace crash_reporter {
namespace {
@@ -43,15 +48,6 @@ namespace {
crashpad::SimpleStringDictionary* g_simple_string_dictionary;
crashpad::CrashReportDatabase* g_database;
-void SetCrashKeyValue(const base::StringPiece& key,
- const base::StringPiece& value) {
- g_simple_string_dictionary->SetKeyValue(key.data(), value.data());
-}
-
-void ClearCrashKey(const base::StringPiece& key) {
- g_simple_string_dictionary->RemoveKey(key.data());
-}
-
bool LogMessageHandler(int severity,
const char* file,
int line,
@@ -92,6 +88,7 @@ bool LogMessageHandler(int severity,
void InitializeCrashpadImpl(bool initial_client,
const std::string& process_type,
+ const std::string& user_data_dir,
bool embedded_handler) {
static bool initialized = false;
DCHECK(!initialized);
@@ -119,7 +116,7 @@ void InitializeCrashpadImpl(bool initial_client,
// database_path is only valid in the browser process.
base::FilePath database_path = internal::PlatformCrashpadInitialization(
- initial_client, browser_process, embedded_handler);
+ initial_client, browser_process, embedded_handler, user_data_dir);
crashpad::CrashpadInfo* crashpad_info =
crashpad::CrashpadInfo::GetCrashpadInfo();
@@ -189,14 +186,24 @@ void InitializeCrashpadImpl(bool initial_client,
} // namespace
+void SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ g_simple_string_dictionary->SetKeyValue(key.data(), value.data());
+}
+
+void ClearCrashKey(const base::StringPiece& key) {
+ g_simple_string_dictionary->RemoveKey(key.data());
+}
+
void InitializeCrashpad(bool initial_client, const std::string& process_type) {
- InitializeCrashpadImpl(initial_client, process_type, false);
+ InitializeCrashpadImpl(initial_client, process_type, std::string(), false);
}
#if defined(OS_WIN)
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
- const std::string& process_type) {
- InitializeCrashpadImpl(initial_client, process_type, true);
+ const std::string& process_type,
+ const std::string& user_data_dir) {
+ InitializeCrashpadImpl(initial_client, process_type, user_data_dir, true);
}
#endif // OS_WIN
@@ -238,7 +245,51 @@ bool GetUploadsEnabled() {
return false;
}
+void DumpWithoutCrashing() {
+ CRASHPAD_SIMULATE_CRASH();
+}
+
void GetReports(std::vector<Report>* reports) {
+#if defined(OS_WIN)
+ // On Windows, the crash client may be linked into another module, which
+ // does the client registration. That means the global that holds the crash
+ // report database lives across a module boundary, where the other module
+ // implements the GetCrashReportsImpl function. Since the other module has
+ // a separate allocation domain, this awkward copying is necessary.
+
+ // Start with an arbitrary copy size.
+ reports->resize(25);
+ while (true) {
+ size_t available_reports =
+ GetCrashReportsImpl(&reports->at(0), reports->size());
+ if (available_reports <= reports->size()) {
+ // The input size was large enough to capture all available crashes.
+ // Trim the vector to the actual number of reports returned and return.
+ reports->resize(available_reports);
+ return;
+ }
+
+ // Resize to the number of available reports, plus some slop to all but
+ // eliminate the possibility of running around the loop again due to a
+ // newly arrived crash report.
+ reports->resize(available_reports + 5);
+ }
+#else
+ GetReportsImpl(reports);
+#endif
+}
+
+void RequestSingleCrashUpload(const std::string& local_id) {
+#if defined(OS_WIN)
+ // On Windows, crash reporting may be implemented in another module, which is
+ // why this can't call crash_reporter::RequestSingleCrashUpload directly.
+ RequestSingleCrashUploadImpl(local_id);
+#else
+ crash_reporter::RequestSingleCrashUploadImpl(local_id);
+#endif
+}
+
+void GetReportsImpl(std::vector<Report>* reports) {
reports->clear();
if (!g_database) {
@@ -260,10 +311,15 @@ void GetReports(std::vector<Report>* reports) {
for (const crashpad::CrashReportDatabase::Report& completed_report :
completed_reports) {
- Report report;
- report.local_id = completed_report.uuid.ToString();
+ Report report = {};
+
+ // TODO(siggi): CHECK that this fits?
+ base::strlcpy(report.local_id, completed_report.uuid.ToString().c_str(),
+ sizeof(report.local_id));
+
report.capture_time = completed_report.creation_time;
- report.remote_id = completed_report.id;
+ base::strlcpy(report.remote_id, completed_report.id.c_str(),
+ sizeof(report.remote_id));
if (completed_report.uploaded) {
report.upload_time = completed_report.last_upload_attempt_time;
report.state = ReportUploadState::Uploaded;
@@ -276,8 +332,9 @@ void GetReports(std::vector<Report>* reports) {
for (const crashpad::CrashReportDatabase::Report& pending_report :
pending_reports) {
- Report report;
- report.local_id = pending_report.uuid.ToString();
+ Report report = {};
+ base::strlcpy(report.local_id, pending_report.uuid.ToString().c_str(),
+ sizeof(report.local_id));
report.capture_time = pending_report.creation_time;
report.upload_time = 0;
report.state = pending_report.upload_explicitly_requested
@@ -292,7 +349,7 @@ void GetReports(std::vector<Report>* reports) {
});
}
-void RequestSingleCrashUpload(const std::string& local_id) {
+void RequestSingleCrashUploadImpl(const std::string& local_id) {
if (!g_database)
return;
crashpad::UUID uuid;
@@ -300,47 +357,4 @@ void RequestSingleCrashUpload(const std::string& local_id) {
g_database->RequestUpload(uuid);
}
-void DumpWithoutCrashing() {
- CRASHPAD_SIMULATE_CRASH();
-}
-
} // namespace crash_reporter
-
-#if defined(OS_WIN)
-
-extern "C" {
-
-// This function is used in chrome_metrics_services_manager_client.cc to trigger
-// changes to the upload-enabled state. This is done when the metrics services
-// are initialized, and when the user changes their consent for uploads. See
-// crash_reporter::SetUploadConsent for effects. The given consent value should
-// be consistent with
-// crash_reporter::GetCrashReporterClient()->GetCollectStatsConsent(), but it's
-// not enforced to avoid blocking startup code on synchronizing them.
-void __declspec(dllexport) __cdecl SetUploadConsentImpl(bool consent) {
- crash_reporter::SetUploadConsent(consent);
-}
-
-// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
-// change the name or signature of this function you will break SyzyASAN
-// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
-// before doing so! See also http://crbug.com/567781.
-void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(const wchar_t* key,
- const wchar_t* value) {
- crash_reporter::SetCrashKeyValue(base::UTF16ToUTF8(key),
- base::UTF16ToUTF8(value));
-}
-
-void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(const wchar_t* key) {
- crash_reporter::ClearCrashKey(base::UTF16ToUTF8(key));
-}
-
-// This helper is invoked by code in chrome.dll to request a single crash report
-// upload. See CrashUploadListCrashpad.
-void __declspec(dllexport)
- RequestSingleCrashUploadImpl(const std::string& local_id) {
- crash_reporter::RequestSingleCrashUpload(local_id);
-}
-} // extern "C"
-
-#endif // OS_WIN
diff --git a/chromium/components/crash/content/app/crashpad.h b/chromium/components/crash/content/app/crashpad.h
index ae6d3a479ba..87207d3a50c 100644
--- a/chromium/components/crash/content/app/crashpad.h
+++ b/chromium/components/crash/content/app/crashpad.h
@@ -17,6 +17,9 @@
#if defined(OS_MACOSX)
#include "base/mac/scoped_mach_port.h"
#endif
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
namespace crashpad {
class CrashpadClient;
@@ -59,9 +62,11 @@ void InitializeCrashpad(bool initial_client, const std::string& process_type);
#if defined(OS_WIN)
// This is the same as InitializeCrashpad(), but rather than launching a
// crashpad_handler executable, relaunches the current executable with a command
-// line argument of --type=crashpad-handler.
+// line argument of --type=crashpad-handler. If user_data_dir is non-empty, it
+// is added to the handler's command line for use by Chrome Crashpad extensions.
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
- const std::string& process_type);
+ const std::string& process_type,
+ const std::string& user_data_dir);
#endif // OS_WIN
// Returns the CrashpadClient for this process. This will lazily create it if
@@ -90,9 +95,9 @@ enum class ReportUploadState {
};
struct Report {
- std::string local_id;
+ char local_id[64];
time_t capture_time;
- std::string remote_id;
+ char remote_id[64];
time_t upload_time;
ReportUploadState state;
};
@@ -109,6 +114,19 @@ void RequestSingleCrashUpload(const std::string& local_id);
void DumpWithoutCrashing();
+// The implementation function for GetReports.
+void GetReportsImpl(std::vector<Report>* reports);
+
+// The implementation function for RequestSingleCrashUpload.
+void RequestSingleCrashUploadImpl(const std::string& local_id);
+
+// Sets a crash key value.
+void SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value);
+
+// Clears a crash key value.
+void ClearCrashKey(const base::StringPiece& key);
+
namespace internal {
#if defined(OS_WIN)
@@ -116,13 +134,28 @@ namespace internal {
// that it may be reused by GetCrashKeysForKasko.
void GetPlatformCrashpadAnnotations(
std::map<std::string, std::string>* annotations);
+
+// The thread functions that implement the InjectDumpForHungInput and
+// InjectDumpForHungInputNoCrashKeys in the target process.
+DWORD WINAPI DumpProcessForHungInputThread(void* crash_keys_str);
+DWORD WINAPI DumpProcessForHungInputNoCrashKeysThread(void* reason);
+
+#if defined(ARCH_CPU_X86_64)
+// V8 support functions.
+void RegisterNonABICompliantCodeRangeImpl(void* start, size_t size_in_bytes);
+void UnregisterNonABICompliantCodeRangeImpl(void* start);
+#endif // defined(ARCH_CPU_X86_64)
+
#endif // defined(OS_WIN)
-// The platform-specific portion of InitializeCrashpad().
+// The platform-specific portion of InitializeCrashpad(). On windows, if
+// user_data_dir is non-empty, the user data directory will be passed to the
+// handler process for use by Chrome Crashpad extensions.
// Returns the database path, if initializing in the browser process.
base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
- bool embedded_handler);
+ bool embedded_handler,
+ const std::string& user_data_dir);
} // namespace internal
diff --git a/chromium/components/crash/content/app/crashpad_mac.mm b/chromium/components/crash/content/app/crashpad_mac.mm
index 3bae07e14c6..485c2b4b3e9 100644
--- a/chromium/components/crash/content/app/crashpad_mac.mm
+++ b/chromium/components/crash/content/app/crashpad_mac.mm
@@ -31,9 +31,11 @@
namespace crash_reporter {
namespace internal {
-base::FilePath PlatformCrashpadInitialization(bool initial_client,
- bool browser_process,
- bool embedded_handler) {
+base::FilePath PlatformCrashpadInitialization(
+ bool initial_client,
+ bool browser_process,
+ bool embedded_handler,
+ const std::string& user_data_dir) {
base::FilePath database_path; // Only valid in the browser process.
base::FilePath metrics_path; // Only valid in the browser process.
DCHECK(!embedded_handler); // This is not used on Mac.
diff --git a/chromium/components/crash/content/app/crashpad_win.cc b/chromium/components/crash/content/app/crashpad_win.cc
index 2c25a0b26fd..bb5c09732c2 100644
--- a/chromium/components/crash/content/app/crashpad_win.cc
+++ b/chromium/components/crash/content/app/crashpad_win.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/crash/content/app/crash_export_thunks.h"
#include "components/crash/content/app/crash_reporter_client.h"
#include "components/crash/content/app/crash_switches.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
@@ -52,9 +53,11 @@ void GetPlatformCrashpadAnnotations(
#endif
}
-base::FilePath PlatformCrashpadInitialization(bool initial_client,
- bool browser_process,
- bool embedded_handler) {
+base::FilePath PlatformCrashpadInitialization(
+ bool initial_client,
+ bool browser_process,
+ bool embedded_handler,
+ const std::string& user_data_dir) {
base::FilePath database_path; // Only valid in the browser process.
base::FilePath metrics_path; // Only valid in the browser process.
@@ -107,6 +110,10 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
if (embedded_handler) {
start_arguments.push_back(std::string("--type=") +
switches::kCrashpadHandler);
+ if (!user_data_dir.empty()) {
+ start_arguments.push_back(std::string("--user-data-dir=") +
+ user_data_dir);
+ }
// The prefetch argument added here has to be documented in
// chrome_switches.cc, below the kPrefetchArgument* constants. A constant
// can't be used here because crashpad can't depend on Chrome.
@@ -151,8 +158,6 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
return database_path;
}
-namespace {
-
// We need to prevent ICF from folding DumpProcessForHungInputThread(),
// DumpProcessForHungInputNoCrashKeysThread() together, since that makes them
// indistinguishable in crash dumps. We do this by making the function
@@ -191,50 +196,6 @@ DWORD WINAPI DumpProcessForHungInputNoCrashKeysThread(void* reason) {
MSVC_POP_WARNING()
MSVC_ENABLE_OPTIMIZE()
-} // namespace
-
-} // namespace internal
-} // namespace crash_reporter
-
-extern "C" {
-
-// Crashes the process after generating a dump for the provided exception. Note
-// that the crash reporter should be initialized before calling this function
-// for it to do anything.
-// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
-// the name or signature of this function you will break SyzyASAN instrumented
-// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
-int __declspec(dllexport) CrashForException(
- EXCEPTION_POINTERS* info) {
- crash_reporter::GetCrashpadClient().DumpAndCrash(info);
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
-// Injects a thread into a remote process to dump state when there is no crash.
-// |serialized_crash_keys| is a nul terminated string that represents serialized
-// crash keys sent from the browser. Keys and values are separated by ':', and
-// key/value pairs are separated by ','. All keys should be previously
-// registered as crash keys. This method is used solely to classify hung input.
-HANDLE __declspec(dllexport) __cdecl InjectDumpForHungInput(
- HANDLE process,
- void* serialized_crash_keys) {
- return CreateRemoteThread(
- process, nullptr, 0,
- crash_reporter::internal::DumpProcessForHungInputThread,
- serialized_crash_keys, 0, nullptr);
-}
-
-// Injects a thread into a remote process to dump state when there is no crash.
-// This method provides |reason| which will interpreted as an integer and logged
-// as a crash key.
-HANDLE __declspec(dllexport) __cdecl InjectDumpForHungInputNoCrashKeys(
- HANDLE process,
- int reason) {
- return CreateRemoteThread(
- process, nullptr, 0,
- crash_reporter::internal::DumpProcessForHungInputNoCrashKeysThread,
- reinterpret_cast<void*>(reason), 0, nullptr);
-}
#if defined(ARCH_CPU_X86_64)
@@ -265,9 +226,8 @@ struct ExceptionHandlerRecord {
};
// These are GetProcAddress()d from V8 binding code.
-void __declspec(dllexport) __cdecl RegisterNonABICompliantCodeRange(
- void* start,
- size_t size_in_bytes) {
+void __cdecl RegisterNonABICompliantCodeRangeImpl(void* start,
+ size_t size_in_bytes) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
@@ -310,8 +270,7 @@ void __declspec(dllexport) __cdecl RegisterNonABICompliantCodeRange(
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
}
-void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange(
- void* start) {
+void UnregisterNonABICompliantCodeRangeImpl(void* start) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
@@ -319,4 +278,5 @@ void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange(
}
#endif // ARCH_CPU_X86_64
-} // extern "C"
+} // namespace internal
+} // namespace crash_reporter
diff --git a/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
index 07340432cec..c19ae79d17d 100644
--- a/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
@@ -143,10 +143,9 @@ TEST_F(FallbackCrashHandlerLauncherTest, LaunchAndWaitForHandler) {
// Because this process is heavily multithreaded it's going to be flaky
// and generally fraught with peril to try and grab a minidump of it.
// Instead, fire off a sacrificial process to do the testing.
- base::SpawnChildResult spawn_child =
- SpawnChild("TestCrashHandlerLauncherMain");
+ base::Process test_process = SpawnChild("TestCrashHandlerLauncherMain");
int exit_code = 0;
- ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
+ ASSERT_TRUE(test_process.WaitForExit(&exit_code));
ASSERT_EQ(0, exit_code);
}
diff --git a/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
index 92c008ea804..13ca131f020 100644
--- a/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handler_win_unittest.cc
@@ -169,12 +169,12 @@ TEST_F(FallbackCrashHandlerWinTest, GenerateCrashDump) {
cmd_line.AppendSwitchPath("directory", database_dir_.GetPath());
base::LaunchOptions options;
options.start_hidden = true;
- base::SpawnChildResult spawn_child = base::SpawnMultiProcessTestChild(
+ base::Process test_child = base::SpawnMultiProcessTestChild(
"FallbackCrashHandlerWinMain", cmd_line, options);
- ASSERT_TRUE(spawn_child.process.IsValid());
+ ASSERT_TRUE(test_child.IsValid());
int exit_code = -1;
- ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
+ ASSERT_TRUE(test_child.WaitForExit(&exit_code));
ASSERT_EQ(0, exit_code);
// Validate that the database contains one valid crash dump.
diff --git a/chromium/components/crash/content/app/fallback_crash_handling_win.cc b/chromium/components/crash/content/app/fallback_crash_handling_win.cc
index e83be6275ea..b67db0379e6 100644
--- a/chromium/components/crash/content/app/fallback_crash_handling_win.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handling_win.cc
@@ -24,7 +24,8 @@ const uint32_t kFallbackCrashTerminationCode = 0xFFFF8001;
namespace {
-std::unique_ptr<FallbackCrashHandlerLauncher> g_fallback_crash_handler_launcher;
+// Intentionally leaked on program exit.
+FallbackCrashHandlerLauncher* g_fallback_crash_handler_launcher = nullptr;
LONG WINAPI FallbackUnhandledExceptionFilter(EXCEPTION_POINTERS* exc_ptrs) {
if (!g_fallback_crash_handler_launcher)
@@ -69,9 +70,8 @@ bool SetupFallbackCrashHandling(const base::CommandLine& command_line) {
// This is necessary because chrome_elf stubs out the
// SetUnhandledExceptionFilter in the IAT of chrome.exe.
- typedef PTOP_LEVEL_EXCEPTION_FILTER(WINAPI *
- SetUnhandledExceptionFilterFunction)(
- PTOP_LEVEL_EXCEPTION_FILTER filter);
+ using SetUnhandledExceptionFilterFunction =
+ PTOP_LEVEL_EXCEPTION_FILTER(WINAPI*)(PTOP_LEVEL_EXCEPTION_FILTER filter);
HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
if (!kernel32)
return false;
@@ -83,7 +83,7 @@ bool SetupFallbackCrashHandling(const base::CommandLine& command_line) {
return false;
// Success, pass ownership to the global.
- g_fallback_crash_handler_launcher = std::move(fallback_launcher);
+ g_fallback_crash_handler_launcher = fallback_launcher.release();
set_unhandled_exception_filter(&FallbackUnhandledExceptionFilter);
diff --git a/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc b/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
index 02d69c5dd27..7df6b20262a 100644
--- a/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
+++ b/chromium/components/crash/content/app/fallback_crash_handling_win_unittest.cc
@@ -62,12 +62,12 @@ TEST_F(FallbackCrashHandlingTest, SetupAndRunAsFallbackCrashHandler) {
base::LaunchOptions options;
options.start_hidden = true;
- base::SpawnChildResult spawn_child = base::SpawnMultiProcessTestChild(
+ base::Process test_child = base::SpawnMultiProcessTestChild(
"FallbackCrashHandlingWinRunHandler", cmd_line, options);
- ASSERT_TRUE(spawn_child.process.IsValid());
+ ASSERT_TRUE(test_child.IsValid());
int exit_code = -1;
- ASSERT_TRUE(spawn_child.process.WaitForExit(&exit_code));
+ ASSERT_TRUE(test_child.WaitForExit(&exit_code));
ASSERT_EQ(kFallbackCrashTerminationCode, static_cast<uint32_t>(exit_code));
// Validate that the database contains one valid crash dump.
diff --git a/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc b/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
index 6ea93489f1f..9e5b05b4a6d 100644
--- a/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
+++ b/chromium/components/crash/content/app/run_as_crashpad_handler_win.cc
@@ -10,18 +10,23 @@
#include <vector>
#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
#include "base/process/memory.h"
-#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/browser_watcher/stability_report_user_stream_data_source.h"
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
+#include "third_party/crashpad/crashpad/handler/user_stream_data_source.h"
namespace crash_reporter {
int RunAsCrashpadHandler(const base::CommandLine& command_line,
- const char* process_type_switch) {
+ const base::FilePath& user_data_dir,
+ const char* process_type_switch,
+ const char* user_data_dir_switch) {
// Make sure this process terminates on OOM in the same mode as other Chrome
// processes.
base::EnableTerminationOnOutOfMemory();
@@ -46,11 +51,16 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line,
std::vector<base::string16> argv = command_line.argv();
const base::string16 process_type_arg_prefix =
base::string16(L"--") + base::UTF8ToUTF16(process_type_switch) + L"=";
+ const base::string16 user_data_dir_arg_prefix =
+ base::string16(L"--") + base::UTF8ToUTF16(user_data_dir_switch) + L"=";
argv.erase(
std::remove_if(argv.begin(), argv.end(),
- [&process_type_arg_prefix](const base::string16& str) {
+ [&process_type_arg_prefix,
+ &user_data_dir_arg_prefix](const base::string16& str) {
return base::StartsWith(str, process_type_arg_prefix,
base::CompareCase::SENSITIVE) ||
+ base::StartsWith(str, user_data_dir_arg_prefix,
+ base::CompareCase::SENSITIVE) ||
(!str.empty() && str[0] == L'/');
}),
argv.end());
@@ -64,8 +74,20 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line,
}
argv_as_utf8[argv.size()] = nullptr;
argv.clear();
+
+ crashpad::UserStreamDataSources user_stream_data_sources;
+ // Interpret an empty user data directory as a missing value.
+ if (!user_data_dir.empty()) {
+ // Register an extension to collect stability information. The extension
+ // will be invoked for any registered process' crashes, but information only
+ // exists for instrumented browser processes.
+ user_stream_data_sources.push_back(
+ base::MakeUnique<browser_watcher::StabilityReportUserStreamDataSource>(
+ user_data_dir));
+ }
+
return crashpad::HandlerMain(static_cast<int>(storage.size()),
- argv_as_utf8.get(), nullptr);
+ argv_as_utf8.get(), &user_stream_data_sources);
}
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/app/run_as_crashpad_handler_win.h b/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
index ade72a01db9..2f2c090aa8f 100644
--- a/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
+++ b/chromium/components/crash/content/app/run_as_crashpad_handler_win.h
@@ -7,20 +7,26 @@
namespace base {
class CommandLine;
+class FilePath;
}
namespace crash_reporter {
// Helper for running an embedded copy of crashpad_handler. Searches for and
-// removes --(process_type_switch)=xyz arguments in the command line, and all
-// options starting with '/' (for "/prefetch:N"), and then runs
-// crashpad::HandlerMain with the remaining arguments.
+// removes --(process_type_switch|user_data_dir_switch)=xyz arguments in the
+// command line, and all options starting with '/' (for "/prefetch:N"), and then
+// runs crashpad::HandlerMain with the remaining arguments. If user_data_dir is
+// non-empty, a Crashpad extension to collect stability instrumentation on crash
+// is used.
//
-// Normally, pass switches::kProcessType for process_type_switch. It's accepted
-// as a parameter because this component does not have access to content/, where
-// that variable lives.
+// Normally, pass switches::kProcessType and switches::kCrashpadHandler for
+// process_type_switch and user_data_dir_switch. These are accepted as
+// parameters because this component does not have access to content/, where
+// those variables live.
int RunAsCrashpadHandler(const base::CommandLine& command_line,
- const char* process_type_switch);
+ const base::FilePath& user_data_dir,
+ const char* process_type_switch,
+ const char* user_data_dir_switch);
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/browser/BUILD.gn b/chromium/components/crash/content/browser/BUILD.gn
index 31fb1d1aeb0..94e18cbce81 100644
--- a/chromium/components/crash/content/browser/BUILD.gn
+++ b/chromium/components/crash/content/browser/BUILD.gn
@@ -8,6 +8,8 @@ if (is_android) {
source_set("browser") {
sources = [
+ "child_process_crash_observer_android.cc",
+ "child_process_crash_observer_android.h",
"crash_dump_manager_android.cc",
"crash_dump_manager_android.h",
"crash_dump_observer_android.cc",
diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.cc b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc
new file mode 100644
index 00000000000..b59a0dd3a1f
--- /dev/null
+++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc
@@ -0,0 +1,52 @@
+// 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/crash/content/browser/child_process_crash_observer_android.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "components/crash/content/app/breakpad_linux.h"
+#include "components/crash/content/browser/crash_dump_manager_android.h"
+
+namespace breakpad {
+
+ChildProcessCrashObserver::ChildProcessCrashObserver(
+ const base::FilePath crash_dump_dir,
+ int descriptor_id)
+ : crash_dump_dir_(crash_dump_dir), descriptor_id_(descriptor_id) {}
+
+ChildProcessCrashObserver::~ChildProcessCrashObserver() {}
+
+void ChildProcessCrashObserver::OnChildStart(
+ int child_process_id,
+ content::PosixFileDescriptorInfo* mappings) {
+ if (!breakpad::IsCrashReporterEnabled())
+ return;
+
+ base::ScopedFD file(
+ CrashDumpManager::GetInstance()->CreateMinidumpFileForChild(
+ child_process_id));
+ if (file.is_valid())
+ mappings->Transfer(descriptor_id_, std::move(file));
+}
+
+void ChildProcessCrashObserver::OnChildExit(
+ int child_process_id,
+ base::ProcessHandle pid,
+ content::ProcessType process_type,
+ base::TerminationStatus termination_status,
+ base::android::ApplicationState app_state) {
+ // This might be called twice for a given child process, with a
+ // NOTIFICATION_RENDERER_PROCESS_TERMINATED and then with
+ // NOTIFICATION_RENDERER_PROCESS_CLOSED.
+ base::PostTaskWithTraits(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ base::Bind(&CrashDumpManager::ProcessMinidumpFileFromChild,
+ base::Unretained(CrashDumpManager::GetInstance()),
+ crash_dump_dir_, child_process_id, process_type,
+ termination_status, app_state));
+}
+
+} // namespace breakpad
diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.h b/chromium/components/crash/content/browser/child_process_crash_observer_android.h
new file mode 100644
index 00000000000..fad32f2709f
--- /dev/null
+++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.h
@@ -0,0 +1,39 @@
+// 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_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
+#define COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
+
+#include "base/files/file_path.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
+
+namespace breakpad {
+
+class ChildProcessCrashObserver : public breakpad::CrashDumpObserver::Client {
+ public:
+ ChildProcessCrashObserver(const base::FilePath crash_dump_dir,
+ int descriptor_id);
+ ~ChildProcessCrashObserver() override;
+
+ // breakpad::CrashDumpObserver::Client implementation:
+ void OnChildStart(int child_process_id,
+ content::PosixFileDescriptorInfo* mappings) override;
+ void OnChildExit(int child_process_id,
+ base::ProcessHandle pid,
+ content::ProcessType process_type,
+ base::TerminationStatus termination_status,
+ base::android::ApplicationState app_state) override;
+
+ private:
+ base::FilePath crash_dump_dir_;
+ // The id used to identify the file descriptor in the set of file
+ // descriptor mappings passed to the child process.
+ int descriptor_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildProcessCrashObserver);
+};
+
+} // namespace breakpad
+
+#endif // COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.cc b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
index fdcfa65f7d6..d7cadd740c6 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
@@ -11,40 +11,39 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
-#include "base/posix/global_descriptors.h"
#include "base/process/process.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
#include "components/crash/content/app/breakpad_linux.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/browser/file_descriptor_info.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
#include "jni/CrashDumpManager_jni.h"
namespace breakpad {
-CrashDumpManager::CrashDumpManager(const base::FilePath& crash_dump_dir,
- int descriptor_id)
- : crash_dump_dir_(crash_dump_dir), descriptor_id_(descriptor_id) {}
+namespace {
+base::LazyInstance<CrashDumpManager>::Leaky g_instance =
+ LAZY_INSTANCE_INITIALIZER;
+}
-CrashDumpManager::~CrashDumpManager() {
+// static
+CrashDumpManager* CrashDumpManager::GetInstance() {
+ return g_instance.Pointer();
}
-void CrashDumpManager::OnChildStart(int child_process_id,
- content::FileDescriptorInfo* mappings) {
- if (!breakpad::IsCrashReporterEnabled())
- return;
+CrashDumpManager::CrashDumpManager() {}
+
+CrashDumpManager::~CrashDumpManager() {}
+base::ScopedFD CrashDumpManager::CreateMinidumpFileForChild(
+ int child_process_id) {
+ base::ThreadRestrictions::AssertIOAllowed();
base::FilePath minidump_path;
if (!base::CreateTemporaryFile(&minidump_path)) {
LOG(ERROR) << "Failed to create temporary file, crash won't be reported.";
- return;
+ return base::ScopedFD();
}
// We need read permission as the minidump is generated in several phases
@@ -54,27 +53,26 @@ void CrashDumpManager::OnChildStart(int child_process_id,
base::File minidump_file(minidump_path, flags);
if (!minidump_file.IsValid()) {
LOG(ERROR) << "Failed to open temporary file, crash won't be reported.";
- return;
+ return base::ScopedFD();
}
- {
- base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
- DCHECK(!base::ContainsKey(child_process_id_to_minidump_path_,
- child_process_id));
- child_process_id_to_minidump_path_[child_process_id] = minidump_path;
- }
- mappings->Transfer(descriptor_id_,
- base::ScopedFD(minidump_file.TakePlatformFile()));
+ SetMinidumpPath(child_process_id, minidump_path);
+ return base::ScopedFD(minidump_file.TakePlatformFile());
}
-// static
-void CrashDumpManager::ProcessMinidump(
- const base::FilePath& minidump_path,
- const base::FilePath& crash_dump_dir,
+void CrashDumpManager::ProcessMinidumpFileFromChild(
+ base::FilePath crash_dump_dir,
base::ProcessHandle pid,
content::ProcessType process_type,
base::TerminationStatus termination_status,
base::android::ApplicationState app_state) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ base::FilePath minidump_path;
+ // If the minidump for a given child process has already been
+ // processed, then there is no more work to do.
+ if (!GetMinidumpPath(pid, &minidump_path))
+ return;
+
int64_t file_size = 0;
int r = base::GetFileSize(minidump_path, &file_size);
DCHECK(r) << "Failed to retrieve size for minidump "
@@ -162,29 +160,25 @@ void CrashDumpManager::ProcessMinidump(
Java_CrashDumpManager_tryToUploadMinidump(env, j_dest_path);
}
-void CrashDumpManager::OnChildExit(int child_process_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) {
- base::FilePath minidump_path;
- {
- base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
- ChildProcessIDToMinidumpPath::iterator iter =
- child_process_id_to_minidump_path_.find(child_process_id);
- if (iter == child_process_id_to_minidump_path_.end()) {
- // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
- // NOTIFICATION_RENDERER_PROCESS_CLOSED.
- return;
- }
- minidump_path = iter->second;
- child_process_id_to_minidump_path_.erase(iter);
+void CrashDumpManager::SetMinidumpPath(int child_process_id,
+ const base::FilePath& minidump_path) {
+ base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
+ DCHECK(
+ !base::ContainsKey(child_process_id_to_minidump_path_, child_process_id));
+ child_process_id_to_minidump_path_[child_process_id] = minidump_path;
+}
+
+bool CrashDumpManager::GetMinidumpPath(int child_process_id,
+ base::FilePath* minidump_path) {
+ base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
+ ChildProcessIDToMinidumpPath::iterator iter =
+ child_process_id_to_minidump_path_.find(child_process_id);
+ if (iter == child_process_id_to_minidump_path_.end()) {
+ return false;
}
- base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
- base::Bind(&CrashDumpManager::ProcessMinidump, minidump_path,
- crash_dump_dir_, pid, process_type, termination_status,
- app_state));
+ *minidump_path = iter->second;
+ child_process_id_to_minidump_path_.erase(iter);
+ return true;
}
} // namespace breakpad
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.h b/chromium/components/crash/content/browser/crash_dump_manager_android.h
index ad711936d7f..6aa58857b9b 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android.h
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android.h
@@ -7,9 +7,13 @@
#include <map>
+#include "base/android/application_status_listener.h"
#include "base/files/file_path.h"
+#include "base/files/platform_file.h"
+#include "base/lazy_instance.h"
+#include "base/process/kill.h"
#include "base/synchronization/lock.h"
-#include "components/crash/content/browser/crash_dump_observer_android.h"
+#include "content/public/common/process_type.h"
namespace breakpad {
@@ -23,21 +27,24 @@ namespace breakpad {
// This class creates these file descriptors and associates them with render
// processes and takes the appropriate action when the render process
// terminates.
-class CrashDumpManager : public breakpad::CrashDumpObserver::Client {
+class CrashDumpManager {
public:
- CrashDumpManager(const base::FilePath& crash_dump_dir, int descriptor_id);
- ~CrashDumpManager() override;
-
- // breakpad::CrashDumpObserver::Client implementation:
- void OnChildStart(int child_process_id,
- content::FileDescriptorInfo* mappings) override;
- void OnChildExit(int child_process_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) override;
+ static CrashDumpManager* GetInstance();
+
+ void ProcessMinidumpFileFromChild(base::FilePath crash_dump_dir,
+ base::ProcessHandle pid,
+ content::ProcessType process_type,
+ base::TerminationStatus termination_status,
+ base::android::ApplicationState app_state);
+
+ base::ScopedFD CreateMinidumpFileForChild(int child_process_id);
private:
+ friend struct base::LazyInstanceTraitsBase<CrashDumpManager>;
+
+ CrashDumpManager();
+ ~CrashDumpManager();
+
typedef std::map<int, base::FilePath> ChildProcessIDToMinidumpPath;
// This enum is used to back a UMA histogram, and must be treated as
@@ -52,25 +59,15 @@ class CrashDumpManager : public breakpad::CrashDumpObserver::Client {
MINIDUMP_STATUS_COUNT
};
- static void ProcessMinidump(const base::FilePath& minidump_path,
- const base::FilePath& crash_dump_dir,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state);
+ void SetMinidumpPath(int child_process_id,
+ const base::FilePath& minidump_path);
+ bool GetMinidumpPath(int child_process_id, base::FilePath* minidump_path);
// This map should only be accessed with its lock aquired as it is accessed
// from the PROCESS_LAUNCHER and UI threads.
base::Lock child_process_id_to_minidump_path_lock_;
ChildProcessIDToMinidumpPath child_process_id_to_minidump_path_;
- // The directory in which temporary minidump files should be created.
- base::FilePath crash_dump_dir_;
-
- // The id used to identify the file descriptor in the set of file
- // descriptor mappings passed to the child process.
- int descriptor_id_;
-
DISALLOW_COPY_AND_ASSIGN(CrashDumpManager);
};
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.cc b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
index acb05e07d66..6e46919a175 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
@@ -84,7 +84,7 @@ void CrashDumpObserver::OnChildExit(int child_process_id,
void CrashDumpObserver::BrowserChildProcessStarted(
int child_process_id,
- content::FileDescriptorInfo* mappings) {
+ content::PosixFileDescriptorInfo* mappings) {
std::vector<Client*> registered_clients_copy;
{
base::AutoLock auto_lock(registered_clients_lock_);
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.h b/chromium/components/crash/content/browser/crash_dump_observer_android.h
index 3f049f31dd4..ac9cec18f6f 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.h
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.h
@@ -14,9 +14,9 @@
#include "base/process/kill.h"
#include "base/process/process.h"
#include "content/public/browser/browser_child_process_observer.h"
-#include "content/public/browser/file_descriptor_info.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/posix_file_descriptor_info.h"
#include "content/public/common/process_type.h"
namespace breakpad {
@@ -36,7 +36,7 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
public:
// OnChildStart is called on the launcher thread.
virtual void OnChildStart(int child_process_id,
- content::FileDescriptorInfo* mappings) = 0;
+ content::PosixFileDescriptorInfo* mappings) = 0;
// OnChildExit is called on the UI thread.
// OnChildExit may be called twice (once for the child process
// termination, and once for the IPC channel disconnection).
@@ -67,7 +67,7 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
// creation, and to allow clients to register any fd mappings they
// need.
void BrowserChildProcessStarted(int child_process_id,
- content::FileDescriptorInfo* mappings);
+ content::PosixFileDescriptorInfo* mappings);
private:
friend struct base::LazyInstanceTraitsBase<CrashDumpObserver>;
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 ce6598f4eff..c1db2482f03 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
@@ -12,6 +12,8 @@
#include <sys/syscall.h>
#include <unistd.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
@@ -21,13 +23,15 @@
#include "base/linux_util.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
@@ -101,9 +105,8 @@ CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type,
#endif
file_descriptor_watcher_(FROM_HERE),
shutting_down_(false),
- worker_pool_token_(base::SequencedWorkerPool::GetSequenceToken()) {
- write_dump_file_sequence_checker_.DetachFromSequence();
-
+ blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {
int fds[2];
// We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
// sending datagrams to other sockets on the system. The sandbox may prevent
@@ -131,8 +134,8 @@ CrashHandlerHostLinux::~CrashHandlerHostLinux() {
}
void CrashHandlerHostLinux::StartUploaderThread() {
- uploader_thread_.reset(
- new base::Thread(process_type_ + "_crash_uploader"));
+ uploader_thread_ =
+ base::MakeUnique<base::Thread>(process_type_ + "_crash_uploader");
uploader_thread_->Start();
}
@@ -162,18 +165,18 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
struct msghdr msg = {0};
struct iovec iov[kCrashIovSize];
- std::unique_ptr<char[]> crash_context(new char[kCrashContextSize]);
+ auto crash_context = base::MakeUnique<char[]>(kCrashContextSize);
#if defined(ADDRESS_SANITIZER)
- std::unique_ptr<char[]> asan_report(new char[kMaxAsanReportSize + 1]);
+ auto asan_report = base::MakeUnique<char[]>(kMaxAsanReportSize + 1);
#endif
- std::unique_ptr<CrashKeyStorage> crash_keys(new CrashKeyStorage);
+ auto crash_keys = base::MakeUnique<CrashKeyStorage>();
google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys;
size_t crash_keys_size = crash_keys->Serialize(
const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
&serialized_crash_keys));
- char* tid_buf_addr = NULL;
+ char* tid_buf_addr = nullptr;
int tid_fd = -1;
uint64_t uptime;
size_t oom_size;
@@ -360,8 +363,7 @@ void CrashHandlerHostLinux::FindCrashingThreadAndDump(
reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context.get());
bad_context->tid = crashing_tid;
- std::unique_ptr<BreakpadInfo> info(new BreakpadInfo);
-
+ auto info = base::MakeUnique<BreakpadInfo>();
info->fd = -1;
info->process_type_length = process_type_.length();
// Freed in CrashDumpTask().
@@ -388,26 +390,23 @@ void CrashHandlerHostLinux::FindCrashingThreadAndDump(
info->upload = upload_;
#endif
-
- BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
- worker_pool_token_,
+ BreakpadInfo* info_ptr = info.get();
+ blocking_task_runner_->PostTaskAndReply(
FROM_HERE,
- base::Bind(&CrashHandlerHostLinux::WriteDumpFile,
- base::Unretained(this),
- base::Passed(&info),
- base::Passed(&crash_context),
- crashing_pid,
- signal_fd));
+ base::BindOnce(&CrashHandlerHostLinux::WriteDumpFile,
+ base::Unretained(this), info_ptr,
+ base::Passed(&crash_context), crashing_pid),
+ base::BindOnce(&CrashHandlerHostLinux::QueueCrashDumpTask,
+ base::Unretained(this), base::Passed(&info), signal_fd));
}
-void CrashHandlerHostLinux::WriteDumpFile(std::unique_ptr<BreakpadInfo> info,
+void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
std::unique_ptr<char[]> crash_context,
- pid_t crashing_pid,
- int signal_fd) {
- DCHECK(write_dump_file_sequence_checker_.CalledOnValidSequence());
+ pid_t crashing_pid) {
+ base::ThreadRestrictions::AssertIOAllowed();
// Set |info->distro| here because base::GetLinuxDistro() needs to run on a
- // blocking thread.
+ // blocking sequence.
std::string distro = base::GetLinuxDistro();
info->distro_length = distro.length();
// Freed in CrashDumpTask().
@@ -456,13 +455,6 @@ void CrashHandlerHostLinux::WriteDumpFile(std::unique_ptr<BreakpadInfo> info,
info->log_filename = minidump_log_filename_str;
#endif
info->pid = crashing_pid;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&CrashHandlerHostLinux::QueueCrashDumpTask,
- base::Unretained(this),
- base::Passed(&info),
- signal_fd));
}
void CrashHandlerHostLinux::QueueCrashDumpTask(
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.h b/chromium/components/crash/content/browser/crash_handler_host_linux.h
index 1c463644ccd..a60b5a9f690 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.h
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.h
@@ -7,18 +7,17 @@
#include <sys/types.h>
+#include <memory>
#include <string>
-#include <utility>
-#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
-#include "base/sequence_checker.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "build/build_config.h"
#include "components/crash/content/app/breakpad_linux_impl.h"
namespace base {
+class SequencedTaskRunner;
class Thread;
}
@@ -64,11 +63,10 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
private:
void Init();
- // Do work in a sequenced worker pool for OnFileCanReadWithoutBlocking().
- void WriteDumpFile(std::unique_ptr<BreakpadInfo> info,
+ // Do work on |blocking_task_runner_| for OnFileCanReadWithoutBlocking().
+ void WriteDumpFile(BreakpadInfo* info,
std::unique_ptr<char[]> crash_context,
- pid_t crashing_pid,
- int signal_fd);
+ pid_t crashing_pid);
// Continue OnFileCanReadWithoutBlocking()'s work on the IO thread.
void QueueCrashDumpTask(std::unique_ptr<BreakpadInfo> info, int signal_fd);
@@ -86,10 +84,10 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
int signal_fd,
int attempt);
- std::string process_type_;
- base::FilePath dumps_path_;
+ const std::string process_type_;
+ const base::FilePath dumps_path_;
#if !defined(OS_ANDROID)
- bool upload_;
+ const bool upload_;
#endif
int process_socket_;
@@ -99,12 +97,7 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
std::unique_ptr<base::Thread> uploader_thread_;
bool shutting_down_;
- // Unique sequence token so that writing crash dump won't be blocked
- // by other tasks.
- base::SequencedWorkerPool::SequenceToken worker_pool_token_;
-
- // Used to verify that calls to WriteDumpFile() are sequenced.
- base::SequenceChecker write_dump_file_sequence_checker_;
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
DISALLOW_COPY_AND_ASSIGN(CrashHandlerHostLinux);
};
diff --git a/chromium/components/crash/content/tools/crash_service.cc b/chromium/components/crash/content/tools/crash_service.cc
index 38f94f78912..46b6359fb7d 100644
--- a/chromium/components/crash/content/tools/crash_service.cc
+++ b/chromium/components/crash/content/tools/crash_service.cc
@@ -15,7 +15,6 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/win/windows_version.h"
#include "breakpad/src/client/windows/crash_generation/client_info.h"
#include "breakpad/src/client/windows/crash_generation/crash_generation_server.h"
#include "breakpad/src/client/windows/sender/crash_report_sender.h"
@@ -210,18 +209,16 @@ bool CrashService::Initialize(const base::FilePath& operating_dir,
SECURITY_ATTRIBUTES security_attributes = {0};
SECURITY_ATTRIBUTES* security_attributes_actual = NULL;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
- SECURITY_DESCRIPTOR* security_descriptor =
- reinterpret_cast<SECURITY_DESCRIPTOR*>(
- GetSecurityDescriptorForLowIntegrity());
- DCHECK(security_descriptor != NULL);
+ SECURITY_DESCRIPTOR* security_descriptor =
+ reinterpret_cast<SECURITY_DESCRIPTOR*>(
+ GetSecurityDescriptorForLowIntegrity());
+ DCHECK(security_descriptor != NULL);
- security_attributes.nLength = sizeof(security_attributes);
- security_attributes.lpSecurityDescriptor = security_descriptor;
- security_attributes.bInheritHandle = FALSE;
+ security_attributes.nLength = sizeof(security_attributes);
+ security_attributes.lpSecurityDescriptor = security_descriptor;
+ security_attributes.bInheritHandle = FALSE;
- security_attributes_actual = &security_attributes;
- }
+ security_attributes_actual = &security_attributes;
// Create the OOP crash generator object.
dumper_ = new CrashGenerationServer(pipe_name, security_attributes_actual,
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index 9e1a3ee9400..0cd47bdd8f6 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -162,81 +162,63 @@ proto_library("cronet_android_cert_proto") {
extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
}
-# Variables:
-# defines: Extra defines.
-# deps: Extra dependencies.
-template("cronet_static_tmpl") {
- source_set(target_name) {
- defines = []
-
- deps = [
- ":cronet_android_cert_proto",
- ":cronet_jni_headers",
- ":cronet_jni_registration",
- ":cronet_version_header",
- "//base",
- "//base/third_party/dynamic_annotations",
- "//components/metrics",
- "//components/prefs",
- "//url:url_features",
- ]
- sources = [
- "//components/cronet/android/cert/cert_verifier_cache_serializer.cc",
- "//components/cronet/android/cert/cert_verifier_cache_serializer.h",
- "//components/cronet/android/cronet_bidirectional_stream_adapter.cc",
- "//components/cronet/android/cronet_bidirectional_stream_adapter.h",
- "//components/cronet/android/cronet_library_loader.cc",
- "//components/cronet/android/cronet_library_loader.h",
- "//components/cronet/android/cronet_upload_data_stream.cc",
- "//components/cronet/android/cronet_upload_data_stream.h",
- "//components/cronet/android/cronet_upload_data_stream_adapter.cc",
- "//components/cronet/android/cronet_upload_data_stream_adapter.h",
- "//components/cronet/android/cronet_url_request_adapter.cc",
- "//components/cronet/android/cronet_url_request_adapter.h",
- "//components/cronet/android/cronet_url_request_context_adapter.cc",
- "//components/cronet/android/cronet_url_request_context_adapter.h",
- "//components/cronet/android/io_buffer_with_byte_buffer.cc",
- "//components/cronet/android/io_buffer_with_byte_buffer.h",
- "//components/cronet/android/metrics_util.cc",
- "//components/cronet/android/metrics_util.h",
- "//components/cronet/android/url_request_error.cc",
- "//components/cronet/android/url_request_error.h",
- "//components/cronet/histogram_manager.cc",
- "//components/cronet/histogram_manager.h",
- "//components/cronet/host_cache_persistence_manager.cc",
- "//components/cronet/host_cache_persistence_manager.h",
- "//components/cronet/stale_host_resolver.cc",
- "//components/cronet/stale_host_resolver.h",
- "//components/cronet/url_request_context_config.cc",
- "//components/cronet/url_request_context_config.h",
- ]
-
- include_dirs = [ _cronet_version_header_include_dir ]
-
- cflags = [
- "-DLOGGING=1",
- "-Wno-sign-promo",
- ]
-
- libs = [
- "android",
- "log",
- ]
-
- if (defined(invoker.defines)) {
- defines += invoker.defines
- }
-
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
- }
-}
-
-cronet_static_tmpl("cronet_static") {
+source_set("cronet_static") {
deps = [
+ ":cronet_android_cert_proto",
+ ":cronet_jni_headers",
+ ":cronet_jni_registration",
+ ":cronet_version_header",
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//components/metrics",
+ "//components/prefs",
"//net",
"//url",
+ "//url:url_features",
+ ]
+ sources = [
+ "//components/cronet/android/cert/cert_verifier_cache_serializer.cc",
+ "//components/cronet/android/cert/cert_verifier_cache_serializer.h",
+ "//components/cronet/android/cronet_bidirectional_stream_adapter.cc",
+ "//components/cronet/android/cronet_bidirectional_stream_adapter.h",
+ "//components/cronet/android/cronet_library_loader.cc",
+ "//components/cronet/android/cronet_library_loader.h",
+ "//components/cronet/android/cronet_upload_data_stream.cc",
+ "//components/cronet/android/cronet_upload_data_stream.h",
+ "//components/cronet/android/cronet_upload_data_stream_adapter.cc",
+ "//components/cronet/android/cronet_upload_data_stream_adapter.h",
+ "//components/cronet/android/cronet_url_request_adapter.cc",
+ "//components/cronet/android/cronet_url_request_adapter.h",
+ "//components/cronet/android/cronet_url_request_context_adapter.cc",
+ "//components/cronet/android/cronet_url_request_context_adapter.h",
+ "//components/cronet/android/io_buffer_with_byte_buffer.cc",
+ "//components/cronet/android/io_buffer_with_byte_buffer.h",
+ "//components/cronet/android/metrics_util.cc",
+ "//components/cronet/android/metrics_util.h",
+ "//components/cronet/android/url_request_error.cc",
+ "//components/cronet/android/url_request_error.h",
+ "//components/cronet/cronet_prefs_manager.cc",
+ "//components/cronet/cronet_prefs_manager.h",
+ "//components/cronet/histogram_manager.cc",
+ "//components/cronet/histogram_manager.h",
+ "//components/cronet/host_cache_persistence_manager.cc",
+ "//components/cronet/host_cache_persistence_manager.h",
+ "//components/cronet/stale_host_resolver.cc",
+ "//components/cronet/stale_host_resolver.h",
+ "//components/cronet/url_request_context_config.cc",
+ "//components/cronet/url_request_context_config.h",
+ ]
+
+ include_dirs = [ _cronet_version_header_include_dir ]
+
+ cflags = [
+ "-DLOGGING=1",
+ "-Wno-sign-promo",
+ ]
+
+ libs = [
+ "android",
+ "log",
]
if (!use_platform_icu_alternatives) {
@@ -344,6 +326,7 @@ android_library("cronet_impl_platform_java") {
deps = [
":cronet_api_java",
":cronet_impl_common_java",
+ "//third_party/android_tools:android_support_annotations_java",
"//third_party/jsr-305:jsr_305_javalib",
]
}
@@ -358,6 +341,7 @@ cronet_impl_native_java_srcjar_deps = [
android_library("cronet_impl_native_java") {
java_files = [
"java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java",
+ "java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java",
"java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
"java/src/org/chromium/net/impl/CronetLibraryLoader.java",
"java/src/org/chromium/net/impl/CronetMetrics.java",
@@ -512,17 +496,11 @@ shared_library("cronet_tests") {
"test/cronet_url_request_context_config_test.cc",
"test/cronet_url_request_context_config_test.h",
"test/experimental_options_test.cc",
- "test/experimental_options_test.h",
"test/mock_cert_verifier.cc",
- "test/mock_cert_verifier.h",
"test/mock_url_request_job_factory.cc",
- "test/mock_url_request_job_factory.h",
"test/native_test_server.cc",
- "test/native_test_server.h",
"test/quic_test_server.cc",
- "test/quic_test_server.h",
"test/sdch_test_util.cc",
- "test/sdch_test_util.h",
"test/test_upload_data_stream_handler.cc",
"test/test_upload_data_stream_handler.h",
]
@@ -690,6 +668,8 @@ android_library("cronet_javatests") {
"test/javatests/src/org/chromium/net/Criteria.java",
"test/javatests/src/org/chromium/net/CronetEngineBuilderTest.java",
"test/javatests/src/org/chromium/net/CronetTestBase.java",
+ "test/javatests/src/org/chromium/net/CronetTestCommon.java",
+ "test/javatests/src/org/chromium/net/CronetTestRule.java",
"test/javatests/src/org/chromium/net/CronetTestBaseTest.java",
"test/javatests/src/org/chromium/net/CronetUploadTest.java",
"test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java",
@@ -732,6 +712,7 @@ android_library("cronet_javatests") {
"//net/android:net_java",
"//net/android:net_java_test_support",
"//third_party/android_support_test_runner:runner_java",
+ "//third_party/junit",
]
run_findbugs_override = true
@@ -811,6 +792,8 @@ instrumentation_test_apk(
android_manifest = "test/javatests/AndroidManifest.xml"
deps = [
":cronet_smoketests_platform_only_java",
+ "//base:base_java_test_support",
+ "//third_party/android_support_test_runner:runner_java",
]
proguard_enabled = true
@@ -951,18 +934,24 @@ action("extract_cronet_jars") {
script = "//components/cronet/tools/extract_from_jars.py"
depfile = "$target_gen_dir/$target_name.d"
- sources = [
- "$root_out_dir/lib.java/base/base_java.jar",
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_native_java.jar",
- "$root_out_dir/lib.java/net/android/net_java.jar",
- "$root_out_dir/lib.java/url/url_java.jar",
- ]
-
_stamp_file = "$target_gen_dir/$target_name.stamp"
outputs = [
_stamp_file,
]
+ deps = [
+ ":cronet_impl_native_java",
+ "//base:base_java",
+ "//net/android:net_java",
+ "//url:url_java",
+ ]
+
+ sources = []
+ foreach(dep, deps) {
+ sources += [ get_label_info(dep, "target_gen_dir") + "/" +
+ get_label_info(dep, "name") + "__compile_java.javac.jar" ]
+ }
+
_rebased_sources = rebase_path(sources, root_build_dir)
args = [
@@ -974,13 +963,6 @@ action("extract_cronet_jars") {
"--stamp",
rebase_path(_stamp_file, root_build_dir),
]
-
- deps = [
- ":cronet_impl_native_java",
- "//base:base_java",
- "//net/android:net_java",
- "//url:url_java",
- ]
}
action("repackage_extracted_jars") {
@@ -1251,9 +1233,6 @@ action("generate_javadoc") {
copy("cronet_package_copy") {
sources = [
- "$root_out_dir/lib.java/components/cronet/android/cronet_api.jar",
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_common_java.jar",
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_platform_java.jar",
"$target_gen_dir/cronet_impl_native_proguard.cfg",
"//AUTHORS",
"//chrome/VERSION",
@@ -1272,6 +1251,50 @@ copy("cronet_package_copy") {
]
}
+template("copy_java8_jars") {
+ _deps = []
+ foreach(dep, invoker.deps) {
+ _dep_name = get_label_info(dep, "name")
+ _source_jar = get_label_info(dep, "target_gen_dir") + "/" + _dep_name +
+ "__compile_java.javac.jar"
+ _output_jar = "$_package_dir/" + _dep_name + ".jar"
+
+ # cronet_api.jar is a special case. Its file name is
+ # different from the target name that builds it.
+ if (_output_jar == "$_package_dir/" + "cronet_api_java.jar") {
+ _output_jar = "$_package_dir/" + "cronet_api.jar"
+ }
+
+ _copy_dep = ":" + _dep_name + "__compile_java__javac"
+ _copy_target_name = "${target_name}_${dep}"
+
+ copy(_copy_target_name) {
+ sources = [
+ _source_jar,
+ ]
+ outputs = [
+ _output_jar,
+ ]
+ deps = [
+ _copy_dep,
+ ]
+ }
+ _deps += [ ":" + _copy_target_name ]
+ }
+
+ group(target_name) {
+ deps = _deps
+ }
+}
+
+copy_java8_jars("copy_cronet_java8_jars") {
+ deps = [
+ ":cronet_api_java",
+ ":cronet_impl_common_java",
+ ":cronet_impl_platform_java",
+ ]
+}
+
action("cronet_combine_proguard_flags") {
script = "//components/cronet/tools/generate_proguard_file.py"
sources = [
@@ -1467,6 +1490,7 @@ group("cronet_package") {
(!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon)) {
deps = [
":api_static_checks",
+ ":copy_cronet_java8_jars",
":cronet_package_copy",
":cronet_package_copy_native_lib",
":cronet_package_copy_native_lib_unstripped",
diff --git a/chromium/components/cronet/ios/BUILD.gn b/chromium/components/cronet/ios/BUILD.gn
index 3227d03ab13..b2b7eca86df 100644
--- a/chromium/components/cronet/ios/BUILD.gn
+++ b/chromium/components/cronet/ios/BUILD.gn
@@ -65,8 +65,12 @@ _cronet_deps = [
]
_cronet_sources = [
+ "../cronet_prefs_manager.cc",
+ "../cronet_prefs_manager.h",
"../histogram_manager.cc",
"../histogram_manager.h",
+ "../host_cache_persistence_manager.cc",
+ "../host_cache_persistence_manager.h",
"../stale_host_resolver.cc",
"../stale_host_resolver.h",
"../url_request_context_config.cc",
@@ -92,6 +96,21 @@ source_set("cronet_sources") {
}
}
+source_set("cronet_sources_with_global_state") {
+ deps = [
+ "//base",
+ "//ios/web/public/global_state",
+ ]
+
+ public_deps = [
+ ":cronet_sources",
+ ]
+
+ sources = [
+ "ios_global_state_configuration.cc",
+ ]
+}
+
# Tweak |info_plist| with current version and revision.
tweak_info_plist("tweak_cronet_plist") {
info_plist = "Info.plist"
@@ -102,7 +121,7 @@ ios_framework_bundle("cronet_framework") {
info_plist_target = ":tweak_cronet_plist"
deps = [
- ":cronet_sources",
+ ":cronet_sources_with_global_state",
"//base",
"//net:net",
]
@@ -136,7 +155,7 @@ test("cronet_unittests") {
]
deps = [
- ":cronet_sources",
+ ":cronet_sources_with_global_state",
"//base",
"//base/test:test_support",
"//components/cronet/ios/test:cronet_test",
@@ -161,6 +180,7 @@ action("generate_accept_languages") {
static_library("cronet_static") {
visibility = [ ":*" ]
deps = _cronet_deps
+ deps += [ ":cronet_sources_with_global_state" ]
sources = _cronet_sources
public_configs = [ ":cronet_include_config" ]
public_deps = [
@@ -233,13 +253,12 @@ template("ios_static_framework") {
_framework_name = invoker.framework_name
}
- _bundle_target_name = _target_name + "_bundle"
_framework_headers_target = _target_name + "_framework_headers"
bundle_data(_framework_headers_target) {
- visibility = [ ":$_bundle_target_name" ]
+ visibility = [ ":$_target_name" ]
sources = invoker.public_headers
outputs = [
- "{{bundle_root_dir}}/Headers/{{source_file_part}}",
+ "{{bundle_contents_dir}}/Headers/{{source_file_part}}",
]
}
@@ -247,36 +266,27 @@ template("ios_static_framework") {
_static_library_target = invoker.static_library_target
bundle_data(_framework_binary_target) {
- visibility = [ ":$_bundle_target_name" ]
+ visibility = [ ":$_target_name" ]
sources = get_target_outputs(_static_library_target)
outputs = [
- "{{bundle_root_dir}}/$_framework_name",
+ "{{bundle_executable_dir}}/$_framework_name",
]
public_deps = [
_static_library_target,
]
}
- create_bundle(_bundle_target_name) {
+ create_bundle(_target_name) {
product_type = "com.apple.product-type.framework"
- bundle_root_dir = "$root_out_dir/Static/$_output_name"
- bundle_executable_dir = bundle_root_dir
- bundle_resources_dir = bundle_root_dir
- bundle_plugins_dir = bundle_root_dir
+ bundle_root_dir = "$root_out_dir/Static/${_output_name}"
+ bundle_contents_dir = bundle_root_dir
+ bundle_executable_dir = bundle_contents_dir
+ bundle_resources_dir = bundle_contents_dir
+ bundle_plugins_dir = bundle_contents_dir
deps = [
":$_framework_binary_target",
":$_framework_headers_target",
]
- }
-
- action(_target_name) {
- script = "//build/config/ios/dummy.py"
- outputs = [
- "$root_out_dir/Static/$_output_name",
- ]
- deps = [
- ":$_bundle_target_name",
- ]
public_configs = invoker.public_configs
}
}
diff --git a/chromium/components/cronet/ios/test/BUILD.gn b/chromium/components/cronet/ios/test/BUILD.gn
index 5c90a1ce0ca..607f3558e80 100644
--- a/chromium/components/cronet/ios/test/BUILD.gn
+++ b/chromium/components/cronet/ios/test/BUILD.gn
@@ -12,6 +12,8 @@ test("cronet_test") {
"cronet_http_test.mm",
"cronet_netlog_test.mm",
"cronet_pkp_test.mm",
+ "cronet_prefs_test.mm",
+ "cronet_quic_test.mm",
"cronet_test_base.mm",
"cronet_test_runner.mm",
"get_stream_engine.mm",
diff --git a/chromium/components/cryptauth/BUILD.gn b/chromium/components/cryptauth/BUILD.gn
index dacb5510543..03bf16b8a46 100644
--- a/chromium/components/cryptauth/BUILD.gn
+++ b/chromium/components/cryptauth/BUILD.gn
@@ -39,6 +39,8 @@ static_library("cryptauth") {
"cryptauth_service.h",
"data_with_timestamp.cc",
"data_with_timestamp.h",
+ "device_capability_manager.cc",
+ "device_capability_manager.h",
"device_to_device_authenticator.cc",
"device_to_device_authenticator.h",
"device_to_device_initiator_helper.cc",
@@ -60,6 +62,8 @@ static_library("cryptauth") {
"remote_device.h",
"remote_device_loader.cc",
"remote_device_loader.h",
+ "remote_device_provider.cc",
+ "remote_device_provider.h",
"secure_channel.cc",
"secure_channel.h",
"secure_context.h",
@@ -157,6 +161,7 @@ source_set("unit_tests") {
"cryptauth_enroller_impl_unittest.cc",
"cryptauth_enrollment_manager_unittest.cc",
"cryptauth_gcm_manager_impl_unittest.cc",
+ "device_capability_manager_unittest.cc",
"device_to_device_authenticator_unittest.cc",
"device_to_device_operations_unittest.cc",
"device_to_device_secure_context_unittest.cc",
@@ -166,6 +171,7 @@ source_set("unit_tests") {
"raw_eid_generator_impl_unittest.cc",
"remote_beacon_seed_fetcher_unittest.cc",
"remote_device_loader_unittest.cc",
+ "remote_device_provider_unittest.cc",
"secure_channel_unittest.cc",
"session_keys_unittest.cc",
"sync_scheduler_impl_unittest.cc",
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc
index 710c057a0b6..f7d05247683 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc
@@ -28,20 +28,14 @@ BluetoothLowEnergyCharacteristicsFinder::
const SuccessCallback& success_callback,
const ErrorCallback& error_callback)
: adapter_(adapter),
+ bluetooth_device_(device),
remote_service_(remote_service),
to_peripheral_char_(to_peripheral_char),
from_peripheral_char_(from_peripheral_char),
success_callback_(success_callback),
error_callback_(error_callback) {
- if (!adapter_) {
- error_callback_.Run(to_peripheral_char_, from_peripheral_char_);
- return;
- }
-
adapter_->AddObserver(this);
ScanRemoteCharacteristics(device, remote_service_.uuid);
-
- // TODO(sacomoto): implement a timeout for characteristic discovery.
}
BluetoothLowEnergyCharacteristicsFinder::
@@ -57,6 +51,9 @@ BluetoothLowEnergyCharacteristicsFinder::
void BluetoothLowEnergyCharacteristicsFinder::GattCharacteristicAdded(
BluetoothAdapter* adapter,
BluetoothRemoteGattCharacteristic* characteristic) {
+ // Ignore events about other devices.
+ if (characteristic->GetService()->GetDevice() != bluetooth_device_)
+ return;
HandleCharacteristicUpdate(characteristic);
}
@@ -66,9 +63,29 @@ void BluetoothLowEnergyCharacteristicsFinder::GattDiscoveryCompleteForService(
if (!service || service->GetUUID() != remote_service_.uuid)
return;
+ OnCharacteristicDiscoveryEnded(service->GetDevice());
+}
+
+void BluetoothLowEnergyCharacteristicsFinder::GattServicesDiscovered(
+ BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ OnCharacteristicDiscoveryEnded(device);
+}
+
+void BluetoothLowEnergyCharacteristicsFinder::OnCharacteristicDiscoveryEnded(
+ BluetoothDevice* device) {
+ // Ignore events about other devices.
+ if (device != bluetooth_device_)
+ return;
+
if (!to_peripheral_char_.id.empty() && !from_peripheral_char_.id.empty())
return;
+ if (has_error_callback_been_invoked_)
+ return;
+ // If all GATT services have been discovered and we haven't found the
+ // characteristics we are looking for, call the error callback.
+ has_error_callback_been_invoked_ = true;
error_callback_.Run(to_peripheral_char_, from_peripheral_char_);
}
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
index 35afee241ff..e755549300c 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
@@ -66,6 +66,8 @@ class BluetoothLowEnergyCharacteristicsFinder
void GattDiscoveryCompleteForService(
device::BluetoothAdapter* adapter,
device::BluetoothRemoteGattService* service) override;
+ void GattServicesDiscovered(device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) override;
void GattCharacteristicAdded(
device::BluetoothAdapter* adapter,
device::BluetoothRemoteGattCharacteristic* characteristic) override;
@@ -79,6 +81,9 @@ class BluetoothLowEnergyCharacteristicsFinder
bool HandleCharacteristicUpdate(
device::BluetoothRemoteGattCharacteristic* characteristic);
+ // Ends the characteristic discovery and calls error callback if necessary.
+ void OnCharacteristicDiscoveryEnded(device::BluetoothDevice* device);
+
// Scans the remote chracteristics of the service with |uuid| in |device|
// calling HandleCharacteristicUpdate() for each of them.
void ScanRemoteCharacteristics(device::BluetoothDevice* device,
@@ -93,6 +98,9 @@ class BluetoothLowEnergyCharacteristicsFinder
// The Bluetooth adapter where the connection was established.
scoped_refptr<device::BluetoothAdapter> adapter_;
+ // The Bluetooth device to which the connection was established.
+ device::BluetoothDevice* bluetooth_device_;
+
// Remote service the |connection_| was established with.
RemoteAttribute remote_service_;
@@ -105,6 +113,9 @@ class BluetoothLowEnergyCharacteristicsFinder
// Called when all characteristics were found.
SuccessCallback success_callback_;
+ // Keeps track whether we have ever call the error callback.
+ bool has_error_callback_been_invoked_ = false;
+
// Called when there is an error.
ErrorCallback error_callback_;
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
index 58ac22f58bf..e87a5b05e14 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
@@ -169,6 +169,43 @@ TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
observer->GattDiscoveryCompleteForService(adapter_.get(), service_.get());
}
+// Tests that CharacteristicFinder ignores events for other devices.
+TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
+ FindRightCharacteristicsWrongDevice) {
+ // Make CharacteristicFinder which is supposed to listen for other device.
+ std::unique_ptr<device::BluetoothDevice> device(
+ new NiceMock<device::MockBluetoothDevice>(
+ adapter_.get(), 0, kDeviceName, kBluetoothAddress, false, false));
+ BluetoothLowEnergyCharacteristicsFinder characteristic_finder(
+ adapter_, device.get(), remote_service_, to_peripheral_char_,
+ from_peripheral_char_, success_callback_, error_callback_);
+ // Upcasting |characteristic_finder| to access the virtual protected methods
+ // from Observer: GattCharacteristicAdded() and
+ // GattDiscoveryCompleteForService().
+ device::BluetoothAdapter::Observer* observer =
+ static_cast<device::BluetoothAdapter::Observer*>(&characteristic_finder);
+
+ RemoteAttribute found_to_char, found_from_char;
+ // These shouldn't be called at all since the GATT events below are for other
+ // devices.
+ EXPECT_CALL(*this, OnCharacteristicsFound(_, _, _)).Times(0);
+ EXPECT_CALL(*this, OnCharacteristicsFinderError(_, _)).Times(0);
+
+ std::unique_ptr<device::MockBluetoothGattCharacteristic> from_char =
+ ExpectToFindCharacteristic(device::BluetoothUUID(kFromPeripheralCharUUID),
+ kFromPeripheralCharID, true);
+ observer->GattCharacteristicAdded(adapter_.get(), from_char.get());
+
+ std::unique_ptr<device::MockBluetoothGattCharacteristic> to_char =
+ ExpectToFindCharacteristic(device::BluetoothUUID(kToPeripheralCharUUID),
+ kToPeripheralCharID, true);
+ observer->GattCharacteristicAdded(adapter_.get(), to_char.get());
+
+ EXPECT_CALL(*service_, GetUUID())
+ .WillOnce(Return(device::BluetoothUUID(kServiceUUID)));
+ observer->GattDiscoveryCompleteForService(adapter_.get(), service_.get());
+}
+
TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
DidntFindRightCharacteristics) {
BluetoothLowEnergyCharacteristicsFinder characteristic_finder(
@@ -191,6 +228,28 @@ TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
}
TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
+ DidntFindRightCharacteristicsNorService) {
+ BluetoothLowEnergyCharacteristicsFinder characteristic_finder(
+ adapter_, device_.get(), remote_service_, to_peripheral_char_,
+ from_peripheral_char_, success_callback_, error_callback_);
+ device::BluetoothAdapter::Observer* observer =
+ static_cast<device::BluetoothAdapter::Observer*>(&characteristic_finder);
+
+ EXPECT_CALL(*this, OnCharacteristicsFound(_, _, _)).Times(0);
+ EXPECT_CALL(*this, OnCharacteristicsFinderError(_, _));
+
+ std::unique_ptr<device::MockBluetoothGattCharacteristic> other_char =
+ ExpectToFindCharacteristic(device::BluetoothUUID(kOtherCharUUID),
+ kOtherCharID, false);
+ observer->GattCharacteristicAdded(adapter_.get(), other_char.get());
+
+ // GattServicesDiscovered event is fired but the service that contains the
+ // characteristics has not been found. OnCharacteristicsFinderError is
+ // expected to be called.
+ observer->GattServicesDiscovered(adapter_.get(), device_.get());
+}
+
+TEST_F(CryptAuthBluetoothLowEnergyCharacteristicFinderTest,
FindOnlyOneRightCharacteristic) {
BluetoothLowEnergyCharacteristicsFinder characteristic_finder(
adapter_, device_.get(), remote_service_, to_peripheral_char_,
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
index c3da0c48fbe..90b9953a76d 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -161,7 +162,8 @@ BluetoothLowEnergyWeaveClientConnection::
BluetoothLowEnergyWeaveClientConnection::
~BluetoothLowEnergyWeaveClientConnection() {
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
void BluetoothLowEnergyWeaveClientConnection::Connect() {
@@ -181,7 +183,9 @@ void BluetoothLowEnergyWeaveClientConnection::SetConnectionLatency() {
if (!bluetooth_device) {
PA_LOG(WARNING) << "Device not found; cannot set connection latency for "
<< GetDeviceInfoLogString() << ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_BLUETOOTH_DEVICE_NOT_AVAILABLE);
return;
}
@@ -205,7 +209,9 @@ void BluetoothLowEnergyWeaveClientConnection::CreateGattConnection() {
if (!bluetooth_device) {
PA_LOG(WARNING) << "Device not found; cannot create GATT connection to "
<< GetDeviceInfoLogString() << ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_BLUETOOTH_DEVICE_NOT_AVAILABLE);
return;
}
@@ -231,10 +237,17 @@ void BluetoothLowEnergyWeaveClientConnection::Disconnect() {
return;
}
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
-void BluetoothLowEnergyWeaveClientConnection::DestroyConnection() {
+void BluetoothLowEnergyWeaveClientConnection::DestroyConnection(
+ BleWeaveConnectionResult result) {
+ if (!has_recorded_connection_result_) {
+ has_recorded_connection_result_ = true;
+ RecordBleWeaveConnectionResult(result);
+ }
+
if (adapter_) {
adapter_->RemoveObserver(this);
adapter_ = nullptr;
@@ -282,7 +295,34 @@ void BluetoothLowEnergyWeaveClientConnection::OnTimeoutForSubStatus(
PA_LOG(ERROR) << "Timed out waiting during SubStatus "
<< SubStatusToString(status) << ". Destroying connection.";
- DestroyConnection();
+
+ BleWeaveConnectionResult result =
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_MAX;
+ switch (status) {
+ case SubStatus::WAITING_CONNECTION_LATENCY:
+ result = BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_SETTING_CONNECTION_LATENCY;
+ break;
+ case SubStatus::WAITING_GATT_CONNECTION:
+ result = BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_CREATING_GATT_CONNECTION;
+ break;
+ case SubStatus::WAITING_CHARACTERISTICS:
+ result = BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_FINDING_GATT_CHARACTERISTICS;
+ break;
+ case SubStatus::WAITING_NOTIFY_SESSION:
+ result = BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_STARTING_NOTIFY_SESSION;
+ break;
+ case SubStatus::WAITING_CONNECTION_RESPONSE:
+ result = BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_CONNECTION_RESPONSE;
+ break;
+ default:
+ NOTREACHED();
+ }
+ DestroyConnection(result);
}
void BluetoothLowEnergyWeaveClientConnection::SetupTestDoubles(
@@ -341,7 +381,8 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceChanged(
PA_LOG(WARNING) << "GATT connection to " << GetDeviceInfoLogString()
<< " has been dropped.";
- DestroyConnection();
+ DestroyConnection(BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED);
}
void BluetoothLowEnergyWeaveClientConnection::DeviceRemoved(
@@ -353,7 +394,8 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceRemoved(
PA_LOG(WARNING) << "Device has been lost: " << GetDeviceInfoLogString()
<< ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_ERROR_DEVICE_LOST);
}
void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged(
@@ -382,7 +424,8 @@ void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged(
PA_LOG(INFO) << "Received \"connection close\" uWeave packet from "
<< GetDeviceInfoLogString()
<< ". Reason: " << GetReasonForClose() << ".";
- DestroyConnection();
+ DestroyConnection(BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
return;
case ReceiverState::ERROR_DETECTED:
PA_LOG(ERROR) << "Received invalid packet from "
@@ -430,14 +473,20 @@ void BluetoothLowEnergyWeaveClientConnection::OnSetConnectionLatencyError() {
void BluetoothLowEnergyWeaveClientConnection::OnCreateGattConnectionError(
device::BluetoothDevice::ConnectErrorCode error_code) {
DCHECK(sub_status_ == SubStatus::WAITING_GATT_CONNECTION);
+ RecordGattConnectionResult(
+ BluetoothDeviceConnectErrorCodeToGattConnectionResult(error_code));
PA_LOG(WARNING) << "Error creating GATT connection to "
<< GetDeviceInfoLogString() << ". Error code: " << error_code;
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_CREATING_GATT_CONNECTION);
}
void BluetoothLowEnergyWeaveClientConnection::OnGattConnectionCreated(
std::unique_ptr<device::BluetoothGattConnection> gatt_connection) {
DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION);
+ RecordGattConnectionResult(
+ GattConnectionResult::GATT_CONNECTION_RESULT_SUCCESS);
gatt_connection_ = std::move(gatt_connection);
SetSubStatus(SubStatus::WAITING_CHARACTERISTICS);
@@ -490,7 +539,7 @@ void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFinderError(
<< ": ";
if (tx_characteristic.id.empty()) {
ss << "[TX: " << tx_characteristic.uuid.canonical_value() << "]";
- if (!rx_characteristic.id.empty())
+ if (rx_characteristic.id.empty())
ss << ", ";
}
if (rx_characteristic.id.empty())
@@ -499,7 +548,9 @@ void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFinderError(
characteristic_finder_.reset();
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_FINDING_GATT_CHARACTERISTICS);
}
void BluetoothLowEnergyWeaveClientConnection::StartNotifySession() {
@@ -511,7 +562,9 @@ void BluetoothLowEnergyWeaveClientConnection::StartNotifySession() {
PA_LOG(ERROR) << "Characteristic no longer available after it was found. "
<< "Cannot start notification session for "
<< GetDeviceInfoLogString() << ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
return;
}
@@ -537,6 +590,8 @@ void BluetoothLowEnergyWeaveClientConnection::StartNotifySession() {
void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted(
std::unique_ptr<device::BluetoothGattNotifySession> notify_session) {
DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
+ RecordGattNotifySessionResult(
+ GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_SUCCESS);
notify_session_ = std::move(notify_session);
SetSubStatus(SubStatus::NOTIFY_SESSION_READY);
SendConnectionRequest();
@@ -545,9 +600,14 @@ void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted(
void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionError(
device::BluetoothRemoteGattService::GattErrorCode error) {
DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
+ RecordGattNotifySessionResult(
+ BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
+ error));
PA_LOG(ERROR) << "Cannot start notification session for "
<< GetDeviceInfoLogString() << ". Error: " << error << ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_STARTING_NOTIFY_SESSION);
}
void BluetoothLowEnergyWeaveClientConnection::SendConnectionRequest() {
@@ -586,7 +646,9 @@ void BluetoothLowEnergyWeaveClientConnection::SendPendingWriteRequest() {
PA_LOG(ERROR) << "Characteristic no longer available after it was found. "
<< "Cannot process write request for "
<< GetDeviceInfoLogString() << ".";
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
return;
}
@@ -604,11 +666,16 @@ void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE ||
sub_status() == SubStatus::CONNECTED);
+ RecordGattWriteCharacteristicResult(
+ GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_SUCCESS);
+
if (!pending_write_request_) {
PA_LOG(ERROR) << "OnRemoteCharacteristicWritten() called, but no pending "
<< "WriteRequest. Stopping connection to "
<< GetDeviceInfoLogString();
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITE_QUEUE_OUT_OF_SYNC);
return;
}
@@ -616,7 +683,8 @@ void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
WriteRequestType::CONNECTION_CLOSE) {
// Once a "connection close" uWeave packet has been sent, the connection
// is ready to be disconnected.
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
return;
}
@@ -626,7 +694,9 @@ void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
PA_LOG(ERROR) << "Sent a WriteRequest with type == MESSAGE_COMPLETE, but "
<< "there were no queued WireMessages. Cannot process "
<< "completed write to " << GetDeviceInfoLogString();
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
return;
}
@@ -655,11 +725,17 @@ void BluetoothLowEnergyWeaveClientConnection::OnWriteRemoteCharacteristicError(
DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE ||
sub_status() == SubStatus::CONNECTED);
+ RecordGattWriteCharacteristicResult(
+ BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
+ error));
+
if (!pending_write_request_) {
PA_LOG(ERROR) << "OnWriteRemoteCharacteristicError() called, but no "
<< "pending WriteRequest. Stopping connection to "
<< GetDeviceInfoLogString();
- DestroyConnection();
+ DestroyConnection(
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITE_QUEUE_OUT_OF_SYNC);
return;
}
@@ -691,8 +767,11 @@ void BluetoothLowEnergyWeaveClientConnection::OnWriteRemoteCharacteristicError(
// chance to process the OnSendCompleted() call.
task_runner_->PostTask(
FROM_HERE,
- base::Bind(&BluetoothLowEnergyWeaveClientConnection::DestroyConnection,
- weak_ptr_factory_.GetWeakPtr()));
+ base::Bind(
+ &BluetoothLowEnergyWeaveClientConnection::DestroyConnection,
+ weak_ptr_factory_.GetWeakPtr(),
+ BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC));
}
void BluetoothLowEnergyWeaveClientConnection::OnDidSendMessage(
@@ -792,6 +871,101 @@ std::string BluetoothLowEnergyWeaveClientConnection::GetReasonForClose() {
}
}
+void BluetoothLowEnergyWeaveClientConnection::RecordBleWeaveConnectionResult(
+ BleWeaveConnectionResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ProximityAuth.BleWeaveConnectionResult", result,
+ BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_MAX);
+}
+
+void BluetoothLowEnergyWeaveClientConnection::RecordGattConnectionResult(
+ GattConnectionResult result) {
+ UMA_HISTOGRAM_ENUMERATION("ProximityAuth.BluetoothGattConnectionResult",
+ result,
+ GattConnectionResult::GATT_CONNECTION_RESULT_MAX);
+}
+
+BluetoothLowEnergyWeaveClientConnection::GattConnectionResult
+BluetoothLowEnergyWeaveClientConnection::
+ BluetoothDeviceConnectErrorCodeToGattConnectionResult(
+ device::BluetoothDevice::ConnectErrorCode error_code) {
+ switch (error_code) {
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_CANCELED:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_CANCELED;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_FAILED:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_FAILED;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_REJECTED:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_REJECTED;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_TIMEOUT:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_TIMEOUT;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_FAILED:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_FAILED;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_INPROGRESS:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_INPROGRESS;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_UNKNOWN;
+ case device::BluetoothDevice::ConnectErrorCode::ERROR_UNSUPPORTED_DEVICE:
+ return GattConnectionResult::
+ GATT_CONNECTION_RESULT_ERROR_UNSUPPORTED_DEVICE;
+ default:
+ return GattConnectionResult::GATT_CONNECTION_RESULT_UNKNOWN;
+ }
+}
+
+void BluetoothLowEnergyWeaveClientConnection::RecordGattNotifySessionResult(
+ GattServiceOperationResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ProximityAuth.BluetoothGattNotifySessionResult", result,
+ GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_MAX);
+}
+
+void BluetoothLowEnergyWeaveClientConnection::
+ RecordGattWriteCharacteristicResult(GattServiceOperationResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ProximityAuth.BluetoothGattWriteCharacteristicResult", result,
+ GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_MAX);
+}
+
+BluetoothLowEnergyWeaveClientConnection::GattServiceOperationResult
+BluetoothLowEnergyWeaveClientConnection::
+ BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
+ device::BluetoothRemoteGattService::GattErrorCode error_code) {
+ switch (error_code) {
+ case device::BluetoothRemoteGattService::GattErrorCode::GATT_ERROR_UNKNOWN:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_UNKNOWN;
+ case device::BluetoothRemoteGattService::GattErrorCode::GATT_ERROR_FAILED:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_FAILED;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_IN_PROGRESS:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_IN_PROGRESS;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_INVALID_LENGTH:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_INVALID_LENGTH;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_NOT_PERMITTED:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PERMITTED;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_NOT_AUTHORIZED:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_AUTHORIZED;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_NOT_PAIRED:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PAIRED;
+ case device::BluetoothRemoteGattService::GattErrorCode::
+ GATT_ERROR_NOT_SUPPORTED:
+ return GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_SUPPORTED;
+ default:
+ return GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_UNKNOWN;
+ }
+}
+
BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
const Packet& val,
WriteRequestType request_type,
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
index 2ae20e4e015..06995a08d3c 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
@@ -104,10 +104,29 @@ class BluetoothLowEnergyWeaveClientConnection
std::string GetDeviceAddress() override;
protected:
+ enum BleWeaveConnectionResult {
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY = 0,
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_SETTING_CONNECTION_LATENCY = 1,
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_CREATING_GATT_CONNECTION = 2,
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_STARTING_NOTIFY_SESSION = 3,
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_FINDING_GATT_CHARACTERISTICS = 4,
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_CONNECTION_RESPONSE = 5,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_BLUETOOTH_DEVICE_NOT_AVAILABLE = 6,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_CREATING_GATT_CONNECTION = 7,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_STARTING_NOTIFY_SESSION = 8,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_FINDING_GATT_CHARACTERISTICS = 9,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC = 10,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE = 11,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITE_QUEUE_OUT_OF_SYNC = 12,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_DEVICE_LOST = 13,
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED = 14,
+ BLE_WEAVE_CONNECTION_RESULT_MAX
+ };
+
// Destroys the connection immediately; if there was an active connection, it
// will be disconnected after this call. Note that this function may notify
// observers of a connection status change.
- void DestroyConnection();
+ void DestroyConnection(BleWeaveConnectionResult result);
SubStatus sub_status() { return sub_status_; }
@@ -142,6 +161,71 @@ class BluetoothLowEnergyWeaveClientConnection
}
private:
+ friend class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest;
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ CreateAndDestroyWithoutConnectCallDoesntCrash);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ DisconnectWithoutConnectDoesntCrash);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectSuccess);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectSuccessDisconnect);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectSuccessDisconnect_DoNotSetLowLatency);
+ FRIEND_TEST_ALL_PREFIXES(
+ CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectIncompleteDisconnectFromWaitingCharacteristicsState);
+ FRIEND_TEST_ALL_PREFIXES(
+ CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectIncompleteDisconnectFromWaitingNotifySessionState);
+ FRIEND_TEST_ALL_PREFIXES(
+ CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectIncompleteDisconnectFromWaitingConnectionResponseState);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectFailsCharacteristicsNotFound);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectFailsCharacteristicsFoundThenUnavailable);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectFailsNotifySessionError);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectFailsErrorSendingConnectionRequest);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiveMessageSmallerThanCharacteristicSize);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiveMessageLargerThanCharacteristicSize);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ SendMessageSmallerThanCharacteristicSize);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ SendMessageLargerThanCharacteristicSize);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ SendMessageKeepsFailing);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiveCloseConnectionTest);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiverErrorTest);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ReceiverErrorWithPendingWritesTest);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ObserverDeletesConnectionOnDisconnect);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ObserverDeletesConnectionOnMessageSent);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ WriteConnectionCloseMaxNumberOfTimes);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ ConnectAfterADelayWhenThrottled);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ SetConnectionLatencyError);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ Timeout_ConnectionLatency);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ Timeout_GattConnection);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ Timeout_GattCharacteristics);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ Timeout_NotifySession);
+ FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
+ Timeout_ConnectionResponse);
+
enum WriteRequestType {
REGULAR,
MESSAGE_COMPLETE,
@@ -149,6 +233,38 @@ class BluetoothLowEnergyWeaveClientConnection
CONNECTION_CLOSE
};
+ // GATT_CONNECTION_RESULT_UNKNOWN indicates that the Bluetooth platform
+ // returned a code that is not recognized.
+ enum GattConnectionResult {
+ GATT_CONNECTION_RESULT_SUCCESS = 0,
+ GATT_CONNECTION_RESULT_ERROR_AUTH_CANCELED = 1,
+ GATT_CONNECTION_RESULT_ERROR_AUTH_FAILED = 2,
+ GATT_CONNECTION_RESULT_ERROR_AUTH_REJECTED = 3,
+ GATT_CONNECTION_RESULT_ERROR_AUTH_TIMEOUT = 4,
+ GATT_CONNECTION_RESULT_ERROR_FAILED = 5,
+ GATT_CONNECTION_RESULT_ERROR_INPROGRESS = 6,
+ GATT_CONNECTION_RESULT_ERROR_UNKNOWN = 7,
+ GATT_CONNECTION_RESULT_ERROR_UNSUPPORTED_DEVICE = 8,
+ GATT_CONNECTION_RESULT_UNKNOWN = 9,
+ GATT_CONNECTION_RESULT_MAX
+ };
+
+ // GATT_SERVICE_OPERATION_RESULT_UNKNOWN indicates that the Bluetooth
+ // platform returned a code that is not recognized.
+ enum GattServiceOperationResult {
+ GATT_SERVICE_OPERATION_RESULT_SUCCESS = 0,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_UNKNOWN = 1,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_FAILED = 2,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_IN_PROGRESS = 3,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_INVALID_LENGTH = 4,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PERMITTED = 5,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_AUTHORIZED = 6,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PAIRED = 7,
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_SUPPORTED = 8,
+ GATT_SERVICE_OPERATION_RESULT_UNKNOWN = 9,
+ GATT_SERVICE_OPERATION_RESULT_MAX
+ };
+
// Represents a request to write |value| to a some characteristic.
// |is_last_write_for_wire_messsage| indicates whether this request
// corresponds to the last write request for some wire message.
@@ -214,6 +330,16 @@ class BluetoothLowEnergyWeaveClientConnection
device::BluetoothRemoteGattService::GattErrorCode error);
void ClearQueueAndSendConnectionClose();
+ void RecordBleWeaveConnectionResult(BleWeaveConnectionResult result);
+ void RecordGattConnectionResult(GattConnectionResult result);
+ GattConnectionResult BluetoothDeviceConnectErrorCodeToGattConnectionResult(
+ device::BluetoothDevice::ConnectErrorCode error_code);
+ void RecordGattNotifySessionResult(GattServiceOperationResult result);
+ void RecordGattWriteCharacteristicResult(GattServiceOperationResult result);
+ GattServiceOperationResult
+ BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
+ device::BluetoothRemoteGattService::GattErrorCode error_code);
+
// Private getters for the Bluetooth classes corresponding to this connection.
device::BluetoothRemoteGattService* GetRemoteService();
device::BluetoothRemoteGattCharacteristic* GetGattCharacteristic(
@@ -229,6 +355,11 @@ class BluetoothLowEnergyWeaveClientConnection
bool should_set_low_connection_latency_;
+ // Tracks if the result of this connection has been recorded (using
+ // BleWeaveConnectionResult). The result of a connection should only be
+ // recorded once.
+ bool has_recorded_connection_result_ = false;
+
scoped_refptr<device::BluetoothAdapter> adapter_;
RemoteAttribute remote_service_;
std::unique_ptr<BluetoothLowEnergyWeavePacketGenerator> packet_generator_;
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
index c8a00920387..7c521788172 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
@@ -13,6 +13,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
#include "base/timer/mock_timer.h"
#include "base/timer/timer.h"
@@ -366,9 +367,14 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
.WillByDefault(Return(tx_characteristic_.get()));
device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
+
+ has_verified_connection_result_ = false;
}
- void TearDown() override { connection_observer_.reset(); }
+ void TearDown() override {
+ connection_observer_.reset();
+ ASSERT_TRUE(has_verified_connection_result_);
+ }
// Creates a BluetoothLowEnergyWeaveClientConnection and verifies it's in
// DISCONNECTED state.
@@ -488,6 +494,8 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
notify_session_success_callback_.Run(std::move(notify_session));
task_runner_->RunUntilIdle();
+ VerifyGattNotifySessionResult(true);
+
// Written value contains only the mock Connection Request.
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionRequest);
@@ -540,7 +548,9 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
connection->Disconnect();
if (connection->sub_status() == SubStatus::CONNECTED) {
- connection->DestroyConnection();
+ connection->DestroyConnection(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseSuccess);
RunWriteCharacteristicSuccessCallback();
@@ -566,6 +576,44 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
task_runner_->RunUntilIdle();
}
+ void VerifyGattConnectionResultSuccess() {
+ histogram_tester_.ExpectUniqueSample(
+ "ProximityAuth.BluetoothGattConnectionResult",
+ BluetoothLowEnergyWeaveClientConnection::GattConnectionResult::
+ GATT_CONNECTION_RESULT_SUCCESS,
+ 1);
+ }
+
+ void VerifyGattNotifySessionResult(bool success) {
+ histogram_tester_.ExpectUniqueSample(
+ "ProximityAuth.BluetoothGattNotifySessionResult",
+ GattServiceOperationResultSuccessOrFailure(success), 1);
+ }
+
+ void VerifyGattWriteCharacteristicResult(bool success, int num_writes) {
+ histogram_tester_.ExpectBucketCount(
+ "ProximityAuth.BluetoothGattWriteCharacteristicResult",
+ GattServiceOperationResultSuccessOrFailure(success), num_writes);
+ }
+
+ void VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult
+ expected_result) {
+ histogram_tester_.ExpectUniqueSample(
+ "ProximityAuth.BleWeaveConnectionResult", expected_result, 1);
+ has_verified_connection_result_ = true;
+ }
+
+ BluetoothLowEnergyWeaveClientConnection::GattServiceOperationResult
+ GattServiceOperationResultSuccessOrFailure(bool success) {
+ return success ? BluetoothLowEnergyWeaveClientConnection::
+ GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_SUCCESS
+ : BluetoothLowEnergyWeaveClientConnection::
+ GattServiceOperationResult::
+ GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_UNKNOWN;
+ }
+
protected:
const RemoteDevice remote_device_;
const device::BluetoothUUID service_uuid_;
@@ -584,6 +632,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
std::vector<uint8_t> last_value_written_on_tx_characteristic_;
base::MessageLoop message_loop_;
bool last_wire_message_success_;
+ bool has_verified_connection_result_;
NiceMock<MockBluetoothLowEnergyWeavePacketGenerator>* generator_;
NiceMock<MockBluetoothLowEnergyWeavePacketReceiver>* receiver_;
std::unique_ptr<MockConnectionObserver> connection_observer_;
@@ -610,6 +659,8 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
device::BluetoothRemoteGattCharacteristic::ErrorCallback
write_remote_characteristic_error_callback_;
+ base::HistogramTester histogram_tester_;
+
private:
DISALLOW_COPY_AND_ASSIGN(
CryptAuthBluetoothLowEnergyWeaveClientConnectionTest);
@@ -617,9 +668,15 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CreateAndDestroyWithoutConnectCallDoesntCrash) {
- BluetoothLowEnergyWeaveClientConnection connection(
- remote_device_, adapter_, service_uuid_, mock_bluetooth_device_.get(),
- true /* should_set_low_connection_latency */);
+ std::unique_ptr<BluetoothLowEnergyWeaveClientConnection> connection =
+ base::MakeUnique<BluetoothLowEnergyWeaveClientConnection>(
+ remote_device_, adapter_, service_uuid_, mock_bluetooth_device_.get(),
+ true /* should_set_low_connection_latency */);
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -627,6 +684,11 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
Disconnect(connection.get());
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -637,6 +699,11 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -646,6 +713,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED);
Disconnect(connection.get());
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -655,6 +726,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED);
Disconnect(connection.get());
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -663,6 +738,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
Disconnect(connection.get());
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -672,6 +751,11 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
Disconnect(connection.get());
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -682,6 +766,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
Disconnect(connection.get());
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -700,6 +788,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_FINDING_GATT_CHARACTERISTICS);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -722,6 +814,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -738,8 +834,14 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
notify_session_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
+ VerifyGattNotifySessionResult(false);
+
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_STARTING_NOTIFY_SESSION);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -769,10 +871,16 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
+ VerifyGattWriteCharacteristicResult(false /* success */,
+ i + 1 /* num_writes */);
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -789,6 +897,11 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
adapter_.get(), rx_characteristic_.get(), kSmallPackets0);
EXPECT_EQ(received_bytes, kSmallMessage);
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -809,6 +922,11 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
adapter_.get(), rx_characteristic_.get(), packet);
}
EXPECT_EQ(received_bytes, kLargeMessage);
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -831,10 +949,16 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(1, connection_observer_->GetNumSendCompleted());
EXPECT_EQ(kSmallMessage, connection_observer_->GetLastDeserializedMessage());
EXPECT_TRUE(connection_observer_->GetLastSendSuccess());
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -867,6 +991,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
SaveArg<2>(&write_remote_characteristic_error_callback_)));
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
bytes_received.insert(bytes_received.end(),
last_value_written_on_tx_characteristic_.begin() + 1,
last_value_written_on_tx_characteristic_.end());
@@ -875,10 +1000,16 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(expected, bytes_received);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 3 /* num_writes */);
EXPECT_EQ(1, connection_observer_->GetNumSendCompleted());
EXPECT_EQ(kLargeMessage, connection_observer_->GetLastDeserializedMessage());
EXPECT_TRUE(connection_observer_->GetLastSendSuccess());
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -904,6 +1035,8 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
+ VerifyGattWriteCharacteristicResult(false /* success */,
+ i + 1 /* num_writes */);
if (i == kMaxNumberOfTries - 1) {
EXPECT_EQ(1, connection_observer_->GetNumSendCompleted());
EXPECT_EQ(kSmallMessage,
@@ -916,6 +1049,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -930,6 +1067,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(receiver_->GetReasonForClose(), ReasonForClose::UNKNOWN_ERROR);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -953,8 +1094,13 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -985,14 +1131,20 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
SaveArg<2>(&write_remote_characteristic_error_callback_)));
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseApplicationError);
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 3 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
// Test for fix to crbug.com/708744. Without the fix, this test will crash.
@@ -1018,9 +1170,14 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
// We cannot check if connection's status and sub_status are DISCONNECTED
// because it has been deleted.
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
// Test for fix to crbug.com/ 751884. Without the fix, this test will crash.
@@ -1043,6 +1200,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
RunWriteCharacteristicSuccessCallback();
+ VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
task_runner_->RunUntilIdle();
EXPECT_EQ(1, connection_observer_->GetNumSendCompleted());
EXPECT_EQ(kSmallMessage, connection_observer_->GetLastDeserializedMessage());
@@ -1050,6 +1208,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
// We cannot check if connection's status and sub_status are DISCONNECTED
// because it has been deleted.
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1085,10 +1247,16 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
+ VerifyGattWriteCharacteristicResult(false /* success */,
+ i + 1 /* num_writes */);
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1135,6 +1303,13 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
+
+ VerifyGattConnectionResultSuccess();
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1173,6 +1348,13 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
+
+ VerifyGattConnectionResultSuccess();
+
+ connection.reset();
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1198,6 +1380,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_SETTING_CONNECTION_LATENCY);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1233,6 +1419,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_CREATING_GATT_CONNECTION);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1248,6 +1438,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_FINDING_GATT_CHARACTERISTICS);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1264,6 +1458,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_STARTING_NOTIFY_SESSION);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
@@ -1279,6 +1477,10 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+ VerifyBleWeaveConnectionResult(
+ BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
+ BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_CONNECTION_RESPONSE);
}
} // namespace weave
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h
index c3f68e6ae08..4ff7c5445b8 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h
@@ -109,7 +109,7 @@ class BluetoothLowEnergyWeavePacketReceiver {
};
explicit BluetoothLowEnergyWeavePacketReceiver(ReceiverType receiver_type);
- ~BluetoothLowEnergyWeavePacketReceiver();
+ virtual ~BluetoothLowEnergyWeavePacketReceiver();
typedef std::vector<uint8_t> Packet;
diff --git a/chromium/components/cryptauth/cryptauth_device_manager.cc b/chromium/components/cryptauth/cryptauth_device_manager.cc
index 76d651d3473..373678f72b9 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager.cc
+++ b/chromium/components/cryptauth/cryptauth_device_manager.cc
@@ -352,6 +352,25 @@ CryptAuthDeviceManager::~CryptAuthDeviceManager() {
}
}
+void CryptAuthDeviceManager::SetSyncSchedulerForTest(
+ std::unique_ptr<SyncScheduler> sync_scheduler) {
+ scheduler_ = std::move(sync_scheduler);
+}
+
+void CryptAuthDeviceManager::NotifySyncStarted() {
+ for (auto& observer : observers_) {
+ observer.OnSyncStarted();
+ }
+}
+
+void CryptAuthDeviceManager::NotifySyncFinished(
+ SyncResult sync_result,
+ DeviceChangeResult device_change_result) {
+ for (auto& observer : observers_) {
+ observer.OnSyncFinished(sync_result, device_change_result);
+ }
+}
+
// static
void CryptAuthDeviceManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDoublePref(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
@@ -502,12 +521,9 @@ void CryptAuthDeviceManager::OnGetMyDevicesSuccess(
sync_request_->OnDidComplete(true);
cryptauth_client_.reset();
sync_request_.reset();
- for (auto& observer : observers_) {
- observer.OnSyncFinished(SyncResult::SUCCESS,
- unlock_keys_changed
- ? DeviceChangeResult::CHANGED
- : DeviceChangeResult::UNCHANGED);
- }
+ NotifySyncFinished(SyncResult::SUCCESS, unlock_keys_changed
+ ? DeviceChangeResult::CHANGED
+ : DeviceChangeResult::UNCHANGED);
}
void CryptAuthDeviceManager::OnGetMyDevicesFailure(const std::string& error) {
@@ -517,8 +533,7 @@ void CryptAuthDeviceManager::OnGetMyDevicesFailure(const std::string& error) {
sync_request_->OnDidComplete(false);
cryptauth_client_.reset();
sync_request_.reset();
- for (auto& observer : observers_)
- observer.OnSyncFinished(SyncResult::FAILURE, DeviceChangeResult::UNCHANGED);
+ NotifySyncFinished(SyncResult::FAILURE, DeviceChangeResult::UNCHANGED);
}
void CryptAuthDeviceManager::OnResyncMessage() {
@@ -548,8 +563,7 @@ void CryptAuthDeviceManager::UpdateUnlockKeysFromPrefs() {
void CryptAuthDeviceManager::OnSyncRequested(
std::unique_ptr<SyncScheduler::SyncRequest> sync_request) {
- for (auto& observer : observers_)
- observer.OnSyncStarted();
+ NotifySyncStarted();
sync_request_ = std::move(sync_request);
cryptauth_client_ = client_factory_->CreateInstance();
diff --git a/chromium/components/cryptauth/cryptauth_device_manager.h b/chromium/components/cryptauth/cryptauth_device_manager.h
index 6994e54759b..c71995b1c65 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager.h
+++ b/chromium/components/cryptauth/cryptauth_device_manager.h
@@ -123,9 +123,15 @@ class CryptAuthDeviceManager : public SyncScheduler::Delegate,
// use this constructor outside of tests.
CryptAuthDeviceManager();
- void SetSyncSchedulerForTest(std::unique_ptr<SyncScheduler> sync_scheduler) {
- scheduler_ = std::move(sync_scheduler);
- }
+ void SetSyncSchedulerForTest(std::unique_ptr<SyncScheduler> sync_scheduler);
+
+ // Invokes OnSyncStarted() on all observers.
+ void NotifySyncStarted();
+
+ // Invokes OnSyncFinished(|sync_result|, |device_change_result|) on all
+ // observers.
+ void NotifySyncFinished(SyncResult sync_result,
+ DeviceChangeResult device_change_result);
private:
// CryptAuthGCMManager::Observer:
diff --git a/chromium/components/cryptauth/device_capability_manager.cc b/chromium/components/cryptauth/device_capability_manager.cc
new file mode 100644
index 00000000000..1e33c58d32b
--- /dev/null
+++ b/chromium/components/cryptauth/device_capability_manager.cc
@@ -0,0 +1,214 @@
+// 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/cryptauth/device_capability_manager.h"
+
+#include "base/logging.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+DeviceCapabilityManager::DeviceCapabilityManager(
+ CryptAuthClientFactory* cryptauth_client_factory)
+ : crypt_auth_client_factory_(cryptauth_client_factory),
+ weak_ptr_factory_(this) {}
+
+DeviceCapabilityManager::~DeviceCapabilityManager() {}
+
+void DeviceCapabilityManager::SetCapabilityEnabled(
+ const std::string& public_key,
+ Capability capability,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ pending_requests_.emplace(base::MakeUnique<Request>(
+ RequestType::SET_CAPABILITY_ENABLED, Capability::CAPABILITY_UNLOCK_KEY,
+ public_key, enabled, success_callback, error_callback));
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::FindEligibleDevicesForCapability(
+ Capability capability,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ pending_requests_.emplace(base::MakeUnique<Request>(
+ RequestType::FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY,
+ Capability::CAPABILITY_UNLOCK_KEY, success_callback, error_callback));
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::IsCapabilityPromotable(
+ const std::string& public_key,
+ Capability capability,
+ const base::Callback<void(bool)>& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ pending_requests_.emplace(base::MakeUnique<Request>(
+ RequestType::IS_CAPABILITY_PROMOTABLE, capability, public_key,
+ success_callback, error_callback));
+ ProcessRequestQueue();
+}
+
+DeviceCapabilityManager::Request::Request(
+ RequestType request_type,
+ Capability capability,
+ std::string public_key,
+ bool enabled,
+ const base::Closure& set_capability_callback,
+ const base::Callback<void(const std::string&)>& error_callback)
+ : request_type(request_type),
+ error_callback(error_callback),
+ capability(capability),
+ public_key(public_key),
+ set_capability_callback(set_capability_callback),
+ enabled(enabled) {}
+
+DeviceCapabilityManager::Request::Request(
+ RequestType request_type,
+ Capability capability,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ find_eligible_devices_callback,
+ const base::Callback<void(const std::string&)>& error_callback)
+ : request_type(request_type),
+ error_callback(error_callback),
+ capability(capability),
+ find_eligible_devices_callback(find_eligible_devices_callback) {}
+
+DeviceCapabilityManager::Request::Request(
+ RequestType request_type,
+ Capability capability,
+ std::string public_key,
+ const base::Callback<void(bool)> is_device_promotable_callback,
+ const base::Callback<void(const std::string&)>& error_callback)
+ : request_type(request_type),
+ error_callback(error_callback),
+ capability(capability),
+ public_key(public_key),
+ is_device_promotable_callback(is_device_promotable_callback) {}
+
+DeviceCapabilityManager::Request::~Request() {}
+
+void DeviceCapabilityManager::CreateNewCryptAuthClient() {
+ DCHECK(!current_cryptauth_client_);
+ current_cryptauth_client_ = crypt_auth_client_factory_->CreateInstance();
+}
+
+void DeviceCapabilityManager::ProcessSetCapabilityEnabledRequest() {
+ DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
+ SetUnlockKeyCapability();
+}
+
+void DeviceCapabilityManager::ProcessFindEligibleDevicesForCapability() {
+ DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
+ FindEligibleUnlockDevices();
+}
+
+void DeviceCapabilityManager::ProcessIsCapabilityPromotableRequest() {
+ DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
+ IsDeviceUnlockPromotable();
+}
+
+void DeviceCapabilityManager::SetUnlockKeyCapability() {
+ CreateNewCryptAuthClient();
+
+ ToggleEasyUnlockRequest request;
+ request.set_enable(current_request_->enabled);
+ request.set_apply_to_all(true);
+ request.set_public_key(current_request_->public_key);
+
+ current_cryptauth_client_->ToggleEasyUnlock(
+ request,
+ base::Bind(&DeviceCapabilityManager::OnToggleEasyUnlockResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&DeviceCapabilityManager::OnErrorResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DeviceCapabilityManager::FindEligibleUnlockDevices() {
+ CreateNewCryptAuthClient();
+
+ current_cryptauth_client_->FindEligibleUnlockDevices(
+ FindEligibleUnlockDevicesRequest(),
+ base::Bind(&DeviceCapabilityManager::OnFindEligibleUnlockDevicesResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&DeviceCapabilityManager::OnErrorResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DeviceCapabilityManager::IsDeviceUnlockPromotable() {
+ CreateNewCryptAuthClient();
+
+ FindEligibleForPromotionRequest request;
+ request.set_promoter_public_key(current_request_->public_key);
+
+ current_cryptauth_client_->FindEligibleForPromotion(
+ request,
+ base::Bind(&DeviceCapabilityManager::OnIsDeviceUnlockPromotableResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&DeviceCapabilityManager::OnErrorResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DeviceCapabilityManager::OnToggleEasyUnlockResponse(
+ const ToggleEasyUnlockResponse& response) {
+ current_cryptauth_client_.reset();
+ current_request_->set_capability_callback.Run();
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::OnFindEligibleUnlockDevicesResponse(
+ const FindEligibleUnlockDevicesResponse& response) {
+ current_cryptauth_client_.reset();
+ current_request_->find_eligible_devices_callback.Run(
+ std::vector<ExternalDeviceInfo>(response.eligible_devices().begin(),
+ response.eligible_devices().end()),
+ std::vector<IneligibleDevice>(response.ineligible_devices().begin(),
+ response.ineligible_devices().end()));
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::OnIsDeviceUnlockPromotableResponse(
+ const FindEligibleForPromotionResponse& response) {
+ current_cryptauth_client_.reset();
+ current_request_->is_device_promotable_callback.Run(
+ response.may_show_promo());
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::OnErrorResponse(const std::string& response) {
+ current_cryptauth_client_.reset();
+ current_request_->error_callback.Run(response);
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void DeviceCapabilityManager::ProcessRequestQueue() {
+ if (current_request_ || pending_requests_.empty())
+ return;
+
+ current_request_ = std::move(pending_requests_.front());
+ pending_requests_.pop();
+
+ switch (current_request_->request_type) {
+ case RequestType::SET_CAPABILITY_ENABLED:
+ ProcessSetCapabilityEnabledRequest();
+ return;
+ case RequestType::FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY:
+ ProcessFindEligibleDevicesForCapability();
+ return;
+ case RequestType::IS_CAPABILITY_PROMOTABLE:
+ ProcessIsCapabilityPromotableRequest();
+ return;
+ default:
+ NOTREACHED();
+ return;
+ }
+}
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/device_capability_manager.h b/chromium/components/cryptauth/device_capability_manager.h
new file mode 100644
index 00000000000..4a40037c67b
--- /dev/null
+++ b/chromium/components/cryptauth/device_capability_manager.h
@@ -0,0 +1,143 @@
+// 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_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
+#define COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
+
+#include <queue>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "components/cryptauth/cryptauth_client.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+// DeviceCapabilityManager sends requests to the back-end which enable/disable
+// device capabilities and finds devices which contain those capabilities. Here,
+// the term "capability" refers to the ability of a device to use a given
+// feature (e.g. EasyUnlock or Magic Tether).
+class DeviceCapabilityManager {
+ public:
+ // CAPABILITY_UNLOCK_KEY refers to EasyUnlock.
+ enum class Capability { CAPABILITY_UNLOCK_KEY };
+
+ DeviceCapabilityManager(CryptAuthClientFactory* cryptauth_client_factory);
+
+ ~DeviceCapabilityManager();
+
+ // Enables or disables |capability| for the device corresponding to
+ // |public_key|. In error cases, |error_callback| is invoked with an error
+ // string.
+ void SetCapabilityEnabled(
+ const std::string& public_key,
+ Capability capability,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ // Fetches metadata about the device which are eligible for |capability|. In
+ // error cases, |error_callback| is invoked with an error string.
+ void FindEligibleDevicesForCapability(
+ Capability capability,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ // Determines whether a device with |public_key| is promotable for
+ // |capability|. In error cases, |error_callback| is invoked with an error
+ // string.
+ void IsCapabilityPromotable(
+ const std::string& public_key,
+ Capability capability,
+ const base::Callback<void(bool)>& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ private:
+ enum class RequestType {
+ SET_CAPABILITY_ENABLED,
+ FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY,
+ IS_CAPABILITY_PROMOTABLE
+ };
+
+ struct Request {
+ // Used for SET_CAPABILITY_ENABLED Requests.
+ Request(RequestType request_type,
+ Capability capability,
+ std::string public_key,
+ bool enabled,
+ const base::Closure& set_capability_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ // Used for FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY Requests.
+ Request(RequestType request_type,
+ Capability capability,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ find_eligible_devices_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ // Used for IS_CAPABILITY_PROMOTABLE Requests.
+ Request(RequestType request_type,
+ Capability capability,
+ std::string public_key,
+ const base::Callback<void(bool)> is_device_promotable_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+
+ ~Request();
+
+ // Defined for every request.
+ RequestType request_type;
+ base::Callback<void(const std::string&)> error_callback;
+ Capability capability;
+
+ // Defined for SET_CAPABILITY_ENABLED and IS_CAPABILITY_PROMOTABLE;
+ // otherwise, unused.
+ std::string public_key;
+
+ // Defined if |request_type_| is SET_CAPABILITY_ENABLED; otherwise, unused.
+ base::Closure set_capability_callback;
+ bool enabled;
+
+ // Defined if |request_type_| is FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY;
+ // otherwise, unused.
+ base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>
+ find_eligible_devices_callback;
+
+ // Defined if |request_type_| is IS_CAPABILITY_PROMOTABLE; otherwise,
+ // unused.
+ base::Callback<void(bool)> is_device_promotable_callback;
+ };
+
+ void CreateNewCryptAuthClient();
+
+ void ProcessSetCapabilityEnabledRequest();
+ void ProcessFindEligibleDevicesForCapability();
+ void ProcessIsCapabilityPromotableRequest();
+
+ void SetUnlockKeyCapability();
+ void FindEligibleUnlockDevices();
+ void IsDeviceUnlockPromotable();
+
+ void OnToggleEasyUnlockResponse(const ToggleEasyUnlockResponse& response);
+ void OnFindEligibleUnlockDevicesResponse(
+ const FindEligibleUnlockDevicesResponse& response);
+ void OnIsDeviceUnlockPromotableResponse(
+ const FindEligibleForPromotionResponse& response);
+ void OnErrorResponse(const std::string& response);
+ void ProcessRequestQueue();
+
+ std::unique_ptr<CryptAuthClient> current_cryptauth_client_;
+ std::unique_ptr<Request> current_request_;
+ std::queue<std::unique_ptr<Request>> pending_requests_;
+ CryptAuthClientFactory* crypt_auth_client_factory_;
+ base::WeakPtrFactory<DeviceCapabilityManager> weak_ptr_factory_;
+};
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
diff --git a/chromium/components/cryptauth/device_capability_manager_unittest.cc b/chromium/components/cryptauth/device_capability_manager_unittest.cc
new file mode 100644
index 00000000000..4f89d7ebf27
--- /dev/null
+++ b/chromium/components/cryptauth/device_capability_manager_unittest.cc
@@ -0,0 +1,417 @@
+// 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/cryptauth/device_capability_manager.h"
+
+#include <stddef.h>
+
+#include <chrono>
+#include <memory>
+#include <thread>
+#include <unordered_set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "components/cryptauth/mock_cryptauth_client.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+
+namespace cryptauth {
+
+namespace {
+
+const char kSuccessResult[] = "success";
+const char kErrorOnToggleEasyUnlockResult[] = "toggleEasyUnlockError";
+const char kErrorFindEligibleUnlockDevices[] = "findEligibleUnlockDeviceError";
+const char kErrorFindEligibleForPromotion[] = "findEligibleForPromotionError";
+const std::string kTestErrorCodeTogglingIneligibleDevice =
+ "togglingIneligibleDevice.";
+
+std::vector<cryptauth::ExternalDeviceInfo>
+CreateExternalDeviceInfosForRemoteDevices(
+ const std::vector<cryptauth::RemoteDevice> remote_devices) {
+ std::vector<cryptauth::ExternalDeviceInfo> device_infos;
+ for (const auto& remote_device : remote_devices) {
+ // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
+ cryptauth::ExternalDeviceInfo info;
+ info.set_public_key(remote_device.public_key);
+ device_infos.push_back(info);
+ }
+ return device_infos;
+}
+
+} // namespace
+
+class DeviceCapabilityManagerTest
+ : public testing::Test,
+ public MockCryptAuthClientFactory::Observer {
+ public:
+ DeviceCapabilityManagerTest()
+ : all_test_external_device_infos_(
+ CreateExternalDeviceInfosForRemoteDevices(
+ cryptauth::GenerateTestRemoteDevices(5))),
+ test_eligible_external_devices_infos_(
+ {all_test_external_device_infos_[0],
+ all_test_external_device_infos_[1],
+ all_test_external_device_infos_[2]}),
+ test_ineligible_external_devices_infos_(
+ {all_test_external_device_infos_[3],
+ all_test_external_device_infos_[4]}) {}
+
+ void SetUp() override {
+ mock_cryptauth_client_factory_ =
+ base::MakeUnique<MockCryptAuthClientFactory>(
+ MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
+ mock_cryptauth_client_factory_->AddObserver(this);
+ device_capability_manager_ = base::MakeUnique<DeviceCapabilityManager>(
+ mock_cryptauth_client_factory_.get());
+ }
+
+ void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
+ ON_CALL(*client, ToggleEasyUnlock(_, _, _))
+ .WillByDefault(
+ Invoke(this, &DeviceCapabilityManagerTest::MockToggleEasyUnlock));
+ ON_CALL(*client, FindEligibleUnlockDevices(_, _, _))
+ .WillByDefault(Invoke(
+ this, &DeviceCapabilityManagerTest::MockFindEligibleUnlockDevices));
+ ON_CALL(*client, FindEligibleForPromotion(_, _, _))
+ .WillByDefault(Invoke(
+ this, &DeviceCapabilityManagerTest::MockFindEligibleForPromotion));
+ }
+
+ // Mock CryptAuthClient::ToggleEasyUnlock() implementation.
+ void MockToggleEasyUnlock(
+ const ToggleEasyUnlockRequest& request,
+ const CryptAuthClient::ToggleEasyUnlockCallback& callback,
+ const CryptAuthClient::ErrorCallback& error_callback) {
+ toggle_easy_unlock_callback_ = callback;
+ error_callback_ = error_callback;
+ error_code_ = kErrorOnToggleEasyUnlockResult;
+ }
+
+ // Mock CryptAuthClient::FindEligibleUnlockDevices() implementation.
+ void MockFindEligibleUnlockDevices(
+ const FindEligibleUnlockDevicesRequest& request,
+ const CryptAuthClient::FindEligibleUnlockDevicesCallback& callback,
+ const CryptAuthClient::ErrorCallback& error_callback) {
+ find_eligible_unlock_devices_callback_ = callback;
+ error_callback_ = error_callback;
+ error_code_ = kErrorFindEligibleUnlockDevices;
+ }
+
+ // Mock CryptAuthClient::FindEligibleForPromotion() implementation.
+ void MockFindEligibleForPromotion(
+ const FindEligibleForPromotionRequest& request,
+ const CryptAuthClient::FindEligibleForPromotionCallback& callback,
+ const CryptAuthClient::ErrorCallback& error_callback) {
+ find_eligible_for_promotion_callback_ = callback;
+ error_callback_ = error_callback;
+ error_code_ = kErrorFindEligibleForPromotion;
+ }
+
+ FindEligibleUnlockDevicesResponse CreateFindEligibleUnlockDevicesResponse() {
+ FindEligibleUnlockDevicesResponse find_eligible_unlock_devices_response;
+ for (const auto& device_info : test_eligible_external_devices_infos_) {
+ find_eligible_unlock_devices_response.add_eligible_devices()->CopyFrom(
+ device_info);
+ }
+ for (const auto& device_info : test_ineligible_external_devices_infos_) {
+ find_eligible_unlock_devices_response.add_ineligible_devices()
+ ->mutable_device()
+ ->CopyFrom(device_info);
+ }
+ return find_eligible_unlock_devices_response;
+ }
+
+ void VerifyDeviceEligibility() {
+ // Ensure that resulting devices are not empty. Otherwise, following for
+ // loop checks will succeed on empty resulting devices.
+ EXPECT_TRUE(result_eligible_devices_.size() > 0);
+ EXPECT_TRUE(result_ineligible_devices_.size() > 0);
+ for (const auto& device_info : result_eligible_devices_) {
+ EXPECT_TRUE(
+ std::find_if(
+ test_eligible_external_devices_infos_.begin(),
+ test_eligible_external_devices_infos_.end(),
+ [&device_info](const cryptauth::ExternalDeviceInfo& device) {
+ return device.public_key() == device_info.public_key();
+ }) != test_eligible_external_devices_infos_.end());
+ }
+ for (const auto& ineligible_device : result_ineligible_devices_) {
+ EXPECT_TRUE(
+ std::find_if(test_ineligible_external_devices_infos_.begin(),
+ test_ineligible_external_devices_infos_.end(),
+ [&ineligible_device](
+ const cryptauth::ExternalDeviceInfo& device) {
+ return device.public_key() ==
+ ineligible_device.device().public_key();
+ }) != test_ineligible_external_devices_infos_.end());
+ }
+ result_eligible_devices_.clear();
+ result_ineligible_devices_.clear();
+ }
+
+ void SetCapabilityEnabled(DeviceCapabilityManager::Capability capability,
+ const ExternalDeviceInfo& device_info,
+ bool enable) {
+ device_capability_manager_->SetCapabilityEnabled(
+ device_info.public_key(), capability, enable,
+ base::Bind(&DeviceCapabilityManagerTest::
+ TestSuccessSetCapabilityKeyUnlockCallback,
+ base::Unretained(this)),
+ base::Bind(&DeviceCapabilityManagerTest::TestErrorCallback,
+ base::Unretained(this)));
+ }
+
+ void FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability capability) {
+ device_capability_manager_->FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ base::Bind(&DeviceCapabilityManagerTest::
+ TestSuccessFindEligibleUnlockDevicesCallback,
+ base::Unretained(this)),
+ base::Bind(&DeviceCapabilityManagerTest::TestErrorCallback,
+ base::Unretained(this)));
+ }
+
+ void IsPromotableDevice(DeviceCapabilityManager::Capability capability,
+ const std::string& public_key) {
+ device_capability_manager_->IsCapabilityPromotable(
+ public_key, capability,
+ base::Bind(&DeviceCapabilityManagerTest::
+ TestSuccessFindEligibleForPromotionDeviceCallback,
+ base::Unretained(this)),
+ base::Bind(&DeviceCapabilityManagerTest::TestErrorCallback,
+ base::Unretained(this)));
+ }
+
+ void TestSuccessSetCapabilityKeyUnlockCallback() { result_ = kSuccessResult; }
+
+ void TestSuccessFindEligibleUnlockDevicesCallback(
+ const std::vector<ExternalDeviceInfo>& eligible_devices,
+ const std::vector<IneligibleDevice>& ineligible_devices) {
+ result_ = kSuccessResult;
+ result_eligible_devices_ = eligible_devices;
+ result_ineligible_devices_ = ineligible_devices;
+ }
+
+ void TestSuccessFindEligibleForPromotionDeviceCallback(bool eligible) {
+ result_ = kSuccessResult;
+ result_eligible_for_promotion_ = eligible;
+ }
+
+ void TestErrorCallback(const std::string& error_message) {
+ result_ = error_message;
+ }
+
+ void InvokeSetCapabilityKeyUnlockCallback() {
+ CryptAuthClient::ToggleEasyUnlockCallback success_callback =
+ toggle_easy_unlock_callback_;
+ ASSERT_TRUE(!success_callback.is_null());
+ toggle_easy_unlock_callback_.Reset();
+ success_callback.Run(ToggleEasyUnlockResponse());
+ }
+
+ void InvokeFindEligibleUnlockDevicesCallback(
+ const FindEligibleUnlockDevicesResponse& retrieved_devices_response) {
+ CryptAuthClient::FindEligibleUnlockDevicesCallback success_callback =
+ find_eligible_unlock_devices_callback_;
+ ASSERT_TRUE(!success_callback.is_null());
+ find_eligible_unlock_devices_callback_.Reset();
+ success_callback.Run(retrieved_devices_response);
+ }
+
+ void InvokeFindEligibleForPromotionCallback(bool eligible_for_promotion) {
+ FindEligibleForPromotionResponse response;
+ response.set_may_show_promo(eligible_for_promotion);
+ CryptAuthClient::FindEligibleForPromotionCallback success_callback =
+ find_eligible_for_promotion_callback_;
+ ASSERT_TRUE(!success_callback.is_null());
+ find_eligible_for_promotion_callback_.Reset();
+ success_callback.Run(response);
+ }
+
+ void InvokeErrorCallback() {
+ CryptAuthClient::ErrorCallback error_callback = error_callback_;
+ ASSERT_TRUE(!error_callback.is_null());
+ error_callback_.Reset();
+ error_callback.Run(error_code_);
+ }
+
+ std::string GetResultAndReset() {
+ std::string result;
+ result.swap(result_);
+ return result;
+ }
+
+ bool GetEligibleForPromotionAndReset() {
+ bool result_eligible_for_promotion = result_eligible_for_promotion_;
+ result_eligible_for_promotion_ = false;
+ return result_eligible_for_promotion;
+ }
+
+ const std::vector<cryptauth::ExternalDeviceInfo>
+ all_test_external_device_infos_;
+ const std::vector<ExternalDeviceInfo> test_eligible_external_devices_infos_;
+ const std::vector<ExternalDeviceInfo> test_ineligible_external_devices_infos_;
+
+ std::unique_ptr<MockCryptAuthClientFactory> mock_cryptauth_client_factory_;
+ std::unique_ptr<cryptauth::DeviceCapabilityManager>
+ device_capability_manager_;
+ CryptAuthClient::ToggleEasyUnlockCallback toggle_easy_unlock_callback_;
+ CryptAuthClient::FindEligibleUnlockDevicesCallback
+ find_eligible_unlock_devices_callback_;
+ CryptAuthClient::FindEligibleForPromotionCallback
+ find_eligible_for_promotion_callback_;
+ CryptAuthClient::ErrorCallback error_callback_;
+
+ // Used by all tests that involve CryptauthClient network calls internally.
+ // Network call statuses are mocked out in place by |result_| and
+ // |error_code_| to keep track of the order in which DevicaCapabilityManager
+ // functions are called.
+ std::string result_;
+ std::string error_code_;
+ // For FindEligibleUnlockDevice tests.
+ std::vector<ExternalDeviceInfo> result_eligible_devices_;
+ std::vector<IneligibleDevice> result_ineligible_devices_;
+ // For FindEligibleForPromotion tests.
+ bool result_eligible_for_promotion_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceCapabilityManagerTest);
+};
+
+TEST_F(DeviceCapabilityManagerTest, TestOrderUponMultipleRequests) {
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0], true /* enable */);
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0].public_key());
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[1], true /* enable */);
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[1].public_key());
+
+ InvokeSetCapabilityKeyUnlockCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ InvokeFindEligibleUnlockDevicesCallback(
+ CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+
+ InvokeFindEligibleForPromotionCallback(true /* eligible */);
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ EXPECT_TRUE(GetEligibleForPromotionAndReset());
+
+ InvokeSetCapabilityKeyUnlockCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ InvokeFindEligibleUnlockDevicesCallback(
+ CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+
+ InvokeFindEligibleForPromotionCallback(true /* eligible */);
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ EXPECT_TRUE(GetEligibleForPromotionAndReset());
+}
+
+TEST_F(DeviceCapabilityManagerTest, TestMultipleSetUnlocksRequests) {
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0], true /* enable */);
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[1], true /* enable */);
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[2], true /* enable */);
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorOnToggleEasyUnlockResult, GetResultAndReset());
+
+ InvokeSetCapabilityKeyUnlockCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ InvokeSetCapabilityKeyUnlockCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+}
+
+TEST_F(DeviceCapabilityManagerTest,
+ TestMultipleFindEligibleForUnlockDevicesRequests) {
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+
+ InvokeFindEligibleUnlockDevicesCallback(
+ CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleUnlockDevices, GetResultAndReset());
+
+ InvokeFindEligibleUnlockDevicesCallback(
+ CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+}
+
+TEST_F(DeviceCapabilityManagerTest, TestMultipleIsPromotableRequests) {
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0].public_key());
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[1].public_key());
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[2].public_key());
+
+ InvokeFindEligibleForPromotionCallback(true /*eligible*/);
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ EXPECT_TRUE(GetEligibleForPromotionAndReset());
+
+ InvokeFindEligibleForPromotionCallback(true /*eligible*/);
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ EXPECT_TRUE(GetEligibleForPromotionAndReset());
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleForPromotion, GetResultAndReset());
+}
+
+TEST_F(DeviceCapabilityManagerTest, TestOrderViaMultipleErrors) {
+ SetCapabilityEnabled(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0], true /* enable */);
+ FindEligibleDevicesForCapability(
+ DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY);
+ IsPromotableDevice(DeviceCapabilityManager::Capability::CAPABILITY_UNLOCK_KEY,
+ test_eligible_external_devices_infos_[0].public_key());
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorOnToggleEasyUnlockResult, GetResultAndReset());
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleUnlockDevices, GetResultAndReset());
+
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleForPromotion, GetResultAndReset());
+}
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_provider.cc b/chromium/components/cryptauth/remote_device_provider.cc
new file mode 100644
index 00000000000..1e9b34730c4
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_provider.cc
@@ -0,0 +1,79 @@
+// 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/cryptauth/remote_device_provider.h"
+
+#include "base/bind.h"
+#include "components/cryptauth/remote_device_loader.h"
+#include "components/cryptauth/secure_message_delegate.h"
+
+namespace cryptauth {
+
+RemoteDeviceProvider::RemoteDeviceProvider(
+ CryptAuthDeviceManager* device_manager,
+ const std::string& user_id,
+ const std::string& user_private_key,
+ SecureMessageDelegateFactory* secure_message_delegate_factory)
+ : device_manager_(device_manager),
+ user_id_(user_id),
+ user_private_key_(user_private_key),
+ secure_message_delegate_factory_(secure_message_delegate_factory),
+ weak_ptr_factory_(this) {
+ device_manager_->AddObserver(this);
+ remote_device_loader_ = cryptauth::RemoteDeviceLoader::Factory::NewInstance(
+ device_manager->GetSyncedDevices(), user_id, user_private_key,
+ secure_message_delegate_factory->CreateSecureMessageDelegate());
+ remote_device_loader_->Load(
+ false /* should_load_beacon_seeds */,
+ base::Bind(&RemoteDeviceProvider::OnRemoteDevicesLoaded,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+RemoteDeviceProvider::~RemoteDeviceProvider() {
+ device_manager_->RemoveObserver(this);
+}
+
+void RemoteDeviceProvider::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RemoteDeviceProvider::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RemoteDeviceProvider::OnSyncFinished(
+ CryptAuthDeviceManager::SyncResult sync_result,
+ CryptAuthDeviceManager::DeviceChangeResult device_change_result) {
+ if (sync_result == CryptAuthDeviceManager::SyncResult::SUCCESS &&
+ device_change_result ==
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED) {
+ remote_device_loader_ = cryptauth::RemoteDeviceLoader::Factory::NewInstance(
+ device_manager_->GetSyncedDevices(), user_id_, user_private_key_,
+ secure_message_delegate_factory_->CreateSecureMessageDelegate());
+
+ remote_device_loader_->Load(
+ false /* should_load_beacon_seeds */,
+ base::Bind(&RemoteDeviceProvider::OnRemoteDevicesLoaded,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void RemoteDeviceProvider::OnRemoteDevicesLoaded(
+ const RemoteDeviceList& synced_remote_devices) {
+ synced_remote_devices_ = synced_remote_devices;
+ remote_device_loader_.reset();
+
+ // Notify observers of change. Note that there is no need to check if
+ // |synced_remote_devices_| has changed here because the fetch is only started
+ // if the change result passed to OnSyncFinished() is CHANGED.
+ for (auto& observer : observers_) {
+ observer.OnSyncDeviceListChanged();
+ }
+}
+
+const RemoteDeviceList RemoteDeviceProvider::GetSyncedDevices() const {
+ return synced_remote_devices_;
+}
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_provider.h b/chromium/components/cryptauth/remote_device_provider.h
new file mode 100644
index 00000000000..133fdfb74ea
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_provider.h
@@ -0,0 +1,78 @@
+// 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_CRYPTAUTH_REMOTE_DEVICE_PROVIDER_H_
+#define COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_PROVIDER_H_
+
+#include "components/cryptauth/cryptauth_device_manager.h"
+#include "components/cryptauth/remote_device.h"
+
+namespace cryptauth {
+
+class RemoteDeviceLoader;
+class SecureMessageDelegate;
+
+// TODO(khorimoto): Move SecureMessageDelegateFactory to another file.
+class SecureMessageDelegateFactory {
+ public:
+ virtual std::unique_ptr<SecureMessageDelegate>
+ CreateSecureMessageDelegate() = 0;
+ virtual ~SecureMessageDelegateFactory(){};
+};
+
+// This class generates and caches RemoteDevice objects when associated metadata
+// has been synced, and updates this cache when a new sync occurs.
+class RemoteDeviceProvider : public CryptAuthDeviceManager::Observer {
+ public:
+ class Observer {
+ public:
+ virtual void OnSyncDeviceListChanged() {}
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ RemoteDeviceProvider(
+ CryptAuthDeviceManager* device_manager,
+ const std::string& user_id,
+ const std::string& user_private_key,
+ SecureMessageDelegateFactory* secure_message_delegate_factory);
+
+ ~RemoteDeviceProvider() override;
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Returns a list of all RemoteDevices that have been synced.
+ const RemoteDeviceList GetSyncedDevices() const;
+
+ // CryptAuthDeviceManager::Observer:
+ void OnSyncFinished(
+ CryptAuthDeviceManager::SyncResult sync_result,
+ CryptAuthDeviceManager::DeviceChangeResult device_change_result) override;
+
+ private:
+ void OnRemoteDevicesLoaded(const RemoteDeviceList& synced_remote_devices);
+
+ // To get ExternalDeviceInfo needed to retrieve RemoteDevices.
+ CryptAuthDeviceManager* device_manager_;
+
+ // The account ID of the current user.
+ const std::string user_id_;
+
+ // The private key used to generate RemoteDevices.
+ const std::string user_private_key_;
+
+ SecureMessageDelegateFactory* secure_message_delegate_factory_;
+ std::unique_ptr<RemoteDeviceLoader> remote_device_loader_;
+ RemoteDeviceList synced_remote_devices_;
+ base::ObserverList<Observer> observers_;
+ base::WeakPtrFactory<RemoteDeviceProvider> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteDeviceProvider);
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_PROVIDER_H_
diff --git a/chromium/components/cryptauth/remote_device_provider_unittest.cc b/chromium/components/cryptauth/remote_device_provider_unittest.cc
new file mode 100644
index 00000000000..cde5644a748
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_provider_unittest.cc
@@ -0,0 +1,347 @@
+// 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/cryptauth/remote_device_provider.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "components/cryptauth/cryptauth_device_manager.h"
+#include "components/cryptauth/fake_secure_message_delegate.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/remote_device_loader.h"
+#include "components/cryptauth/remote_device_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+
+namespace cryptauth {
+
+namespace {
+
+const char kTestUserId[] = "testUserId";
+const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
+
+class MockCryptAuthDeviceManager : public cryptauth::CryptAuthDeviceManager {
+ public:
+ ~MockCryptAuthDeviceManager() override {}
+
+ void NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult sync_result,
+ CryptAuthDeviceManager::DeviceChangeResult device_change_result) {
+ cryptauth::CryptAuthDeviceManager::NotifySyncFinished(sync_result,
+ device_change_result);
+ }
+
+ MOCK_CONST_METHOD0(GetSyncedDevices,
+ std::vector<::cryptauth::ExternalDeviceInfo>());
+};
+
+class FakeSecureMessageDelegateFactory
+ : public cryptauth::SecureMessageDelegateFactory {
+ public:
+ // cryptauth::SecureMessageDelegateFactory:
+ std::unique_ptr<cryptauth::SecureMessageDelegate>
+ CreateSecureMessageDelegate() override {
+ cryptauth::FakeSecureMessageDelegate* delegate =
+ new cryptauth::FakeSecureMessageDelegate();
+ created_delegates_.push_back(delegate);
+ return base::WrapUnique(delegate);
+ }
+
+ private:
+ std::vector<cryptauth::FakeSecureMessageDelegate*> created_delegates_;
+};
+
+std::vector<cryptauth::ExternalDeviceInfo>
+CreateExternalDeviceInfosForRemoteDevices(
+ const std::vector<cryptauth::RemoteDevice> remote_devices) {
+ std::vector<cryptauth::ExternalDeviceInfo> device_infos;
+ for (const auto& remote_device : remote_devices) {
+ // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
+ cryptauth::ExternalDeviceInfo info;
+ info.set_public_key(remote_device.public_key);
+ device_infos.push_back(info);
+ }
+ return device_infos;
+}
+
+class TestObserver : public RemoteDeviceProvider::Observer {
+ public:
+ TestObserver() {}
+ ~TestObserver() override {}
+
+ int num_times_device_list_changed() { return num_times_device_list_changed_; }
+
+ // RemoteDeviceProvider::Observer:
+ void OnSyncDeviceListChanged() override { num_times_device_list_changed_++; }
+
+ private:
+ int num_times_device_list_changed_ = 0;
+};
+
+} // namespace
+
+class FakeDeviceLoader final : public cryptauth::RemoteDeviceLoader {
+ public:
+ class TestRemoteDeviceLoaderFactory final
+ : public RemoteDeviceLoader::Factory {
+ public:
+ explicit TestRemoteDeviceLoaderFactory()
+ : test_devices_(cryptauth::GenerateTestRemoteDevices(5)),
+ test_device_infos_(
+ CreateExternalDeviceInfosForRemoteDevices(test_devices_)) {}
+
+ ~TestRemoteDeviceLoaderFactory() {}
+
+ std::unique_ptr<RemoteDeviceLoader> BuildInstance(
+ const std::vector<cryptauth::ExternalDeviceInfo>& device_info_list,
+ const std::string& user_id,
+ const std::string& user_private_key,
+ std::unique_ptr<cryptauth::SecureMessageDelegate>
+ secure_message_delegate) override {
+ EXPECT_EQ(std::string(kTestUserId), user_id);
+ EXPECT_EQ(std::string(kTestUserPrivateKey), user_private_key);
+ std::unique_ptr<FakeDeviceLoader> device_loader =
+ base::MakeUnique<FakeDeviceLoader>();
+ device_loader->remote_device_loader_factory_ = this;
+ return std::move(device_loader);
+ }
+
+ void InvokeLastCallback(
+ const std::vector<cryptauth::ExternalDeviceInfo>& device_info_list) {
+ ASSERT_TRUE(!callback_.is_null());
+ // Fetch only the devices inserted by tests, since test_devices_ contains
+ // all available devices.
+ std::vector<RemoteDevice> devices;
+ for (const auto& remote_device : test_devices_) {
+ for (const auto& external_device_info : device_info_list) {
+ if (remote_device.public_key == external_device_info.public_key())
+ devices.push_back(remote_device);
+ }
+ }
+ callback_.Run(devices);
+ callback_.Reset();
+ }
+
+ // Fetch is only started if the change result passed to OnSyncFinished() is
+ // CHANGED and sync is SUCCESS.
+ bool HasQueuedCallback() { return !callback_.is_null(); }
+ const std::vector<cryptauth::RemoteDevice> test_devices_;
+ const std::vector<cryptauth::ExternalDeviceInfo> test_device_infos_;
+
+ void QueueCallback(const RemoteDeviceCallback& callback) {
+ callback_ = callback;
+ }
+
+ private:
+ cryptauth::RemoteDeviceLoader::RemoteDeviceCallback callback_;
+ };
+
+ FakeDeviceLoader()
+ : cryptauth::RemoteDeviceLoader(
+ std::vector<cryptauth::ExternalDeviceInfo>(),
+ "",
+ "",
+ nullptr) {}
+
+ ~FakeDeviceLoader() override {}
+
+ TestRemoteDeviceLoaderFactory* remote_device_loader_factory_;
+
+ void Load(bool should_load_beacon_seeds,
+ const RemoteDeviceCallback& callback) override {
+ remote_device_loader_factory_->QueueCallback(callback);
+ }
+};
+
+class RemoteDeviceProviderTest : public testing::Test {
+ public:
+ RemoteDeviceProviderTest() {}
+
+ void SetUp() override {
+ mock_device_manager_ =
+ base::WrapUnique(new NiceMock<MockCryptAuthDeviceManager>());
+ ON_CALL(*mock_device_manager_, GetSyncedDevices())
+ .WillByDefault(Invoke(
+ this, &RemoteDeviceProviderTest::mock_device_manager_sync_devices));
+ fake_secure_message_delegate_factory_ =
+ base::MakeUnique<FakeSecureMessageDelegateFactory>();
+ test_device_loader_factory_ =
+ base::MakeUnique<FakeDeviceLoader::TestRemoteDeviceLoaderFactory>();
+ cryptauth::RemoteDeviceLoader::Factory::SetInstanceForTesting(
+ test_device_loader_factory_.get());
+ test_observer_ = base::MakeUnique<TestObserver>();
+ }
+
+ void CreateRemoteDeviceProvider() {
+ remote_device_provider_ = base::MakeUnique<RemoteDeviceProvider>(
+ mock_device_manager_.get(), kTestUserId, kTestUserPrivateKey,
+ fake_secure_message_delegate_factory_.get());
+ remote_device_provider_->AddObserver(test_observer_.get());
+ EXPECT_EQ(0u, remote_device_provider_->GetSyncedDevices().size());
+ test_device_loader_factory_->InvokeLastCallback(
+ mock_device_manager_synced_device_infos_);
+ VerifySyncedDevicesMatchExpectation(
+ mock_device_manager_synced_device_infos_.size());
+ }
+
+ void VerifySyncedDevicesMatchExpectation(size_t expected_size) {
+ std::vector<cryptauth::RemoteDevice> synced_devices =
+ remote_device_provider_->GetSyncedDevices();
+ EXPECT_EQ(expected_size, synced_devices.size());
+ EXPECT_EQ(expected_size, mock_device_manager_sync_devices().size());
+ std::unordered_set<std::string> public_keys;
+ for (const auto& device_info : mock_device_manager_synced_device_infos_) {
+ public_keys.insert(device_info.public_key());
+ }
+ for (const auto& remote_device : synced_devices) {
+ EXPECT_TRUE(public_keys.find(remote_device.public_key) !=
+ public_keys.end());
+ }
+ }
+
+ // This is the mock implementation of mock_device_manager_'s
+ // GetSyncedDevices().
+ std::vector<ExternalDeviceInfo> mock_device_manager_sync_devices() {
+ return mock_device_manager_synced_device_infos_;
+ }
+
+ std::vector<cryptauth::RemoteDevice> test_devices() {
+ return test_device_loader_factory_->test_devices_;
+ }
+
+ ExternalDeviceInfo test_device_infos_(int val) {
+ return test_device_loader_factory_->test_device_infos_[val];
+ }
+
+ std::vector<cryptauth::ExternalDeviceInfo>
+ mock_device_manager_synced_device_infos_;
+
+ std::unique_ptr<FakeSecureMessageDelegateFactory>
+ fake_secure_message_delegate_factory_;
+
+ std::unique_ptr<NiceMock<MockCryptAuthDeviceManager>> mock_device_manager_;
+
+ std::unique_ptr<FakeDeviceLoader::TestRemoteDeviceLoaderFactory>
+ test_device_loader_factory_;
+
+ std::unique_ptr<RemoteDeviceProvider> remote_device_provider_;
+
+ std::unique_ptr<TestObserver> test_observer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteDeviceProviderTest);
+};
+
+TEST_F(RemoteDeviceProviderTest, TestMultipleSyncs) {
+ // Initialize with devices 0 and 1.
+ mock_device_manager_synced_device_infos_ = std::vector<ExternalDeviceInfo>{
+ test_device_infos_(0), test_device_infos_(1)};
+ CreateRemoteDeviceProvider();
+ VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+
+ // Now add device 2 and trigger another sync.
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(2));
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ test_device_loader_factory_->InvokeLastCallback(
+ mock_device_manager_synced_device_infos_);
+ VerifySyncedDevicesMatchExpectation(3u /* expected_size */);
+ EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
+
+ // Now, simulate a sync which shows that device 0 was removed.
+ mock_device_manager_synced_device_infos_.erase(
+ mock_device_manager_synced_device_infos_.begin());
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ test_device_loader_factory_->InvokeLastCallback(
+ mock_device_manager_synced_device_infos_);
+ VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
+ EXPECT_EQ(3, test_observer_->num_times_device_list_changed());
+}
+
+TEST_F(RemoteDeviceProviderTest, TestNotifySyncFinishedParameterCombinations) {
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(0));
+ CreateRemoteDeviceProvider();
+ VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::FAILURE,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
+ VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
+ EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
+ VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::FAILURE,
+ CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
+ EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
+ VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(1));
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ test_device_loader_factory_->InvokeLastCallback(
+ mock_device_manager_synced_device_infos_);
+ VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
+ EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
+}
+
+TEST_F(RemoteDeviceProviderTest, TestNewSyncDuringDeviceRegeneration) {
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(0));
+ CreateRemoteDeviceProvider();
+ VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
+
+ // Add device 1 and trigger a sync.
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(1));
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+
+ // Do not wait for the new devices to be generated (i.e., don't call
+ // test_device_loader_factory_->InvokeLastCallback() yet). Trigger a new
+ // sync with device 2 included.
+ mock_device_manager_synced_device_infos_.push_back(test_device_infos_(2));
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
+ test_device_loader_factory_->InvokeLastCallback(
+ mock_device_manager_synced_device_infos_);
+ VerifySyncedDevicesMatchExpectation(3u /* expected_size */);
+ EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
+}
+
+TEST_F(RemoteDeviceProviderTest, TestZeroSyncedDevices) {
+ CreateRemoteDeviceProvider();
+ VerifySyncedDevicesMatchExpectation(0 /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+ mock_device_manager_->NotifySyncFinished(
+ CryptAuthDeviceManager::SyncResult::SUCCESS,
+ CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
+ EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
+ VerifySyncedDevicesMatchExpectation(0 /* expected_size */);
+ EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/secure_channel_unittest.cc b/chromium/components/cryptauth/secure_channel_unittest.cc
index 97156a48374..5a45beb81a3 100644
--- a/chromium/components/cryptauth/secure_channel_unittest.cc
+++ b/chromium/components/cryptauth/secure_channel_unittest.cc
@@ -42,7 +42,7 @@ struct ReceivedMessage {
std::string payload;
};
-class TestObserver : public SecureChannel::Observer {
+class TestObserver final : public SecureChannel::Observer {
public:
TestObserver(SecureChannel* secure_channel)
: secure_channel_(secure_channel) {}
@@ -91,7 +91,7 @@ class TestObserver : public SecureChannel::Observer {
// Observer used in the ObserverDeletesChannel test. This Observer deletes the
// SecureChannel when it receives an OnMessageSent() call.
-class DeletingObserver : public SecureChannel::Observer {
+class DeletingObserver final : public SecureChannel::Observer {
public:
DeletingObserver(std::unique_ptr<SecureChannel>* secure_channel)
: secure_channel_(secure_channel) {}
@@ -117,7 +117,8 @@ class DeletingObserver : public SecureChannel::Observer {
std::unique_ptr<SecureChannel>* secure_channel_;
};
-class TestAuthenticatorFactory : public DeviceToDeviceAuthenticator::Factory {
+class TestAuthenticatorFactory final
+ : public DeviceToDeviceAuthenticator::Factory {
public:
TestAuthenticatorFactory() : last_instance_(nullptr) {}
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
index 013475c4942..e8351437455 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
@@ -29,23 +29,14 @@ ContentLoFiDecider::~ContentLoFiDecider() {}
bool ContentLoFiDecider::IsUsingLoFi(const net::URLRequest& request) const {
const content::ResourceRequestInfo* request_info =
content::ResourceRequestInfo::ForRequest(&request);
- // The Lo-Fi directive should not be added for users in the Lo-Fi field
- // trial "Control" group. Check that the user is in a group that can get
- // "q=low".
- bool lofi_enabled_via_flag_or_field_trial =
- params::IsLoFiOnViaFlags() || params::IsIncludedInLoFiEnabledFieldTrial();
-
- // Return if the user is using Lo-Fi and not part of the "Control" group.
- if (request_info) {
- return (request_info->GetPreviewsState() & content::SERVER_LOFI_ON) &&
- lofi_enabled_via_flag_or_field_trial;
- }
- return false;
+ if (!request_info)
+ return false;
+
+ return (request_info->GetPreviewsState() & content::SERVER_LOFI_ON);
}
void ContentLoFiDecider::MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
- bool are_previews_disabled,
net::HttpRequestHeaders* headers) const {
const content::ResourceRequestInfo* request_info =
content::ResourceRequestInfo::ForRequest(&request);
@@ -78,89 +69,28 @@ void ContentLoFiDecider::MaybeSetAcceptTransformHeader(
return;
}
- // For the proxy-decides-transform feature, the header is set based only
- // on the request's PreviewsState (no checking of previews flags).
- // This is for a newer version of the proxy server protocol where the
- // server makes the transform decision and client simply advertises
- // if is accepts transforms for the resource type (determined here from
- // previously set previews state bits). The previous logic in this method
- // that checks various flags will be deprecated.
- bool check_previews_flags = !base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform);
-
- bool lofi_enabled_via_flags_or_field_trial = false;
- bool lite_page_enabled_via_flags_or_field_trial = false;
- if (check_previews_flags) {
- // The Lo-Fi and Lite Page directives should not be added for users in the
- // Lo-Fi field trial "Control" group.
- lofi_enabled_via_flags_or_field_trial =
- params::IsLoFiOnViaFlags() ||
- params::IsIncludedInLoFiEnabledFieldTrial();
-
- lite_page_enabled_via_flags_or_field_trial =
- (params::IsLoFiOnViaFlags() && params::AreLitePagesEnabledViaFlags()) ||
- params::IsIncludedInLitePageFieldTrial();
-
- // Previews have been disabled.
- if (are_previews_disabled)
- return;
-
- // User does not have previews enabled.
- if (!lofi_enabled_via_flags_or_field_trial &&
- !lite_page_enabled_via_flags_or_field_trial) {
- return;
- }
- }
-
- // Lo-Fi is not allowed on the main frame, stylesheet, script, font resource,
- // media, service worker, or CSP report.
- bool resource_type_supports_empty_image =
- !(resource_type == content::RESOURCE_TYPE_MAIN_FRAME ||
- resource_type == content::RESOURCE_TYPE_STYLESHEET ||
- resource_type == content::RESOURCE_TYPE_SCRIPT ||
- resource_type == content::RESOURCE_TYPE_FONT_RESOURCE ||
- resource_type == content::RESOURCE_TYPE_MEDIA ||
- resource_type == content::RESOURCE_TYPE_CSP_REPORT);
-
std::string accept_transform_value;
- if (!check_previews_flags) {
- // For the proxy-decides-transform feature, check PreviewsState bits and
- // type of resource to determine which, if any, transformation to accept.
- if ((previews_state & content::SERVER_LITE_PAGE_ON) &&
- resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
- accept_transform_value = lite_page_directive();
- } else if ((previews_state & content::SERVER_LOFI_ON) &&
- resource_type_supports_empty_image) {
- // Note that for subresource requests, the Lo-Fi bit should only be set
- // if the main frame response provided the "empty-image" directive (for
- // the client to echo back to the server here for any image resources).
+ if ((previews_state & content::SERVER_LITE_PAGE_ON) &&
+ resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
+ accept_transform_value = lite_page_directive();
+ } else if ((previews_state & content::SERVER_LOFI_ON)) {
+ // Note that for subresource requests, the Lo-Fi bit should only be set
+ // if the main frame response provided the "empty-image" directive (for
+ // the client to echo back to the server here for any image resources).
+ // Also, it should only be set for subresource requests that might be
+ // image requests.
+ bool resource_type_supports_empty_image =
+ !(resource_type == content::RESOURCE_TYPE_MAIN_FRAME ||
+ resource_type == content::RESOURCE_TYPE_STYLESHEET ||
+ resource_type == content::RESOURCE_TYPE_SCRIPT ||
+ resource_type == content::RESOURCE_TYPE_FONT_RESOURCE ||
+ resource_type == content::RESOURCE_TYPE_MEDIA ||
+ resource_type == content::RESOURCE_TYPE_CSP_REPORT);
+ if (resource_type_supports_empty_image) {
accept_transform_value = empty_image_directive();
}
- } else if (lite_page_enabled_via_flags_or_field_trial &&
- resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
- // If the Lite Page field trial or flag is enabled, only add the "lite-page"
- // directive on main frame requests. Only add "empty-image" directives to
- // other requests when Lite Page previews are not enabled after the main
- // frame. Add the "if-heavy" qualifier to allow the server to provide a
- // preview when the page is data heavy on if a preview was not otherwise
- // triggered.
- accept_transform_value = lite_page_directive();
-
- // Since a Lite Page was not triggered client side, ask the server to
- // provide a Lite Page only if the page is otherwise data-heavy.
- if (!(previews_state & content::SERVER_LITE_PAGE_ON))
- accept_transform_value += base::StringPrintf(";%s", if_heavy_qualifier());
- } else if (lofi_enabled_via_flags_or_field_trial &&
- !lite_page_enabled_via_flags_or_field_trial &&
- resource_type_supports_empty_image &&
- !(previews_state & content::SERVER_LITE_PAGE_ON)) {
- accept_transform_value = empty_image_directive();
-
- // Since Lo-Fi was not triggered client side, ask the server to provide
- // Lo-Fi only if the page is otherwise data-heavy.
- if (!(previews_state & content::SERVER_LOFI_ON))
- accept_transform_value += base::StringPrintf(";%s", if_heavy_qualifier());
}
+
if (accept_transform_value.empty())
return;
@@ -215,15 +145,11 @@ bool ContentLoFiDecider::ShouldRecordLoFiUMA(
const content::ResourceRequestInfo* request_info =
content::ResourceRequestInfo::ForRequest(&request);
- // User is not using Lo-Fi.
- if (!request_info ||
- !(request_info->GetPreviewsState() & content::SERVER_LOFI_ON ||
- request_info->GetPreviewsState() & content::SERVER_LITE_PAGE_ON)) {
+ if (!request_info)
return false;
- }
- return params::IsIncludedInLoFiEnabledFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial();
+ return request_info->GetPreviewsState() & content::SERVER_LOFI_ON ||
+ request_info->GetPreviewsState() & content::SERVER_LITE_PAGE_ON;
}
bool ContentLoFiDecider::IsClientLoFiImageRequest(
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.h b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.h
index 327278e9548..f508a64be3a 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.h
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.h
@@ -30,7 +30,6 @@ class ContentLoFiDecider : public LoFiDecider {
bool IsUsingLoFi(const net::URLRequest& request) const override;
void MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
- bool are_previews_disabled,
net::HttpRequestHeaders* headers) const override;
bool IsSlowPagePreviewRequested(
const net::HttpRequestHeaders& headers) const override;
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
index 8b4522f948d..7fe5276d8c2 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -165,36 +165,22 @@ class ContentLoFiDeciderTest : public testing::Test {
}
static void VerifyLoFiHeader(bool expected_lofi_used,
- bool expected_if_heavy,
const net::HttpRequestHeaders& headers) {
if (expected_lofi_used)
EXPECT_TRUE(headers.HasHeader(chrome_proxy_accept_transform_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_accept_transform_header(), &header_value);
- if (expected_if_heavy) {
- std::string empty_image_if_heavy = base::StringPrintf(
- "%s;%s", empty_image_directive(), if_heavy_qualifier());
- EXPECT_EQ(expected_lofi_used, empty_image_if_heavy == header_value);
- } else {
- EXPECT_EQ(expected_lofi_used, header_value == empty_image_directive());
- }
+ EXPECT_EQ(expected_lofi_used, header_value == empty_image_directive());
}
static void VerifyLitePageHeader(bool expected_lofi_preview_used,
- bool expected_if_heavy,
const net::HttpRequestHeaders& headers) {
if (expected_lofi_preview_used)
EXPECT_TRUE(headers.HasHeader(chrome_proxy_accept_transform_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_accept_transform_header(), &header_value);
- if (expected_if_heavy) {
- std::string lite_page_if_heavy = base::StringPrintf(
- "%s;%s", lite_page_directive(), if_heavy_qualifier());
- EXPECT_EQ(expected_lofi_preview_used, lite_page_if_heavy == header_value);
- } else {
- EXPECT_EQ(expected_lofi_preview_used,
- header_value == lite_page_directive());
- }
+ EXPECT_EQ(expected_lofi_preview_used,
+ header_value == lite_page_directive());
}
static void VerifyAcceptTransformHeader(const net::URLRequest& request,
@@ -203,7 +189,7 @@ class ContentLoFiDeciderTest : public testing::Test {
std::unique_ptr<data_reduction_proxy::ContentLoFiDecider> lofi_decider(
new data_reduction_proxy::ContentLoFiDecider());
net::HttpRequestHeaders headers;
- lofi_decider->MaybeSetAcceptTransformHeader(request, false, &headers);
+ lofi_decider->MaybeSetAcceptTransformHeader(request, &headers);
std::string header_value;
EXPECT_EQ(expected_accept_lite_page || expected_accept_empty_image,
@@ -236,103 +222,6 @@ class ContentLoFiDeciderTest : public testing::Test {
data_reduction_proxy_network_delegate_;
};
-TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- // Enable Lo-Fi.
- const struct {
- bool is_using_lofi;
- bool is_using_lite_page;
- bool is_main_frame;
- } tests[] = {
- {false, false, false}, {false, false, true}, {true, false, true},
- {true, false, false}, {false, true, false}, {false, true, true},
- {true, true, true}, {true, true, false},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- content::PreviewsState previews_state = content::PREVIEWS_UNSPECIFIED;
- if (tests[i].is_using_lofi)
- previews_state |= content::SERVER_LOFI_ON;
- if (tests[i].is_using_lite_page)
- previews_state |= content::SERVER_LITE_PAGE_ON;
-
- std::unique_ptr<net::URLRequest> request =
- CreateRequest(tests[i].is_main_frame, previews_state);
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- command_line->InitFromArgv(command_line->argv());
- if (tests[i].is_using_lite_page) {
- command_line->AppendSwitch(switches::kEnableDataReductionProxyLitePage);
- }
-
- // No flags or field trials. The Lo-Fi header should not be added.
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(false, false, headers);
- VerifyLitePageHeader(false, false, headers);
- // The Lo-Fi flag is "always-on", Lo-Fi is being used, and it's a main frame
- // request. Lo-Fi or lite page header should be added.
- command_line->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueAlwaysOn);
- headers.Clear();
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(!tests[i].is_main_frame && !tests[i].is_using_lite_page,
- !tests[i].is_main_frame && !tests[i].is_using_lofi &&
- !tests[i].is_using_lite_page,
- headers);
- VerifyLitePageHeader(tests[i].is_using_lite_page && tests[i].is_main_frame,
- false, headers);
- DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
- // |lofi_requested| should be set to false when Lo-Fi is enabled using
- // flags.
- EXPECT_FALSE(data->lofi_requested());
-
- // The Lo-Fi flag is "always-on" and Lo-Fi is being used. Lo-Fi header
- // should be added.
- AllocateRequestInfoForTesting(
- request.get(), content::RESOURCE_TYPE_SUB_FRAME, previews_state);
- headers.Clear();
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(!tests[i].is_using_lite_page, !tests[i].is_using_lofi,
- headers);
- VerifyLitePageHeader(false, false, headers);
-
- // The Lo-Fi flag is "cellular-only" and Lo-Fi is being used. Lo-Fi header
- // should be added.
- command_line->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueCellularOnly);
- headers.Clear();
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(!tests[i].is_using_lite_page, !tests[i].is_using_lofi,
- headers);
- VerifyLitePageHeader(false, false, headers);
- data = DataReductionProxyData::GetData(*request);
- // |lofi_requested| should be set to false when Lo-Fi is enabled using
- // flags.
- EXPECT_FALSE(data->lofi_requested());
-
- // The Lo-Fi flag is "slow-connections-only" and Lo-Fi is being used. Lo-Fi
- // header should be added.
- command_line->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
- headers.Clear();
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(!tests[i].is_using_lite_page, !tests[i].is_using_lofi,
- headers);
- VerifyLitePageHeader(false, false, headers);
- data = DataReductionProxyData::GetData(*request);
- // |lofi_requested| should be set to false when Lo-Fi is enabled using
- // flags.
- EXPECT_FALSE(data->lofi_requested());
- }
-}
-
TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformNoAcceptForPreviewsOff) {
// Turn on proxy-decides-transform feature for these unit tests.
base::test::ScopedFeatureList scoped_feature_list;
@@ -429,65 +318,41 @@ TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformHeaderAcceptEmptyImage) {
false /* empty-image */);
}
-TEST_F(ContentLoFiDeciderTest, LoFiEnabledFieldTrial) {
- // Turn off proxy-decides-transform feature for these unit tests.
+TEST_F(ContentLoFiDeciderTest, AcceptTransformPerResourceType) {
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
+ scoped_feature_list.InitAndEnableFeature(
features::kDataReductionProxyDecidesTransform);
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
-
- // Enable Lo-Fi.
const struct {
- bool is_using_lofi;
content::ResourceType resource_type;
- } tests[] = {{false, content::RESOURCE_TYPE_MAIN_FRAME},
- {false, content::RESOURCE_TYPE_SUB_FRAME},
- {false, content::RESOURCE_TYPE_STYLESHEET},
- {false, content::RESOURCE_TYPE_SCRIPT},
- {false, content::RESOURCE_TYPE_IMAGE},
- {false, content::RESOURCE_TYPE_FONT_RESOURCE},
- {false, content::RESOURCE_TYPE_SUB_RESOURCE},
- {false, content::RESOURCE_TYPE_OBJECT},
- {false, content::RESOURCE_TYPE_MEDIA},
- {false, content::RESOURCE_TYPE_WORKER},
- {false, content::RESOURCE_TYPE_SHARED_WORKER},
- {false, content::RESOURCE_TYPE_PREFETCH},
- {false, content::RESOURCE_TYPE_FAVICON},
- {false, content::RESOURCE_TYPE_XHR},
- {false, content::RESOURCE_TYPE_PING},
- {false, content::RESOURCE_TYPE_SERVICE_WORKER},
- {false, content::RESOURCE_TYPE_CSP_REPORT},
- {false, content::RESOURCE_TYPE_PLUGIN_RESOURCE},
-
- {true, content::RESOURCE_TYPE_MAIN_FRAME},
- {true, content::RESOURCE_TYPE_SUB_FRAME},
- {true, content::RESOURCE_TYPE_STYLESHEET},
- {true, content::RESOURCE_TYPE_SCRIPT},
- {true, content::RESOURCE_TYPE_IMAGE},
- {true, content::RESOURCE_TYPE_FONT_RESOURCE},
- {true, content::RESOURCE_TYPE_SUB_RESOURCE},
- {true, content::RESOURCE_TYPE_OBJECT},
- {true, content::RESOURCE_TYPE_MEDIA},
- {true, content::RESOURCE_TYPE_WORKER},
- {true, content::RESOURCE_TYPE_SHARED_WORKER},
- {true, content::RESOURCE_TYPE_PREFETCH},
- {true, content::RESOURCE_TYPE_FAVICON},
- {true, content::RESOURCE_TYPE_XHR},
- {true, content::RESOURCE_TYPE_PING},
- {true, content::RESOURCE_TYPE_SERVICE_WORKER},
- {true, content::RESOURCE_TYPE_CSP_REPORT},
- {true, content::RESOURCE_TYPE_PLUGIN_RESOURCE}};
+ } tests[] = {{content::RESOURCE_TYPE_MAIN_FRAME},
+ {content::RESOURCE_TYPE_SUB_FRAME},
+ {content::RESOURCE_TYPE_STYLESHEET},
+ {content::RESOURCE_TYPE_SCRIPT},
+ {content::RESOURCE_TYPE_IMAGE},
+ {content::RESOURCE_TYPE_FONT_RESOURCE},
+ {content::RESOURCE_TYPE_SUB_RESOURCE},
+ {content::RESOURCE_TYPE_OBJECT},
+ {content::RESOURCE_TYPE_MEDIA},
+ {content::RESOURCE_TYPE_WORKER},
+ {content::RESOURCE_TYPE_SHARED_WORKER},
+ {content::RESOURCE_TYPE_PREFETCH},
+ {content::RESOURCE_TYPE_FAVICON},
+ {content::RESOURCE_TYPE_XHR},
+ {content::RESOURCE_TYPE_PING},
+ {content::RESOURCE_TYPE_SERVICE_WORKER},
+ {content::RESOURCE_TYPE_CSP_REPORT},
+ {content::RESOURCE_TYPE_PLUGIN_RESOURCE}};
for (size_t i = 0; i < arraysize(tests); ++i) {
std::unique_ptr<net::URLRequest> request = CreateRequestByType(
tests[i].resource_type, false,
- tests[i].is_using_lofi ? content::SERVER_LOFI_ON
- : content::PREVIEWS_UNSPECIFIED);
+ content::SERVER_LOFI_ON | content::SERVER_LITE_PAGE_ON);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
+
+ bool is_main_frame =
+ tests[i].resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
bool is_lofi_resource_type =
!(tests[i].resource_type == content::RESOURCE_TYPE_MAIN_FRAME ||
tests[i].resource_type == content::RESOURCE_TYPE_STYLESHEET ||
@@ -496,232 +361,12 @@ TEST_F(ContentLoFiDeciderTest, LoFiEnabledFieldTrial) {
tests[i].resource_type == content::RESOURCE_TYPE_MEDIA ||
tests[i].resource_type == content::RESOURCE_TYPE_CSP_REPORT);
- VerifyLoFiHeader(is_lofi_resource_type, !tests[i].is_using_lofi, headers);
- VerifyLitePageHeader(false, false, headers);
- DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
- EXPECT_EQ(tests[i].is_using_lofi, data->lofi_requested()) << i;
- }
-}
-
-TEST_F(ContentLoFiDeciderTest, LoFiControlFieldTrial) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Control");
- // Enable Lo-Fi.
- const struct {
- bool is_using_lofi;
- bool is_main_frame;
- } tests[] = {{false, false}, {false, true}, {true, false}, {true, true}};
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- std::unique_ptr<net::URLRequest> request =
- CreateRequest(tests[i].is_main_frame,
- tests[i].is_using_lofi ? content::SERVER_LOFI_ON
- : content::PREVIEWS_UNSPECIFIED);
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(false, false, headers);
- VerifyLitePageHeader(false, false, headers);
- DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
- EXPECT_EQ(tests[i].is_using_lofi, data->lofi_requested()) << i;
- }
-}
-
-TEST_F(ContentLoFiDeciderTest, LitePageFieldTrial) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled_Preview");
- // Enable Lo-Fi.
- const struct {
- bool is_using_lite_page;
- bool is_main_frame;
- } tests[] = {
- {false, false}, {true, false}, {false, true}, {true, true},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- std::unique_ptr<net::URLRequest> request = CreateRequest(
- tests[i].is_main_frame, tests[i].is_using_lite_page
- ? content::SERVER_LITE_PAGE_ON
- : content::PREVIEWS_UNSPECIFIED);
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(false, false, headers);
- VerifyLitePageHeader(tests[i].is_main_frame, !tests[i].is_using_lite_page,
- headers);
- DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
- EXPECT_EQ(tests[i].is_using_lite_page, data->lofi_requested()) << i;
- }
-}
-
-TEST_F(ContentLoFiDeciderTest, LitePageFieldTrialFallbackDisabled) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled_Preview");
- // Enable Lo-Fi.
- const struct {
- bool is_using_lofi;
- bool is_using_lite_page;
- bool is_main_frame;
- } tests[] = {
- {false, false, false}, {false, false, true}, {true, false, true},
- {true, false, false}, {false, true, false}, {false, true, true},
- {true, true, true}, {true, true, false},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- content::PreviewsState previews_state = content::PREVIEWS_UNSPECIFIED;
- if (tests[i].is_using_lofi)
- previews_state |= content::SERVER_LOFI_ON;
- if (tests[i].is_using_lite_page)
- previews_state |= content::SERVER_LITE_PAGE_ON;
-
- std::unique_ptr<net::URLRequest> request =
- CreateRequest(tests[i].is_main_frame, previews_state);
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(false, false, headers);
- VerifyLitePageHeader(tests[i].is_main_frame,
- tests[i].is_main_frame && !tests[i].is_using_lite_page,
- headers);
- DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
- EXPECT_EQ(tests[i].is_using_lofi || tests[i].is_using_lite_page,
- data->lofi_requested())
- << i;
- }
-}
-
-TEST_F(ContentLoFiDeciderTest, AutoLoFi) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- const struct {
- bool auto_lofi_enabled_group;
- bool auto_lofi_control_group;
- bool network_prohibitively_slow;
- bool is_main_frame;
- } tests[] = {
- {false, false, false, false},
- {false, false, true, false},
- {true, false, false, false},
- {true, false, true, false},
- {true, false, true, true},
- {false, true, false, false},
- {false, true, true, false},
- // Repeat this test data to simulate user moving out of Lo-Fi control
- // experiment.
- {false, true, false, false},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- test_context_->config()->ResetLoFiStatusForTest();
- const bool expect_lofi_header = tests[i].auto_lofi_enabled_group &&
- !tests[i].is_main_frame;
-
- base::FieldTrialList field_trial_list(nullptr);
- if (tests[i].auto_lofi_enabled_group) {
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- }
-
- if (tests[i].auto_lofi_control_group) {
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Control");
- }
-
- test_context_->config()->SetNetworkProhibitivelySlow(
- tests[i].network_prohibitively_slow);
-
- std::unique_ptr<net::URLRequest> request = CreateRequest(
- tests[i].is_main_frame, tests[i].network_prohibitively_slow);
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
-
- VerifyLoFiHeader(expect_lofi_header, !tests[i].network_prohibitively_slow,
- headers);
- }
-}
-
-TEST_F(ContentLoFiDeciderTest, SlowConnectionsFlag) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- const struct {
- bool slow_connections_flag_enabled;
- bool network_prohibitively_slow;
- bool auto_lofi_enabled_group;
- bool is_main_frame;
- } tests[] = {
- {false, false, false, false}, {false, true, false, false},
- {true, false, false, false}, {true, true, false, false},
- {true, true, false, true}, {false, false, true, false},
- {false, false, true, true}, {false, true, true, false},
- {true, false, true, false}, {true, true, true, false},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- test_context_->config()->ResetLoFiStatusForTest();
- // For the purpose of this test, Lo-Fi header is expected only if LoFi Slow
- // Connection Flag is enabled or session is part of Lo-Fi enabled field
- // trial. For both cases, an additional condition is that network must be
- // prohibitively slow.
- const bool expect_lofi_header = ((tests[i].slow_connections_flag_enabled &&
- tests[i].network_prohibitively_slow) ||
- (!tests[i].slow_connections_flag_enabled &&
- tests[i].auto_lofi_enabled_group &&
- tests[i].network_prohibitively_slow)) &&
- !tests[i].is_main_frame;
-
- std::string expected_header;
-
- if (tests[i].slow_connections_flag_enabled) {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
- }
-
- base::FieldTrialList field_trial_list(nullptr);
- if (tests[i].auto_lofi_enabled_group) {
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- }
-
- test_context_->config()->SetNetworkProhibitivelySlow(
- tests[i].network_prohibitively_slow);
-
- std::unique_ptr<net::URLRequest> request = CreateRequest(
- tests[i].is_main_frame, tests[i].network_prohibitively_slow);
- net::HttpRequestHeaders headers;
- NotifyBeforeSendHeaders(&headers, request.get(), true);
-
- VerifyLoFiHeader(expect_lofi_header, false, headers);
+ VerifyLitePageHeader(is_main_frame, headers);
+ VerifyLoFiHeader(is_lofi_resource_type, headers);
}
}
TEST_F(ContentLoFiDeciderTest, ProxyIsNotDataReductionProxy) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- // Enable Lo-Fi.
const struct {
content::PreviewsState previews_state;
} tests[] = {
@@ -740,11 +385,7 @@ TEST_F(ContentLoFiDeciderTest, ProxyIsNotDataReductionProxy) {
}
TEST_F(ContentLoFiDeciderTest, VideoDirectiveNotOverridden) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
// Verify the directive gets added even when LoFi is triggered.
- test_context_->config()->SetNetworkProhibitivelySlow(true);
std::unique_ptr<net::URLRequest> request =
CreateRequestByType(content::RESOURCE_TYPE_MEDIA, false, true);
net::HttpRequestHeaders headers;
@@ -753,10 +394,6 @@ TEST_F(ContentLoFiDeciderTest, VideoDirectiveNotOverridden) {
}
TEST_F(ContentLoFiDeciderTest, VideoDirectiveNotAdded) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- test_context_->config()->SetNetworkProhibitivelySlow(true);
std::unique_ptr<net::URLRequest> request =
CreateRequestByType(content::RESOURCE_TYPE_MEDIA, false, true);
net::HttpRequestHeaders headers;
@@ -766,11 +403,7 @@ TEST_F(ContentLoFiDeciderTest, VideoDirectiveNotAdded) {
}
TEST_F(ContentLoFiDeciderTest, VideoDirectiveDoesNotOverride) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
// Verify the directive gets added even when LoFi is triggered.
- test_context_->config()->SetNetworkProhibitivelySlow(true);
std::unique_ptr<net::URLRequest> request =
CreateRequestByType(content::RESOURCE_TYPE_MEDIA, false, true);
net::HttpRequestHeaders headers;
@@ -828,10 +461,21 @@ TEST_F(ContentLoFiDeciderTest, RemoveAcceptTransformHeader) {
EXPECT_FALSE(headers.HasHeader(chrome_proxy_accept_transform_header()));
}
+TEST_F(ContentLoFiDeciderTest, ShouldRecordLoFiUMA) {
+ std::unique_ptr<data_reduction_proxy::ContentLoFiDecider> lofi_decider(
+ new data_reduction_proxy::ContentLoFiDecider());
+ std::unique_ptr<net::URLRequest> request1 = CreateRequestByType(
+ content::RESOURCE_TYPE_IMAGE, false, content::SERVER_LOFI_ON);
+ EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request1.get()));
+ std::unique_ptr<net::URLRequest> request2 = CreateRequestByType(
+ content::RESOURCE_TYPE_MAIN_FRAME, false, content::PREVIEWS_OFF);
+ EXPECT_FALSE(lofi_decider->ShouldRecordLoFiUMA(*request2.get()));
+ std::unique_ptr<net::URLRequest> request3 = CreateRequestByType(
+ content::RESOURCE_TYPE_MAIN_FRAME, false, content::SERVER_LITE_PAGE_ON);
+ EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request3.get()));
+}
+
TEST_F(ContentLoFiDeciderTest, NoTransformDoesNotAddHeader) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
std::unique_ptr<net::URLRequest> request =
CreateRequest(false, content::PREVIEWS_NO_TRANSFORM);
net::HttpRequestHeaders headers;
diff --git a/chromium/components/data_reduction_proxy/content/renderer/BUILD.gn b/chromium/components/data_reduction_proxy/content/renderer/BUILD.gn
new file mode 100644
index 00000000000..9a402008684
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/content/renderer/BUILD.gn
@@ -0,0 +1,31 @@
+# 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.
+
+static_library("renderer") {
+ sources = [
+ "content_previews_render_frame_observer.cc",
+ "content_previews_render_frame_observer.h",
+ ]
+ deps = [
+ "//base",
+ "//components/data_reduction_proxy/core/common",
+ "//content/public/common",
+ "//content/public/renderer",
+ "//third_party/WebKit/public:blink",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "content_previews_render_frame_observer_unittest.cc",
+ ]
+ deps = [
+ ":renderer",
+ "//base/test:test_support",
+ "//content/public/common",
+ "//testing/gtest",
+ "//third_party/WebKit/public:blink",
+ ]
+}
diff --git a/chromium/components/data_reduction_proxy/content/renderer/DEPS b/chromium/components/data_reduction_proxy/content/renderer/DEPS
new file mode 100644
index 00000000000..04ab6a902c4
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/content/renderer/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+content/public/renderer",
+ "+third_party/WebKit/public/platform",
+ "+third_party/WebKit/public/web",
+] \ No newline at end of file
diff --git a/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.cc b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.cc
new file mode 100644
index 00000000000..c44eaa5317a
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.cc
@@ -0,0 +1,123 @@
+// 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/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h"
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
+#include "content/public/renderer/render_frame.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebDocumentLoader.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace data_reduction_proxy {
+
+namespace {
+
+bool HasEmptyImageDirective(const blink::WebURLResponse& web_url_response) {
+ std::string chrome_proxy_value =
+ web_url_response
+ .HttpHeaderField(blink::WebString::FromUTF8(chrome_proxy_header()))
+ .Utf8();
+ for (const auto& directive :
+ base::SplitStringPiece(chrome_proxy_value, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ if (!base::StartsWith(directive, page_policies_directive(),
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ continue;
+ }
+
+ // Check policy directive for empty-image entry.
+ base::StringPiece page_policies_value = base::StringPiece(directive).substr(
+ strlen(page_policies_directive()) + 1);
+ for (const auto& policy :
+ base::SplitStringPiece(page_policies_value, "|", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ if (base::LowerCaseEqualsASCII(policy, empty_image_directive())) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+ContentPreviewsRenderFrameObserver::ContentPreviewsRenderFrameObserver(
+ content::RenderFrame* render_frame)
+ : content::RenderFrameObserver(render_frame) {}
+
+ContentPreviewsRenderFrameObserver::~ContentPreviewsRenderFrameObserver() =
+ default;
+
+content::PreviewsState
+ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::PreviewsState original_state,
+ const blink::WebURLResponse& web_url_response) {
+ if (original_state == content::PREVIEWS_UNSPECIFIED) {
+ return content::PREVIEWS_OFF;
+ }
+
+ // Don't update the state if server previews were not enabled.
+ if (!(original_state & content::SERVER_LITE_PAGE_ON)) {
+ return original_state;
+ }
+
+ // At this point, this is a proxy main frame response for which the
+ // PreviewsState needs to be updated from what was enabled/accepted by the
+ // client to what the client should actually do based on the server response.
+
+ content::PreviewsState updated_state = original_state;
+
+ // Clear the Lite Page bit if Lite Page transformation did not occur.
+ // TODO(megjablon): Leverage common code in drp_headers.
+ if (web_url_response
+ .HttpHeaderField(blink::WebString::FromUTF8(
+ chrome_proxy_content_transform_header()))
+ .Utf8() != lite_page_directive()) {
+ updated_state &= ~(content::SERVER_LITE_PAGE_ON);
+ }
+
+ // Determine whether to keep or clear Lo-Fi bits. We need to receive the
+ // empty-image policy directive and have SERVER_LOFI_ON in order to retain
+ // Lo-Fi bits.
+ if (!(original_state & content::SERVER_LOFI_ON)) {
+ // Server Lo-Fi not enabled so ensure Client Lo-Fi off for this request.
+ updated_state &= ~(content::CLIENT_LOFI_ON);
+ } else if (!HasEmptyImageDirective(web_url_response)) {
+ updated_state &= ~(content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON);
+ }
+
+ // If we are left with no previews bits set, return the off state.
+ if (updated_state == content::PREVIEWS_UNSPECIFIED) {
+ return content::PREVIEWS_OFF;
+ }
+
+ return updated_state;
+}
+
+void ContentPreviewsRenderFrameObserver::OnDestruct() {
+ delete this;
+}
+
+void ContentPreviewsRenderFrameObserver::DidCommitProvisionalLoad(
+ bool is_new_navigation,
+ bool is_same_document_navigation) {
+ if (is_same_document_navigation)
+ return;
+
+ content::PreviewsState original_state = render_frame()->GetPreviewsState();
+ const blink::WebURLResponse& web_url_response =
+ render_frame()->GetWebFrame()->GetDocumentLoader()->GetResponse();
+
+ render_frame()->SetPreviewsState(
+ GetPreviewsStateFromResponse(original_state, web_url_response));
+}
+
+} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h
new file mode 100644
index 00000000000..bbb40e9f226
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h
@@ -0,0 +1,37 @@
+// 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_DATA_REDUCTION_PROXY_CONTENT_RENDERER_CONTENT_PREVIEWS_RENDER_FRAME_OBSERVER_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_RENDERER_CONTENT_PREVIEWS_RENDER_FRAME_OBSERVER_H_
+
+#include "base/macros.h"
+#include "content/public/common/previews_state.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+
+namespace data_reduction_proxy {
+
+// This class is created by ChromeRenderFrameObserver, and it class manages its
+// own lifetime. It deletes itself when the RenderFrame it is observing goes
+// away.
+class ContentPreviewsRenderFrameObserver : public content::RenderFrameObserver {
+ public:
+ ContentPreviewsRenderFrameObserver(content::RenderFrame* render_frame);
+ ~ContentPreviewsRenderFrameObserver() override;
+
+ static content::PreviewsState GetPreviewsStateFromResponse(
+ content::PreviewsState original_state,
+ const blink::WebURLResponse& web_url_response);
+
+ private:
+ // content::RenderFrameObserver:
+ void OnDestruct() override;
+ void DidCommitProvisionalLoad(bool is_new_navigation,
+ bool is_same_document_navigation) override;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentPreviewsRenderFrameObserver);
+};
+
+} // namespace data_reduction_proxy
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_RENDERER_CONTENT_PREVIEWS_RENDER_FRAME_OBSERVER_H_
diff --git a/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer_unittest.cc b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer_unittest.cc
new file mode 100644
index 00000000000..0125343e83d
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/content/renderer/content_previews_render_frame_observer_unittest.cc
@@ -0,0 +1,172 @@
+// 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/data_reduction_proxy/content/renderer/content_previews_render_frame_observer.h"
+
+#include "content/public/common/previews_state.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+
+namespace data_reduction_proxy {
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateNoServerTransformRequested) {
+ blink::WebURLResponse response_no_headers;
+
+ // No transforms specified.
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::PREVIEWS_UNSPECIFIED, response_no_headers));
+
+ // Client Lo-Fi preserved if no Server Lo-Fi nor Lite Page.
+ EXPECT_EQ(content::CLIENT_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::CLIENT_LOFI_ON, response_no_headers));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateNoTransformResponseHeaders) {
+ blink::WebURLResponse response_no_headers;
+ // Lite Page enabled but no CPCT nor page-polices => all cleared.
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_no_headers));
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON, response_no_headers));
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::CLIENT_LOFI_ON,
+ response_no_headers));
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_no_headers));
+
+ // Legacy Lo-Fi path (Lite Pages not enabled but Server Lo-Fi is).
+ EXPECT_EQ(content::SERVER_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LOFI_ON, response_no_headers));
+ EXPECT_EQ(content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON,
+ response_no_headers));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateLitePageTransform) {
+ blink::WebURLResponse response_with_lite_page;
+ response_with_lite_page.AddHTTPHeaderField("chrome-proxy-content-transform",
+ "lite-page");
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON, response_with_lite_page));
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_with_lite_page));
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::CLIENT_LOFI_ON,
+ response_with_lite_page));
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_with_lite_page));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateLitePageAndLoFiTransforms) {
+ blink::WebURLResponse response_with_lite_page_and_page_policy;
+ response_with_lite_page_and_page_policy.AddHTTPHeaderField(
+ "chrome-proxy-content-transform", "lite-page");
+ response_with_lite_page_and_page_policy.AddHTTPHeaderField(
+ "Chrome-Proxy", "Page-Policies=Empty-Image");
+
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_with_lite_page_and_page_policy));
+ EXPECT_EQ(content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_with_lite_page_and_page_policy));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateLoFiFallbackPagePolicy) {
+ blink::WebURLResponse response_with_page_policy;
+ response_with_page_policy.AddHTTPHeaderField("Chrome-Proxy", "SomeNoise");
+ response_with_page_policy.AddHTTPHeaderField("Chrome-Proxy",
+ "Page-Policies=Empty-Image");
+
+ // No fallbacks if Server Lo-Fi not enabled.
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON, response_with_page_policy));
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::CLIENT_LOFI_ON,
+ response_with_page_policy));
+
+ // Lo-Fi fallbacks if Server Lo-Fi enabled and get empty-image directive.
+ EXPECT_EQ(content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_with_page_policy));
+ EXPECT_EQ(content::SERVER_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_with_page_policy));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest,
+ GetPreviewsStateLoFiFallbackAndOtherPolicies) {
+ blink::WebURLResponse response_with_page_policy;
+ response_with_page_policy.AddHTTPHeaderField("chrome-proxy", "Prefix=Noise");
+ response_with_page_policy.AddHTTPHeaderField(
+ "chrome-proxy", "page-policies=new-hotness|empty-image|newer-hotness");
+ response_with_page_policy.AddHTTPHeaderField("chrome-proxy",
+ "Suffix=More|Noise");
+
+ // Lo-Fi fallbacks if Server Lo-Fi enabled and get empty-image directive.
+ EXPECT_EQ(content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_with_page_policy));
+ EXPECT_EQ(content::SERVER_LOFI_ON,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_with_page_policy));
+}
+
+TEST(ContentPreviewsRenderFrameObserverTest, GetPreviewsStateNoKnownPolicies) {
+ blink::WebURLResponse response_with_page_policy;
+ response_with_page_policy.AddHTTPHeaderField("chrome-proxy", "Prefix=Noise");
+ response_with_page_policy.AddHTTPHeaderField(
+ "chrome-proxy",
+ "page-policies=new-hotness|new-empty-image|newer-hotness");
+ response_with_page_policy.AddHTTPHeaderField("chrome-proxy",
+ "Suffix=More|Noise");
+
+ // Lo-Fi fallbacks if Server Lo-Fi enabled and get empty-image directive.
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
+ content::CLIENT_LOFI_ON,
+ response_with_page_policy));
+ EXPECT_EQ(content::PREVIEWS_OFF,
+ ContentPreviewsRenderFrameObserver::GetPreviewsStateFromResponse(
+ content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON,
+ response_with_page_policy));
+}
+
+} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
index b5d3c926fec..8050850314a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -64,6 +64,7 @@ if (is_android) {
"//components/prefs",
"//components/previews/core",
"//components/variations",
+ "//components/variations/net",
"//crypto",
"//google_apis",
"//net:net",
@@ -91,6 +92,7 @@ static_library("browser") {
"//components/prefs",
"//components/previews/core",
"//components/variations",
+ "//components/variations/net",
"//crypto",
"//google_apis",
"//net",
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
index c20c7ea1128..239e35b019c 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
@@ -169,8 +169,7 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
data_reduction_proxy_info->bypass_all,
data_reduction_proxy_type_info.proxy_servers);
} else {
- request->SetLoadFlags(request->load_flags() |
- net::LOAD_DISABLE_CACHE |
+ request->SetLoadFlags(request->load_flags() | net::LOAD_BYPASS_CACHE |
net::LOAD_BYPASS_PROXY);
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
index 72801848901..4d08ef3793e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -190,15 +190,27 @@ class DataReductionProxyProtocolTest : public testing::Test {
response2_via_header = "Via: 1.1 Chrome-Compression-Proxy\r\n";
}
- request2 = base::StringPrintf(
+ std::string request2_prefix = base::StringPrintf(
"%s %s HTTP/1.1\r\n"
"Host: www.google.com\r\n"
- "%sConnection: keep-alive\r\n%s"
- "User-Agent:\r\n"
- "Accept-Encoding: gzip, deflate\r\n\r\n",
+ "%sConnection: keep-alive\r\n%s",
method, request2_path.c_str(), request2_connection_type.c_str(),
trailer.c_str());
+ // Cache headers are set only if the request was intercepted and retried by
+ // data reduction proxy. If the request was restarted by the network stack,
+ // then the cache headers are unset.
+ std::string request2_middle = expected_bad_proxy_count == 0
+ ? "Pragma: no-cache\r\n"
+ "Cache-Control: no-cache\r\n"
+ : "";
+
+ std::string request2_suffix =
+ "User-Agent:\r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n";
+
+ request2 = request2_prefix + request2_middle + request2_suffix;
+
response2 = base::StringPrintf(
"HTTP/1.0 200 OK\r\n"
"Server: foo\r\n%s\r\n", response2_via_header.c_str());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index d35166936ef..dcab08bb13b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -17,6 +17,7 @@
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -91,136 +92,6 @@ void RecordNetworkChangeEvent(DataReductionProxyNetworkChangeEvent event) {
CHANGE_EVENT_COUNT);
}
-// Returns a descriptive name corresponding to |connection_type|.
-const char* GetNameForConnectionType(
- net::NetworkChangeNotifier::ConnectionType connection_type) {
- switch (connection_type) {
- case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
- return "Unknown";
- case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
- return "Ethernet";
- case net::NetworkChangeNotifier::CONNECTION_WIFI:
- return "WiFi";
- case net::NetworkChangeNotifier::CONNECTION_2G:
- return "2G";
- case net::NetworkChangeNotifier::CONNECTION_3G:
- return "3G";
- case net::NetworkChangeNotifier::CONNECTION_4G:
- return "4G";
- case net::NetworkChangeNotifier::CONNECTION_NONE:
- return "None";
- case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
- return "Bluetooth";
- }
- NOTREACHED();
- return "";
-}
-
-// Returns an enumerated histogram that should be used to record the given
-// statistic. |max_limit| is the maximum value that can be stored in the
-// histogram. Number of buckets in the enumerated histogram are one more than
-// |max_limit|.
-base::HistogramBase* GetEnumeratedHistogram(
- base::StringPiece prefix,
- net::NetworkChangeNotifier::ConnectionType type,
- int32_t max_limit) {
- DCHECK_GT(max_limit, 0);
-
- base::StringPiece name_for_connection_type(GetNameForConnectionType(type));
- std::string histogram_name;
- histogram_name.reserve(prefix.size() + name_for_connection_type.size());
- histogram_name.append(prefix.data(), prefix.size());
- histogram_name.append(name_for_connection_type.data(),
- name_for_connection_type.size());
-
- return base::Histogram::FactoryGet(
- histogram_name, 0, max_limit, max_limit + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
-}
-
-// Following UMA is plotted to measure how frequently Lo-Fi state changes.
-// Too frequent changes are undesirable. |connection_type| is the current
-// connection type.
-void RecordAutoLoFiRequestHeaderStateChange(
- net::NetworkChangeNotifier::ConnectionType connection_type,
- bool previous_header_low,
- bool current_header_low) {
- // Auto Lo-Fi request header state changes.
- // Possible Lo-Fi header directives are empty ("") and low ("q=low").
- // This enum must remain synchronized with the enum of the same name in
- // metrics/histograms/histograms.xml.
- enum AutoLoFiRequestHeaderState {
- AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_EMPTY = 0,
- AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_LOW = 1,
- AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_EMPTY = 2,
- AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_LOW = 3,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY
- };
-
- AutoLoFiRequestHeaderState state;
-
- if (!previous_header_low) {
- if (current_header_low)
- state = AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_LOW;
- else
- state = AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_EMPTY;
- } else {
- if (current_header_low) {
- // Low to low in useful in checking how many consecutive page loads
- // are done with Lo-Fi enabled.
- state = AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_LOW;
- } else {
- state = AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_EMPTY;
- }
- }
-
- switch (connection_type) {
- case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.Unknown", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.Ethernet", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_WIFI:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.WiFi", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_2G:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.2G", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_3G:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.3G", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_4G:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.4G", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_NONE:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.None", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.AutoLoFiRequestHeaderState.Bluetooth", state,
- AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
// Records UMA containing the result of requesting the secure proxy check.
void RecordSecureProxyCheckFetchResult(
data_reduction_proxy::SecureProxyCheckFetchResult result) {
@@ -275,7 +146,7 @@ class SecureProxyChecker : public net::URLFetcherDelegate {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can control Data Saver on Android via the 'Data Saver' "
"setting. Data Saver is not available on iOS, and on desktop "
@@ -353,7 +224,7 @@ class WarmupURLFetcher : public net::URLFetcherDelegate {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can control Data Saver on Android via the 'Data Saver' "
"setting. Data Saver is not available on iOS, and on desktop it "
@@ -408,15 +279,8 @@ DataReductionProxyConfig::DataReductionProxyConfig(
net_log_(net_log),
configurator_(configurator),
event_creator_(event_creator),
- lofi_effective_connection_type_threshold_(
- net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
- auto_lofi_hysteresis_(base::TimeDelta::Max()),
- network_prohibitively_slow_(false),
connection_type_(net::NetworkChangeNotifier::GetConnectionType()),
- connection_type_changed_(false),
lofi_off_(false),
- network_quality_at_last_query_(NETWORK_QUALITY_AT_LAST_QUERY_UNKNOWN),
- previous_state_lofi_on_(false),
is_captive_portal_(false),
weak_factory_(this) {
DCHECK(io_task_runner_);
@@ -431,7 +295,7 @@ DataReductionProxyConfig::DataReductionProxyConfig(
DataReductionProxyConfig::~DataReductionProxyConfig() {
net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
void DataReductionProxyConfig::InitializeOnIOThread(
@@ -445,20 +309,9 @@ void DataReductionProxyConfig::InitializeOnIOThread(
new SecureProxyChecker(basic_url_request_context_getter));
warmup_url_fetcher_.reset(new WarmupURLFetcher(url_request_context_getter));
- PopulateAutoLoFiParams();
AddDefaultProxyBypassRules();
net::NetworkChangeNotifier::AddIPAddressObserver(this);
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
-
- // Record accuracy at 3 different intervals. The values used here must remain
- // in sync with the suffixes specified in
- // tools/metrics/histograms/histograms.xml.
- lofi_accuracy_recording_intervals_.push_back(
- base::TimeDelta::FromSeconds(15));
- lofi_accuracy_recording_intervals_.push_back(
- base::TimeDelta::FromSeconds(30));
- lofi_accuracy_recording_intervals_.push_back(
- base::TimeDelta::FromSeconds(60));
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
}
void DataReductionProxyConfig::ReloadConfig() {
@@ -596,121 +449,6 @@ bool DataReductionProxyConfig::AreProxiesBypassed(
return bypassed;
}
-bool DataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
- const net::NetworkQualityEstimator* network_quality_estimator) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(params::IsIncludedInLoFiEnabledFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial() ||
- params::IsLoFiSlowConnectionsOnlyViaFlags());
-
- if (!network_quality_estimator)
- return false;
-
- const net::EffectiveConnectionType effective_connection_type =
- network_quality_estimator->GetEffectiveConnectionType();
-
- const bool is_network_quality_available =
- effective_connection_type != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-
- // True only if the network is currently estimated to be slower than the
- // defined thresholds.
- const bool is_network_currently_slow =
- is_network_quality_available &&
- IsEffectiveConnectionTypeSlowerThanThreshold(effective_connection_type);
-
- if (is_network_quality_available) {
- network_quality_at_last_query_ =
- is_network_currently_slow ? NETWORK_QUALITY_AT_LAST_QUERY_SLOW
- : NETWORK_QUALITY_AT_LAST_QUERY_NOT_SLOW;
-
- if ((params::IsIncludedInLoFiEnabledFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial()) &&
- !params::IsLoFiSlowConnectionsOnlyViaFlags()) {
- // Post tasks to record accuracy of network quality prediction at
- // different intervals.
- for (const base::TimeDelta& measuring_delay :
- GetLofiAccuracyRecordingIntervals()) {
- io_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&DataReductionProxyConfig::RecordAutoLoFiAccuracyRate,
- weak_factory_.GetWeakPtr(), network_quality_estimator,
- measuring_delay),
- measuring_delay);
- }
- }
- }
-
- // Return the cached entry if the last update was within the hysteresis
- // duration and if the connection type has not changed.
- if (!connection_type_changed_ && !network_quality_last_checked_.is_null() &&
- GetTicksNow() - network_quality_last_checked_ <= auto_lofi_hysteresis_) {
- return network_prohibitively_slow_;
- }
-
- network_quality_last_checked_ = GetTicksNow();
- connection_type_changed_ = false;
-
- if (!is_network_quality_available)
- return false;
-
- network_prohibitively_slow_ = is_network_currently_slow;
- return network_prohibitively_slow_;
-}
-
-void DataReductionProxyConfig::PopulateAutoLoFiParams() {
- std::string field_trial = params::GetLoFiFieldTrialName();
-
- // Default parameters to use.
- const net::EffectiveConnectionType
- default_effective_connection_type_threshold =
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- const base::TimeDelta default_hysterisis = base::TimeDelta::FromSeconds(60);
-
- if (params::IsLoFiSlowConnectionsOnlyViaFlags()) {
- // Use the default parameters.
- lofi_effective_connection_type_threshold_ =
- default_effective_connection_type_threshold;
- auto_lofi_hysteresis_ = default_hysterisis;
- field_trial = params::GetLoFiFlagFieldTrialName();
- }
-
- if (!params::IsIncludedInLoFiControlFieldTrial() &&
- !params::IsIncludedInLoFiEnabledFieldTrial() &&
- !params::IsLoFiSlowConnectionsOnlyViaFlags()) {
- return;
- }
-
- std::string variation_value = variations::GetVariationParamValue(
- field_trial, "effective_connection_type");
- if (!variation_value.empty()) {
- bool effective_connection_type_available =
- net::GetEffectiveConnectionTypeForName(
- variation_value, &lofi_effective_connection_type_threshold_);
- DCHECK(effective_connection_type_available);
-
- // Silence unused variable warning in release builds.
- (void)effective_connection_type_available;
- } else {
- // Use the default parameters.
- lofi_effective_connection_type_threshold_ =
- default_effective_connection_type_threshold;
- }
-
- uint32_t auto_lofi_hysteresis_period_seconds;
- variation_value = variations::GetVariationParamValue(
- field_trial, "hysteresis_period_seconds");
- if (!variation_value.empty() &&
- base::StringToUint(variation_value,
- &auto_lofi_hysteresis_period_seconds)) {
- auto_lofi_hysteresis_ =
- base::TimeDelta::FromSeconds(auto_lofi_hysteresis_period_seconds);
- } else {
- // Use the default parameters.
- auto_lofi_hysteresis_ = default_hysterisis;
- }
- DCHECK_GE(auto_lofi_hysteresis_, base::TimeDelta());
-}
-
bool DataReductionProxyConfig::IsProxyBypassed(
const net::ProxyRetryInfoMap& retry_map,
const net::ProxyServer& proxy_server,
@@ -838,11 +576,15 @@ void DataReductionProxyConfig::HandleSecureProxyCheckResponse(
}
}
-void DataReductionProxyConfig::OnConnectionTypeChanged(
+void DataReductionProxyConfig::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) {
DCHECK(thread_checker_.CalledOnValidThread());
- connection_type_changed_ = true;
+
connection_type_ = type;
+
+ if (connection_type_ == net::NetworkChangeNotifier::CONNECTION_NONE)
+ return;
+
FetchWarmupURL();
}
@@ -852,10 +594,6 @@ void DataReductionProxyConfig::OnIPAddressChanged() {
if (enabled_by_user_) {
RecordNetworkChangeEvent(IP_CHANGED);
- // Reset |network_quality_at_last_query_| to prevent recording of network
- // quality prediction accuracy if there was a change in the IP address.
- network_quality_at_last_query_ = NETWORK_QUALITY_AT_LAST_QUERY_UNKNOWN;
-
HandleCaptivePortal();
// It is safe to use base::Unretained here, since it gets executed
// synchronously on the IO thread, and |this| outlives
@@ -921,91 +659,6 @@ void DataReductionProxyConfig::SetLoFiModeOff() {
lofi_off_ = true;
}
-void DataReductionProxyConfig::RecordAutoLoFiAccuracyRate(
- const net::NetworkQualityEstimator* network_quality_estimator,
- const base::TimeDelta& measuring_duration) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(network_quality_estimator);
- DCHECK((params::IsIncludedInLoFiEnabledFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial()) &&
- !params::IsLoFiSlowConnectionsOnlyViaFlags());
- DCHECK_EQ(0, measuring_duration.InMilliseconds() % 1000);
- DCHECK(base::ContainsValue(GetLofiAccuracyRecordingIntervals(),
- measuring_duration));
-
- if (network_quality_at_last_query_ == NETWORK_QUALITY_AT_LAST_QUERY_UNKNOWN)
- return;
-
- const base::TimeTicks now = GetTicksNow();
-
- // Return if the time since |last_query_| is less than |measuring_duration|.
- // This may happen if another main frame request started during last
- // |measuring_duration|.
- if (now - last_query_ < measuring_duration)
- return;
-
- // Return if the time since |last_query_| is off by a factor of 2.
- if (now - last_query_ > 2 * measuring_duration)
- return;
-
- const net::EffectiveConnectionType recent_effective_connection_type =
- network_quality_estimator->GetRecentEffectiveConnectionType(last_query_);
- if (recent_effective_connection_type ==
- net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
- return;
- }
-
- // Values of Auto Lo-Fi accuracy.
- // This enum must remain synchronized with the enum of the same name in
- // metrics/histograms/histograms.xml.
- enum AutoLoFiAccuracy {
- AUTO_LOFI_ACCURACY_ESTIMATED_SLOW_ACTUAL_SLOW = 0,
- AUTO_LOFI_ACCURACY_ESTIMATED_SLOW_ACTUAL_NOT_SLOW = 1,
- AUTO_LOFI_ACCURACY_ESTIMATED_NOT_SLOW_ACTUAL_SLOW = 2,
- AUTO_LOFI_ACCURACY_ESTIMATED_NOT_SLOW_ACTUAL_NOT_SLOW = 3,
- AUTO_LOFI_ACCURACY_INDEX_BOUNDARY
- };
-
- const bool should_have_used_lofi =
- IsEffectiveConnectionTypeSlowerThanThreshold(
- recent_effective_connection_type);
-
- AutoLoFiAccuracy accuracy = AUTO_LOFI_ACCURACY_INDEX_BOUNDARY;
-
- if (should_have_used_lofi) {
- if (network_quality_at_last_query_ == NETWORK_QUALITY_AT_LAST_QUERY_SLOW) {
- accuracy = AUTO_LOFI_ACCURACY_ESTIMATED_SLOW_ACTUAL_SLOW;
- } else if (network_quality_at_last_query_ ==
- NETWORK_QUALITY_AT_LAST_QUERY_NOT_SLOW) {
- accuracy = AUTO_LOFI_ACCURACY_ESTIMATED_NOT_SLOW_ACTUAL_SLOW;
- } else {
- NOTREACHED();
- }
- } else {
- if (network_quality_at_last_query_ == NETWORK_QUALITY_AT_LAST_QUERY_SLOW) {
- accuracy = AUTO_LOFI_ACCURACY_ESTIMATED_SLOW_ACTUAL_NOT_SLOW;
- } else if (network_quality_at_last_query_ ==
- NETWORK_QUALITY_AT_LAST_QUERY_NOT_SLOW) {
- accuracy = AUTO_LOFI_ACCURACY_ESTIMATED_NOT_SLOW_ACTUAL_NOT_SLOW;
- } else {
- NOTREACHED();
- }
- }
-
- base::HistogramBase* accuracy_histogram = GetEnumeratedHistogram(
- base::StringPrintf("DataReductionProxy.LoFi.Accuracy.%d.",
- static_cast<int>(measuring_duration.InSeconds())),
- connection_type_, AUTO_LOFI_ACCURACY_INDEX_BOUNDARY - 1);
-
- accuracy_histogram->Add(accuracy);
-}
-
-bool DataReductionProxyConfig::IsEffectiveConnectionTypeSlowerThanThreshold(
- net::EffectiveConnectionType effective_connection_type) const {
- return effective_connection_type >= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
- effective_connection_type <= lofi_effective_connection_type_threshold_;
-}
-
bool DataReductionProxyConfig::ShouldEnableLoFi(
const net::URLRequest& request,
const previews::PreviewsDecider& previews_decider) {
@@ -1013,21 +666,7 @@ bool DataReductionProxyConfig::ShouldEnableLoFi(
DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) != 0);
DCHECK(!request.url().SchemeIsCryptographic());
- if (base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform)) {
- return ShouldAcceptServerPreview(request, previews_decider);
- }
-
- bool enable_lofi = ShouldEnableLoFiInternal(request, previews_decider);
-
- if (params::IsLoFiSlowConnectionsOnlyViaFlags() ||
- params::IsIncludedInLoFiEnabledFieldTrial()) {
- RecordAutoLoFiRequestHeaderStateChange(
- connection_type_, previous_state_lofi_on_, enable_lofi);
- previous_state_lofi_on_ = enable_lofi;
- }
-
- return enable_lofi;
+ return ShouldAcceptServerPreview(request, previews_decider);
}
bool DataReductionProxyConfig::ShouldEnableLitePages(
@@ -1037,12 +676,7 @@ bool DataReductionProxyConfig::ShouldEnableLitePages(
DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) != 0);
DCHECK(!request.url().SchemeIsCryptographic());
- if (base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform)) {
- return ShouldAcceptServerPreview(request, previews_decider);
- }
-
- return ShouldEnableLitePagesInternal(request, previews_decider);
+ return ShouldAcceptServerPreview(request, previews_decider);
}
bool DataReductionProxyConfig::enabled_by_user_and_reachable() const {
@@ -1056,10 +690,9 @@ bool DataReductionProxyConfig::IsBlackListedOrDisabled(
previews::PreviewsType previews_type) const {
// Make sure request is not locally blacklisted.
if (params::IsBlackListEnabledForServerPreviews()) {
- // Pass in net::EFFECTIVE_CONNECTION_TYPE_4G as the thresold as network
- // speed is checked in IsNetworkQualityProhibitivelySlow().
- // TODO(ryansturm): Use the correct ECT value (or add new method to
- // just check blacklist). crbug.com/720102
+ // Pass in net::EFFECTIVE_CONNECTION_TYPE_4G as the threshold since we
+ // just want to check blacklisting here.
+ // TODO(crbug.com/720102): Consider new method to just check blacklist.
return !previews_decider.ShouldAllowPreviewAtECT(
request, previews_type, net::EFFECTIVE_CONNECTION_TYPE_4G,
std::vector<std::string>());
@@ -1075,8 +708,11 @@ bool DataReductionProxyConfig::ShouldAcceptServerPreview(
const net::URLRequest& request,
const previews::PreviewsDecider& previews_decider) const {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform));
+
+ if (!base::FeatureList::IsEnabled(
+ features::kDataReductionProxyDecidesTransform)) {
+ return false;
+ }
// For the transition to server-driven previews decisions, we will
// use existing Lo-Fi flags for disabling and cellular-only mode.
@@ -1095,7 +731,9 @@ bool DataReductionProxyConfig::ShouldAcceptServerPreview(
return true;
if (IsBlackListedOrDisabled(request, previews_decider,
- previews::PreviewsType::LITE_PAGE)) {
+ previews::PreviewsType::LITE_PAGE) ||
+ IsBlackListedOrDisabled(request, previews_decider,
+ previews::PreviewsType::LOFI)) {
UMA_HISTOGRAM_ENUMERATION(
"DataReductionProxy.Protocol.NotAcceptingTransform",
NOT_ACCEPTING_TRANSFORM_BLACKLISTED,
@@ -1115,93 +753,6 @@ bool DataReductionProxyConfig::ShouldAcceptServerPreview(
return true;
}
-bool DataReductionProxyConfig::ShouldEnableLoFiInternal(
- const net::URLRequest& request,
- const previews::PreviewsDecider& previews_decider) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform));
-
- last_query_ = GetTicksNow();
- network_quality_at_last_query_ = NETWORK_QUALITY_AT_LAST_QUERY_UNKNOWN;
-
- // LitePages overrides Server Lo-Fi. No fallback to Lo-Fi supported
- // on this code path (not using DataReductionProxyDecidesTransform feature).
- // TODO(dougarnett): Delete this surrounding method and related code once the
- // DataReductionProxyDecidesTransform feature is launched to stable [725645].
- if (ShouldEnableLitePages(request, previews_decider)) {
- return false;
- }
-
- // AlwaysOn skips blacklist or disabled checks.
- if (params::IsLoFiAlwaysOnViaFlags())
- return true;
-
- if (IsBlackListedOrDisabled(request, previews_decider,
- previews::PreviewsType::LOFI)) {
- return false;
- }
-
- if (params::IsLoFiCellularOnlyViaFlags()) {
- return net::NetworkChangeNotifier::IsConnectionCellular(connection_type_);
- }
-
- net::NetworkQualityEstimator* network_quality_estimator;
- network_quality_estimator =
- request.context() ? request.context()->network_quality_estimator()
- : nullptr;
-
- if (params::IsLoFiSlowConnectionsOnlyViaFlags() ||
- params::IsIncludedInLoFiEnabledFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial()) {
- return IsNetworkQualityProhibitivelySlow(network_quality_estimator);
- }
-
- return false;
-}
-
-bool DataReductionProxyConfig::ShouldEnableLitePagesInternal(
- const net::URLRequest& request,
- const previews::PreviewsDecider& previews_decider) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!base::FeatureList::IsEnabled(
- features::kDataReductionProxyDecidesTransform));
-
- // AlwaysOn skips blacklist or disabled checks.
- if (params::IsLoFiAlwaysOnViaFlags() && params::AreLitePagesEnabledViaFlags())
- return true;
-
- if (IsBlackListedOrDisabled(request, previews_decider,
- previews::PreviewsType::LITE_PAGE)) {
- return false;
- }
-
- if (params::IsLoFiCellularOnlyViaFlags() &&
- params::AreLitePagesEnabledViaFlags()) {
- return net::NetworkChangeNotifier::IsConnectionCellular(
- net::NetworkChangeNotifier::GetConnectionType());
- }
- net::NetworkQualityEstimator* network_quality_estimator;
- network_quality_estimator =
- request.context() ? request.context()->network_quality_estimator()
- : nullptr;
-
- if ((params::IsLoFiSlowConnectionsOnlyViaFlags() &&
- params::AreLitePagesEnabledViaFlags()) ||
- params::IsIncludedInLitePageFieldTrial() ||
- params::IsIncludedInLoFiControlFieldTrial()) {
- return IsNetworkQualityProhibitivelySlow(network_quality_estimator);
- }
-
- return false;
-}
-
-const std::vector<base::TimeDelta>&
-DataReductionProxyConfig::GetLofiAccuracyRecordingIntervals() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return lofi_accuracy_recording_intervals_;
-}
-
base::TimeTicks DataReductionProxyConfig::GetTicksNow() const {
DCHECK(thread_checker_.CalledOnValidThread());
return base::TimeTicks::Now();
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 0df055b9582..f7f0dafaa5a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -90,7 +90,7 @@ enum SecureProxyCheckFetchResult {
// called from there.
class DataReductionProxyConfig
: public net::NetworkChangeNotifier::IPAddressObserver,
- public net::NetworkChangeNotifier::ConnectionTypeObserver {
+ public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
// The caller must ensure that all parameters remain alive for the lifetime
// of the |DataReductionProxyConfig| instance, with the exception of
@@ -215,11 +215,6 @@ class DataReductionProxyConfig
std::vector<DataReductionProxyServer> GetProxiesForHttp() const;
protected:
- // Virtualized for testing. Returns the list of intervals at which accuracy of
- // network quality prediction should be recorded.
- virtual const std::vector<base::TimeDelta>&
- GetLofiAccuracyRecordingIntervals() const;
-
virtual base::TimeTicks GetTicksNow() const;
// Updates the Data Reduction Proxy configurator with the current config.
@@ -234,13 +229,6 @@ class DataReductionProxyConfig
AreProxiesBypassed);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
AreProxiesBypassedRetryDelay);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest, AutoLoFiParams);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest, AutoLoFiMissingParams);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
- AutoLoFiParamsSlowConnectionsFlag);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest, LoFiAccuracy);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
- LoFiAccuracyNonZeroDelay);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest, WarmupURL);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
ShouldAcceptServerLoFi);
@@ -255,14 +243,12 @@ class DataReductionProxyConfig
NETWORK_QUALITY_AT_LAST_QUERY_NOT_SLOW
};
- // NetworkChangeNotifier::IPAddressObserver:
+ // NetworkChangeNotifier::IPAddressObserver implementation:
void OnIPAddressChanged() override;
- void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) override;
- // Populates the parameters for the Lo-Fi field trial if the session is part
- // of either Lo-Fi enabled or Lo-Fi control field trial group.
- void PopulateAutoLoFiParams();
+ // NetworkChangeNotifier::NetworkChangeObserver implementation:
+ void OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override;
// Requests the secure proxy check URL. Upon completion, returns the results
// to the caller via the |fetcher_callback|. Virtualized for unit testing.
@@ -305,48 +291,6 @@ class DataReductionProxyConfig
const net::URLRequest& request,
const previews::PreviewsDecider& previews_decider) const;
- // Returns true when Lo-Fi Previews should be activated. Determines if Lo-Fi
- // Previews should be activated by checking the Lo-Fi flags and if the network
- // quality is prohibitively slow. |network_quality_estimator| may be NULL.
- // |previews_decider| is a non-null object that determines eligibility of the
- // showing the preview based on past opt outs.
- // Should NOT be used if the kDataReductionProxyDecidesTransform feature is
- // enabled.
- bool ShouldEnableLoFiInternal(
- const net::URLRequest& request,
- const previews::PreviewsDecider& previews_decider);
-
- // Returns true when Lite Page Previews should be activated. Determines if
- // Lite Page Previewsmode should be activated by checking the Lite Page
- // Previews flags and if the network quality is prohibitively slow.
- // |network_quality_estimator| may be NULL. |previews_decider| is a non-null
- // object that determines eligibility of showing the preview based on past opt
- // outs.
- // Should NOT be used if the kDataReductionProxyDecidesTransform feature is
- // enabled.
- bool ShouldEnableLitePagesInternal(
- const net::URLRequest& request,
- const previews::PreviewsDecider& previews_decider);
-
- // Returns true if the network quality is at least as poor as the one
- // specified in the Auto Lo-Fi field trial parameters.
- // |network_quality_estimator| may be NULL. Virtualized for unit testing.
- virtual bool IsNetworkQualityProhibitivelySlow(
- const net::NetworkQualityEstimator* network_quality_estimator);
-
- // Records Lo-Fi accuracy metric. |measuring_duration| should belong to the
- // vector returned by LofiAccuracyRecordingIntervals().
- // RecordAutoLoFiAccuracyRate should be called |measuring_duration| after a
- // main frame request is observed.
- void RecordAutoLoFiAccuracyRate(
- const net::NetworkQualityEstimator* network_quality_estimator,
- const base::TimeDelta& measuring_duration) const;
-
- // Returns true if |effective_connection_type| is at least as poor as
- // |lofi_effective_connection_type_threshold_|.
- bool IsEffectiveConnectionTypeSlowerThanThreshold(
- net::EffectiveConnectionType effective_connection_type) const;
-
// Checks if the current network has captive portal, and handles the result.
// If the captive portal probe was blocked on the current network, disables
// the use of secure proxies.
@@ -393,54 +337,13 @@ class DataReductionProxyConfig
// Enforce usage on the IO thread.
base::ThreadChecker thread_checker_;
- // Thresholds from the field trial at which auto Lo-Fi is turned on.
- // If the effective connection type is at least as slow as
- // |lofi_effective_connection_type_threshold_|, Lo-Fi would be turned on.
- net::EffectiveConnectionType lofi_effective_connection_type_threshold_;
-
- // State of auto Lo-Fi is not changed more than once in any period of
- // duration shorter than |auto_lofi_hysteresis_|.
- base::TimeDelta auto_lofi_hysteresis_;
-
- // Time when the network quality was last checked.
- base::TimeTicks network_quality_last_checked_;
-
- // True iff the network was determined to be prohibitively slow when the
- // network quality was last updated. This happens on when the network quality
- // was last checked, and not more than once in any window of duration shorter
- // than |auto_lofi_hysteresis_|.
- bool network_prohibitively_slow_;
-
// The current connection type.
net::NetworkChangeNotifier::ConnectionType connection_type_;
- // True if the connection type changed since the last call to
- // IsNetworkQualityProhibitivelySlow(). This call happens only on main frame
- // requests.
- bool connection_type_changed_;
-
// If true, Lo-Fi is turned off for the rest of the session. This is set to
// true if Lo-Fi is disabled via flags or if the user implicitly opts out.
bool lofi_off_;
- // Timestamp when the most recent query of the Network Quality Estimator
- // happened.
- base::TimeTicks last_query_;
-
- // Holds the estimated network quality at the last query of the estimator.
- // This should be used only for the purpose of recording Lo-Fi accuracy UMA.
- NetworkQualityAtLastQuery network_quality_at_last_query_;
-
- // True if the previous state of Lo-Fi was on, so that change in Lo-Fi status
- // can be recorded properly. This is not recorded for the control group,
- // because it is only used to report changes in request headers, and the
- // request headers are never modified in the control group.
- bool previous_state_lofi_on_;
-
- // Intervals after the main frame request arrives at which accuracy of network
- // quality prediction is recorded.
- std::vector<base::TimeDelta> lofi_accuracy_recording_intervals_;
-
// Set to true if the captive portal probe for the current network has been
// blocked.
bool is_captive_portal_;
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 ef0b077e08c..2453c726bae 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
@@ -28,6 +28,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/variations/net/variations_http_headers.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
#include "net/base/load_timing_info.h"
@@ -390,6 +391,15 @@ void DataReductionProxyConfigServiceClient::RetrieveRemoteConfig() {
fetcher_ = std::move(fetcher);
fetch_in_progress_ = true;
+
+ // Attach variations headers.
+ net::HttpRequestHeaders headers;
+ variations::AppendVariationHeaders(config_service_url_, false /* incognito */,
+ false /* uma_enabled */,
+ false /* is_signed_in */, &headers);
+ if (!headers.IsEmpty())
+ fetcher_->SetExtraRequestHeaders(headers.ToString());
+
fetcher_->Start();
}
@@ -423,7 +433,7 @@ DataReductionProxyConfigServiceClient::GetURLFetcherForConfig(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can control Data Saver on Android via 'Data Saver' setting. "
"Data Saver is not available on iOS, and on desktop it is enabled "
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index ce2beb17215..9ad05df49b9 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -49,23 +49,12 @@ TestDataReductionProxyConfig::TestDataReductionProxyConfig(
configurator,
event_creator),
tick_clock_(nullptr),
- network_quality_prohibitively_slow_set_(false),
- network_quality_prohibitively_slow_(false),
- lofi_accuracy_recording_intervals_set_(false),
is_captive_portal_(false) {
}
TestDataReductionProxyConfig::~TestDataReductionProxyConfig() {
}
-bool TestDataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
- const net::NetworkQualityEstimator* network_quality_estimator) {
- if (network_quality_prohibitively_slow_set_)
- return network_quality_prohibitively_slow_;
- return DataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
- network_quality_estimator);
-}
-
void TestDataReductionProxyConfig::ResetParamFlagsForTest() {
config_values_ = base::MakeUnique<TestDataReductionProxyParams>();
}
@@ -82,25 +71,6 @@ void TestDataReductionProxyConfig::ResetLoFiStatusForTest() {
lofi_off_ = false;
}
-void TestDataReductionProxyConfig::SetNetworkProhibitivelySlow(
- bool network_quality_prohibitively_slow) {
- network_quality_prohibitively_slow_set_ = true;
- network_quality_prohibitively_slow_ = network_quality_prohibitively_slow;
-}
-
-void TestDataReductionProxyConfig::SetLofiAccuracyRecordingIntervals(
- const std::vector<base::TimeDelta>& lofi_accuracy_recording_intervals) {
- lofi_accuracy_recording_intervals_set_ = true;
- lofi_accuracy_recording_intervals_ = lofi_accuracy_recording_intervals;
-}
-
-const std::vector<base::TimeDelta>&
-TestDataReductionProxyConfig::GetLofiAccuracyRecordingIntervals() const {
- if (lofi_accuracy_recording_intervals_set_)
- return lofi_accuracy_recording_intervals_;
- return DataReductionProxyConfig::GetLofiAccuracyRecordingIntervals();
-}
-
void TestDataReductionProxyConfig::SetTickClock(base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index c124e62290e..2c5a6fde68f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -70,18 +70,6 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
// Resets the Lo-Fi status to default state.
void ResetLoFiStatusForTest();
- // Allows tests to mark the network as prohibitively slow.
- void SetNetworkProhibitivelySlow(bool network_quality_prohibitively_slow);
-
- bool IsNetworkQualityProhibitivelySlow(
- const net::NetworkQualityEstimator* network_quality_estimator) override;
-
- void SetLofiAccuracyRecordingIntervals(
- const std::vector<base::TimeDelta>& lofi_accuracy_recording_intervals);
-
- const std::vector<base::TimeDelta>& GetLofiAccuracyRecordingIntervals()
- const override;
-
// Sets the |tick_clock_| to |tick_clock|. Ownership of |tick_clock| is not
// passed to the callee.
void SetTickClock(base::TickClock* tick_clock);
@@ -121,13 +109,6 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
base::Optional<bool> was_data_reduction_proxy_used_;
base::Optional<int> proxy_index_;
- bool network_quality_prohibitively_slow_set_;
- // True if the network quality is slow enough to turn Lo-Fi ON.
- bool network_quality_prohibitively_slow_;
-
- bool lofi_accuracy_recording_intervals_set_;
- std::vector<base::TimeDelta> lofi_accuracy_recording_intervals_;
-
// Set to true if the captive portal probe for the current network has been
// blocked.
bool is_captive_portal_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 8e9f7281d5d..1dd4241f78a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -401,7 +401,7 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
// Set the connection type to 4G so that warm up URL is fetched even if
// the test device does not have connectivity.
- net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_4G);
RunUntilIdle();
@@ -417,7 +417,7 @@ TEST_F(DataReductionProxyConfigTest, WarmupURL) {
// Warm up URL should not be fetched since the device does not have
// connectivity.
- net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
net::NetworkChangeNotifier::CONNECTION_NONE);
RunUntilIdle();
@@ -817,7 +817,8 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
};
std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
- DataReductionProxyMutableConfigValues::CreateFromParams(params());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
+
config_values->UpdateValues(proxies_for_http);
std::unique_ptr<DataReductionProxyConfig> config(new DataReductionProxyConfig(
task_runner(), net_log(), std::move(config_values), configurator(),
@@ -834,643 +835,11 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
}
}
-TEST_F(DataReductionProxyConfigTest, LoFiOn) {
- const struct {
- bool lofi_enabled;
- bool previews_black_list_used;
- const std::string lofi_field_trial_group_name;
- bool network_prohibitively_slow;
- bool expect_lofi_header;
- int bucket_to_check_for_auto_lofi_uma;
- int expect_bucket_count;
- bool is_opted_out;
- } tests[] = {
- {
- // The Lo-Fi switch is off and the user is not in the enabled field
- // trial group. Lo-Fi should not be used.
- false, false, std::string(), false, false, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
- },
- {
- // The Lo-Fi switch is off and the user is not in enabled field trial
- // group and the network quality is bad. Lo-Fi should not be used.
- false, false, std::string(), true, false, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
-
- },
- {
- // Lo-Fi is enabled through command line switch, but opted out. LoFi
- // should be used.
- true, false, std::string(), false, true, 0,
- 0, // not in enabled field trial, UMA is not recorded
- true,
- },
- {
- // Lo-Fi is enabled through command line switch. LoFi should be used.
- true, false, std::string(), false, true, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, false, "Enabled", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, false, "Enabled_Control", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used.
- false, false, "Enabled", true, true,
- 1, // Lo-Fi request header is now used (state change: empty to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used.
- false, false, "Enabled_Control", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used again.
- false, false, "Enabled", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used again.
- false, false, "Enabled_Control", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, false, "Enabled", false, false,
- 2, // Lo-Fi request header is not used (state change: low to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, false, "Enabled_Control", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- {
- // The Lo-Fi switch is off and the user is not in the enabled field
- // trial group. Lo-Fi should not be used.
- false, true, std::string(), false, false, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
- },
- {
- // The Lo-Fi switch is off and the user is not in enabled field trial
- // group and the network quality is bad. Lo-Fi should not be used.
- false, true, std::string(), true, false, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
- },
- {
- // Lo-Fi is enabled through command line switch. LoFi should be used.
- true, true, std::string(), false, true, 0,
- 0, // not in enabled field trial, UMA is not recorded
- false,
- },
- {
- // Lo-Fi is enabled through command line switch, but opted out. LoFi
- // should be used.
- true, true, std::string(), false, true, 0,
- 0, // not in enabled field trial, UMA is not recorded
- true,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, true, "Enabled", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, true, "Enabled_Control", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used.
- false, true, "Enabled", true, true,
- 1, // Lo-Fi request header is now used (state change: empty to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used.
- false, true, "Enabled_Control", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used again.
- false, true, "Enabled", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group and the network
- // quality is bad. Lo-Fi should be used again.
- false, true, "Enabled_Control", true, true,
- 3, // Lo-Fi request header is now used (state change: low to low)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, true, "Enabled", false, false,
- 2, // Lo-Fi request header is not used (state change: low to empty)
- 1, false,
- },
- {
- // The user is in the enabled field trial group but the network
- // quality is not bad. Lo-Fi should not be used.
- false, true, "Enabled_Control", false, false,
- 0, // Lo-Fi request header is not used (state change: empty to empty)
- 1, false,
- },
- };
- for (size_t i = 0; i < arraysize(tests); ++i) {
- config()->ResetLoFiStatusForTest();
-
- // Ensure not using proxy-decides-transform feature.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- base::FieldTrialList field_trial_list(nullptr);
- if (tests[i].previews_black_list_used) {
- base::FieldTrialList::CreateFieldTrial(
- "DataReductionProxyPreviewsBlackListTransition", "Enabled_");
- } else if (tests[i].is_opted_out) {
- config()->SetLoFiModeOff();
- }
- if (tests[i].lofi_enabled) {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueAlwaysOn);
- } else {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi, std::string());
- }
-
- if (!tests[i].lofi_field_trial_group_name.empty()) {
- base::FieldTrialList::CreateFieldTrial(
- params::GetLoFiFieldTrialName(),
- tests[i].lofi_field_trial_group_name);
- }
-
- EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
- .WillRepeatedly(testing::Return(tests[i].network_prohibitively_slow));
-
- base::HistogramTester histogram_tester;
- net::TestURLRequestContext context_;
- net::TestDelegate delegate_;
- std::unique_ptr<net::URLRequest> request = context_.CreateRequest(
- GURL(), net::IDLE, &delegate_, TRAFFIC_ANNOTATION_FOR_TESTS);
- request->SetLoadFlags(request->load_flags() |
- net::LOAD_MAIN_FRAME_DEPRECATED);
- std::unique_ptr<TestPreviewsDecider> previews_decider =
- base::MakeUnique<TestPreviewsDecider>(!tests[i].is_opted_out);
- bool should_enable_lofi =
- config()->ShouldEnableLoFi(*request.get(), *previews_decider.get());
- if (tests[i].expect_bucket_count != 0) {
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.AutoLoFiRequestHeaderState.Unknown",
- tests[i].bucket_to_check_for_auto_lofi_uma,
- tests[i].expect_bucket_count);
- }
-
- EXPECT_EQ(tests[i].expect_lofi_header, should_enable_lofi) << i;
- }
-}
-
-TEST_F(DataReductionProxyConfigTest, AutoLoFiParams) {
- DataReductionProxyConfig config(task_runner(), nullptr, nullptr,
- configurator(), event_creator());
- variations::testing::ClearAllVariationParams();
- std::map<std::string, std::string> variation_params;
- std::map<std::string, std::string> variation_params_flag;
-
- variation_params["effective_connection_type"] = "Slow2G";
- variation_params_flag["effective_connection_type"] = "2G";
-
- variation_params["hysteresis_period_seconds"] = "360";
- variation_params_flag["hysteresis_period_seconds"] = "361";
-
- variation_params["spurious_field"] = "480";
- variation_params_flag["spurious_field"] = "481";
-
- ASSERT_TRUE(variations::AssociateVariationParams(
- params::GetLoFiFieldTrialName(), "Enabled", variation_params));
-
- ASSERT_TRUE(variations::AssociateVariationParams(
- params::GetLoFiFlagFieldTrialName(), "Enabled", variation_params_flag));
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFlagFieldTrialName(),
- "Enabled");
-
- scoped_refptr<net::URLRequestContextGetter> request_context_getter =
- new net::TestURLRequestContextGetter(task_runner());
- config.InitializeOnIOThread(request_context_getter.get(),
- request_context_getter.get());
-
- const struct {
- bool lofi_flag_group;
-
- } tests[] = {
- {
- false,
- },
- {
- true,
- },
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- net::EffectiveConnectionType expected_effective_connection_type =
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- int expected_hysteresis_sec = 360;
-
- if (tests[i].lofi_flag_group) {
- // LoFi flag field trial has higher priority than LoFi field trial.
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
- expected_effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_2G;
- expected_hysteresis_sec = 361;
- }
-
- config.PopulateAutoLoFiParams();
-
- EXPECT_EQ(expected_effective_connection_type,
- config.lofi_effective_connection_type_threshold_);
- EXPECT_EQ(base::TimeDelta::FromSeconds(expected_hysteresis_sec),
- config.auto_lofi_hysteresis_);
-
- net::TestNetworkQualityEstimator test_network_quality_estimator;
-
- // Network is slow.
- test_network_quality_estimator.set_effective_connection_type(
- expected_effective_connection_type);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Network quality improved. However, network should still be marked as slow
- // because of hysteresis.
- test_network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_4G);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Change the last update time to be older than the hysteresis duration.
- // Checking network quality afterwards should show that network is no longer
- // slow.
- config.network_quality_last_checked_ =
- base::TimeTicks::Now() -
- base::TimeDelta::FromSeconds(expected_hysteresis_sec + 1);
- EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Changing the network quality has no effect because of hysteresis.
- test_network_quality_estimator.set_effective_connection_type(
- expected_effective_connection_type);
- EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Change in connection type changes the network quality despite hysteresis.
- EXPECT_FALSE(config.connection_type_changed_);
- net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
- net::NetworkChangeNotifier::CONNECTION_WIFI);
- RunUntilIdle();
-
- EXPECT_TRUE(config.connection_type_changed_);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
- }
-}
-
-// Tests that default parameters for Lo-Fi are used when the parameters from
-// field trial are missing.
-TEST_F(DataReductionProxyConfigTest, AutoLoFiMissingParams) {
- DataReductionProxyConfig config(task_runner(), nullptr, nullptr,
- configurator(), event_creator());
- variations::testing::ClearAllVariationParams();
- std::map<std::string, std::string> variation_params;
- variation_params["spurious_field"] = "480";
-
- ASSERT_TRUE(variations::AssociateVariationParams(
- params::GetLoFiFieldTrialName(), "Enabled", variation_params));
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
-
- config.PopulateAutoLoFiParams();
-
- EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- config.lofi_effective_connection_type_threshold_);
- EXPECT_EQ(base::TimeDelta::FromSeconds(60), config.auto_lofi_hysteresis_);
-}
-
-TEST_F(DataReductionProxyConfigTest, AutoLoFiParamsSlowConnectionsFlag) {
- DataReductionProxyConfig config(task_runner(), nullptr, nullptr,
- configurator(), event_creator());
- variations::testing::ClearAllVariationParams();
-
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
- scoped_refptr<net::URLRequestContextGetter> request_context_getter =
- new net::TestURLRequestContextGetter(task_runner());
- config.InitializeOnIOThread(request_context_getter.get(),
- request_context_getter.get());
-
- config.PopulateAutoLoFiParams();
-
- net::EffectiveConnectionType expected_effective_connection_type =
- net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- int hysteresis_sec = 60;
- EXPECT_EQ(expected_effective_connection_type,
- config.lofi_effective_connection_type_threshold_);
- EXPECT_EQ(base::TimeDelta::FromSeconds(hysteresis_sec),
- config.auto_lofi_hysteresis_);
-
- net::TestNetworkQualityEstimator test_network_quality_estimator;
-
- // Network is slow.
- test_network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Network quality improved. However, network should still be marked as slow
- // because of hysteresis.
- test_network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_2G);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Change the last update time to be older than the hysteresis duration.
- // Checking network quality afterwards should show that network is no longer
- // slow.
- config.network_quality_last_checked_ =
- base::TimeTicks::Now() - base::TimeDelta::FromSeconds(hysteresis_sec + 1);
- EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Changing the network quality has no effect because of hysteresis.
- test_network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
- EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-
- // Change in connection type changes the network quality despite hysteresis.
- EXPECT_FALSE(config.connection_type_changed_);
- net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
- net::NetworkChangeNotifier::CONNECTION_WIFI);
- RunUntilIdle();
-
- EXPECT_TRUE(config.connection_type_changed_);
- EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
-}
-
-// Tests if metrics for Lo-Fi accuracy are recorded properly.
-TEST_F(DataReductionProxyConfigTest, LoFiAccuracy) {
- std::unique_ptr<base::SimpleTestTickClock> tick_clock(
- new base::SimpleTestTickClock());
-
- std::vector<base::TimeDelta> lofi_accuracy_recording_intervals;
- lofi_accuracy_recording_intervals.push_back(base::TimeDelta::FromSeconds(0));
-
- TestDataReductionProxyConfig config(task_runner(), nullptr, configurator(),
- event_creator());
- config.SetLofiAccuracyRecordingIntervals(lofi_accuracy_recording_intervals);
- config.SetTickClock(tick_clock.get());
-
- variations::testing::ClearAllVariationParams();
- std::map<std::string, std::string> variation_params;
-
- int expected_hysteresis_sec = 360;
-
- variation_params["effective_connection_type"] = "Slow2G";
- variation_params["hysteresis_period_seconds"] =
- base::IntToString(expected_hysteresis_sec);
-
- const struct {
- std::string description;
- std::string field_trial_group;
- net::EffectiveConnectionType effective_connection_type;
- net::EffectiveConnectionType recent_effective_connection_type;
- bool expect_network_quality_slow;
- uint32_t bucket_to_check;
- uint32_t expected_bucket_count;
- } tests[] = {
- {"Predicted slow, actually slow, Enabled group", "Enabled",
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
- {"Predicted slow, actually slow, Enabled_NoControl group",
- "Enabled_NoControl", net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
- {"Predicted slow, actually slow, Control group", "Control",
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
- {"Predicted slow, actually not slow", "Enabled",
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::EFFECTIVE_CONNECTION_TYPE_2G, true, 1, 1},
- {"Predicted not slow, actually slow", "Enabled",
- net::EFFECTIVE_CONNECTION_TYPE_2G,
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, false, 2, 1},
- {"Predicted not slow, actually not slow", "Enabled",
- net::EFFECTIVE_CONNECTION_TYPE_2G, net::EFFECTIVE_CONNECTION_TYPE_2G,
- false, 3, 1},
- };
-
- for (const auto& test : tests) {
- base::FieldTrialList field_trial_list(nullptr);
- variations::testing::ClearAllVariationIDs();
- variations::testing::ClearAllVariationParams();
- ASSERT_TRUE(variations::AssociateVariationParams(
- params::GetLoFiFieldTrialName(), test.field_trial_group,
- variation_params))
- << test.description;
-
- ASSERT_NE(nullptr,
- base::FieldTrialList::CreateFieldTrial(
- params::GetLoFiFieldTrialName(), test.field_trial_group))
- << test.description;
- config.PopulateAutoLoFiParams();
-
- net::TestNetworkQualityEstimator test_network_quality_estimator;
-
- base::HistogramTester histogram_tester;
- test_network_quality_estimator.set_effective_connection_type(
- test.effective_connection_type);
- test_network_quality_estimator.set_recent_effective_connection_type(
- test.recent_effective_connection_type);
- ASSERT_EQ(test.expect_network_quality_slow,
- config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator))
- << test.description;
- RunUntilIdle();
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LoFi.Accuracy.0.Unknown", 1);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.LoFi.Accuracy.0.Unknown", test.bucket_to_check,
- test.expected_bucket_count);
- }
-}
-
-// Tests if metrics for Lo-Fi accuracy are recorded properly at the specified
-// interval.
-TEST_F(DataReductionProxyConfigTest, LoFiAccuracyNonZeroDelay) {
- std::unique_ptr<base::SimpleTestTickClock> tick_clock(
- new base::SimpleTestTickClock());
-
- std::vector<base::TimeDelta> lofi_accuracy_recording_intervals;
- lofi_accuracy_recording_intervals.push_back(base::TimeDelta::FromSeconds(1));
-
- TestDataReductionProxyConfig config(task_runner(), nullptr, configurator(),
- event_creator());
- config.SetLofiAccuracyRecordingIntervals(lofi_accuracy_recording_intervals);
- config.SetTickClock(tick_clock.get());
-
- variations::testing::ClearAllVariationParams();
- std::map<std::string, std::string> variation_params;
-
- variation_params["effective_connection_type"] = "Slow2G";
-
- ASSERT_TRUE(variations::AssociateVariationParams(
- params::GetLoFiFieldTrialName(), "Enabled", variation_params));
-
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- config.PopulateAutoLoFiParams();
-
- net::TestNetworkQualityEstimator test_network_quality_estimator;
-
- base::HistogramTester histogram_tester;
- // Network was predicted to be slow and actually was slow.
- test_network_quality_estimator.set_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
- test_network_quality_estimator.set_recent_effective_connection_type(
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
- ASSERT_TRUE(config.IsNetworkQualityProhibitivelySlow(
- &test_network_quality_estimator));
- tick_clock->Advance(base::TimeDelta::FromSeconds(1));
-
- // Sleep to ensure that the delayed task is posted.
- base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
- RunUntilIdle();
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LoFi.Accuracy.1.Unknown", 1);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.LoFi.Accuracy.1.Unknown", 0, 1);
-}
-
-TEST_F(DataReductionProxyConfigTest, ShouldEnableLoFiDoesNotFallback) {
- // Turn off proxy-decides-transform feature (path for client ECT check).
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- // Enable Server Lo-Fi.
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueAlwaysOn);
-
- // Also enable LitePages
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableDataReductionProxyLitePage);
-
- net::TestURLRequestContext context;
- net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> request = context.CreateRequest(
- GURL(), net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
- request->SetLoadFlags(request->load_flags() |
- net::LOAD_MAIN_FRAME_DEPRECATED);
- std::unique_ptr<TestPreviewsDecider> previews_decider =
- base::MakeUnique<TestPreviewsDecider>(false);
-
- EXPECT_TRUE(
- config()->ShouldEnableLitePages(*request.get(), *previews_decider.get()));
- EXPECT_FALSE(
- config()->ShouldEnableLoFi(*request.get(), *previews_decider.get()));
-}
-
-TEST_F(DataReductionProxyConfigTest, ShouldEnableLoFiWithECTCheck) {
- // Turn off proxy-decides-transform feature (so will locally check ECT).
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- // Enable Server Lo-Fi field trial.
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
-
- EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
- .WillRepeatedly(testing::Return(true));
-
- net::TestURLRequestContext context;
- net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> request = context.CreateRequest(
- GURL(), net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
- request->SetLoadFlags(request->load_flags() |
- net::LOAD_MAIN_FRAME_DEPRECATED);
- std::unique_ptr<TestPreviewsDecider> previews_decider =
- base::MakeUnique<TestPreviewsDecider>(false);
-
- EXPECT_TRUE(
- config()->ShouldEnableLoFi(*request.get(), *previews_decider.get()));
-
- // Now verify should not enable with good network connection.
- EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
- .WillRepeatedly(testing::Return(false));
-
- EXPECT_FALSE(
- config()->ShouldEnableLoFi(*request.get(), *previews_decider.get()));
-}
-
-TEST_F(DataReductionProxyConfigTest, ShouldEnableLoFiWithoutECTCheck) {
- // Turn on proxy-decides-transform feature (so will not locally check ECT).
+TEST_F(DataReductionProxyConfigTest, ShouldEnableLoFi) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kDataReductionProxyDecidesTransform);
- // Enable Server Lo-Fi field trial.
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
-
// Expect network quality check is never called.
EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_)).Times(0);
@@ -1487,51 +856,11 @@ TEST_F(DataReductionProxyConfigTest, ShouldEnableLoFiWithoutECTCheck) {
config()->ShouldEnableLoFi(*request.get(), *previews_decider.get()));
}
-TEST_F(DataReductionProxyConfigTest, ShouldEnableLitePagesWithECTCheck) {
- // Turn off proxy-decides-transform feature (so will locally check ECT).
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
- // Enable Server Lo-Fi field trial.
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled_Preview");
-
- EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
- .WillRepeatedly(testing::Return(true));
-
- net::TestURLRequestContext context;
- net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> request = context.CreateRequest(
- GURL(), net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
- request->SetLoadFlags(request->load_flags() |
- net::LOAD_MAIN_FRAME_DEPRECATED);
- std::unique_ptr<TestPreviewsDecider> previews_decider =
- base::MakeUnique<TestPreviewsDecider>(false);
-
- EXPECT_TRUE(
- config()->ShouldEnableLitePages(*request.get(), *previews_decider.get()));
-
- // Now verify should not enable with good network connection.
- EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
- .WillRepeatedly(testing::Return(false));
-
- EXPECT_FALSE(
- config()->ShouldEnableLitePages(*request.get(), *previews_decider.get()));
-}
-
-TEST_F(DataReductionProxyConfigTest, ShouldEnableLitePagesWithoutECTCheck) {
- // Turn on proxy-decides-transform feature (so will not locally check ECT).
+TEST_F(DataReductionProxyConfigTest, ShouldEnableLitePages) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kDataReductionProxyDecidesTransform);
- // Enable Server Lo-Fi field trial.
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled_Preview");
-
// Expect network quality check is never called.
EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_)).Times(0);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc
index 3812a8d531e..7e70c062676 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc
@@ -22,7 +22,7 @@ namespace {
class DataUseUserDataBytes : public base::SupportsUserData::Data {
public:
// Key used to store data usage in userdata until the page URL is available.
- static const void* kUserDataKey;
+ static const void* const kUserDataKey;
DataUseUserDataBytes(int64_t network_bytes, int64_t original_bytes)
: network_bytes_(network_bytes), original_bytes_(original_bytes) {}
@@ -45,7 +45,7 @@ class DataUseUserDataBytes : public base::SupportsUserData::Data {
const char kOtherHostName[] = "Other";
// static
-const void* DataUseUserDataBytes::kUserDataKey =
+const void* const DataUseUserDataBytes::kUserDataKey =
&DataUseUserDataBytes::kUserDataKey;
} // namespace
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index 4985301b706..82b1530ede6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -143,12 +143,8 @@ void DataReductionProxyDelegate::OnBeforeTunnelRequest(
bool DataReductionProxyDelegate::IsTrustedSpdyProxy(
const net::ProxyServer& proxy_server) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!proxy_server.is_https() ||
- !params::IsIncludedInTrustedSpdyProxyFieldTrial() ||
- !proxy_server.is_valid()) {
- return false;
- }
- return config_ && config_->IsDataReductionProxy(proxy_server, nullptr);
+ return proxy_server.is_valid() && proxy_server.is_https() && config_ &&
+ config_->IsDataReductionProxy(proxy_server, nullptr);
}
void DataReductionProxyDelegate::OnTunnelHeadersReceived(
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index a39600bd77d..ab7f1571e1a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -152,43 +152,29 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
.Build();
const struct {
- bool is_in_trusted_spdy_proxy_field_trial;
net::ProxyServer::Scheme first_proxy_scheme;
net::ProxyServer::Scheme second_proxy_scheme;
bool expect_proxy_is_trusted;
} test_cases[] = {
- {false, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_INVALID,
- false},
- {true, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_INVALID,
- false},
- {true, net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_INVALID,
- false},
- {true, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_HTTP,
- false},
- {true, net::ProxyServer::SCHEME_INVALID, net::ProxyServer::SCHEME_INVALID,
+ {net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_INVALID, false},
+ {net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_INVALID, false},
+ {net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_HTTP, false},
+ {net::ProxyServer::SCHEME_INVALID, net::ProxyServer::SCHEME_INVALID,
false},
// First proxy is HTTPS, and second is invalid.
- {true, net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_INVALID,
- true},
+ {net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_INVALID, true},
// First proxy is invalid, and second proxy is HTTPS.
- {true, net::ProxyServer::SCHEME_INVALID, net::ProxyServer::SCHEME_HTTPS,
- true},
+ {net::ProxyServer::SCHEME_INVALID, net::ProxyServer::SCHEME_HTTPS, true},
// First proxy is HTTPS, and second is HTTP.
- {true, net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTPS,
- true},
+ {net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTPS, true},
// Second proxy is HTTPS, and first is HTTP.
- {true, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_HTTPS,
- true},
- {true, net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_INVALID,
- false},
- {true, net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTP,
- false},
- {true, net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTPS,
- true},
+ {net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_HTTPS, true},
+ {net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_INVALID, false},
+ {net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTP, false},
+ {net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTPS, true},
};
for (const auto& test : test_cases) {
ASSERT_EQ(test.expect_proxy_is_trusted,
- test.is_in_trusted_spdy_proxy_field_trial &&
(test.first_proxy_scheme == net::ProxyServer::SCHEME_HTTPS ||
test.second_proxy_scheme == net::ProxyServer::SCHEME_HTTPS))
<< (&test - test_cases);
@@ -208,8 +194,7 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
}
std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
- DataReductionProxyMutableConfigValues::CreateFromParams(
- test_context->test_params());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
config_values->UpdateValues(proxies_for_http);
std::unique_ptr<DataReductionProxyConfig> config(
@@ -225,15 +210,6 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
test_context->io_data()->net_log());
base::FieldTrialList field_trial_list(nullptr);
- EXPECT_TRUE(params::IsIncludedInTrustedSpdyProxyFieldTrial());
- if (!test.is_in_trusted_spdy_proxy_field_trial) {
- // Trusted Spdy proxy field trial experiment is enabled by default.
- base::FieldTrialList::CreateFieldTrial(
- params::GetTrustedSpdyProxyFieldTrialName(), "Control");
- }
- EXPECT_EQ(test.is_in_trusted_spdy_proxy_field_trial,
- params::IsIncludedInTrustedSpdyProxyFieldTrial());
-
EXPECT_EQ(test.expect_proxy_is_trusted,
delegate.IsTrustedSpdyProxy(first_proxy) ||
delegate.IsTrustedSpdyProxy(second_proxy))
@@ -318,8 +294,7 @@ TEST(DataReductionProxyDelegate, AlternativeProxy) {
}
std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
- DataReductionProxyMutableConfigValues::CreateFromParams(
- test_context->test_params());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
config_values->UpdateValues(proxies_for_http);
std::unique_ptr<DataReductionProxyConfig> config(
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index e43687a3b97..24fb1506d33 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -122,7 +122,7 @@ DataReductionProxyIOData::DataReductionProxyIOData(
DataReductionProxyMutableConfigValues* raw_mutable_config = nullptr;
if (use_config_client) {
std::unique_ptr<DataReductionProxyMutableConfigValues> mutable_config =
- DataReductionProxyMutableConfigValues::CreateFromParams(params.get());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
raw_mutable_config = mutable_config.get();
config_.reset(new DataReductionProxyConfig(
io_task_runner, net_log, std::move(mutable_config), configurator_.get(),
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
index 4985b9a284e..ddd898a4a15 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
@@ -4,27 +4,15 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
-#include <vector>
-
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
namespace data_reduction_proxy {
-std::unique_ptr<DataReductionProxyMutableConfigValues>
-DataReductionProxyMutableConfigValues::CreateFromParams(
- const DataReductionProxyParams* params) {
- std::unique_ptr<DataReductionProxyMutableConfigValues> config_values(
- new DataReductionProxyMutableConfigValues());
- return config_values;
-}
-
DataReductionProxyMutableConfigValues::DataReductionProxyMutableConfigValues()
- : use_override_proxies_for_http_(false) {
- use_override_proxies_for_http_ =
- params::GetOverrideProxiesForHttpFromCommandLine(
- &override_proxies_for_http_);
-
+ : use_override_proxies_for_http_(
+ params::GetOverrideProxiesForHttpFromCommandLine(
+ &override_proxies_for_http_)) {
// Constructed on the UI thread, but should be checked on the IO thread.
thread_checker_.DetachFromThread();
}
@@ -43,9 +31,6 @@ DataReductionProxyMutableConfigValues::proxies_for_http() const {
// without valid credentials could cause a proxy bypass.
return override_proxies_for_http_;
}
- // TODO(sclittle): Support overriding individual proxies in the proxy list
- // according to field trials such as the DRP QUIC field trial and their
- // corresponding command line flags (crbug.com/533637).
return proxies_for_http_;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
index 5e97de0b54e..a749d00b43e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_MUTABLE_CONFIG_VALUES_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_MUTABLE_CONFIG_VALUES_H_
-#include <memory>
#include <vector>
#include "base/macros.h"
@@ -16,7 +15,6 @@
namespace data_reduction_proxy {
-class DataReductionProxyParams;
class DataReductionProxyServer;
// A |DataReductionProxyConfigValues| which is permitted to change its
@@ -24,11 +22,7 @@ class DataReductionProxyServer;
class DataReductionProxyMutableConfigValues
: public DataReductionProxyConfigValues {
public:
- // Creates a new |DataReductionProxyMutableConfigValues| using |params| as
- // the basis for its initial values.
- static std::unique_ptr<DataReductionProxyMutableConfigValues>
- CreateFromParams(const DataReductionProxyParams* params);
-
+ DataReductionProxyMutableConfigValues();
~DataReductionProxyMutableConfigValues() override;
// Updates |proxies_for_http_| with the provided values.
@@ -43,16 +37,13 @@ class DataReductionProxyMutableConfigValues
const std::vector<DataReductionProxyServer>& proxies_for_http()
const override;
- protected:
- DataReductionProxyMutableConfigValues();
-
private:
std::vector<DataReductionProxyServer> proxies_for_http_;
+ std::vector<DataReductionProxyServer> override_proxies_for_http_;
// Permits use of locally specified Data Reduction Proxy servers instead of
// ones specified from the Data Saver API.
- bool use_override_proxies_for_http_;
- std::vector<DataReductionProxyServer> override_proxies_for_http_;
+ const bool use_override_proxies_for_http_;
// Enforce usage on the IO thread.
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
index 2e0917f62b6..02d48226c83 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -24,9 +25,8 @@ class DataReductionProxyMutableConfigValuesTest : public testing::Test {
~DataReductionProxyMutableConfigValuesTest() override {}
void Init() {
- params_.reset(new DataReductionProxyParams());
mutable_config_values_ =
- DataReductionProxyMutableConfigValues::CreateFromParams(params_.get());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
}
DataReductionProxyMutableConfigValues* mutable_config_values() const {
@@ -34,7 +34,6 @@ class DataReductionProxyMutableConfigValuesTest : public testing::Test {
}
private:
- std::unique_ptr<DataReductionProxyParams> params_;
std::unique_ptr<DataReductionProxyMutableConfigValues> mutable_config_values_;
};
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index ca8d3b05dab..2a6445af01d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -56,6 +56,8 @@ enum AcceptTransformEvent {
COMPRESSED_VIDEO_REQUESTED = 5,
IDENTITY_TRANSFORM_REQUESTED = 6,
IDENTITY_TRANSFORM_RECEIVED = 7,
+ COMPRESSED_VIDEO_RECEIVED = 8,
+ UNKNOWN_TRANSFORM_RECEIVED = 9,
ACCEPT_TRANSFORM_EVENT_BOUNDARY
};
@@ -206,6 +208,7 @@ void RecordAcceptTransformSentUMA(
case TRANSFORM_NONE:
break;
case TRANSFORM_PAGE_POLICIES_EMPTY_IMAGE:
+ case TRANSFORM_UNKNOWN:
NOTREACHED();
break;
}
@@ -218,6 +221,9 @@ void RecordAcceptTransformReceivedUMA(const net::URLRequest& request) {
}
switch (ParseResponseTransform(*response_headers)) {
+ case TRANSFORM_UNKNOWN:
+ RecordAcceptTransformEvent(UNKNOWN_TRANSFORM_RECEIVED);
+ break;
case TRANSFORM_LITE_PAGE:
RecordAcceptTransformEvent(LITE_PAGE_TRANSFORM_RECEIVED);
break;
@@ -230,11 +236,10 @@ void RecordAcceptTransformReceivedUMA(const net::URLRequest& request) {
case TRANSFORM_IDENTITY:
RecordAcceptTransformEvent(IDENTITY_TRANSFORM_RECEIVED);
break;
- case TRANSFORM_NONE:
- break;
case TRANSFORM_COMPRESSED_VIDEO:
- // Compressed video response would instead be a redirect to resource.
- NOTREACHED();
+ RecordAcceptTransformEvent(COMPRESSED_VIDEO_RECEIVED);
+ break;
+ case TRANSFORM_NONE:
break;
}
}
@@ -266,6 +271,17 @@ void VerifyHttpRequestHeaders(bool via_chrome_proxy,
}
}
+// If the response is the entire resource, then the renderer won't show a
+// placeholder. This should match the behavior in blink::ImageResource.
+bool IsEntireResource(const net::HttpResponseHeaders* response_headers) {
+ if (!response_headers || response_headers->response_code() != 206)
+ return true;
+
+ int64_t first, last, length;
+ return response_headers->GetContentRangeFor206(&first, &last, &length) &&
+ first == 0 && last + 1 == length;
+}
+
} // namespace
DataReductionProxyNetworkDelegate::DataReductionProxyNetworkDelegate(
@@ -335,11 +351,7 @@ void DataReductionProxyNetworkDelegate::OnBeforeStartTransactionInternal(
if (data_reduction_proxy_io_data_->lofi_decider()) {
data_reduction_proxy_io_data_->lofi_decider()
- ->MaybeSetAcceptTransformHeader(
- *request,
- !params::IsBlackListEnabledForServerPreviews() &&
- data_reduction_proxy_config_->lofi_off(),
- headers);
+ ->MaybeSetAcceptTransformHeader(*request, headers);
}
MaybeAddChromeProxyECTHeader(headers, *request);
@@ -494,12 +506,18 @@ void DataReductionProxyNetworkDelegate::OnCompletedInternal(
net::HttpRequestHeaders request_headers;
bool server_lofi = request->response_headers() &&
IsEmptyImagePreview(*(request->response_headers()));
- bool client_lofi =
+ bool will_show_client_lofi_placeholder =
data_reduction_proxy_io_data_ &&
data_reduction_proxy_io_data_->lofi_decider() &&
data_reduction_proxy_io_data_->lofi_decider()->IsClientLoFiImageRequest(
- *request);
- if ((server_lofi || client_lofi) && data_reduction_proxy_io_data_ &&
+ *request) &&
+ // If the response contains the entire resource, then the renderer won't
+ // show a placeholder for this image, so don't bother triggering an
+ // infobar.
+ !IsEntireResource(request->response_headers());
+
+ if ((server_lofi || will_show_client_lofi_placeholder) &&
+ data_reduction_proxy_io_data_ &&
data_reduction_proxy_io_data_->lofi_ui_service()) {
data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived(
*request);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 46b1d24828b..3151e620349 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
#include <map>
#include <string>
#include <utility>
@@ -24,6 +25,7 @@
#include "base/strings/safe_sprintf.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/scoped_feature_list.h"
@@ -229,7 +231,6 @@ class TestLoFiDecider : public LoFiDecider {
void MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
- bool is_previews_disabled,
net::HttpRequestHeaders* headers) const override {
if (should_request_lofi_resource_) {
headers->SetHeader(chrome_proxy_accept_transform_header(),
@@ -945,7 +946,6 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
"Enabled");
}
- config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
io_data()->SetLoFiModeActiveOnMainFrame(false);
net::ProxyInfo data_reduction_proxy_info;
@@ -1267,11 +1267,6 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
}
TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
- // Turn off proxy-decides-transform feature for these unit tests.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyDecidesTransform);
-
Init(USE_INSECURE_PROXY, false);
base::HistogramTester histogram_tester;
@@ -1328,44 +1323,29 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
// Check Lo-Fi histograms.
const struct {
- bool lofi_enabled_through_switch;
- bool auto_lofi_enabled;
+ bool lofi_enabled;
int expected_count;
} tests[] = {
{
// Lo-Fi disabled.
- false, false, 0,
+ false, 0,
},
{
- // Auto Lo-Fi enabled.
- // This should populate Lo-Fi content length histogram.
- false, true, 1,
- },
- {
- // Lo-Fi enabled through switch.
- // This should populate Lo-Fi content length histogram.
- true, false, 1,
- },
- {
- // Lo-Fi enabled through switch and Auto Lo-Fi also enabled.
- // This should populate Lo-Fi content length histogram.
- true, true, 1,
+ // Lo-Fi enabled so should populate Lo-Fi content length histogram.
+ true, 1,
},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
config()->ResetLoFiStatusForTest();
- config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
- base::FieldTrialList field_trial_list(nullptr);
- if (tests[i].auto_lofi_enabled) {
- base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
- "Enabled");
- }
- if (tests[i].lofi_enabled_through_switch) {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kDataReductionProxyLoFi,
- switches::kDataReductionProxyLoFiValueAlwaysOn);
+ base::test::ScopedFeatureList scoped_feature_list;
+ if (tests[i].lofi_enabled) {
+ scoped_feature_list.InitAndEnableFeature(
+ features::kDataReductionProxyDecidesTransform);
+ } else {
+ scoped_feature_list.InitAndDisableFeature(
+ features::kDataReductionProxyDecidesTransform);
}
// Needed as a parameter, but functionality is not tested.
@@ -1634,37 +1614,123 @@ TEST_F(DataReductionProxyNetworkDelegateTest, DetailedNetHistograms) {
}
}
-TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) {
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ NonServerLoFiResponseDoesNotTriggerInfobar) {
Init(USE_INSECURE_PROXY, false);
- // Enable Lo-Fi.
- const struct {
- bool lofi_response;
- bool was_server;
- } tests[] = {{false, false}, {true, true}, {true, false}};
- for (const auto& test : tests) {
- lofi_decider()->SetIsUsingClientLoFi(false);
+ ClearLoFiUIService();
+ lofi_decider()->SetIsUsingClientLoFi(false);
+ std::string response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: 200\r\n\r\n";
+
+ auto request =
+ FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+
+ EXPECT_FALSE(DataReductionProxyData::GetData(*request)->lofi_received());
+ VerifyDidNotifyLoFiResponse(false);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ ServerLoFiResponseDoesTriggerInfobar) {
+ Init(USE_INSECURE_PROXY, false);
+
+ ClearLoFiUIService();
+ lofi_decider()->SetIsUsingClientLoFi(false);
+ std::string response_headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: 200\r\n"
+ "Chrome-Proxy-Content-Transform: empty-image\r\n\r\n";
+
+ auto request =
+ FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+
+ EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lofi_received());
+ VerifyDidNotifyLoFiResponse(true);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ NonClientLoFiResponseDoesNotTriggerInfobar) {
+ Init(USE_INSECURE_PROXY, false);
+
+ ClearLoFiUIService();
+ lofi_decider()->SetIsUsingClientLoFi(false);
+
+ FetchURLRequest(GURL(kTestURL), nullptr,
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Range: bytes 0-139/2048\r\n\r\n",
+ 140, 0);
+
+ VerifyDidNotifyLoFiResponse(false);
+}
+
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ ClientLoFiCompleteResponseDoesNotTriggerInfobar) {
+ Init(USE_INSECURE_PROXY, false);
+
+ const char* const test_response_headers[] = {
+ "HTTP/1.1 200 OK\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+
+ "HTTP/1.1 204 No Content\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+
+ "HTTP/1.1 404 Not Found\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Range: bytes 0-139/140\r\n\r\n",
+ };
+
+ for (const char* headers : test_response_headers) {
ClearLoFiUIService();
- std::string response_headers =
- "HTTP/1.1 200 OK\r\n"
- "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
- "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n"
- "x-original-content-length: 200\r\n";
+ lofi_decider()->SetIsUsingClientLoFi(true);
+ FetchURLRequest(GURL(kTestURL), nullptr, headers, 140, 0);
+ VerifyDidNotifyLoFiResponse(false);
+ }
+}
- if (test.lofi_response) {
- if (test.was_server)
- response_headers += "Chrome-Proxy-Content-Transform: empty-image\r\n";
- else
- lofi_decider()->SetIsUsingClientLoFi(true);
- }
+TEST_F(DataReductionProxyNetworkDelegateTest,
+ ClientLoFiPartialRangeDoesTriggerInfobar) {
+ Init(USE_INSECURE_PROXY, false);
- response_headers += "\r\n";
- auto request =
- FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
- EXPECT_EQ(test.was_server,
- DataReductionProxyData::GetData(*request)->lofi_received());
- VerifyDidNotifyLoFiResponse(test.lofi_response);
+ const char* const test_response_headers[] = {
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Range: bytes 0-139/2048\r\n\r\n",
+
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Range: bytes 5-144/145\r\n\r\n",
+ };
+
+ for (const char* headers : test_response_headers) {
+ ClearLoFiUIService();
+ lofi_decider()->SetIsUsingClientLoFi(true);
+ FetchURLRequest(GURL(kTestURL), nullptr, headers, 140, 0);
+ VerifyDidNotifyLoFiResponse(true);
}
}
@@ -2170,6 +2236,15 @@ TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
Init(USE_INSECURE_PROXY, false);
base::HistogramTester histogram_tester;
+ const char kResponseHeadersWithCPCTFormat[] =
+ "HTTP/1.1 200 OK\r\n"
+ "Chrome-Proxy-Content-Transform: %s\r\n"
+ "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
+ "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "x-original-content-length: 200\r\n"
+ "\r\n";
+
// Verify lite page request.
net::HttpRequestHeaders request_headers;
request_headers.SetHeader("chrome-proxy-accept-transform", "lite-page");
@@ -2194,16 +2269,9 @@ TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
3 /* EMPTY_IMAGE_REQUESTED */, 1);
// Verify lite page response.
- std::string response_headers =
- "HTTP/1.1 200 OK\r\n"
- "Chrome-Proxy-Content-Transform: lite-page\r\n"
- "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
- "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n"
- "x-original-content-length: 200\r\n"
- "\r\n";
- auto request =
- FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+ auto request = FetchURLRequest(
+ GURL(kTestURL), nullptr,
+ base::StringPrintf(kResponseHeadersWithCPCTFormat, "lite-page"), 140, 0);
EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lite_page_received());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.Protocol.AcceptTransform", 3);
@@ -2215,7 +2283,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
"DataReductionProxy.LoFi.TransformationType", LITE_PAGE, 1);
// Verify page policy response.
- response_headers =
+ std::string response_headers =
"HTTP/1.1 200 OK\r\n"
"Chrome-Proxy: page-policies=empty-image\r\n"
"Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
@@ -2232,21 +2300,50 @@ TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
2 /* EMPTY_IMAGE_POLICY_DIRECTIVE_RECEIVED */, 1);
// Verify empty image response.
- response_headers =
- "HTTP/1.1 200 OK\r\n"
- "Chrome-Proxy-Content-Transform: empty-image\r\n"
- "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
- "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n"
- "x-original-content-length: 200\r\n"
- "\r\n";
- request = FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
+ request = FetchURLRequest(
+ GURL(kTestURL), nullptr,
+ base::StringPrintf(kResponseHeadersWithCPCTFormat, "empty-image"), 140,
+ 0);
EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lofi_received());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.Protocol.AcceptTransform", 5);
histogram_tester.ExpectBucketCount(
"DataReductionProxy.Protocol.AcceptTransform",
4 /* EMPTY_IMAGE_TRANSFORM_RECEIVED */, 1);
+
+ // Verify compressed-video request.
+ request_headers.SetHeader("chrome-proxy-accept-transform",
+ "compressed-video");
+ FetchURLRequest(GURL(kTestURL), &request_headers, std::string(), 140, 0);
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Protocol.AcceptTransform", 6);
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.Protocol.AcceptTransform",
+ 5 /* COMPRESSED_VIDEO_REQUESTED */, 1);
+
+ // Verify compressed-video response.
+ request = FetchURLRequest(
+ GURL(kTestURL), nullptr,
+ base::StringPrintf(kResponseHeadersWithCPCTFormat, "compressed-video"),
+ 140, 0);
+ EXPECT_FALSE(DataReductionProxyData::GetData(*request)->lofi_received());
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Protocol.AcceptTransform", 7);
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.Protocol.AcceptTransform",
+ 8 /* COMPRESSED_VIDEO_RECEIVED */, 1);
+
+ // Verify response with an unknown CPAT value.
+ request = FetchURLRequest(GURL(kTestURL), nullptr,
+ base::StringPrintf(kResponseHeadersWithCPCTFormat,
+ "this-is-a-fake-transform"),
+ 140, 0);
+ EXPECT_FALSE(DataReductionProxyData::GetData(*request)->lofi_received());
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Protocol.AcceptTransform", 8);
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.Protocol.AcceptTransform",
+ 9 /* UNKNOWN_TRANSFORM_RECEIVED */, 1);
}
} // namespace
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
index bae6a4ed6d0..8eea3c6a5bd 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
@@ -5,12 +5,11 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
#include <stdint.h>
+#include <string>
-#include "base/bind_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/rand_util.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
@@ -18,6 +17,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/variations/net/variations_http_headers.h"
#include "net/base/load_flags.h"
#include "net/nqe/effective_connection_type.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
@@ -39,8 +39,7 @@ static const char kHistogramAttempted[] =
// timing and data reduction proxy state.
void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
const DataReductionProxyPageLoadTiming& timing,
- PageloadMetrics* request,
- bool opted_out) {
+ PageloadMetrics* request) {
request->set_session_key(request_data.session_key());
request->set_holdback_group(params::HoldbackFieldTrialGroup());
// For the timing events, any of them could be zero. Fill the message as a
@@ -123,7 +122,7 @@ void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
return;
}
- if (opted_out) {
+ if (timing.opt_out_occurred) {
request->set_previews_opt_out(PageloadMetrics_PreviewsOptOut_OPT_OUT);
return;
}
@@ -151,7 +150,6 @@ DataReductionProxyPingbackClient::DataReductionProxyPingbackClient(
pingback_reporting_fraction_(0.0) {}
DataReductionProxyPingbackClient::~DataReductionProxyPingbackClient() {
- DCHECK(opt_outs_.empty());
DCHECK(thread_checker_.CalledOnValidThread());
}
@@ -175,17 +173,8 @@ void DataReductionProxyPingbackClient::SendPingback(
if (!send_pingback)
return;
- bool opted_out = false;
- if (request_data.page_id()) {
- auto opt_out = opt_outs_.find(NavigationID(request_data.page_id().value(),
- request_data.session_key()));
- opted_out = opt_out != opt_outs_.end();
- if (opted_out)
- opt_outs_.erase(opt_out);
- }
-
PageloadMetrics* pageload_metrics = metrics_request_.add_pageloads();
- AddDataToPageloadMetrics(request_data, timing, pageload_metrics, opted_out);
+ AddDataToPageloadMetrics(request_data, timing, pageload_metrics);
if (current_fetcher_.get())
return;
DCHECK_EQ(1, metrics_request_.pageloads_size());
@@ -215,7 +204,7 @@ void DataReductionProxyPingbackClient::CreateFetcherForDataAndStart() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can control Data Saver on Android via 'Data Saver' setting. "
"Data Saver is not available on iOS, and on desktop it is enabled "
@@ -237,6 +226,15 @@ void DataReductionProxyPingbackClient::CreateFetcherForDataAndStart() {
// already be overloaded.
static const int kMaxRetries = 5;
current_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+
+ // Attach variations headers.
+ net::HttpRequestHeaders headers;
+ variations::AppendVariationHeaders(pingback_url_, false /* incognito */,
+ false /* uma_enabled */,
+ false /* is_signed_in */, &headers);
+ if (!headers.IsEmpty())
+ current_fetcher_->SetExtraRequestHeaders(headers.ToString());
+
current_fetcher_->Start();
}
@@ -261,26 +259,4 @@ void DataReductionProxyPingbackClient::SetPingbackReportingFraction(
pingback_reporting_fraction_ = pingback_reporting_fraction;
}
-void DataReductionProxyPingbackClient::AddOptOut(
- const NavigationID& navigation_id) {
- opt_outs_.emplace(navigation_id);
-}
-
-void DataReductionProxyPingbackClient::ClearNavigationKeySync(
- const NavigationID& navigation_id) {
- opt_outs_.erase(navigation_id);
-}
-
-void DataReductionProxyPingbackClient::ClearNavigationKeyAsync(
- const NavigationID& navigation_id) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&DataReductionProxyPingbackClient::ClearNavigationKeySync,
- base::Unretained(this), navigation_id));
-}
-
-size_t DataReductionProxyPingbackClient::OptOutsSizeForTesting() const {
- return opt_outs_.size();
-}
-
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
index 1f437b6a85c..31da4099bc6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
@@ -5,12 +5,7 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
-#include <stdint.h>
-
#include <memory>
-#include <set>
-#include <string>
-#include <utility>
#include "base/macros.h"
#include "base/threading/thread_checker.h"
@@ -31,8 +26,6 @@ namespace data_reduction_proxy {
class DataReductionProxyData;
struct DataReductionProxyPageLoadTiming;
-using NavigationID = std::pair<uint64_t, std::string>;
-
// Manages pingbacks about page load timing information to the data saver proxy
// server. This class is not thread safe.
class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
@@ -52,17 +45,6 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// call to SendPingback.
void SetPingbackReportingFraction(float pingback_reporting_fraction);
- // Adds an opt out for |tab_identifier_key| for a data saver |page_id|. An opt
- // out occurs when users dismiss the preview in favor of the full page.
- void AddOptOut(const NavigationID& navigation_id);
-
- // Removes any stored data associated with |tab_identifier_key| in a task that
- // runs later.
- void ClearNavigationKeyAsync(const NavigationID& navigation_id);
-
- // The total number of pending loads being tracked due to opt outs.
- size_t OptOutsSizeForTesting() const;
-
protected:
// Generates a float in the range [0, 1). Virtualized in testing.
virtual float GenerateRandomFloat() const;
@@ -83,9 +65,6 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// reset to an empty RecordPageloadMetricsRequest.
void CreateFetcherForDataAndStart();
- // Removes any stored data associated with |tab_identifier_key|.
- void ClearNavigationKeySync(const NavigationID& navigation_id);
-
net::URLRequestContextGetter* url_request_context_;
// The URL for the data saver proxy's ping back service.
@@ -100,9 +79,6 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// The probability of sending a pingback to the server.
float pingback_reporting_fraction_;
- // The map of tab identifier keys to page IDs.
- std::set<NavigationID> opt_outs_;
-
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyPingbackClient);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
index 829bc3d9f7e..a8a8d51d974 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
@@ -106,7 +106,8 @@ class DataReductionProxyPingbackClientTest : public testing::Test {
void CreateAndSendPingback(bool lofi_received,
bool lite_page_received,
- bool app_background_occurred) {
+ bool app_background_occurred,
+ bool opt_out_occurred) {
timing_ = base::MakeUnique<DataReductionProxyPageLoadTiming>(
base::Time::FromJsTime(1500) /* navigation_start */,
base::Optional<base::TimeDelta>(
@@ -124,7 +125,7 @@ class DataReductionProxyPingbackClientTest : public testing::Test {
base::Optional<base::TimeDelta>(
base::TimeDelta::FromMilliseconds(2000)) /* parse_stop */,
kBytes /* network_bytes */, kBytesOriginal /* original_network_bytes */,
- app_background_occurred /* app_background_occurred */);
+ app_background_occurred, opt_out_occurred);
DataReductionProxyData request_data;
request_data.set_session_key(kSessionKey);
@@ -165,9 +166,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyPingbackContent) {
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
uint64_t data_page_id = page_id();
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -230,9 +231,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyHoldback) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -254,22 +255,22 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoPingbacksBatchedContent) {
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
// First pingback
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
// Two more pingbacks batched together.
std::list<uint64_t> page_ids;
page_ids.push_back(page_id());
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
page_ids.push_back(page_id());
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 3);
// Ignore the first pingback.
@@ -335,13 +336,13 @@ TEST_F(DataReductionProxyPingbackClientTest, SendTwoPingbacks) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
@@ -360,9 +361,9 @@ TEST_F(DataReductionProxyPingbackClientTest, NoPingbackSent) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(0.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, false, 1);
histogram_tester().ExpectTotalCount(kHistogramSucceeded, 0);
EXPECT_FALSE(factory()->GetFetcherByID(0));
@@ -376,9 +377,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// pingback is created.
pingback_client()->SetPingbackReportingFraction(0.5f);
pingback_client()->OverrideRandom(true, 0.4f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -388,9 +389,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// Verify that if the random number is greater than the reporting fraction,
// the pingback is not created.
pingback_client()->OverrideRandom(true, 0.6f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, false, 1);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_FALSE(test_fetcher);
@@ -400,9 +401,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
// and the random number is zero, no pingback is sent.
pingback_client()->SetPingbackReportingFraction(0.0f);
pingback_client()->OverrideRandom(true, 0.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, false, 2);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_FALSE(test_fetcher);
@@ -412,9 +413,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyReportingBehvaior) {
data_reduction_proxy::switches::kEnableDataReductionProxyForcePingback);
pingback_client()->SetPingbackReportingFraction(0.0f);
pingback_client()->OverrideRandom(true, 1.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectBucketCount(kHistogramAttempted, true, 2);
test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -427,9 +428,9 @@ TEST_F(DataReductionProxyPingbackClientTest, FailedPingback) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback(false /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_TRUE(test_fetcher);
@@ -447,9 +448,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentNoOptOut) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- CreateAndSendPingback(true /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ true /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, false /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -473,10 +474,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentOptOut) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- CreateAndSendPingback(true /* lofi_received */,
- false /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ true /* lofi_received */, false /* lite_page_received */,
+ false /* app_background_occurred */, true /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -500,10 +500,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyLoFiContentBackground) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- CreateAndSendPingback(true /* lofi_received */,
- false /* lite_page_received */,
- true /* app_background_occurred */);
+ CreateAndSendPingback(
+ true /* lofi_received */, false /* lite_page_received */,
+ true /* app_background_occurred */, true /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -527,10 +526,9 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyLitePageContent) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- CreateAndSendPingback(false /* lofi_received */,
- true /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, true /* lite_page_received */,
+ false /* app_background_occurred */, true /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -554,14 +552,12 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoLitePagePingbacks) {
pingback_client()->SetPingbackReportingFraction(1.0f);
base::Time current_time = base::Time::UnixEpoch();
pingback_client()->set_current_time(current_time);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- CreateAndSendPingback(false /* lofi_received */,
- true /* lite_page_received */,
- false /* app_background_occurred */);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- CreateAndSendPingback(false /* lofi_received */,
- true /* lite_page_received */,
- false /* app_background_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, true /* lite_page_received */,
+ false /* app_background_occurred */, true /* opt_out_occurred */);
+ CreateAndSendPingback(
+ false /* lofi_received */, true /* lite_page_received */,
+ false /* app_background_occurred */, true /* opt_out_occurred */);
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
@@ -587,19 +583,4 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoLitePagePingbacks) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
}
-TEST_F(DataReductionProxyPingbackClientTest, VerifyClearingPendingLoads) {
- Init();
- EXPECT_FALSE(factory()->GetFetcherByID(0));
- pingback_client()->OverrideRandom(true, 0.5f);
- pingback_client()->SetPingbackReportingFraction(1.0f);
- base::Time current_time = base::Time::UnixEpoch();
- pingback_client()->set_current_time(current_time);
- pingback_client()->AddOptOut(NavigationID(page_id(), kSessionKey));
- EXPECT_EQ(1u, pingback_client()->OptOutsSizeForTesting());
- pingback_client()->ClearNavigationKeyAsync(
- NavigationID(page_id(), kSessionKey));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0u, pingback_client()->OptOutsSizeForTesting());
-}
-
} // namespace data_reduction_proxy
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 df652759579..22964cf3acb 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
@@ -44,6 +44,23 @@
namespace {
+enum TestContextOptions {
+ // Permits mocking of the underlying |DataReductionProxyConfig|.
+ USE_MOCK_CONFIG = 0x1,
+ // Construct, but do not initialize the |DataReductionProxySettings| object.
+ // Primarily used for testing of the |DataReductionProxySettings| object
+ // itself.
+ SKIP_SETTINGS_INITIALIZATION = 0x2,
+ // Permits mocking of the underlying |DataReductionProxyService|.
+ USE_MOCK_SERVICE = 0x4,
+ // Permits mocking of the underlying |DataReductionProxyRequestOptions|.
+ USE_MOCK_REQUEST_OPTIONS = 0x8,
+ // Specifies the use of the |DataReductionProxyConfigServiceClient|.
+ USE_CONFIG_CLIENT = 0x10,
+ // Specifies the use of the |TESTDataReductionProxyConfigServiceClient|.
+ USE_TEST_CONFIG_CLIENT = 0x20,
+};
+
const char kTestKey[] = "test-key";
// Name of the preference that governs enabling the Data Reduction Proxy.
@@ -414,7 +431,7 @@ DataReductionProxyTestContext::Builder::Build() {
if (use_config_client_) {
test_context_flags |= USE_CONFIG_CLIENT;
std::unique_ptr<DataReductionProxyMutableConfigValues> mutable_config =
- DataReductionProxyMutableConfigValues::CreateFromParams(params.get());
+ base::MakeUnique<DataReductionProxyMutableConfigValues>();
if (!proxy_servers_.empty()) {
mutable_config->UpdateValues(proxy_servers_);
}
@@ -555,8 +572,7 @@ void DataReductionProxyTestContext::RunUntilIdle() {
}
void DataReductionProxyTestContext::InitSettings() {
- DCHECK(test_context_flags_ &
- DataReductionProxyTestContext::SKIP_SETTINGS_INITIALIZATION);
+ DCHECK(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION);
InitSettingsWithoutCheck();
}
@@ -586,15 +602,14 @@ void DataReductionProxyTestContext::InitSettingsWithoutCheck() {
std::unique_ptr<DataReductionProxyService>
DataReductionProxyTestContext::CreateDataReductionProxyService(
DataReductionProxySettings* settings) {
- DCHECK(test_context_flags_ &
- DataReductionProxyTestContext::SKIP_SETTINGS_INITIALIZATION);
+ DCHECK(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION);
return CreateDataReductionProxyServiceInternal(settings);
}
std::unique_ptr<DataReductionProxyService>
DataReductionProxyTestContext::CreateDataReductionProxyServiceInternal(
DataReductionProxySettings* settings) {
- if (test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_SERVICE) {
+ if (test_context_flags_ & USE_MOCK_SERVICE) {
return base::MakeUnique<MockDataReductionProxyService>(
settings, simple_pref_service_.get(), request_context_getter_.get(),
task_runner_);
@@ -650,7 +665,7 @@ void DataReductionProxyTestContext::
MockDataReductionProxyConfig* DataReductionProxyTestContext::mock_config()
const {
- DCHECK(test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_CONFIG);
+ DCHECK(test_context_flags_ & USE_MOCK_CONFIG);
return reinterpret_cast<MockDataReductionProxyConfig*>(io_data_->config());
}
@@ -662,17 +677,15 @@ DataReductionProxyTestContext::data_reduction_proxy_service() const {
MockDataReductionProxyService*
DataReductionProxyTestContext::mock_data_reduction_proxy_service()
const {
- DCHECK(!(test_context_flags_ &
- DataReductionProxyTestContext::SKIP_SETTINGS_INITIALIZATION));
- DCHECK(test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_SERVICE);
+ DCHECK(!(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION));
+ DCHECK(test_context_flags_ & USE_MOCK_SERVICE);
return reinterpret_cast<MockDataReductionProxyService*>(
data_reduction_proxy_service());
}
MockDataReductionProxyRequestOptions*
DataReductionProxyTestContext::mock_request_options() const {
- DCHECK(test_context_flags_ &
- DataReductionProxyTestContext::USE_MOCK_REQUEST_OPTIONS);
+ DCHECK(test_context_flags_ & USE_MOCK_REQUEST_OPTIONS);
return reinterpret_cast<MockDataReductionProxyRequestOptions*>(
io_data_->request_options());
}
@@ -683,16 +696,14 @@ TestDataReductionProxyConfig* DataReductionProxyTestContext::config() const {
DataReductionProxyMutableConfigValues*
DataReductionProxyTestContext::mutable_config_values() {
- DCHECK(test_context_flags_ &
- DataReductionProxyTestContext::USE_CONFIG_CLIENT);
+ DCHECK(test_context_flags_ & USE_CONFIG_CLIENT);
return reinterpret_cast<DataReductionProxyMutableConfigValues*>(
config()->config_values());
}
TestDataReductionProxyConfigServiceClient*
DataReductionProxyTestContext::test_config_client() {
- DCHECK(test_context_flags_ &
- DataReductionProxyTestContext::USE_TEST_CONFIG_CLIENT);
+ DCHECK(test_context_flags_ & USE_TEST_CONFIG_CLIENT);
return reinterpret_cast<TestDataReductionProxyConfigServiceClient*>(
io_data_->config_client());
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 953af6fba60..39c949f223f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -459,23 +459,6 @@ class DataReductionProxyTestContext {
std::vector<net::ProxyServer> GetConfiguredProxiesForHttp() const;
private:
- enum TestContextOptions {
- // Permits mocking of the underlying |DataReductionProxyConfig|.
- USE_MOCK_CONFIG = 0x1,
- // Construct, but do not initialize the |DataReductionProxySettings| object.
- // Primarily used for testing of the |DataReductionProxySettings| object
- // itself.
- SKIP_SETTINGS_INITIALIZATION = 0x2,
- // Permits mocking of the underlying |DataReductionProxyService|.
- USE_MOCK_SERVICE = 0x4,
- // Permits mocking of the underlying |DataReductionProxyRequestOptions|.
- USE_MOCK_REQUEST_OPTIONS = 0x8,
- // Specifies the use of the |DataReductionProxyConfigServiceClient|.
- USE_CONFIG_CLIENT = 0x10,
- // Specifies the use of the |TESTDataReductionProxyConfigServiceClient|.
- USE_TEST_CONFIG_CLIENT = 0x20,
- };
-
// Used to storage a serialized Data Reduction Proxy config.
class TestConfigStorer {
public:
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
index 564b70b721b..37b69fee82b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
@@ -114,7 +114,7 @@ DataStore::Status DataStoreImpl::Delete(base::StringPiece key) {
DataStore::Status DataStoreImpl::OpenDB() {
DCHECK(sequence_checker_.CalledOnValidSequence());
- leveldb::Options options;
+ leveldb_env::Options options;
options.create_if_missing = true;
options.paranoid_checks = true;
// Deletes to buckets not found are stored in the log. Use a new log so that
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
index ee0fa9dfcd1..e54f4bacca5 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
@@ -106,8 +106,8 @@ DataReductionProxyEventStore::GetSummaryValue() const {
auto data_reduction_proxy_values = base::MakeUnique<base::DictionaryValue>();
data_reduction_proxy_values->SetBoolean("enabled", enabled_);
if (current_configuration_) {
- data_reduction_proxy_values->Set(
- "proxy_config", base::MakeUnique<base::Value>(*current_configuration_));
+ data_reduction_proxy_values->SetKey("proxy_config",
+ current_configuration_->Clone());
}
switch (secure_proxy_check_state_) {
@@ -129,8 +129,8 @@ DataReductionProxyEventStore::GetSummaryValue() const {
int current_time_ticks_ms =
(base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
if (expiration_ticks_ > current_time_ticks_ms) {
- data_reduction_proxy_values->Set(
- "last_bypass", base::MakeUnique<base::Value>(*last_bypass_event));
+ data_reduction_proxy_values->SetKey("last_bypass",
+ last_bypass_event->Clone());
}
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index 543bcc5cdf1..0ccabc2e50e 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -47,15 +47,10 @@ const char kCompressedVideoDirective[] = "compressed-video";
const char kIdentityDirective[] = "identity";
const char kChromeProxyPagePoliciesDirective[] = "page-policies";
-// The legacy Chrome-Proxy response header directive for LoFi images.
-const char kLegacyChromeProxyLoFiResponseDirective[] = "q=low";
-
const char kChromeProxyExperimentForceLitePage[] = "force_lite_page";
const char kChromeProxyExperimentForceEmptyImage[] =
"force_page_policies_empty_image";
-const char kIfHeavyQualifier[] = "if-heavy";
-
const char kChromeProxyActionBlockOnce[] = "block-once";
const char kChromeProxyActionBlock[] = "block";
const char kChromeProxyActionBypass[] = "bypass";
@@ -184,6 +179,10 @@ const char* compressed_video_directive() {
return kCompressedVideoDirective;
}
+const char* page_policies_directive() {
+ return kChromeProxyPagePoliciesDirective;
+}
+
const char* chrome_proxy_experiment_force_lite_page() {
return kChromeProxyExperimentForceLitePage;
}
@@ -192,10 +191,6 @@ const char* chrome_proxy_experiment_force_empty_image() {
return kChromeProxyExperimentForceEmptyImage;
}
-const char* if_heavy_qualifier() {
- return kIfHeavyQualifier;
-}
-
TransformDirective ParseRequestTransform(
const net::HttpRequestHeaders& headers) {
std::string accept_transform_value;
@@ -216,9 +211,9 @@ TransformDirective ParseRequestTransform(
} else if (base::LowerCaseEqualsASCII(accept_transform_value,
kIdentityDirective)) {
return TRANSFORM_IDENTITY;
- } else {
- return TRANSFORM_NONE;
}
+
+ return TRANSFORM_NONE;
}
TransformDirective ParseResponseTransform(
@@ -232,6 +227,7 @@ TransformDirective ParseResponseTransform(
&chrome_proxy_header_value)) {
return ParsePagePolicyDirective(chrome_proxy_header_value);
}
+ return TRANSFORM_NONE;
} else if (base::LowerCaseEqualsASCII(content_transform_value,
lite_page_directive())) {
return TRANSFORM_LITE_PAGE;
@@ -241,17 +237,15 @@ TransformDirective ParseResponseTransform(
} else if (base::LowerCaseEqualsASCII(content_transform_value,
kIdentityDirective)) {
return TRANSFORM_IDENTITY;
- } else {
- NOTREACHED() << "Unexpected content transform header: "
- << content_transform_value;
+ } else if (base::LowerCaseEqualsASCII(content_transform_value,
+ compressed_video_directive())) {
+ return TRANSFORM_COMPRESSED_VIDEO;
}
- return TRANSFORM_NONE;
+ return TRANSFORM_UNKNOWN;
}
bool IsEmptyImagePreview(const net::HttpResponseHeaders& headers) {
- return IsPreviewType(headers, kEmptyImageDirective) ||
- headers.HasHeaderValue(kChromeProxyHeader,
- kLegacyChromeProxyLoFiResponseDirective);
+ return IsPreviewType(headers, kEmptyImageDirective);
}
bool IsEmptyImagePreview(const std::string& content_transform_value,
@@ -259,16 +253,6 @@ bool IsEmptyImagePreview(const std::string& content_transform_value,
if (IsPreviewTypeInHeaderValue(content_transform_value, kEmptyImageDirective))
return true;
- // Look for "q=low" in the "Chrome-Proxy" response header.
- net::HttpUtil::ValuesIterator values(chrome_proxy_value.begin(),
- chrome_proxy_value.end(), ',');
- while (values.GetNext()) {
- base::StringPiece value(values.value_begin(), values.value_end());
- if (base::LowerCaseEqualsASCII(value,
- kLegacyChromeProxyLoFiResponseDirective)) {
- return true;
- }
- }
return false;
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
index 7dfedda6edc..e7e855d505f 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
@@ -25,6 +25,7 @@ namespace data_reduction_proxy {
// Transform directives that may be parsed out of http headers.
enum TransformDirective {
+ TRANSFORM_UNKNOWN,
TRANSFORM_NONE,
TRANSFORM_LITE_PAGE,
TRANSFORM_EMPTY_IMAGE,
@@ -107,9 +108,9 @@ const char* lite_page_directive();
// compressed video.
const char* compressed_video_directive();
-// Gets the Chrome-Proxy directive used by data reduction proxy lite page
-// preview requests and responses.
-const char* chrome_proxy_lite_page_directive();
+// Gets the directive used by the data reduction proxy to tell the client to use
+// a specific page policy.
+const char* page_policies_directive();
// Gets the Chrome-Proxy experiment ("exp") value to force a lite page preview
// for requests that accept lite pages.
@@ -119,12 +120,6 @@ const char* chrome_proxy_experiment_force_lite_page();
// preview for requests that enable server provided previews.
const char* chrome_proxy_experiment_force_empty_image();
-// Requests a transformation only if the server determines that the page is
-// otherwise heavy (i.e., the associated page load ordinarily requires the
-// network to transfer of a lot of bytes). Added to a previews directive. E.g.,
-// "lite-page;if-heavy".
-const char* if_heavy_qualifier();
-
// Returns true if the Chrome-Proxy-Content-Transform response header indicates
// that an empty image has been provided.
bool IsEmptyImagePreview(const net::HttpResponseHeaders& headers);
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
index 2e10c016f9e..81ac8200227 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
@@ -77,28 +77,6 @@ TEST_F(DataReductionProxyHeadersTest, IsEmptyImagePreview) {
"Another-Header: empty-image\n",
false,
},
- {
- "HTTP/1.1 200 OK\n"
- "Chrome-Proxy: q=low\n",
- true,
- },
- {
- "HTTP/1.1 200 OK\n"
- "Chrome-Proxy: foo=bar, Q=LOW\n",
- true,
- },
- {
- "HTTP/1.1 200 OK\n"
- "Chrome-Proxy-Content-Transform: q=low\n"
- "Chrome-Proxy: empty-image\n",
- false,
- },
- {
- "HTTP/1.1 200 OK\n"
- "Chrome-Proxy-Content-Transform: foo\n"
- "Chrome-Proxy: q=low\n",
- true,
- },
};
for (size_t i = 0; i < arraysize(tests); ++i) {
std::string headers(tests[i].headers);
@@ -116,19 +94,12 @@ TEST_F(DataReductionProxyHeadersTest, IsEmptyImagePreviewValue) {
bool expected_result;
} tests[] = {
{"", "", false},
- {"foo", "", false},
- {"", "bar", false},
{"foo", "bar", false},
{"empty-image", "", true},
{"empty-image;foo", "", true},
{"Empty-Image", "", true},
{"foo;empty-image", "", false},
{"empty-image", "foo", true},
- {"foo;empty-image", "bar", false},
- {"", "q=low", true},
- {"foo", "q=low", true},
- {"foo", "bar, baz, Q=LOW ", true},
- {"empty-image", "q=low", true},
};
for (const auto& test : tests) {
EXPECT_EQ(test.expected_result,
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
index 13ff57d2f35..1ed7dd81155 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
@@ -18,7 +18,8 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
int64_t original_network_bytes,
- bool app_background_occurred)
+ bool app_background_occurred,
+ bool opt_out_occurred)
: navigation_start(navigation_start),
response_start(response_start),
load_event_start(load_event_start),
@@ -30,7 +31,8 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
parse_stop(parse_stop),
network_bytes(network_bytes),
original_network_bytes(original_network_bytes),
- app_background_occurred(app_background_occurred) {}
+ app_background_occurred(app_background_occurred),
+ opt_out_occurred(opt_out_occurred) {}
DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
const DataReductionProxyPageLoadTiming& other) = default;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
index 84e1357dae1..a38a7998435 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
@@ -27,7 +27,8 @@ struct DataReductionProxyPageLoadTiming {
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
int64_t original_network_bytes,
- bool app_background_occurred);
+ bool app_background_occurred,
+ bool opt_out_occurred);
DataReductionProxyPageLoadTiming(
const DataReductionProxyPageLoadTiming& other);
@@ -60,6 +61,8 @@ struct DataReductionProxyPageLoadTiming {
const int64_t original_network_bytes;
// True when android app background occurred during the page load lifetime.
const bool app_background_occurred;
+ // True when the user clicks "Show Original" on the Previews infobar.
+ const bool opt_out_occurred;
};
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 66c9a2d0055..34b5d9f3746 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -30,7 +30,6 @@ namespace {
const char kEnabled[] = "Enabled";
const char kControl[] = "Control";
const char kDisabled[] = "Disabled";
-const char kLitePage[] = "Enabled_Preview";
const char kDefaultSecureProxyCheckUrl[] = "http://check.googlezip.net/connect";
const char kDefaultWarmupUrl[] = "http://check.googlezip.net/generate_204";
@@ -42,8 +41,6 @@ const char kLoFiFlagFieldTrial[] = "DataCompressionProxyLoFiFlag";
const char kBlackListTransitionFieldTrial[] =
"DataReductionProxyPreviewsBlackListTransition";
-const char kTrustedSpdyProxyFieldTrialName[] = "DataReductionTrustedSpdyProxy";
-
// Default URL for retrieving the Data Reduction Proxy configuration.
const char kClientConfigURL[] =
"https://datasaver.googleapis.com/v1/clientConfigs";
@@ -136,25 +133,6 @@ std::string HoldbackFieldTrialGroup() {
return base::FieldTrialList::FindFullName("DataCompressionProxyHoldback");
}
-const char* GetTrustedSpdyProxyFieldTrialName() {
- return kTrustedSpdyProxyFieldTrialName;
-}
-
-bool IsIncludedInTrustedSpdyProxyFieldTrial() {
- if (base::StartsWith(base::FieldTrialList::FindFullName(
- GetTrustedSpdyProxyFieldTrialName()),
- kControl, base::CompareCase::SENSITIVE)) {
- return false;
- }
- if (base::StartsWith(base::FieldTrialList::FindFullName(
- GetTrustedSpdyProxyFieldTrialName()),
- kDisabled, base::CompareCase::SENSITIVE)) {
- return false;
- }
- // Trusted SPDY proxy experiment is enabled by default.
- return true;
-}
-
const char* GetLoFiFieldTrialName() {
return kLoFiFieldTrial;
}
@@ -163,25 +141,6 @@ const char* GetLoFiFlagFieldTrialName() {
return kLoFiFlagFieldTrial;
}
-bool IsIncludedInLoFiEnabledFieldTrial() {
- return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- IsIncludedInFieldTrial(GetLoFiFieldTrialName());
-}
-
-bool IsIncludedInLoFiControlFieldTrial() {
- return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- base::StartsWith(
- base::FieldTrialList::FindFullName(GetLoFiFieldTrialName()),
- kControl, base::CompareCase::SENSITIVE);
-}
-
-bool IsIncludedInLitePageFieldTrial() {
- return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- base::StartsWith(
- base::FieldTrialList::FindFullName(GetLoFiFieldTrialName()),
- kLitePage, base::CompareCase::SENSITIVE);
-}
-
bool IsIncludedInServerExperimentsFieldTrial() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
data_reduction_proxy::switches::
@@ -467,40 +426,20 @@ DataReductionProxyTypeInfo::DataReductionProxyTypeInfo(
DataReductionProxyTypeInfo::~DataReductionProxyTypeInfo() {}
-DataReductionProxyParams::DataReductionProxyParams()
- : use_override_proxies_for_http_(false) {
- static const char kDefaultSpdyOrigin[] = "https://proxy.googlezip.net:443";
- static const char kDefaultFallbackOrigin[] = "compress.googlezip.net:80";
+DataReductionProxyParams::DataReductionProxyParams() {
+ bool use_override_proxies_for_http =
+ params::GetOverrideProxiesForHttpFromCommandLine(&proxies_for_http_);
- use_override_proxies_for_http_ =
- params::GetOverrideProxiesForHttpFromCommandLine(
- &override_data_reduction_proxy_servers_);
-
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- std::string origin =
- command_line.GetSwitchValueASCII(switches::kDataReductionProxy);
- std::string fallback_origin =
- command_line.GetSwitchValueASCII(switches::kDataReductionProxyFallback);
-
- // Set from preprocessor constants those params that are not specified on the
- // command line.
- if (origin.empty())
- origin = kDefaultSpdyOrigin;
- if (fallback_origin.empty())
- fallback_origin = kDefaultFallbackOrigin;
-
- net::ProxyServer origin_proxy_server =
- net::ProxyServer::FromURI(origin, net::ProxyServer::SCHEME_HTTP);
- net::ProxyServer fallback_proxy_server =
- net::ProxyServer::FromURI(fallback_origin, net::ProxyServer::SCHEME_HTTP);
- if (origin_proxy_server.is_valid()) {
- proxies_for_http_.push_back(
- DataReductionProxyServer(origin_proxy_server, ProxyServer::CORE));
- }
- if (fallback_proxy_server.is_valid()) {
- proxies_for_http_.push_back(
- DataReductionProxyServer(fallback_proxy_server, ProxyServer::CORE));
+ if (!use_override_proxies_for_http) {
+ DCHECK(proxies_for_http_.empty());
+ proxies_for_http_.push_back(DataReductionProxyServer(
+ net::ProxyServer::FromURI("https://proxy.googlezip.net:443",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::CORE));
+ proxies_for_http_.push_back(DataReductionProxyServer(
+ net::ProxyServer::FromURI("compress.googlezip.net:80",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::CORE));
}
}
@@ -513,8 +452,6 @@ void DataReductionProxyParams::SetProxiesForHttpForTesting(
const std::vector<DataReductionProxyServer>&
DataReductionProxyParams::proxies_for_http() const {
- if (use_override_proxies_for_http_)
- return override_data_reduction_proxy_servers_;
return proxies_for_http_;
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 96f7ba69c93..73c94983fef 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -45,13 +45,6 @@ bool IsIncludedInHoldbackFieldTrial();
// not included in a group.
std::string HoldbackFieldTrialGroup();
-// Returns the name of the trusted SPDY/HTTP2 proxy field trial.
-const char* GetTrustedSpdyProxyFieldTrialName();
-
-// Returns true if this client is part of the enabled group of the trusted
-// SPDY/HTTP2 proxy field trial.
-bool IsIncludedInTrustedSpdyProxyFieldTrial();
-
// Returns true if this client is part of the field trial that should display
// a promotion for the data reduction proxy on Android One devices. This is for
// testing purposes and should not be called outside of tests.
@@ -59,24 +52,14 @@ bool IsIncludedInAndroidOnePromoFieldTrialForTesting(
base::StringPiece build_fingerprint);
// Returns the name of the Lo-Fi field trial.
+// TODO(ryansturm): crbug.com/759052 Cleanup once fully cutover to new blacklist
const char* GetLoFiFieldTrialName();
// Returns the name of the Lo-Fi field trial that configures LoFi flags when it
// is force enabled through flags.
+// TODO(ryansturm): crbug.com/759052 Cleanup once fully cutover to new blacklist
const char* GetLoFiFlagFieldTrialName();
-// Returns true if this client is part of the "Enabled" or "Enabled_Preview"
-// group of the Lo-Fi field trial, both of which mean Lo-Fi should be enabled.
-bool IsIncludedInLoFiEnabledFieldTrial();
-
-// Returns true if this client is part of the "Control" group of the Lo-Fi field
-// trial.
-bool IsIncludedInLoFiControlFieldTrial();
-
-// Returns true if this client is part of the "Preview" group of the Lo-Fi field
-// trial.
-bool IsIncludedInLitePageFieldTrial();
-
// Returns true if this client is part of the field trial that should enable
// server experiments for the data reduction proxy.
bool IsIncludedInServerExperimentsFieldTrial();
@@ -215,9 +198,6 @@ class DataReductionProxyParams : public DataReductionProxyConfigValues {
private:
std::vector<DataReductionProxyServer> proxies_for_http_;
- bool use_override_proxies_for_http_;
- std::vector<DataReductionProxyServer> override_data_reduction_proxy_servers_;
-
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyParams);
};
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index 63e8cda5a02..4eb560f9cd7 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -247,120 +247,6 @@ TEST_F(DataReductionProxyParamsTest, IsTamperDetectionEnabled) {
}
}
-// Tests if Lo-Fi field trial is set correctly.
-TEST_F(DataReductionProxyParamsTest, LoFiEnabledFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- bool expected_control;
- bool expected_lite_page_enabled;
- } tests[] = {
- {"Enabled", true, false, false},
- {"Enabled_Control", true, false, false},
- {"Disabled", false, false, false},
- {"enabled", false, false, false},
- };
-
- for (const auto& test : tests) {
- base::FieldTrialList field_trial_list(nullptr);
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- params::GetLoFiFieldTrialName(), test.trial_group_name));
- EXPECT_EQ(test.expected_enabled,
- params::IsIncludedInLoFiEnabledFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_control,
- params::IsIncludedInLoFiControlFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_lite_page_enabled,
- params::IsIncludedInLitePageFieldTrial())
- << test.trial_group_name;
- }
-}
-
-// Tests if Lo-Fi field trial is set correctly.
-TEST_F(DataReductionProxyParamsTest, LoFiControlFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- bool expected_control;
- bool expected_lite_page_enabled;
- } tests[] = {
- {"Control", false, true, false},
- {"Control_Enabled", false, true, false},
- {"Disabled", false, false, false},
- {"control", false, false, false},
- };
-
- for (const auto& test : tests) {
- base::FieldTrialList field_trial_list(nullptr);
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- params::GetLoFiFieldTrialName(), test.trial_group_name));
- EXPECT_EQ(test.expected_enabled,
- params::IsIncludedInLoFiEnabledFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_control,
- params::IsIncludedInLoFiControlFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_lite_page_enabled,
- params::IsIncludedInLitePageFieldTrial())
- << test.trial_group_name;
- }
-}
-
-// Tests if Lo-Fi field trial is set correctly.
-TEST_F(DataReductionProxyParamsTest, LoFiPreviewFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- bool expected_control;
- bool expected_lite_page_enabled;
- } tests[] = {
- {"Enabled_Preview", true, false, true},
- {"Enabled_Preview_Control", true, false, true},
- {"Disabled", false, false, false},
- {"enabled_Preview", false, false, false},
- };
-
- for (const auto& test : tests) {
- base::FieldTrialList field_trial_list(nullptr);
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- params::GetLoFiFieldTrialName(), test.trial_group_name));
- EXPECT_EQ(test.expected_enabled,
- params::IsIncludedInLoFiEnabledFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_control,
- params::IsIncludedInLoFiControlFieldTrial())
- << test.trial_group_name;
- EXPECT_EQ(test.expected_lite_page_enabled,
- params::IsIncludedInLitePageFieldTrial())
- << test.trial_group_name;
- }
-}
-
-TEST_F(DataReductionProxyParamsTest, TrustedSpdyProxyFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- } tests[] = {
- {"Enabled", true}, {"Enabled_Control", true}, {"Control", false},
- {"Disabled", false}, {"enabled", true}, {"Enabled", true},
- {std::string(), true},
- };
-
- for (const auto& test : tests) {
- variations::testing::ClearAllVariationParams();
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial(
- params::GetTrustedSpdyProxyFieldTrialName(), test.trial_group_name);
-
- EXPECT_EQ(test.expected_enabled,
- params::IsIncludedInTrustedSpdyProxyFieldTrial());
- }
-}
-
// Tests if the QUIC field trial is set correctly.
TEST_F(DataReductionProxyParamsTest, QuicFieldTrial) {
const struct {
diff --git a/chromium/components/data_reduction_proxy/core/common/lofi_decider.h b/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
index 61ce4668d6d..bb30d06eda0 100644
--- a/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
+++ b/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
@@ -25,17 +25,9 @@ class LoFiDecider {
virtual bool IsUsingLoFi(const net::URLRequest& request) const = 0;
// Adds a previews-specific directive to the Chrome-Proxy-Accept-Transform
- // header if needed. If a slow page preview is triggered, adds "lite-page" or
- // "empty-image", depending on whether the request is for the main frame
- // and lite pages are enabled, or for a subresource and Lo-Fi mode is enabled,
- // respectively. If a slow page preview is not triggered, "lite-page;if-heavy"
- // and "empty-image;if-heavy" are added in the respective aforementioned cases
- // to request that the server transform the page if it determines it to be
- // heavy. Previews-related transformation headers are never added if
- // |is_previews_disabled| is true.
+ // header if needed.
virtual void MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
- bool are_previews_disabled,
net::HttpRequestHeaders* headers) const = 0;
// Returns true if |headers| contains the Chrome-Proxy-Accept-Transform
diff --git a/chromium/components/data_usage/core/data_use.cc b/chromium/components/data_usage/core/data_use.cc
index 838b7ffa232..879426178c4 100644
--- a/chromium/components/data_usage/core/data_use.cc
+++ b/chromium/components/data_usage/core/data_use.cc
@@ -10,8 +10,7 @@ namespace {
bool AreNonByteCountFieldsEqual(const DataUse& a, const DataUse& b) {
return a.url == b.url && a.request_start == b.request_start &&
- a.first_party_for_cookies == b.first_party_for_cookies &&
- a.tab_id == b.tab_id &&
+ a.site_for_cookies == b.site_for_cookies && a.tab_id == b.tab_id &&
a.main_frame_global_request_id == b.main_frame_global_request_id &&
a.connection_type == b.connection_type && a.mcc_mnc == b.mcc_mnc;
}
@@ -28,7 +27,7 @@ const DataUse::MainFrameGlobalRequestID
DataUse::DataUse(const GURL& url,
const base::TimeTicks& request_start,
- const GURL& first_party_for_cookies,
+ const GURL& site_for_cookies,
int32_t tab_id,
net::NetworkChangeNotifier::ConnectionType connection_type,
const std::string& mcc_mnc,
@@ -36,7 +35,7 @@ DataUse::DataUse(const GURL& url,
int64_t rx_bytes)
: url(url),
request_start(request_start),
- first_party_for_cookies(first_party_for_cookies),
+ site_for_cookies(site_for_cookies),
tab_id(tab_id),
main_frame_global_request_id(DataUse::kInvalidMainFrameGlobalRequestID),
connection_type(connection_type),
diff --git a/chromium/components/data_usage/core/data_use.h b/chromium/components/data_usage/core/data_use.h
index c3994790ffb..27effe3f1aa 100644
--- a/chromium/components/data_usage/core/data_use.h
+++ b/chromium/components/data_usage/core/data_use.h
@@ -24,7 +24,7 @@ struct DataUse {
DataUse(const GURL& url,
const base::TimeTicks& request_start,
- const GURL& first_party_for_cookies,
+ const GURL& site_for_cookies,
int32_t tab_id,
net::NetworkChangeNotifier::ConnectionType connection_type,
const std::string& mcc_mnc,
@@ -44,7 +44,7 @@ struct DataUse {
// The TimeTicks when the request that is associated with these bytes was
// started.
base::TimeTicks request_start;
- GURL first_party_for_cookies;
+ GURL site_for_cookies;
// Tab id where the data use happens. When PlzNavigate is enabled tab id could
// be invalid(-1) for the mainframe request since tab cannot be retrieved yet.
diff --git a/chromium/components/data_usage/core/data_use_aggregator.cc b/chromium/components/data_usage/core/data_use_aggregator.cc
index 8efb20b1f21..844c9034f54 100644
--- a/chromium/components/data_usage/core/data_use_aggregator.cc
+++ b/chromium/components/data_usage/core/data_use_aggregator.cc
@@ -30,11 +30,11 @@ DataUseAggregator::DataUseAggregator(
#if defined(OS_ANDROID)
mcc_mnc_ = net::android::GetTelephonySimOperator();
#endif // OS_ANDROID
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
}
DataUseAggregator::~DataUseAggregator() {
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
void DataUseAggregator::AddObserver(Observer* observer) {
@@ -57,7 +57,7 @@ void DataUseAggregator::ReportDataUse(net::URLRequest* request,
std::unique_ptr<DataUse> data_use(
new DataUse(request->url(), load_timing_info.request_start,
- request->first_party_for_cookies(), -1 /* tab_id */,
+ request->site_for_cookies(), -1 /* tab_id */,
connection_type_, mcc_mnc_, tx_bytes, rx_bytes));
if (!annotator_) {
@@ -89,7 +89,7 @@ base::WeakPtr<DataUseAggregator> DataUseAggregator::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-void DataUseAggregator::OnConnectionTypeChanged(
+void DataUseAggregator::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/components/data_usage/core/data_use_aggregator.h b/chromium/components/data_usage/core/data_use_aggregator.h
index 9cb12e3f8d5..7e6088f9f19 100644
--- a/chromium/components/data_usage/core/data_use_aggregator.h
+++ b/chromium/components/data_usage/core/data_use_aggregator.h
@@ -29,7 +29,7 @@ struct DataUse;
// Class that collects and aggregates network usage, reporting the usage to
// observers. Should only be used on the IO thread.
class DataUseAggregator
- : public net::NetworkChangeNotifier::ConnectionTypeObserver {
+ : public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
class Observer {
public:
@@ -63,9 +63,9 @@ class DataUseAggregator
base::WeakPtr<DataUseAggregator> GetWeakPtr();
protected:
- // net::NetworkChangeNotifier::ConnectionTypeObserver implementation.
+ // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
// Protected for testing.
- void OnConnectionTypeChanged(
+ void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
// Protected for testing.
diff --git a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
index 8088c5318a1..bb3bdc45730 100644
--- a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
+++ b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
@@ -52,7 +52,7 @@ class TestDataUseAggregator : public DataUseAggregator {
private:
friend class TestNetworkChangeNotifier;
- using DataUseAggregator::OnConnectionTypeChanged;
+ using DataUseAggregator::OnNetworkChanged;
using DataUseAggregator::SetMccMncForTests;
};
@@ -69,7 +69,7 @@ class TestNetworkChangeNotifier : public net::NetworkChangeNotifier {
void SimulateNetworkConnectionChange(ConnectionType type,
const std::string& mcc_mnc) {
connection_type_to_return_ = type;
- data_use_aggregator_->OnConnectionTypeChanged(type);
+ data_use_aggregator_->OnNetworkChanged(type);
data_use_aggregator_->SetMccMncForTests(mcc_mnc);
}
@@ -267,7 +267,7 @@ class DataUseAggregatorTest : public testing::Test {
std::unique_ptr<net::URLRequest> ExecuteRequest(
const GURL& url,
- const GURL& first_party_for_cookies,
+ const GURL& site_for_cookies,
int32_t tab_id,
net::NetworkChangeNotifier::ConnectionType connection_type,
const std::string& mcc_mnc) {
@@ -281,7 +281,7 @@ class DataUseAggregatorTest : public testing::Test {
net::TestDelegate delegate;
std::unique_ptr<net::URLRequest> request = context_->CreateRequest(
url, net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
- request->set_first_party_for_cookies(first_party_for_cookies);
+ request->set_site_for_cookies(site_for_cookies);
ReportingNetworkDelegate::DataUseContextMap data_use_context_map;
data_use_context_map[request.get()] =
@@ -368,7 +368,7 @@ TEST_F(DataUseAggregatorTest, ReportDataUse) {
data_use_it->url == "http://foo.com/") {
EXPECT_EQ(GetRequestStart(*foo_request), data_use_it->request_start);
EXPECT_EQ(GURL("http://foofirstparty.com"),
- data_use_it->first_party_for_cookies);
+ data_use_it->site_for_cookies);
if (test_case.expect_tab_ids)
EXPECT_EQ(kFooTabId, data_use_it->tab_id);
@@ -395,7 +395,7 @@ TEST_F(DataUseAggregatorTest, ReportDataUse) {
EXPECT_EQ(GURL("http://bar.com"), data_use_it->url);
EXPECT_EQ(GetRequestStart(*bar_request), data_use_it->request_start);
EXPECT_EQ(GURL("http://barfirstparty.com"),
- data_use_it->first_party_for_cookies);
+ data_use_it->site_for_cookies);
if (test_case.expect_tab_ids)
EXPECT_EQ(kBarTabId, data_use_it->tab_id);
diff --git a/chromium/components/discardable_memory/common/discardable_shared_memory_heap.cc b/chromium/components/discardable_memory/common/discardable_shared_memory_heap.cc
index 7eacbeeec77..b8f2b0d0c90 100644
--- a/chromium/components/discardable_memory/common/discardable_shared_memory_heap.cc
+++ b/chromium/components/discardable_memory/common/discardable_shared_memory_heap.cc
@@ -395,11 +395,6 @@ void DiscardableSharedMemoryHeap::OnMemoryDump(
base::StringPrintf("discardable/segment_%d", segment_id);
base::trace_event::MemoryAllocatorDump* segment_dump =
pmd->CreateAllocatorDump(segment_dump_name);
- // The size is added here so that telemetry picks up the size. Usually it is
- // just enough to add it to the global dump.
- segment_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- allocated_objects_size_in_bytes);
segment_dump->AddScalar("virtual_size",
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
size);
@@ -416,42 +411,9 @@ void DiscardableSharedMemoryHeap::OnMemoryDump(
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
locked_objects_size_in_bytes);
- // Emit an ownership edge towards a global allocator dump node. This allows
- // to avoid double-counting segments when both browser and client process emit
- // them. In the special case of single-process-mode, this will be the only
- // dumper active and the single ownership edge will become a no-op in the UI.
- // The global dump is created as a weak dump so that the segment is removed if
- // the browser does not dump it (segment was purged).
- const uint64_t tracing_process_id =
- base::trace_event::MemoryDumpManager::GetInstance()
- ->GetTracingProcessId();
- base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid =
- GetSegmentGUIDForTracing(tracing_process_id, segment_id);
- // TODO(ssid): Make this weak once the GUID created is consistent
- // crbug.com/661257.
- pmd->CreateSharedGlobalAllocatorDump(shared_segment_guid);
-
- // The size is added to the global dump so that it gets propagated to both the
- // dumps associated.
- pmd->GetSharedGlobalAllocatorDump(shared_segment_guid)
- ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- allocated_objects_size_in_bytes);
-
- // By creating an edge with a higher |importance| (w.r.t. browser-side dumps)
- // the tracing UI will account the effective size of the segment to the
- // client.
- const int kImportance = 2;
- pmd->AddOwnershipEdge(segment_dump->guid(), shared_segment_guid, kImportance);
-}
-
-// static
-base::trace_event::MemoryAllocatorDumpGuid
-DiscardableSharedMemoryHeap::GetSegmentGUIDForTracing(
- uint64_t tracing_process_id,
- int32_t segment_id) {
- return base::trace_event::MemoryAllocatorDumpGuid(base::StringPrintf(
- "discardable-x-process/%" PRIx64 "/%d", tracing_process_id, segment_id));
+ // The memory is owned by the client process (current).
+ shared_memory->CreateSharedMemoryOwnershipEdge(segment_dump, pmd,
+ /*is_owned=*/true);
}
base::trace_event::MemoryAllocatorDump*
diff --git a/chromium/components/discardable_memory/common/discardable_shared_memory_heap.h b/chromium/components/discardable_memory/common/discardable_shared_memory_heap.h
index 2d68e253510..8c9ff8d1d20 100644
--- a/chromium/components/discardable_memory/common/discardable_shared_memory_heap.h
+++ b/chromium/components/discardable_memory/common/discardable_shared_memory_heap.h
@@ -96,12 +96,6 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryHeap {
// Dumps memory statistics for chrome://tracing.
bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd);
- // Returns a unique identifier for a given tuple of (process id, segment id)
- // that can be used to match memory dumps across different processes.
- static base::trace_event::MemoryAllocatorDumpGuid GetSegmentGUIDForTracing(
- uint64_t tracing_process_id,
- int32_t segment_id);
-
// Returns a MemoryAllocatorDump for a given span on |pmd| with the size of
// the span.
base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
diff --git a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
index aca8774ab80..096f71da9a9 100644
--- a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
@@ -16,6 +16,7 @@
#include "base/memory/discardable_memory.h"
#include "base/memory/memory_coordinator_client_registry.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory_tracker.h"
#include "base/numerics/safe_math.h"
#include "base/process/memory.h"
#include "base/strings/string_number_conversions.h"
@@ -40,24 +41,8 @@
namespace discardable_memory {
namespace {
-const char kSingleProcess[] = "single-process";
-
const int kInvalidUniqueClientID = -1;
-const uint64_t kBrowserTracingProcessId = std::numeric_limits<uint64_t>::max();
-
-uint64_t ClientProcessUniqueIdToTracingProcessId(int client_id) {
- // TODO(penghuang): Move this function to right place.
- // https://crbug.com/661257
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcess))
- return kBrowserTracingProcessId;
- // The hash value is incremented so that the tracing id is never equal to
- // MemoryDumpManager::kInvalidTracingProcessId.
- return static_cast<uint64_t>(base::Hash(
- reinterpret_cast<const char*>(&client_id), sizeof(client_id))) +
- 1;
-}
-
// mojom::DiscardableSharedMemoryManager implementation. It contains the
// |client_id_| which is not visible to client. We associate allocations with a
// given mojo instance, so if the instance is closed, we can release the
@@ -242,6 +227,7 @@ DiscardableSharedMemoryManager::DiscardableSharedMemoryManager()
}
DiscardableSharedMemoryManager::~DiscardableSharedMemoryManager() {
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
this);
}
@@ -302,7 +288,6 @@ bool DiscardableSharedMemoryManager::OnMemoryDump(
if (!segment->memory()->mapped_size())
continue;
- // The "size" will be inherited form the shared global dump.
std::string dump_name = base::StringPrintf(
"discardable/process_%x/segment_%d", client_id, segment_id);
base::trace_event::MemoryAllocatorDump* dump =
@@ -318,33 +303,8 @@ bool DiscardableSharedMemoryManager::OnMemoryDump(
segment->memory()->IsMemoryLocked() ? segment->memory()->mapped_size()
: 0u);
- // Create the cross-process ownership edge. If the client creates a
- // corresponding dump for the same segment, this will avoid to
- // double-count them in tracing. If, instead, no other process will emit a
- // dump with the same guid, the segment will be accounted to the browser.
- const uint64_t client_tracing_id =
- ClientProcessUniqueIdToTracingProcessId(client_id);
- base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid =
- DiscardableSharedMemoryHeap::GetSegmentGUIDForTracing(
- client_tracing_id, segment_id);
- pmd->CreateSharedGlobalAllocatorDump(shared_segment_guid);
- pmd->AddOwnershipEdge(dump->guid(), shared_segment_guid);
-
-#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
- if (args.level_of_detail ==
- base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {
- size_t resident_size =
- base::trace_event::ProcessMemoryDump::CountResidentBytes(
- segment->memory()->memory(), segment->memory()->mapped_size());
-
- // This is added to the global dump since it has to be attributed to
- // both the allocator dumps involved.
- pmd->GetSharedGlobalAllocatorDump(shared_segment_guid)
- ->AddScalar("resident_size",
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- static_cast<uint64_t>(resident_size));
- }
-#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+ segment->memory()->CreateSharedMemoryOwnershipEdge(dump, pmd,
+ /*is_owned=*/false);
}
}
return true;
diff --git a/chromium/components/dom_distiller/README b/chromium/components/dom_distiller/README
index e8d7bb37f6b..d02997ef8e4 100644
--- a/chromium/components/dom_distiller/README
+++ b/chromium/components/dom_distiller/README
@@ -1,7 +1,8 @@
The DOM Distiller component contains code for an experimental prototype for
distilling the core part of a web page.
-To enable this feature, use the command line flag --enable-distiller.
+To enable this feature, use the command line flag --enable-dom-distiller.
+It may also help to use a new user profile --user-data-dir=<directory>
The DOM Distiller is a layered component. See:
http://www.chromium.org/developers/design-documents/layered-components-design
diff --git a/chromium/components/dom_distiller/content/browser/BUILD.gn b/chromium/components/dom_distiller/content/browser/BUILD.gn
index e7ebb3b7322..ae836592158 100644
--- a/chromium/components/dom_distiller/content/browser/BUILD.gn
+++ b/chromium/components/dom_distiller/content/browser/BUILD.gn
@@ -48,10 +48,7 @@ static_library("browser") {
if (is_android) {
sources += [
- "android/content_jni_registrar.cc",
- "android/content_jni_registrar.h",
"distillable_page_utils_android.cc",
- "distillable_page_utils_android.h",
]
deps += [ "android:jni_headers" ]
}
diff --git a/chromium/components/dom_distiller/content/browser/distillability_driver.cc b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
index 0bb7d2befee..f4c9d30c963 100644
--- a/chromium/components/dom_distiller/content/browser/distillability_driver.cc
+++ b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
@@ -11,7 +11,6 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(
dom_distiller::DistillabilityDriver);
@@ -27,8 +26,6 @@ class DistillabilityServiceImpl : public mojom::DistillabilityService {
: distillability_driver_(distillability_driver) {}
~DistillabilityServiceImpl() override {
- if (!distillability_driver_) return;
- distillability_driver_->SetNeedsMojoSetup();
}
void NotifyIsDistillable(bool is_distillable, bool is_last_update) override {
@@ -43,10 +40,11 @@ class DistillabilityServiceImpl : public mojom::DistillabilityService {
DistillabilityDriver::DistillabilityDriver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
- mojo_needs_setup_(true),
weak_factory_(this) {
if (!web_contents) return;
- SetupMojoService(web_contents->GetMainFrame());
+ frame_interfaces_.AddInterface(
+ base::Bind(&DistillabilityDriver::CreateDistillabilityService,
+ base::Unretained(this)));
}
DistillabilityDriver::~DistillabilityDriver() {
@@ -65,47 +63,17 @@ void DistillabilityDriver::SetDelegate(
m_delegate_ = delegate;
}
-void DistillabilityDriver::OnDistillability(
- bool distillable, bool is_last) {
+void DistillabilityDriver::OnDistillability(bool distillable, bool is_last) {
if (m_delegate_.is_null()) return;
m_delegate_.Run(distillable, is_last);
}
-void DistillabilityDriver::SetNeedsMojoSetup() {
- mojo_needs_setup_ = true;
-}
-
-void DistillabilityDriver::RenderFrameHostChanged(
- content::RenderFrameHost* old_host,
- content::RenderFrameHost* new_host) {
- // This method is invoked if any of the active RenderFrameHosts are swapped.
- // Only add the mojo service to the main frame host.
- if (!web_contents() || web_contents()->GetMainFrame() != new_host) return;
-
- // If the RenderFrameHost changes (this will happen if the user navigates to
- // or from a native page), the service needs to be attached to that host.
- mojo_needs_setup_ = true;
- SetupMojoService(new_host);
-}
-
-void DistillabilityDriver::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsSameDocument())
- SetupMojoService(navigation_handle->GetRenderFrameHost());
-}
-
-void DistillabilityDriver::SetupMojoService(
- content::RenderFrameHost* frame_host) {
- if (!frame_host || !frame_host->GetInterfaceRegistry()
- || !mojo_needs_setup_) {
- return;
- }
-
- frame_host->GetInterfaceRegistry()->AddInterface(
- base::Bind(&DistillabilityDriver::CreateDistillabilityService,
- weak_factory_.GetWeakPtr()));
- mojo_needs_setup_ = false;
+void DistillabilityDriver::OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ frame_interfaces_.TryBindInterface(interface_name, interface_pipe);
}
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/content/browser/distillability_driver.h b/chromium/components/dom_distiller/content/browser/distillability_driver.h
index 0cc51eb9a6e..ebfd4b07fde 100644
--- a/chromium/components/dom_distiller/content/browser/distillability_driver.h
+++ b/chromium/components/dom_distiller/content/browser/distillability_driver.h
@@ -11,6 +11,7 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
namespace dom_distiller {
@@ -26,25 +27,21 @@ class DistillabilityDriver
void SetDelegate(const base::Callback<void(bool, bool)>& delegate);
// content::WebContentsObserver implementation.
- void ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) override;
- void RenderFrameHostChanged(
- content::RenderFrameHost* old_host,
- content::RenderFrameHost* new_host) override;
+ void OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
private:
explicit DistillabilityDriver(content::WebContents* web_contents);
friend class content::WebContentsUserData<DistillabilityDriver>;
friend class DistillabilityServiceImpl;
- void SetupMojoService(content::RenderFrameHost* frame_host);
void OnDistillability(bool distillable, bool is_last);
- void SetNeedsMojoSetup();
-
base::Callback<void(bool, bool)> m_delegate_;
- bool mojo_needs_setup_;
+ service_manager::BinderRegistry frame_interfaces_;
base::WeakPtrFactory<DistillabilityDriver> weak_factory_;
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc b/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc
index 68430f6d964..ce50f4d30fe 100644
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc
+++ b/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.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/dom_distiller/content/browser/distillable_page_utils_android.h"
-
#include <memory>
#include "base/bind.h"
@@ -70,9 +68,5 @@ static void SetDelegate(JNIEnv* env,
setDelegate(web_contents, delegate);
}
-bool RegisterDistillablePageUtils(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
}
}
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.h b/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.h
deleted file mode 100644
index ba8bb75621a..00000000000
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.h
+++ /dev/null
@@ -1,16 +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.
-
-#ifndef COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_ANDROID_H_
-#define COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_ANDROID_H_
-
-#include <jni.h>
-
-namespace dom_distiller {
-namespace android {
-bool RegisterDistillablePageUtils(JNIEnv* env);
-}
-}
-
-#endif // COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_ANDROID_H_
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
index 800881a29f2..847a63b7159 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
@@ -32,9 +32,9 @@ void DistillerJavaScriptServiceImpl::HandleDistillerOpenSettingsCall() {
}
void CreateDistillerJavaScriptService(
- content::RenderFrameHost* render_frame_host,
DistillerUIHandle* distiller_ui_handle,
- mojom::DistillerJavaScriptServiceRequest request) {
+ mojom::DistillerJavaScriptServiceRequest request,
+ content::RenderFrameHost* render_frame_host) {
mojo::MakeStrongBinding(base::MakeUnique<DistillerJavaScriptServiceImpl>(
render_frame_host, distiller_ui_handle),
std::move(request));
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
index 90698a638c9..db5b9ee8a15 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
@@ -34,9 +34,9 @@ class DistillerJavaScriptServiceImpl
// static
void CreateDistillerJavaScriptService(
- content::RenderFrameHost* render_frame_host,
DistillerUIHandle* distiller_ui_handle,
- mojom::DistillerJavaScriptServiceRequest request);
+ mojom::DistillerJavaScriptServiceRequest request,
+ content::RenderFrameHost* render_frame_host);
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
index 0ac8f7c7b8e..739a62b64ec 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
@@ -163,8 +163,7 @@ void DistillerPageWebContents::DidFailLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& error_description,
- bool was_ignored_by_handler) {
+ const base::string16& error_description) {
if (!render_frame_host->GetParent()) {
content::WebContentsObserver::Observe(NULL);
DCHECK(state_ == LOADING_PAGE || state_ == EXECUTING_JAVASCRIPT);
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.h b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.h
index 56883d134aa..3f1d50c2800 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.h
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.h
@@ -69,8 +69,7 @@ class DistillerPageWebContents : public DistillerPage,
void DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& error_description,
- bool was_ignored_by_handler) override;
+ const base::string16& error_description) override;
protected:
bool StringifyOutput() override;
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index 212145b3c66..bed7d3189a1 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -67,6 +67,10 @@ class DomDistillerViewerSource::RequestViewerHandle
void WebContentsDestroyed() override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
+ void OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
private:
// Sends JavaScript to the attached Viewer, buffering data if the viewer isn't
@@ -96,6 +100,9 @@ class DomDistillerViewerSource::RequestViewerHandle
// feedback and opening the distiller settings. Guaranteed to outlive this
// object.
DistillerUIHandle* distiller_ui_handle_;
+
+ service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>
+ frame_interfaces_;
};
DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
@@ -111,6 +118,9 @@ DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
distiller_ui_handle_(ui_handle) {
content::WebContentsObserver::Observe(web_contents);
distilled_page_prefs_->AddObserver(this);
+
+ frame_interfaces_.AddInterface(
+ base::Bind(&CreateDistillerJavaScriptService, distiller_ui_handle_));
}
DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
@@ -145,13 +155,6 @@ void DomDistillerViewerSource::RequestViewerHandle::DidFinishNavigation(
navigation_handle->GetRenderFrameHost();
CHECK_EQ(0, render_frame_host->GetEnabledBindings());
- // Add mojo service for JavaScript functionality. This is the receiving
- // end of this particular service.
- render_frame_host->GetInterfaceRegistry()->AddInterface(
- base::Bind(&CreateDistillerJavaScriptService,
- render_frame_host,
- distiller_ui_handle_));
-
// Tell the renderer that this is currently a distilled page.
mojom::DistillerPageNotifierServicePtr page_notifier_service;
render_frame_host->GetRemoteInterfaces()->GetInterface(
@@ -208,6 +211,14 @@ void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad(
// No need to Cancel() here.
}
+void DomDistillerViewerSource::RequestViewerHandle::OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ frame_interfaces_.TryBindInterface(interface_name, interface_pipe,
+ render_frame_host);
+}
+
DomDistillerViewerSource::DomDistillerViewerSource(
DomDistillerServiceInterface* dom_distiller_service,
const std::string& scheme,
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
index 5be613204b9..1e42153998c 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
@@ -19,26 +19,29 @@ namespace dom_distiller {
DistillerJsRenderFrameObserver::DistillerJsRenderFrameObserver(
content::RenderFrame* render_frame,
- const int distiller_isolated_world_id)
+ const int distiller_isolated_world_id,
+ service_manager::BinderRegistry* registry)
: RenderFrameObserver(render_frame),
distiller_isolated_world_id_(distiller_isolated_world_id),
is_distiller_page_(false),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ registry->AddInterface(base::Bind(
+ &DistillerJsRenderFrameObserver::CreateDistillerPageNotifierService,
+ weak_factory_.GetWeakPtr()));
+}
DistillerJsRenderFrameObserver::~DistillerJsRenderFrameObserver() {}
void DistillerJsRenderFrameObserver::DidStartProvisionalLoad(
- blink::WebDataSource* data_source) {
- RegisterMojoInterface();
+ blink::WebDocumentLoader* document_loader) {
+ load_active_ = true;
}
void DistillerJsRenderFrameObserver::DidFinishLoad() {
// If no message about the distilled page was received at this point, there
- // will not be one; remove the mojom::DistillerPageNotifierService from the
- // registry.
- render_frame()
- ->GetInterfaceRegistry()
- ->RemoveInterface<mojom::DistillerPageNotifierService>();
+ // will not be one; stop binding requests for
+ // mojom::DistillerPageNotifierService.
+ load_active_ = false;
}
void DistillerJsRenderFrameObserver::DidCreateScriptContext(
@@ -53,14 +56,10 @@ void DistillerJsRenderFrameObserver::DidCreateScriptContext(
native_javascript_handle_->AddJavaScriptObjectToFrame(context);
}
-void DistillerJsRenderFrameObserver::RegisterMojoInterface() {
- render_frame()->GetInterfaceRegistry()->AddInterface(base::Bind(
- &DistillerJsRenderFrameObserver::CreateDistillerPageNotifierService,
- weak_factory_.GetWeakPtr()));
-}
-
void DistillerJsRenderFrameObserver::CreateDistillerPageNotifierService(
mojom::DistillerPageNotifierServiceRequest request) {
+ if (!load_active_)
+ return;
mojo::MakeStrongBinding(
base::MakeUnique<DistillerPageNotifierServiceImpl>(this),
std::move(request));
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
index c57c3c4a0d0..6a67caec56c 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
+++ b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
@@ -11,7 +11,7 @@
#include "components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "v8/include/v8.h"
namespace dom_distiller {
@@ -23,18 +23,17 @@ namespace dom_distiller {
class DistillerJsRenderFrameObserver : public content::RenderFrameObserver {
public:
DistillerJsRenderFrameObserver(content::RenderFrame* render_frame,
- const int distiller_isolated_world_id);
+ const int distiller_isolated_world_id,
+ service_manager::BinderRegistry* registry);
~DistillerJsRenderFrameObserver() override;
// RenderFrameObserver implementation.
- void DidStartProvisionalLoad(blink::WebDataSource* data_source) override;
+ void DidStartProvisionalLoad(
+ blink::WebDocumentLoader* document_loader) override;
void DidFinishLoad() override;
void DidCreateScriptContext(v8::Local<v8::Context> context,
int world_id) override;
- // Add the mojo interface to a RenderFrame's
- // service_manager::InterfaceRegistry.
- void RegisterMojoInterface();
// Flag the current page as a distiller page.
void SetIsDistillerPage();
@@ -51,6 +50,10 @@ class DistillerJsRenderFrameObserver : public content::RenderFrameObserver {
// Track if the current page is distilled. This is needed for testing.
bool is_distiller_page_;
+ // True if a load is in progress and we are currently able to bind requests
+ // for mojom::DistillerPageNotifierService.
+ bool load_active_ = false;
+
// Handle to "distiller" JavaScript object functionality.
std::unique_ptr<DistillerNativeJavaScript> native_javascript_handle_;
base::WeakPtrFactory<DistillerJsRenderFrameObserver> weak_factory_;
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
index f4293659abf..ae6959a7074 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
@@ -14,11 +14,8 @@
#include "gin/function_template.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "v8/include/v8.h"
-using blink::WebLocalFrame;
-
namespace dom_distiller {
DistillerNativeJavaScript::DistillerNativeJavaScript(
diff --git a/chromium/components/dom_distiller/core/distiller_url_fetcher.cc b/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
index 696af4f95c2..2cf48ec7711 100644
--- a/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
+++ b/chromium/components/dom_distiller/core/distiller_url_fetcher.cc
@@ -70,7 +70,7 @@ std::unique_ptr<URLFetcher> DistillerURLFetcher::CreateURLFetcher(
destination: WEBSITE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "user"
setting: "Users can enable or disable Mobile-friendly view by "
"toggling chrome://flags#reader-mode-heuristics in Chromium on "
diff --git a/chromium/components/dom_distiller/core/dom_distiller_model.h b/chromium/components/dom_distiller/core/dom_distiller_model.h
index ce96d4d0852..cff3820c34c 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_model.h
+++ b/chromium/components/dom_distiller/core/dom_distiller_model.h
@@ -12,7 +12,7 @@
#include <vector>
#include "base/containers/hash_tables.h"
-#include "base/id_map.h"
+#include "base/containers/id_map.h"
#include "base/macros.h"
#include "components/dom_distiller/core/article_entry.h"
#include "components/sync/model/sync_change.h"
diff --git a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
index c81a6530786..c9014ca1c73 100644
--- a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -7,8 +7,8 @@
#include <utility>
#include "base/command_line.h"
+#include "base/containers/id_map.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/id_map.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
diff --git a/chromium/components/domain_reliability/context.h b/chromium/components/domain_reliability/context.h
index da4a2448df3..aa77580e87e 100644
--- a/chromium/components/domain_reliability/context.h
+++ b/chromium/components/domain_reliability/context.h
@@ -7,10 +7,10 @@
#include <stddef.h>
-#include <deque>
#include <memory>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
@@ -119,7 +119,7 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
DomainReliabilityDispatcher* dispatcher_;
DomainReliabilityUploader* uploader_;
- std::deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
+ base::circular_deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
size_t uploading_beacons_size_;
base::TimeTicks upload_time_;
base::TimeTicks last_upload_time_;
diff --git a/chromium/components/domain_reliability/google_configs.cc b/chromium/components/domain_reliability/google_configs.cc
index a28a0b6e0c8..e5959d9b1b8 100644
--- a/chromium/components/domain_reliability/google_configs.cc
+++ b/chromium/components/domain_reliability/google_configs.cc
@@ -524,19 +524,19 @@ const GoogleConfigParams kGoogleConfigs[] = {
{"redirector.googlevideo.com", false, false, false},
};
-const char* kGoogleStandardCollectors[] = {
- "https://beacons.gcp.gvt2.com/domainreliability/upload",
- "https://beacons.gvt2.com/domainreliability/upload",
- "https://beacons2.gvt2.com/domainreliability/upload",
- "https://beacons3.gvt2.com/domainreliability/upload",
- "https://beacons4.gvt2.com/domainreliability/upload",
- "https://beacons5.gvt2.com/domainreliability/upload",
- "https://beacons5.gvt3.com/domainreliability/upload",
- "https://clients2.google.com/domainreliability/upload",
+const char* const kGoogleStandardCollectors[] = {
+ "https://beacons.gcp.gvt2.com/domainreliability/upload",
+ "https://beacons.gvt2.com/domainreliability/upload",
+ "https://beacons2.gvt2.com/domainreliability/upload",
+ "https://beacons3.gvt2.com/domainreliability/upload",
+ "https://beacons4.gvt2.com/domainreliability/upload",
+ "https://beacons5.gvt2.com/domainreliability/upload",
+ "https://beacons5.gvt3.com/domainreliability/upload",
+ "https://clients2.google.com/domainreliability/upload",
};
-const char* kGoogleOriginSpecificCollectorPathString =
- "/domainreliability/upload";
+const char* const kGoogleOriginSpecificCollectorPathString =
+ "/domainreliability/upload";
static std::unique_ptr<DomainReliabilityConfig> CreateGoogleConfig(
const GoogleConfigParams& params,
diff --git a/chromium/components/domain_reliability/monitor.cc b/chromium/components/domain_reliability/monitor.cc
index b9b11530a80..68efc592540 100644
--- a/chromium/components/domain_reliability/monitor.cc
+++ b/chromium/components/domain_reliability/monitor.cc
@@ -134,6 +134,7 @@ void DomainReliabilityMonitor::MoveToNetworkThread() {
void DomainReliabilityMonitor::InitURLRequestContext(
net::URLRequestContext* url_request_context) {
+ DCHECK(url_request_context);
DCHECK(OnNetworkThread());
DCHECK(moved_to_network_thread_);
diff --git a/chromium/components/domain_reliability/uploader.cc b/chromium/components/domain_reliability/uploader.cc
index 92bea3c394d..8ab248127de 100644
--- a/chromium/components/domain_reliability/uploader.cc
+++ b/chromium/components/domain_reliability/uploader.cc
@@ -103,7 +103,7 @@ class DomainReliabilityUploaderImpl
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable Domain Reliability on desktop, via "
"toggling 'Automatically send usage statistics and crash reports "
diff --git a/chromium/components/domain_reliability/util.cc b/chromium/components/domain_reliability/util.cc
index 9c4406fe9a4..8a9eb549dde 100644
--- a/chromium/components/domain_reliability/util.cc
+++ b/chromium/components/domain_reliability/util.cc
@@ -128,6 +128,7 @@ std::string GetDomainReliabilityProtocol(
case net::HttpResponseInfo::CONNECTION_INFO_QUIC_38:
case net::HttpResponseInfo::CONNECTION_INFO_QUIC_39:
case net::HttpResponseInfo::CONNECTION_INFO_QUIC_40:
+ case net::HttpResponseInfo::CONNECTION_INFO_QUIC_41:
return "QUIC";
case net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS:
NOTREACHED();
diff --git a/chromium/components/doodle/BUILD.gn b/chromium/components/doodle/BUILD.gn
deleted file mode 100644
index 0588d1738e6..00000000000
--- a/chromium/components/doodle/BUILD.gn
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-static_library("doodle") {
- sources = [
- "doodle_fetcher.h",
- "doodle_fetcher_impl.cc",
- "doodle_fetcher_impl.h",
- "doodle_service.cc",
- "doodle_service.h",
- "doodle_types.cc",
- "doodle_types.h",
- "pref_names.cc",
- "pref_names.h",
- ]
-
- deps = [
- "//base",
- "//components/data_use_measurement/core",
- "//components/google/core/browser",
- "//components/image_fetcher/core",
- "//components/keyed_service/core",
- "//components/prefs",
- "//net",
- "//ui/gfx",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "doodle_fetcher_impl_unittest.cc",
- "doodle_service_unittest.cc",
- "doodle_types_unittest.cc",
- ]
-
- deps = [
- ":doodle",
- "//components/google/core/browser",
- "//components/image_fetcher/core",
- "//components/prefs:test_support",
- "//net:test_support",
- "//ui/base",
- "//ui/gfx:test_support",
- ]
-}
diff --git a/chromium/components/doodle/DEPS b/chromium/components/doodle/DEPS
deleted file mode 100644
index f5fa82b871a..00000000000
--- a/chromium/components/doodle/DEPS
+++ /dev/null
@@ -1,12 +0,0 @@
-include_rules = [
- "+components/data_use_measurement/core",
- "+components/google/core/browser",
- "+components/image_fetcher/core",
- "+components/keyed_service/core",
- "+components/prefs",
- "+net/base",
- "+net/http/http_status_code.h",
- "+net/traffic_annotation",
- "+net/url_request",
- "+ui/gfx",
-]
diff --git a/chromium/components/doodle/OWNERS b/chromium/components/doodle/OWNERS
deleted file mode 100644
index 009f486a1d8..00000000000
--- a/chromium/components/doodle/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-treib@chromium.org
diff --git a/chromium/components/doodle/doodle_fetcher.h b/chromium/components/doodle/doodle_fetcher.h
deleted file mode 100644
index 5418bd97f57..00000000000
--- a/chromium/components/doodle/doodle_fetcher.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOODLE_DOODLE_FETCHER_H_
-#define COMPONENTS_DOODLE_DOODLE_FETCHER_H_
-
-#include "base/callback_forward.h"
-#include "base/optional.h"
-#include "components/doodle/doodle_types.h"
-
-namespace base {
-class TimeDelta;
-}
-
-namespace doodle {
-
-// Interface for fetching the current doodle from the network.
-// It asynchronously calls a callback when fetching the doodle information from
-// the remote enpoint finishes.
-// DoodleFetcherImpl is the default implementation; this interface exists to
-// make it easy to use fakes or mocks in tests.
-class DoodleFetcher {
- public:
- // Callback that is invoked when the fetching is done.
- // |time_to_live| will only be meaningful, and |doodle_config| will only
- // contain a value, if |state| is AVAILABLE.
- using FinishedCallback = base::OnceCallback<void(
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& doodle_config)>;
-
- virtual ~DoodleFetcher() = default;
-
- // Fetches a doodle asynchronously. The |callback| is called with a
- // DoodleState indicating whether the request succeded in fetching a doodle.
- // If a fetch is already running, the callback will be queued and invoked with
- // the result from the next completed request.
- virtual void FetchDoodle(FinishedCallback callback) = 0;
-
- // Returns whether a fetch is currently in progress, i.e. whether any callback
- // passed to FetchDoodle hasn't been called yet.
- virtual bool IsFetchInProgress() const = 0;
-};
-
-} // namespace doodle
-
-#endif // COMPONENTS_DOODLE_DOODLE_FETCHER_H_
diff --git a/chromium/components/doodle/doodle_fetcher_impl.cc b/chromium/components/doodle/doodle_fetcher_impl.cc
deleted file mode 100644
index c673745533e..00000000000
--- a/chromium/components/doodle/doodle_fetcher_impl.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/doodle_fetcher_impl.h"
-
-#include <utility>
-
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/google/core/browser/google_url_tracker.h"
-#include "components/google/core/browser/google_util.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-
-using net::URLFetcher;
-
-namespace doodle {
-
-namespace {
-
-// "/async/ddljson" is the base API path. "ntp:1" identifies this request as
-// being for a New Tab page. The "graybg:" param specifies whether the doodle
-// will be displayed on a gray background.
-const char kDoodleConfigPathFormat[] = "/async/ddljson?async=ntp:1,graybg:%d";
-
-std::string StripSafetyPreamble(const std::string& json) {
- // The response may start with )]}'. Ignore this.
- const char kResponsePreamble[] = ")]}'";
-
- base::StringPiece json_sp(json);
- if (json_sp.starts_with(kResponsePreamble)) {
- json_sp.remove_prefix(strlen(kResponsePreamble));
- }
-
- return json_sp.as_string();
-}
-
-GURL BuildDoodleURL(const GURL& base_url,
- bool gray_background,
- const base::Optional<std::string>& override_url) {
- std::string path =
- base::StringPrintf(kDoodleConfigPathFormat, gray_background ? 1 : 0);
- if (override_url.has_value()) {
- // The override URL may or may not be relative to the base URL.
- path = *override_url;
- }
- return base_url.Resolve(path);
-}
-
-} // namespace
-
-DoodleFetcherImpl::DoodleFetcherImpl(
- scoped_refptr<net::URLRequestContextGetter> download_context,
- GoogleURLTracker* google_url_tracker,
- const ParseJSONCallback& json_parsing_callback,
- bool gray_background,
- const base::Optional<std::string>& override_url)
- : download_context_(download_context),
- google_url_tracker_(google_url_tracker),
- json_parsing_callback_(json_parsing_callback),
- gray_background_(gray_background),
- override_url_(override_url),
- weak_ptr_factory_(this) {
- DCHECK(google_url_tracker_);
-}
-
-DoodleFetcherImpl::~DoodleFetcherImpl() = default;
-
-void DoodleFetcherImpl::FetchDoodle(FinishedCallback callback) {
- if (IsFetchInProgress()) {
- callbacks_.push_back(std::move(callback));
- return; // The callback will be called for the existing request's results.
- }
- DCHECK(!fetcher_.get());
- callbacks_.push_back(std::move(callback));
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("doodle_fetcher", R"(
- semantics {
- sender: "Doodle Fetcher"
- description:
- "Retrieves metadata (image URL, clickthrough URL etc) for any "
- "currently running Doodle."
- trigger:
- "Displaying the new tab page on Android."
- data:
- "The user's Google cookies. Used for example to show birthday "
- "doodles at appropriate times."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: true
- cookies_store: "user"
- setting:
- "Choosing a non-Google search engine in Chromium settings under "
- "'Search Engine' will disable this feature."
- chrome_policy {
- DefaultSearchProviderEnabled {
- policy_options {mode: MANDATORY}
- DefaultSearchProviderEnabled: false
- }
- }
- })");
- fetcher_ = URLFetcher::Create(
- BuildDoodleURL(GetGoogleBaseUrl(), gray_background_, override_url_),
- URLFetcher::GET, this, traffic_annotation);
- fetcher_->SetRequestContext(download_context_.get());
- // TODO(treib): Use OAuth2 authentication instead of cookies. crbug.com/711314
- fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_AUTH_DATA);
- fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
- data_use_measurement::DataUseUserData::AttachToFetcher(
- fetcher_.get(), data_use_measurement::DataUseUserData::DOODLE);
- fetcher_->Start();
-}
-
-bool DoodleFetcherImpl::IsFetchInProgress() const {
- return !callbacks_.empty();
-}
-
-void DoodleFetcherImpl::OnURLFetchComplete(const URLFetcher* source) {
- DCHECK_EQ(fetcher_.get(), source);
- std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
-
- std::string json_string;
- if (!(source->GetStatus().is_success() &&
- source->GetResponseCode() == net::HTTP_OK &&
- source->GetResponseAsString(&json_string))) {
- RespondToAllCallbacks(DoodleState::DOWNLOAD_ERROR, base::TimeDelta(),
- base::nullopt);
- return;
- }
-
- json_parsing_callback_.Run(StripSafetyPreamble(std::move(json_string)),
- base::Bind(&DoodleFetcherImpl::OnJsonParsed,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&DoodleFetcherImpl::OnJsonParseFailed,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DoodleFetcherImpl::OnJsonParsed(std::unique_ptr<base::Value> json) {
- std::unique_ptr<base::DictionaryValue> config =
- base::DictionaryValue::From(std::move(json));
- if (!config.get()) {
- DLOG(WARNING) << "Doodle JSON is not valid.";
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
- base::nullopt);
- return;
- }
-
- const base::DictionaryValue* ddljson = nullptr;
- if (!config->GetDictionary("ddljson", &ddljson)) {
- DLOG(WARNING) << "Doodle JSON response did not contain 'ddljson' key.";
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
- base::nullopt);
- return;
- }
-
- base::TimeDelta time_to_live;
- base::Optional<DoodleConfig> doodle =
- ParseDoodleConfigAndTimeToLive(*ddljson, &time_to_live);
- if (!doodle.has_value()) {
- RespondToAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
- base::nullopt);
- return;
- }
-
- RespondToAllCallbacks(DoodleState::AVAILABLE, time_to_live,
- std::move(doodle));
-}
-
-void DoodleFetcherImpl::OnJsonParseFailed(const std::string& error_message) {
- DLOG(WARNING) << "JSON parsing failed: " << error_message;
- RespondToAllCallbacks(DoodleState::PARSING_ERROR, base::TimeDelta(),
- base::nullopt);
-}
-
-base::Optional<DoodleConfig> DoodleFetcherImpl::ParseDoodleConfigAndTimeToLive(
- const base::DictionaryValue& ddljson,
- base::TimeDelta* time_to_live) const {
- base::Optional<DoodleConfig> doodle =
- DoodleConfig::FromDictionary(ddljson, GetGoogleBaseUrl());
-
- // The JSON doesn't guarantee the number to fit into an int.
- double ttl_ms = 0; // Expires immediately if the parameter is missing.
- if (!ddljson.GetDouble("time_to_live_ms", &ttl_ms) || ttl_ms < 0) {
- DLOG(WARNING) << "No valid Doodle TTL present in ddljson!";
- ttl_ms = 0;
- }
- *time_to_live = base::TimeDelta::FromMillisecondsD(ttl_ms);
-
- return doodle;
-}
-
-void DoodleFetcherImpl::RespondToAllCallbacks(
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& config) {
- for (auto& callback : callbacks_) {
- std::move(callback).Run(state, time_to_live, config);
- }
- callbacks_.clear();
-}
-
-GURL DoodleFetcherImpl::GetGoogleBaseUrl() const {
- GURL cmd_line_url = google_util::CommandLineGoogleBaseURL();
- if (cmd_line_url.is_valid()) {
- return cmd_line_url;
- }
- return google_url_tracker_->google_url();
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/doodle_fetcher_impl.h b/chromium/components/doodle/doodle_fetcher_impl.h
deleted file mode 100644
index f8eb6fd9949..00000000000
--- a/chromium/components/doodle/doodle_fetcher_impl.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOODLE_DOODLE_FETCHER_IMPL_H_
-#define COMPONENTS_DOODLE_DOODLE_FETCHER_IMPL_H_
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "components/doodle/doodle_fetcher.h"
-#include "components/doodle/doodle_types.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
-
-class GoogleURLTracker;
-
-namespace base {
-class DictionaryValue;
-class TimeDelta;
-class Value;
-}
-
-namespace doodle {
-
-// This class provides information about any recent doodle.
-// It works asynchronously and calls a callback when finished fetching the
-// information from the remote enpoint.
-class DoodleFetcherImpl : public DoodleFetcher, public net::URLFetcherDelegate {
- public:
- // Callback for JSON parsing to allow injecting platform-dependent code.
- using ParseJSONCallback = base::Callback<void(
- const std::string& unsafe_json,
- const base::Callback<void(std::unique_ptr<base::Value> json)>& success,
- const base::Callback<void(const std::string&)>& error)>;
-
- DoodleFetcherImpl(
- scoped_refptr<net::URLRequestContextGetter> download_context,
- GoogleURLTracker* google_url_tracker,
- const ParseJSONCallback& json_parsing_callback,
- bool gray_background,
- const base::Optional<std::string>& override_url);
- ~DoodleFetcherImpl() override;
-
- // DoodleFetcher implementation.
- void FetchDoodle(FinishedCallback callback) override;
- bool IsFetchInProgress() const override;
-
- private:
- // net::URLFetcherDelegate implementation.
- void OnURLFetchComplete(const net::URLFetcher* source) override;
-
- // ParseJSONCallback Success callback
- void OnJsonParsed(std::unique_ptr<base::Value> json);
- // ParseJSONCallback Failure callback
- void OnJsonParseFailed(const std::string& error_message);
-
- base::Optional<DoodleConfig> ParseDoodleConfigAndTimeToLive(
- const base::DictionaryValue& ddljson,
- base::TimeDelta* time_to_live) const;
-
- void RespondToAllCallbacks(DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& config);
-
- GURL GetGoogleBaseUrl() const;
-
- // Parameters set from constructor.
- scoped_refptr<net::URLRequestContextGetter> const download_context_;
- GoogleURLTracker* google_url_tracker_;
- ParseJSONCallback json_parsing_callback_;
- const bool gray_background_;
- const base::Optional<std::string> override_url_;
-
- std::vector<FinishedCallback> callbacks_;
- std::unique_ptr<net::URLFetcher> fetcher_;
-
- base::WeakPtrFactory<DoodleFetcherImpl> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DoodleFetcherImpl);
-};
-
-} // namespace doodle
-
-#endif // COMPONENTS_DOODLE_DOODLE_FETCHER_IMPL_H_
diff --git a/chromium/components/doodle/doodle_fetcher_impl_unittest.cc b/chromium/components/doodle/doodle_fetcher_impl_unittest.cc
deleted file mode 100644
index 94f95740da3..00000000000
--- a/chromium/components/doodle/doodle_fetcher_impl_unittest.cc
+++ /dev/null
@@ -1,439 +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/doodle/doodle_fetcher_impl.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/mock_callback.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "components/google/core/browser/google_switches.h"
-#include "components/google/core/browser/google_url_tracker.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::DoAll;
-using testing::Eq;
-using testing::SaveArg;
-
-namespace doodle {
-
-namespace {
-
-const char kDoodleConfigPath[] = "/async/ddljson?async=ntp:1,graybg:1";
-const char kDoodleConfigPathNoGrayBg[] = "/async/ddljson?async=ntp:1,graybg:0";
-
-// Required to instantiate a GoogleUrlTracker in UNIT_TEST_MODE.
-class GoogleURLTrackerClientStub : public GoogleURLTrackerClient {
- public:
- GoogleURLTrackerClientStub() {}
- ~GoogleURLTrackerClientStub() override {}
-
- bool IsBackgroundNetworkingEnabled() override { return true; }
-
- PrefService* GetPrefs() override { return nullptr; }
-
- net::URLRequestContextGetter* GetRequestContext() override { return nullptr; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GoogleURLTrackerClientStub);
-};
-
-void ParseJson(
- const std::string& json,
- const base::Callback<void(std::unique_ptr<base::Value> json)>& success,
- const base::Callback<void(const std::string&)>& error) {
- base::JSONReader json_reader;
- std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
- if (value) {
- success.Run(std::move(value));
- } else {
- error.Run(json_reader.GetErrorMessage());
- }
-}
-
-} // namespace
-
-class DoodleFetcherImplTestBase : public testing::Test {
- public:
- DoodleFetcherImplTestBase(bool gray_background,
- const base::Optional<std::string>& override_url)
- : google_url_tracker_(base::MakeUnique<GoogleURLTrackerClientStub>(),
- GoogleURLTracker::UNIT_TEST_MODE),
- doodle_fetcher_(
- new net::TestURLRequestContextGetter(message_loop_.task_runner()),
- &google_url_tracker_,
- base::Bind(ParseJson),
- gray_background,
- override_url) {}
-
- void RespondWithData(const std::string& data) {
- net::TestURLFetcher* url_fetcher = GetRunningFetcher();
- url_fetcher->set_status(net::URLRequestStatus());
- url_fetcher->set_response_code(net::HTTP_OK);
- url_fetcher->SetResponseString(data);
- // Call the URLFetcher delegate to continue the test.
- url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
- }
-
- void RespondWithError(int error_code) {
- net::TestURLFetcher* url_fetcher = GetRunningFetcher();
- url_fetcher->set_status(net::URLRequestStatus::FromError(error_code));
- url_fetcher->SetResponseString("");
- // Call the URLFetcher delegate to continue the test.
- url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
- }
-
- net::TestURLFetcher* GetRunningFetcher() {
- // All created TestURLFetchers have ID 0 by default.
- net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(0);
- DCHECK(url_fetcher);
- return url_fetcher;
- }
-
- DoodleFetcherImpl* doodle_fetcher() { return &doodle_fetcher_; }
-
- GURL GetGoogleBaseURL() { return google_url_tracker_.google_url(); }
-
- GURL Resolve(const std::string& relative_url) {
- return GetGoogleBaseURL().Resolve(relative_url);
- }
-
- private:
- base::MessageLoop message_loop_;
- net::TestURLFetcherFactory url_fetcher_factory_;
- GoogleURLTracker google_url_tracker_;
- DoodleFetcherImpl doodle_fetcher_;
-};
-
-class DoodleFetcherImplTest : public DoodleFetcherImplTestBase {
- public:
- DoodleFetcherImplTest()
- : DoodleFetcherImplTestBase(/*gray_background=*/true,
- /*override_url=*/base::nullopt) {}
-};
-
-TEST_F(DoodleFetcherImplTest, ReturnsFromFetchWithoutError) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData(R"json({"ddljson": {
- "time_to_live_ms":55000,
- "large_image": {"url":"/logos/doodles/2015/some.gif"}
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- EXPECT_TRUE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ReturnsFrom404FetchWithError) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithError(net::ERR_FILE_NOT_FOUND);
-
- EXPECT_THAT(state, Eq(DoodleState::DOWNLOAD_ERROR));
- EXPECT_FALSE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ReturnsErrorForInvalidJson) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData("}");
-
- EXPECT_THAT(state, Eq(DoodleState::PARSING_ERROR));
- EXPECT_FALSE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ReturnsErrorForIncompleteJson) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData("{}");
-
- EXPECT_THAT(state, Eq(DoodleState::PARSING_ERROR));
- EXPECT_FALSE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ResponseContainsValidBaseInformation) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::TimeDelta time_to_live;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
- SaveArg<2>(&response)));
- RespondWithData(R"json()]}'{
- "ddljson": {
- "alt_text":"Mouseover Text",
- "doodle_type":"SIMPLE",
- "target_url":"/search?q\u003dtest\u0026sa\u003dX\u0026ved\u003d0ahUKEw",
- "time_to_live_ms":55000,
- "large_image": {
- "url":"/logos/doodles/2015/new-years-eve-2015-59854387958251-hp.gif"
- }
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- ASSERT_TRUE(response.has_value());
- DoodleConfig config = response.value();
-
- EXPECT_TRUE(config.target_url.is_valid());
- EXPECT_THAT(config.target_url,
- Eq(Resolve("/search?q\u003dtest\u0026sa\u003dX\u0026ved\u003d"
- "0ahUKEw")));
- EXPECT_THAT(config.doodle_type, Eq(DoodleType::SIMPLE));
- EXPECT_THAT(config.alt_text, Eq("Mouseover Text"));
-
- EXPECT_FALSE(config.large_cta_image.has_value());
-
- EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(55000)));
-}
-
-TEST_F(DoodleFetcherImplTest, DoodleExpiresImmediatelyWithNegativeTTL) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::TimeDelta time_to_live;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
- SaveArg<2>(&response)));
- RespondWithData(R"json({"ddljson": {
- "time_to_live_ms":-1,
- "large_image": {"url":"/logos/doodles/2015/some.gif"}
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- EXPECT_TRUE(response.has_value());
- EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(0)));
-}
-
-TEST_F(DoodleFetcherImplTest, DoodleExpiresImmediatelyWithoutValidTTL) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::TimeDelta time_to_live;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<1>(&time_to_live),
- SaveArg<2>(&response)));
- RespondWithData(R"json({"ddljson": {
- "large_image": {"url":"/logos/doodles/2015/some.gif"}
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- EXPECT_TRUE(response.has_value());
- EXPECT_THAT(time_to_live, Eq(base::TimeDelta::FromMilliseconds(0)));
-}
-
-TEST_F(DoodleFetcherImplTest, ReturnsNoDoodleForMissingLargeImageUrl) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::AVAILABLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData(R"json({"ddljson": {
- "time_to_live_ms":55000,
- "large_image": {}
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::NO_DOODLE));
- EXPECT_FALSE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, EmptyResponsesCausesNoDoodleState) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::AVAILABLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData("{\"ddljson\":{}}");
-
- EXPECT_THAT(state, Eq(DoodleState::NO_DOODLE));
- EXPECT_FALSE(response.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ResponseContainsExactlyTheSampleImages) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- DoodleState state = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response;
- EXPECT_CALL(callback, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state), SaveArg<2>(&response)));
- RespondWithData(R"json()]}'{
- "ddljson": {
- "time_to_live_ms":55000,
- "large_image": {
- "height":225,
- "url":"/logos/doodles/2015/new-years-eve-2015-59854387958251-hp.gif",
- "width":489
- },
- "large_cta_image": {
- "height":225,
- "url":"/logos/doodles/2015/new-years-eve-2015-59854387958251-cta.gif",
- "width":489
- }
- }})json");
-
- EXPECT_THAT(state, Eq(DoodleState::AVAILABLE));
- ASSERT_TRUE(response.has_value());
- DoodleConfig config = response.value();
-
- EXPECT_TRUE(config.large_image.url.is_valid());
- EXPECT_THAT(config.large_image.url,
- Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
- "8251-hp.gif")));
-
- ASSERT_TRUE(config.large_cta_image.has_value());
- EXPECT_TRUE(config.large_cta_image->url.is_valid());
- EXPECT_THAT(config.large_cta_image->url,
- Eq(Resolve("/logos/doodles/2015/new-years-eve-2015-5985438795"
- "8251-cta.gif")));
-}
-
-TEST_F(DoodleFetcherImplTest, RespondsToMultipleRequestsWithSameFetcher) {
- // Trigger two requests.
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback1;
- doodle_fetcher()->FetchDoodle(callback1.Get());
- net::URLFetcher* first_created_fetcher = GetRunningFetcher();
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback2;
- doodle_fetcher()->FetchDoodle(callback2.Get());
- net::URLFetcher* second_created_fetcher = GetRunningFetcher();
-
- // Expect that only one fetcher handles both requests.
- EXPECT_THAT(first_created_fetcher, Eq(second_created_fetcher));
-
- // But both callbacks should get called.
- DoodleState state1 = DoodleState::NO_DOODLE;
- DoodleState state2 = DoodleState::NO_DOODLE;
- base::Optional<DoodleConfig> response1;
- base::Optional<DoodleConfig> response2;
-
- EXPECT_CALL(callback1, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state1), SaveArg<2>(&response1)));
- EXPECT_CALL(callback2, Run(_, _, _))
- .WillOnce(DoAll(SaveArg<0>(&state2), SaveArg<2>(&response2)));
-
- RespondWithData(R"json({"ddljson": {
- "time_to_live_ms":55000,
- "large_image": {"url":"/logos/doodles/2015/some.gif"}
- }})json");
-
- // Ensure that both requests received a response.
- EXPECT_THAT(state1, Eq(DoodleState::AVAILABLE));
- EXPECT_TRUE(response1.has_value());
- EXPECT_THAT(state2, Eq(DoodleState::AVAILABLE));
- EXPECT_TRUE(response2.has_value());
-}
-
-TEST_F(DoodleFetcherImplTest, ReceivesBaseUrlFromTracker) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- // TODO(treib,fhorschig): This doesn't really test anything useful, since the
- // Google base URL is the default anyway. Find a way to set the base URL in
- // the tracker.
- EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
- Eq(Resolve(kDoodleConfigPath)));
-}
-
-TEST_F(DoodleFetcherImplTest, OverridesBaseUrlWithCommandLineArgument) {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kGoogleBaseURL, "http://www.google.kz");
-
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
- Eq(GURL("http://www.google.kz").Resolve(kDoodleConfigPath)));
-}
-
-class DoodleFetcherImplNoGrayBgTest : public DoodleFetcherImplTestBase {
- public:
- DoodleFetcherImplNoGrayBgTest()
- : DoodleFetcherImplTestBase(/*gray_background=*/false,
- /*override_url=*/base::nullopt) {}
-};
-
-TEST_F(DoodleFetcherImplNoGrayBgTest, PassesNoGrayBgParam) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
- Eq(Resolve(kDoodleConfigPathNoGrayBg)));
-}
-
-class DoodleFetcherImplRelativeOverrideUrlTest
- : public DoodleFetcherImplTestBase {
- public:
- DoodleFetcherImplRelativeOverrideUrlTest()
- : DoodleFetcherImplTestBase(/*gray_background=*/false,
- /*override_url=*/std::string("/different")) {}
-};
-
-TEST_F(DoodleFetcherImplRelativeOverrideUrlTest, OverridesWithRelativeUrl) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(), Eq(Resolve("/different")));
-}
-
-class DoodleFetcherImplAbsoluteOverrideUrlTest
- : public DoodleFetcherImplTestBase {
- public:
- DoodleFetcherImplAbsoluteOverrideUrlTest()
- : DoodleFetcherImplTestBase(
- /*gray_background=*/false,
- /*override_url=*/std::string("http://host.com/ddl")) {}
-};
-
-TEST_F(DoodleFetcherImplAbsoluteOverrideUrlTest, OverridesWithAbsoluteUrl) {
- base::MockCallback<DoodleFetcherImpl::FinishedCallback> callback;
- doodle_fetcher()->FetchDoodle(callback.Get());
-
- EXPECT_THAT(GetRunningFetcher()->GetOriginalURL(),
- Eq(GURL("http://host.com/ddl")));
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/doodle_service.cc b/chromium/components/doodle/doodle_service.cc
deleted file mode 100644
index ce3ab4d73a2..00000000000
--- a/chromium/components/doodle/doodle_service.cc
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/doodle_service.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/values.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/doodle/pref_names.h"
-#include "components/image_fetcher/core/image_fetcher.h"
-#include "components/image_fetcher/core/request_metadata.h"
-#include "components/prefs/pref_registry.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "ui/gfx/image/image.h"
-
-namespace doodle {
-
-namespace {
-
-// The maximum time-to-live we'll accept; any larger values will be clamped to
-// this one. This is a last resort in case the server sends bad data.
-const int64_t kMaxTimeToLiveSecs = 30 * 24 * 60 * 60; // 30 days
-
-// The default value for DoodleService::min_refresh_interval_.
-const int64_t kDefaultMinRefreshIntervalSecs = 15 * 60; // 15 minutes
-
-// The maximum number of bytes to allow in a doodle image. This limits the
-// downloaded data to an amount that real images are unlikely to exceed. It is a
-// safeguard against server-side errors.
-const int64_t kMaxImageDownloadBytes = 1024 * 1024;
-
-} // namespace
-
-// static
-void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) {
- pref_registry->RegisterDictionaryPref(
- prefs::kCachedConfig, base::MakeUnique<base::DictionaryValue>(),
- PrefRegistry::LOSSY_PREF);
- pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0,
- PrefRegistry::LOSSY_PREF);
-}
-
-DoodleService::DoodleService(
- PrefService* pref_service,
- std::unique_ptr<DoodleFetcher> fetcher,
- std::unique_ptr<base::OneShotTimer> expiry_timer,
- std::unique_ptr<base::Clock> clock,
- std::unique_ptr<base::TickClock> tick_clock,
- base::Optional<base::TimeDelta> override_min_refresh_interval,
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher)
- : pref_service_(pref_service),
- fetcher_(std::move(fetcher)),
- expiry_timer_(std::move(expiry_timer)),
- clock_(std::move(clock)),
- tick_clock_(std::move(tick_clock)),
- min_refresh_interval_(
- override_min_refresh_interval.has_value()
- ? override_min_refresh_interval.value()
- : base::TimeDelta::FromSeconds(kDefaultMinRefreshIntervalSecs)),
- image_fetcher_(std::move(image_fetcher)) {
- DCHECK(pref_service_);
- DCHECK(fetcher_);
- DCHECK(expiry_timer_);
- DCHECK(clock_);
- DCHECK(tick_clock_);
- DCHECK(image_fetcher_);
-
- image_fetcher_->SetImageDownloadLimit(kMaxImageDownloadBytes);
- image_fetcher_->SetDataUseServiceName(
- data_use_measurement::DataUseUserData::DOODLE);
-
- base::Time expiry_date = base::Time::FromInternalValue(
- pref_service_->GetInt64(prefs::kCachedConfigExpiry));
- base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary(
- *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt);
- DoodleState state =
- config.has_value() ? DoodleState::AVAILABLE : DoodleState::NO_DOODLE;
- HandleNewConfig(state, expiry_date - clock_->Now(), config);
-
- // If we don't have a cached doodle, immediately start a fetch, so that the
- // first NTP will get it quicker.
- if (state == DoodleState::NO_DOODLE) {
- Refresh();
- }
-}
-
-DoodleService::~DoodleService() = default;
-
-void DoodleService::Shutdown() {}
-
-void DoodleService::GetImage(const ImageCallback& callback) {
- if (!cached_config_.has_value()) {
- callback.Run(gfx::Image());
- return;
- }
-
- // If there is a CTA image, that means the main image is animated. Show the
- // non-animated CTA image first, and load the animated one only when the
- // user requests it.
- bool has_cta = cached_config_->large_cta_image.has_value();
- const GURL& image_url = has_cta ? cached_config_->large_cta_image->url
- : cached_config_->large_image.url;
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("doodle_service", R"(
- semantics {
- sender: "Doodle Service"
- description:
- "Downloads the Doodle image if Google is the configured search "
- "provider."
- trigger: "Displaying the new tab page on Android."
- data: "None."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: false
- setting:
- "Choosing a non-Google search engine in Chromium settings under "
- "'Search Engine' disables this feature."
- chrome_policy {
- DefaultSearchProviderEnabled {
- policy_options {mode: MANDATORY}
- DefaultSearchProviderEnabled: false
- }
- }
- })");
- image_fetcher_->StartOrQueueNetworkRequest(
- image_url.spec(), image_url,
- base::Bind(&DoodleService::ImageFetched, base::Unretained(this),
- callback),
- traffic_annotation);
-}
-
-void DoodleService::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void DoodleService::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void DoodleService::Refresh() {
- // If we're already waiting for a fetch, don't start another one. The
- // observers will get notified when the ongoing fetch returns.
- if (fetcher_->IsFetchInProgress()) {
- return;
- }
-
- base::TimeTicks now_ticks = tick_clock_->NowTicks();
- // Check if we have passed the minimum refresh interval.
- base::TimeDelta time_since_fetch = now_ticks - last_successful_fetch_;
- if (time_since_fetch < min_refresh_interval_) {
- RecordDownloadMetrics(OUTCOME_REFRESH_INTERVAL_NOT_PASSED,
- base::TimeDelta());
- for (auto& observer : observers_) {
- observer.OnDoodleConfigRevalidated(/*from_cache=*/true);
- }
- return;
- }
-
- fetcher_->FetchDoodle(base::BindOnce(&DoodleService::DoodleFetched,
- base::Unretained(this), now_ticks));
-}
-
-// static
-bool DoodleService::DownloadOutcomeIsSuccess(DownloadOutcome outcome) {
- switch (outcome) {
- case OUTCOME_NEW_DOODLE:
- case OUTCOME_REVALIDATED_DOODLE:
- case OUTCOME_CHANGED_DOODLE:
- case OUTCOME_NO_DOODLE:
- return true;
- case OUTCOME_EXPIRED:
- case OUTCOME_DOWNLOAD_ERROR:
- case OUTCOME_PARSING_ERROR:
- case OUTCOME_REFRESH_INTERVAL_NOT_PASSED:
- return false;
- case OUTCOME_COUNT:
- NOTREACHED();
- }
- return false;
-}
-
-// static
-void DoodleService::RecordDownloadMetrics(DownloadOutcome outcome,
- base::TimeDelta download_time) {
- UMA_HISTOGRAM_ENUMERATION("Doodle.ConfigDownloadOutcome", outcome,
- OUTCOME_COUNT);
-
- if (DownloadOutcomeIsSuccess(outcome)) {
- UMA_HISTOGRAM_MEDIUM_TIMES("Doodle.ConfigDownloadTime", download_time);
- }
-}
-
-// static
-DoodleService::DownloadOutcome DoodleService::DetermineDownloadOutcome(
- const base::Optional<DoodleConfig>& old_config,
- const base::Optional<DoodleConfig>& new_config,
- DoodleState state,
- bool expired) {
- // First, handle error cases: *_ERROR or EXPIRED override other outcomes.
- switch (state) {
- case DoodleState::AVAILABLE:
- if (expired) {
- return OUTCOME_EXPIRED;
- }
- break;
-
- case DoodleState::NO_DOODLE:
- break;
-
- case DoodleState::DOWNLOAD_ERROR:
- return OUTCOME_DOWNLOAD_ERROR;
-
- case DoodleState::PARSING_ERROR:
- return OUTCOME_PARSING_ERROR;
- }
-
- if (!new_config.has_value()) {
- return OUTCOME_NO_DOODLE;
- }
- if (!old_config.has_value()) {
- return OUTCOME_NEW_DOODLE;
- }
- if (old_config.value() != new_config.value()) {
- return OUTCOME_CHANGED_DOODLE;
- }
- return OUTCOME_REVALIDATED_DOODLE;
-}
-
-void DoodleService::DoodleFetched(
- base::TimeTicks start_time,
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& doodle_config) {
- base::TimeTicks now_ticks = tick_clock_->NowTicks();
- DownloadOutcome outcome = HandleNewConfig(state, time_to_live, doodle_config);
- if (DownloadOutcomeIsSuccess(outcome)) {
- last_successful_fetch_ = now_ticks;
- }
- base::TimeDelta download_time = now_ticks - start_time;
- RecordDownloadMetrics(outcome, download_time);
-}
-
-DoodleService::DownloadOutcome DoodleService::HandleNewConfig(
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& doodle_config) {
- // Clamp the time-to-live to some reasonable maximum.
- if (time_to_live.InSeconds() > kMaxTimeToLiveSecs) {
- time_to_live = base::TimeDelta::FromSeconds(kMaxTimeToLiveSecs);
- DLOG(WARNING) << "Clamping TTL to " << kMaxTimeToLiveSecs << " seconds!";
- }
-
- // Handle the case where the new config is already expired.
- bool expired = time_to_live <= base::TimeDelta();
- const base::Optional<DoodleConfig>& new_config =
- expired ? base::nullopt : doodle_config;
-
- // Determine the download outcome *before* updating the cached config.
- DownloadOutcome outcome =
- DetermineDownloadOutcome(cached_config_, new_config, state, expired);
-
- // Note that this checks both for existence changes as well as changes of the
- // configs themselves.
- if (cached_config_ != new_config) {
- UpdateCachedConfig(time_to_live, new_config);
-
- for (auto& observer : observers_) {
- observer.OnDoodleConfigUpdated(cached_config_);
- }
- } else {
- for (auto& observer : observers_) {
- observer.OnDoodleConfigRevalidated(/*from_cache=*/false);
- }
- }
-
- // Even if the configs are identical, the time-to-live might have changed.
- // (Re-)schedule the cache expiry.
- if (cached_config_.has_value()) {
- expiry_timer_->Start(
- FROM_HERE, time_to_live,
- base::Bind(&DoodleService::DoodleExpired, base::Unretained(this)));
- } else {
- expiry_timer_->Stop();
- }
-
- return outcome;
-}
-
-void DoodleService::UpdateCachedConfig(
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& new_config) {
- DCHECK(cached_config_ != new_config);
-
- cached_config_ = new_config;
-
- if (cached_config_.has_value()) {
- pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary());
- base::Time expiry_date = clock_->Now() + time_to_live;
- pref_service_->SetInt64(prefs::kCachedConfigExpiry,
- expiry_date.ToInternalValue());
- } else {
- pref_service_->ClearPref(prefs::kCachedConfig);
- pref_service_->ClearPref(prefs::kCachedConfigExpiry);
- }
-}
-
-void DoodleService::DoodleExpired() {
- DCHECK(cached_config_.has_value());
- HandleNewConfig(DoodleState::NO_DOODLE, base::TimeDelta(), base::nullopt);
-}
-
-void DoodleService::ImageFetched(
- const ImageCallback& callback,
- const std::string& id,
- const gfx::Image& image,
- const image_fetcher::RequestMetadata& metadata) {
- if (image.IsEmpty()) {
- DLOG(WARNING) << "Failed to download doodle image";
- } else {
- // TODO(treib): Rename this to "Doodle.*" after we've decided what to do
- // about crbug.com/719513.
- UMA_HISTOGRAM_BOOLEAN("NewTabPage.LogoImageDownloaded",
- metadata.from_http_cache);
- }
-
- callback.Run(image);
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/doodle_service.h b/chromium/components/doodle/doodle_service.h
deleted file mode 100644
index a1d574aac88..00000000000
--- a/chromium/components/doodle/doodle_service.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOODLE_DOODLE_SERVICE_H_
-#define COMPONENTS_DOODLE_DOODLE_SERVICE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/optional.h"
-#include "base/time/clock.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/doodle/doodle_fetcher.h"
-#include "components/doodle/doodle_types.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace gfx {
-class Image;
-}
-
-namespace image_fetcher {
-class ImageFetcher;
-struct RequestMetadata;
-}
-
-namespace doodle {
-
-class DoodleService : public KeyedService {
- public:
- class Observer {
- public:
- virtual void OnDoodleConfigRevalidated(bool from_cache) = 0;
- virtual void OnDoodleConfigUpdated(const base::Optional<DoodleConfig>&) = 0;
- };
-
- using ImageCallback = base::Callback<void(const gfx::Image& image)>;
-
- static void RegisterProfilePrefs(PrefRegistrySimple* pref_registry);
-
- // All pointer parameters must be non-null. If |min_refresh_interval| doesn't
- // have a value, the default value is used.
- DoodleService(PrefService* pref_service,
- std::unique_ptr<DoodleFetcher> fetcher,
- std::unique_ptr<base::OneShotTimer> expiry_timer,
- std::unique_ptr<base::Clock> clock,
- std::unique_ptr<base::TickClock> tick_clock,
- base::Optional<base::TimeDelta> override_min_refresh_interval,
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher);
- ~DoodleService() override;
-
- // KeyedService implementation.
- void Shutdown() override;
-
- // Returns the current (cached) config, if any.
- const base::Optional<DoodleConfig>& config() const { return cached_config_; }
-
- // Returns the image for the currently-cached doodle config via |callback|,
- // which may be run synchronously or asynchronously. If the doodle is
- // animated, this returns the static CTA image.
- void GetImage(const ImageCallback& callback);
-
- // Adds a new observer to the service. It'll only be called when the config
- // changes; to get the current (cached) config, call |config()|.
- void AddObserver(Observer* observer);
-
- // Prevents |observer| from receiving future updates. This is safe to call
- // even when the observer is being notified of an update.
- void RemoveObserver(Observer* observer);
-
- // Requests an asynchronous refresh of the DoodleConfig from the network.
- // After the update completes, the observers will be notified whether the
- // config changed or active config remains valid.
- void Refresh();
-
- private:
- // Note: Keep in sync with the corresponding enum in histograms.xml. Never
- // remove values, and only insert new values at the end.
- enum DownloadOutcome {
- OUTCOME_NEW_DOODLE = 0,
- OUTCOME_REVALIDATED_DOODLE = 1,
- OUTCOME_CHANGED_DOODLE = 2,
- OUTCOME_NO_DOODLE = 3,
- OUTCOME_EXPIRED = 4,
- OUTCOME_DOWNLOAD_ERROR = 5,
- OUTCOME_PARSING_ERROR = 6,
- OUTCOME_REFRESH_INTERVAL_NOT_PASSED = 7,
- // Insert new values here!
- OUTCOME_COUNT = 8
- };
-
- static bool DownloadOutcomeIsSuccess(DownloadOutcome outcome);
- static void RecordDownloadMetrics(DownloadOutcome outcome,
- base::TimeDelta download_time);
-
- static DownloadOutcome DetermineDownloadOutcome(
- const base::Optional<DoodleConfig>& old_config,
- const base::Optional<DoodleConfig>& new_config,
- DoodleState state,
- bool expired);
-
- // Callback for the fetcher.
- void DoodleFetched(base::TimeTicks start_time,
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& doodle_config);
-
- DownloadOutcome HandleNewConfig(
- DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& doodle_config);
-
- void UpdateCachedConfig(base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& new_config);
-
- // Callback for the expiry timer.
- void DoodleExpired();
-
- void ImageFetched(const ImageCallback& callback,
- const std::string& id,
- const gfx::Image& image,
- const image_fetcher::RequestMetadata& metadata);
-
- PrefService* pref_service_;
-
- // The fetcher for getting fresh DoodleConfigs from the network.
- std::unique_ptr<DoodleFetcher> fetcher_;
-
- std::unique_ptr<base::OneShotTimer> expiry_timer_;
- std::unique_ptr<base::Clock> clock_;
- std::unique_ptr<base::TickClock> tick_clock_;
-
- // The minimum interval between server fetches. After a successful fetch,
- // refresh requests are ignored for this period.
- const base::TimeDelta min_refresh_interval_;
-
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
-
- // The result of the last network fetch.
- base::Optional<DoodleConfig> cached_config_;
-
- // The time of the most recent successful fetch.
- base::TimeTicks last_successful_fetch_;
-
- // The list of observers to be notified when the DoodleConfig changes.
- base::ObserverList<Observer> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(DoodleService);
-};
-
-} // namespace doodle
-
-#endif // COMPONENTS_DOODLE_DOODLE_SERVICE_H_
diff --git a/chromium/components/doodle/doodle_service_unittest.cc b/chromium/components/doodle/doodle_service_unittest.cc
deleted file mode 100644
index 9fb046477d7..00000000000
--- a/chromium/components/doodle/doodle_service_unittest.cc
+++ /dev/null
@@ -1,743 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/doodle_service.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/test/histogram_tester.h"
-#include "base/test/mock_callback.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/image_fetcher/core/image_fetcher.h"
-#include "components/image_fetcher/core/request_metadata.h"
-#include "components/prefs/testing_pref_service.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_unittest_util.h"
-
-using image_fetcher::ImageFetcher;
-using image_fetcher::RequestMetadata;
-using testing::_;
-using testing::Eq;
-using testing::StrictMock;
-using testing::Not;
-
-namespace doodle {
-
-namespace {
-
-class FakeDoodleFetcher : public DoodleFetcher {
- public:
- FakeDoodleFetcher() = default;
- ~FakeDoodleFetcher() override = default;
-
- void FetchDoodle(FinishedCallback callback) override {
- callbacks_.push_back(std::move(callback));
- }
-
- bool IsFetchInProgress() const override { return !callbacks_.empty(); }
-
- size_t num_pending_callbacks() const { return callbacks_.size(); }
-
- void ServeAllCallbacks(DoodleState state,
- base::TimeDelta time_to_live,
- const base::Optional<DoodleConfig>& config) {
- for (auto& callback : callbacks_) {
- std::move(callback).Run(state, time_to_live, config);
- }
- callbacks_.clear();
- }
-
- private:
- std::vector<FinishedCallback> callbacks_;
-};
-
-class MockDoodleObserver : public DoodleService::Observer {
- public:
- MOCK_METHOD1(OnDoodleConfigUpdated,
- void(const base::Optional<DoodleConfig>&));
- MOCK_METHOD1(OnDoodleConfigRevalidated, void(bool));
-};
-
-class FakeImageFetcher : public ImageFetcher {
- public:
- FakeImageFetcher() = default;
- ~FakeImageFetcher() override = default;
-
- void SetImageFetcherDelegate(image_fetcher::ImageFetcherDelegate*) override {
- NOTREACHED();
- }
-
- void SetDataUseServiceName(DataUseServiceName) override {
- // Ignored.
- }
-
- void SetImageDownloadLimit(base::Optional<int64_t>) override {
- // Ignored.
- }
-
- void SetDesiredImageFrameSize(const gfx::Size&) override {
- // Ignored.
- }
-
- void StartOrQueueNetworkRequest(
- const std::string& id,
- const GURL& url,
- const ImageFetcherCallback& callback,
- const net::NetworkTrafficAnnotationTag&) override {
- // For simplicity, the fake doesn't support multiple concurrent requests.
- DCHECK(!HasPendingRequest());
-
- pending_id_ = id;
- pending_url_ = url;
- pending_callback_ = callback;
- }
-
- image_fetcher::ImageDecoder* GetImageDecoder() override {
- NOTREACHED();
- return nullptr;
- }
-
- bool HasPendingRequest() const { return !pending_callback_.is_null(); }
-
- const GURL& pending_url() const { return pending_url_; }
-
- void RespondToPendingRequest(const gfx::Image& image) {
- DCHECK(HasPendingRequest());
-
- RequestMetadata metadata;
- metadata.http_response_code = 200;
- pending_callback_.Run(pending_id_, image, metadata);
-
- pending_id_.clear();
- pending_url_ = GURL();
- pending_callback_.Reset();
- }
-
- private:
- std::string pending_id_;
- GURL pending_url_;
- ImageFetcherCallback pending_callback_;
-};
-
-DoodleConfig CreateConfig(DoodleType type) {
- return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg")));
-}
-
-MATCHER(IsEmptyImage, "") {
- return arg.IsEmpty();
-}
-
-} // namespace
-
-class DoodleServiceTest : public testing::Test {
- public:
- DoodleServiceTest()
- : task_runner_(new base::TestMockTimeTaskRunner()),
- task_runner_handle_(task_runner_),
- tick_clock_(task_runner_->GetMockTickClock()),
- fetcher_(nullptr),
- expiry_timer_(nullptr) {
- DoodleService::RegisterProfilePrefs(pref_service_.registry());
-
- task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345));
-
- // Set the minimum refresh interval to 0 by default, so tests don't have to
- // worry about it. The tests that care set it explicitly.
- RecreateServiceWithZeroRefreshInterval();
- }
-
- void TearDown() override { DestroyService(); }
-
- void DestroyService() {
- if (image_fetcher_) {
- // Make sure we didn't receive an unexpected image request.
- ASSERT_FALSE(image_fetcher_->HasPendingRequest());
- }
-
- fetcher_ = nullptr;
- expiry_timer_ = nullptr;
- image_fetcher_ = nullptr;
-
- service_ = nullptr;
- }
-
- void RecreateServiceWithZeroRefreshInterval() {
- RecreateService(/*min_refresh_interval=*/base::TimeDelta());
- }
-
- void RecreateService(base::Optional<base::TimeDelta> refresh_interval) {
- auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get());
- expiry_timer->SetTaskRunner(task_runner_);
- expiry_timer_ = expiry_timer.get();
-
- auto fetcher = base::MakeUnique<FakeDoodleFetcher>();
- fetcher_ = fetcher.get();
-
- auto image_fetcher = base::MakeUnique<FakeImageFetcher>();
- image_fetcher_ = image_fetcher.get();
-
- service_ = base::MakeUnique<DoodleService>(
- &pref_service_, std::move(fetcher), std::move(expiry_timer),
- task_runner_->GetMockClock(), task_runner_->GetMockTickClock(),
- refresh_interval, std::move(image_fetcher));
- }
-
- DoodleService* service() { return service_.get(); }
- FakeDoodleFetcher* fetcher() { return fetcher_; }
- FakeImageFetcher* image_fetcher() { return image_fetcher_; }
-
- base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
-
- private:
- TestingPrefServiceSimple pref_service_;
-
- scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
- std::unique_ptr<base::TickClock> tick_clock_;
-
- std::unique_ptr<DoodleService> service_;
-
- // Weak, owned by the service.
- FakeDoodleFetcher* fetcher_;
- base::OneShotTimer* expiry_timer_;
- FakeImageFetcher* image_fetcher_;
-};
-
-TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) {
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Request a refresh of the doodle config.
- service()->Refresh();
- // The request should have arrived at the fetcher.
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve it (with an arbitrary config).
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
-
- // The config should be available.
- EXPECT_THAT(service()->config(), Eq(config));
-
- // Request a refresh again.
- service()->Refresh();
- // The request should have arrived at the fetcher again.
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve it with a different config.
- DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW);
- DCHECK(config != other_config);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), other_config);
-
- // The config should have been updated.
- EXPECT_THAT(service()->config(), Eq(other_config));
-}
-
-TEST_F(DoodleServiceTest, CoalescesRefreshCalls) {
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Request a refresh of the doodle config, twice.
- service()->Refresh();
- service()->Refresh();
- // Only one request should have arrived at the fetcher.
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-}
-
-TEST_F(DoodleServiceTest, PersistsConfig) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- config.large_image.url = GURL("https://doodle.com/doodle.jpg");
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Re-create the service. It should have persisted the config, and load it
- // again automatically.
- RecreateServiceWithZeroRefreshInterval();
- EXPECT_THAT(service()->config(), Eq(config));
-}
-
-TEST_F(DoodleServiceTest, FetchesOnCreationIfEmpty) {
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Since there was no cached config, the service should have sent a request.
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-}
-
-TEST_F(DoodleServiceTest, DoesNotFetchOnCreationWithCachedConfig) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- RecreateServiceWithZeroRefreshInterval();
-
- // Since there was a cached config, there should be no refresh request.
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
-}
-
-TEST_F(DoodleServiceTest, PersistsExpiryDate) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- config.large_image.url = GURL("https://doodle.com/doodle.jpg");
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Destroy the service, and let some time pass.
- DestroyService();
- task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(15));
-
- // Remove the abandoned expiry task from the task runner.
- ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
- task_runner()->ClearPendingTasks();
-
- // Re-create the service. The persisted config should have been loaded again.
- RecreateServiceWithZeroRefreshInterval();
- EXPECT_THAT(service()->config(), Eq(config));
-
- // Its time-to-live should have been updated.
- EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
- EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
- Eq(base::TimeDelta::FromMinutes(45)));
-}
-
-TEST_F(DoodleServiceTest, PersistedConfigExpires) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- config.large_image.url = GURL("https://doodle.com/doodle.jpg");
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Destroy the service, and let enough time pass so that the config expires.
- DestroyService();
- task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
-
- // Re-create the service. The persisted config should have been discarded
- // because it is expired.
- RecreateServiceWithZeroRefreshInterval();
- EXPECT_THAT(service()->config(), Eq(base::nullopt));
-}
-
-TEST_F(DoodleServiceTest, RespectsMinRefreshInterval) {
- // Create a service with the default refresh interval.
- RecreateService(/*min_refresh_interval=*/base::nullopt);
-
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- config.large_image.url = GURL("https://doodle.com/doodle.jpg");
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Let some time pass (less than the refresh interval).
- task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(10));
-
- // Request a refresh. This should get ignored.
- service()->Refresh();
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
-
- // Let more time pass, so we get past the refresh interval.
- task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(6));
-
- // Now the refresh request should be honored again.
- service()->Refresh();
- EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-}
-
-TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) {
- StrictMock<MockDoodleObserver> observer;
- service()->AddObserver(&observer);
-
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Request a refresh of the doodle config.
- service()->Refresh();
- // The request should have arrived at the fetcher.
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve it (with an arbitrary config). The observer should get notified.
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, CallsObserverOnConfigRemoved) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Register an observer and request a refresh.
- StrictMock<MockDoodleObserver> observer;
- service()->AddObserver(&observer);
- service()->Refresh();
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve the request with an empty doodle config. The observer should get
- // notified.
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
- fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
- base::nullopt);
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, CallsObserverOnConfigUpdated) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Register an observer and request a refresh.
- StrictMock<MockDoodleObserver> observer;
- service()->AddObserver(&observer);
- service()->Refresh();
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve the request with a different doodle config. The observer should get
- // notified.
- DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW);
- DCHECK(config != other_config);
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(other_config)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), other_config);
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, CallsObserverIfConfigRevalidatedByNetworkRequest) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Let some time pass (more than the refresh interval).
- task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(16));
-
- // Register an observer and request a refresh after refresh intervall passed.
- StrictMock<MockDoodleObserver> observer;
- EXPECT_CALL(observer, OnDoodleConfigRevalidated(Eq(/*from_cache=*/false)));
- service()->AddObserver(&observer);
- service()->Refresh();
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u));
-
- // Serve the request with an equivalent doodle config. The observer should
- // get notified about a (non-cached) revalidation.
- DoodleConfig equivalent_config = CreateConfig(DoodleType::SIMPLE);
- DCHECK(config == equivalent_config);
- fetcher()->ServeAllCallbacks(
- DoodleState::AVAILABLE, base::TimeDelta::FromHours(1), equivalent_config);
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, CallsObserverIfConfigRevalidatedByCache) {
- // Create a service with the default refresh interval.
- RecreateService(/*min_refresh_interval=*/base::nullopt);
-
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Register an observer and request a refresh within refresh intervall.
- StrictMock<MockDoodleObserver> observer;
- EXPECT_CALL(observer, OnDoodleConfigRevalidated(Eq(/*from_cache=*/true)));
- service()->AddObserver(&observer);
- service()->Refresh();
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, CallsObserverWhenConfigExpires) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Make sure the task arrived at the timer's task runner.
- EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
- EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
- Eq(base::TimeDelta::FromHours(1)));
-
- // Register an observer.
- StrictMock<MockDoodleObserver> observer;
- service()->AddObserver(&observer);
-
- // Fast-forward time so that the expiry task will run. The observer should get
- // notified that there's no config anymore.
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
- task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, DisregardsAlreadyExpiredConfigs) {
- StrictMock<MockDoodleObserver> observer;
- service()->AddObserver(&observer);
-
- // If there was no config and an expired config is loaded, not having a config
- // must be revalidated.
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Load an already-expired config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- EXPECT_CALL(observer, OnDoodleConfigRevalidated(Eq(/*from_cache=*/false)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromSeconds(0), config);
- EXPECT_THAT(service()->config(), Eq(base::nullopt));
-
- // Load a doodle config as usual. Nothing to see here.
- service()->Refresh();
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Now load an expired config again. The cached one should go away.
- service()->Refresh();
- EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt)));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromSeconds(0), config);
-
- // Remove the observer before the service gets destroyed.
- service()->RemoveObserver(&observer);
-}
-
-TEST_F(DoodleServiceTest, ClampsTimeToLive) {
- // Load a config with an excessive time-to-live.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromDays(100), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // The time-to-live should have been clamped to a reasonable maximum.
- ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u));
- EXPECT_THAT(task_runner()->NextPendingTaskDelay(),
- Eq(base::TimeDelta::FromDays(30)));
-}
-
-TEST_F(DoodleServiceTest, RecordsMetricsForSuccessfulDownload) {
- base::HistogramTester histograms;
-
- // Load a doodle config as usual, but let it take some time.
- service()->Refresh();
- task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Metrics should have been recorded.
- histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
- 0, // OUTCOME_NEW_DOODLE
- 1);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 1);
- histograms.ExpectTimeBucketCount("Doodle.ConfigDownloadTime",
- base::TimeDelta::FromSeconds(5), 1);
-}
-
-TEST_F(DoodleServiceTest, RecordsMetricsForEmptyDownload) {
- base::HistogramTester histograms;
-
- // Send a "no doodle" response after some time.
- service()->Refresh();
- task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
- fetcher()->ServeAllCallbacks(DoodleState::NO_DOODLE, base::TimeDelta(),
- base::nullopt);
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // Metrics should have been recorded.
- histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
- 3, // OUTCOME_NO_DOODLE
- 1);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 1);
- histograms.ExpectTimeBucketCount("Doodle.ConfigDownloadTime",
- base::TimeDelta::FromSeconds(5), 1);
-}
-
-TEST_F(DoodleServiceTest, RecordsMetricsForFailedDownload) {
- base::HistogramTester histograms;
-
- // Let the download fail after some time.
- service()->Refresh();
- task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(5));
- fetcher()->ServeAllCallbacks(DoodleState::DOWNLOAD_ERROR, base::TimeDelta(),
- base::nullopt);
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // The outcome should have been recorded, but not the time - we only record
- // that for successful downloads.
- histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
- 5, // OUTCOME_DOWNLOAD_ERROR
- 1);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
-}
-
-TEST_F(DoodleServiceTest, RecordsMetricsForEarlyRefreshRequest) {
- // Create a service with some refresh interval.
- RecreateService(/*min_refresh_interval=*/base::TimeDelta::FromMinutes(10));
-
- // Load a doodle config as usual.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- base::HistogramTester histograms;
-
- // Request a refresh before the min refresh interval has passed.
- task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(5));
- service()->Refresh();
-
- // This should not have resulted in a request.
- ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(0u));
-
- // The outcome should still have been recorded, but not the time - we only
- // record that for successful downloads.
- histograms.ExpectUniqueSample("Doodle.ConfigDownloadOutcome",
- 7, // OUTCOME_REFRESH_INTERVAL_NOT_PASSED
- 1);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
-}
-
-TEST_F(DoodleServiceTest, DoesNotRecordMetricsAtStartup) {
- // Creating the service should not emit any histogram samples.
- base::HistogramTester histograms;
- RecreateServiceWithZeroRefreshInterval();
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
- histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
-}
-
-TEST_F(DoodleServiceTest, DoesNotRecordMetricsAtStartupWithConfig) {
- // Load a doodle config as usual.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- // Recreating the service should not emit any histogram samples, even though
- // a config gets loaded.
- base::HistogramTester histograms;
- RecreateServiceWithZeroRefreshInterval();
- ASSERT_THAT(service()->config(), Eq(config));
- histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
-}
-
-TEST_F(DoodleServiceTest, DoesNotRecordMetricsWhenConfigExpires) {
- // Load some doodle config.
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- base::HistogramTester histograms;
-
- // Fast-forward time so that the config expires.
- task_runner()->FastForwardBy(base::TimeDelta::FromHours(1));
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- // This should not have resulted in any metrics being emitted.
- histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0);
- histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
-}
-
-TEST_F(DoodleServiceTest, GetImageWithEmptyConfigReturnsImmediately) {
- ASSERT_THAT(service()->config(), Eq(base::nullopt));
-
- base::MockCallback<DoodleService::ImageCallback> callback;
- EXPECT_CALL(callback, Run(IsEmptyImage()));
-
- service()->GetImage(callback.Get());
-}
-
-TEST_F(DoodleServiceTest, GetImageFetchesLargeImage) {
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- base::MockCallback<DoodleService::ImageCallback> callback;
- service()->GetImage(callback.Get());
-
- EXPECT_EQ(config.large_image.url, image_fetcher()->pending_url());
-
- EXPECT_CALL(callback, Run(Not(IsEmptyImage())));
- gfx::Image image = gfx::test::CreateImage(1, 1);
- ASSERT_TRUE(image_fetcher()->HasPendingRequest());
- image_fetcher()->RespondToPendingRequest(image);
-}
-
-TEST_F(DoodleServiceTest, GetImageFetchesCTAImage) {
- service()->Refresh();
- DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
- // Set a CTA image, which should take precedence over the regular image.
- config.large_cta_image = DoodleImage(GURL("https://doodle.com/cta.jpg"));
- fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
- base::TimeDelta::FromHours(1), config);
- ASSERT_THAT(service()->config(), Eq(config));
-
- base::MockCallback<DoodleService::ImageCallback> callback;
- service()->GetImage(callback.Get());
-
- // If the doodle has a CTA image, that should loaded instead of the regular
- // large image.
- EXPECT_EQ(config.large_cta_image->url, image_fetcher()->pending_url());
-
- EXPECT_CALL(callback, Run(Not(IsEmptyImage())));
- gfx::Image image = gfx::test::CreateImage(1, 1);
- ASSERT_TRUE(image_fetcher()->HasPendingRequest());
- image_fetcher()->RespondToPendingRequest(image);
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/doodle_types.cc b/chromium/components/doodle/doodle_types.cc
deleted file mode 100644
index b438145b483..00000000000
--- a/chromium/components/doodle/doodle_types.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/doodle_types.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/values.h"
-
-namespace doodle {
-
-namespace {
-
-// String representations for the DoodleType enum.
-const char kDoodleTypeUnknown[] = "UNKNOWN";
-const char kDoodleTypeSimple[] = "SIMPLE";
-const char kDoodleTypeRandom[] = "RANDOM";
-const char kDoodleTypeVideo[] = "VIDEO";
-const char kDoodleTypeInteractive[] = "INTERACTIVE";
-const char kDoodleTypeInlineInteractive[] = "INLINE_INTERACTIVE";
-const char kDoodleTypeSlideshow[] = "SLIDESHOW";
-
-// JSON keys for DoodleImage fields.
-const char kKeyUrl[] = "url";
-
-// JSON keys for DoodleConfig fields.
-const char kKeyDoodleType[] = "doodle_type";
-const char kKeyAltText[] = "alt_text";
-const char kKeyTargetUrl[] = "target_url";
-const char kKeyLargeImage[] = "large_image";
-const char kKeyLargeCtaImage[] = "large_cta_image";
-
-std::string DoodleTypeToString(DoodleType type) {
- switch (type) {
- case DoodleType::UNKNOWN:
- return kDoodleTypeUnknown;
- case DoodleType::SIMPLE:
- return kDoodleTypeSimple;
- case DoodleType::RANDOM:
- return kDoodleTypeRandom;
- case DoodleType::VIDEO:
- return kDoodleTypeVideo;
- case DoodleType::INTERACTIVE:
- return kDoodleTypeInteractive;
- case DoodleType::INLINE_INTERACTIVE:
- return kDoodleTypeInlineInteractive;
- case DoodleType::SLIDESHOW:
- return kDoodleTypeSlideshow;
- }
- NOTREACHED();
- return std::string();
-}
-
-DoodleType DoodleTypeFromString(const std::string& type_str) {
- if (type_str == kDoodleTypeSimple) {
- return DoodleType::SIMPLE;
- }
- if (type_str == kDoodleTypeRandom) {
- return DoodleType::RANDOM;
- }
- if (type_str == kDoodleTypeVideo) {
- return DoodleType::VIDEO;
- }
- if (type_str == kDoodleTypeInteractive) {
- return DoodleType::INTERACTIVE;
- }
- if (type_str == kDoodleTypeInlineInteractive) {
- return DoodleType::INLINE_INTERACTIVE;
- }
- if (type_str == kDoodleTypeSlideshow) {
- return DoodleType::SLIDESHOW;
- }
- return DoodleType::UNKNOWN;
-}
-
-GURL ResolvePossiblyRelativeUrl(const std::string& url_str,
- const base::Optional<GURL>& base_url) {
- if (!base_url.has_value()) {
- return GURL(url_str);
- }
- return base_url->Resolve(url_str);
-}
-
-GURL ParseUrl(const base::DictionaryValue& parent_dict,
- const std::string& key,
- const base::Optional<GURL>& base_url) {
- std::string url_str;
- if (!parent_dict.GetString(key, &url_str) || url_str.empty()) {
- return GURL();
- }
- return ResolvePossiblyRelativeUrl(url_str, base_url);
-}
-
-base::Optional<DoodleImage> ParseImage(const base::DictionaryValue& parent_dict,
- const std::string& key,
- const base::Optional<GURL>& base_url) {
- const base::DictionaryValue* image_dict = nullptr;
- if (!parent_dict.GetDictionary(key, &image_dict)) {
- return base::nullopt;
- }
- return DoodleImage::FromDictionary(*image_dict, base_url);
-}
-
-} // namespace
-
-// static
-base::Optional<DoodleImage> DoodleImage::FromDictionary(
- const base::DictionaryValue& dict,
- const base::Optional<GURL>& base_url) {
- // The URL is the only required field.
- GURL url = ParseUrl(dict, kKeyUrl, base_url);
- if (!url.is_valid()) {
- return base::nullopt;
- }
-
- return DoodleImage(url);
-}
-
-DoodleImage::DoodleImage(const GURL& url) : url(url) {
- DCHECK(url.is_valid());
-}
-
-DoodleImage::~DoodleImage() = default;
-
-std::unique_ptr<base::DictionaryValue> DoodleImage::ToDictionary() const {
- auto dict = base::MakeUnique<base::DictionaryValue>();
- dict->SetString(kKeyUrl, url.spec());
- return dict;
-}
-
-bool DoodleImage::operator==(const DoodleImage& other) const {
- return url == other.url;
-}
-
-bool DoodleImage::operator!=(const DoodleImage& other) const {
- return !(*this == other);
-}
-
-DoodleConfig::DoodleConfig(DoodleType doodle_type,
- const DoodleImage& large_image)
- : doodle_type(doodle_type), large_image(large_image) {}
-DoodleConfig::DoodleConfig(const DoodleConfig& config) = default;
-DoodleConfig::~DoodleConfig() = default;
-
-// static
-base::Optional<DoodleConfig> DoodleConfig::FromDictionary(
- const base::DictionaryValue& dict,
- const base::Optional<GURL>& base_url) {
- // The |large_image| field is required (it's the "default" representation for
- // the doodle).
- base::Optional<DoodleImage> large_image =
- ParseImage(dict, kKeyLargeImage, base_url);
- if (!large_image.has_value()) {
- return base::nullopt;
- }
-
- std::string type_str;
- dict.GetString(kKeyDoodleType, &type_str);
-
- DoodleConfig doodle(DoodleTypeFromString(type_str), large_image.value());
-
- dict.GetString(kKeyAltText, &doodle.alt_text);
-
- doodle.target_url = ParseUrl(dict, kKeyTargetUrl, base_url);
-
- doodle.large_cta_image = ParseImage(dict, kKeyLargeCtaImage, base_url);
-
- return doodle;
-}
-
-std::unique_ptr<base::DictionaryValue> DoodleConfig::ToDictionary() const {
- auto dict = base::MakeUnique<base::DictionaryValue>();
- dict->SetString(kKeyDoodleType, DoodleTypeToString(doodle_type));
- dict->SetString(kKeyAltText, alt_text);
- dict->SetString(kKeyTargetUrl, target_url.spec());
- dict->Set(kKeyLargeImage, large_image.ToDictionary());
- if (large_cta_image.has_value()) {
- dict->Set(kKeyLargeCtaImage, large_cta_image->ToDictionary());
- }
- return dict;
-}
-
-bool DoodleConfig::operator==(const DoodleConfig& other) const {
- return doodle_type == other.doodle_type && alt_text == other.alt_text &&
- large_image == other.large_image &&
- large_cta_image == other.large_cta_image;
-}
-
-bool DoodleConfig::operator!=(const DoodleConfig& other) const {
- return !(*this == other);
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/doodle_types.h b/chromium/components/doodle/doodle_types.h
deleted file mode 100644
index ecc7214923c..00000000000
--- a/chromium/components/doodle/doodle_types.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOODLE_DOODLE_TYPES_H_
-#define COMPONENTS_DOODLE_DOODLE_TYPES_H_
-
-#include <memory>
-#include <string>
-
-#include "base/optional.h"
-#include "url/gurl.h"
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace doodle {
-
-enum class DoodleState {
- AVAILABLE,
- NO_DOODLE,
- DOWNLOAD_ERROR,
- PARSING_ERROR,
-};
-
-enum class DoodleType {
- UNKNOWN,
- SIMPLE,
- RANDOM,
- VIDEO,
- INTERACTIVE,
- INLINE_INTERACTIVE,
- SLIDESHOW,
-};
-
-// Information about a Doodle image.
-struct DoodleImage {
- DoodleImage(const GURL& url);
- ~DoodleImage();
-
- static base::Optional<DoodleImage> FromDictionary(
- const base::DictionaryValue& dict,
- const base::Optional<GURL>& base_url);
-
- std::unique_ptr<base::DictionaryValue> ToDictionary() const;
-
- bool operator==(const DoodleImage& other) const;
- bool operator!=(const DoodleImage& other) const;
-
- GURL url;
-
- // Copying and assignment allowed.
-};
-
-// All information about a current doodle that can be fetched from the remote
-// end. By default, all URLs are empty and therefore invalid.
-struct DoodleConfig {
- DoodleConfig(DoodleType doodle_type, const DoodleImage& large_image);
- DoodleConfig(const DoodleConfig& config); // = default;
- ~DoodleConfig();
-
- static base::Optional<DoodleConfig> FromDictionary(
- const base::DictionaryValue& dict,
- const base::Optional<GURL>& base_url);
-
- std::unique_ptr<base::DictionaryValue> ToDictionary() const;
-
- bool operator==(const DoodleConfig& other) const;
- bool operator!=(const DoodleConfig& other) const;
-
- DoodleType doodle_type;
- std::string alt_text;
-
- GURL target_url;
-
- DoodleImage large_image;
- base::Optional<DoodleImage> large_cta_image;
-
- // Copying and assignment allowed.
-};
-
-} // namespace doodle
-
-#endif // COMPONENTS_DOODLE_DOODLE_TYPES_H_
diff --git a/chromium/components/doodle/doodle_types_unittest.cc b/chromium/components/doodle/doodle_types_unittest.cc
deleted file mode 100644
index 5b04c95c8eb..00000000000
--- a/chromium/components/doodle/doodle_types_unittest.cc
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/doodle_types.h"
-
-#include <memory>
-#include <string>
-
-#include "base/json/json_reader.h"
-#include "base/optional.h"
-#include "base/values.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using testing::Eq;
-
-namespace doodle {
-
-namespace {
-
-// Parses the given |json| string into a base::DictionaryValue and creates a
-// DoodleImage out of that. |json| must be a valid json string.
-base::Optional<DoodleImage> DoodleImageFromJson(
- const std::string& json,
- const base::Optional<GURL>& base_url) {
- std::unique_ptr<base::DictionaryValue> value =
- base::DictionaryValue::From(base::JSONReader::Read(json));
- DCHECK(value);
- return DoodleImage::FromDictionary(*value, base_url);
-}
-
-// Parses the given |json| string into a base::DictionaryValue and creates a
-// DoodleConfig out of that. |json| must be a valid json string.
-base::Optional<DoodleConfig> DoodleConfigFromJson(
- const std::string& json,
- const base::Optional<GURL>& base_url) {
- std::unique_ptr<base::DictionaryValue> value =
- base::DictionaryValue::From(base::JSONReader::Read(json));
- DCHECK(value);
- return DoodleConfig::FromDictionary(*value, base_url);
-}
-
-} // namespace
-
-TEST(DoodleImageTest, ParsesImage) {
- std::string json = R"json({
- "url":"https://www.doodle.com/doodle"
- })json";
- base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
- ASSERT_TRUE(image.has_value());
- EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/doodle")));
-}
-
-TEST(DoodleImageTest, ResolvesRelativeUrl) {
- std::string json = R"json({
- "url":"/the_doodle_path"
- })json";
- base::Optional<DoodleImage> image =
- DoodleImageFromJson(json, GURL("https://doodle.dood/"));
- ASSERT_TRUE(image.has_value());
- EXPECT_THAT(image->url, Eq(GURL("https://doodle.dood/the_doodle_path")));
-}
-
-TEST(DoodleImageTest, DoesNotResolveAbsoluteUrl) {
- std::string json = R"json({
- "url":"https://www.doodle.com/the_doodle_path"
- })json";
- base::Optional<DoodleImage> image =
- DoodleImageFromJson(json, GURL("https://other.com/"));
- ASSERT_TRUE(image.has_value());
- EXPECT_THAT(image->url, Eq(GURL("https://www.doodle.com/the_doodle_path")));
-}
-
-TEST(DoodleImageTest, RequiresUrl) {
- std::string json = R"json({
- "height":100,
- "width":50
- })json";
- base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
- EXPECT_FALSE(image.has_value());
-}
-
-TEST(DoodleImageTest, HandlesInvalidUrl) {
- std::string json = R"json({
- "url":"not_a_url"
- })json";
- base::Optional<DoodleImage> image = DoodleImageFromJson(json, base::nullopt);
- // The URL is required, and invalid should be treated like missing.
- EXPECT_FALSE(image.has_value());
-}
-
-TEST(DoodleImageTest, PreservesFieldsOverRoundtrip) {
- // Set all fields to non-default values.
- DoodleImage image(GURL("https://www.doodle.com/doodle"));
-
- // Convert to a dictionary and back.
- base::Optional<DoodleImage> after_roundtrip =
- DoodleImage::FromDictionary(*image.ToDictionary(), base::nullopt);
-
- // Make sure everything survived.
- ASSERT_TRUE(after_roundtrip.has_value());
- EXPECT_THAT(*after_roundtrip, Eq(image));
-}
-
-TEST(DoodleConfigTest, ParsesMinimalConfig) {
- std::string json = R"json({
- "large_image":{"url":"https://doodle.com/img.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, base::nullopt);
- ASSERT_TRUE(config.has_value());
- EXPECT_THAT(config->doodle_type, Eq(DoodleType::UNKNOWN));
- EXPECT_THAT(config->alt_text, Eq(std::string()));
- EXPECT_THAT(config->target_url, Eq(GURL()));
- EXPECT_FALSE(config->large_cta_image.has_value());
-}
-
-TEST(DoodleConfigTest, ParsesFullConfig) {
- std::string json = R"json({
- "doodle_type":"SLIDESHOW",
- "alt_text":"some text",
- "target_url":"https://doodle.com/target",
- "large_image":{"url":"https://doodle.com/img.jpg"},
- "large_cta_image":{"url":"https://doodle.com/cta.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, base::nullopt);
- ASSERT_TRUE(config.has_value());
- EXPECT_THAT(config->doodle_type, Eq(DoodleType::SLIDESHOW));
- EXPECT_THAT(config->alt_text, Eq("some text"));
- EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
- EXPECT_THAT(config->large_image.url, Eq(GURL("https://doodle.com/img.jpg")));
- ASSERT_TRUE(config->large_cta_image.has_value());
- EXPECT_THAT(config->large_cta_image->url,
- Eq(GURL("https://doodle.com/cta.jpg")));
-}
-
-TEST(DoodleConfigTest, RequiresLargeImage) {
- std::string json = R"json({
- "doodle_type":"SLIDESHOW",
- "alt_text":"some text",
- "target_url":"https://doodle.com/target",
- "large_cta_image":{"url":"https://doodle.com/cta.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, base::nullopt);
- EXPECT_FALSE(config.has_value());
-}
-
-TEST(DoodleConfigTest, RequiresValidLargeImage) {
- std::string json = R"json({
- "doodle_type":"SLIDESHOW",
- "alt_text":"some text",
- "target_url":"https://doodle.com/target",
- "large_image":{"no_url":"asdf"},
- "large_cta_image":{"url":"https://doodle.com/cta.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, base::nullopt);
- EXPECT_FALSE(config.has_value());
-}
-
-TEST(DoodleConfigTest, ResolvesRelativeUrls) {
- std::string json = R"json({
- "target_url":"/target",
- "large_image":{"url":"/large.jpg"},
- "large_cta_image":{"url":"/cta.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, GURL("https://doodle.com/"));
- ASSERT_TRUE(config.has_value());
- EXPECT_THAT(config->target_url, Eq(GURL("https://doodle.com/target")));
- EXPECT_THAT(config->large_image.url,
- Eq(GURL("https://doodle.com/large.jpg")));
- ASSERT_TRUE(config->large_cta_image.has_value());
- EXPECT_THAT(config->large_cta_image->url,
- Eq(GURL("https://doodle.com/cta.jpg")));
-}
-
-TEST(DoodleConfigTest, HandlesInvalidUrls) {
- std::string json = R"json({
- "target_url":"not_a_url",
- "large_image":{"url":"https://doodle.com/img.jpg"}
- })json";
- base::Optional<DoodleConfig> config =
- DoodleConfigFromJson(json, base::nullopt);
- // All the URLs are optional, so invalid ones shouldn't matter.
- ASSERT_TRUE(config.has_value());
- EXPECT_TRUE(config->target_url.is_empty());
-}
-
-TEST(DoodleConfigTest, PreservesFieldsOverRoundtrip) {
- // Set all fields to non-default values.
- DoodleConfig config(DoodleType::SLIDESHOW,
- DoodleImage(GURL("https://www.doodle.com/img.jpg")));
- config.alt_text = "some text";
- config.target_url = GURL("https://doodle.com/target");
- config.large_cta_image = DoodleImage(GURL("https://www.doodle.com/cta.jpg"));
-
- // Convert to a dictionary and back.
- // Note: The different |base_url| should make no difference, since all
- // persisted URLs are absolute already.
- base::Optional<DoodleConfig> after_roundtrip = DoodleConfig::FromDictionary(
- *config.ToDictionary(), GURL("https://other.com"));
-
- // Make sure everything survived.
- ASSERT_TRUE(after_roundtrip.has_value());
- EXPECT_THAT(*after_roundtrip, Eq(config));
-}
-
-} // namespace doodle
diff --git a/chromium/components/doodle/pref_names.cc b/chromium/components/doodle/pref_names.cc
deleted file mode 100644
index 17ff266090e..00000000000
--- a/chromium/components/doodle/pref_names.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/doodle/pref_names.h"
-
-namespace doodle {
-namespace prefs {
-
-const char kCachedConfig[] = "doodle.cached_config";
-const char kCachedConfigExpiry[] = "doodle.cached_config_expiry";
-
-} // namespace prefs
-} // namespace doodle
diff --git a/chromium/components/doodle/pref_names.h b/chromium/components/doodle/pref_names.h
deleted file mode 100644
index 20d7b061a1a..00000000000
--- a/chromium/components/doodle/pref_names.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOODLE_PREF_NAMES_H_
-#define COMPONENTS_DOODLE_PREF_NAMES_H_
-
-namespace doodle {
-namespace prefs {
-
-extern const char kCachedConfig[];
-extern const char kCachedConfigExpiry[];
-
-} // namespace prefs
-} // namespace doodle
-
-#endif // COMPONENTS_DOODLE_PREF_NAMES_H_
diff --git a/chromium/components/download/BUILD.gn b/chromium/components/download/BUILD.gn
index 441c1be542d..2bd5bb61e9a 100644
--- a/chromium/components/download/BUILD.gn
+++ b/chromium/components/download/BUILD.gn
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# TODO(dtrainor): Remove this file and have components_unittests depend on
-# //components/download/internal:unit_tests directly.
group("unit_tests") {
testonly = true
@@ -11,6 +9,13 @@ group("unit_tests") {
"//components/download/internal:unit_tests",
]
+ if (!is_ios) {
+ deps += [
+ "//components/download/content/internal:unit_tests",
+ "//components/download/content/public:unit_tests",
+ ]
+ }
+
data_deps = [
":components_unittests_gtest_filter",
]
diff --git a/chromium/components/download/OWNERS b/chromium/components/download/OWNERS
index 866d43d7f42..67edbd16bec 100644
--- a/chromium/components/download/OWNERS
+++ b/chromium/components/download/OWNERS
@@ -3,4 +3,4 @@ qinmin@chromium.org
shaktisahu@chromium.org
xingliu@chromium.org
-# COMPONENT: UI>Browser>Downloads \ No newline at end of file
+# COMPONENT: UI>Browser>Downloads
diff --git a/chromium/components/download/content/BUILD.gn b/chromium/components/download/content/BUILD.gn
deleted file mode 100644
index 049294f31a1..00000000000
--- a/chromium/components/download/content/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(dtrainor): Remove this file and have components_unittests depend on
-# //components/download/content/internal:unit_tests directly.
-group("unit_tests") {
- testonly = true
-
- deps = [
- "//components/download/content/internal:unit_tests",
- "//components/download/content/public:unit_tests",
- ]
-}
diff --git a/chromium/components/download/content/internal/download_driver_impl.cc b/chromium/components/download/content/internal/download_driver_impl.cc
index 99686e18454..6197972404e 100644
--- a/chromium/components/download/content/internal/download_driver_impl.cc
+++ b/chromium/components/download/content/internal/download_driver_impl.cc
@@ -268,7 +268,6 @@ void DownloadDriverImpl::OnManagerInitialized(
void DownloadDriverImpl::OnManagerGoingDown(content::DownloadManager* manager) {
DCHECK_EQ(download_manager_, manager);
- notifier_.reset();
download_manager_ = nullptr;
}
diff --git a/chromium/components/download/internal/BUILD.gn b/chromium/components/download/internal/BUILD.gn
index f138251c6fc..04f100c9be2 100644
--- a/chromium/components/download/internal/BUILD.gn
+++ b/chromium/components/download/internal/BUILD.gn
@@ -46,6 +46,8 @@ static_library("internal") {
"scheduler/device_status.h",
"scheduler/device_status_listener.cc",
"scheduler/device_status_listener.h",
+ "scheduler/network_status_listener.cc",
+ "scheduler/network_status_listener.h",
"scheduler/scheduler.h",
"scheduler/scheduler_impl.cc",
"scheduler/scheduler_impl.h",
@@ -65,6 +67,34 @@ static_library("internal") {
"//components/leveldb_proto",
"//net",
]
+
+ if (is_android) {
+ sources += [
+ "android/network_status_listener_android.cc",
+ "android/network_status_listener_android.h",
+ ]
+
+ deps += [ ":jni_headers" ]
+ }
+}
+
+if (is_android) {
+ android_library("internal_java") {
+ java_files = [ "android/java/src/org/chromium/components/download/internal/NetworkStatusListenerAndroid.java" ]
+
+ deps = [
+ "//base:base_java",
+ "//net/android:net_java",
+ ]
+ }
+
+ generate_jni("jni_headers") {
+ visibility = [ ":*" ]
+ sources = [
+ "android/java/src/org/chromium/components/download/internal/NetworkStatusListenerAndroid.java",
+ ]
+ jni_package = "components/download/internal"
+ }
}
source_set("unit_tests") {
@@ -90,6 +120,7 @@ source_set("unit_tests") {
"//components/download/internal/proto",
"//components/download/internal/test:test_support",
"//components/leveldb_proto:test_support",
+ "//net:test_support",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/download/internal/DEPS b/chromium/components/download/internal/DEPS
index 6a99578f611..85b754e1898 100644
--- a/chromium/components/download/internal/DEPS
+++ b/chromium/components/download/internal/DEPS
@@ -3,5 +3,6 @@ include_rules = [
"-content",
"+components/leveldb_proto",
"+base",
+ "+jni",
"+net",
]
diff --git a/chromium/components/download/internal/android/network_status_listener_android.cc b/chromium/components/download/internal/android/network_status_listener_android.cc
new file mode 100644
index 00000000000..e33d181dfb3
--- /dev/null
+++ b/chromium/components/download/internal/android/network_status_listener_android.cc
@@ -0,0 +1,51 @@
+// 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/download/internal/android/network_status_listener_android.h"
+
+#include "base/android/jni_android.h"
+#include "jni/NetworkStatusListenerAndroid_jni.h"
+
+namespace download {
+
+NetworkStatusListenerAndroid::NetworkStatusListenerAndroid() = default;
+
+NetworkStatusListenerAndroid::~NetworkStatusListenerAndroid() = default;
+
+void NetworkStatusListenerAndroid::NotifyNetworkChange(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ jint connectionType) {
+ DCHECK(observer_);
+ using ConnectionType = net::NetworkChangeNotifier::ConnectionType;
+ ConnectionType connection_type = static_cast<ConnectionType>(connectionType);
+ observer_->OnConnectionTypeChanged(connection_type);
+}
+
+void NetworkStatusListenerAndroid::Start(
+ NetworkStatusListener::Observer* observer) {
+ NetworkStatusListener::Start(observer);
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ java_obj_.Reset(env, Java_NetworkStatusListenerAndroid_create(
+ env, reinterpret_cast<intptr_t>(this))
+ .obj());
+}
+
+void NetworkStatusListenerAndroid::Stop() {
+ NetworkStatusListener::Stop();
+ Java_NetworkStatusListenerAndroid_clearNativePtr(
+ base::android::AttachCurrentThread(), java_obj_);
+}
+
+net::NetworkChangeNotifier::ConnectionType
+NetworkStatusListenerAndroid::GetConnectionType() {
+ int connection_type =
+ Java_NetworkStatusListenerAndroid_getCurrentConnectionType(
+ base::android::AttachCurrentThread(), java_obj_);
+ return static_cast<net::NetworkChangeNotifier::ConnectionType>(
+ connection_type);
+}
+
+} // namespace download
diff --git a/chromium/components/download/internal/android/network_status_listener_android.h b/chromium/components/download/internal/android/network_status_listener_android.h
new file mode 100644
index 00000000000..13bda6618b2
--- /dev/null
+++ b/chromium/components/download/internal/android/network_status_listener_android.h
@@ -0,0 +1,43 @@
+// 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_DOWNLOAD_INTERNAL_ANDROID_NETWORK_STATUS_LISTENER_ANDROID_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_ANDROID_NETWORK_STATUS_LISTENER_ANDROID_H_
+
+#include "components/download/internal/scheduler/network_status_listener.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+namespace download {
+
+// Android implementation of NetworkStatusListener.
+// Backed by a Java class that can notify network change even when the app is
+// in the background.
+// The default implementation with net::NetworkChangeNotifier will NOT
+// immediately notify changes when the app is in the background.
+class NetworkStatusListenerAndroid : public NetworkStatusListener {
+ public:
+ NetworkStatusListenerAndroid();
+ ~NetworkStatusListenerAndroid() override;
+
+ // NetworkStatusListener implementation.
+ void Start(NetworkStatusListener::Observer* observer) override;
+ void Stop() override;
+ net::NetworkChangeNotifier::ConnectionType GetConnectionType() override;
+
+ void NotifyNetworkChange(JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ jint connectionType);
+
+ private:
+ // The Java side object owned by this class.
+ base::android::ScopedJavaGlobalRef<jobject> java_obj_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkStatusListenerAndroid);
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_INTERNAL_ANDROID_NETWORK_STATUS_LISTENER_ANDROID_H_
diff --git a/chromium/components/download/internal/config.cc b/chromium/components/download/internal/config.cc
index 02bcfdde4ef..9e667bac725 100644
--- a/chromium/components/download/internal/config.cc
+++ b/chromium/components/download/internal/config.cc
@@ -27,13 +27,18 @@ const uint32_t kDefaultMaxScheduledDownloads = 15;
// Default value for maximum retry count.
const uint32_t kDefaultMaxRetryCount = 5;
-// Default value for file keep alive time in minutes, keep the file alive for
-// 12 hours by default.
+// Default value for file keep alive time, keep the file alive for 12 hours by
+// default.
const base::TimeDelta kDefaultFileKeepAliveTime =
base::TimeDelta::FromHours(12);
-// Default value for file cleanup window in minutes, the system will schedule a
-// cleanup task within this window.
+// Default value for maximum duration that the file can be kept alive time,
+// default is 7 days.
+const base::TimeDelta kDefaultMaxFileKeepAliveTime =
+ base::TimeDelta::FromDays(7);
+
+// Default value for file cleanup window, the system will schedule a cleanup
+// task within this window.
const base::TimeDelta kDefaultFileCleanupWindow =
base::TimeDelta::FromHours(24);
@@ -79,6 +84,10 @@ std::unique_ptr<Configuration> Configuration::CreateFromFinch() {
base::TimeDelta::FromMinutes(base::saturated_cast<int>(
GetFinchConfigUInt(kFileKeepAliveTimeMinutesConfig,
kDefaultFileKeepAliveTime.InMinutes())));
+ config->max_file_keep_alive_time =
+ base::TimeDelta::FromMinutes(base::saturated_cast<int>(
+ GetFinchConfigUInt(kMaxFileKeepAliveTimeMinutesConfig,
+ kDefaultMaxFileKeepAliveTime.InMinutes())));
config->file_cleanup_window =
base::TimeDelta::FromMinutes(base::saturated_cast<int>(
GetFinchConfigUInt(kFileCleanupWindowMinutesConfig,
@@ -106,6 +115,7 @@ Configuration::Configuration()
max_scheduled_downloads(kDefaultMaxScheduledDownloads),
max_retry_count(kDefaultMaxRetryCount),
file_keep_alive_time(kDefaultFileKeepAliveTime),
+ max_file_keep_alive_time(kDefaultMaxFileKeepAliveTime),
file_cleanup_window(kDefaultFileCleanupWindow),
window_start_time(kDefaultWindowStartTime),
window_end_time(kDefaultWindowEndTime),
diff --git a/chromium/components/download/internal/config.h b/chromium/components/download/internal/config.h
index 073676fcc38..9b31a9ce82a 100644
--- a/chromium/components/download/internal/config.h
+++ b/chromium/components/download/internal/config.h
@@ -25,7 +25,12 @@ constexpr char kMaxScheduledDownloadsConfig[] = "max_scheduled_downloads";
constexpr char kMaxRetryCountConfig[] = "max_retry_count";
// Configuration name for file keep alive time.
-constexpr char kFileKeepAliveTimeMinutesConfig[] = "file_keep_alive_time";
+constexpr char kFileKeepAliveTimeMinutesConfig[] =
+ "file_keep_alive_time_minutes";
+
+// Configuration name for maximum duration that the file can be kept alive.
+constexpr char kMaxFileKeepAliveTimeMinutesConfig[] =
+ "max_file_keep_alive_time_minutes";
// Configuration name for file keep alive time.
constexpr char kFileCleanupWindowMinutesConfig[] = "file_cleanup_window";
@@ -73,6 +78,10 @@ struct Configuration {
// deleting them if the client hasn't handle the files.
base::TimeDelta file_keep_alive_time;
+ // The maximum time that the download service can keep the files around before
+ // forcefully deleting them even if the client doesn't agree.
+ base::TimeDelta max_file_keep_alive_time;
+
// The length of the flexible time window during which the scheduler must
// schedule a file cleanup task.
base::TimeDelta file_cleanup_window;
diff --git a/chromium/components/download/internal/controller_impl.cc b/chromium/components/download/internal/controller_impl.cc
index 03fa70c46ec..89973a77082 100644
--- a/chromium/components/download/internal/controller_impl.cc
+++ b/chromium/components/download/internal/controller_impl.cc
@@ -20,6 +20,7 @@
#include "components/download/internal/scheduler/scheduler.h"
#include "components/download/internal/stats.h"
#include "components/download/public/client.h"
+#include "components/download/public/download_metadata.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace download {
@@ -143,8 +144,8 @@ void ControllerImpl::StartDownload(const DownloadParams& params) {
return;
}
- uint32_t client_count =
- util::GetNumberOfEntriesForClient(params.client, model_->PeekEntries());
+ uint32_t client_count = util::GetNumberOfLiveEntriesForClient(
+ params.client, model_->PeekEntries());
if (client_count >= config_->max_scheduled_downloads) {
HandleStartDownloadResponse(params.client, params.guid,
DownloadParams::StartResult::BACKOFF,
@@ -290,10 +291,39 @@ void ControllerImpl::OnCompleteCleanupTask() {
}
void ControllerImpl::RemoveCleanupEligibleDownloads() {
- auto timed_out_entries = file_monitor_->CleanupFilesForCompletedEntries(
- model_->PeekEntries(), base::Bind(&ControllerImpl::OnCompleteCleanupTask,
- weak_ptr_factory_.GetWeakPtr()));
- for (auto* entry : timed_out_entries) {
+ std::vector<Entry*> entries_to_remove;
+ for (auto* entry : model_->PeekEntries()) {
+ if (entry->state != Entry::State::COMPLETE)
+ continue;
+
+ bool optional_cleanup =
+ base::Time::Now() >
+ (entry->last_cleanup_check_time + config_->file_keep_alive_time);
+ bool mandatory_cleanup =
+ base::Time::Now() >
+ (entry->completion_time + config_->max_file_keep_alive_time);
+
+ if (!optional_cleanup && !mandatory_cleanup)
+ continue;
+
+ download::Client* client = clients_->GetClient(entry->client);
+ DCHECK(client);
+ bool client_ok =
+ client->CanServiceRemoveDownloadedFile(entry->guid, mandatory_cleanup);
+ entry->cleanup_attempt_count++;
+
+ if (client_ok || mandatory_cleanup) {
+ entries_to_remove.push_back(entry);
+ } else {
+ entry->last_cleanup_check_time = base::Time::Now();
+ }
+ }
+
+ file_monitor_->CleanupFilesForCompletedEntries(
+ entries_to_remove, base::Bind(&ControllerImpl::OnCompleteCleanupTask,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ for (auto* entry : entries_to_remove) {
DCHECK_EQ(Entry::State::COMPLETE, entry->state);
model_->Remove(entry->guid);
}
@@ -775,16 +805,16 @@ void ControllerImpl::UpdateDriverState(Entry* entry) {
if (driver_entry.has_value()) {
driver_->Resume(entry->guid);
} else {
- driver_->Start(entry->request_params, entry->guid,
- entry->target_file_path, NO_TRAFFIC_ANNOTATION_YET);
+ driver_->Start(
+ entry->request_params, entry->guid, entry->target_file_path,
+ net::NetworkTrafficAnnotationTag(entry->traffic_annotation));
}
}
}
void ControllerImpl::NotifyClientsOfStartup(bool state_lost) {
- std::set<Entry::State> ignored_states = {Entry::State::COMPLETE};
- auto categorized = util::MapEntriesToClients(
- clients_->GetRegisteredClients(), model_->PeekEntries(), ignored_states);
+ auto categorized = util::MapEntriesToMetadataForClients(
+ clients_->GetRegisteredClients(), model_->PeekEntries());
for (auto client_id : clients_->GetRegisteredClients()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -845,21 +875,22 @@ void ControllerImpl::HandleCompleteDownload(CompletionType type,
auto driver_entry = driver_->Find(guid);
uint64_t file_size =
driver_entry.has_value() ? driver_entry->bytes_downloaded : 0;
- stats::LogDownloadCompletion(
- type, entry->completion_time - entry->create_time, file_size);
+ stats::LogDownloadCompletion(type, file_size);
if (type == CompletionType::SUCCEED) {
DCHECK(driver_entry.has_value());
stats::LogFilePathRenamed(driver_entry->current_file_path !=
entry->target_file_path);
entry->target_file_path = driver_entry->current_file_path;
-
entry->completion_time = driver_entry->completion_time;
+ entry->bytes_downloaded = driver_entry->bytes_downloaded;
+ CompletionInfo completion_info(driver_entry->current_file_path,
+ driver_entry->bytes_downloaded);
+ entry->last_cleanup_check_time = driver_entry->completion_time;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&ControllerImpl::SendOnDownloadSucceeded,
weak_ptr_factory_.GetWeakPtr(), entry->client,
- guid, driver_entry->current_file_path,
- driver_entry->bytes_downloaded));
+ guid, completion_info));
TransitTo(entry, Entry::State::COMPLETE, model_.get());
ScheduleCleanupTask();
} else {
@@ -877,23 +908,29 @@ void ControllerImpl::HandleCompleteDownload(CompletionType type,
}
void ControllerImpl::ScheduleCleanupTask() {
- base::Time earliest_completion_time = base::Time::Max();
+ base::Time earliest_cleanup_start_time = base::Time::Max();
for (const Entry* entry : model_->PeekEntries()) {
- if (entry->completion_time == base::Time() ||
- entry->state != Entry::State::COMPLETE)
+ if (entry->state != Entry::State::COMPLETE)
continue;
- if (entry->completion_time < earliest_completion_time) {
- earliest_completion_time = entry->completion_time;
+
+ base::Time cleanup_time_for_entry =
+ std::min(entry->last_cleanup_check_time + config_->file_keep_alive_time,
+ entry->completion_time + config_->max_file_keep_alive_time);
+ cleanup_time_for_entry =
+ std::max(cleanup_time_for_entry, base::Time::Now());
+ if (cleanup_time_for_entry < earliest_cleanup_start_time) {
+ earliest_cleanup_start_time = cleanup_time_for_entry;
}
}
- if (earliest_completion_time == base::Time::Max())
+ if (earliest_cleanup_start_time == base::Time::Max())
return;
- base::TimeDelta start_time = earliest_completion_time +
- config_->file_keep_alive_time -
- base::Time::Now();
+ base::TimeDelta start_time = earliest_cleanup_start_time - base::Time::Now();
base::TimeDelta end_time = start_time + config_->file_cleanup_window;
+ DCHECK_LT(std::ceil(start_time.InSecondsF()),
+ std::ceil(end_time.InSecondsF()))
+ << "GCM requires start time to be less than end time";
task_scheduler_->ScheduleTask(DownloadTaskType::CLEANUP_TASK, false, false,
std::ceil(start_time.InSecondsF()),
@@ -990,10 +1027,10 @@ void ControllerImpl::HandleExternalDownload(const std::string& guid,
void ControllerImpl::SendOnServiceInitialized(
DownloadClient client_id,
bool state_lost,
- const std::vector<std::string>& guids) {
+ const std::vector<DownloadMetaData>& downloads) {
auto* client = clients_->GetClient(client_id);
DCHECK(client);
- client->OnServiceInitialized(state_lost, guids);
+ client->OnServiceInitialized(state_lost, downloads);
}
void ControllerImpl::SendOnServiceUnavailable() {
@@ -1013,13 +1050,13 @@ void ControllerImpl::SendOnDownloadUpdated(DownloadClient client_id,
client->OnDownloadUpdated(guid, bytes_downloaded);
}
-void ControllerImpl::SendOnDownloadSucceeded(DownloadClient client_id,
- const std::string& guid,
- const base::FilePath& path,
- uint64_t size) {
+void ControllerImpl::SendOnDownloadSucceeded(
+ DownloadClient client_id,
+ const std::string& guid,
+ const CompletionInfo& completion_info) {
auto* client = clients_->GetClient(client_id);
DCHECK(client);
- client->OnDownloadSucceeded(guid, path, size);
+ client->OnDownloadSucceeded(guid, completion_info);
}
void ControllerImpl::SendOnDownloadFailed(
diff --git a/chromium/components/download/internal/controller_impl.h b/chromium/components/download/internal/controller_impl.h
index 911ada78f00..b2df0c5a88c 100644
--- a/chromium/components/download/internal/controller_impl.h
+++ b/chromium/components/download/internal/controller_impl.h
@@ -33,6 +33,7 @@ class Model;
class Scheduler;
struct Configuration;
+struct DownloadMetaData;
struct SchedulingParams;
// The internal Controller implementation. This class does all of the heavy
@@ -176,15 +177,14 @@ class ControllerImpl : public Controller,
// meant to help prevent reentrancy.
void SendOnServiceInitialized(DownloadClient client_id,
bool state_lost,
- const std::vector<std::string>& guids);
+ const std::vector<DownloadMetaData>& downloads);
void SendOnServiceUnavailable();
void SendOnDownloadUpdated(DownloadClient client_id,
const std::string& guid,
uint64_t bytes_downloaded);
void SendOnDownloadSucceeded(DownloadClient client_id,
const std::string& guid,
- const base::FilePath& path,
- uint64_t size);
+ const CompletionInfo& completion_info);
void SendOnDownloadFailed(DownloadClient client_id,
const std::string& guid,
download::Client::FailureReason reason);
diff --git a/chromium/components/download/internal/controller_impl_unittest.cc b/chromium/components/download/internal/controller_impl_unittest.cc
index 5a5a7a1bbb7..fa2350245f7 100644
--- a/chromium/components/download/internal/controller_impl_unittest.cc
+++ b/chromium/components/download/internal/controller_impl_unittest.cc
@@ -18,15 +18,18 @@
#include "components/download/internal/client_set.h"
#include "components/download/internal/config.h"
#include "components/download/internal/entry.h"
+#include "components/download/internal/entry_utils.h"
#include "components/download/internal/file_monitor.h"
#include "components/download/internal/model_impl.h"
#include "components/download/internal/scheduler/scheduler.h"
#include "components/download/internal/stats.h"
+#include "components/download/internal/test/empty_client.h"
#include "components/download/internal/test/entry_utils.h"
#include "components/download/internal/test/mock_client.h"
#include "components/download/internal/test/test_device_status_listener.h"
#include "components/download/internal/test/test_download_driver.h"
#include "components/download/internal/test/test_store.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -91,8 +94,7 @@ class MockFileMonitor : public FileMonitor {
MOCK_METHOD2(DeleteUnknownFiles,
void(const Model::EntryList&, const std::vector<DriverEntry>&));
MOCK_METHOD2(CleanupFilesForCompletedEntries,
- std::vector<Entry*>(const Model::EntryList&,
- const base::Closure&));
+ void(const Model::EntryList&, const base::Closure&));
MOCK_METHOD2(DeleteFiles,
void(const std::set<base::FilePath>&, stats::FileCleanupReason));
void HardRecover(const FileMonitor::InitCallback&) override;
@@ -156,6 +158,8 @@ class DownloadServiceControllerImplTest : public testing::Test {
auto clients = base::MakeUnique<DownloadClientMap>();
clients->insert(std::make_pair(DownloadClient::TEST, std::move(client)));
+ clients->insert(std::make_pair(DownloadClient::TEST_2,
+ base::MakeUnique<test::EmptyClient>()));
auto client_set = base::MakeUnique<ClientSet>(std::move(clients));
auto model = base::MakeUnique<ModelImpl>(std::move(store));
auto device_status_listener =
@@ -392,11 +396,13 @@ TEST_F(DownloadServiceControllerImplTest, SuccessfulInitWithExistingDownload) {
test::BuildEntry(DownloadClient::INVALID, base::GenerateGUID());
std::vector<Entry> entries = {entry1, entry2, entry3};
- std::vector<std::string> expected_guids = {entry1.guid, entry2.guid};
+ std::vector<DownloadMetaData> expected_downloads = {
+ util::BuildDownloadMetaData(&entry1),
+ util::BuildDownloadMetaData(&entry2)};
EXPECT_CALL(*client_,
- OnServiceInitialized(
- false, testing::UnorderedElementsAreArray(expected_guids)));
+ OnServiceInitialized(false, testing::UnorderedElementsAreArray(
+ expected_downloads)));
EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
@@ -688,6 +694,7 @@ TEST_F(DownloadServiceControllerImplTest, Pause) {
entry1.state = Entry::State::AVAILABLE;
entry2.state = Entry::State::ACTIVE;
entry3.state = Entry::State::COMPLETE;
+ entry3.completion_time = base::Time::Now();
std::vector<Entry> entries = {entry1, entry2, entry3};
EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
@@ -850,7 +857,7 @@ TEST_F(DownloadServiceControllerImplTest, RetryOnFailure) {
// Test retry on failure.
config_->max_retry_count = 4;
- EXPECT_CALL(*client_, OnDownloadSucceeded(entry1.guid, _, _)).Times(1);
+ EXPECT_CALL(*client_, OnDownloadSucceeded(entry1.guid, _)).Times(1);
base::FilePath path = base::FilePath::FromUTF8Unsafe("123");
driver_->NotifyDownloadFailed(dentry1, FailureType::RECOVERABLE);
driver_->NotifyDownloadFailed(dentry1, FailureType::RECOVERABLE);
@@ -870,14 +877,15 @@ TEST_F(DownloadServiceControllerImplTest, RetryOnFailure) {
// Retry is done, and failed entry should be removed.
EXPECT_EQ(nullptr, model_->Get(entry2.guid));
}
-
TEST_F(DownloadServiceControllerImplTest, OnDownloadSucceeded) {
Entry entry = test::BuildBasicEntry();
entry.state = Entry::State::ACTIVE;
std::vector<Entry> entries = {entry};
+ CompletionInfo completion_info(base::FilePath::FromUTF8Unsafe("123"), 1024u);
EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
- EXPECT_CALL(*client_, OnDownloadSucceeded(entry.guid, _, _)).Times(1);
+ EXPECT_CALL(*client_, OnDownloadSucceeded(entry.guid, completion_info))
+ .Times(1);
EXPECT_CALL(*scheduler_, Next(_, _)).Times(2);
EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2);
@@ -888,30 +896,47 @@ TEST_F(DownloadServiceControllerImplTest, OnDownloadSucceeded) {
DriverEntry driver_entry;
driver_entry.guid = entry.guid;
- driver_entry.bytes_downloaded = 1024;
- driver_entry.completion_time = base::Time::Now();
- driver_entry.current_file_path = base::FilePath::FromUTF8Unsafe("123");
+ driver_entry.current_file_path = completion_info.path;
+ driver_entry.bytes_downloaded = completion_info.bytes_downloaded;
+ base::Time now = base::Time::Now();
+ driver_entry.completion_time = now;
long start_time = 0;
EXPECT_CALL(*task_scheduler_,
ScheduleTask(DownloadTaskType::CLEANUP_TASK, _, _, _, _))
.WillOnce(SaveArg<3>(&start_time));
driver_->NotifyDownloadSucceeded(driver_entry);
- EXPECT_EQ(Entry::State::COMPLETE, model_->Get(entry.guid)->state);
+ Entry* updated_entry = model_->Get(entry.guid);
+ DCHECK(updated_entry);
+ EXPECT_EQ(Entry::State::COMPLETE, updated_entry->state);
+ EXPECT_EQ(completion_info.bytes_downloaded, updated_entry->bytes_downloaded);
+ EXPECT_EQ(completion_info.path, updated_entry->target_file_path);
+ EXPECT_EQ(now, updated_entry->completion_time);
EXPECT_LE(driver_entry.completion_time + config_->file_keep_alive_time,
- base::Time::Now() + base::TimeDelta::FromSeconds(start_time));
+ now + base::TimeDelta::FromSeconds(start_time));
task_runner_->RunUntilIdle();
}
TEST_F(DownloadServiceControllerImplTest, CleanupTaskScheduledAtEarliestTime) {
- Entry entry1 = test::BuildBasicEntry();
- entry1.state = Entry::State::ACTIVE;
- entry1.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(1);
- Entry entry2 = test::BuildBasicEntry();
- entry2.state = Entry::State::COMPLETE;
- entry2.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(2);
- std::vector<Entry> entries = {entry1, entry2};
+ // File keep alive time is 10 minutes.
+ // entry1 should be ignored.
+ Entry entry1 = test::BuildBasicEntry(Entry::State::ACTIVE);
+ entry1.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(7);
+ entry1.last_cleanup_check_time = entry1.completion_time;
+ Entry entry2 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry2.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(1);
+ entry2.last_cleanup_check_time = entry2.completion_time;
+ Entry entry3 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry3.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(2);
+ entry3.last_cleanup_check_time = entry3.completion_time;
+
+ // For entry4, keep_alive_until time should be considered instead.
+ Entry entry4 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry4.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(5);
+ entry4.last_cleanup_check_time =
+ base::Time::Now() - base::TimeDelta::FromMinutes(1);
+ std::vector<Entry> entries = {entry1, entry2, entry3, entry4};
InitializeController();
store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
@@ -924,6 +949,8 @@ TEST_F(DownloadServiceControllerImplTest, CleanupTaskScheduledAtEarliestTime) {
driver_entry.completion_time = base::Time::Now();
driver_entry.current_file_path = base::FilePath::FromUTF8Unsafe("123");
+ // Since keep_alive_time is 10 minutes and oldest completion time was 2
+ // minutes ago, we should see the cleanup window start at 8 minutes.
EXPECT_CALL(*task_scheduler_, ScheduleTask(DownloadTaskType::CLEANUP_TASK,
false, false, 480, 780))
.Times(1);
@@ -1008,7 +1035,7 @@ TEST_F(DownloadServiceControllerImplTest, DownloadCompletionTest) {
OnDownloadFailed(entry2.guid, Client::FailureReason::ABORTED))
.Times(1);
driver_->Start(RequestParams(), entry2.guid, entry2.target_file_path,
- NO_TRAFFIC_ANNOTATION_YET);
+ TRAFFIC_ANNOTATION_FOR_TESTS);
// Test FailureReason::NETWORK.
EXPECT_CALL(*client_,
@@ -1081,18 +1108,23 @@ TEST_F(DownloadServiceControllerImplTest, StartupRecovery) {
entries.push_back(test::BuildBasicEntry(Entry::State::PAUSED));
entries.push_back(test::BuildBasicEntry(Entry::State::COMPLETE));
+ entries.back().completion_time = base::Time::Now();
driver_entries.push_back(
BuildDriverEntry(entries.back(), DriverEntry::State::IN_PROGRESS));
entries.push_back(test::BuildBasicEntry(Entry::State::COMPLETE));
+ entries.back().completion_time = base::Time::Now();
driver_entries.push_back(
BuildDriverEntry(entries.back(), DriverEntry::State::COMPLETE));
entries.push_back(test::BuildBasicEntry(Entry::State::COMPLETE));
+ entries.back().completion_time = base::Time::Now();
driver_entries.push_back(
BuildDriverEntry(entries.back(), DriverEntry::State::CANCELLED));
entries.push_back(test::BuildBasicEntry(Entry::State::COMPLETE));
+ entries.back().completion_time = base::Time::Now();
driver_entries.push_back(
BuildDriverEntry(entries.back(), DriverEntry::State::INTERRUPTED));
entries.push_back(test::BuildBasicEntry(Entry::State::COMPLETE));
+ entries.back().completion_time = base::Time::Now();
// Set up the Controller.
device_status_listener_->SetDeviceStatus(
@@ -1264,7 +1296,7 @@ TEST_F(DownloadServiceControllerImplTest, NewExternalDownload) {
// Simulate a newly created external download.
driver_->Start(RequestParams(), dentry2.guid, dentry2.current_file_path,
- NO_TRAFFIC_ANNOTATION_YET);
+ TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_TRUE(driver_->Find(entry1.guid).value().paused);
EXPECT_FALSE(driver_->Find(entry2.guid).value().paused);
@@ -1293,7 +1325,7 @@ TEST_F(DownloadServiceControllerImplTest, NewExternalDownload) {
// Rebuild the download so we can simulate more.
dentry2.state = DriverEntry::State::IN_PROGRESS;
driver_->Start(RequestParams(), dentry2.guid, dentry2.current_file_path,
- NO_TRAFFIC_ANNOTATION_YET);
+ TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_TRUE(driver_->Find(entry1.guid).value().paused);
EXPECT_FALSE(driver_->Find(entry2.guid).value().paused);
@@ -1318,6 +1350,7 @@ TEST_F(DownloadServiceControllerImplTest, CancelTimeTest) {
entry2.create_time = base::Time::Now() - base::TimeDelta::FromSeconds(10);
entry2.scheduling_params.cancel_time =
base::Time::Now() - base::TimeDelta::FromSeconds(2);
+ entry2.completion_time = base::Time::Now();
std::vector<Entry> entries = {entry1, entry2};
EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
@@ -1333,6 +1366,60 @@ TEST_F(DownloadServiceControllerImplTest, CancelTimeTest) {
EXPECT_EQ(1u, updated_entries.size());
}
+TEST_F(DownloadServiceControllerImplTest, RemoveCleanupEligibleDownloads) {
+ config_->file_keep_alive_time = base::TimeDelta::FromMinutes(5);
+ config_->max_file_keep_alive_time = base::TimeDelta::FromMinutes(50);
+
+ Entry entry1 = test::BuildBasicEntry(Entry::State::ACTIVE);
+ entry1.client = DownloadClient::TEST_2;
+
+ Entry entry2 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry2.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(2);
+ entry2.last_cleanup_check_time = entry2.completion_time;
+ entry2.client = DownloadClient::TEST_2;
+
+ Entry entry3 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry3.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(20);
+ entry3.last_cleanup_check_time = entry3.completion_time;
+ entry3.client = DownloadClient::TEST_2;
+
+ // last_cleanup_check_time was recent and enough time hasn't passed.
+ Entry entry4 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry4.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(20);
+ entry4.last_cleanup_check_time =
+ base::Time::Now() - base::TimeDelta::FromMinutes(2);
+ entry4.client = DownloadClient::TEST_2;
+
+ // Client doesn't want to delete.
+ Entry entry5 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry5.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(45);
+ entry5.last_cleanup_check_time =
+ base::Time::Now() - base::TimeDelta::FromMinutes(20);
+ entry5.client = DownloadClient::TEST;
+
+ // Client doesn't want to delete, but entry has gotten too many life times.
+ Entry entry6 = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry6.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(80);
+ entry6.last_cleanup_check_time =
+ base::Time::Now() - base::TimeDelta::FromMinutes(20);
+ entry6.client = DownloadClient::TEST;
+
+ std::vector<Entry> entries = {entry1, entry2, entry3, entry4, entry5, entry6};
+
+ EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1);
+
+ InitializeController();
+ store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
+ file_monitor_->TriggerInit(true);
+ driver_->MakeReady();
+ task_runner_->RunUntilIdle();
+
+ std::vector<Entry*> expected = {&entry1, &entry2, &entry4, &entry5};
+ EXPECT_EQ(expected.size(), model_->PeekEntries().size());
+ EXPECT_TRUE(
+ test::CompareEntryListUsingGuidOnly(expected, model_->PeekEntries()));
+}
+
// Ensures no more downloads are activated if the number of downloads exceeds
// the max running download configuration.
TEST_F(DownloadServiceControllerImplTest, ThrottlingConfigMaxRunning) {
diff --git a/chromium/components/download/internal/download_service_impl.cc b/chromium/components/download/internal/download_service_impl.cc
index ceff12d729f..c48b24067c7 100644
--- a/chromium/components/download/internal/download_service_impl.cc
+++ b/chromium/components/download/internal/download_service_impl.cc
@@ -74,7 +74,6 @@ DownloadService::ServiceStatus DownloadServiceImpl::GetStatus() {
void DownloadServiceImpl::StartDownload(const DownloadParams& download_params) {
stats::LogServiceApiAction(download_params.client,
stats::ServiceApiAction::START_DOWNLOAD);
- DCHECK_EQ(download_params.guid, base::ToUpperASCII(download_params.guid));
stats::LogDownloadParams(download_params);
if (startup_completed_) {
controller_->StartDownload(download_params);
@@ -88,8 +87,6 @@ void DownloadServiceImpl::StartDownload(const DownloadParams& download_params) {
void DownloadServiceImpl::PauseDownload(const std::string& guid) {
stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
stats::ServiceApiAction::PAUSE_DOWNLOAD);
- DCHECK_EQ(guid, base::ToUpperASCII(guid));
-
if (startup_completed_) {
controller_->PauseDownload(guid);
} else {
@@ -101,8 +98,6 @@ void DownloadServiceImpl::PauseDownload(const std::string& guid) {
void DownloadServiceImpl::ResumeDownload(const std::string& guid) {
stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
stats::ServiceApiAction::RESUME_DOWNLOAD);
- DCHECK_EQ(guid, base::ToUpperASCII(guid));
-
if (startup_completed_) {
controller_->ResumeDownload(guid);
} else {
@@ -115,8 +110,6 @@ void DownloadServiceImpl::ResumeDownload(const std::string& guid) {
void DownloadServiceImpl::CancelDownload(const std::string& guid) {
stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
stats::ServiceApiAction::CANCEL_DOWNLOAD);
- DCHECK_EQ(guid, base::ToUpperASCII(guid));
-
if (startup_completed_) {
controller_->CancelDownload(guid);
} else {
@@ -131,8 +124,6 @@ void DownloadServiceImpl::ChangeDownloadCriteria(
const SchedulingParams& params) {
stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
stats::ServiceApiAction::CHANGE_CRITERIA);
- DCHECK_EQ(guid, base::ToUpperASCII(guid));
-
if (startup_completed_) {
controller_->ChangeDownloadCriteria(guid, params);
} else {
diff --git a/chromium/components/download/internal/download_service_impl.h b/chromium/components/download/internal/download_service_impl.h
index 0333f9d0b1f..808f2efb250 100644
--- a/chromium/components/download/internal/download_service_impl.h
+++ b/chromium/components/download/internal/download_service_impl.h
@@ -5,11 +5,11 @@
#ifndef COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_SERVICE_IMPL_H_
#define COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_SERVICE_IMPL_H_
-#include <deque>
#include <map>
#include <memory>
#include <string>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "components/download/internal/config.h"
#include "components/download/internal/service_config_impl.h"
@@ -51,7 +51,7 @@ class DownloadServiceImpl : public DownloadService {
std::unique_ptr<Controller> controller_;
ServiceConfigImpl service_config_;
- std::deque<base::Closure> pending_actions_;
+ base::circular_deque<base::Closure> pending_actions_;
std::map<DownloadTaskType, base::Closure> pending_tasks_;
bool startup_completed_;
diff --git a/chromium/components/download/internal/download_service_impl_unittest.cc b/chromium/components/download/internal/download_service_impl_unittest.cc
index 74090dfbca8..ed6e9b66ce4 100644
--- a/chromium/components/download/internal/download_service_impl_unittest.cc
+++ b/chromium/components/download/internal/download_service_impl_unittest.cc
@@ -66,9 +66,6 @@ TEST_F(DownloadServiceImplTest, TestGetStatus) {
TEST_F(DownloadServiceImplTest, TestApiPassThrough) {
DownloadParams params = test::BuildBasicDownloadParams();
- // TODO(xingliu): Remove the limitation of upper case guid in
- // |download_params|, see http://crbug.com/734818.
- params.guid = base::ToUpperASCII(params.guid);
SchedulingParams scheduling_params;
scheduling_params.priority = SchedulingParams::Priority::UI;
diff --git a/chromium/components/download/internal/download_store.cc b/chromium/components/download/internal/download_store.cc
index 877547846df..7b6ee87a72e 100644
--- a/chromium/components/download/internal/download_store.cc
+++ b/chromium/components/download/internal/download_store.cc
@@ -12,6 +12,8 @@
#include "components/download/internal/proto_conversions.h"
#include "components/leveldb_proto/proto_database_impl.h"
+using leveldb_env::SharedReadCache;
+
namespace download {
namespace {
@@ -40,7 +42,8 @@ bool DownloadStore::IsInitialized() {
void DownloadStore::Initialize(InitCallback callback) {
DCHECK(!IsInitialized());
db_->InitWithOptions(
- kDatabaseClientName, leveldb_proto::Options(database_dir_),
+ kDatabaseClientName,
+ leveldb_proto::Options(database_dir_, SharedReadCache::Default),
base::BindOnce(&DownloadStore::OnDatabaseInited,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -82,7 +85,8 @@ void DownloadStore::OnDatabaseDestroyed(StoreCallback callback, bool success) {
}
db_->InitWithOptions(
- kDatabaseClientName, leveldb_proto::Options(database_dir_),
+ kDatabaseClientName,
+ leveldb_proto::Options(database_dir_, SharedReadCache::Default),
base::BindOnce(&DownloadStore::OnDatabaseInitedAfterDestroy,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
diff --git a/chromium/components/download/internal/entry.cc b/chromium/components/download/internal/entry.cc
index 4df4757a0b0..09f5451d949 100644
--- a/chromium/components/download/internal/entry.cc
+++ b/chromium/components/download/internal/entry.cc
@@ -6,7 +6,8 @@
namespace download {
-Entry::Entry() : attempt_count(0) {}
+Entry::Entry()
+ : bytes_downloaded(0u), attempt_count(0), cleanup_attempt_count(0) {}
Entry::Entry(const Entry& other) = default;
Entry::Entry(const DownloadParams& params)
@@ -15,7 +16,10 @@ Entry::Entry(const DownloadParams& params)
create_time(base::Time::Now()),
scheduling_params(params.scheduling_params),
request_params(params.request_params),
- attempt_count(0) {}
+ bytes_downloaded(0u),
+ attempt_count(0),
+ cleanup_attempt_count(0),
+ traffic_annotation(params.traffic_annotation) {}
Entry::~Entry() = default;
@@ -34,7 +38,11 @@ bool Entry::operator==(const Entry& other) const {
state == other.state && target_file_path == other.target_file_path &&
create_time == other.create_time &&
completion_time == other.completion_time &&
- attempt_count == other.attempt_count;
+ last_cleanup_check_time == other.last_cleanup_check_time &&
+ bytes_downloaded == other.bytes_downloaded &&
+ attempt_count == other.attempt_count &&
+ cleanup_attempt_count == other.cleanup_attempt_count &&
+ traffic_annotation == other.traffic_annotation;
}
} // namespace download
diff --git a/chromium/components/download/internal/entry.h b/chromium/components/download/internal/entry.h
index 20766317889..b72c45ae412 100644
--- a/chromium/components/download/internal/entry.h
+++ b/chromium/components/download/internal/entry.h
@@ -9,6 +9,7 @@
#include "components/download/public/client.h"
#include "components/download/public/clients.h"
#include "components/download/public/download_params.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
namespace download {
@@ -75,8 +76,22 @@ struct Entry {
// not yet complete.
base::Time completion_time;
+ // Last time when the entry was checked for cleanup, default is
+ // |completion_time|.
+ base::Time last_cleanup_check_time;
+
+ // Size of the download file in bytes, 0 if download is not successfully
+ // completed.
+ uint64_t bytes_downloaded;
+
// Stores the number of retries for this download.
uint32_t attempt_count;
+
+ // Stores the number of times the service tried to delete the download file.
+ uint32_t cleanup_attempt_count;
+
+ // Traffic annotation for the network request.
+ net::MutableNetworkTrafficAnnotationTag traffic_annotation;
};
} // namespace download
diff --git a/chromium/components/download/internal/entry_utils.cc b/chromium/components/download/internal/entry_utils.cc
index 35aa3ede353..97657af339a 100644
--- a/chromium/components/download/internal/entry_utils.cc
+++ b/chromium/components/download/internal/entry_utils.cc
@@ -5,35 +5,32 @@
#include "components/download/internal/entry_utils.h"
#include "components/download/internal/entry.h"
+#include "components/download/public/download_metadata.h"
namespace download {
namespace util {
-uint32_t GetNumberOfEntriesForClient(DownloadClient client,
- const std::vector<Entry*>& entries) {
+uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client,
+ const std::vector<Entry*>& entries) {
uint32_t count = 0;
for (auto* entry : entries)
- if (entry->client == client)
+ if (entry->client == client && entry->state != Entry::State::COMPLETE)
count++;
return count;
}
-std::map<DownloadClient, std::vector<std::string>> MapEntriesToClients(
- const std::set<DownloadClient>& clients,
- const std::vector<Entry*>& entries,
- const std::set<Entry::State>& ignored_states) {
- std::map<DownloadClient, std::vector<std::string>> categorized;
+std::map<DownloadClient, std::vector<DownloadMetaData>>
+MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients,
+ const std::vector<Entry*>& entries) {
+ std::map<DownloadClient, std::vector<DownloadMetaData>> categorized;
for (auto* entry : entries) {
- if (ignored_states.find(entry->state) != ignored_states.end())
- continue;
-
DownloadClient client = entry->client;
if (clients.find(client) == clients.end())
client = DownloadClient::INVALID;
- categorized[client].push_back(entry->guid);
+ categorized[client].push_back(BuildDownloadMetaData(entry));
}
return categorized;
@@ -63,5 +60,16 @@ bool EntryBetterThan(const Entry& lhs, const Entry& rhs) {
rhs.scheduling_params.cancel_time);
}
+DownloadMetaData BuildDownloadMetaData(Entry* entry) {
+ DCHECK(entry);
+ DownloadMetaData meta_data;
+ meta_data.guid = entry->guid;
+ if (entry->state == Entry::State::COMPLETE) {
+ meta_data.completion_info =
+ CompletionInfo(entry->target_file_path, entry->bytes_downloaded);
+ }
+ return meta_data;
+}
+
} // namespace util
} // namespace download
diff --git a/chromium/components/download/internal/entry_utils.h b/chromium/components/download/internal/entry_utils.h
index 780b49467fb..de024af6034 100644
--- a/chromium/components/download/internal/entry_utils.h
+++ b/chromium/components/download/internal/entry_utils.h
@@ -13,27 +13,29 @@
#include "components/download/internal/model.h"
#include "components/download/internal/scheduler/device_status.h"
#include "components/download/public/clients.h"
+#include "components/download/public/download_metadata.h"
namespace download {
+struct DownloadMetaData;
struct Entry;
namespace util {
// Helper method to return the number of Entry objects in |entries| are
-// associated with |client|.
-uint32_t GetNumberOfEntriesForClient(DownloadClient client,
- const std::vector<Entry*>& entries);
+// associated with |client| and do not have a state of Entry::State::COMPLETE.
+uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client,
+ const std::vector<Entry*>& entries);
// Effectively runs a map reduce to turn a list of Entry objects into a map of
-// [Client Id] -> List of entries. Any Entry in |entries| that does not have a
-// matching DownloadClient in |clients| will be put in the
-// DownloadClient::INVALID bucket. Any Entry in |entries| with an Entry::State
-// that is in |ignored_states| will not be included.
-std::map<DownloadClient, std::vector<std::string>> MapEntriesToClients(
- const std::set<DownloadClient>& clients,
- const std::vector<Entry*>& entries,
- const std::set<Entry::State>& ignored_states);
+// [Client Id] -> List of entries meta data.
+// Any Entry in |entries| that does not have a matching DownloadClient in
+// |clients| will be put in the DownloadClient::INVALID bucket.
+// Any Entry in |entries| with an Entry::State that is in |ignored_states| will
+// not be included.
+std::map<DownloadClient, std::vector<DownloadMetaData>>
+MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients,
+ const std::vector<Entry*>& entries);
// Gets the least strict scheduling criteria from |entries|, the criteria is
// used to schedule platform background tasks.
@@ -43,6 +45,9 @@ Criteria GetSchedulingCriteria(const Model::EntryList& entries);
// |rhs| based on their priority and cancel time.
bool EntryBetterThan(const Entry& lhs, const Entry& rhs);
+// Builds a download meta data based on |entry|.
+DownloadMetaData BuildDownloadMetaData(Entry* entry);
+
} // namespace util
} // namespace download
diff --git a/chromium/components/download/internal/entry_utils_unittest.cc b/chromium/components/download/internal/entry_utils_unittest.cc
index 472151dc50c..1de8f155bd5 100644
--- a/chromium/components/download/internal/entry_utils_unittest.cc
+++ b/chromium/components/download/internal/entry_utils_unittest.cc
@@ -9,21 +9,23 @@
#include "base/memory/ptr_util.h"
#include "components/download/internal/test/entry_utils.h"
#include "components/download/public/clients.h"
+#include "components/download/public/download_metadata.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace download {
-TEST(DownloadServiceEntryUtilsTest, TestGetNumberOfEntriesForClient_NoEntries) {
+TEST(DownloadServiceEntryUtilsTest, TestGetNumberOfLiveEntriesForClient) {
Entry entry1 = test::BuildBasicEntry();
Entry entry2 = test::BuildBasicEntry();
Entry entry3 = test::BuildBasicEntry();
+ Entry entry4 = test::BuildBasicEntry(Entry::State::COMPLETE);
- std::vector<Entry*> entries = {&entry1, &entry2, &entry3};
+ std::vector<Entry*> entries = {&entry1, &entry2, &entry3, &entry4};
+ EXPECT_EQ(0U, util::GetNumberOfLiveEntriesForClient(DownloadClient::INVALID,
+ entries));
EXPECT_EQ(
- 0U, util::GetNumberOfEntriesForClient(DownloadClient::INVALID, entries));
- EXPECT_EQ(3U,
- util::GetNumberOfEntriesForClient(DownloadClient::TEST, entries));
+ 3U, util::GetNumberOfLiveEntriesForClient(DownloadClient::TEST, entries));
}
TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
@@ -34,14 +36,21 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
Entry entry5 = test::BuildBasicEntry(Entry::State::AVAILABLE);
std::vector<Entry*> entries = {&entry1, &entry2, &entry3, &entry4, &entry5};
- std::vector<std::string> expected_list = {
- entry1.guid, entry2.guid, entry3.guid, entry4.guid, entry5.guid};
- std::vector<std::string> expected_pruned_list = {entry1.guid, entry2.guid,
- entry3.guid, entry5.guid};
+ std::vector<DownloadMetaData> expected_list = {
+ util::BuildDownloadMetaData(&entry1),
+ util::BuildDownloadMetaData(&entry2),
+ util::BuildDownloadMetaData(&entry3),
+ util::BuildDownloadMetaData(&entry4),
+ util::BuildDownloadMetaData(&entry5)};
+ std::vector<DownloadMetaData> expected_pruned_list = {
+ util::BuildDownloadMetaData(&entry1),
+ util::BuildDownloadMetaData(&entry2),
+ util::BuildDownloadMetaData(&entry3),
+ util::BuildDownloadMetaData(&entry5)};
// If DownloadClient::TEST isn't a valid Client, all of the associated entries
// should move to the DownloadClient::INVALID bucket.
- auto mapped1 = util::MapEntriesToClients(std::set<DownloadClient>(), entries,
- std::set<Entry::State>());
+ auto mapped1 =
+ util::MapEntriesToMetadataForClients(std::set<DownloadClient>(), entries);
EXPECT_EQ(1U, mapped1.size());
EXPECT_NE(mapped1.end(), mapped1.find(DownloadClient::INVALID));
EXPECT_EQ(mapped1.end(), mapped1.find(DownloadClient::TEST));
@@ -54,8 +63,7 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
// If DownloadClient::TEST is a valid Client, it should have the associated
// entries.
std::set<DownloadClient> clients = {DownloadClient::TEST};
- auto mapped2 =
- util::MapEntriesToClients(clients, entries, std::set<Entry::State>());
+ auto mapped2 = util::MapEntriesToMetadataForClients(clients, entries);
EXPECT_EQ(1U, mapped2.size());
EXPECT_NE(mapped2.end(), mapped2.find(DownloadClient::TEST));
EXPECT_EQ(mapped2.end(), mapped2.find(DownloadClient::INVALID));
@@ -64,17 +72,6 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
EXPECT_EQ(5U, list2.size());
EXPECT_TRUE(
std::equal(expected_list.begin(), expected_list.end(), list2.begin()));
-
- // If we are pruning entries with certain states, make sure those entries
- // don't show up in the results.
- std::set<Entry::State> ignored_states = {Entry::State::ACTIVE,
- Entry::State::COMPLETE};
- auto mapped3 = util::MapEntriesToClients(clients, entries, ignored_states);
- EXPECT_EQ(1U, mapped3.size());
- auto list3 = mapped3.find(DownloadClient::TEST)->second;
- EXPECT_EQ(4U, list3.size());
- EXPECT_TRUE(std::equal(expected_pruned_list.begin(),
- expected_pruned_list.end(), list3.begin()));
}
TEST(DownloadServiceEntryUtilsTest, GetSchedulingCriteria) {
@@ -116,4 +113,25 @@ TEST(DownloadServiceEntryUtilsTest, GetSchedulingCriteria) {
EXPECT_EQ(Criteria(false, false), util::GetSchedulingCriteria(list5));
}
+// Test to verify download meta data is built correctly.
+TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaData) {
+ Entry entry = test::BuildBasicEntry(Entry::State::PAUSED);
+ entry.target_file_path = base::FilePath::FromUTF8Unsafe("123");
+ entry.bytes_downloaded = 200u;
+ auto meta_data = util::BuildDownloadMetaData(&entry);
+ EXPECT_EQ(entry.guid, meta_data.guid);
+ // Incomplete downloads don't copy the following data.
+ EXPECT_FALSE(meta_data.completion_info.has_value());
+
+ entry = test::BuildBasicEntry(Entry::State::COMPLETE);
+ entry.target_file_path = base::FilePath::FromUTF8Unsafe("123");
+ entry.bytes_downloaded = 100u;
+ meta_data = util::BuildDownloadMetaData(&entry);
+ EXPECT_EQ(entry.guid, meta_data.guid);
+ EXPECT_TRUE(meta_data.completion_info.has_value());
+ EXPECT_EQ(entry.target_file_path, meta_data.completion_info->path);
+ EXPECT_EQ(entry.bytes_downloaded,
+ meta_data.completion_info->bytes_downloaded);
+}
+
} // namespace download
diff --git a/chromium/components/download/internal/file_monitor.h b/chromium/components/download/internal/file_monitor.h
index 9df409c1e70..1174b2ef7d1 100644
--- a/chromium/components/download/internal/file_monitor.h
+++ b/chromium/components/download/internal/file_monitor.h
@@ -20,7 +20,6 @@ class FilePath;
namespace download {
struct DriverEntry;
-struct Entry;
// An utility class containing various file cleanup methods.
class FileMonitor {
@@ -36,9 +35,8 @@ class FileMonitor {
const Model::EntryList& known_entries,
const std::vector<DriverEntry>& known_driver_entries) = 0;
- // Deletes the files for the database entries which have been completed and
- // ready for cleanup. Returns the entries eligible for clean up.
- virtual std::vector<Entry*> CleanupFilesForCompletedEntries(
+ // Deletes the files associated with the |entries|.
+ virtual void CleanupFilesForCompletedEntries(
const Model::EntryList& entries,
const base::Closure& completion_callback) = 0;
diff --git a/chromium/components/download/internal/file_monitor_impl.cc b/chromium/components/download/internal/file_monitor_impl.cc
index 639db4b9f22..4b6cf7c3b6f 100644
--- a/chromium/components/download/internal/file_monitor_impl.cc
+++ b/chromium/components/download/internal/file_monitor_impl.cc
@@ -173,21 +173,17 @@ void FileMonitorImpl::DeleteUnknownFiles(
download_file_paths));
}
-std::vector<Entry*> FileMonitorImpl::CleanupFilesForCompletedEntries(
+void FileMonitorImpl::CleanupFilesForCompletedEntries(
const Model::EntryList& entries,
const base::Closure& completion_callback) {
- std::vector<Entry*> entries_to_remove;
std::set<base::FilePath> files_to_remove;
for (auto* entry : entries) {
- if (!ReadyForCleanup(entry))
- continue;
-
- entries_to_remove.push_back(entry);
files_to_remove.insert(entry->target_file_path);
// TODO(xingliu): Consider logs life time after the file being deleted on
// the file thread.
- stats::LogFileLifeTime(base::Time::Now() - entry->completion_time);
+ stats::LogFileLifeTime(base::Time::Now() - entry->completion_time,
+ entry->cleanup_attempt_count);
}
file_thread_task_runner_->PostTaskAndReply(
@@ -195,7 +191,6 @@ std::vector<Entry*> FileMonitorImpl::CleanupFilesForCompletedEntries(
base::Bind(&DeleteFilesOnFileThread, files_to_remove,
stats::FileCleanupReason::TIMEOUT),
completion_callback);
- return entries_to_remove;
}
void FileMonitorImpl::DeleteFiles(
@@ -211,9 +206,4 @@ void FileMonitorImpl::HardRecover(const InitCallback& callback) {
base::Bind(&HardRecoverOnFileThread, download_file_dir_), callback);
}
-bool FileMonitorImpl::ReadyForCleanup(const Entry* entry) {
- return entry->state == Entry::State::COMPLETE &&
- (base::Time::Now() - entry->completion_time) > file_keep_alive_time_;
-}
-
} // namespace download
diff --git a/chromium/components/download/internal/file_monitor_impl.h b/chromium/components/download/internal/file_monitor_impl.h
index f0e5b55ad51..8b8635319c2 100644
--- a/chromium/components/download/internal/file_monitor_impl.h
+++ b/chromium/components/download/internal/file_monitor_impl.h
@@ -23,8 +23,6 @@
namespace download {
-struct Entry;
-
// An utility class containing various file cleanup methods.
class FileMonitorImpl : public FileMonitor {
public:
@@ -39,7 +37,7 @@ class FileMonitorImpl : public FileMonitor {
void DeleteUnknownFiles(
const Model::EntryList& known_entries,
const std::vector<DriverEntry>& known_driver_entries) override;
- std::vector<Entry*> CleanupFilesForCompletedEntries(
+ void CleanupFilesForCompletedEntries(
const Model::EntryList& entries,
const base::Closure& completion_callback) override;
void DeleteFiles(const std::set<base::FilePath>& files_to_remove,
@@ -47,8 +45,6 @@ class FileMonitorImpl : public FileMonitor {
void HardRecover(const InitCallback& callback) override;
private:
- bool ReadyForCleanup(const Entry* entry);
-
const base::FilePath download_file_dir_;
const base::TimeDelta file_keep_alive_time_;
diff --git a/chromium/components/download/internal/file_monitor_unittest.cc b/chromium/components/download/internal/file_monitor_unittest.cc
index d668872c802..1fb7be535fb 100644
--- a/chromium/components/download/internal/file_monitor_unittest.cc
+++ b/chromium/components/download/internal/file_monitor_unittest.cc
@@ -128,26 +128,21 @@ TEST_F(FileMonitorTest, TestDeleteUnknownFiles) {
TEST_F(FileMonitorTest, TestCleanupFilesForCompletedEntries) {
Entry entry1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID());
- entry1.state = Entry::State::COMPLETE;
- entry1.completion_time = base::Time::Now() - base::TimeDelta::FromHours(20);
EXPECT_TRUE(
base::CreateTemporaryFileInDir(download_dir_, &entry1.target_file_path));
Entry entry2 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID());
- entry2.state = Entry::State::ACTIVE;
EXPECT_TRUE(
base::CreateTemporaryFileInDir(download_dir_, &entry2.target_file_path));
std::vector<Entry*> entries = {&entry1, &entry2};
- std::vector<Entry*> entries_to_remove =
- monitor_->CleanupFilesForCompletedEntries(
- entries, base::Bind(&FileMonitorTest::CompletionCallback,
- base::Unretained(this)));
+ monitor_->CleanupFilesForCompletedEntries(
+ entries,
+ base::Bind(&FileMonitorTest::CompletionCallback, base::Unretained(this)));
task_runner_->RunUntilIdle();
- EXPECT_EQ(1u, entries_to_remove.size());
EXPECT_FALSE(base::PathExists(entry1.target_file_path));
- EXPECT_TRUE(base::PathExists(entry2.target_file_path));
+ EXPECT_FALSE(base::PathExists(entry2.target_file_path));
EXPECT_TRUE(completion_callback_called_);
}
diff --git a/chromium/components/download/internal/proto/entry.proto b/chromium/components/download/internal/proto/entry.proto
index 426588a29e6..964176db211 100644
--- a/chromium/components/download/internal/proto/entry.proto
+++ b/chromium/components/download/internal/proto/entry.proto
@@ -52,4 +52,14 @@ message Entry {
optional int64 completion_time = 8;
optional uint32 attempt_count = 9;
+
+ // Representation of a net::NetworkTrafficAnnotationTag.
+ optional int32 traffic_annotation = 10;
+
+ // Size of the download file in bytes.
+ optional uint64 bytes_downloaded = 11;
+
+ // Uses internal time representation.
+ optional int64 last_cleanup_check_time = 12;
+ optional uint32 cleanup_attempt_count = 13;
}
diff --git a/chromium/components/download/internal/proto_conversions.cc b/chromium/components/download/internal/proto_conversions.cc
index f78f521b054..7badbc20323 100644
--- a/chromium/components/download/internal/proto_conversions.cc
+++ b/chromium/components/download/internal/proto_conversions.cc
@@ -8,6 +8,7 @@
#include "base/time/time.h"
#include "components/download/internal/proto_conversions.h"
#include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
namespace download {
@@ -261,7 +262,13 @@ Entry ProtoConversions::EntryFromProto(const protodb::Entry& proto) {
entry.create_time = base::Time::FromInternalValue(proto.create_time());
entry.completion_time =
base::Time::FromInternalValue(proto.completion_time());
+ entry.last_cleanup_check_time =
+ base::Time::FromInternalValue(proto.last_cleanup_check_time());
entry.attempt_count = proto.attempt_count();
+ entry.cleanup_attempt_count = proto.cleanup_attempt_count();
+ entry.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag({proto.traffic_annotation()});
+ entry.bytes_downloaded = proto.bytes_downloaded();
return entry;
}
@@ -278,8 +285,12 @@ protodb::Entry ProtoConversions::EntryToProto(const Entry& entry) {
proto.set_target_file_path(entry.target_file_path.AsUTF8Unsafe());
proto.set_create_time(entry.create_time.ToInternalValue());
proto.set_completion_time(entry.completion_time.ToInternalValue());
+ proto.set_last_cleanup_check_time(
+ entry.last_cleanup_check_time.ToInternalValue());
proto.set_attempt_count(entry.attempt_count);
-
+ proto.set_cleanup_attempt_count(entry.cleanup_attempt_count);
+ proto.set_traffic_annotation(entry.traffic_annotation.unique_id_hash_code);
+ proto.set_bytes_downloaded(entry.bytes_downloaded);
return proto;
}
diff --git a/chromium/components/download/internal/proto_conversions_unittest.cc b/chromium/components/download/internal/proto_conversions_unittest.cc
index ea1e9cbf4fd..af7261d9021 100644
--- a/chromium/components/download/internal/proto_conversions_unittest.cc
+++ b/chromium/components/download/internal/proto_conversions_unittest.cc
@@ -126,7 +126,7 @@ TEST_F(ProtoConversionsTest, EntryConversion) {
SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE,
SchedulingParams::Priority::HIGH, GURL(TEST_URL), "GET",
Entry::State::ACTIVE, base::FilePath(FILE_PATH_LITERAL("/test/xyz")),
- base::Time::Now(), base::Time::Now(), 3);
+ base::Time::Now(), base::Time::Now(), base::Time::Now(), 1024u, 3, 5);
actual = EntryFromProto(EntryToProto(expected));
EXPECT_TRUE(test::CompareEntry(&expected, &actual));
}
@@ -143,7 +143,7 @@ TEST_F(ProtoConversionsTest, EntryVectorConversion) {
SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE,
SchedulingParams::Priority::HIGH, GURL(TEST_URL), "GET",
Entry::State::ACTIVE, base::FilePath(FILE_PATH_LITERAL("/test/xyz")),
- base::Time::Now(), base::Time::Now(), 2));
+ base::Time::Now(), base::Time::Now(), base::Time::Now(), 1024u, 2, 5));
auto actual = EntryVectorFromProto(
EntryVectorToProto(base::MakeUnique<std::vector<Entry>>(expected)));
diff --git a/chromium/components/download/internal/scheduler/device_status_listener.cc b/chromium/components/download/internal/scheduler/device_status_listener.cc
index ba277b04489..0a7f2fe500d 100644
--- a/chromium/components/download/internal/scheduler/device_status_listener.cc
+++ b/chromium/components/download/internal/scheduler/device_status_listener.cc
@@ -4,7 +4,14 @@
#include "components/download/internal/scheduler/device_status_listener.h"
+#include "base/memory/ptr_util.h"
#include "base/power_monitor/power_monitor.h"
+#include "build/build_config.h"
+#include "components/download/internal/scheduler/network_status_listener.h"
+
+#if defined(OS_ANDROID)
+#include "components/download/internal/android/network_status_listener_android.h"
+#endif
namespace download {
@@ -55,16 +62,20 @@ void DeviceStatusListener::Start(DeviceStatusListener::Observer* observer) {
DCHECK(observer);
observer_ = observer;
+
+ // Listen to battery status changes.
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
DCHECK(power_monitor);
power_monitor->AddObserver(this);
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+ // Listen to network status changes.
+ BuildNetworkStatusListener();
+ network_listener_->Start(this);
status_.battery_status =
ToBatteryStatus(base::PowerMonitor::Get()->IsOnBatteryPower());
status_.network_status =
- ToNetworkStatus(net::NetworkChangeNotifier::GetConnectionType());
+ ToNetworkStatus(network_listener_->GetConnectionType());
listening_ = true;
}
@@ -73,7 +84,9 @@ void DeviceStatusListener::Stop() {
return;
base::PowerMonitor::Get()->RemoveObserver(this);
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+
+ network_listener_->Stop();
+ network_listener_.reset();
status_ = DeviceStatus();
listening_ = false;
@@ -119,4 +132,12 @@ void DeviceStatusListener::NotifyNetworkChangeAfterDelay(
NotifyStatusChange();
}
+void DeviceStatusListener::BuildNetworkStatusListener() {
+#if defined(OS_ANDROID)
+ network_listener_ = base::MakeUnique<NetworkStatusListenerAndroid>();
+#else
+ network_listener_ = base::MakeUnique<NetworkStatusListenerImpl>();
+#endif
+}
+
} // namespace download
diff --git a/chromium/components/download/internal/scheduler/device_status_listener.h b/chromium/components/download/internal/scheduler/device_status_listener.h
index a14a28c6f84..af3c21a3411 100644
--- a/chromium/components/download/internal/scheduler/device_status_listener.h
+++ b/chromium/components/download/internal/scheduler/device_status_listener.h
@@ -5,17 +5,19 @@
#ifndef COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_LISTENER_H_
#define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_LISTENER_H_
+#include <memory>
+
#include "base/power_monitor/power_observer.h"
#include "base/timer/timer.h"
#include "components/download/internal/scheduler/device_status.h"
+#include "components/download/internal/scheduler/network_status_listener.h"
#include "net/base/network_change_notifier.h"
namespace download {
// Listens to network and battery status change and notifies the observer.
-class DeviceStatusListener
- : public net::NetworkChangeNotifier::ConnectionTypeObserver,
- public base::PowerObserver {
+class DeviceStatusListener : public NetworkStatusListener::Observer,
+ public base::PowerObserver {
public:
class Observer {
public:
@@ -23,7 +25,7 @@ class DeviceStatusListener
virtual void OnDeviceStatusChanged(const DeviceStatus& device_status) = 0;
};
- DeviceStatusListener(const base::TimeDelta& delay);
+ explicit DeviceStatusListener(const base::TimeDelta& delay);
~DeviceStatusListener() override;
// Returns the current device status for download scheduling.
@@ -35,6 +37,12 @@ class DeviceStatusListener
virtual void Stop();
protected:
+ // Creates the instance of |network_listener_|, visible for testing.
+ virtual void BuildNetworkStatusListener();
+
+ // Used to listen to network connectivity changes.
+ std::unique_ptr<NetworkStatusListener> network_listener_;
+
// The current device status.
DeviceStatus status_;
@@ -45,7 +53,7 @@ class DeviceStatusListener
bool listening_;
private:
- // net::NetworkChangeNotifier::ConnectionTypeObserver implementation.
+ // NetworkStatusListener::Observer implementation.
void OnConnectionTypeChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
diff --git a/chromium/components/download/internal/scheduler/device_status_listener_unittest.cc b/chromium/components/download/internal/scheduler/device_status_listener_unittest.cc
index 45fea61651c..e2f592f4247 100644
--- a/chromium/components/download/internal/scheduler/device_status_listener_unittest.cc
+++ b/chromium/components/download/internal/scheduler/device_status_listener_unittest.cc
@@ -51,14 +51,25 @@ class MockObserver : public DeviceStatusListener::Observer {
MOCK_METHOD1(OnDeviceStatusChanged, void(const DeviceStatus&));
};
+// Test target that only loads default implementation of NetworkStatusListener.
+class TestDeviceStatusListener : public DeviceStatusListener {
+ public:
+ explicit TestDeviceStatusListener(const base::TimeDelta& delay)
+ : DeviceStatusListener(delay) {}
+
+ void BuildNetworkStatusListener() override {
+ network_listener_ = base::MakeUnique<NetworkStatusListenerImpl>();
+ }
+};
+
class DeviceStatusListenerTest : public testing::Test {
public:
void SetUp() override {
power_monitor_ = base::MakeUnique<base::PowerMonitor>(
base::MakeUnique<base::PowerMonitorTestSource>());
- listener_ =
- base::MakeUnique<DeviceStatusListener>(base::TimeDelta::FromSeconds(0));
+ listener_ = base::MakeUnique<TestDeviceStatusListener>(
+ base::TimeDelta::FromSeconds(0));
}
void TearDown() override { listener_.reset(); }
diff --git a/chromium/components/download/internal/scheduler/network_status_listener.cc b/chromium/components/download/internal/scheduler/network_status_listener.cc
new file mode 100644
index 00000000000..c5d05f46643
--- /dev/null
+++ b/chromium/components/download/internal/scheduler/network_status_listener.cc
@@ -0,0 +1,45 @@
+// 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/download/internal/scheduler/network_status_listener.h"
+
+namespace download {
+
+NetworkStatusListener::NetworkStatusListener() = default;
+
+void NetworkStatusListener::Start(NetworkStatusListener::Observer* observer) {
+ observer_ = observer;
+}
+
+void NetworkStatusListener::Stop() {
+ observer_ = nullptr;
+}
+
+NetworkStatusListenerImpl::NetworkStatusListenerImpl() = default;
+
+NetworkStatusListenerImpl::~NetworkStatusListenerImpl() = default;
+
+void NetworkStatusListenerImpl::Start(
+ NetworkStatusListener::Observer* observer) {
+ NetworkStatusListener::Start(observer);
+ net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+}
+
+void NetworkStatusListenerImpl::Stop() {
+ net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+ NetworkStatusListener::Stop();
+}
+
+net::NetworkChangeNotifier::ConnectionType
+NetworkStatusListenerImpl::GetConnectionType() {
+ return net::NetworkChangeNotifier::GetConnectionType();
+}
+
+void NetworkStatusListenerImpl::OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ DCHECK(observer_);
+ observer_->OnConnectionTypeChanged(type);
+}
+
+} // namespace download
diff --git a/chromium/components/download/internal/scheduler/network_status_listener.h b/chromium/components/download/internal/scheduler/network_status_listener.h
new file mode 100644
index 00000000000..4d5a80d87fa
--- /dev/null
+++ b/chromium/components/download/internal/scheduler/network_status_listener.h
@@ -0,0 +1,77 @@
+// 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_DOWNLOAD_INTERNAL_SCHEDULER_NETWORK_STATUS_LISTENER_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_NETWORK_STATUS_LISTENER_H_
+
+#include "net/base/network_change_notifier.h"
+
+namespace download {
+
+// Monitor and propagate network status change events.
+// Base class only manages the observer pointer, derived class should override
+// to provide actual network hook to monitor the changes, and call base class
+// virtual functions.
+class NetworkStatusListener {
+ public:
+ // Observer to receive network connection type change notifications.
+ class Observer {
+ public:
+ virtual void OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // Starts to listen to network changes.
+ virtual void Start(Observer* observer);
+
+ // Stops to listen to network changes.
+ virtual void Stop();
+
+ // Gets the current connection type.
+ virtual net::NetworkChangeNotifier::ConnectionType GetConnectionType() = 0;
+
+ virtual ~NetworkStatusListener() {}
+
+ protected:
+ NetworkStatusListener();
+
+ // The only observer that listens to connection type change.
+ Observer* observer_ = nullptr;
+
+ // The current network status.
+ net::NetworkChangeNotifier::ConnectionType network_status_ =
+ net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkStatusListener);
+};
+
+// Default implementation of NetworkStatusListener using
+// net::NetworkChangeNotifier to listen to connectivity changes.
+class NetworkStatusListenerImpl
+ : public net::NetworkChangeNotifier::ConnectionTypeObserver,
+ public NetworkStatusListener {
+ public:
+ NetworkStatusListenerImpl();
+ ~NetworkStatusListenerImpl() override;
+
+ // NetworkStatusListener implementation.
+ void Start(NetworkStatusListener::Observer* observer) override;
+ void Stop() override;
+ net::NetworkChangeNotifier::ConnectionType GetConnectionType() override;
+
+ private:
+ // net::NetworkChangeNotifier::ConnectionTypeObserver implementation.
+ void OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkStatusListenerImpl);
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_NETWORK_STATUS_LISTENER_H_
diff --git a/chromium/components/download/internal/stats.cc b/chromium/components/download/internal/stats.cc
index 5b4f12c52a3..e58349d877a 100644
--- a/chromium/components/download/internal/stats.cc
+++ b/chromium/components/download/internal/stats.cc
@@ -207,7 +207,6 @@ void LogRecoveryOperation(Entry::State to_state) {
}
void LogDownloadCompletion(CompletionType type,
- const base::TimeDelta& time_span,
uint64_t file_size_bytes) {
// Records completion type.
UMA_HISTOGRAM_ENUMERATION("Download.Service.Finish.Type", type,
@@ -287,10 +286,13 @@ void LogFileCleanupStatus(FileCleanupReason reason,
base::UmaHistogramCounts100(name, external_cleanups);
}
-void LogFileLifeTime(const base::TimeDelta& file_life_time) {
+void LogFileLifeTime(const base::TimeDelta& file_life_time,
+ int num_cleanup_attempts) {
UMA_HISTOGRAM_CUSTOM_TIMES("Download.Service.Files.LifeTime", file_life_time,
base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromDays(8), 100);
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Download.Service.Files.Cleanup.Attempts",
+ num_cleanup_attempts);
}
void LogFileDirDiskUtilization(int64_t total_disk_space,
diff --git a/chromium/components/download/internal/stats.h b/chromium/components/download/internal/stats.h
index e100d35189d..55774d631a6 100644
--- a/chromium/components/download/internal/stats.h
+++ b/chromium/components/download/internal/stats.h
@@ -147,7 +147,6 @@ void LogRecoveryOperation(Entry::State to_state);
// Logs download completion event, download time, and the file size.
void LogDownloadCompletion(CompletionType type,
- const base::TimeDelta& time_span,
uint64_t file_size_bytes);
// Logs statistics about the result of a model operation. Used to track failure
@@ -172,7 +171,8 @@ void LogFileCleanupStatus(FileCleanupReason reason,
int external_cleanups);
// Logs the file life time for successfully completed download.
-void LogFileLifeTime(const base::TimeDelta& file_life_time);
+void LogFileLifeTime(const base::TimeDelta& file_life_time,
+ int num_cleanup_attempts);
// Logs the total disk space utilized by download files.
// This includes the total size of all the files in |file_dir|.
diff --git a/chromium/components/download/internal/test/BUILD.gn b/chromium/components/download/internal/test/BUILD.gn
index 99011eef401..798f419ef1a 100644
--- a/chromium/components/download/internal/test/BUILD.gn
+++ b/chromium/components/download/internal/test/BUILD.gn
@@ -3,7 +3,10 @@
# found in the LICENSE file.
source_set("test_support") {
- visibility = [ "//components/download/internal:unit_tests" ]
+ visibility = [
+ "//components/download/internal:unit_tests",
+ "//components/offline_pages/core/prefetch:unit_tests",
+ ]
testonly = true
@@ -18,6 +21,8 @@ source_set("test_support") {
"mock_client.h",
"mock_controller.cc",
"mock_controller.h",
+ "mock_download_service.cc",
+ "mock_download_service.h",
"mock_model_client.cc",
"mock_model_client.h",
"noop_store.cc",
@@ -26,6 +31,8 @@ source_set("test_support") {
"test_device_status_listener.h",
"test_download_driver.cc",
"test_download_driver.h",
+ "test_download_service.cc",
+ "test_download_service.h",
"test_store.cc",
"test_store.h",
]
@@ -34,6 +41,7 @@ source_set("test_support") {
"//base",
"//components/download/internal",
"//components/download/public",
+ "//net:test_support",
"//testing/gmock",
]
}
diff --git a/chromium/components/download/public/BUILD.gn b/chromium/components/download/public/BUILD.gn
index f51a715b16d..c394cbdc882 100644
--- a/chromium/components/download/public/BUILD.gn
+++ b/chromium/components/download/public/BUILD.gn
@@ -11,6 +11,8 @@ source_set("public") {
sources = [
"client.h",
"clients.h",
+ "download_metadata.cc",
+ "download_metadata.h",
"download_params.cc",
"download_params.h",
"download_service.h",
diff --git a/chromium/components/download/public/DEPS b/chromium/components/download/public/DEPS
index 5171a85caa1..6b96427e999 100644
--- a/chromium/components/download/public/DEPS
+++ b/chromium/components/download/public/DEPS
@@ -3,5 +3,6 @@ include_rules = [
"+base",
"+components/keyed_service",
"+net/http",
+ "+net/traffic_annotation",
"+url",
]
diff --git a/chromium/components/download/public/client.h b/chromium/components/download/public/client.h
index 518d7e223b3..beb929695d3 100644
--- a/chromium/components/download/public/client.h
+++ b/chromium/components/download/public/client.h
@@ -14,6 +14,9 @@
namespace download {
+struct CompletionInfo;
+struct DownloadMetaData;
+
// The Client interface required by any feature that wants to start a download
// through the DownloadService. Should be registered immediately at startup
// when the DownloadService is created (see the factory).
@@ -60,14 +63,15 @@ class Client {
virtual ~Client() = default;
// Called when the DownloadService is initialized and ready to be interacted
- // with. |outstanding_download_guids| is a list of all downloads the
- // DownloadService is aware of that are associated with this Client. If
- // |state_lost| is |true|, the service ran into an error initializing and had
- // to destroy all internal persisted state. At this point any saved files
+ // with. |downloads| is a list of all downloads the DownloadService is aware
+ // of that are associated with this Client, including in-progress downloads
+ // and recently completed downloads.
+ // If |state_lost| is |true|, the service ran into an error initializing and
+ // had to destroy all internal persisted state. At this point any saved files
// might not be available and any previously scheduled downloads are gone.
virtual void OnServiceInitialized(
bool state_lost,
- const std::vector<std::string>& outstanding_download_guids) = 0;
+ const std::vector<DownloadMetaData>& downloads) = 0;
// Called when the DownloadService fails to initialize and should not be used.
virtual void OnServiceUnavailable() = 0;
@@ -95,16 +99,23 @@ class Client {
virtual void OnDownloadFailed(const std::string& guid,
FailureReason reason) = 0;
- // Called when a download has been successfully completed. After this call
- // the download entry will be purged from the database. The file will be
- // automatically removed if it is not renamed or deleted after a window of
- // time (12 hours, but finch configurable). The timeout is meant to be a
- // failsafe to ensure that we clean up properly.
- // TODO(dtrainor): Investigate alternate output formats.
+ // Called when a download has been successfully completed.
+ // The file and the database record will be automatically removed if it is not
+ // renamed or deleted after a window of time (12 hours, but finch
+ // configurable).
+ // The timeout is meant to be a failsafe to ensure that we clean up properly.
// TODO(dtrainor): Point to finch configurable timeout when it is added.
virtual void OnDownloadSucceeded(const std::string& guid,
- const base::FilePath& path,
- uint64_t size) = 0;
+ const CompletionInfo& completion_info) = 0;
+
+ // Called by the service to ask the client whether it is okay to remove a
+ // completed file. If true, the file is deleted. If false, the file life time
+ // is granted another grace period (12 hours, configurable) after which
+ // the service will try again. If |force_delete| is true which happens when
+ // the file was completed too long ago, the file will be deleted regardless of
+ // the outcome of this function.
+ virtual bool CanServiceRemoveDownloadedFile(const std::string& guid,
+ bool force_delete) = 0;
};
} // namespace download
diff --git a/chromium/components/download/public/download_metadata.cc b/chromium/components/download/public/download_metadata.cc
new file mode 100644
index 00000000000..c5eb929a604
--- /dev/null
+++ b/chromium/components/download/public/download_metadata.cc
@@ -0,0 +1,31 @@
+// 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/download/public/download_metadata.h"
+
+namespace download {
+
+CompletionInfo::CompletionInfo(const base::FilePath& path,
+ uint64_t bytes_downloaded)
+ : path(path), bytes_downloaded(bytes_downloaded) {}
+
+CompletionInfo::CompletionInfo(const CompletionInfo& other) = default;
+
+CompletionInfo::~CompletionInfo() = default;
+
+bool CompletionInfo::operator==(const CompletionInfo& other) const {
+ return path == other.path && bytes_downloaded == other.bytes_downloaded;
+}
+
+DownloadMetaData::DownloadMetaData() = default;
+
+DownloadMetaData::DownloadMetaData(const DownloadMetaData& other) = default;
+
+bool DownloadMetaData::operator==(const DownloadMetaData& other) const {
+ return guid == other.guid && completion_info == other.completion_info;
+}
+
+DownloadMetaData::~DownloadMetaData() = default;
+
+} // namespace download
diff --git a/chromium/components/download/public/download_metadata.h b/chromium/components/download/public/download_metadata.h
new file mode 100644
index 00000000000..bcf01a87f9b
--- /dev/null
+++ b/chromium/components/download/public/download_metadata.h
@@ -0,0 +1,44 @@
+// 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_DOWNLOAD_PUBLIC_DOWNLOAD_METADATA_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_DOWNLOAD_METADATA_H_
+
+#include "base/files/file_path.h"
+#include "base/optional.h"
+
+namespace download {
+
+// Struct that contains information about successfully completed downloads.
+struct CompletionInfo {
+ // The file path for the download file.
+ base::FilePath path;
+
+ // Download file size in bytes.
+ uint64_t bytes_downloaded;
+
+ CompletionInfo(const base::FilePath& path, uint64_t bytes_downloaded);
+ CompletionInfo(const CompletionInfo& other);
+ ~CompletionInfo();
+ bool operator==(const CompletionInfo& other) const;
+};
+
+// Struct to describe general download status.
+struct DownloadMetaData {
+ // The GUID of the download.
+ std::string guid;
+
+ // Info about successfully completed download, or null for in-progress
+ // download. Failed download will not be persisted and exposed as meta data.
+ base::Optional<CompletionInfo> completion_info;
+
+ DownloadMetaData();
+ ~DownloadMetaData();
+ DownloadMetaData(const DownloadMetaData& other);
+ bool operator==(const DownloadMetaData& other) const;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_PUBLIC_DOWNLOAD_METADATA_H_
diff --git a/chromium/components/download/public/download_params.h b/chromium/components/download/public/download_params.h
index 217718efbc9..c6f74885617 100644
--- a/chromium/components/download/public/download_params.h
+++ b/chromium/components/download/public/download_params.h
@@ -9,6 +9,7 @@
#include "base/time/time.h"
#include "components/download/public/clients.h"
#include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "url/gurl.h"
namespace download {
@@ -143,8 +144,6 @@ struct DownloadParams {
DownloadClient client;
// A unique GUID that represents this download. See |base::GenerateGUID()|.
- // TODO(xingliu): guid in content download must be upper case, see
- // http://crbug.com/734818.
std::string guid;
// A callback that will be notified if this download has been accepted and
@@ -157,6 +156,9 @@ struct DownloadParams {
// The parameters that define the actual download request to make.
RequestParams request_params;
+
+ // Traffic annotation for the network request.
+ net::MutableNetworkTrafficAnnotationTag traffic_annotation;
};
} // namespace download
diff --git a/chromium/components/download/public/download_service.h b/chromium/components/download/public/download_service.h
index fdf8ac512bf..8954b75fe7a 100644
--- a/chromium/components/download/public/download_service.h
+++ b/chromium/components/download/public/download_service.h
@@ -76,8 +76,6 @@ class DownloadService : public KeyedService {
// Sends the download to the service. A callback to
// |DownloadParams::callback| will be triggered once the download has been
// persisted and saved in the service.
- // TODO(xingliu): Remove the limitation of upper case guid in
- // |download_params|, see http://crbug.com/734818.
virtual void StartDownload(const DownloadParams& download_params) = 0;
// Allows any feature to pause or resume downloads at will. Paused downloads
diff --git a/chromium/components/error_page/common/BUILD.gn b/chromium/components/error_page/common/BUILD.gn
index 16eaa845971..c91f2e64e28 100644
--- a/chromium/components/error_page/common/BUILD.gn
+++ b/chromium/components/error_page/common/BUILD.gn
@@ -4,6 +4,8 @@
static_library("common") {
sources = [
+ "error.cc",
+ "error.h",
"error_page_params.cc",
"error_page_params.h",
"error_page_switches.cc",
diff --git a/chromium/components/error_page/common/error.cc b/chromium/components/error_page/common/error.cc
new file mode 100644
index 00000000000..6bfce30e31b
--- /dev/null
+++ b/chromium/components/error_page/common/error.cc
@@ -0,0 +1,37 @@
+// 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/error_page/common/error.h"
+
+#include "net/base/net_errors.h"
+
+namespace error_page {
+
+const char Error::kHttpErrorDomain[] = "http";
+const char Error::kDnsProbeErrorDomain[] = "dnsprobe";
+
+Error Error::NetError(const GURL& url, int reason, bool stale_copy_in_cache) {
+ return Error(url, net::kErrorDomain, reason, stale_copy_in_cache);
+}
+
+Error Error::HttpError(const GURL& url, int http_status_code) {
+ return Error(url, kHttpErrorDomain, http_status_code, false);
+}
+
+Error Error::DnsProbeError(const GURL& url,
+ int status,
+ bool stale_copy_in_cache) {
+ return Error(url, kDnsProbeErrorDomain, status, stale_copy_in_cache);
+}
+
+Error::Error(const GURL& url,
+ const std::string& domain,
+ int reason,
+ bool stale_copy_in_cache)
+ : url_(url),
+ domain_(domain),
+ reason_(reason),
+ stale_copy_in_cache_(stale_copy_in_cache) {}
+
+} // namespace error_page
diff --git a/chromium/components/error_page/common/error.h b/chromium/components/error_page/common/error.h
new file mode 100644
index 00000000000..08c3de882bc
--- /dev/null
+++ b/chromium/components/error_page/common/error.h
@@ -0,0 +1,57 @@
+// 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_ERROR_PAGE_COMMON_ERROR_H_
+#define COMPONENTS_ERROR_PAGE_COMMON_ERROR_H_
+
+#include <string>
+
+#include "url/gurl.h"
+
+namespace error_page {
+
+// Represents an error info necessary to show an error page.
+// This class is a copiable value class.
+class Error {
+ public:
+ // Use net::kErroDomain for network errors.
+ // For http errors.
+ static const char kHttpErrorDomain[];
+ // For DNS probe errors.
+ static const char kDnsProbeErrorDomain[];
+
+ // Returns a net::kErrorDomain error.
+ static Error NetError(const GURL& url, int reason, bool stale_copy_in_cache);
+ // Returns a kHttpErrorDomain error.
+ static Error HttpError(const GURL& url, int status);
+ // Returns a kDnsProbeErrorDomain error.
+ static Error DnsProbeError(const GURL& url,
+ int status,
+ bool stale_copy_in_cache);
+
+ // Returns the url that failed to load.
+ const GURL& url() const { return url_; }
+ // Returns the domain of this error.
+ const std::string& domain() const { return domain_; }
+ // Returns a numeric error code. The meaning of this code depends on the
+ // domain string.
+ int reason() const { return reason_; }
+ // Returns true if chrome has a stale cache entry for the url.
+ bool stale_copy_in_cache() const { return stale_copy_in_cache_; }
+
+ private:
+ Error(const GURL& url,
+ const std::string& domain,
+ int reason,
+ bool stale_copy_in_cache);
+
+ GURL url_;
+ std::string domain_;
+ int reason_;
+ bool stale_copy_in_cache_;
+};
+
+} // namespace error_page
+
+#endif // COMPONENTS_ERROR_PAGE_COMMON_ERROR_H_
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index e0ac6f3399f..aed848b2550 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -20,6 +20,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "components/error_page/common/error.h"
#include "components/error_page/common/error_page_params.h"
#include "components/error_page/common/error_page_switches.h"
#include "components/error_page/common/net_error_info.h"
@@ -450,11 +451,11 @@ const LocalizedErrorMap* LookupErrorMap(const std::string& error_domain,
return FindErrorMapInArray(net_error_options,
arraysize(net_error_options),
error_code);
- } else if (error_domain == LocalizedError::kHttpErrorDomain) {
+ } else if (error_domain == Error::kHttpErrorDomain) {
return FindErrorMapInArray(http_error_options,
arraysize(http_error_options),
error_code);
- } else if (error_domain == error_page::kDnsProbeErrorDomain) {
+ } else if (error_domain == Error::kDnsProbeErrorDomain) {
const LocalizedErrorMap* map =
FindErrorMapInArray(dns_probe_error_options,
arraysize(dns_probe_error_options),
@@ -484,7 +485,7 @@ const char* GetIconClassForError(const std::string& error_domain,
if ((error_code == net::ERR_INTERNET_DISCONNECTED &&
error_domain == net::kErrorDomain) ||
(error_code == error_page::DNS_PROBE_FINISHED_NO_INTERNET &&
- error_domain == error_page::kDnsProbeErrorDomain))
+ error_domain == Error::kDnsProbeErrorDomain))
return "icon-offline";
return "icon-generic";
@@ -847,8 +848,6 @@ std::string HttpErrorCodeToString(int error) {
} // namespace
-const char LocalizedError::kHttpErrorDomain[] = "http";
-
void LocalizedError::GetStrings(
int error_code,
const std::string& error_domain,
@@ -882,8 +881,7 @@ void LocalizedError::GetStrings(
// ERR_ACCESS_DENIED to the map isn't sufficient, since that message may be
// generated by some OSs when the operation doesn't involve a file URL.
if (error_domain == net::kErrorDomain &&
- error_code == net::ERR_ACCESS_DENIED &&
- failed_url.scheme() == "file") {
+ error_code == net::ERR_ACCESS_DENIED && failed_url.scheme() == "file") {
options.heading_resource_id = IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED;
options.summary_resource_id = IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED;
options.suggestions = SUGGEST_NONE;
@@ -946,12 +944,12 @@ void LocalizedError::GetStrings(
if (error_domain == net::kErrorDomain) {
// Non-internationalized error string, for debugging Chrome itself.
error_string = base::ASCIIToUTF16(net::ErrorToShortString(error_code));
- } else if (error_domain == error_page::kDnsProbeErrorDomain) {
+ } else if (error_domain == Error::kDnsProbeErrorDomain) {
std::string ascii_error_string =
error_page::DnsProbeStatusToString(error_code);
error_string = base::ASCIIToUTF16(ascii_error_string);
} else {
- DCHECK_EQ(LocalizedError::kHttpErrorDomain, error_domain);
+ DCHECK_EQ(Error::kHttpErrorDomain, error_domain);
error_string = base::ASCIIToUTF16(HttpErrorCodeToString(error_code));
}
error_strings->SetString("errorCode", error_string);
diff --git a/chromium/components/error_page/common/localized_error.h b/chromium/components/error_page/common/localized_error.h
index 009771748ef..0126397a3d3 100644
--- a/chromium/components/error_page/common/localized_error.h
+++ b/chromium/components/error_page/common/localized_error.h
@@ -43,8 +43,6 @@ class LocalizedError {
// Returns true if an error page exists for the specified parameters.
static bool HasStrings(const std::string& error_domain, int error_code);
- static const char kHttpErrorDomain[];
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(LocalizedError);
diff --git a/chromium/components/error_page/common/net_error_info.cc b/chromium/components/error_page/common/net_error_info.cc
index 1ac72644b31..26870c5769a 100644
--- a/chromium/components/error_page/common/net_error_info.cc
+++ b/chromium/components/error_page/common/net_error_info.cc
@@ -9,8 +9,6 @@
namespace error_page {
-const char kDnsProbeErrorDomain[] = "dnsprobe";
-
const char* DnsProbeStatusToString(int status) {
switch (status) {
case DNS_PROBE_POSSIBLE:
diff --git a/chromium/components/error_page/common/net_error_info.h b/chromium/components/error_page/common/net_error_info.h
index a9d84262199..e72b710ab90 100644
--- a/chromium/components/error_page/common/net_error_info.h
+++ b/chromium/components/error_page/common/net_error_info.h
@@ -112,10 +112,6 @@ bool DnsProbeStatusIsFinished(DnsProbeStatus status);
// Record specific error page events.
void RecordEvent(NetworkErrorPageEvent event);
-// The error domain used to pass DNS probe statuses to the localized error
-// code.
-extern const char kDnsProbeErrorDomain[];
-
} // namespace error_page
#endif // COMPONENTS_ERROR_PAGE_COMMON_NET_ERROR_INFO_H_
diff --git a/chromium/components/error_page/renderer/BUILD.gn b/chromium/components/error_page/renderer/BUILD.gn
deleted file mode 100644
index d80faa9ddc4..00000000000
--- a/chromium/components/error_page/renderer/BUILD.gn
+++ /dev/null
@@ -1,42 +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.
-
-static_library("renderer") {
- sources = [
- "net_error_helper_core.cc",
- "net_error_helper_core.h",
- ]
-
- deps = [
- "//base",
- "//base:i18n",
- "//components/error_page/common",
- "//components/strings",
- "//components/url_formatter",
- "//content/public/common",
- "//net",
- "//third_party/WebKit/public:blink",
- "//ui/base",
- "//url",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "net_error_helper_core_unittest.cc",
- ]
-
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- ":renderer",
- "//base",
- "//base/test:test_support",
- "//components/error_page/common",
- "//content/public/common",
- "//net",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/error_page/renderer/DEPS b/chromium/components/error_page/renderer/DEPS
deleted file mode 100644
index a9b7cae6eb3..00000000000
--- a/chromium/components/error_page/renderer/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
- "+components/strings/grit/components_strings.h",
- "+components/url_formatter",
- "+content/public/common",
- "+net",
- "+third_party/WebKit/public/platform",
- "+ui/base",
-]
diff --git a/chromium/components/error_page/renderer/net_error_helper_core.cc b/chromium/components/error_page/renderer/net_error_helper_core.cc
deleted file mode 100644
index 89dff328466..00000000000
--- a/chromium/components/error_page/renderer/net_error_helper_core.cc
+++ /dev/null
@@ -1,1057 +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/error_page/renderer/net_error_helper_core.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/i18n/rtl.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_value_converter.h"
-#include "base/json/json_writer.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/error_page/common/error_page_params.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/url_formatter/url_formatter.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/escape.h"
-#include "net/base/net_errors.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURLError.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-#include "url/url_constants.h"
-
-namespace error_page {
-
-namespace {
-
-// |NetErrorNavigationCorrectionTypes| enum id for Web search query.
-// Other correction types uses the |kCorrectionResourceTable| array order.
-const int kWebSearchQueryUMAId = 100;
-
-// Number of URL correction suggestions to display.
-const int kMaxUrlCorrectionsToDisplay = 1;
-
-struct CorrectionTypeToResourceTable {
- int resource_id;
- const char* correction_type;
-};
-
-// Note: Ordering should be the same as |NetErrorNavigationCorrectionTypes| enum
-// in histograms.xml.
-const CorrectionTypeToResourceTable kCorrectionResourceTable[] = {
- {IDS_ERRORPAGES_SUGGESTION_VISIT_GOOGLE_CACHE, "cachedPage"},
- // "reloadPage" is has special handling.
- {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "urlCorrection"},
- {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "siteDomain"},
- {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "host"},
- {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "sitemap"},
- {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "pathParentFolder"},
- // "siteSearchQuery" is not yet supported.
- // TODO(mmenke): Figure out what format "siteSearchQuery" uses for its
- // suggestions.
- // "webSearchQuery" has special handling.
- {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "contentOverlap"},
- {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "emphasizedUrlCorrection"},
-};
-
-struct NavigationCorrection {
- NavigationCorrection() : is_porn(false), is_soft_porn(false) {
- }
-
- static void RegisterJSONConverter(
- base::JSONValueConverter<NavigationCorrection>* converter) {
- converter->RegisterStringField("correctionType",
- &NavigationCorrection::correction_type);
- converter->RegisterStringField("urlCorrection",
- &NavigationCorrection::url_correction);
- converter->RegisterStringField("clickType",
- &NavigationCorrection::click_type);
- converter->RegisterStringField("clickData",
- &NavigationCorrection::click_data);
- converter->RegisterBoolField("isPorn", &NavigationCorrection::is_porn);
- converter->RegisterBoolField("isSoftPorn",
- &NavigationCorrection::is_soft_porn);
- }
-
- std::string correction_type;
- std::string url_correction;
- std::string click_type;
- std::string click_data;
- bool is_porn;
- bool is_soft_porn;
-};
-
-struct NavigationCorrectionResponse {
- std::string event_id;
- std::string fingerprint;
- std::vector<std::unique_ptr<NavigationCorrection>> corrections;
-
- static void RegisterJSONConverter(
- base::JSONValueConverter<NavigationCorrectionResponse>* converter) {
- converter->RegisterStringField("result.eventId",
- &NavigationCorrectionResponse::event_id);
- converter->RegisterStringField("result.fingerprint",
- &NavigationCorrectionResponse::fingerprint);
- converter->RegisterRepeatedMessage(
- "result.UrlCorrections",
- &NavigationCorrectionResponse::corrections);
- }
-};
-
-base::TimeDelta GetAutoReloadTime(size_t reload_count) {
- static const int kDelaysMs[] = {
- 0, 5000, 30000, 60000, 300000, 600000, 1800000
- };
- if (reload_count >= arraysize(kDelaysMs))
- reload_count = arraysize(kDelaysMs) - 1;
- return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]);
-}
-
-// Returns whether |error| is a DNS-related error (and therefore whether
-// the tab helper should start a DNS probe after receiving it).
-bool IsBlinkDnsError(const blink::WebURLError& error) {
- return (error.domain.Utf8() == net::kErrorDomain) &&
- net::IsDnsError(error.reason);
-}
-
-GURL SanitizeURL(const GURL& url) {
- GURL::Replacements remove_params;
- remove_params.ClearUsername();
- remove_params.ClearPassword();
- remove_params.ClearQuery();
- remove_params.ClearRef();
- return url.ReplaceComponents(remove_params);
-}
-
-// Sanitizes and formats a URL for upload to the error correction service.
-std::string PrepareUrlForUpload(const GURL& url) {
- // TODO(yuusuke): Change to url_formatter::FormatUrl when Link Doctor becomes
- // unicode-capable.
- std::string spec_to_send = SanitizeURL(url).spec();
-
- // Notify navigation correction service of the url truncation by sending of
- // "?" at the end.
- if (url.has_query())
- spec_to_send.append("?");
- return spec_to_send;
-}
-
-// Given a WebURLError, returns true if the FixURL service should be used
-// for that error. Also sets |error_param| to the string that should be sent to
-// the FixURL service to identify the error type.
-bool ShouldUseFixUrlServiceForError(const blink::WebURLError& error,
- std::string* error_param) {
- error_param->clear();
-
- // Don't use the correction service for HTTPS (for privacy reasons).
- GURL unreachable_url(error.unreachable_url);
- if (GURL(unreachable_url).SchemeIsCryptographic())
- return false;
-
- std::string domain = error.domain.Utf8();
- if (domain == url::kHttpScheme && error.reason == 404) {
- *error_param = "http404";
- return true;
- }
- if (IsBlinkDnsError(error)) {
- *error_param = "dnserror";
- return true;
- }
- if (domain == net::kErrorDomain &&
- (error.reason == net::ERR_CONNECTION_FAILED ||
- error.reason == net::ERR_CONNECTION_REFUSED ||
- error.reason == net::ERR_ADDRESS_UNREACHABLE ||
- error.reason == net::ERR_CONNECTION_TIMED_OUT)) {
- *error_param = "connectionFailure";
- return true;
- }
- return false;
-}
-
-// Creates a request body for use with the fixurl service. Sets parameters
-// shared by all types of requests to the service. |correction_params| must
-// contain the parameters specific to the actual request type.
-std::string CreateRequestBody(
- const std::string& method,
- const std::string& error_param,
- const NetErrorHelperCore::NavigationCorrectionParams& correction_params,
- std::unique_ptr<base::DictionaryValue> params_dict) {
- // Set params common to all request types.
- params_dict->SetString("key", correction_params.api_key);
- params_dict->SetString("clientName", "chrome");
- params_dict->SetString("error", error_param);
-
- if (!correction_params.language.empty())
- params_dict->SetString("language", correction_params.language);
-
- if (!correction_params.country_code.empty())
- params_dict->SetString("originCountry", correction_params.country_code);
-
- base::DictionaryValue request_dict;
- request_dict.SetString("method", method);
- request_dict.SetString("apiVersion", "v1");
- request_dict.Set("params", std::move(params_dict));
-
- std::string request_body;
- bool success = base::JSONWriter::Write(request_dict, &request_body);
- DCHECK(success);
- return request_body;
-}
-
-// If URL correction information should be retrieved remotely for a main frame
-// load that failed with |error|, returns true and sets
-// |correction_request_body| to be the body for the correction request.
-std::string CreateFixUrlRequestBody(
- const blink::WebURLError& error,
- const NetErrorHelperCore::NavigationCorrectionParams& correction_params) {
- std::string error_param;
- bool result = ShouldUseFixUrlServiceForError(error, &error_param);
- DCHECK(result);
-
- // TODO(mmenke): Investigate open sourcing the relevant protocol buffers and
- // using those directly instead.
- std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
- params->SetString("urlQuery", PrepareUrlForUpload(error.unreachable_url));
- return CreateRequestBody("linkdoctor.fixurl.fixurl", error_param,
- correction_params, std::move(params));
-}
-
-std::string CreateClickTrackingUrlRequestBody(
- const blink::WebURLError& error,
- const NetErrorHelperCore::NavigationCorrectionParams& correction_params,
- const NavigationCorrectionResponse& response,
- const NavigationCorrection& correction) {
- std::string error_param;
- bool result = ShouldUseFixUrlServiceForError(error, &error_param);
- DCHECK(result);
-
- std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
-
- params->SetString("originalUrlQuery",
- PrepareUrlForUpload(error.unreachable_url));
-
- params->SetString("clickedUrlCorrection", correction.url_correction);
- params->SetString("clickType", correction.click_type);
- params->SetString("clickData", correction.click_data);
-
- params->SetString("eventId", response.event_id);
- params->SetString("fingerprint", response.fingerprint);
-
- return CreateRequestBody("linkdoctor.fixurl.clicktracking", error_param,
- correction_params, std::move(params));
-}
-
-base::string16 FormatURLForDisplay(const GURL& url, bool is_rtl) {
- // Translate punycode into UTF8, unescape UTF8 URLs.
- base::string16 url_for_display(url_formatter::FormatUrl(
- url, url_formatter::kFormatUrlOmitNothing,
- net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr));
- // URLs are always LTR.
- if (is_rtl)
- base::i18n::WrapStringWithLTRFormatting(&url_for_display);
- return url_for_display;
-}
-
-std::unique_ptr<NavigationCorrectionResponse> ParseNavigationCorrectionResponse(
- const std::string raw_response) {
- // TODO(mmenke): Open source related protocol buffers and use them directly.
- std::unique_ptr<base::Value> parsed = base::JSONReader::Read(raw_response);
- std::unique_ptr<NavigationCorrectionResponse> response(
- new NavigationCorrectionResponse());
- base::JSONValueConverter<NavigationCorrectionResponse> converter;
- if (!parsed || !converter.Convert(*parsed, response.get()))
- response.reset();
- return response;
-}
-
-void LogCorrectionTypeShown(int type_id) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.ErrorPageCounts.NavigationCorrectionLinksShown", type_id,
- kWebSearchQueryUMAId + 1);
-}
-
-std::unique_ptr<ErrorPageParams> CreateErrorPageParams(
- const NavigationCorrectionResponse& response,
- const blink::WebURLError& error,
- const NetErrorHelperCore::NavigationCorrectionParams& correction_params,
- bool is_rtl) {
- // Version of URL for display in suggestions. It has to be sanitized first
- // because any received suggestions will be relative to the sanitized URL.
- base::string16 original_url_for_display =
- FormatURLForDisplay(SanitizeURL(GURL(error.unreachable_url)), is_rtl);
-
- std::unique_ptr<ErrorPageParams> params(new ErrorPageParams());
- params->override_suggestions.reset(new base::ListValue());
- std::unique_ptr<base::ListValue> parsed_corrections(new base::ListValue());
- for (auto it = response.corrections.begin(); it != response.corrections.end();
- ++it) {
- // Doesn't seem like a good idea to show these.
- if ((*it)->is_porn || (*it)->is_soft_porn)
- continue;
-
- int tracking_id = it - response.corrections.begin();
-
- if ((*it)->correction_type == "reloadPage") {
- params->suggest_reload = true;
- params->reload_tracking_id = tracking_id;
- continue;
- }
-
- if ((*it)->correction_type == "webSearchQuery") {
- // If there are multiple searches suggested, use the first suggestion.
- if (params->search_terms.empty()) {
- params->search_url = correction_params.search_url;
- params->search_terms = (*it)->url_correction;
- params->search_tracking_id = tracking_id;
- LogCorrectionTypeShown(kWebSearchQueryUMAId);
- }
- continue;
- }
-
- // Allow reload page and web search query to be empty strings, but not
- // links.
- if ((*it)->url_correction.empty() ||
- (params->override_suggestions->GetSize() >=
- kMaxUrlCorrectionsToDisplay)) {
- continue;
- }
-
- size_t correction_index;
- for (correction_index = 0;
- correction_index < arraysize(kCorrectionResourceTable);
- ++correction_index) {
- if ((*it)->correction_type !=
- kCorrectionResourceTable[correction_index].correction_type) {
- continue;
- }
- std::unique_ptr<base::DictionaryValue> suggest(
- new base::DictionaryValue());
- suggest->SetString("summary",
- l10n_util::GetStringUTF16(
- kCorrectionResourceTable[correction_index].resource_id));
- suggest->SetString("urlCorrection", (*it)->url_correction);
- suggest->SetString(
- "urlCorrectionForDisplay",
- FormatURLForDisplay(GURL((*it)->url_correction), is_rtl));
- suggest->SetString("originalUrlForDisplay", original_url_for_display);
- suggest->SetInteger("trackingId", tracking_id);
- suggest->SetInteger("type", static_cast<int>(correction_index));
-
- params->override_suggestions->Append(std::move(suggest));
- LogCorrectionTypeShown(static_cast<int>(correction_index));
- break;
- }
- }
-
- if (params->override_suggestions->empty() && !params->search_url.is_valid())
- params.reset();
- return params;
-}
-
-void ReportAutoReloadSuccess(const blink::WebURLError& error, size_t count) {
- if (error.domain.Utf8() != net::kErrorDomain)
- return;
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AutoReload.ErrorAtSuccess", -error.reason);
- UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess",
- static_cast<base::HistogramBase::Sample>(count));
- if (count == 1) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AutoReload.ErrorAtFirstSuccess",
- -error.reason);
- }
-}
-
-void ReportAutoReloadFailure(const blink::WebURLError& error, size_t count) {
- if (error.domain.Utf8() != net::kErrorDomain)
- return;
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AutoReload.ErrorAtStop", -error.reason);
- UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop",
- static_cast<base::HistogramBase::Sample>(count));
-}
-
-// Tracks navigation correction service usage in UMA to enable more in depth
-// analysis.
-void TrackClickUMA(std::string type_id) {
- // Web search suggestion isn't in |kCorrectionResourceTable| array.
- if (type_id == "webSearchQuery") {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.ErrorPageCounts.NavigationCorrectionLinksUsed",
- kWebSearchQueryUMAId, kWebSearchQueryUMAId + 1);
- return;
- }
-
- size_t correction_index;
- for (correction_index = 0;
- correction_index < arraysize(kCorrectionResourceTable);
- ++correction_index) {
- if (kCorrectionResourceTable[correction_index].correction_type ==
- type_id) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.ErrorPageCounts.NavigationCorrectionLinksUsed",
- static_cast<int>(correction_index), kWebSearchQueryUMAId + 1);
- break;
- }
- }
-}
-
-} // namespace
-
-struct NetErrorHelperCore::ErrorPageInfo {
- ErrorPageInfo(blink::WebURLError error,
- bool was_failed_post,
- bool was_ignoring_cache)
- : error(error),
- was_failed_post(was_failed_post),
- was_ignoring_cache(was_ignoring_cache),
- needs_dns_updates(false),
- needs_load_navigation_corrections(false),
- reload_button_in_page(false),
- show_saved_copy_button_in_page(false),
- show_cached_copy_button_in_page(false),
- download_button_in_page(false),
- is_finished_loading(false),
- auto_reload_triggered(false) {}
-
- // Information about the failed page load.
- blink::WebURLError error;
- bool was_failed_post;
- bool was_ignoring_cache;
-
- // Information about the status of the error page.
-
- // True if a page is a DNS error page and has not yet received a final DNS
- // probe status.
- bool needs_dns_updates;
-
- // True if a blank page was loaded, and navigation corrections need to be
- // loaded to generate the real error page.
- bool needs_load_navigation_corrections;
-
- // Navigation correction service paramers, which will be used in response to
- // certain types of network errors. They are all stored here in case they
- // change over the course of displaying the error page.
- std::unique_ptr<NetErrorHelperCore::NavigationCorrectionParams>
- navigation_correction_params;
-
- std::unique_ptr<NavigationCorrectionResponse> navigation_correction_response;
-
- // All the navigation corrections that have been clicked, for tracking
- // purposes.
- std::set<int> clicked_corrections;
-
- // Track if specific buttons are included in an error page, for statistics.
- bool reload_button_in_page;
- bool show_saved_copy_button_in_page;
- bool show_cached_copy_button_in_page;
- bool download_button_in_page;
-
- // True if a page has completed loading, at which point it can receive
- // updates.
- bool is_finished_loading;
-
- // True if the auto-reload timer has fired and a reload is or has been in
- // flight.
- bool auto_reload_triggered;
-};
-
-NetErrorHelperCore::NavigationCorrectionParams::NavigationCorrectionParams() {
-}
-
-NetErrorHelperCore::NavigationCorrectionParams::NavigationCorrectionParams(
- const NavigationCorrectionParams& other) = default;
-
-NetErrorHelperCore::NavigationCorrectionParams::~NavigationCorrectionParams() {
-}
-
-bool NetErrorHelperCore::IsReloadableError(
- const NetErrorHelperCore::ErrorPageInfo& info) {
- GURL url = info.error.unreachable_url;
- return info.error.domain.Utf8() == net::kErrorDomain &&
- info.error.reason != net::ERR_ABORTED &&
- // For now, net::ERR_UNKNOWN_URL_SCHEME is only being displayed on
- // Chrome for Android.
- info.error.reason != net::ERR_UNKNOWN_URL_SCHEME &&
- // Do not trigger if the server rejects a client certificate.
- // https://crbug.com/431387
- !net::IsClientCertificateError(info.error.reason) &&
- // Some servers reject client certificates with a generic
- // handshake_failure alert.
- // https://crbug.com/431387
- info.error.reason != net::ERR_SSL_PROTOCOL_ERROR &&
- // Do not trigger for XSS Auditor violations.
- info.error.reason != net::ERR_BLOCKED_BY_XSS_AUDITOR &&
- !info.was_failed_post &&
- // Don't auto-reload non-http/https schemas.
- // https://crbug.com/471713
- url.SchemeIsHTTPOrHTTPS();
-}
-
-NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate,
- bool auto_reload_enabled,
- bool auto_reload_visible_only,
- bool is_visible)
- : delegate_(delegate),
- last_probe_status_(DNS_PROBE_POSSIBLE),
- can_show_network_diagnostics_dialog_(false),
- auto_reload_enabled_(auto_reload_enabled),
- auto_reload_visible_only_(auto_reload_visible_only),
- auto_reload_timer_(new base::Timer(false, false)),
- auto_reload_paused_(false),
- auto_reload_in_flight_(false),
- uncommitted_load_started_(false),
- // TODO(ellyjones): Make online_ accurate at object creation.
- online_(true),
- visible_(is_visible),
- auto_reload_count_(0),
- navigation_from_button_(NO_BUTTON) {
-}
-
-NetErrorHelperCore::~NetErrorHelperCore() {
- if (committed_error_page_info_ &&
- committed_error_page_info_->auto_reload_triggered) {
- ReportAutoReloadFailure(committed_error_page_info_->error,
- auto_reload_count_);
- }
-}
-
-void NetErrorHelperCore::CancelPendingFetches() {
- // Cancel loading the alternate error page, and prevent any pending error page
- // load from starting a new error page load. Swapping in the error page when
- // it's finished loading could abort the navigation, otherwise.
- if (committed_error_page_info_)
- committed_error_page_info_->needs_load_navigation_corrections = false;
- if (pending_error_page_info_)
- pending_error_page_info_->needs_load_navigation_corrections = false;
- delegate_->CancelFetchNavigationCorrections();
- auto_reload_timer_->Stop();
- auto_reload_paused_ = false;
-}
-
-void NetErrorHelperCore::OnStop() {
- if (committed_error_page_info_ &&
- committed_error_page_info_->auto_reload_triggered) {
- ReportAutoReloadFailure(committed_error_page_info_->error,
- auto_reload_count_);
- }
- CancelPendingFetches();
- uncommitted_load_started_ = false;
- auto_reload_count_ = 0;
- auto_reload_in_flight_ = false;
-}
-
-void NetErrorHelperCore::OnWasShown() {
- visible_ = true;
- if (!auto_reload_visible_only_)
- return;
- if (auto_reload_paused_)
- MaybeStartAutoReloadTimer();
-}
-
-void NetErrorHelperCore::OnWasHidden() {
- visible_ = false;
- if (!auto_reload_visible_only_)
- return;
- PauseAutoReloadTimer();
-}
-
-void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) {
- if (frame_type != MAIN_FRAME)
- return;
-
- uncommitted_load_started_ = true;
-
- // If there's no pending error page information associated with the page load,
- // or the new page is not an error page, then reset pending error page state.
- if (!pending_error_page_info_ || page_type != ERROR_PAGE)
- CancelPendingFetches();
-}
-
-void NetErrorHelperCore::OnCommitLoad(FrameType frame_type, const GURL& url) {
- if (frame_type != MAIN_FRAME)
- return;
-
- // If a page is committing, either it's an error page and autoreload will be
- // started again below, or it's a success page and we need to clear autoreload
- // state.
- auto_reload_in_flight_ = false;
-
- // uncommitted_load_started_ could already be false, since RenderFrameImpl
- // calls OnCommitLoad once for each in-page navigation (like a fragment
- // change) with no corresponding OnStartLoad.
- uncommitted_load_started_ = false;
-
- // Track if an error occurred due to a page button press.
- // This isn't perfect; if (for instance), the server is slow responding
- // to a request generated from the page reload button, and the user hits
- // the browser reload button, this code will still believe the
- // result is from the page reload button.
- if (committed_error_page_info_ && pending_error_page_info_ &&
- navigation_from_button_ != NO_BUTTON &&
- committed_error_page_info_->error.unreachable_url ==
- pending_error_page_info_->error.unreachable_url) {
- DCHECK(navigation_from_button_ == RELOAD_BUTTON ||
- navigation_from_button_ == SHOW_SAVED_COPY_BUTTON);
- RecordEvent(navigation_from_button_ == RELOAD_BUTTON ?
- NETWORK_ERROR_PAGE_RELOAD_BUTTON_ERROR :
- NETWORK_ERROR_PAGE_SHOW_SAVED_COPY_BUTTON_ERROR);
- }
- navigation_from_button_ = NO_BUTTON;
-
- if (committed_error_page_info_ && !pending_error_page_info_ &&
- committed_error_page_info_->auto_reload_triggered) {
- const blink::WebURLError& error = committed_error_page_info_->error;
- const GURL& error_url = error.unreachable_url;
- if (url == error_url)
- ReportAutoReloadSuccess(error, auto_reload_count_);
- else if (url != content::kUnreachableWebDataURL)
- ReportAutoReloadFailure(error, auto_reload_count_);
- }
-
- committed_error_page_info_ = std::move(pending_error_page_info_);
-}
-
-void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) {
- if (frame_type != MAIN_FRAME)
- return;
-
- if (!committed_error_page_info_) {
- auto_reload_count_ = 0;
- return;
- }
-
- committed_error_page_info_->is_finished_loading = true;
-
- RecordEvent(NETWORK_ERROR_PAGE_SHOWN);
- if (committed_error_page_info_->reload_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_RELOAD_BUTTON_SHOWN);
- }
- if (committed_error_page_info_->show_saved_copy_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_SHOW_SAVED_COPY_BUTTON_SHOWN);
- }
- if (committed_error_page_info_->download_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_DOWNLOAD_BUTTON_SHOWN);
- }
- if (committed_error_page_info_->reload_button_in_page &&
- committed_error_page_info_->show_saved_copy_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_BOTH_BUTTONS_SHOWN);
- }
- if (committed_error_page_info_->show_cached_copy_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_CACHED_COPY_BUTTON_SHOWN);
- }
-
- delegate_->SetIsShowingDownloadButton(
- committed_error_page_info_->download_button_in_page);
-
- delegate_->EnablePageHelperFunctions();
-
- if (committed_error_page_info_->needs_load_navigation_corrections) {
- // If there is another pending error page load, |fix_url| should have been
- // cleared.
- DCHECK(!pending_error_page_info_);
- DCHECK(!committed_error_page_info_->needs_dns_updates);
- delegate_->FetchNavigationCorrections(
- committed_error_page_info_->navigation_correction_params->url,
- CreateFixUrlRequestBody(
- committed_error_page_info_->error,
- *committed_error_page_info_->navigation_correction_params));
- } else if (auto_reload_enabled_ &&
- IsReloadableError(*committed_error_page_info_)) {
- MaybeStartAutoReloadTimer();
- }
-
- if (!committed_error_page_info_->needs_dns_updates ||
- last_probe_status_ == DNS_PROBE_POSSIBLE) {
- return;
- }
- DVLOG(1) << "Error page finished loading; sending saved status.";
- UpdateErrorPage();
-}
-
-void NetErrorHelperCore::GetErrorHTML(FrameType frame_type,
- const blink::WebURLError& error,
- bool is_failed_post,
- bool is_ignoring_cache,
- std::string* error_html) {
- if (frame_type == MAIN_FRAME) {
- // If navigation corrections were needed before, that should have been
- // cancelled earlier by starting a new page load (Which has now failed).
- DCHECK(!committed_error_page_info_ ||
- !committed_error_page_info_->needs_load_navigation_corrections);
-
- pending_error_page_info_.reset(
- new ErrorPageInfo(error, is_failed_post, is_ignoring_cache));
- pending_error_page_info_->navigation_correction_params.reset(
- new NavigationCorrectionParams(navigation_correction_params_));
- GetErrorHtmlForMainFrame(pending_error_page_info_.get(), error_html);
- } else {
- // These values do not matter, as error pages in iframes hide the buttons.
- bool reload_button_in_page;
- bool show_saved_copy_button_in_page;
- bool show_cached_copy_button_in_page;
- bool download_button_in_page;
-
- delegate_->GenerateLocalizedErrorPage(
- error, is_failed_post,
- false /* No diagnostics dialogs allowed for subframes. */, nullptr,
- &reload_button_in_page, &show_saved_copy_button_in_page,
- &show_cached_copy_button_in_page, &download_button_in_page,
- error_html);
- }
-}
-
-void NetErrorHelperCore::OnNetErrorInfo(DnsProbeStatus status) {
- DCHECK_NE(DNS_PROBE_POSSIBLE, status);
-
- last_probe_status_ = status;
-
- if (!committed_error_page_info_ ||
- !committed_error_page_info_->needs_dns_updates ||
- !committed_error_page_info_->is_finished_loading) {
- return;
- }
-
- UpdateErrorPage();
-}
-
-void NetErrorHelperCore::OnSetCanShowNetworkDiagnosticsDialog(
- bool can_show_network_diagnostics_dialog) {
- can_show_network_diagnostics_dialog_ = can_show_network_diagnostics_dialog;
-}
-
-void NetErrorHelperCore::OnSetNavigationCorrectionInfo(
- const GURL& navigation_correction_url,
- const std::string& language,
- const std::string& country_code,
- const std::string& api_key,
- const GURL& search_url) {
- navigation_correction_params_.url = navigation_correction_url;
- navigation_correction_params_.language = language;
- navigation_correction_params_.country_code = country_code;
- navigation_correction_params_.api_key = api_key;
- navigation_correction_params_.search_url = search_url;
-}
-
-void NetErrorHelperCore::GetErrorHtmlForMainFrame(
- ErrorPageInfo* pending_error_page_info,
- std::string* error_html) {
- std::string error_param;
- blink::WebURLError error = pending_error_page_info->error;
-
- if (pending_error_page_info->navigation_correction_params &&
- pending_error_page_info->navigation_correction_params->url.is_valid() &&
- ShouldUseFixUrlServiceForError(error, &error_param)) {
- pending_error_page_info->needs_load_navigation_corrections = true;
- return;
- }
-
- if (IsBlinkDnsError(pending_error_page_info->error)) {
- // The last probe status needs to be reset if this is a DNS error. This
- // means that if a DNS error page is committed but has not yet finished
- // loading, a DNS probe status scheduled to be sent to it may be thrown
- // out, but since the new error page should trigger a new DNS probe, it
- // will just get the results for the next page load.
- last_probe_status_ = DNS_PROBE_POSSIBLE;
- pending_error_page_info->needs_dns_updates = true;
- error = GetUpdatedError(error);
- }
-
- delegate_->GenerateLocalizedErrorPage(
- error, pending_error_page_info->was_failed_post,
- can_show_network_diagnostics_dialog_, nullptr,
- &pending_error_page_info->reload_button_in_page,
- &pending_error_page_info->show_saved_copy_button_in_page,
- &pending_error_page_info->show_cached_copy_button_in_page,
- &pending_error_page_info->download_button_in_page, error_html);
-}
-
-void NetErrorHelperCore::UpdateErrorPage() {
- DCHECK(committed_error_page_info_->needs_dns_updates);
- DCHECK(committed_error_page_info_->is_finished_loading);
- DCHECK_NE(DNS_PROBE_POSSIBLE, last_probe_status_);
-
- UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus",
- last_probe_status_,
- DNS_PROBE_MAX);
- // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a
- // final status code. Once one is reached, the page does not need further
- // updates.
- if (last_probe_status_ != DNS_PROBE_STARTED)
- committed_error_page_info_->needs_dns_updates = false;
-
- // There is no need to worry about the button display statistics here because
- // the presentation of the reload and show saved copy buttons can't be changed
- // by a DNS error update.
- delegate_->UpdateErrorPage(
- GetUpdatedError(committed_error_page_info_->error),
- committed_error_page_info_->was_failed_post,
- can_show_network_diagnostics_dialog_);
-}
-
-void NetErrorHelperCore::OnNavigationCorrectionsFetched(
- const std::string& corrections,
- bool is_rtl) {
- // Loading suggestions only starts when a blank error page finishes loading,
- // and is cancelled with a new load.
- DCHECK(!pending_error_page_info_);
- DCHECK(committed_error_page_info_->is_finished_loading);
- DCHECK(committed_error_page_info_->needs_load_navigation_corrections);
- DCHECK(committed_error_page_info_->navigation_correction_params);
-
- pending_error_page_info_.reset(new ErrorPageInfo(
- committed_error_page_info_->error,
- committed_error_page_info_->was_failed_post,
- committed_error_page_info_->was_ignoring_cache));
- pending_error_page_info_->navigation_correction_response =
- ParseNavigationCorrectionResponse(corrections);
-
- std::string error_html;
- std::unique_ptr<ErrorPageParams> params;
- if (pending_error_page_info_->navigation_correction_response) {
- // Copy navigation correction parameters used for the request, so tracking
- // requests can still be sent if the configuration changes.
- pending_error_page_info_->navigation_correction_params.reset(
- new NavigationCorrectionParams(
- *committed_error_page_info_->navigation_correction_params));
- params = CreateErrorPageParams(
- *pending_error_page_info_->navigation_correction_response,
- pending_error_page_info_->error,
- *pending_error_page_info_->navigation_correction_params, is_rtl);
- delegate_->GenerateLocalizedErrorPage(
- pending_error_page_info_->error,
- pending_error_page_info_->was_failed_post,
- can_show_network_diagnostics_dialog_,
- std::move(params), &pending_error_page_info_->reload_button_in_page,
- &pending_error_page_info_->show_saved_copy_button_in_page,
- &pending_error_page_info_->show_cached_copy_button_in_page,
- &pending_error_page_info_->download_button_in_page,
- &error_html);
- } else {
- // Since |navigation_correction_params| in |pending_error_page_info_| is
- // NULL, this won't trigger another attempt to load corrections.
- GetErrorHtmlForMainFrame(pending_error_page_info_.get(), &error_html);
- }
-
- // TODO(mmenke): Once the new API is in place, look into replacing this
- // double page load by just updating the error page, like DNS
- // probes do.
- delegate_->LoadErrorPage(error_html,
- pending_error_page_info_->error.unreachable_url);
-}
-
-blink::WebURLError NetErrorHelperCore::GetUpdatedError(
- const blink::WebURLError& error) const {
- // If a probe didn't run or wasn't conclusive, restore the original error.
- if (last_probe_status_ == DNS_PROBE_NOT_RUN ||
- last_probe_status_ == DNS_PROBE_FINISHED_INCONCLUSIVE) {
- return error;
- }
-
- blink::WebURLError updated_error;
- updated_error.domain = blink::WebString::FromUTF8(kDnsProbeErrorDomain);
- updated_error.reason = last_probe_status_;
- updated_error.unreachable_url = error.unreachable_url;
- updated_error.stale_copy_in_cache = error.stale_copy_in_cache;
-
- return updated_error;
-}
-
-void NetErrorHelperCore::Reload(bool bypass_cache) {
- if (!committed_error_page_info_) {
- return;
- }
- delegate_->ReloadPage(bypass_cache);
-}
-
-bool NetErrorHelperCore::MaybeStartAutoReloadTimer() {
- if (!committed_error_page_info_ ||
- !committed_error_page_info_->is_finished_loading ||
- pending_error_page_info_ ||
- uncommitted_load_started_) {
- return false;
- }
-
- StartAutoReloadTimer();
- return true;
-}
-
-void NetErrorHelperCore::StartAutoReloadTimer() {
- DCHECK(committed_error_page_info_);
- DCHECK(IsReloadableError(*committed_error_page_info_));
-
- committed_error_page_info_->auto_reload_triggered = true;
-
- if (!online_ || (!visible_ && auto_reload_visible_only_)) {
- auto_reload_paused_ = true;
- return;
- }
-
- auto_reload_paused_ = false;
- base::TimeDelta delay = GetAutoReloadTime(auto_reload_count_);
- auto_reload_timer_->Stop();
- auto_reload_timer_->Start(FROM_HERE, delay,
- base::Bind(&NetErrorHelperCore::AutoReloadTimerFired,
- base::Unretained(this)));
-}
-
-void NetErrorHelperCore::AutoReloadTimerFired() {
- // AutoReloadTimerFired only runs if:
- // 1. StartAutoReloadTimer was previously called, which requires that
- // committed_error_page_info_ is populated;
- // 2. No other page load has started since (1), since OnStartLoad stops the
- // auto-reload timer.
- DCHECK(committed_error_page_info_);
-
- auto_reload_count_++;
- auto_reload_in_flight_ = true;
- Reload(committed_error_page_info_->was_ignoring_cache);
-}
-
-void NetErrorHelperCore::PauseAutoReloadTimer() {
- if (!auto_reload_timer_->IsRunning())
- return;
- DCHECK(committed_error_page_info_);
- DCHECK(!auto_reload_paused_);
- DCHECK(committed_error_page_info_->auto_reload_triggered);
- auto_reload_timer_->Stop();
- auto_reload_paused_ = true;
-}
-
-void NetErrorHelperCore::NetworkStateChanged(bool online) {
- bool was_online = online_;
- online_ = online;
- if (!was_online && online) {
- // Transitioning offline -> online
- if (auto_reload_paused_)
- MaybeStartAutoReloadTimer();
- } else if (was_online && !online) {
- // Transitioning online -> offline
- if (auto_reload_timer_->IsRunning())
- auto_reload_count_ = 0;
- PauseAutoReloadTimer();
- }
-}
-
-bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type,
- const GURL& url) {
- // Don't suppress child frame errors.
- if (frame_type != MAIN_FRAME)
- return false;
-
- // If there's no auto reload attempt in flight, this error page didn't come
- // from auto reload, so don't suppress it.
- if (!auto_reload_in_flight_)
- return false;
-
- uncommitted_load_started_ = false;
- // This serves to terminate the auto-reload in flight attempt. If
- // ShouldSuppressErrorPage is called, the auto-reload yielded an error, which
- // means the request was already sent.
- auto_reload_in_flight_ = false;
- MaybeStartAutoReloadTimer();
- return true;
-}
-
-void NetErrorHelperCore::ExecuteButtonPress(Button button) {
- // If there's no committed error page, should not be invoked.
- DCHECK(committed_error_page_info_);
-
- switch (button) {
- case RELOAD_BUTTON:
- RecordEvent(NETWORK_ERROR_PAGE_RELOAD_BUTTON_CLICKED);
- if (committed_error_page_info_->show_saved_copy_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_BOTH_BUTTONS_RELOAD_CLICKED);
- }
- navigation_from_button_ = RELOAD_BUTTON;
- Reload(false);
- return;
- case SHOW_SAVED_COPY_BUTTON:
- RecordEvent(NETWORK_ERROR_PAGE_SHOW_SAVED_COPY_BUTTON_CLICKED);
- navigation_from_button_ = SHOW_SAVED_COPY_BUTTON;
- if (committed_error_page_info_->reload_button_in_page) {
- RecordEvent(NETWORK_ERROR_PAGE_BOTH_BUTTONS_SHOWN_SAVED_COPY_CLICKED);
- }
- delegate_->LoadPageFromCache(
- committed_error_page_info_->error.unreachable_url);
- return;
- case MORE_BUTTON:
- // Visual effects on page are handled in Javascript code.
- RecordEvent(NETWORK_ERROR_PAGE_MORE_BUTTON_CLICKED);
- return;
- case EASTER_EGG:
- RecordEvent(NETWORK_ERROR_EASTER_EGG_ACTIVATED);
- return;
- case SHOW_CACHED_COPY_BUTTON:
- RecordEvent(NETWORK_ERROR_PAGE_CACHED_COPY_BUTTON_CLICKED);
- return;
- case DIAGNOSE_ERROR:
- RecordEvent(NETWORK_ERROR_DIAGNOSE_BUTTON_CLICKED);
- delegate_->DiagnoseError(
- committed_error_page_info_->error.unreachable_url);
- return;
- case DOWNLOAD_BUTTON:
- RecordEvent(NETWORK_ERROR_PAGE_DOWNLOAD_BUTTON_CLICKED);
- delegate_->DownloadPageLater();
- return;
- case NO_BUTTON:
- NOTREACHED();
- return;
- }
-}
-
-void NetErrorHelperCore::TrackClick(int tracking_id) {
- // It's technically possible for |navigation_correction_params| to be NULL but
- // for |navigation_correction_response| not to be NULL, if the paramters
- // changed between loading the original error page and loading the error page
- if (!committed_error_page_info_ ||
- !committed_error_page_info_->navigation_correction_response) {
- return;
- }
-
- NavigationCorrectionResponse* response =
- committed_error_page_info_->navigation_correction_response.get();
-
- // |tracking_id| is less than 0 when the error page was not generated by the
- // navigation correction service. |tracking_id| should never be greater than
- // the array size, but best to be safe, since it contains data from a remote
- // site, though none of that data should make it into Javascript callbacks.
- if (tracking_id < 0 ||
- static_cast<size_t>(tracking_id) >= response->corrections.size()) {
- return;
- }
-
- // Only report a clicked link once.
- if (committed_error_page_info_->clicked_corrections.count(tracking_id))
- return;
-
- TrackClickUMA(response->corrections[tracking_id]->correction_type);
-
- committed_error_page_info_->clicked_corrections.insert(tracking_id);
- std::string request_body = CreateClickTrackingUrlRequestBody(
- committed_error_page_info_->error,
- *committed_error_page_info_->navigation_correction_params,
- *response,
- *response->corrections[tracking_id]);
- delegate_->SendTrackingRequest(
- committed_error_page_info_->navigation_correction_params->url,
- request_body);
-}
-
-} // namespace error_page
diff --git a/chromium/components/error_page/renderer/net_error_helper_core.h b/chromium/components/error_page/renderer/net_error_helper_core.h
deleted file mode 100644
index 57d51941b01..00000000000
--- a/chromium/components/error_page/renderer/net_error_helper_core.h
+++ /dev/null
@@ -1,293 +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_ERROR_PAGE_RENDERER_NET_ERROR_HELPER_CORE_H_
-#define COMPONENTS_ERROR_PAGE_RENDERER_NET_ERROR_HELPER_CORE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "build/build_config.h"
-#include "components/error_page/common/net_error_info.h"
-#include "url/gurl.h"
-
-namespace blink {
-struct WebURLError;
-}
-
-namespace error_page {
-
-struct ErrorPageParams;
-
-// Class that contains the logic for how the NetErrorHelper. This allows for
-// testing the logic without a RenderView or WebFrame, which are difficult to
-// mock, and for testing races which are impossible to reliably reproduce
-// with real RenderViews or WebFrames.
-class NetErrorHelperCore {
- public:
- enum FrameType {
- MAIN_FRAME,
- SUB_FRAME,
- };
-
- enum PageType {
- NON_ERROR_PAGE,
- ERROR_PAGE,
- };
-
- enum Button {
- NO_BUTTON,
- RELOAD_BUTTON,
- SHOW_SAVED_COPY_BUTTON,
- MORE_BUTTON,
- EASTER_EGG,
- SHOW_CACHED_COPY_BUTTON, // "Google cached copy" button label experiment.
- DIAGNOSE_ERROR,
- DOWNLOAD_BUTTON, // "Download page later" experiment.
- };
-
- // The Delegate handles all interaction with the RenderView, WebFrame, and
- // the network, as well as the generation of error pages.
- class Delegate {
- public:
- // Generates an error page's HTML for the given error.
- virtual void GenerateLocalizedErrorPage(
- const blink::WebURLError& error,
- bool is_failed_post,
- bool can_show_network_diagnostics_dialog,
- std::unique_ptr<ErrorPageParams> params,
- bool* reload_button_shown,
- bool* show_saved_copy_button_shown,
- bool* show_cached_copy_button_shown,
- bool* download_button_shown,
- std::string* html) const = 0;
-
- // Loads the given HTML in the frame for use as an error page.
- virtual void LoadErrorPage(const std::string& html,
- const GURL& failed_url) = 0;
-
- // Create extra Javascript bindings in the error page. Will only be invoked
- // after an error page has finished loading.
- virtual void EnablePageHelperFunctions() = 0;
-
- // Updates the currently displayed error page with a new error code. The
- // currently displayed error page must have finished loading, and must have
- // been generated by a call to GenerateLocalizedErrorPage.
- virtual void UpdateErrorPage(const blink::WebURLError& error,
- bool is_failed_post,
- bool can_show_network_diagnostics_dialog) = 0;
-
- // Fetches an error page and calls into OnErrorPageFetched when done. Any
- // previous fetch must either be canceled or finished before calling. Can't
- // be called synchronously after a previous fetch completes.
- virtual void FetchNavigationCorrections(
- const GURL& navigation_correction_url,
- const std::string& navigation_correction_request_body) = 0;
-
- // Cancels fetching navigation corrections. Does nothing if no fetch is
- // ongoing.
- virtual void CancelFetchNavigationCorrections() = 0;
-
- // Sends an HTTP request used to track which link on the page was clicked to
- // the navigation correction service.
- virtual void SendTrackingRequest(
- const GURL& tracking_url,
- const std::string& tracking_request_body) = 0;
-
- // Starts a reload of the page in the observed frame.
- virtual void ReloadPage(bool bypass_cache) = 0;
-
- // Load the original page from cache.
- virtual void LoadPageFromCache(const GURL& page_url) = 0;
-
- // Run the platform diagnostics too for the specified URL.
- virtual void DiagnoseError(const GURL& page_url) = 0;
-
- // Schedule to download the page at a later time.
- virtual void DownloadPageLater() = 0;
-
- // Inform that download button is being shown in the error page.
- virtual void SetIsShowingDownloadButton(bool show) = 0;
-
- protected:
- virtual ~Delegate() {}
- };
-
- struct NavigationCorrectionParams {
- NavigationCorrectionParams();
- NavigationCorrectionParams(const NavigationCorrectionParams& other);
- ~NavigationCorrectionParams();
-
- // URL used both for getting the suggestions and tracking clicks.
- GURL url;
-
- std::string language;
- std::string country_code;
- std::string api_key;
- GURL search_url;
- };
-
- NetErrorHelperCore(Delegate* delegate,
- bool auto_reload_enabled,
- bool auto_reload_visible_only,
- bool is_visible);
- ~NetErrorHelperCore();
-
- // Initializes |error_html| with the HTML of an error page in response to
- // |error|. Updates internals state with the assumption the page will be
- // loaded immediately.
- void GetErrorHTML(FrameType frame_type,
- const blink::WebURLError& error,
- bool is_failed_post,
- bool is_ignoring_cache,
- std::string* error_html);
-
- // These methods handle tracking the actual state of the page.
- void OnStartLoad(FrameType frame_type, PageType page_type);
- void OnCommitLoad(FrameType frame_type, const GURL& url);
- void OnFinishLoad(FrameType frame_type);
- void OnStop();
- void OnWasShown();
- void OnWasHidden();
-
- void CancelPendingFetches();
-
- // Called when an error page have has been retrieved over the network. |html|
- // must be an empty string on error.
- void OnNavigationCorrectionsFetched(const std::string& corrections,
- bool is_rtl);
-
- // Notifies |this| that network error information from the browser process
- // has been received.
- void OnNetErrorInfo(DnsProbeStatus status);
-
- // Notifies |this| if it can use a local error diagnostics service through its
- // delegate.
- void OnSetCanShowNetworkDiagnosticsDialog(
- bool can_show_network_diagnostics_dialog);
-
- void OnSetNavigationCorrectionInfo(const GURL& navigation_correction_url,
- const std::string& language,
- const std::string& country_code,
- const std::string& api_key,
- const GURL& search_url);
-
- // Notifies |this| that the network's online status changed.
- // Handler for NetworkStateChanged notification from the browser process. If
- // the network state changes to online, this method is responsible for
- // starting the auto-reload process.
- //
- // Warning: if there are many tabs sitting at an error page, this handler will
- // be run at the same time for each of their top-level renderframes, which can
- // cause many requests to be started at the same time. There's no current
- // protection against this kind of "reload storm".
- //
- // TODO(rdsmith): prevent the reload storm.
- void NetworkStateChanged(bool online);
-
- int auto_reload_count() const { return auto_reload_count_; }
-
- bool ShouldSuppressErrorPage(FrameType frame_type, const GURL& url);
-
- void set_timer_for_testing(std::unique_ptr<base::Timer> timer) {
- auto_reload_timer_ = std::move(timer);
- }
-
- // Execute the effect of pressing the specified button.
- // Note that the visual effects of the 'MORE' button are taken
- // care of in JavaScript.
- void ExecuteButtonPress(Button button);
-
- // Reports to the correction service that the link with the given tracking
- // ID was clicked. Only pages generated with information from the service
- // have links with tracking IDs. Duplicate requests from the same page with
- // the same tracking ID are ignored.
- void TrackClick(int tracking_id);
-
- private:
- struct ErrorPageInfo;
-
- // Gets HTML for a main frame error page. Depending on
- // |pending_error_page_info|, may use the navigation correction service, or
- // show a DNS probe error page. May modify |pending_error_page_info|.
- void GetErrorHtmlForMainFrame(ErrorPageInfo* pending_error_page_info,
- std::string* error_html);
-
- // Updates the currently displayed error page with a new error based on the
- // most recently received DNS probe result. The page must have finished
- // loading before this is called.
- void UpdateErrorPage();
-
- blink::WebURLError GetUpdatedError(const blink::WebURLError& error) const;
-
- void Reload(bool bypass_cache);
- bool MaybeStartAutoReloadTimer();
- void StartAutoReloadTimer();
- void AutoReloadTimerFired();
- void PauseAutoReloadTimer();
-
- static bool IsReloadableError(const ErrorPageInfo& info);
-
- Delegate* delegate_;
-
- // The last DnsProbeStatus received from the browser.
- DnsProbeStatus last_probe_status_;
-
- // Information for the provisional / "pre-provisional" error page. NULL when
- // there's no page pending, or the pending page is not an error page.
- std::unique_ptr<ErrorPageInfo> pending_error_page_info_;
-
- // Information for the committed error page. NULL when the committed page is
- // not an error page.
- std::unique_ptr<ErrorPageInfo> committed_error_page_info_;
-
- bool can_show_network_diagnostics_dialog_;
-
- NavigationCorrectionParams navigation_correction_params_;
-
- // True if auto-reload is enabled at all.
- const bool auto_reload_enabled_;
-
- // True if auto-reload should only run when the observed frame is visible.
- const bool auto_reload_visible_only_;
-
- // Timer used to wait for auto-reload attempts.
- std::unique_ptr<base::Timer> auto_reload_timer_;
-
- // True if the auto-reload timer would be running but is waiting for an
- // offline->online network transition.
- bool auto_reload_paused_;
-
- // Whether an auto-reload-initiated Reload() attempt is in flight.
- bool auto_reload_in_flight_;
-
- // True if there is an uncommitted-but-started load, error page or not. This
- // is used to inhibit starting auto-reload when an error page finishes, in
- // case this happens:
- // Error page starts
- // Error page commits
- // Non-error page starts
- // Error page finishes
- bool uncommitted_load_started_;
-
- // Is the browser online?
- bool online_;
-
- // Is the RenderFrame this object is observing visible?
- bool visible_;
-
- int auto_reload_count_;
-
- // This value is set only when a navigation has been initiated from
- // the error page. It is used to detect when such navigations result
- // in errors.
- Button navigation_from_button_;
-};
-
-} // namespace error_page
-
-#endif // COMPONENTS_ERROR_PAGE_RENDERER_NET_ERROR_HELPER_CORE_H_
diff --git a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc b/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
deleted file mode 100644
index 12bb4a425ec..00000000000
--- a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
+++ /dev/null
@@ -1,2585 +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/error_page/renderer/net_error_helper_core.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/histogram_tester.h"
-#include "base/timer/mock_timer.h"
-#include "base/timer/timer.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/error_page/common/error_page_params.h"
-#include "components/error_page/common/net_error_info.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/net_errors.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebURLError.h"
-#include "url/gurl.h"
-
-namespace error_page {
-namespace {
-
-using blink::WebURLError;
-
-const char kFailedUrl[] = "http://failed/";
-const char kFailedHttpsUrl[] = "https://failed/";
-
-const char kNavigationCorrectionUrl[] = "http://navigation.corrections/";
-const char kLanguage[] = "en";
-const char kCountry[] = "us";
-const char kApiKey[] = "api_key";
-const char kSearchUrl[] = "http://www.google.com/search";
-
-const char kSuggestedSearchTerms[] = "Happy Goats";
-const char kNavigationCorrectionEventId[] = "#007";
-const char kNavigationCorrectionFingerprint[] = "RandumStuff";
-
-struct NavigationCorrection {
- const char* correction_type;
- const char* url_correction;
- const char* click_type;
- const char* click_data;
- bool is_porn;
- bool is_soft_porn;
-
- std::unique_ptr<base::DictionaryValue> ToValue() const {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("correctionType", correction_type);
- dict->SetString("urlCorrection", url_correction);
- dict->SetString("clickType", click_type);
- dict->SetString("clickData", click_data);
- dict->SetBoolean("isPorn", is_porn);
- dict->SetBoolean("isSoftPorn", is_soft_porn);
- return dict;
- }
-};
-
-const NavigationCorrection kDefaultCorrections[] = {
- {"reloadPage", kFailedUrl, "rld", "data1", false, false},
- {"urlCorrection", "http://somewhere_else/", "btn", "data2", false, false},
- {"contentOverlap", "http://pony_island/", "btn", "data3", false, false},
-
- // Porn should be ignored.
- {"emphasizedUrlCorrection", "http://porn/", "btn", "data4", true, false},
- {"sitemap", "http://more_porn/", "btn", "data5", false, true},
-
- {"webSearchQuery", kSuggestedSearchTerms, "frm", "data6", false, false},
-};
-
-std::string SuggestionsToResponse(const NavigationCorrection* corrections,
- int num_corrections) {
- auto url_corrections = base::MakeUnique<base::ListValue>();
- for (int i = 0; i < num_corrections; ++i)
- url_corrections->Append(corrections[i].ToValue());
-
- base::DictionaryValue response;
- response.Set("result.UrlCorrections", std::move(url_corrections));
- response.SetString("result.eventId", kNavigationCorrectionEventId);
- response.SetString("result.fingerprint", kNavigationCorrectionFingerprint);
-
- std::string json;
- base::JSONWriter::Write(response, &json);
- return json;
-}
-
-testing::AssertionResult StringValueEquals(
- const base::DictionaryValue& dict,
- const std::string& key,
- const std::string& expected_value) {
- std::string actual_value;
- if (!dict.GetString(key, &actual_value))
- return testing::AssertionFailure() << key << " not found.";
- if (actual_value != expected_value) {
- return testing::AssertionFailure()
- << "actual: " << actual_value << "\n expected: " << expected_value;
- }
- return testing::AssertionSuccess();
-}
-
-// Creates a string from an error that is used as a mock locally generated
-// error page for that error.
-std::string ErrorToString(const WebURLError& error, bool is_failed_post) {
- return base::StringPrintf("(%s, %s, %i, %s)",
- error.unreachable_url.GetString().Utf8().c_str(),
- error.domain.Utf8().c_str(), error.reason,
- is_failed_post ? "POST" : "NOT POST");
-}
-
-WebURLError ProbeError(DnsProbeStatus status) {
- WebURLError error;
- error.unreachable_url = GURL(kFailedUrl);
- error.domain = blink::WebString::FromUTF8(kDnsProbeErrorDomain);
- error.reason = status;
- return error;
-}
-
-WebURLError NetErrorForURL(net::Error net_error, const GURL& url) {
- WebURLError error;
- error.unreachable_url = url;
- error.domain = blink::WebString::FromUTF8(net::kErrorDomain);
- error.reason = net_error;
- return error;
-}
-
-WebURLError NetError(net::Error net_error) {
- return NetErrorForURL(net_error, GURL(kFailedUrl));
-}
-
-// Convenience functions that create an error string for a non-POST request.
-
-std::string ProbeErrorString(DnsProbeStatus status) {
- return ErrorToString(ProbeError(status), false);
-}
-
-std::string NetErrorStringForURL(net::Error net_error, const GURL& url) {
- return ErrorToString(NetErrorForURL(net_error, url), false);
-}
-
-std::string NetErrorString(net::Error net_error) {
- return ErrorToString(NetError(net_error), false);
-}
-
-class NetErrorHelperCoreTest : public testing::Test,
- public NetErrorHelperCore::Delegate {
- public:
- NetErrorHelperCoreTest()
- : timer_(NULL),
- update_count_(0),
- error_html_update_count_(0),
- reload_count_(0),
- reload_bypassing_cache_count_(0),
- show_saved_copy_count_(0),
- diagnose_error_count_(0),
- download_count_(0),
- enable_page_helper_functions_count_(0),
- default_url_(GURL(kFailedUrl)),
- error_url_(GURL(content::kUnreachableWebDataURL)),
- tracking_request_count_(0) {
- SetUpCore(false, false, true);
- }
-
- ~NetErrorHelperCoreTest() override {
- // No test finishes while an error page is being fetched.
- EXPECT_FALSE(is_url_being_fetched());
- }
-
- void SetUp() override { base::StatisticsRecorder::Initialize(); }
-
- void SetUpCore(bool auto_reload_enabled,
- bool auto_reload_visible_only,
- bool visible) {
- // The old value of timer_, if any, will be freed by the old core_ being
- // destructed, since core_ takes ownership of the timer.
- timer_ = new base::MockTimer(false, false);
- core_.reset(new NetErrorHelperCore(this,
- auto_reload_enabled,
- auto_reload_visible_only,
- visible));
- core_->set_timer_for_testing(std::unique_ptr<base::Timer>(timer_));
- }
-
- NetErrorHelperCore* core() { return core_.get(); }
-
- const GURL& url_being_fetched() const { return url_being_fetched_; }
- bool is_url_being_fetched() const { return !url_being_fetched_.is_empty(); }
-
- int reload_count() const {
- return reload_count_;
- }
-
- int reload_bypassing_cache_count() const {
- return reload_bypassing_cache_count_;
- }
-
- int show_saved_copy_count() const {
- return show_saved_copy_count_;
- }
-
- const GURL& show_saved_copy_url() const {
- return show_saved_copy_url_;
- }
-
- int diagnose_error_count() const {
- return diagnose_error_count_;
- }
-
- const GURL& diagnose_error_url() const {
- return diagnose_error_url_;
- }
-
- int download_count() const { return download_count_; }
-
- const GURL& default_url() const {
- return default_url_;
- }
-
- const GURL& error_url() const {
- return error_url_;
- }
-
- int enable_page_helper_functions_count() const {
- return enable_page_helper_functions_count_;
- }
-
- const std::string& last_update_string() const { return last_update_string_; }
- int update_count() const { return update_count_; }
-
- const std::string& last_error_html() const { return last_error_html_; }
- int error_html_update_count() const { return error_html_update_count_; }
-
- bool last_can_show_network_diagnostics_dialog() const {
- return last_can_show_network_diagnostics_dialog_;
- }
-
- const ErrorPageParams* last_error_page_params() const {
- return last_error_page_params_.get();
- }
-
- const GURL& last_tracking_url() const { return last_tracking_url_; }
- const std::string& last_tracking_request_body() const {
- return last_tracking_request_body_;
- }
- int tracking_request_count() const { return tracking_request_count_; }
-
- base::MockTimer* timer() { return timer_; }
-
- void NavigationCorrectionsLoadSuccess(
- const NavigationCorrection* corrections, int num_corrections) {
- NavigationCorrectionsLoadFinished(
- SuggestionsToResponse(corrections, num_corrections));
- }
-
- void NavigationCorrectionsLoadFailure() {
- NavigationCorrectionsLoadFinished("");
- }
-
- void NavigationCorrectionsLoadFinished(const std::string& result) {
- url_being_fetched_ = GURL();
- core()->OnNavigationCorrectionsFetched(result, false);
- }
-
- void DoErrorLoadOfURL(net::Error error, const GURL& url) {
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(NetErrorHelperCore::MAIN_FRAME,
- NetErrorForURL(error, url), false /* is_failed_post */,
- false /* is_ignoring_cache */, &html);
- EXPECT_FALSE(html.empty());
- EXPECT_EQ(NetErrorStringForURL(error, url), html);
-
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME,
- error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- }
-
- void DoErrorLoad(net::Error error) {
- DoErrorLoadOfURL(error, GURL(kFailedUrl));
- }
-
- void DoErrorReoadBypassingCache(net::Error error) {
- const GURL url(kFailedUrl);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(NetErrorHelperCore::MAIN_FRAME,
- NetErrorForURL(error, url), false /* is_failed_post */,
- true /* is_ignoring_cache */, &html);
- EXPECT_FALSE(html.empty());
- EXPECT_EQ(NetErrorStringForURL(error, url), html);
-
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- }
-
- void DoSuccessLoad() {
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, default_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- }
-
- void DoDnsProbe(DnsProbeStatus final_status) {
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(final_status);
- }
-
- void EnableNavigationCorrections() {
- SetNavigationCorrectionURL(GURL(kNavigationCorrectionUrl));
- }
-
- void DisableNavigationCorrections() {
- SetNavigationCorrectionURL(GURL());
- }
-
- void ExpectDefaultNavigationCorrections() const {
- // Checks that the last error page params correspond to kDefaultSuggestions.
- ASSERT_TRUE(last_error_page_params());
- EXPECT_TRUE(last_error_page_params()->suggest_reload);
- EXPECT_EQ(1u, last_error_page_params()->override_suggestions->GetSize());
- EXPECT_EQ(GURL(kSearchUrl), last_error_page_params()->search_url);
- EXPECT_EQ(kSuggestedSearchTerms, last_error_page_params()->search_terms);
- }
-
- private:
- void SetNavigationCorrectionURL(const GURL& navigation_correction_url) {
- core()->OnSetNavigationCorrectionInfo(navigation_correction_url,
- kLanguage, kCountry, kApiKey,
- GURL(kSearchUrl));
- }
-
- // NetErrorHelperCore::Delegate implementation:
- void GenerateLocalizedErrorPage(const WebURLError& error,
- bool is_failed_post,
- bool can_show_network_diagnostics_dialog,
- std::unique_ptr<ErrorPageParams> params,
- bool* reload_button_shown,
- bool* show_saved_copy_button_shown,
- bool* show_cached_copy_button_shown,
- bool* download_button_shown,
- std::string* html) const override {
- last_can_show_network_diagnostics_dialog_ =
- can_show_network_diagnostics_dialog;
- last_error_page_params_ = std::move(params);
- *reload_button_shown = false;
- *show_saved_copy_button_shown = false;
- *show_cached_copy_button_shown = false;
- *download_button_shown = false;
- *html = ErrorToString(error, is_failed_post);
- }
-
- void LoadErrorPage(const std::string& html, const GURL& failed_url) override {
- error_html_update_count_++;
- last_error_html_ = html;
- }
-
- void EnablePageHelperFunctions() override {
- enable_page_helper_functions_count_++;
- }
-
- void UpdateErrorPage(const WebURLError& error,
- bool is_failed_post,
- bool can_show_network_diagnostics_dialog) override {
- update_count_++;
- last_can_show_network_diagnostics_dialog_ =
- can_show_network_diagnostics_dialog;
- last_error_page_params_.reset(nullptr);
- last_error_html_ = ErrorToString(error, is_failed_post);
- }
-
- void FetchNavigationCorrections(
- const GURL& navigation_correction_url,
- const std::string& navigation_correction_request_body) override {
- EXPECT_TRUE(url_being_fetched_.is_empty());
- EXPECT_TRUE(request_body_.empty());
- EXPECT_EQ(GURL(kNavigationCorrectionUrl), navigation_correction_url);
-
- url_being_fetched_ = navigation_correction_url;
- request_body_ = navigation_correction_request_body;
-
- // Check the body of the request.
-
- base::JSONReader reader;
- std::unique_ptr<base::Value> parsed_body(
- reader.Read(navigation_correction_request_body));
- ASSERT_TRUE(parsed_body);
- base::DictionaryValue* dict = NULL;
- ASSERT_TRUE(parsed_body->GetAsDictionary(&dict));
-
- EXPECT_TRUE(StringValueEquals(*dict, "params.urlQuery", kFailedUrl));
- EXPECT_TRUE(StringValueEquals(*dict, "params.language", kLanguage));
- EXPECT_TRUE(StringValueEquals(*dict, "params.originCountry", kCountry));
- EXPECT_TRUE(StringValueEquals(*dict, "params.key", kApiKey));
- }
-
- void CancelFetchNavigationCorrections() override {
- url_being_fetched_ = GURL();
- request_body_.clear();
- }
-
- void ReloadPage(bool bypass_cache) override {
- reload_count_++;
- if (bypass_cache)
- reload_bypassing_cache_count_++;
- }
-
- void LoadPageFromCache(const GURL& page_url) override {
- show_saved_copy_count_++;
- show_saved_copy_url_ = page_url;
- }
-
- void DiagnoseError(const GURL& page_url) override {
- diagnose_error_count_++;
- diagnose_error_url_ = page_url;
- }
-
- void DownloadPageLater() override {
- download_count_++;
- }
-
- void SetIsShowingDownloadButton(bool show) override {}
-
- void SendTrackingRequest(const GURL& tracking_url,
- const std::string& tracking_request_body) override {
- last_tracking_url_ = tracking_url;
- last_tracking_request_body_ = tracking_request_body;
- tracking_request_count_++;
-
- // Check the body of the request.
-
- base::JSONReader reader;
- std::unique_ptr<base::Value> parsed_body(
- reader.Read(tracking_request_body));
- ASSERT_TRUE(parsed_body);
- base::DictionaryValue* dict = NULL;
- ASSERT_TRUE(parsed_body->GetAsDictionary(&dict));
-
- EXPECT_TRUE(StringValueEquals(*dict, "params.originalUrlQuery",
- kFailedUrl));
- EXPECT_TRUE(StringValueEquals(*dict, "params.language", kLanguage));
- EXPECT_TRUE(StringValueEquals(*dict, "params.originCountry", kCountry));
- EXPECT_TRUE(StringValueEquals(*dict, "params.key", kApiKey));
- }
-
- base::MockTimer* timer_;
-
- std::unique_ptr<NetErrorHelperCore> core_;
-
- GURL url_being_fetched_;
- std::string request_body_;
-
- // Contains the information passed to the last call to UpdateErrorPage, as a
- // string.
- std::string last_update_string_;
- // Number of times |last_update_string_| has been changed.
- int update_count_;
-
- // Contains the HTML set by the last call to LoadErrorPageInMainFrame.
- std::string last_error_html_;
- // Number of times |last_error_html_| has been changed.
- int error_html_update_count_;
-
- // Values passed in to the last call of GenerateLocalizedErrorPage or
- // UpdateErrorPage. Mutable because GenerateLocalizedErrorPage is const.
- mutable bool last_can_show_network_diagnostics_dialog_;
- mutable std::unique_ptr<ErrorPageParams> last_error_page_params_;
-
- int reload_count_;
- int reload_bypassing_cache_count_;
- int show_saved_copy_count_;
- GURL show_saved_copy_url_;
- int diagnose_error_count_;
- GURL diagnose_error_url_;
- int download_count_;
-
- int enable_page_helper_functions_count_;
-
- const GURL default_url_;
- const GURL error_url_;
-
- GURL last_tracking_url_;
- std::string last_tracking_request_body_;
- int tracking_request_count_;
-};
-
-//------------------------------------------------------------------------------
-// Basic tests that don't update the error page for probes or load navigation
-// corrections.
-//------------------------------------------------------------------------------
-
-TEST_F(NetErrorHelperCoreTest, Null) {
-}
-
-TEST_F(NetErrorHelperCoreTest, SuccessfulPageLoad) {
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, default_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, SuccessfulPageLoadWithNavigationCorrections) {
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, default_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsError) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page.
- EXPECT_FALSE(html.empty());
- EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html);
-
- // Error page loads.
- EXPECT_EQ(0, enable_page_helper_functions_count());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
- EXPECT_EQ(1, enable_page_helper_functions_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsErrorWithCorrections) {
- EnableNavigationCorrections();
-
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page.
- EXPECT_FALSE(html.empty());
- EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Much like above tests, but with a bunch of spurious DNS status messages that
-// should have no effect.
-TEST_F(NetErrorHelperCoreTest, MainFrameNonDnsErrorSpuriousStatus) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- // Should have returned a local error page.
- EXPECT_FALSE(html.empty());
- EXPECT_EQ(NetErrorString(net::ERR_CONNECTION_RESET), html);
-
- // Error page loads.
-
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, SubFrameDnsError) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::SUB_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page.
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::SUB_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::SUB_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, SubFrameDnsErrorWithCorrections) {
- EnableNavigationCorrections();
-
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::SUB_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page.
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::SUB_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::SUB_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Much like above tests, but with a bunch of spurious DNS status messages that
-// should have no effect.
-TEST_F(NetErrorHelperCoreTest, SubFrameDnsErrorSpuriousStatus) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::SUB_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- // Should have returned a local error page.
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), html);
-
- // Error page loads.
-
- core()->OnStartLoad(NetErrorHelperCore::SUB_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- core()->OnCommitLoad(NetErrorHelperCore::SUB_FRAME, error_url());
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- core()->OnFinishLoad(NetErrorHelperCore::SUB_FRAME);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-//------------------------------------------------------------------------------
-// Tests for updating the error page in response to DNS probe results. None
-// of these have navigation corrections enabled.
-//------------------------------------------------------------------------------
-
-// Test case where the error page finishes loading before receiving any DNS
-// probe messages.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbe) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Same as above, but the probe is not run.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeNotRun) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
-
- // When the not run status arrives, the page should revert to the normal dns
- // error page.
- core()->OnNetErrorInfo(DNS_PROBE_NOT_RUN);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Same as above, but the probe result is inconclusive.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeInconclusive) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- // When the inconclusive status arrives, the page should revert to the normal
- // dns error page.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_INCONCLUSIVE);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_INCONCLUSIVE);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Same as above, but the probe result is no internet.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeNoInternet) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- // When the inconclusive status arrives, the page should revert to the normal
- // dns error page.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NO_INTERNET);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NO_INTERNET),
- last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NO_INTERNET);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Same as above, but the probe result is bad config.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbeBadConfig) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- // When the inconclusive status arrives, the page should revert to the normal
- // dns error page.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_BAD_CONFIG);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_BAD_CONFIG), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_BAD_CONFIG);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Test case where the error page finishes loading after receiving the start
-// DNS probe message.
-TEST_F(NetErrorHelperCoreTest, FinishedAfterStartProbe) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
-
- // Nothing should be done when a probe status comes in before loading
- // finishes.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(0, update_count());
-
- // When loading finishes, however, the buffered probe status should be sent
- // to the page.
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- // Should update the page again when the probe result comes in.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_NOT_RUN);
- EXPECT_EQ(2, update_count());
-}
-
-// Test case where the error page finishes loading before receiving any DNS
-// probe messages and the request is a POST.
-TEST_F(NetErrorHelperCoreTest, FinishedBeforeProbePost) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- true /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ErrorToString(ProbeError(DNS_PROBE_POSSIBLE), true), html);
-
- // Error page loads.
- EXPECT_EQ(0, enable_page_helper_functions_count());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(1, enable_page_helper_functions_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ErrorToString(ProbeError(DNS_PROBE_STARTED), true),
- last_error_html());
-
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ErrorToString(ProbeError(DNS_PROBE_FINISHED_NXDOMAIN), true),
- last_error_html());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Test case where the probe finishes before the page is committed.
-TEST_F(NetErrorHelperCoreTest, ProbeFinishesEarly) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
-
- // Nothing should be done when the probe statuses come in before loading
- // finishes.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- EXPECT_EQ(0, update_count());
-
- // When loading finishes, however, the buffered probe status should be sent
- // to the page.
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // Any other probe updates should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(1, update_count());
-}
-
-// Test case where one error page loads completely before a new navigation
-// results in another error page. Probes are run for both pages.
-TEST_F(NetErrorHelperCoreTest, TwoErrorsWithProbes) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Probe results come in.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // The process starts again.
-
- // Normal page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(2, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(3, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- // The probe returns a different result this time.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NO_INTERNET);
- EXPECT_EQ(4, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NO_INTERNET),
- last_error_html());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Test case where one error page loads completely before a new navigation
-// results in another error page. Probe results for the first probe are only
-// received after the second load starts, but before it commits.
-TEST_F(NetErrorHelperCoreTest, TwoErrorsWithProbesAfterSecondStarts) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // The process starts again.
-
- // Normal page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page starts to load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
-
- // Probe results come in, and the first page is updated.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // Second page finishes loading, and is updated using the same probe result.
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(3, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // Other probe results should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NO_INTERNET);
- EXPECT_EQ(3, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// Same as above, but a new page is loaded before the error page commits.
-TEST_F(NetErrorHelperCoreTest, ErrorPageLoadInterrupted) {
- // Original page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and an error page is requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- // Probe statuses come in, but should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-
- // A new navigation begins while the error page is loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // And fails.
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- // Should have returned a local error page indicating a probe may run.
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_POSSIBLE), html);
-
- // Error page finishes loading.
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Probe results come in.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED),
- last_error_html());
-
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NO_INTERNET);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NO_INTERNET),
- last_error_html());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-//------------------------------------------------------------------------------
-// Navigation correction tests.
-//------------------------------------------------------------------------------
-
-// Check that corrections are not used for HTTPS URLs.
-TEST_F(NetErrorHelperCoreTest, NoCorrectionsForHttps) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // The HTTPS page fails to load.
- std::string html;
- blink::WebURLError error = NetError(net::ERR_NAME_NOT_RESOLVED);
- error.unreachable_url = GURL(kFailedHttpsUrl);
- core()->GetErrorHTML(NetErrorHelperCore::MAIN_FRAME, error,
- false /* is_failed_post */,
- false /* is_ignoring_cache */, &html);
-
- blink::WebURLError probe_error = ProbeError(DNS_PROBE_POSSIBLE);
- probe_error.unreachable_url = GURL(kFailedHttpsUrl);
- EXPECT_EQ(ErrorToString(probe_error, false), html);
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // The blank page loads, no error page is loaded.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Page is updated in response to DNS probes as normal.
- EXPECT_EQ(0, update_count());
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_FALSE(last_error_page_params());
- blink::WebURLError final_probe_error =
- ProbeError(DNS_PROBE_FINISHED_NXDOMAIN);
- final_probe_error.unreachable_url = GURL(kFailedHttpsUrl);
- EXPECT_EQ(ErrorToString(final_probe_error, false), last_error_html());
-}
-
-// The blank page loads, then the navigation corrections request succeeds and is
-// loaded. Then the probe results come in.
-TEST_F(NetErrorHelperCoreTest, CorrectionsReceivedBeforeProbe) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
-
- // Corrections retrieval starts when the error page finishes loading.
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- ExpectDefaultNavigationCorrections();
- EXPECT_FALSE(is_url_being_fetched());
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Any probe statuses should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
-
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-// The blank page finishes loading, then probe results come in, and then
-// the navigation corrections request succeeds.
-TEST_F(NetErrorHelperCoreTest, CorrectionsRetrievedAfterProbes) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Probe statuses should be ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- ExpectDefaultNavigationCorrections();
- EXPECT_FALSE(is_url_being_fetched());
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(0, update_count());
-}
-
-// The corrections request fails and then the error page loads for an error that
-// does not trigger DNS probes.
-TEST_F(NetErrorHelperCoreTest, CorrectionsFailLoadNoProbes) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_FAILED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Corrections request fails, final error page is shown.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadFailure();
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(), NetErrorString(net::ERR_CONNECTION_FAILED));
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
- EXPECT_FALSE(last_error_page_params());
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // If probe statuses come in last from another page load, they should be
- // ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-// The corrections request fails and then the error page loads before probe
-// results are received.
-TEST_F(NetErrorHelperCoreTest, CorrectionsFailLoadBeforeProbe) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Corrections request fails, probe pending page shown.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadFailure();
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(),
- ProbeErrorString(DNS_PROBE_POSSIBLE));
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
-
- // Probe page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Probe statuses comes in, and page is updated.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
-
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
-
- // The commit results in sending a second probe status, which is ignored.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-// The corrections request fails after receiving probe results.
-TEST_F(NetErrorHelperCoreTest, CorrectionsFailAfterProbe) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Results come in, but end up being ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-
- // Corrections request fails, probe pending page shown.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadFailure();
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(), ProbeErrorString(DNS_PROBE_POSSIBLE));
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
-
- // Probe page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Probe statuses comes in, and page is updated.
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(1, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-// An error page load that would normally load correction is interrupted
-// by a new navigation before the blank page commits.
-TEST_F(NetErrorHelperCoreTest, CorrectionsInterruptedBeforeCommit) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page starts loading.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
-
- // A new page load starts.
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // A new page load interrupts the original load.
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, default_url());
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// An error page load that would normally load corrections is interrupted
-// by a new navigation before the blank page finishes loading.
-TEST_F(NetErrorHelperCoreTest, CorrectionsInterruptedBeforeLoad) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page starts loading and is committed.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
-
- // A new page load interrupts the original load.
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, default_url());
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(0, error_html_update_count());
-}
-
-// The corrections request is cancelled due to a new navigation. The new
-// navigation fails and then loads corrections successfully.
-TEST_F(NetErrorHelperCoreTest, CorrectionsInterrupted) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
-
- // Results come in, but end up being ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-
- // A new load appears!
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_FALSE(is_url_being_fetched());
-
- // It fails, and corrections are requested again once a blank page is loaded.
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- EXPECT_FALSE(is_url_being_fetched());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
-
- // Corrections request succeeds.
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- ExpectDefaultNavigationCorrections();
- EXPECT_FALSE(is_url_being_fetched());
-
- // Probe statuses come in, and are ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-}
-
-// The corrections request is cancelled due to call to Stop(). The cross
-// process navigation is cancelled, and then a new load fails and tries to load
-// corrections again, unsuccessfully.
-TEST_F(NetErrorHelperCoreTest, CorrectionsStopped) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- EXPECT_TRUE(is_url_being_fetched());
- core()->OnStop();
- EXPECT_FALSE(is_url_being_fetched());
-
- // Results come in, but end up being ignored.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(0, update_count());
-
- // Cross process navigation must have been cancelled, and a new load appears!
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested again.
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads again.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
-
- // Corrections request fails, probe pending page shown.
- NavigationCorrectionsLoadFailure();
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(), ProbeErrorString(DNS_PROBE_POSSIBLE));
- EXPECT_FALSE(is_url_being_fetched());
-
- // Probe page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Probe statuses comes in, and page is updated.
- core()->OnNetErrorInfo(DNS_PROBE_STARTED);
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_STARTED), last_error_html());
- EXPECT_EQ(1, update_count());
-
- core()->OnNetErrorInfo(DNS_PROBE_FINISHED_NXDOMAIN);
- EXPECT_EQ(2, update_count());
- EXPECT_EQ(ProbeErrorString(DNS_PROBE_FINISHED_NXDOMAIN), last_error_html());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-// Check the case corrections are disabled while the blank page (Loaded
-// before the corrections page) is being loaded.
-TEST_F(NetErrorHelperCoreTest, CorrectionsDisabledBeforeFetch) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- // Corrections is disabled.
- DisableNavigationCorrections();
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- EXPECT_FALSE(is_url_being_fetched());
- ExpectDefaultNavigationCorrections();
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(0, update_count());
-}
-
-// Check the case corrections is disabled while fetching the corrections for
-// a failed page load.
-TEST_F(NetErrorHelperCoreTest, CorrectionsDisabledDuringFetch) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are disabled.
- DisableNavigationCorrections();
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- EXPECT_FALSE(is_url_being_fetched());
- ExpectDefaultNavigationCorrections();
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(0, update_count());
-}
-
-// Checks corrections are is used when there are no search suggestions.
-TEST_F(NetErrorHelperCoreTest, CorrectionsWithoutSearch) {
- const NavigationCorrection kCorrections[] = {
- {"urlCorrection", "http://somewhere_else/", "btn", "data", false, false},
- };
-
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kCorrections, arraysize(kCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- EXPECT_FALSE(is_url_being_fetched());
-
- // Check params.
- ASSERT_TRUE(last_error_page_params());
- EXPECT_FALSE(last_error_page_params()->suggest_reload);
- EXPECT_EQ(1u, last_error_page_params()->override_suggestions->GetSize());
- EXPECT_FALSE(last_error_page_params()->search_url.is_valid());
- EXPECT_EQ("", last_error_page_params()->search_terms);
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(0, update_count());
-}
-
-// Checks corrections are used when there are only search suggestions.
-TEST_F(NetErrorHelperCoreTest, CorrectionsOnlySearchSuggestion) {
- const NavigationCorrection kCorrections[] = {
- {"webSearchQuery", kSuggestedSearchTerms, "frm", "data", false, false},
- };
-
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kCorrections, arraysize(kCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- EXPECT_FALSE(is_url_being_fetched());
-
- // Check params.
- ASSERT_TRUE(last_error_page_params());
- EXPECT_FALSE(last_error_page_params()->suggest_reload);
- EXPECT_EQ(0u, last_error_page_params()->override_suggestions->GetSize());
- EXPECT_EQ(GURL(kSearchUrl), last_error_page_params()->search_url);
- EXPECT_EQ(kSuggestedSearchTerms, last_error_page_params()->search_terms);
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(0, update_count());
-}
-
-// The correction service returns a non-JSON result.
-TEST_F(NetErrorHelperCoreTest, CorrectionServiceReturnsNonJsonResult) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_FAILED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Corrections request fails, final error page is shown.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadFinished("Weird Response");
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(), NetErrorString(net::ERR_CONNECTION_FAILED));
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
- EXPECT_FALSE(last_error_page_params());
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-}
-
-// The correction service returns a JSON result that isn't a valid list of
-// corrections.
-TEST_F(NetErrorHelperCoreTest, CorrectionServiceReturnsInvalidJsonResult) {
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails, and corrections are requested.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_FAILED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- // Corrections request fails, final error page is shown.
- EXPECT_TRUE(is_url_being_fetched());
- NavigationCorrectionsLoadFinished("{\"result\": 42}");
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(last_error_html(), NetErrorString(net::ERR_CONNECTION_FAILED));
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_EQ(0, update_count());
- EXPECT_FALSE(last_error_page_params());
-
- // Error page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-}
-
-TEST_F(NetErrorHelperCoreTest, CorrectionClickTracking) {
- // Go through the standard navigation correction steps.
-
- // Original page starts loading.
- EnableNavigationCorrections();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
-
- // It fails.
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_NAME_NOT_RESOLVED),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- EXPECT_TRUE(html.empty());
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // The blank page loads.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
-
- // Corrections retrieval starts when the error page finishes loading.
- EXPECT_FALSE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_TRUE(is_url_being_fetched());
- EXPECT_FALSE(last_error_page_params());
-
- // Corrections are retrieved.
- NavigationCorrectionsLoadSuccess(kDefaultCorrections,
- arraysize(kDefaultCorrections));
- EXPECT_EQ(1, error_html_update_count());
- EXPECT_EQ(NetErrorString(net::ERR_NAME_NOT_RESOLVED), last_error_html());
- ExpectDefaultNavigationCorrections();
- EXPECT_FALSE(is_url_being_fetched());
-
- // Corrections load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- EXPECT_EQ(0, tracking_request_count());
-
- // Invalid clicks should be ignored.
- core()->TrackClick(-1);
- core()->TrackClick(arraysize(kDefaultCorrections));
- EXPECT_EQ(0, tracking_request_count());
-
- for (size_t i = 0; i < arraysize(kDefaultCorrections); ++i) {
- // Skip links that do not appear in the page.
- if (kDefaultCorrections[i].is_porn || kDefaultCorrections[i].is_soft_porn)
- continue;
-
- int old_tracking_request_count = tracking_request_count();
- core()->TrackClick(i);
- EXPECT_EQ(old_tracking_request_count + 1, tracking_request_count());
- EXPECT_EQ(GURL(kNavigationCorrectionUrl), last_tracking_url());
-
- // Make sure all expected strings appear in output.
- EXPECT_TRUE(last_tracking_request_body().find(
- kDefaultCorrections[i].url_correction));
- EXPECT_TRUE(last_tracking_request_body().find(
- kDefaultCorrections[i].click_data));
- EXPECT_TRUE(last_tracking_request_body().find(
- kDefaultCorrections[i].click_type));
- EXPECT_TRUE(last_tracking_request_body().find(
- kNavigationCorrectionEventId));
- EXPECT_TRUE(last_tracking_request_body().find(
- kNavigationCorrectionFingerprint));
- }
-
- // Make sure duplicate tracking requests are ignored.
- for (size_t i = 0; i < arraysize(kDefaultCorrections); ++i) {
- // Skip links that do not appear in the page.
- if (kDefaultCorrections[i].is_porn || kDefaultCorrections[i].is_soft_porn)
- continue;
-
- int old_tracking_request_count = tracking_request_count();
- core()->TrackClick(i);
- EXPECT_EQ(old_tracking_request_count, tracking_request_count());
- }
-
- EXPECT_EQ(0, update_count());
- EXPECT_EQ(1, error_html_update_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, AutoReloadDisabled) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
-
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(0, reload_count());
-}
-
-class NetErrorHelperCoreAutoReloadTest : public NetErrorHelperCoreTest {
- public:
- void SetUp() override {
- NetErrorHelperCoreTest::SetUp();
- SetUpCore(true, false, true);
- }
-};
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, Succeeds) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
-
- EXPECT_TRUE(timer()->IsRunning());
- EXPECT_EQ(0, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
-
- timer()->Fire();
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(1, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
-
- DoSuccessLoad();
-
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, BypassingCache) {
- DoErrorReoadBypassingCache(net::ERR_CONNECTION_RESET);
-
- EXPECT_TRUE(timer()->IsRunning());
- EXPECT_EQ(0, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
-
- timer()->Fire();
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(1, reload_count());
- EXPECT_EQ(1, reload_bypassing_cache_count());
-
- DoSuccessLoad();
-
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, Retries) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
-
- EXPECT_TRUE(timer()->IsRunning());
- base::TimeDelta first_delay = timer()->GetCurrentDelay();
- EXPECT_EQ(0, reload_count());
-
- timer()->Fire();
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(1, reload_count());
-
- DoErrorLoad(net::ERR_CONNECTION_RESET);
-
- EXPECT_TRUE(timer()->IsRunning());
- EXPECT_GT(timer()->GetCurrentDelay(), first_delay);
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, StopsTimerOnStop) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(timer()->IsRunning());
- core()->OnStop();
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, StopsLoadingOnStop) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_EQ(0, core()->auto_reload_count());
- timer()->Fire();
- EXPECT_EQ(1, core()->auto_reload_count());
- EXPECT_EQ(1, reload_count());
- core()->OnStop();
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(0, core()->auto_reload_count());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, StopsOnOtherLoadStart) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(timer()->IsRunning());
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_FALSE(timer()->IsRunning());
- EXPECT_EQ(0, core()->auto_reload_count());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ResetsCountOnSuccess) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- base::TimeDelta delay = timer()->GetCurrentDelay();
- EXPECT_EQ(0, core()->auto_reload_count());
- timer()->Fire();
- EXPECT_EQ(1, core()->auto_reload_count());
- EXPECT_EQ(1, reload_count());
- DoSuccessLoad();
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_EQ(0, core()->auto_reload_count());
- EXPECT_EQ(timer()->GetCurrentDelay(), delay);
- timer()->Fire();
- EXPECT_EQ(1, core()->auto_reload_count());
- EXPECT_EQ(2, reload_count());
- DoSuccessLoad();
- EXPECT_EQ(0, core()->auto_reload_count());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, RestartsOnOnline) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- base::TimeDelta delay = timer()->GetCurrentDelay();
- timer()->Fire();
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(timer()->IsRunning());
- EXPECT_NE(delay, timer()->GetCurrentDelay());
- core()->NetworkStateChanged(false);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_TRUE(timer()->IsRunning());
- EXPECT_EQ(delay, timer()->GetCurrentDelay());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, DoesNotStartOnOnline) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- DoSuccessLoad();
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, DoesNotStartOffline) {
- core()->NetworkStateChanged(false);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, DoesNotRestartOnOnlineAfterStop) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- core()->OnStop();
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, WithDnsProbes) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- DoDnsProbe(DNS_PROBE_FINISHED_NXDOMAIN);
- timer()->Fire();
- EXPECT_EQ(1, reload_count());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ExponentialBackoffLevelsOff) {
- base::TimeDelta previous = base::TimeDelta::FromMilliseconds(0);
- const int kMaxTries = 50;
- int tries = 0;
- for (tries = 0; tries < kMaxTries; tries++) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(timer()->IsRunning());
- if (previous == timer()->GetCurrentDelay())
- break;
- previous = timer()->GetCurrentDelay();
- timer()->Fire();
- }
-
- EXPECT_LT(tries, kMaxTries);
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, SlowError) {
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- EXPECT_FALSE(timer()->IsRunning());
- // Start a new non-error page load.
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_FALSE(timer()->IsRunning());
- // Finish the error page load.
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_FALSE(timer()->IsRunning());
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, OnlineSlowError) {
- core()->NetworkStateChanged(false);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(false);
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, OnlinePendingError) {
- core()->NetworkStateChanged(false);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(false);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, OnlinePartialErrorReplacement) {
- core()->NetworkStateChanged(false);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- std::string html;
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME, error_url());
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->GetErrorHTML(
- NetErrorHelperCore::MAIN_FRAME, NetError(net::ERR_CONNECTION_RESET),
- false /* is_failed_post */, false /* is_ignoring_cache */, &html);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ShouldSuppressNonReloadableErrorPage) {
- DoErrorLoad(net::ERR_ABORTED);
- EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedUrl)));
-
- DoErrorLoad(net::ERR_UNKNOWN_URL_SCHEME);
- EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedUrl)));
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, DoesNotReload) {
- DoErrorLoad(net::ERR_ABORTED);
- EXPECT_FALSE(timer()->IsRunning());
-
- DoErrorLoad(net::ERR_UNKNOWN_URL_SCHEME);
- EXPECT_FALSE(timer()->IsRunning());
-
- DoErrorLoad(net::ERR_SSL_PROTOCOL_ERROR);
- EXPECT_FALSE(timer()->IsRunning());
-
- DoErrorLoad(net::ERR_BAD_SSL_CLIENT_AUTH_CERT);
- EXPECT_FALSE(timer()->IsRunning());
-
- DoErrorLoadOfURL(net::ERR_ACCESS_DENIED, GURL("data://some-data-here"));
- EXPECT_FALSE(timer()->IsRunning());
-
- DoErrorLoadOfURL(net::ERR_ACCESS_DENIED, GURL("chrome-extension://foo"));
- EXPECT_FALSE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ShouldSuppressErrorPage) {
- // Set up the environment to test ShouldSuppressErrorPage: auto-reload is
- // enabled, an error page is loaded, and the auto-reload callback is running.
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
-
- // Sub-frame load.
- EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::SUB_FRAME,
- GURL(kFailedUrl)));
- EXPECT_TRUE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedUrl)));
- // No auto-reload attempt in flight.
- EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedUrl)));
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, HiddenAndShown) {
- SetUpCore(true, true, true);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(timer()->IsRunning());
- core()->OnWasHidden();
- EXPECT_FALSE(timer()->IsRunning());
- core()->OnWasShown();
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, HiddenWhileOnline) {
- SetUpCore(true, true, true);
- core()->NetworkStateChanged(false);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_FALSE(timer()->IsRunning());
- core()->OnWasHidden();
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(false);
- core()->OnWasShown();
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_TRUE(timer()->IsRunning());
- core()->NetworkStateChanged(false);
- core()->OnWasHidden();
- EXPECT_FALSE(timer()->IsRunning());
- core()->NetworkStateChanged(true);
- EXPECT_FALSE(timer()->IsRunning());
- core()->OnWasShown();
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ShownWhileNotReloading) {
- SetUpCore(true, true, false);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_FALSE(timer()->IsRunning());
- core()->OnWasShown();
- EXPECT_TRUE(timer()->IsRunning());
-}
-
-TEST_F(NetErrorHelperCoreAutoReloadTest, ManualReloadShowsError) {
- SetUpCore(true, true, true);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::ERROR_PAGE);
- EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedUrl)));
-}
-
-class NetErrorHelperCoreHistogramTest
- : public NetErrorHelperCoreAutoReloadTest {
- public:
- void SetUp() override { NetErrorHelperCoreAutoReloadTest::SetUp(); }
-
- static const char kCountAtStop[];
- static const char kErrorAtStop[];
- static const char kCountAtSuccess[];
- static const char kErrorAtSuccess[];
- static const char kErrorAtFirstSuccess[];
-
- protected:
- base::HistogramTester histogram_tester_;
-};
-
-const char NetErrorHelperCoreHistogramTest::kCountAtStop[] =
- "Net.AutoReload.CountAtStop";
-const char NetErrorHelperCoreHistogramTest::kErrorAtStop[] =
- "Net.AutoReload.ErrorAtStop";
-const char NetErrorHelperCoreHistogramTest::kCountAtSuccess[] =
- "Net.AutoReload.CountAtSuccess";
-const char NetErrorHelperCoreHistogramTest::kErrorAtSuccess[] =
- "Net.AutoReload.ErrorAtSuccess";
-const char NetErrorHelperCoreHistogramTest::kErrorAtFirstSuccess[] =
- "Net.AutoReload.ErrorAtFirstSuccess";
-
-// Test that the success histograms are updated when auto-reload succeeds at the
-// first attempt, and that the failure histograms are not updated.
-TEST_F(NetErrorHelperCoreHistogramTest, SuccessAtFirstAttempt) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- DoSuccessLoad();
-
- // All of CountAtSuccess, ErrorAtSuccess, and ErrorAtFirstSuccess should
- // reflect this successful load. The failure histograms should be unchanged.
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 1);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 0);
-}
-
-// Test that the success histograms are updated when auto-reload succeeds but
-// not on the first attempt, and that the first-success histogram is not
-// updated.
-TEST_F(NetErrorHelperCoreHistogramTest, SuccessAtSecondAttempt) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- EXPECT_TRUE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- default_url()));
- timer()->Fire();
- DoSuccessLoad();
-
- // CountAtSuccess and ErrorAtSuccess should reflect this successful load, but
- // not ErrorAtFirstSuccess since it wasn't a first success.
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 0);
-}
-
-// Test that a user stop (caused by the user pressing the 'Stop' button)
-// registers as an auto-reload failure if an auto-reload attempt is in flight.
-// Note that "user stop" is also caused by a cross-process navigation, for which
-// the browser process will send an OnStop to the old process.
-TEST_F(NetErrorHelperCoreHistogramTest, UserStop) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnStop();
-
- // CountAtStop and ErrorAtStop should reflect the failure.
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 1);
-}
-
-// Test that a user stop (caused by the user pressing the 'Stop' button)
-// registers as an auto-reload failure even if an auto-reload attempt has not
-// been launched yet (i.e., if the timer is running, but no reload is in
-// flight), because this means auto-reload didn't successfully replace the error
-// page.
-TEST_F(NetErrorHelperCoreHistogramTest, OtherPageLoaded) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnStop();
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 1);
-}
-
-// Test that a commit of a different URL (caused by the user navigating to a
-// different page) with an auto-reload attempt in flight registers as an
-// auto-reload failure.
-TEST_F(NetErrorHelperCoreHistogramTest, OtherPageLoadedAfterTimerFires) {
- const GURL kTestUrl("https://anotherurl");
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME,
- kTestUrl);
- core()->OnFinishLoad(NetErrorHelperCore::MAIN_FRAME);
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 1);
-}
-
-// Test that a commit of the same URL with an auto-reload attempt in flight
-// registers as an auto-reload success.
-TEST_F(NetErrorHelperCoreHistogramTest, SamePageLoadedAfterTimerFires) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- DoSuccessLoad();
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 1);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 0);
-}
-
-TEST_F(NetErrorHelperCoreHistogramTest, SamePageLoadedAfterLoadStarts) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- // Autoreload attempt starts
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- // User does a manual reload
- DoSuccessLoad();
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 1);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 0);
-}
-
-// In this test case, the user presses the reload button manually after an
-// auto-reload fails and the error page is suppressed.
-TEST_F(NetErrorHelperCoreHistogramTest, ErrorPageLoadedAfterTimerFires) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- timer()->Fire();
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- EXPECT_TRUE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME,
- default_url()));
- DoErrorLoad(net::ERR_CONNECTION_RESET);
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 0);
-}
-
-TEST_F(NetErrorHelperCoreHistogramTest, SuccessPageLoadedBeforeTimerFires) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME,
- NetErrorHelperCore::NON_ERROR_PAGE);
- core()->OnCommitLoad(NetErrorHelperCore::MAIN_FRAME,
- GURL(kFailedHttpsUrl));
-
- histogram_tester_.ExpectTotalCount(kCountAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtSuccess, 0);
- histogram_tester_.ExpectTotalCount(kErrorAtFirstSuccess, 0);
- histogram_tester_.ExpectTotalCount(kCountAtStop, 1);
- histogram_tester_.ExpectTotalCount(kErrorAtStop, 1);
-}
-
-TEST_F(NetErrorHelperCoreTest, ExplicitReloadSucceeds) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_EQ(0, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
- core()->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
- EXPECT_EQ(1, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, ExplicitReloadDoNotBypassCache) {
- DoErrorReoadBypassingCache(net::ERR_CONNECTION_RESET);
- EXPECT_EQ(0, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
- core()->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
- EXPECT_EQ(1, reload_count());
- EXPECT_EQ(0, reload_bypassing_cache_count());
-}
-
-TEST_F(NetErrorHelperCoreTest, ExplicitShowSavedSucceeds) {
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_EQ(0, show_saved_copy_count());
- core()->ExecuteButtonPress(NetErrorHelperCore::SHOW_SAVED_COPY_BUTTON);
- EXPECT_EQ(1, show_saved_copy_count());
- EXPECT_EQ(GURL(kFailedUrl), show_saved_copy_url());
-}
-
-TEST_F(NetErrorHelperCoreTest, CanNotShowNetworkDiagnostics) {
- core()->OnSetCanShowNetworkDiagnosticsDialog(false);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_FALSE(last_can_show_network_diagnostics_dialog());
-}
-
-TEST_F(NetErrorHelperCoreTest, CanShowNetworkDiagnostics) {
- core()->OnSetCanShowNetworkDiagnosticsDialog(true);
- DoErrorLoad(net::ERR_CONNECTION_RESET);
- EXPECT_TRUE(last_can_show_network_diagnostics_dialog());
-
- core()->ExecuteButtonPress(NetErrorHelperCore::DIAGNOSE_ERROR);
- EXPECT_EQ(1, diagnose_error_count());
- EXPECT_EQ(GURL(kFailedUrl), diagnose_error_url());
-}
-
-#if defined(OS_ANDROID)
-TEST_F(NetErrorHelperCoreTest, Download) {
- DoErrorLoad(net::ERR_INTERNET_DISCONNECTED);
- EXPECT_EQ(0, download_count());
- core()->ExecuteButtonPress(NetErrorHelperCore::DOWNLOAD_BUTTON);
- EXPECT_EQ(1, download_count());
-}
-#endif // defined(OS_ANDROID)
-
-} // namespace
-} // namespace error_page
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index 0546b563962..41a6440c033 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -65,11 +65,12 @@ source_set("exo") {
"//base",
"//cc",
"//cc/ipc:interfaces",
- "//cc/surfaces",
+ "//components/viz/service",
"//device/gamepad",
"//device/gamepad/public/cpp:shared_with_blink",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
+ "//services/ui/public/interfaces",
"//skia",
"//ui/aura",
"//ui/compositor",
@@ -150,9 +151,9 @@ source_set("unit_tests") {
"//base/test:test_support",
"//cc",
"//cc:test_support",
- "//cc/surfaces:surfaces",
"//components/user_manager",
"//components/viz/service",
+ "//components/viz/test:test_support",
"//device/gamepad:test_helpers",
"//gpu/command_buffer/client:gles2_interface",
"//skia",
diff --git a/chromium/components/exo/DEPS b/chromium/components/exo/DEPS
index 860fb114185..4f81d0ee5b5 100644
--- a/chromium/components/exo/DEPS
+++ b/chromium/components/exo/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+device/gamepad",
"+gpu",
"+mojo/public/cpp",
+ "+services/ui/public/interfaces",
"+third_party/khronos",
"+third_party/skia",
"+ui",
@@ -16,4 +17,8 @@ specific_include_rules = {
"run_all_unittests\.cc": [
"+mojo/edk/embedder/embedder.h",
],
+
+ "surface_unittest\.cc": [
+ "+components/viz/test",
+ ],
}
diff --git a/chromium/components/exo/buffer.cc b/chromium/components/exo/buffer.cc
index 011aa770f65..fcdadbeaf3a 100644
--- a/chromium/components/exo/buffer.cc
+++ b/chromium/components/exo/buffer.cc
@@ -21,11 +21,11 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
-#include "cc/resources/single_release_callback.h"
#include "components/exo/layer_tree_frame_sink_holder.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/quads/single_release_callback.h"
#include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/aura/env.h"
@@ -414,15 +414,10 @@ Buffer::~Buffer() {}
bool Buffer::ProduceTransferableResource(
LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
- cc::ResourceId resource_id,
bool secure_output_only,
- bool client_usage,
- cc::TransferableResource* resource) {
+ viz::TransferableResource* resource) {
TRACE_EVENT0("exo", "Buffer::ProduceTransferableResource");
-
DCHECK(attach_count_);
- DLOG_IF(WARNING, !release_contents_callback_.IsCancelled() && client_usage)
- << "Producing a texture mailbox for a buffer that has not been released";
// If textures are lost, destroy them to ensure that we create new ones below.
if (contents_texture_ && contents_texture_->IsLost())
@@ -442,7 +437,7 @@ bool Buffer::ProduceTransferableResource(
return false;
}
- resource->id = resource_id;
+ resource->id = layer_tree_frame_sink_holder->AllocateResourceId();
resource->format = viz::RGBA_8888;
resource->filter = GL_LINEAR;
resource->size = gpu_memory_buffer_->GetSize();
@@ -476,7 +471,7 @@ bool Buffer::ProduceTransferableResource(
// The contents texture will be released when no longer used by the
// compositor.
layer_tree_frame_sink_holder->SetResourceReleaseCallback(
- resource_id,
+ resource->id,
base::Bind(&Buffer::Texture::ReleaseTexImage,
base::Unretained(contents_texture),
base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
@@ -506,7 +501,7 @@ bool Buffer::ProduceTransferableResource(
// The mailbox texture will be released when no longer used by the
// compositor.
layer_tree_frame_sink_holder->SetResourceReleaseCallback(
- resource_id,
+ resource->id,
base::Bind(&Buffer::Texture::Release, base::Unretained(texture),
base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
base::Passed(&texture_))));
diff --git a/chromium/components/exo/buffer.h b/chromium/components/exo/buffer.h
index 890edf4ce9a..0c722beddf7 100644
--- a/chromium/components/exo/buffer.h
+++ b/chromium/components/exo/buffer.h
@@ -11,7 +11,7 @@
#include "base/cancelable_callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "cc/resources/transferable_resource.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "ui/gfx/geometry/size.h"
namespace base {
@@ -54,10 +54,8 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
// |non_client_usage| is true.
bool ProduceTransferableResource(
LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
- cc::ResourceId resource_id,
bool secure_output_only,
- bool client_usage,
- cc::TransferableResource* resource);
+ viz::TransferableResource* resource);
// This should be called when the buffer is attached to a Surface.
void OnAttach();
diff --git a/chromium/components/exo/buffer_unittest.cc b/chromium/components/exo/buffer_unittest.cc
index 29e32e5b1d4..457c0e38891 100644
--- a/chromium/components/exo/buffer_unittest.cc
+++ b/chromium/components/exo/buffer_unittest.cc
@@ -5,12 +5,12 @@
#include <GLES2/gl2extchromium.h>
#include "base/bind.h"
-#include "cc/resources/single_release_callback.h"
#include "components/exo/buffer.h"
-#include "components/exo/surface.h"
+#include "components/exo/surface_tree_host.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/quads/single_release_callback.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2.h"
@@ -30,12 +30,12 @@ void Release(int* release_call_count) {
TEST_F(BufferTest, ReleaseCallback) {
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);
- const viz::FrameSinkId arbitrary_frame_sink_id(1, 1);
- LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder =
- surface->layer_tree_frame_sink_holder();
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface_tree_host =
+ base::MakeUnique<SurfaceTreeHost>("BufferTest", nullptr);
+ LayerTreeFrameSinkHolder* frame_sink_holder =
+ surface_tree_host->layer_tree_frame_sink_holder();
// Set the release callback.
int release_call_count = 0;
@@ -43,19 +43,19 @@ TEST_F(BufferTest, ReleaseCallback) {
base::Bind(&Release, base::Unretained(&release_call_count)));
buffer->OnAttach();
- cc::TransferableResource resource;
+ viz::TransferableResource resource;
// Produce a transferable resource for the contents of the buffer.
- bool rv = buffer->ProduceTransferableResource(layer_tree_frame_sink_holder, 0,
- false, true, &resource);
+ bool rv =
+ buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
ASSERT_TRUE(rv);
// Release buffer.
- cc::ReturnedResource returned_resource;
+ viz::ReturnedResource returned_resource;
returned_resource.id = resource.id;
returned_resource.sync_token = resource.mailbox_holder.sync_token;
returned_resource.lost = false;
- std::vector<cc::ReturnedResource> resources = {returned_resource};
- layer_tree_frame_sink_holder->ReclaimResources(resources);
+ std::vector<viz::ReturnedResource> resources = {returned_resource};
+ frame_sink_holder->ReclaimResources(resources);
RunAllPendingInMessageLoop();
ASSERT_EQ(release_call_count, 0);
@@ -68,19 +68,18 @@ TEST_F(BufferTest, ReleaseCallback) {
TEST_F(BufferTest, IsLost) {
gfx::Size buffer_size(256, 256);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- const viz::FrameSinkId arbitrary_frame_sink_id(1, 1);
- std::unique_ptr<Surface> surface(new Surface);
- LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder =
- surface->layer_tree_frame_sink_holder();
- cc::ResourceId resource_id = 0;
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface_tree_host =
+ base::MakeUnique<SurfaceTreeHost>("BufferTest", nullptr);
+ LayerTreeFrameSinkHolder* frame_sink_holder =
+ surface_tree_host->layer_tree_frame_sink_holder();
buffer->OnAttach();
// Acquire a texture transferable resource for the contents of the buffer.
- cc::TransferableResource resource;
- bool rv = buffer->ProduceTransferableResource(
- layer_tree_frame_sink_holder, resource_id, false, true, &resource);
+ viz::TransferableResource resource;
+ bool rv =
+ buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
ASSERT_TRUE(rv);
scoped_refptr<viz::ContextProvider> context_provider =
@@ -95,29 +94,28 @@ TEST_F(BufferTest, IsLost) {
// Release buffer.
bool is_lost = true;
- cc::ReturnedResource returned_resource;
- returned_resource.id = resource_id;
+ viz::ReturnedResource returned_resource;
+ returned_resource.id = resource.id;
returned_resource.sync_token = gpu::SyncToken();
returned_resource.lost = is_lost;
- std::vector<cc::ReturnedResource> resources = {returned_resource};
- layer_tree_frame_sink_holder->ReclaimResources(resources);
+ std::vector<viz::ReturnedResource> resources = {returned_resource};
+ frame_sink_holder->ReclaimResources(resources);
RunAllPendingInMessageLoop();
// Producing a new texture transferable resource for the contents of the
// buffer.
- ++resource_id;
- cc::TransferableResource new_resource;
- rv = buffer->ProduceTransferableResource(
- layer_tree_frame_sink_holder, resource_id, false, false, &new_resource);
+ viz::TransferableResource new_resource;
+ rv = buffer->ProduceTransferableResource(frame_sink_holder, false,
+ &new_resource);
ASSERT_TRUE(rv);
buffer->OnDetach();
- cc::ReturnedResource returned_resource2;
- returned_resource2.id = resource_id;
+ viz::ReturnedResource returned_resource2;
+ returned_resource2.id = new_resource.id;
returned_resource2.sync_token = gpu::SyncToken();
returned_resource2.lost = false;
- std::vector<cc::ReturnedResource> resources2 = {returned_resource2};
- layer_tree_frame_sink_holder->ReclaimResources(resources2);
+ std::vector<viz::ReturnedResource> resources2 = {returned_resource2};
+ frame_sink_holder->ReclaimResources(resources2);
RunAllPendingInMessageLoop();
}
@@ -136,8 +134,8 @@ TEST_F(BufferTest, OnLostResources) {
buffer->OnAttach();
// Acquire a texture transferable resource for the contents of the buffer.
viz::TransferableResource resource;
- bool rv = buffer->ProduceTransferableResource(frame_sink_holder, false, true,
- &resource);
+ bool rv =
+ buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
ASSERT_TRUE(rv);
static_cast<ui::InProcessContextFactory*>(
diff --git a/chromium/components/exo/display.cc b/chromium/components/exo/display.cc
index 6bf7395a08a..c55757f083d 100644
--- a/chromium/components/exo/display.cc
+++ b/chromium/components/exo/display.cc
@@ -183,7 +183,8 @@ std::unique_ptr<ShellSurface> Display::CreatePopupShellSurface(
std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
Surface* surface,
- int container) {
+ int container,
+ double default_device_scale_factor) {
TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface",
surface->AsTracedValue(), "container", container);
@@ -195,9 +196,12 @@ std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
// Remote shell surfaces in system modal container cannot be minimized.
bool can_minimize = container != ash::kShellWindowId_SystemModalContainer;
- return base::MakeUnique<ShellSurface>(
+ std::unique_ptr<ShellSurface> shell_surface(base::MakeUnique<ShellSurface>(
surface, nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(),
- true /* activatable */, can_minimize, container);
+ true /* activatable */, can_minimize, container));
+ DCHECK_GE(default_device_scale_factor, 1.0);
+ shell_surface->SetScale(default_device_scale_factor);
+ return shell_surface;
}
std::unique_ptr<SubSurface> Display::CreateSubSurface(Surface* surface,
diff --git a/chromium/components/exo/display.h b/chromium/components/exo/display.h
index e115d200017..7e75762ef0d 100644
--- a/chromium/components/exo/display.h
+++ b/chromium/components/exo/display.h
@@ -78,9 +78,11 @@ class Display {
const gfx::Point& position);
// Creates a remote shell surface for an existing surface using |container|.
+ // The surface is scaled by 1 / |default_device_scale_factor|.
std::unique_ptr<ShellSurface> CreateRemoteShellSurface(
Surface* surface,
- int container);
+ int container,
+ double default_device_scale_factor);
// Creates a sub-surface for an existing surface. The sub-surface will be
// a child of |parent|.
diff --git a/chromium/components/exo/display_unittest.cc b/chromium/components/exo/display_unittest.cc
index 68aca8980e4..6d68c958355 100644
--- a/chromium/components/exo/display_unittest.cc
+++ b/chromium/components/exo/display_unittest.cc
@@ -150,13 +150,15 @@ TEST_F(DisplayTest, CreateRemoteShellSurface) {
// Create a remote shell surface for surface1.
std::unique_ptr<ShellSurface> shell_surface1 =
display->CreateRemoteShellSurface(
- surface1.get(), ash::kShellWindowId_SystemModalContainer);
+ surface1.get(), ash::kShellWindowId_SystemModalContainer,
+ 2.0 /* default_scale_factor */);
EXPECT_TRUE(shell_surface1);
// Create a remote shell surface for surface2.
std::unique_ptr<ShellSurface> shell_surface2 =
display->CreateRemoteShellSurface(surface2.get(),
- ash::kShellWindowId_DefaultContainer);
+ ash::kShellWindowId_DefaultContainer,
+ 1.0 /* default_scale_factor */);
EXPECT_TRUE(shell_surface2);
}
diff --git a/chromium/components/exo/gaming_seat.h b/chromium/components/exo/gaming_seat.h
index 2c9787f08a9..ad4c28e0b6b 100644
--- a/chromium/components/exo/gaming_seat.h
+++ b/chromium/components/exo/gaming_seat.h
@@ -65,6 +65,10 @@ class GamingSeat : public WMHelper::FocusObserver
#if defined(USE_OZONE_GAMEPAD)
// Contains the delegate for each gamepad device.
base::flat_map<int, GamepadDelegate*> gamepads_;
+
+ // The flag if a valid target for gaming seat is focused. In other words, if
+ // it's true, this class is observing gamepad events.
+ bool focused_ = false;
#else
class ThreadSafeGamepadChangeFetcher;
diff --git a/chromium/components/exo/gaming_seat_ozone.cc b/chromium/components/exo/gaming_seat_ozone.cc
index 0429e95c925..59631e128be 100644
--- a/chromium/components/exo/gaming_seat_ozone.cc
+++ b/chromium/components/exo/gaming_seat_ozone.cc
@@ -23,7 +23,8 @@ GamingSeat::GamingSeat(GamingSeatDelegate* delegate,
}
GamingSeat::~GamingSeat() {
- ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
+ if (focused_)
+ ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
delegate_->OnGamingSeatDestroying(this);
// Disconnect all the gamepads.
for (auto& entry : gamepads_)
@@ -48,11 +49,14 @@ void GamingSeat::OnWindowFocused(aura::Window* gained_focus,
}
bool focused = target && delegate_->CanAcceptGamepadEventsForSurface(target);
- if (focused) {
- ui::GamepadProviderOzone::GetInstance()->AddGamepadObserver(this);
- OnGamepadDevicesUpdated();
- } else {
- ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
+ if (focused_ != focused) {
+ focused_ = focused;
+ if (focused) {
+ ui::GamepadProviderOzone::GetInstance()->AddGamepadObserver(this);
+ OnGamepadDevicesUpdated();
+ } else {
+ ui::GamepadProviderOzone::GetInstance()->RemoveGamepadObserver(this);
+ }
}
}
diff --git a/chromium/components/exo/keyboard_unittest.cc b/chromium/components/exo/keyboard_unittest.cc
index 88441881556..ba7ff9ba237 100644
--- a/chromium/components/exo/keyboard_unittest.cc
+++ b/chromium/components/exo/keyboard_unittest.cc
@@ -7,6 +7,7 @@
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "components/exo/buffer.h"
#include "components/exo/keyboard_delegate.h"
#include "components/exo/keyboard_device_configuration_delegate.h"
diff --git a/chromium/components/exo/layer_tree_frame_sink_holder.cc b/chromium/components/exo/layer_tree_frame_sink_holder.cc
index a750192d97a..05c10a1f1bb 100644
--- a/chromium/components/exo/layer_tree_frame_sink_holder.cc
+++ b/chromium/components/exo/layer_tree_frame_sink_holder.cc
@@ -5,8 +5,8 @@
#include "components/exo/layer_tree_frame_sink_holder.h"
#include "cc/output/layer_tree_frame_sink.h"
-#include "cc/resources/returned_resource.h"
-#include "components/exo/surface.h"
+#include "components/exo/surface_tree_host.h"
+#include "components/viz/common/resources/returned_resource.h"
namespace exo {
@@ -14,19 +14,16 @@ namespace exo {
// LayerTreeFrameSinkHolder, public:
LayerTreeFrameSinkHolder::LayerTreeFrameSinkHolder(
- Surface* surface,
+ SurfaceTreeHost* surface_tree_host,
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink)
- : surface_(surface),
+ : surface_tree_host_(surface_tree_host),
frame_sink_(std::move(frame_sink)),
weak_factory_(this) {
- surface_->AddSurfaceObserver(this);
frame_sink_->BindToClient(this);
}
LayerTreeFrameSinkHolder::~LayerTreeFrameSinkHolder() {
frame_sink_->DetachFromClient();
- if (surface_)
- surface_->RemoveSurfaceObserver(this);
// Release all resources which aren't returned from LayerTreeFrameSink.
for (auto& callback : release_callbacks_)
@@ -34,13 +31,13 @@ LayerTreeFrameSinkHolder::~LayerTreeFrameSinkHolder() {
}
bool LayerTreeFrameSinkHolder::HasReleaseCallbackForResource(
- cc::ResourceId id) {
+ viz::ResourceId id) {
return release_callbacks_.find(id) != release_callbacks_.end();
}
void LayerTreeFrameSinkHolder::SetResourceReleaseCallback(
- cc::ResourceId id,
- const cc::ReleaseCallback& callback) {
+ viz::ResourceId id,
+ const viz::ReleaseCallback& callback) {
DCHECK(!callback.is_null());
release_callbacks_[id] = callback;
}
@@ -57,13 +54,13 @@ base::WeakPtr<LayerTreeFrameSinkHolder> LayerTreeFrameSinkHolder::GetWeakPtr() {
// cc::LayerTreeFrameSinkClient overrides:
void LayerTreeFrameSinkHolder::SetBeginFrameSource(
- cc::BeginFrameSource* source) {
- if (surface_)
- surface_->SetBeginFrameSource(source);
+ viz::BeginFrameSource* source) {
+ if (surface_tree_host_)
+ surface_tree_host_->SetBeginFrameSource(source);
}
void LayerTreeFrameSinkHolder::ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<viz::ReturnedResource>& resources) {
for (auto& resource : resources) {
auto it = release_callbacks_.find(resource.id);
DCHECK(it != release_callbacks_.end());
@@ -75,16 +72,7 @@ void LayerTreeFrameSinkHolder::ReclaimResources(
}
void LayerTreeFrameSinkHolder::DidReceiveCompositorFrameAck() {
- if (surface_)
- surface_->DidReceiveCompositorFrameAck();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SurfaceObserver overrides:
-
-void LayerTreeFrameSinkHolder::OnSurfaceDestroying(Surface* surface) {
- surface_->RemoveSurfaceObserver(this);
- surface_ = nullptr;
+ surface_tree_host_->DidReceiveCompositorFrameAck();
}
} // namespace exo
diff --git a/chromium/components/exo/layer_tree_frame_sink_holder.h b/chromium/components/exo/layer_tree_frame_sink_holder.h
index 12b0c453c22..2d950ef77a2 100644
--- a/chromium/components/exo/layer_tree_frame_sink_holder.h
+++ b/chromium/components/exo/layer_tree_frame_sink_holder.h
@@ -9,39 +9,35 @@
#include "base/containers/flat_map.h"
#include "cc/output/layer_tree_frame_sink_client.h"
-#include "cc/resources/release_callback.h"
-#include "components/exo/surface_observer.h"
+#include "components/viz/common/quads/release_callback.h"
namespace cc {
class LayerTreeFrameSink;
}
namespace exo {
-class Surface;
+class SurfaceTreeHost;
// This class talks to CompositorFrameSink and keeps track of references to
-// the contents of Buffers. It's keeped alive by references from
-// release_callbacks_. It's destroyed when its owning Surface is destroyed and
-// the last outstanding release callback is called.
-class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient,
- public SurfaceObserver {
+// the contents of Buffers.
+class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient {
public:
- LayerTreeFrameSinkHolder(Surface* surface,
+ LayerTreeFrameSinkHolder(SurfaceTreeHost* surface_tree_host,
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink);
~LayerTreeFrameSinkHolder() override;
- bool HasReleaseCallbackForResource(cc::ResourceId id);
- void SetResourceReleaseCallback(cc::ResourceId id,
- const cc::ReleaseCallback& callback);
+ bool HasReleaseCallbackForResource(viz::ResourceId id);
+ void SetResourceReleaseCallback(viz::ResourceId id,
+ const viz::ReleaseCallback& callback);
int AllocateResourceId();
base::WeakPtr<LayerTreeFrameSinkHolder> GetWeakPtr();
cc::LayerTreeFrameSink* frame_sink() { return frame_sink_.get(); }
// Overridden from cc::LayerTreeFrameSinkClient:
- void SetBeginFrameSource(cc::BeginFrameSource* source) override;
+ void SetBeginFrameSource(viz::BeginFrameSource* source) override;
void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override;
+ const std::vector<viz::ReturnedResource>& resources) override;
void SetTreeActivationCallback(const base::Closure& callback) override {}
void DidReceiveCompositorFrameAck() override;
void DidLoseLayerTreeFrameSink() override {}
@@ -53,15 +49,13 @@ class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient,
const gfx::Rect& viewport_rect,
const gfx::Transform& transform) override {}
- // Overridden from SurfaceObserver:
- void OnSurfaceDestroying(Surface* surface) override;
-
private:
// A collection of callbacks used to release resources.
- using ResourceReleaseCallbackMap = base::flat_map<int, cc::ReleaseCallback>;
+ using ResourceReleaseCallbackMap =
+ base::flat_map<viz::ResourceId, viz::ReleaseCallback>;
ResourceReleaseCallbackMap release_callbacks_;
- Surface* surface_;
+ SurfaceTreeHost* surface_tree_host_;
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink_;
// The next resource id the buffer is attached to.
diff --git a/chromium/components/exo/notification_surface.cc b/chromium/components/exo/notification_surface.cc
index 79f613b5e92..40ee243971c 100644
--- a/chromium/components/exo/notification_surface.cc
+++ b/chromium/components/exo/notification_surface.cc
@@ -7,73 +7,14 @@
#include "components/exo/notification_surface_manager.h"
#include "components/exo/surface.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/hit_test.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/views/widget/widget.h"
namespace exo {
-namespace {
-
-class CustomWindowDelegate : public aura::WindowDelegate {
- public:
- explicit CustomWindowDelegate(NotificationSurface* notification_surface)
- : notification_surface_(notification_surface) {}
- ~CustomWindowDelegate() override {}
-
- // Overridden from aura::WindowDelegate:
- gfx::Size GetMinimumSize() const override { return gfx::Size(); }
- gfx::Size GetMaximumSize() const override { return gfx::Size(); }
- void OnBoundsChanged(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override {}
- gfx::NativeCursor GetCursor(const gfx::Point& point) override {
- return notification_surface_->GetCursor(point);
- }
- int GetNonClientComponent(const gfx::Point& point) const override {
- return HTNOWHERE;
- }
- bool ShouldDescendIntoChildForEventHandling(
- aura::Window* child,
- const gfx::Point& location) override {
- return true;
- }
- bool CanFocus() override { return true; }
- void OnCaptureLost() override {}
- void OnPaint(const ui::PaintContext& context) override {}
- void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
- void OnWindowDestroying(aura::Window* window) override {}
- void OnWindowDestroyed(aura::Window* window) override { delete this; }
- void OnWindowTargetVisibilityChanged(bool visible) override {}
- bool HasHitTestMask() const override {
- return notification_surface_->HasHitTestMask();
- }
- void GetHitTestMask(gfx::Path* mask) const override {
- notification_surface_->GetHitTestMask(mask);
- }
- void OnKeyEvent(ui::KeyEvent* event) override {
- // Propagates the key event upto the top-level views Widget so that we can
- // trigger proper events in the views/ash level there. Event handling for
- // Surfaces is done in a post event handler in keyboard.cc.
- views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
- notification_surface_->host_window());
- if (widget)
- widget->OnKeyEvent(event);
- }
-
- private:
- NotificationSurface* const notification_surface_;
-
- DISALLOW_COPY_AND_ASSIGN(CustomWindowDelegate);
-};
-
-} // namespace
-
NotificationSurface::NotificationSurface(NotificationSurfaceManager* manager,
Surface* surface,
const std::string& notification_key)
- : SurfaceTreeHost("ExoNotificationSurface", new CustomWindowDelegate(this)),
+ : SurfaceTreeHost("ExoNotificationSurface", nullptr),
manager_(manager),
notification_key_(notification_key) {
surface->AddSurfaceObserver(this);
@@ -95,18 +36,13 @@ const gfx::Size& NotificationSurface::GetContentSize() const {
void NotificationSurface::OnSurfaceCommit() {
SurfaceTreeHost::OnSurfaceCommit();
- gfx::Rect bounds = host_window()->bounds();
- auto& size = host_window()->bounds().size();
- if (bounds.size() != size) {
- bounds.set_size(size);
- host_window()->SetBounds(bounds);
- }
-
// Defer AddSurface until there are contents to show.
- if (!added_to_manager_ && !size.IsEmpty()) {
+ if (!added_to_manager_ && !host_window()->bounds().IsEmpty()) {
added_to_manager_ = true;
manager_->AddSurface(this);
}
+
+ SubmitCompositorFrame();
}
void NotificationSurface::OnSurfaceDestroying(Surface* surface) {
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index a08283c4959..1ad08d48167 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -7,12 +7,12 @@
#include <utility>
#include "ash/public/cpp/shell_window_ids.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/pointer_stylus_delegate.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/quads/copy_output_result.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
@@ -158,8 +158,10 @@ void Pointer::OnSurfaceCommit() {
SurfaceTreeHost::OnSurfaceCommit();
// Capture new cursor to reflect result of commit.
- if (focus_surface_)
+ if (focus_surface_ && !host_window()->bounds().IsEmpty())
CaptureCursor(hotspot_);
+
+ SubmitCompositorFrame();
}
////////////////////////////////////////////////////////////////////////////////
@@ -361,8 +363,8 @@ void Pointer::CaptureCursor(const gfx::Point& hotspot) {
capture_scale_ / display.device_scale_factor();
host_window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
- std::unique_ptr<cc::CopyOutputRequest> request =
- cc::CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+ std::unique_ptr<viz::CopyOutputRequest> request =
+ viz::CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
&Pointer::OnCursorCaptured,
cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
@@ -371,7 +373,7 @@ void Pointer::CaptureCursor(const gfx::Point& hotspot) {
}
void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
- std::unique_ptr<cc::CopyOutputResult> result) {
+ std::unique_ptr<viz::CopyOutputResult> result) {
if (!focus_surface_)
return;
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index 109bb592231..21d98c720d2 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -21,7 +21,7 @@
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/native_widget_types.h"
-namespace cc {
+namespace viz {
class CopyOutputResult;
}
@@ -87,7 +87,7 @@ class Pointer : public SurfaceTreeHost,
// Called when cursor snapshot has been captured.
void OnCursorCaptured(const gfx::Point& hotspot,
- std::unique_ptr<cc::CopyOutputResult> result);
+ std::unique_ptr<viz::CopyOutputResult> result);
// Update |cursor_| to |cursor_bitmap_| transformed for the current display.
void UpdateCursor();
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index 1831ec5c2ab..014b49306c5 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -11,6 +11,7 @@
#include "components/exo/buffer.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/shell_surface.h"
+#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_helper.h"
@@ -152,7 +153,8 @@ TEST_F(PointerTest, OnPointerMotion) {
gfx::Vector2d(1, 1));
std::unique_ptr<Surface> sub_surface(new Surface);
- surface->AddSubSurface(sub_surface.get());
+ std::unique_ptr<SubSurface> sub(
+ new SubSurface(sub_surface.get(), surface.get()));
surface->SetSubSurfacePosition(sub_surface.get(), gfx::Point(5, 5));
gfx::Size sub_buffer_size(5, 5);
std::unique_ptr<Buffer> sub_buffer(
diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc
index 395cb87d848..e6e7a7ddc30 100644
--- a/chromium/components/exo/shell_surface.cc
+++ b/chromium/components/exo/shell_surface.cc
@@ -21,7 +21,9 @@
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
+#include "cc/output/layer_tree_frame_sink.h"
#include "components/exo/surface.h"
+#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
@@ -651,8 +653,11 @@ void ShellSurface::SetRectangularShadow_DEPRECATED(
TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadow_DEPRECATED",
"content_bounds", content_bounds.ToString());
pending_shadow_underlay_in_surface_ = false;
- shadow_content_bounds_ = content_bounds;
- shadow_enabled_ = !content_bounds.IsEmpty();
+ if (content_bounds != shadow_content_bounds_) {
+ shadow_content_bounds_ = content_bounds;
+ shadow_content_bounds_changed_ = true;
+ shadow_enabled_ = !content_bounds.IsEmpty();
+ }
}
void ShellSurface::SetRectangularSurfaceShadow(
@@ -660,8 +665,11 @@ void ShellSurface::SetRectangularSurfaceShadow(
TRACE_EVENT1("exo", "ShellSurface::SetRectangularSurfaceShadow",
"content_bounds", content_bounds.ToString());
pending_shadow_underlay_in_surface_ = true;
- shadow_content_bounds_ = content_bounds;
- shadow_enabled_ = !content_bounds.IsEmpty();
+ if (content_bounds != shadow_content_bounds_) {
+ shadow_content_bounds_ = content_bounds;
+ shadow_content_bounds_changed_ = true;
+ shadow_enabled_ = !content_bounds.IsEmpty();
+ }
}
void ShellSurface::SetRectangularShadowBackgroundOpacity(float opacity) {
@@ -741,11 +749,18 @@ std::unique_ptr<base::trace_event::TracedValue> ShellSurface::AsTracedValue()
// SurfaceDelegate overrides:
void ShellSurface::OnSurfaceCommit() {
+ // When the shadow underlay is in surface coordinate space and the surface's
+ // bounds have changed, shadow API requires that we synchronize the shadow
+ // bounds change with the next frame, so we have to submit the next frame to a
+ // new surface, and let the host_window() use the new surface.
+ if (pending_shadow_underlay_in_surface_ && shadow_content_bounds_changed_)
+ host_window()->AllocateLocalSurfaceId();
+
SurfaceTreeHost::OnSurfaceCommit();
if (enabled() && !widget_) {
// Defer widget creation until surface contains some contents.
- if (host_window()->bounds().size().IsEmpty()) {
+ if (host_window()->bounds().IsEmpty()) {
Configure();
return;
}
@@ -753,6 +768,8 @@ void ShellSurface::OnSurfaceCommit() {
CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
}
+ SubmitCompositorFrame();
+
// Apply the accumulated pending origin offset to reflect acknowledged
// configure requests.
origin_offset_ += pending_origin_offset_;
@@ -1008,6 +1025,9 @@ void ShellSurface::OnPostWindowStateTypeChange(
void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
+ if (window == host_window())
+ return;
+
// TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does not
// yet support resizing. See crbug.com/699746.
if (bounds_mode_ == BoundsMode::CLIENT)
@@ -1039,7 +1059,23 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
}
}
+void ShellSurface::OnWindowAddedToRootWindow(aura::Window* window) {
+ if (window == host_window())
+ SurfaceTreeHost::OnWindowAddedToRootWindow(window);
+}
+
+void ShellSurface::OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) {
+ if (window == host_window())
+ SurfaceTreeHost::OnWindowRemovingFromRootWindow(window, new_root);
+}
+
void ShellSurface::OnWindowDestroying(aura::Window* window) {
+ if (window == host_window()) {
+ SurfaceTreeHost::OnWindowDestroying(window);
+ return;
+ }
+
if (window == parent_) {
parent_ = nullptr;
// |parent_| being set to null effects the ability to maximize the window.
@@ -1533,8 +1569,11 @@ bool ShellSurface::IsResizing() const {
gfx::Rect ShellSurface::GetVisibleBounds() const {
// Use |geometry_| if set, otherwise use the visual bounds of the surface.
- return geometry_.IsEmpty() ? gfx::Rect(host_window()->bounds().size())
- : geometry_;
+ if (!geometry_.IsEmpty())
+ return geometry_;
+
+ return root_surface() ? gfx::Rect(root_surface()->content_size())
+ : gfx::Rect();
}
gfx::Point ShellSurface::GetSurfaceOrigin() const {
@@ -1665,20 +1704,22 @@ void ShellSurface::UpdateSurfaceBounds() {
void ShellSurface::UpdateShadow() {
if (!widget_ || !root_surface())
return;
+
if (shadow_underlay_in_surface_ != pending_shadow_underlay_in_surface_) {
shadow_underlay_in_surface_ = pending_shadow_underlay_in_surface_;
shadow_overlay_.reset();
shadow_underlay_.reset();
}
+ shadow_content_bounds_changed_ = false;
+
UpdateBackdrop();
aura::Window* window = widget_->GetNativeWindow();
if (!shadow_enabled_) {
wm::SetShadowElevation(window, wm::ShadowElevation::NONE);
- if (shadow_underlay_)
- shadow_underlay_->Hide();
+ shadow_underlay_.reset();
} else {
wm::SetShadowElevation(window, wm::ShadowElevation::DEFAULT);
gfx::Rect shadow_content_bounds =
@@ -1691,19 +1732,6 @@ void ShellSurface::UpdateShadow() {
shadow_content_bounds.set_origin(origin);
}
- gfx::Rect shadow_underlay_bounds = shadow_content_bounds_;
-
- if (shadow_underlay_bounds.IsEmpty()) {
- shadow_underlay_bounds = gfx::Rect(host_window()->bounds().size());
- } else if (shadow_underlay_in_surface_) {
- // Since the shadow underlay is positioned relative to the surface, its
- // origin corresponds to the shadow content position relative to the
- // origin specified by the client.
- shadow_underlay_bounds -=
- gfx::ScaleToCeiledPoint(origin_ + origin_offset_, scale_)
- .OffsetFromOrigin();
- }
-
if (!shadow_underlay_in_surface_) {
shadow_content_bounds = shadow_content_bounds_;
if (shadow_content_bounds.IsEmpty()) {
@@ -1720,49 +1748,40 @@ void ShellSurface::UpdateShadow() {
shadow_origin -= window->bounds().OffsetFromOrigin();
gfx::Rect shadow_bounds(shadow_origin, shadow_content_bounds.size());
- // Always create and show the underlay, even in maximized/fullscreen.
- if (!shadow_underlay_) {
- shadow_underlay_ = base::MakeUnique<aura::Window>(nullptr);
- shadow_underlay_->set_owned_by_parent(false);
- DCHECK(!shadow_underlay_->owned_by_parent());
- // Ensure the background area inside the shadow is solid black.
- // Clients that provide translucent contents should not be using
- // rectangular shadows as this method requires opaque contents to
- // cast a shadow that represent it correctly.
- shadow_underlay_->Init(ui::LAYER_SOLID_COLOR);
- shadow_underlay_->layer()->SetColor(SK_ColorBLACK);
- DCHECK(shadow_underlay_->layer()->fills_bounds_opaquely());
- if (shadow_underlay_in_surface_) {
- host_window()->AddChild(shadow_underlay());
- host_window()->StackChildAtBottom(shadow_underlay());
- } else {
+ bool needs_shadow_underlay = shadow_background_opacity_ > 0.f;
+ if (needs_shadow_underlay) {
+ if (!shadow_underlay_) {
+ shadow_underlay_ = base::MakeUnique<aura::Window>(nullptr);
+ shadow_underlay_->set_owned_by_parent(false);
+ DCHECK(!shadow_underlay_->owned_by_parent());
+ // Ensure the background area inside the shadow is solid black.
+ // Clients that provide translucent contents should not be using
+ // rectangular shadows as this method requires opaque contents to
+ // cast a shadow that represent it correctly.
+ shadow_underlay_->Init(ui::LAYER_SOLID_COLOR);
+ shadow_underlay_->layer()->SetColor(SK_ColorBLACK);
+ DCHECK(shadow_underlay_->layer()->fills_bounds_opaquely());
window->AddChild(shadow_underlay());
window->StackChildAtBottom(shadow_underlay());
}
- }
-
- float shadow_underlay_opacity = shadow_background_opacity_;
-
- if (!shadow_underlay_in_surface_)
- shadow_underlay_bounds = shadow_bounds;
-
- // Constrain the underlay bounds to the client area in case shell surface
- // frame is enabled.
- if (frame_enabled_) {
- shadow_underlay_bounds.Intersect(
- widget_->non_client_view()->frame_view()->GetBoundsForClientView());
- }
-
- shadow_underlay_->SetBounds(shadow_underlay_bounds);
-
- if (!shadow_underlay_->IsVisible())
- shadow_underlay_->Show();
-
- // TODO(oshima): Setting to the same value should be no-op.
- // crbug.com/642223.
- if (shadow_underlay_opacity !=
- shadow_underlay_->layer()->GetTargetOpacity()) {
- shadow_underlay_->layer()->SetOpacity(shadow_underlay_opacity);
+ gfx::Rect shadow_underlay_bounds(shadow_bounds);
+ // Constrain the underlay bounds to the client area in case shell surface
+ // frame is enabled.
+ if (frame_enabled_) {
+ shadow_underlay_bounds.Intersect(
+ widget_->non_client_view()->frame_view()->GetBoundsForClientView());
+ }
+ shadow_underlay_->SetBounds(shadow_underlay_bounds);
+ if (!shadow_underlay_->IsVisible())
+ shadow_underlay_->Show();
+ // TODO(oshima): Setting to the same value should be no-op.
+ // crbug.com/642223.
+ if (shadow_background_opacity_ !=
+ shadow_underlay_->layer()->GetTargetOpacity()) {
+ shadow_underlay_->layer()->SetOpacity(shadow_background_opacity_);
+ }
+ } else {
+ shadow_underlay_.reset();
}
wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
@@ -1774,16 +1793,12 @@ void ShellSurface::UpdateShadow() {
shadow_overlay_ = base::MakeUnique<aura::Window>(nullptr);
shadow_overlay_->set_owned_by_parent(false);
DCHECK(!shadow_overlay_->owned_by_parent());
- shadow_overlay_->set_ignore_events(true);
+ shadow_overlay_->SetEventTargetingPolicy(
+ ui::mojom::EventTargetingPolicy::NONE);
shadow_overlay_->Init(ui::LAYER_NOT_DRAWN);
shadow_overlay_->layer()->Add(shadow->layer());
window->AddChild(shadow_overlay());
-
- if (shadow_underlay_in_surface_) {
- window->StackChildBelow(shadow_overlay(), host_window());
- } else {
- window->StackChildAbove(shadow_overlay(), shadow_underlay());
- }
+ window->StackChildBelow(shadow_overlay(), host_window());
shadow_overlay_->Show();
}
shadow_overlay_->SetBounds(shadow_bounds);
diff --git a/chromium/components/exo/shell_surface.h b/chromium/components/exo/shell_surface.h
index efcd3292b90..1e6ecc96216 100644
--- a/chromium/components/exo/shell_surface.h
+++ b/chromium/components/exo/shell_surface.h
@@ -6,17 +6,16 @@
#define COMPONENTS_EXO_SHELL_SURFACE_H_
#include <cstdint>
-#include <deque>
#include <memory>
#include <string>
#include "ash/wm/window_state_observer.h"
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/exo/surface_observer.h"
#include "components/exo/surface_tree_host.h"
#include "components/exo/wm_helper.h"
-#include "ui/aura/window_observer.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/compositor_lock.h"
#include "ui/display/display_observer.h"
@@ -56,10 +55,9 @@ class ShellSurface : public SurfaceTreeHost,
public views::View,
public display::DisplayObserver,
public ash::wm::WindowStateObserver,
- public aura::WindowObserver,
public WMHelper::ActivationObserver,
public WMHelper::DisplayConfigurationObserver,
- NON_EXPORTED_BASE(public ui::CompositorLockClient) {
+ public ui::CompositorLockClient {
public:
enum class BoundsMode { SHELL, CLIENT, FIXED };
@@ -271,6 +269,9 @@ class ShellSurface : public SurfaceTreeHost,
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) override;
+ void OnWindowAddedToRootWindow(aura::Window* window) override;
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override;
void OnWindowDestroying(aura::Window* window) override;
// Overridden from WMHelper::ActivationObserver:
@@ -395,8 +396,9 @@ class ShellSurface : public SurfaceTreeHost,
std::unique_ptr<aura::Window> shadow_overlay_;
std::unique_ptr<aura::Window> shadow_underlay_;
gfx::Rect shadow_content_bounds_;
+ bool shadow_content_bounds_changed_ = false;
float shadow_background_opacity_ = 1.0;
- std::deque<Config> pending_configs_;
+ base::circular_deque<Config> pending_configs_;
std::unique_ptr<ash::WindowResizer> resizer_;
std::unique_ptr<ScopedAnimationsDisabled> scoped_animations_disabled_;
int top_inset_height_ = 0;
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index a8c08164200..d2318e81f78 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -26,6 +26,7 @@
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/wm_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
@@ -33,6 +34,7 @@
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/display/display.h"
+#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/widget/widget.h"
@@ -85,9 +87,13 @@ class ShellSurfaceBoundsModeTest
}
std::unique_ptr<ShellSurface> CreateDefaultShellSurface(Surface* surface) {
- return base::MakeUnique<ShellSurface>(surface, nullptr, GetParam(),
- gfx::Point(), true, false,
- ash::kShellWindowId_DefaultContainer);
+ if (IsClientBoundsMode()) {
+ return Display().CreateRemoteShellSurface(
+ surface, ash::kShellWindowId_DefaultContainer,
+ WMHelper::GetInstance()->GetDefaultDeviceScaleFactor());
+ } else {
+ return Display().CreateShellSurface(surface);
+ }
}
private:
@@ -318,7 +324,7 @@ TEST_F(ShellSurfaceTest, SetApplicationId) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
- EXPECT_EQ(nullptr, shell_surface->GetWidget());
+ EXPECT_FALSE(shell_surface->GetWidget());
shell_surface->SetApplicationId("pre-widget-id");
surface->Attach(buffer.get());
@@ -376,20 +382,73 @@ TEST_F(ShellSurfaceTest, SetGeometry) {
shell_surface->host_window()->bounds().ToString());
}
-TEST_F(ShellSurfaceTest, SetScale) {
+TEST_P(ShellSurfaceBoundsModeTest, DefaultDeviceScaleFactorForcedScaleFactor) {
+ double scale = 1.5;
+ display::Display::SetForceDeviceScaleFactor(scale);
+
+ int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+ display::Display::SetInternalDisplayId(display_id);
+
gfx::Size buffer_size(64, 64);
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()));
+ std::unique_ptr<ShellSurface> shell_surface(
+ CreateDefaultShellSurface(surface.get()));
+ surface->Attach(buffer.get());
+ surface->Commit();
+ gfx::Transform transform;
+ if (IsClientBoundsMode())
+ transform.Scale(1.0 / scale, 1.0 / scale);
+
+ EXPECT_EQ(
+ transform.ToString(),
+ shell_surface->host_window()->layer()->GetTargetTransform().ToString());
+}
+
+TEST_P(ShellSurfaceBoundsModeTest, DefaultDeviceScaleFactorFromDisplayManager) {
+ int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+ display::Display::SetInternalDisplayId(display_id);
+ gfx::Size size(1920, 1080);
+
+ display::DisplayManager* display_manager =
+ ash::Shell::Get()->display_manager();
+
+ double scale = 1.25;
+ scoped_refptr<display::ManagedDisplayMode> mode(
+ new display::ManagedDisplayMode(size, 60.f, false /* overscan */,
+ true /*native*/, 1.0, scale));
+ mode->set_is_default(true);
+
+ display::ManagedDisplayInfo::ManagedDisplayModeList mode_list;
+ mode_list.push_back(mode);
+
+ display::ManagedDisplayInfo native_display_info(display_id, "test", false);
+ native_display_info.SetManagedDisplayModes(mode_list);
+
+ native_display_info.SetBounds(gfx::Rect(size));
+ native_display_info.set_device_scale_factor(scale);
+
+ std::vector<display::ManagedDisplayInfo> display_info_list;
+ display_info_list.push_back(native_display_info);
+
+ display_manager->OnNativeDisplaysChanged(display_info_list);
+ display_manager->UpdateInternalManagedDisplayModeListForTest();
+
+ gfx::Size buffer_size(64, 64);
+ 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(
+ CreateDefaultShellSurface(surface.get()));
- double scale = 1.5;
- shell_surface->SetScale(scale);
surface->Attach(buffer.get());
surface->Commit();
gfx::Transform transform;
- transform.Scale(1.0 / scale, 1.0 / scale);
+ if (IsClientBoundsMode())
+ transform.Scale(1.0 / scale, 1.0 / scale);
+
EXPECT_EQ(
transform.ToString(),
shell_surface->host_window()->layer()->GetTargetTransform().ToString());
@@ -483,6 +542,11 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
base::Bind(&Configure, base::Unretained(&suggested_size),
base::Unretained(&has_state_type),
base::Unretained(&is_resizing), base::Unretained(&is_active)));
+ // Commit without contents should result in a configure callback with empty
+ // suggested size as a mechanims to ask the client size itself.
+ surface->Commit();
+ EXPECT_EQ(gfx::Size(), suggested_size);
+
shell_surface->Maximize();
shell_surface->AcknowledgeConfigure(0);
EXPECT_EQ(CurrentContext()->bounds().width(), suggested_size.width());
@@ -699,12 +763,42 @@ TEST_F(ShellSurfaceTest, SurfaceShadow) {
EXPECT_TRUE(shadow->layer()->visible());
// For surface shadow, the underlay is placed at the bottom of shell surfaces.
- EXPECT_EQ(shell_surface->host_window(),
- shell_surface->shadow_underlay()->parent());
+ EXPECT_EQ(window, shell_surface->shadow_underlay()->parent());
+ EXPECT_EQ(window, shell_surface->shadow_overlay()->parent());
+
+ auto child_it = window->children().begin();
+ EXPECT_EQ(*child_it++, shell_surface->shadow_underlay());
+ EXPECT_EQ(*child_it++, shell_surface->shadow_overlay());
+ EXPECT_EQ(*child_it++, shell_surface->host_window());
+ EXPECT_EQ(child_it, window->children().end());
+
+ // Set the shadow background to 0, and the shadow_underlay should be
+ // destroyed.
+ shell_surface->SetRectangularShadowBackgroundOpacity(0.f);
+ surface->Commit();
+
+ EXPECT_FALSE(shell_surface->shadow_underlay());
+ EXPECT_EQ(window, shell_surface->shadow_overlay()->parent());
+
+ child_it = window->children().begin();
+ EXPECT_EQ(*child_it++, shell_surface->shadow_overlay());
+ EXPECT_EQ(*child_it++, shell_surface->host_window());
+ EXPECT_EQ(child_it, window->children().end());
+
+ // Set the shadow background to 1, and the shadow_underlay should be
+ // recreated.
+ shell_surface->SetRectangularShadowBackgroundOpacity(1.f);
+ surface->Commit();
+
+ EXPECT_TRUE(shell_surface->shadow_underlay());
+ EXPECT_EQ(window, shell_surface->shadow_underlay()->parent());
EXPECT_EQ(window, shell_surface->shadow_overlay()->parent());
- EXPECT_EQ(*shell_surface->host_window()->children().begin(),
- shell_surface->shadow_underlay());
+ child_it = window->children().begin();
+ EXPECT_EQ(*child_it++, shell_surface->shadow_underlay());
+ EXPECT_EQ(*child_it++, shell_surface->shadow_overlay());
+ EXPECT_EQ(*child_it++, shell_surface->host_window());
+ EXPECT_EQ(child_it, window->children().end());
}
TEST_F(ShellSurfaceTest, NonSurfaceShadow) {
@@ -903,7 +997,6 @@ TEST_F(ShellSurfaceTest, ShadowStartMaximized) {
// Underlay should be created even without shadow.
ASSERT_TRUE(shell_surface->shadow_underlay());
EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible());
-
shell_surface->SetRectangularSurfaceShadow(gfx::Rect(0, 0, 0, 0));
// Underlay should be created even without shadow.
ASSERT_TRUE(shell_surface->shadow_underlay());
@@ -999,7 +1092,8 @@ TEST_F(ShellSurfaceTest,
surface->Commit();
EXPECT_EQ(shadow_bounds,
shell_surface->GetWidget()->GetWindowBoundsInScreen());
- ASSERT_EQ(shadow_bounds, shell_surface->shadow_underlay()->bounds());
+ ASSERT_EQ(shadow_bounds,
+ shell_surface->shadow_underlay()->GetBoundsInScreen());
EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().size(),
shell_surface->surface_for_testing()->window()->bounds().size());
diff --git a/chromium/components/exo/sub_surface.cc b/chromium/components/exo/sub_surface.cc
index 1f8e2f3075f..f170daebf13 100644
--- a/chromium/components/exo/sub_surface.cc
+++ b/chromium/components/exo/sub_surface.cc
@@ -96,7 +96,8 @@ void SubSurface::OnSurfaceCommit() {
if (IsSurfaceSynchronized())
return;
- surface_->CommitSurfaceHierarchy();
+ // TODO(penghuang): http://crbug.com/740110 Support async mode.
+ NOTIMPLEMENTED() << "Async subsurface is not supported!";
}
bool SubSurface::IsSurfaceSynchronized() const {
diff --git a/chromium/components/exo/sub_surface_unittest.cc b/chromium/components/exo/sub_surface_unittest.cc
index 1132dec0b18..c5697538c37 100644
--- a/chromium/components/exo/sub_surface_unittest.cc
+++ b/chromium/components/exo/sub_surface_unittest.cc
@@ -5,6 +5,7 @@
#include "components/exo/sub_surface.h"
#include "base/memory/ptr_util.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_helper.h"
@@ -16,10 +17,10 @@ namespace {
using SubSurfaceTest = test::ExoTestBase;
TEST_F(SubSurfaceTest, SetPosition) {
- std::unique_ptr<Surface> parent(new Surface);
- std::unique_ptr<Surface> surface(new Surface);
- std::unique_ptr<SubSurface> sub_surface(
- new SubSurface(surface.get(), parent.get()));
+ auto parent = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(parent.get());
+ auto surface = base::MakeUnique<Surface>();
+ auto sub_surface = base::MakeUnique<SubSurface>(surface.get(), parent.get());
// Initial position is at the origin.
EXPECT_EQ(gfx::Point().ToString(),
@@ -49,14 +50,15 @@ TEST_F(SubSurfaceTest, SetPosition) {
}
TEST_F(SubSurfaceTest, PlaceAbove) {
- std::unique_ptr<Surface> parent(new Surface);
- std::unique_ptr<Surface> surface1(new Surface);
- std::unique_ptr<Surface> surface2(new Surface);
- std::unique_ptr<Surface> non_sibling_surface(new Surface);
- std::unique_ptr<SubSurface> sub_surface1(
- new SubSurface(surface1.get(), parent.get()));
- std::unique_ptr<SubSurface> sub_surface2(
- new SubSurface(surface2.get(), parent.get()));
+ auto parent = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(parent.get());
+ auto surface1 = base::MakeUnique<Surface>();
+ auto surface2 = base::MakeUnique<Surface>();
+ auto non_sibling_surface = base::MakeUnique<Surface>();
+ auto sub_surface1 =
+ base::MakeUnique<SubSurface>(surface1.get(), parent.get());
+ auto sub_surface2 =
+ base::MakeUnique<SubSurface>(surface2.get(), parent.get());
ASSERT_EQ(2u, parent->window()->children().size());
EXPECT_EQ(surface1->window(), parent->window()->children()[0]);
@@ -80,14 +82,15 @@ TEST_F(SubSurfaceTest, PlaceAbove) {
}
TEST_F(SubSurfaceTest, PlaceBelow) {
- std::unique_ptr<Surface> parent(new Surface);
- std::unique_ptr<Surface> surface1(new Surface);
- std::unique_ptr<Surface> surface2(new Surface);
- std::unique_ptr<Surface> non_sibling_surface(new Surface);
- std::unique_ptr<SubSurface> sub_surface1(
- new SubSurface(surface1.get(), parent.get()));
- std::unique_ptr<SubSurface> sub_surface2(
- new SubSurface(surface2.get(), parent.get()));
+ auto parent = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(parent.get());
+ auto surface1 = base::MakeUnique<Surface>();
+ auto surface2 = base::MakeUnique<Surface>();
+ auto non_sibling_surface = base::MakeUnique<Surface>();
+ auto sub_surface1 =
+ base::MakeUnique<SubSurface>(surface1.get(), parent.get());
+ auto sub_surface2 =
+ base::MakeUnique<SubSurface>(surface2.get(), parent.get());
ASSERT_EQ(2u, parent->window()->children().size());
EXPECT_EQ(surface1->window(), parent->window()->children()[0]);
@@ -111,13 +114,14 @@ TEST_F(SubSurfaceTest, PlaceBelow) {
}
TEST_F(SubSurfaceTest, SetCommitBehavior) {
- std::unique_ptr<Surface> parent(new Surface);
- std::unique_ptr<Surface> child(new Surface);
- std::unique_ptr<Surface> grandchild(new Surface);
- std::unique_ptr<SubSurface> child_sub_surface(
- new SubSurface(child.get(), parent.get()));
- std::unique_ptr<SubSurface> grandchild_sub_surface(
- new SubSurface(grandchild.get(), child.get()));
+ auto parent = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(parent.get());
+ auto child = base::MakeUnique<Surface>();
+ auto grandchild = base::MakeUnique<Surface>();
+ auto child_sub_surface =
+ base::MakeUnique<SubSurface>(child.get(), parent.get());
+ auto grandchild_sub_surface =
+ base::MakeUnique<SubSurface>(grandchild.get(), child.get());
// Initial position is at the origin.
EXPECT_EQ(gfx::Point().ToString(),
@@ -141,19 +145,20 @@ TEST_F(SubSurfaceTest, SetCommitBehavior) {
EXPECT_EQ(position1.ToString(),
grandchild->window()->bounds().origin().ToString());
+ // TODO(penghuang): http://crbug.com/740110 Support async mode.
// Disable synchronous commit behavior.
- bool synchronized = false;
- child_sub_surface->SetCommitBehavior(synchronized);
+ // bool synchronized = false;
+ // child_sub_surface->SetCommitBehavior(synchronized);
// Set position to 20, 20.
- gfx::Point position2(20, 20);
- grandchild_sub_surface->SetPosition(position2);
- child->Commit();
+ // gfx::Point position2(20, 20);
+ // grandchild_sub_surface->SetPosition(position2);
+ // child->Commit();
// A Commit() call on child should be sufficient for the position of
// grandchild to take effect when synchronous is disabled.
- EXPECT_EQ(position2.ToString(),
- grandchild->window()->bounds().origin().ToString());
+ // EXPECT_EQ(position2.ToString(),
+ // grandchild->window()->bounds().origin().ToString());
}
} // namespace
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index 7cca49f6a19..b12081847d4 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/callback_helpers.h"
+#include "base/containers/adapters.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -14,20 +15,19 @@
#include "base/trace_event/trace_event_argument.h"
#include "cc/output/layer_tree_frame_sink.h"
#include "cc/quads/render_pass.h"
-#include "cc/quads/shared_quad_state.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/resources/single_release_callback.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.h"
#include "components/exo/buffer.h"
#include "components/exo/pointer.h"
#include "components/exo/surface_delegate.h"
#include "components/exo/surface_observer.h"
+#include "components/viz/common/quads/shared_quad_state.h"
+#include "components/viz/common/quads/single_release_callback.h"
#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/env.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_targeter.h"
@@ -37,6 +37,7 @@
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -90,6 +91,20 @@ bool FormatHasAlpha(gfx::BufferFormat format) {
}
}
+// Helper function that returns |size| after adjusting for |transform|.
+gfx::Size ToTransformedSize(const gfx::Size& size, Transform transform) {
+ switch (transform) {
+ case Transform::NORMAL:
+ case Transform::ROTATE_180:
+ return size;
+ case Transform::ROTATE_90:
+ case Transform::ROTATE_270:
+ return gfx::Size(size.height(), size.width());
+ }
+
+ NOTREACHED();
+}
+
class CustomWindowDelegate : public aura::WindowDelegate {
public:
explicit CustomWindowDelegate(Surface* surface) : surface_(surface) {}
@@ -114,9 +129,7 @@ class CustomWindowDelegate : public aura::WindowDelegate {
bool CanFocus() override { return true; }
void OnCaptureLost() override {}
void OnPaint(const ui::PaintContext& context) override {}
- void OnDeviceScaleFactorChanged(float device_scale_factor) override {
- surface_->SetDeviceScaleFactor(device_scale_factor);
- }
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
void OnWindowDestroying(aura::Window* window) override {}
void OnWindowDestroyed(aura::Window* window) override { delete this; }
void OnWindowTargetVisibilityChanged(bool visible) override {}
@@ -190,42 +203,23 @@ Surface::Surface() : window_(new aura::Window(new CustomWindowDelegate(this))) {
window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
window_->SetName("ExoSurface");
window_->SetProperty(kSurfaceKey, this);
- window_->Init(ui::LAYER_SOLID_COLOR);
+ window_->Init(ui::LAYER_NOT_DRAWN);
window_->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter));
window_->set_owned_by_parent(false);
- window_->AddObserver(this);
- aura::Env::GetInstance()->context_factory()->AddObserver(this);
- layer_tree_frame_sink_holder_ = base::MakeUnique<LayerTreeFrameSinkHolder>(
- this, window_->CreateLayerTreeFrameSink());
WMHelper::GetInstance()->SetDragDropDelegate(window_.get());
}
Surface::~Surface() {
- aura::Env::GetInstance()->context_factory()->RemoveObserver(this);
for (SurfaceObserver& observer : observers_)
observer.OnSurfaceDestroying(this);
- window_->RemoveObserver(this);
- if (window_->layer()->GetCompositor())
- window_->layer()->GetCompositor()->vsync_manager()->RemoveObserver(this);
- window_->layer()->SetShowSolidColorContent();
-
- frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
- active_frame_callbacks_.splice(active_frame_callbacks_.end(),
- frame_callbacks_);
// Call all frame callbacks with a null frame time to indicate that they
// have been cancelled.
- for (const auto& frame_callback : active_frame_callbacks_)
+ for (const auto& frame_callback : pending_frame_callbacks_)
frame_callback.Run(base::TimeTicks());
- presentation_callbacks_.splice(presentation_callbacks_.end(),
- pending_presentation_callbacks_);
- swapping_presentation_callbacks_.splice(
- swapping_presentation_callbacks_.end(), presentation_callbacks_);
- swapped_presentation_callbacks_.splice(swapped_presentation_callbacks_.end(),
- swapping_presentation_callbacks_);
// Call all presentation callbacks with a null presentation time to indicate
// that they have been cancelled.
- for (const auto& presentation_callback : swapped_presentation_callbacks_)
+ for (const auto& presentation_callback : pending_presentation_callbacks_)
presentation_callback.Run(base::TimeTicks(), base::TimeDelta());
WMHelper::GetInstance()->ResetDragDropDelegate(window_.get());
@@ -236,10 +230,6 @@ Surface* Surface::AsSurface(const aura::Window* window) {
return window->GetProperty(kSurfaceKey);
}
-viz::SurfaceId Surface::GetSurfaceId() const {
- return window_->GetSurfaceId();
-}
-
void Surface::Attach(Buffer* buffer) {
TRACE_EVENT1("exo", "Surface::Attach", "buffer",
buffer ? buffer->GetSize().ToString() : "null");
@@ -287,17 +277,26 @@ void Surface::SetBufferScale(float scale) {
pending_state_.buffer_scale = scale;
}
+void Surface::SetBufferTransform(Transform transform) {
+ TRACE_EVENT1("exo", "Surface::SetBufferTransform", "transform",
+ static_cast<int>(transform));
+
+ pending_state_.buffer_transform = transform;
+}
+
void Surface::AddSubSurface(Surface* sub_surface) {
TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface",
sub_surface->AsTracedValue());
DCHECK(!sub_surface->window()->parent());
DCHECK(!sub_surface->window()->IsVisible());
+ sub_surface->window()->SetBounds(
+ gfx::Rect(sub_surface->window()->bounds().size()));
window_->AddChild(sub_surface->window());
DCHECK(!ListContainsEntry(pending_sub_surfaces_, sub_surface));
pending_sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point()));
- has_pending_layer_changes_ = true;
+ sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point()));
}
void Surface::RemoveSubSurface(Surface* sub_surface) {
@@ -311,7 +310,16 @@ void Surface::RemoveSubSurface(Surface* sub_surface) {
DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
pending_sub_surfaces_.erase(
FindListEntry(pending_sub_surfaces_, sub_surface));
- has_pending_layer_changes_ = true;
+
+ DCHECK(ListContainsEntry(sub_surfaces_, sub_surface));
+ auto it = FindListEntry(sub_surfaces_, sub_surface);
+ pending_damage_.op(SkIRect::MakeXYWH(it->second.x(), it->second.y(),
+ sub_surface->content_size().width(),
+ sub_surface->content_size().height()),
+ SkRegion::kUnion_Op);
+ sub_surfaces_.erase(it);
+ // Force recreating resources when the surface is added to a tree again.
+ sub_surface->SurfaceHierarchyResourcesLost();
}
void Surface::SetSubSurfacePosition(Surface* sub_surface,
@@ -324,7 +332,7 @@ void Surface::SetSubSurfacePosition(Surface* sub_surface,
if (it->second == position)
return;
it->second = position;
- has_pending_layer_changes_ = true;
+ sub_surfaces_changed_ = true;
}
void Surface::PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference) {
@@ -356,7 +364,7 @@ void Surface::PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference) {
if (it == position_it)
return;
pending_sub_surfaces_.splice(position_it, pending_sub_surfaces_, it);
- has_pending_layer_changes_ = true;
+ sub_surfaces_changed_ = true;
}
void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
@@ -381,7 +389,7 @@ void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
if (it == sibling_it)
return;
pending_sub_surfaces_.splice(sibling_it, pending_sub_surfaces_, it);
- has_pending_layer_changes_ = true;
+ sub_surfaces_changed_ = true;
}
void Surface::SetViewport(const gfx::Size& viewport) {
@@ -416,128 +424,133 @@ void Surface::SetAlpha(float alpha) {
pending_state_.alpha = alpha;
}
-void Surface::SetDeviceScaleFactor(float device_scale_factor) {
- device_scale_factor_ = device_scale_factor;
-}
-
void Surface::Commit() {
TRACE_EVENT0("exo", "Surface::Commit");
- needs_commit_surface_hierarchy_ = true;
-
- if (state_ != pending_state_)
- has_pending_layer_changes_ = true;
-
- if (has_pending_contents_) {
- if (pending_buffer_.buffer()) {
- if (current_resource_.size != pending_buffer_.buffer()->GetSize())
- has_pending_layer_changes_ = true;
- // Whether layer fills bounds opaquely or not might have changed.
- if (current_resource_has_alpha_ !=
- FormatHasAlpha(pending_buffer_.buffer()->GetFormat()))
- has_pending_layer_changes_ = true;
- } else if (!current_resource_.size.IsEmpty()) {
- has_pending_layer_changes_ = true;
- }
- }
-
- if (delegate_) {
+ needs_commit_surface_ = true;
+ if (delegate_)
delegate_->OnSurfaceCommit();
- } else {
- CommitSurfaceHierarchy();
- }
-
- if (current_begin_frame_ack_.sequence_number !=
- cc::BeginFrameArgs::kInvalidFrameNumber) {
- if (!current_begin_frame_ack_.has_damage) {
- layer_tree_frame_sink_holder_->frame_sink()->DidNotProduceFrame(
- current_begin_frame_ack_);
- }
- current_begin_frame_ack_.sequence_number =
- cc::BeginFrameArgs::kInvalidFrameNumber;
- if (begin_frame_source_)
- begin_frame_source_->DidFinishFrame(this);
- }
}
-void Surface::CommitSurfaceHierarchy() {
- DCHECK(needs_commit_surface_hierarchy_);
- needs_commit_surface_hierarchy_ = false;
- has_pending_layer_changes_ = false;
-
- bool full_damage = false;
- if (pending_state_.opaque_region != state_.opaque_region ||
- pending_state_.buffer_scale != state_.buffer_scale ||
- 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) {
- full_damage = true;
- }
-
- state_ = pending_state_;
- pending_state_.only_visible_on_secure_output = false;
-
- // We update contents if Attach() has been called since last commit.
- if (has_pending_contents_) {
- has_pending_contents_ = false;
+gfx::Rect Surface::CommitSurfaceHierarchy(
+ std::list<FrameCallback>* frame_callbacks,
+ std::list<PresentationCallback>* presentation_callbacks) {
+ if (needs_commit_surface_) {
+ needs_commit_surface_ = false;
+
+ bool needs_full_damage =
+ 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;
+
+ bool needs_update_buffer_transform =
+ pending_state_.buffer_scale != state_.buffer_scale ||
+ pending_state_.buffer_transform != state_.buffer_transform;
+
+ state_ = pending_state_;
+ pending_state_.only_visible_on_secure_output = false;
+
+ // We update contents if Attach() has been called since last commit.
+ if (has_pending_contents_) {
+ has_pending_contents_ = false;
+ current_buffer_ = std::move(pending_buffer_);
+ needs_update_resource_ = true;
+ }
- current_buffer_ = std::move(pending_buffer_);
+ if (needs_update_buffer_transform)
+ UpdateBufferTransform();
+
+ // Move pending frame callbacks to the end of frame_callbacks.
+ frame_callbacks->splice(frame_callbacks->end(), pending_frame_callbacks_);
+
+ // Move pending presentation callbacks to the end of presentation_callbacks.
+ presentation_callbacks->splice(presentation_callbacks->end(),
+ pending_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.
+ if (sub_surfaces_changed_) {
+ sub_surfaces_.clear();
+ aura::Window* stacking_target = nullptr;
+ for (const auto& sub_surface_entry : pending_sub_surfaces_) {
+ Surface* sub_surface = sub_surface_entry.first;
+ sub_surfaces_.push_back(sub_surface_entry);
+ // Move sub-surface to its new position in the stack.
+ if (stacking_target)
+ window_->StackChildAbove(sub_surface->window(), stacking_target);
+
+ // Stack next sub-surface above this sub-surface.
+ stacking_target = sub_surface->window();
+
+ // Update sub-surface position relative to surface origin.
+ sub_surface->window()->SetBounds(gfx::Rect(
+ sub_surface_entry.second, sub_surface->window()->bounds().size()));
+ }
+ sub_surfaces_changed_ = false;
+ }
- UpdateResource(true);
+ SkIRect output_rect =
+ SkIRect::MakeWH(content_size_.width(), content_size_.height());
+ if (needs_full_damage) {
+ damage_.setRect(output_rect);
+ } else {
+ // pending_damage_ is in Surface coordinates.
+ damage_.set(pending_damage_);
+ damage_.intersects(output_rect);
+ }
+ pending_damage_.setEmpty();
}
- // Move pending frame callbacks to the end of frame_callbacks_.
- frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
-
- // Move pending presentation callbacks to the end of presentation_callbacks_.
- presentation_callbacks_.splice(presentation_callbacks_.end(),
- pending_presentation_callbacks_);
-
- UpdateSurface(full_damage);
-
- window_->layer()->SetFillsBoundsOpaquely(
- !current_resource_has_alpha_ || state_.blend_mode == SkBlendMode::kSrc ||
- state_.opaque_region.contains(
- gfx::RectToSkIRect(gfx::Rect(content_size_))));
-
- // Reset damage.
- pending_damage_.setEmpty();
- DCHECK(!current_resource_.id ||
- layer_tree_frame_sink_holder_->HasReleaseCallbackForResource(
- current_resource_.id));
+ gfx::Rect bounds(content_size_);
+
+ // The top most sub-surface is at the front of the RenderPass's quad_list,
+ // so we need composite sub-surface in reversed order.
+ for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
+ auto* sub_surface = sub_surface_entry.first;
+ gfx::Point origin = sub_surface_entry.second;
+ // Synchronously commit all pending state of the sub-surface and its
+ // descendants.
+ bounds.Union(sub_surface->CommitSurfaceHierarchy(frame_callbacks,
+ presentation_callbacks) +
+ origin.OffsetFromOrigin());
+ }
- // Synchronize window hierarchy. This will position and update the stacking
- // order of all sub-surfaces after committing all pending state of sub-surface
- // descendants.
- aura::Window* stacking_target = nullptr;
- for (auto& sub_surface_entry : pending_sub_surfaces_) {
- Surface* sub_surface = sub_surface_entry.first;
+ return bounds;
+}
+void Surface::AppendSurfaceHierarchyContentsToFrame(
+ const gfx::Point& origin,
+ float device_scale_factor,
+ LayerTreeFrameSinkHolder* frame_sink_holder,
+ cc::CompositorFrame* frame) {
+ // The top most sub-surface is at the front of the RenderPass's quad_list,
+ // so we need composite sub-surface in reversed order.
+ for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
+ auto* sub_surface = sub_surface_entry.first;
// Synchronsouly commit all pending state of the sub-surface and its
// decendents.
- if (sub_surface->needs_commit_surface_hierarchy())
- sub_surface->CommitSurfaceHierarchy();
-
- // Enable/disable sub-surface based on if it has contents.
- if (sub_surface->has_contents())
- sub_surface->window()->Show();
- else
- sub_surface->window()->Hide();
+ sub_surface->AppendSurfaceHierarchyContentsToFrame(
+ origin + sub_surface_entry.second.OffsetFromOrigin(),
+ device_scale_factor, frame_sink_holder, frame);
+ }
- // Move sub-surface to its new position in the stack.
- if (stacking_target)
- window_->StackChildAbove(sub_surface->window(), stacking_target);
+ if (needs_update_resource_)
+ UpdateResource(frame_sink_holder);
- // Stack next sub-surface above this sub-surface.
- stacking_target = sub_surface->window();
+ AppendContentsToFrame(origin, device_scale_factor, frame);
- // Update sub-surface position relative to surface origin.
- sub_surface->window()->SetBounds(
- gfx::Rect(sub_surface_entry.second, sub_surface->content_size_));
- }
+ DCHECK(
+ !current_resource_.id ||
+ frame_sink_holder->HasReleaseCallbackForResource(current_resource_.id));
}
bool Surface::IsSynchronized() const {
@@ -614,49 +627,6 @@ std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
return value;
}
-void Surface::DidReceiveCompositorFrameAck() {
- active_frame_callbacks_.splice(active_frame_callbacks_.end(),
- frame_callbacks_);
- swapping_presentation_callbacks_.splice(
- swapping_presentation_callbacks_.end(), presentation_callbacks_);
- UpdateNeedsBeginFrame();
-}
-
-void Surface::SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) {
- if (needs_begin_frame_) {
- DCHECK(begin_frame_source_);
- begin_frame_source_->RemoveObserver(this);
- needs_begin_frame_ = false;
- }
- begin_frame_source_ = begin_frame_source;
- UpdateNeedsBeginFrame();
-}
-
-void Surface::UpdateNeedsBeginFrame() {
- if (!begin_frame_source_)
- return;
-
- bool needs_begin_frame = !active_frame_callbacks_.empty();
- if (needs_begin_frame == needs_begin_frame_)
- return;
-
- needs_begin_frame_ = needs_begin_frame;
- if (needs_begin_frame_)
- begin_frame_source_->AddObserver(this);
- else
- begin_frame_source_->RemoveObserver(this);
-}
-
-bool Surface::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
- current_begin_frame_ack_ =
- cc::BeginFrameAck(args.source_id, args.sequence_number, false);
- while (!active_frame_callbacks_.empty()) {
- active_frame_callbacks_.front().Run(args.frame_time);
- active_frame_callbacks_.pop_front();
- }
- return true;
-}
-
bool Surface::IsStylusOnly() {
return window_->GetProperty(kStylusOnlyKey);
}
@@ -665,48 +635,20 @@ void Surface::SetStylusOnly() {
window_->SetProperty(kStylusOnlyKey, true);
}
-////////////////////////////////////////////////////////////////////////////////
-// ui::ContextFactoryObserver overrides:
-
-void Surface::OnLostResources() {
- if (!window_->GetSurfaceId().is_valid())
- return;
- UpdateResource(false);
- UpdateSurface(true);
+void Surface::SurfaceHierarchyResourcesLost() {
+ // Update resource and full damage are needed for next frame.
+ needs_update_resource_ = true;
+ damage_.setRect(
+ SkIRect::MakeWH(content_size_.width(), content_size_.height()));
+ for (const auto& sub_surface : sub_surfaces_)
+ sub_surface.first->SurfaceHierarchyResourcesLost();
}
-////////////////////////////////////////////////////////////////////////////////
-// aura::WindowObserver overrides:
-
-void Surface::OnWindowAddedToRootWindow(aura::Window* window) {
- window->layer()->GetCompositor()->vsync_manager()->AddObserver(this);
-}
-
-void Surface::OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) {
- window->layer()->GetCompositor()->vsync_manager()->RemoveObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ui::CompositorVSyncManager::Observer overrides:
-
-void Surface::OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) {
- // Use current time if platform doesn't provide an accurate timebase.
- if (timebase.is_null())
- timebase = base::TimeTicks::Now();
-
- while (!swapped_presentation_callbacks_.empty()) {
- swapped_presentation_callbacks_.front().Run(timebase, interval);
- swapped_presentation_callbacks_.pop_front();
- }
-
- // VSync parameters updates are generated at the start of a new swap. Move
- // the swapping presentation callbacks to swapped callbacks so they fire
- // at the next VSync parameters update as that will contain the presentation
- // time for the previous frame.
- swapped_presentation_callbacks_.splice(swapped_presentation_callbacks_.end(),
- swapping_presentation_callbacks_);
+bool Surface::FillsBoundsOpaquely() const {
+ return !current_resource_has_alpha_ ||
+ state_.blend_mode == SkBlendMode::kSrc ||
+ state_.opaque_region.contains(
+ gfx::RectToSkIRect(gfx::Rect(content_size_)));
}
////////////////////////////////////////////////////////////////////////////////
@@ -717,11 +659,13 @@ Surface::State::State() : input_region(SkIRect::MakeLargest()) {}
Surface::State::~State() = default;
bool Surface::State::operator==(const State& other) {
- return (other.crop == crop && alpha == other.alpha &&
- other.blend_mode == blend_mode && other.viewport == viewport &&
- other.opaque_region == opaque_region &&
- other.buffer_scale == buffer_scale &&
- other.input_region == input_region);
+ return other.opaque_region == opaque_region &&
+ other.input_region == input_region &&
+ other.buffer_scale == buffer_scale &&
+ other.buffer_transform == buffer_transform &&
+ other.viewport == viewport && other.crop == crop &&
+ other.only_visible_on_secure_output == only_visible_on_secure_output &&
+ other.blend_mode == blend_mode && other.alpha == alpha;
}
Surface::BufferAttachment::BufferAttachment() {}
@@ -756,15 +700,22 @@ void Surface::BufferAttachment::Reset(base::WeakPtr<Buffer> buffer) {
buffer_ = buffer;
}
-void Surface::UpdateResource(bool client_usage) {
- if (current_buffer_.buffer() &&
- current_buffer_.buffer()->ProduceTransferableResource(
- layer_tree_frame_sink_holder_.get(),
- layer_tree_frame_sink_holder_->AllocateResourceId(),
- state_.only_visible_on_secure_output, client_usage,
- &current_resource_)) {
- current_resource_has_alpha_ =
- FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+void Surface::UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder) {
+ DCHECK(needs_update_resource_);
+ needs_update_resource_ = false;
+ if (current_buffer_.buffer()) {
+ if (current_buffer_.buffer()->ProduceTransferableResource(
+ frame_sink_holder, state_.only_visible_on_secure_output,
+ &current_resource_)) {
+ current_resource_has_alpha_ =
+ FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+ } 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_.buffer()->GetSize();
+ current_resource_has_alpha_ = false;
+ }
} else {
current_resource_.id = 0;
current_resource_.size = gfx::Size();
@@ -772,111 +723,139 @@ void Surface::UpdateResource(bool client_usage) {
}
}
-void Surface::UpdateSurface(bool full_damage) {
- gfx::Size buffer_size = current_resource_.size;
- gfx::SizeF scaled_buffer_size(
- gfx::ScaleSize(gfx::SizeF(buffer_size), 1.0f / state_.buffer_scale));
-
- gfx::Size layer_size; // Size of the output layer, in DIP.
- if (!state_.viewport.IsEmpty()) {
- layer_size = state_.viewport;
- } else if (!state_.crop.IsEmpty()) {
- DLOG_IF(WARNING, !gfx::IsExpressibleAsInt(state_.crop.width()) ||
- !gfx::IsExpressibleAsInt(state_.crop.height()))
- << "Crop rectangle size (" << state_.crop.size().ToString()
- << ") most be expressible using integers when viewport is not set";
- layer_size = gfx::ToCeiledSize(state_.crop.size());
- } else {
- layer_size = gfx::ToCeiledSize(scaled_buffer_size);
+void Surface::UpdateBufferTransform() {
+ SkMatrix buffer_matrix;
+ switch (state_.buffer_transform) {
+ case Transform::NORMAL:
+ buffer_matrix.setIdentity();
+ break;
+ case Transform::ROTATE_90:
+ buffer_matrix.setSinCos(-1, 0, 0.5f, 0.5f);
+ break;
+ case Transform::ROTATE_180:
+ buffer_matrix.setSinCos(0, -1, 0.5f, 0.5f);
+ break;
+ case Transform::ROTATE_270:
+ buffer_matrix.setSinCos(1, 0, 0.5f, 0.5f);
+ break;
}
-
- content_size_ = layer_size;
- // We need update window_'s bounds with content size, because the
- // LayerTreeFrameSink may not update the window's size base the size of
- // the lastest submitted CompositorFrame.
- window_->SetBounds(gfx::Rect(window_->bounds().origin(), content_size_));
- // TODO(jbauman): Figure out how this interacts with the pixel size of
- // CopyOutputRequests on the layer.
- gfx::Size contents_surface_size = layer_size;
-
- gfx::PointF uv_top_left(0.f, 0.f);
- gfx::PointF uv_bottom_right(1.f, 1.f);
- if (!state_.crop.IsEmpty()) {
- uv_top_left = state_.crop.origin();
-
- uv_top_left.Scale(1.f / scaled_buffer_size.width(),
- 1.f / scaled_buffer_size.height());
- uv_bottom_right = state_.crop.bottom_right();
- uv_bottom_right.Scale(1.f / scaled_buffer_size.width(),
- 1.f / scaled_buffer_size.height());
- }
-
- gfx::Rect damage_rect;
- gfx::Rect output_rect = gfx::Rect(contents_surface_size);
- if (full_damage) {
- damage_rect = output_rect;
- } else {
- // pending_damage_ is in Surface coordinates.
- damage_rect = gfx::SkIRectToRect(pending_damage_.getBounds());
- damage_rect.Intersect(output_rect);
- }
-
- const int kRenderPassId = 1;
- std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
- render_pass->SetNew(kRenderPassId, output_rect, damage_rect,
- gfx::Transform());
-
- gfx::Rect quad_rect = output_rect;
- cc::SharedQuadState* quad_state =
+ buffer_matrix.postIDiv(state_.buffer_scale, state_.buffer_scale);
+ buffer_transform_ = gfx::Transform(buffer_matrix);
+}
+
+void Surface::AppendContentsToFrame(const gfx::Point& origin,
+ float device_scale_factor,
+ cc::CompositorFrame* frame) {
+ const std::unique_ptr<cc::RenderPass>& render_pass =
+ frame->render_pass_list.back();
+ gfx::Rect output_rect(origin, content_size_);
+ gfx::Rect quad_rect(0, 0, 1, 1);
+
+ // 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 = gfx::SkIRectToRect(damage_.getBounds());
+ damage_rect.set_origin(origin);
+ render_pass->damage_rect.Union(
+ gfx::ConvertRectToPixel(device_scale_factor, damage_rect));
+ render_pass->output_rect.Union(
+ gfx::ConvertRectToPixel(device_scale_factor, output_rect));
+
+ // Compute the total transformation from post-transform buffer coordinates to
+ // target coordinates.
+ SkMatrix viewport_to_target_matrix;
+ // Scale and offset the normalized space to fit the content size rectangle.
+ viewport_to_target_matrix.setScale(
+ content_size_.width() * state_.buffer_scale,
+ content_size_.height() * state_.buffer_scale);
+ viewport_to_target_matrix.postTranslate(origin.x(), origin.y());
+ // Convert from DPs to pixels.
+ viewport_to_target_matrix.postScale(device_scale_factor, device_scale_factor);
+
+ gfx::Transform quad_to_target_transform(buffer_transform_);
+ quad_to_target_transform.ConcatTransform(
+ gfx::Transform(viewport_to_target_matrix));
+
+ viz::SharedQuadState* quad_state =
render_pass->CreateAndAppendSharedQuadState();
- quad_state->quad_layer_rect = gfx::Rect(contents_surface_size);
- quad_state->visible_quad_layer_rect = quad_rect;
- quad_state->opacity = state_.alpha;
-
- cc::CompositorFrame frame;
- // If we commit while we don't have an active BeginFrame, we acknowledge a
- // manual one.
- if (current_begin_frame_ack_.sequence_number ==
- cc::BeginFrameArgs::kInvalidFrameNumber) {
- current_begin_frame_ack_ = cc::BeginFrameAck::CreateManualAckWithDamage();
- } else {
- current_begin_frame_ack_.has_damage = true;
- }
- frame.metadata.begin_frame_ack = current_begin_frame_ack_;
- frame.metadata.device_scale_factor = device_scale_factor_;
+ quad_state->SetAll(
+ quad_to_target_transform, quad_rect /* quad_layer_rect */,
+ quad_rect /* visible_quad_layer_rect */, gfx::Rect() /* clip_rect */,
+ false /* is_clipped */, state_.alpha /* opacity */,
+ SkBlendMode::kSrcOver /* blend_mode */, 0 /* sorting_context_id */);
if (current_resource_.id) {
+ gfx::RectF uv_crop(gfx::SizeF(1, 1));
+ if (!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));
+ if (!transformed_buffer_size.IsEmpty())
+ uv_crop.Scale(1.f / transformed_buffer_size.width(),
+ 1.f / transformed_buffer_size.height());
+
+ buffer_transform_.TransformRectReverse(&uv_crop);
+ }
+
// Texture quad is only needed if buffer is not fully transparent.
if (state_.alpha) {
cc::TextureDrawQuad* texture_quad =
render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0};
- gfx::Rect opaque_rect;
- if (!current_resource_has_alpha_ ||
- state_.blend_mode == SkBlendMode::kSrc ||
- state_.opaque_region.contains(gfx::RectToSkIRect(quad_rect))) {
- opaque_rect = quad_rect;
- } else if (state_.opaque_region.isRect()) {
- opaque_rect = gfx::SkIRectToRect(state_.opaque_region.getBounds());
- }
-
- texture_quad->SetNew(quad_state, quad_rect, opaque_rect, quad_rect,
- current_resource_.id, true, uv_top_left,
- uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity,
- false, false, state_.only_visible_on_secure_output);
+ bool needs_blending =
+ current_resource_has_alpha_ &&
+ state_.blend_mode != SkBlendMode::kSrc &&
+ !state_.opaque_region.contains(gfx::RectToSkIRect(output_rect));
+
+ texture_quad->SetNew(
+ quad_state, quad_rect, quad_rect, needs_blending,
+ current_resource_.id, true /* premultiplied_alpha */,
+ uv_crop.origin(), uv_crop.bottom_right(),
+ SK_ColorTRANSPARENT /* background_color */, vertex_opacity,
+ false /* y_flipped */, false /* nearest_neighbor */,
+ state_.only_visible_on_secure_output);
if (current_resource_.is_overlay_candidate)
texture_quad->set_resource_size_in_pixels(current_resource_.size);
- frame.resource_list.push_back(current_resource_);
+ frame->resource_list.push_back(current_resource_);
}
} else {
cc::SolidColorDrawQuad* solid_quad =
render_pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
- solid_quad->SetNew(quad_state, quad_rect, quad_rect, SK_ColorBLACK, false);
+ solid_quad->SetNew(quad_state, quad_rect, quad_rect, SK_ColorBLACK,
+ false /* force_anti_aliasing_off */);
}
+}
- frame.render_pass_list.push_back(std::move(render_pass));
- layer_tree_frame_sink_holder_->frame_sink()->SubmitCompositorFrame(
- std::move(frame));
+void Surface::UpdateContentSize() {
+ gfx::Size content_size;
+ if (!state_.viewport.IsEmpty()) {
+ content_size = state_.viewport;
+ } else if (!state_.crop.IsEmpty()) {
+ DLOG_IF(WARNING, !gfx::IsExpressibleAsInt(state_.crop.width()) ||
+ !gfx::IsExpressibleAsInt(state_.crop.height()))
+ << "Crop rectangle size (" << state_.crop.size().ToString()
+ << ") most be expressible using integers when viewport is not set";
+ content_size = gfx::ToCeiledSize(state_.crop.size());
+ } else {
+ auto size = current_buffer_.buffer() ? current_buffer_.buffer()->GetSize()
+ : gfx::Size();
+ content_size = gfx::ToCeiledSize(gfx::ScaleSize(
+ gfx::SizeF(ToTransformedSize(size, state_.buffer_transform)),
+ 1.0f / state_.buffer_scale));
+ }
+
+ // Enable/disable sub-surface based on if it has contents.
+ if (has_contents())
+ window_->Show();
+ else
+ window_->Hide();
+
+ if (content_size_ != content_size) {
+ content_size_ = content_size;
+ window_->SetBounds(gfx::Rect(window_->bounds().origin(), content_size_));
+ }
}
} // namespace exo
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index ae168733029..b860a040e18 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -14,16 +14,15 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
-#include "cc/resources/transferable_resource.h"
-#include "cc/scheduler/begin_frame_source.h"
#include "components/exo/layer_tree_frame_sink_holder.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/transform.h"
namespace base {
namespace trace_event {
@@ -31,12 +30,17 @@ class TracedValue;
}
}
+namespace cc {
+class CompositorFrame;
+}
+
namespace gfx {
class Path;
}
namespace exo {
class Buffer;
+class LayerTreeFrameSinkHolder;
class Pointer;
class SurfaceDelegate;
class SurfaceObserver;
@@ -46,34 +50,27 @@ namespace subtle {
class PropertyHelper;
}
+// Counter-clockwise rotations.
+enum class Transform { NORMAL, ROTATE_90, ROTATE_180, ROTATE_270 };
+
// The pointer class is currently the only cursor provider class but this can
// change in the future when better hardware cursor support is added.
using CursorProvider = Pointer;
// This class represents a rectangular area that is displayed on the screen.
// It has a location, size and pixel contents.
-class Surface : public ui::ContextFactoryObserver,
- public aura::WindowObserver,
- public ui::PropertyHandler,
- public ui::CompositorVSyncManager::Observer,
- public cc::BeginFrameObserverBase {
+class Surface : public ui::PropertyHandler {
public:
using PropertyDeallocator = void (*)(int64_t value);
Surface();
- ~Surface() override;
+ ~Surface();
// Type-checking downcast routine.
static Surface* AsSurface(const aura::Window* window);
aura::Window* window() { return window_.get(); }
- viz::SurfaceId GetSurfaceId() const;
-
- LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder() {
- return layer_tree_frame_sink_holder_.get();
- }
-
// Set a buffer as the content of this surface. A buffer can only be attached
// to one surface at a time.
void Attach(Buffer* buffer);
@@ -108,6 +105,10 @@ class Surface : public ui::ContextFactoryObserver,
// dimension) than the desired surface size.
void SetBufferScale(float scale);
+ // This sets the transformation used to interpret the contents of the buffer
+ // attached to the surface.
+ void SetBufferTransform(Transform transform);
+
// Functions that control sub-surface state. All sub-surface state is
// double-buffered and will be applied when Commit() is called.
void AddSubSurface(Surface* sub_surface);
@@ -132,9 +133,6 @@ class Surface : public ui::ContextFactoryObserver,
// This sets the alpha value that will be applied to the whole surface.
void SetAlpha(float alpha);
- // This sets the device scale factor sent in CompositorFrames.
- void SetDeviceScaleFactor(float device_scale_factor);
-
// Surface state (damage regions, attached buffers, etc.) is double-buffered.
// A Commit() call atomically applies all pending state, replacing the
// current state. Commit() is not guaranteed to be synchronous. See
@@ -143,8 +141,17 @@ class Surface : public ui::ContextFactoryObserver,
// This will synchronously commit all pending state of the surface and its
// descendants by recursively calling CommitSurfaceHierarchy() for each
- // sub-surface with pending state.
- void CommitSurfaceHierarchy();
+ // sub-surface with pending state. Returns the bounding box of the surface
+ // and its descendants, in the local coordinate space of the surface.
+ gfx::Rect CommitSurfaceHierarchy(
+ std::list<FrameCallback>* frame_callbacks,
+ std::list<PresentationCallback>* presentation_callbacks);
+
+ void AppendSurfaceHierarchyContentsToFrame(
+ const gfx::Point& origin,
+ float device_scale_factor,
+ LayerTreeFrameSinkHolder* frame_sink_holder,
+ cc::CompositorFrame* frame);
// Returns true if surface is in synchronized mode.
bool IsSynchronized() const;
@@ -186,12 +193,8 @@ class Surface : public ui::ContextFactoryObserver,
// Returns a trace value representing the state of the surface.
std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
- // Call this to indicate that the previous CompositorFrame is processed and
- // the surface is being scheduled for a draw.
- void DidReceiveCompositorFrameAck();
-
// Called when the begin frame source has changed.
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source);
+ void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source);
// Returns the active contents size.
const gfx::Size& content_size() const { return content_size_; }
@@ -202,26 +205,16 @@ class Surface : public ui::ContextFactoryObserver,
// Enables 'stylus-only' mode for the associated window.
void SetStylusOnly();
- // Overridden from ui::ContextFactoryObserver:
- void OnLostResources() override;
+ // Notify surface that resources and subsurfaces' resources have been lost.
+ void SurfaceHierarchyResourcesLost();
- // Overridden from aura::WindowObserver:
- void OnWindowAddedToRootWindow(aura::Window* window) override;
- void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) override;
-
- // Overridden from ui::CompositorVSyncManager::Observer:
- void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) override;
+ // Returns true if the surface's bounds should be filled opaquely.
+ bool FillsBoundsOpaquely() const;
bool HasPendingDamageForTesting(const gfx::Rect& damage) const {
return pending_damage_.contains(gfx::RectToSkIRect(damage));
}
- // Overridden from cc::BeginFrameObserverBase:
- bool OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) override;
- void OnBeginFrameSourcePausedChanged(bool paused) override {}
-
private:
struct State {
State();
@@ -233,6 +226,7 @@ class Surface : public ui::ContextFactoryObserver,
SkRegion opaque_region;
SkRegion input_region;
float buffer_scale = 1.0f;
+ Transform buffer_transform = Transform::NORMAL;
gfx::Size viewport;
gfx::RectF crop;
bool only_visible_on_secure_output = false;
@@ -258,25 +252,23 @@ class Surface : public ui::ContextFactoryObserver,
friend class subtle::PropertyHelper;
- bool needs_commit_surface_hierarchy() const {
- return needs_commit_surface_hierarchy_;
- }
-
- // Set SurfaceLayer contents to the current buffer.
- void SetSurfaceLayerContents(ui::Layer* layer);
-
// Updates current_resource_ with a new resource id corresponding to the
// contents of the attached buffer (or id 0, if no buffer is attached).
// UpdateSurface must be called afterwards to ensure the release callback
// will be called.
- void UpdateResource(bool client_usage);
+ void UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder);
- // Updates the current Surface with a new frame referring to the resource in
- // current_resource_.
- void UpdateSurface(bool full_damage);
+ // Updates buffer_transform_ to match the current buffer parameters.
+ void UpdateBufferTransform();
- // Adds/Removes begin frame observer based on state.
- void UpdateNeedsBeginFrame();
+ // Puts the current surface into a draw quad, and appends the draw quads into
+ // the |frame|.
+ void AppendContentsToFrame(const gfx::Point& origin,
+ float device_scale_factor,
+ cc::CompositorFrame* frame);
+
+ // Update surface content size base on current buffer size.
+ void UpdateContentSize();
// This returns true when the surface has some contents assigned to it.
bool has_contents() const { return !!current_buffer_.buffer(); }
@@ -284,10 +276,8 @@ class Surface : public ui::ContextFactoryObserver,
// This window has the layer which contains the Surface contents.
std::unique_ptr<aura::Window> window_;
- // This is true if it's possible that the layer properties (size, opacity,
- // etc.) may have been modified since the last commit. Attaching a new
- // buffer with the same size as the old shouldn't set this to true.
- bool has_pending_layer_changes_ = true;
+ // This true, if sub_surfaces_ has changes (order, position, etc).
+ bool sub_surfaces_changed_ = false;
// This is the size of the last committed contents.
gfx::Size content_size_;
@@ -299,22 +289,19 @@ class Surface : public ui::ContextFactoryObserver,
// The buffer that will become the content of surface when Commit() is called.
BufferAttachment pending_buffer_;
- // The device scale factor sent in CompositorFrames.
- float device_scale_factor_ = 1.0f;
-
- std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_;
-
// The damage region to schedule paint for when Commit() is called.
SkRegion pending_damage_;
+ // The damage region which will be used by
+ // AppendSurfaceHierarchyContentsToFrame() to generate frame.
+ SkRegion 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_;
- std::list<FrameCallback> active_frame_callbacks_;
// These lists contains the callbacks to notify the client when surface
// contents have been presented. These callbacks move to
@@ -324,9 +311,6 @@ class Surface : public ui::ContextFactoryObserver,
// 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_;
- std::list<PresentationCallback> swapping_presentation_callbacks_;
- std::list<PresentationCallback> swapped_presentation_callbacks_;
// This is the state that has yet to be committed.
State pending_state_;
@@ -340,19 +324,27 @@ class Surface : public ui::ContextFactoryObserver,
using SubSurfaceEntry = std::pair<Surface*, gfx::Point>;
using SubSurfaceEntryList = std::list<SubSurfaceEntry>;
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.
- cc::TransferableResource current_resource_;
+ viz::TransferableResource current_resource_;
// Whether the last resource that was sent to a surface has an alpha channel.
bool current_resource_has_alpha_ = false;
// This is true if a call to Commit() as been made but
// CommitSurfaceHierarchy() has not yet been called.
- bool needs_commit_surface_hierarchy_ = false;
+ bool needs_commit_surface_ = false;
+
+ // This is true if UpdateResources() should be called.
+ bool needs_update_resource_ = true;
+
+ // The current buffer transform matrix. It specifies the transformation from
+ // normalized buffer coordinates to post-tranform buffer coordinates.
+ gfx::Transform buffer_transform_;
// This is set when the compositing starts and passed to active frame
// callbacks when compositing successfully ends.
@@ -369,11 +361,6 @@ class Surface : public ui::ContextFactoryObserver,
// Surface observer list. Surface does not own the observers.
base::ObserverList<SurfaceObserver, true> observers_;
- // The begin frame source being observed.
- cc::BeginFrameSource* begin_frame_source_ = nullptr;
- bool needs_begin_frame_ = false;
- cc::BeginFrameAck current_begin_frame_ack_;
-
DISALLOW_COPY_AND_ASSIGN(Surface);
};
diff --git a/chromium/components/exo/surface_tree_host.cc b/chromium/components/exo/surface_tree_host.cc
index 36442f58f32..812691632b4 100644
--- a/chromium/components/exo/surface_tree_host.cc
+++ b/chromium/components/exo/surface_tree_host.cc
@@ -8,13 +8,20 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/layer_tree_frame_sink.h"
+#include "components/exo/layer_tree_frame_sink_holder.h"
#include "components/exo/surface.h"
+#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_targeter.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/path.h"
namespace exo {
@@ -69,19 +76,32 @@ class CustomWindowTargeter : public aura::WindowTargeter {
// SurfaceTreeHost, public:
SurfaceTreeHost::SurfaceTreeHost(const std::string& window_name,
- aura::WindowDelegate* window_delegate) {
- host_window_ = base::MakeUnique<aura::Window>(window_delegate);
+ aura::WindowDelegate* window_delegate)
+ : host_window_(new aura::Window(window_delegate)),
+ surface_host_(new aura::Window(nullptr)) {
host_window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
host_window_->SetName(window_name);
host_window_->Init(ui::LAYER_NOT_DRAWN);
host_window_->set_owned_by_parent(false);
host_window_->SetEventTargeter(base::MakeUnique<CustomWindowTargeter>(this));
+
+ surface_host_->SetName("ExoSurfaceHost");
+ surface_host_->Init(ui::LAYER_SOLID_COLOR);
+ layer_tree_frame_sink_holder_ = base::MakeUnique<LayerTreeFrameSinkHolder>(
+ this, surface_host_->CreateLayerTreeFrameSink());
+
+ host_window_->AddChild(surface_host_);
+ surface_host_->Show();
+
+ aura::Env::GetInstance()->context_factory()->AddObserver(this);
}
SurfaceTreeHost::~SurfaceTreeHost() {
- if (root_surface_) {
- root_surface_->window()->Hide();
- root_surface_->SetSurfaceDelegate(nullptr);
+ aura::Env::GetInstance()->context_factory()->RemoveObserver(this);
+ SetRootSurface(nullptr);
+ if (host_window_->layer()->GetCompositor()) {
+ host_window_->layer()->GetCompositor()->vsync_manager()->RemoveObserver(
+ this);
}
}
@@ -95,15 +115,37 @@ void SurfaceTreeHost::SetRootSurface(Surface* root_surface) {
host_window_->SetBounds(
gfx::Rect(host_window_->bounds().origin(), gfx::Size()));
root_surface_->SetSurfaceDelegate(nullptr);
+ // Force recreating resources when the surface is added to a tree again.
+ root_surface_->SurfaceHierarchyResourcesLost();
root_surface_ = nullptr;
+
+ active_frame_callbacks_.splice(active_frame_callbacks_.end(),
+ frame_callbacks_);
+ // Call all frame callbacks with a null frame time to indicate that they
+ // have been cancelled.
+ while (!active_frame_callbacks_.empty()) {
+ active_frame_callbacks_.front().Run(base::TimeTicks());
+ active_frame_callbacks_.pop_front();
+ }
+
+ swapping_presentation_callbacks_.splice(
+ swapping_presentation_callbacks_.end(), presentation_callbacks_);
+ swapped_presentation_callbacks_.splice(
+ swapped_presentation_callbacks_.end(),
+ swapping_presentation_callbacks_);
+ // Call all presentation callbacks with a null presentation time to indicate
+ // that they have been cancelled.
+ while (!swapped_presentation_callbacks_.empty()) {
+ swapped_presentation_callbacks_.front().Run(base::TimeTicks(),
+ base::TimeDelta());
+ swapped_presentation_callbacks_.pop_front();
+ }
}
if (root_surface) {
root_surface_ = root_surface;
root_surface_->SetSurfaceDelegate(this);
host_window_->AddChild(root_surface_->window());
- host_window_->SetBounds(gfx::Rect(host_window_->bounds().origin(),
- root_surface_->content_size()));
root_surface_->window()->Show();
}
}
@@ -125,14 +167,55 @@ gfx::NativeCursor SurfaceTreeHost::GetCursor(const gfx::Point& point) const {
return root_surface_ ? root_surface_->GetCursor() : ui::CursorType::kNull;
}
+void SurfaceTreeHost::DidReceiveCompositorFrameAck() {
+ active_frame_callbacks_.splice(active_frame_callbacks_.end(),
+ frame_callbacks_);
+ swapping_presentation_callbacks_.splice(
+ swapping_presentation_callbacks_.end(), presentation_callbacks_);
+ UpdateNeedsBeginFrame();
+}
+
+void SurfaceTreeHost::SetBeginFrameSource(
+ viz::BeginFrameSource* begin_frame_source) {
+ if (needs_begin_frame_) {
+ DCHECK(begin_frame_source_);
+ begin_frame_source_->RemoveObserver(this);
+ needs_begin_frame_ = false;
+ }
+ begin_frame_source_ = begin_frame_source;
+ UpdateNeedsBeginFrame();
+}
+
+void SurfaceTreeHost::UpdateNeedsBeginFrame() {
+ if (!begin_frame_source_)
+ return;
+ bool needs_begin_frame = !active_frame_callbacks_.empty();
+ if (needs_begin_frame == needs_begin_frame_)
+ return;
+ needs_begin_frame_ = needs_begin_frame;
+ if (needs_begin_frame_)
+ begin_frame_source_->AddObserver(this);
+ else
+ begin_frame_source_->RemoveObserver(this);
+}
+
////////////////////////////////////////////////////////////////////////////////
// SurfaceDelegate overrides:
void SurfaceTreeHost::OnSurfaceCommit() {
- DCHECK(root_surface_);
- root_surface_->CommitSurfaceHierarchy();
- host_window_->SetBounds(gfx::Rect(host_window_->bounds().origin(),
- root_surface_->content_size()));
+ gfx::Rect bounds = root_surface_->CommitSurfaceHierarchy(
+ &frame_callbacks_, &presentation_callbacks_);
+
+ gfx::Point origin = bounds.origin();
+ origin.SetToMin(gfx::Point());
+
+ surface_host_->SetBounds(gfx::Rect(origin, bounds.size()));
+ surface_host_->layer()->SetFillsBoundsOpaquely(
+ bounds.size() == root_surface_->content_size() &&
+ root_surface_->FillsBoundsOpaquely());
+
+ host_window_->SetBounds(
+ gfx::Rect(host_window_->bounds().origin(), bounds.size()));
}
bool SurfaceTreeHost::IsSurfaceSynchronized() const {
@@ -141,4 +224,121 @@ bool SurfaceTreeHost::IsSurfaceSynchronized() const {
return false;
}
+////////////////////////////////////////////////////////////////////////////////
+// aura::WindowObserver overrides:
+
+void SurfaceTreeHost::OnWindowAddedToRootWindow(aura::Window* window) {
+ DCHECK_EQ(window, host_window());
+ window->layer()->GetCompositor()->vsync_manager()->AddObserver(this);
+}
+
+void SurfaceTreeHost::OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) {
+ DCHECK_EQ(window, host_window());
+ window->layer()->GetCompositor()->vsync_manager()->RemoveObserver(this);
+}
+
+void SurfaceTreeHost::OnWindowDestroying(aura::Window* window) {
+ DCHECK_EQ(window, host_window());
+ window->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::BeginFrameObserverBase overrides:
+
+bool SurfaceTreeHost::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) {
+ current_begin_frame_ack_ =
+ viz::BeginFrameAck(args.source_id, args.sequence_number, false);
+ while (!active_frame_callbacks_.empty()) {
+ active_frame_callbacks_.front().Run(args.frame_time);
+ active_frame_callbacks_.pop_front();
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ui::CompositorVSyncManager::Observer overrides:
+
+void SurfaceTreeHost::OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ // Use current time if platform doesn't provide an accurate timebase.
+ if (timebase.is_null())
+ timebase = base::TimeTicks::Now();
+ while (!swapped_presentation_callbacks_.empty()) {
+ swapped_presentation_callbacks_.front().Run(timebase, interval);
+ swapped_presentation_callbacks_.pop_front();
+ }
+ // VSync parameters updates are generated at the start of a new swap. Move
+ // the swapping presentation callbacks to swapped callbacks so they fire
+ // at the next VSync parameters update as that will contain the presentation
+ // time for the previous frame.
+ swapped_presentation_callbacks_.splice(swapped_presentation_callbacks_.end(),
+ swapping_presentation_callbacks_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ui::ContextFactoryObserver overrides:
+
+void SurfaceTreeHost::OnLostResources() {
+ if (!surface_host_->GetSurfaceId().is_valid() || !root_surface_)
+ return;
+ root_surface_->SurfaceHierarchyResourcesLost();
+ SubmitCompositorFrame();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SurfaceTreeHost, protected:
+
+void SurfaceTreeHost::SubmitCompositorFrame() {
+ DCHECK(root_surface_);
+ cc::CompositorFrame frame;
+ // If we commit while we don't have an active BeginFrame, we acknowledge a
+ // manual one.
+ if (current_begin_frame_ack_.sequence_number ==
+ viz::BeginFrameArgs::kInvalidFrameNumber) {
+ current_begin_frame_ack_ = viz::BeginFrameAck::CreateManualAckWithDamage();
+ } else {
+ current_begin_frame_ack_.has_damage = true;
+ }
+ frame.metadata.begin_frame_ack = current_begin_frame_ack_;
+ frame.render_pass_list.push_back(cc::RenderPass::Create());
+ const std::unique_ptr<cc::RenderPass>& render_pass =
+ frame.render_pass_list.back();
+ const int kRenderPassId = 1;
+ render_pass->SetNew(kRenderPassId, gfx::Rect(), gfx::Rect(),
+ gfx::Transform());
+ float device_scale_factor = surface_host_->layer()->device_scale_factor();
+ frame.metadata.device_scale_factor = device_scale_factor;
+ root_surface_->AppendSurfaceHierarchyContentsToFrame(
+ gfx::Point(), device_scale_factor, layer_tree_frame_sink_holder_.get(),
+ &frame);
+
+ gfx::Point origin = render_pass->output_rect.origin();
+ origin.SetToMin(gfx::Point());
+
+ render_pass->output_rect -= origin.OffsetFromOrigin();
+ render_pass->damage_rect -= origin.OffsetFromOrigin();
+
+ gfx::Transform translation;
+ translation.Translate(-origin.x(), -origin.y());
+
+ for (auto* quad_state : render_pass->shared_quad_state_list)
+ quad_state->quad_to_target_transform.ConcatTransform(translation);
+
+ layer_tree_frame_sink_holder_->frame_sink()->SubmitCompositorFrame(
+ std::move(frame));
+
+ if (current_begin_frame_ack_.sequence_number !=
+ viz::BeginFrameArgs::kInvalidFrameNumber) {
+ if (!current_begin_frame_ack_.has_damage) {
+ layer_tree_frame_sink_holder_->frame_sink()->DidNotProduceFrame(
+ current_begin_frame_ack_);
+ }
+ current_begin_frame_ack_.sequence_number =
+ viz::BeginFrameArgs::kInvalidFrameNumber;
+ if (begin_frame_source_)
+ begin_frame_source_->DidFinishFrame(this);
+ }
+}
+
} // namespace exo
diff --git a/chromium/components/exo/surface_tree_host.h b/chromium/components/exo/surface_tree_host.h
index c92a4342e04..5dc3a6c22c9 100644
--- a/chromium/components/exo/surface_tree_host.h
+++ b/chromium/components/exo/surface_tree_host.h
@@ -8,8 +8,12 @@
#include <memory>
#include "base/macros.h"
+#include "components/exo/layer_tree_frame_sink_holder.h"
#include "components/exo/surface.h"
#include "components/exo/surface_delegate.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "ui/aura/window_observer.h"
+#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/gfx/geometry/rect.h"
namespace aura {
@@ -21,11 +25,20 @@ namespace gfx {
class Path;
} // namespace gfx
+namespace viz {
+class BeginFrameSource;
+} // namespace viz
+
namespace exo {
+class LayerTreeFrameSinkHolder;
// This class provides functionality for hosting a surface tree. The surface
// tree is hosted in the |host_window_|.
-class SurfaceTreeHost : public SurfaceDelegate {
+class SurfaceTreeHost : public SurfaceDelegate,
+ public aura::WindowObserver,
+ public viz::BeginFrameObserverBase,
+ public ui::CompositorVSyncManager::Observer,
+ public ui::ContextFactoryObserver {
public:
SurfaceTreeHost(const std::string& window_name,
aura::WindowDelegate* window_delegate);
@@ -48,19 +61,83 @@ class SurfaceTreeHost : public SurfaceDelegate {
// registered then CursorType::kNull is returned.
gfx::NativeCursor GetCursor(const gfx::Point& point) const;
+ // Call this to indicate that the previous CompositorFrame is processed and
+ // the surface is being scheduled for a draw.
+ void DidReceiveCompositorFrameAck();
+
+ // Called when the begin frame source has changed.
+ void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source);
+
+ // Adds/Removes begin frame observer based on state.
+ void UpdateNeedsBeginFrame();
+
aura::Window* host_window() { return host_window_.get(); }
const aura::Window* host_window() const { return host_window_.get(); }
+ aura::Window* surface_host() { return surface_host_; }
+ const aura::Window* surface_host() const { return surface_host_; }
+
Surface* root_surface() { return root_surface_; }
const Surface* root_surface() const { return root_surface_; }
+ LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder() {
+ return layer_tree_frame_sink_holder_.get();
+ }
+
// Overridden from SurfaceDelegate:
void OnSurfaceCommit() override;
bool IsSurfaceSynchronized() const override;
+ // Overridden from aura::WindowObserver:
+ void OnWindowAddedToRootWindow(aura::Window* window) override;
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override;
+ void OnWindowDestroying(aura::Window* window) override;
+
+ // Overridden from cc::BeginFrameObserverBase:
+ bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override {}
+
+ // Overridden from ui::CompositorVSyncManager::Observer:
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+
+ // Overridden from ui::ContextFactoryObserver:
+ void OnLostResources() override;
+
+ protected:
+ // Call this to submit a compositor frame.
+ void SubmitCompositorFrame();
+
private:
Surface* root_surface_ = nullptr;
- std::unique_ptr<aura::Window> host_window_;
+ const std::unique_ptr<aura::Window> host_window_;
+ aura::Window* const surface_host_;
+ std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_;
+
+ // The begin frame source being observed.
+ viz::BeginFrameSource* begin_frame_source_ = nullptr;
+ bool needs_begin_frame_ = false;
+ viz::BeginFrameAck current_begin_frame_ack_;
+
+ // These lists contain 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<Surface::FrameCallback> frame_callbacks_;
+ std::list<Surface::FrameCallback> active_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<Surface::PresentationCallback> presentation_callbacks_;
+ std::list<Surface::PresentationCallback> swapping_presentation_callbacks_;
+ std::list<Surface::PresentationCallback> swapped_presentation_callbacks_;
DISALLOW_COPY_AND_ASSIGN(SurfaceTreeHost);
};
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index 5aa26f8905d..048e4086ceb 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_unittest.cc
@@ -2,33 +2,73 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/surfaces/surface.h"
+#include "components/exo/surface.h"
+
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
#include "cc/output/compositor_frame.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/test/begin_frame_args_test.h"
-#include "cc/test/fake_external_begin_frame_source.h"
#include "components/exo/buffer.h"
-#include "components/exo/surface.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/sub_surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2.h"
#include "ui/aura/env.h"
#include "ui/compositor/layer_tree_owner.h"
+#include "ui/display/display.h"
+#include "ui/display/display_switches.h"
+#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/wm/core/window_util.h"
namespace exo {
namespace {
-using SurfaceTest = test::ExoTestBase;
+class SurfaceTest : public test::ExoTestBase,
+ public ::testing::WithParamInterface<float> {
+ public:
+ SurfaceTest() = default;
+ ~SurfaceTest() override = default;
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ // Set the device scale factor.
+ command_line->AppendSwitchASCII(
+ switches::kForceDeviceScaleFactor,
+ base::StringPrintf("%f", device_scale_factor()));
+ test::ExoTestBase::SetUp();
+ }
+
+ void TearDown() override {
+ test::ExoTestBase::TearDown();
+ display::Display::ResetForceDeviceScaleFactorForTesting();
+ }
+
+ float device_scale_factor() const { return GetParam(); }
+
+ gfx::Rect ToPixel(const gfx::Rect rect) {
+ return gfx::ConvertRectToPixel(device_scale_factor(), rect);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SurfaceTest);
+};
void ReleaseBuffer(int* release_buffer_call_count) {
(*release_buffer_call_count)++;
}
-TEST_F(SurfaceTest, Attach) {
+// Instantiate the Boolean which is used to toggle mouse and touch events in
+// the parameterized tests.
+INSTANTIATE_TEST_CASE_P(, SurfaceTest, testing::Values(1.0f, 1.25f, 2.0f));
+
+TEST_P(SurfaceTest, Attach) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
@@ -60,7 +100,7 @@ TEST_F(SurfaceTest, Attach) {
ASSERT_EQ(1, release_buffer_call_count);
}
-TEST_F(SurfaceTest, Damage) {
+TEST_P(SurfaceTest, Damage) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
@@ -87,7 +127,7 @@ void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
*result = frame_time;
}
-TEST_F(SurfaceTest, RequestFrameCallback) {
+TEST_P(SurfaceTest, RequestFrameCallback) {
std::unique_ptr<Surface> surface(new Surface);
base::TimeTicks frame_time;
@@ -99,22 +139,23 @@ TEST_F(SurfaceTest, RequestFrameCallback) {
EXPECT_TRUE(frame_time.is_null());
}
-const cc::CompositorFrame& GetFrameFromSurface(Surface* surface) {
- viz::SurfaceId surface_id = surface->GetSurfaceId();
- cc::SurfaceManager* surface_manager = aura::Env::GetInstance()
- ->context_factory_private()
- ->GetFrameSinkManager()
- ->surface_manager();
+const cc::CompositorFrame& GetFrameFromSurface(ShellSurface* shell_surface) {
+ viz::SurfaceId surface_id = shell_surface->surface_host()->GetSurfaceId();
+ viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+ ->context_factory_private()
+ ->GetFrameSinkManager()
+ ->surface_manager();
const cc::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
return frame;
}
-TEST_F(SurfaceTest, SetOpaqueRegion) {
+TEST_P(SurfaceTest, SetOpaqueRegion) {
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
// Attaching a buffer with alpha channel.
surface->Attach(buffer.get());
@@ -126,13 +167,13 @@ TEST_F(SurfaceTest, SetOpaqueRegion) {
RunAllPendingInMessageLoop();
{
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
EXPECT_FALSE(frame.render_pass_list.back()
->quad_list.back()
->ShouldDrawWithBlending());
- EXPECT_EQ(gfx::Rect(0, 0, 1, 1),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 1, 1)),
frame.render_pass_list.back()->damage_rect);
}
@@ -142,13 +183,13 @@ TEST_F(SurfaceTest, SetOpaqueRegion) {
RunAllPendingInMessageLoop();
{
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
EXPECT_TRUE(frame.render_pass_list.back()
->quad_list.back()
->ShouldDrawWithBlending());
- EXPECT_EQ(gfx::Rect(0, 0, 1, 1),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 1, 1)),
frame.render_pass_list.back()->damage_rect);
}
@@ -163,18 +204,18 @@ TEST_F(SurfaceTest, SetOpaqueRegion) {
RunAllPendingInMessageLoop();
{
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
EXPECT_FALSE(frame.render_pass_list.back()
->quad_list.back()
->ShouldDrawWithBlending());
- EXPECT_EQ(gfx::Rect(0, 0, 0, 0),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 0, 0)),
frame.render_pass_list.back()->damage_rect);
}
}
-TEST_F(SurfaceTest, SetInputRegion) {
+TEST_P(SurfaceTest, SetInputRegion) {
std::unique_ptr<Surface> surface(new Surface);
// Setting a non-empty input region should succeed.
@@ -184,11 +225,12 @@ TEST_F(SurfaceTest, SetInputRegion) {
surface->SetInputRegion(SkRegion(SkIRect::MakeEmpty()));
}
-TEST_F(SurfaceTest, SetBufferScale) {
+TEST_P(SurfaceTest, SetBufferScale) {
gfx::Size buffer_size(512, 512);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
// This will update the bounds of the surface and take the buffer scale into
// account.
@@ -205,37 +247,118 @@ TEST_F(SurfaceTest, SetBufferScale) {
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
- EXPECT_EQ(gfx::Rect(0, 0, 256, 256),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 256, 256)),
frame.render_pass_list.back()->damage_rect);
}
-TEST_F(SurfaceTest, MirrorLayers) {
+TEST_P(SurfaceTest, SetBufferTransform) {
+ gfx::Size buffer_size(256, 512);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
+
+ // This will update the bounds of the surface and take the buffer transform
+ // into account.
+ surface->Attach(buffer.get());
+ surface->SetBufferTransform(Transform::ROTATE_90);
+ surface->Commit();
+ EXPECT_EQ(gfx::Size(buffer_size.height(), buffer_size.width()),
+ surface->window()->bounds().size());
+ EXPECT_EQ(gfx::Size(buffer_size.height(), buffer_size.width()),
+ surface->content_size());
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(0, 0, buffer_size.height(), buffer_size.width())),
+ frame.render_pass_list.back()->damage_rect);
+ const cc::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(0, 0, 512, 256)),
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad_list.front()->shared_quad_state->quad_to_target_transform,
+ quad_list.front()->rect));
+ }
+
+ gfx::Size child_buffer_size(64, 128);
+ auto child_buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
+ auto child_surface = base::MakeUnique<Surface>();
+ auto sub_surface =
+ base::MakeUnique<SubSurface>(child_surface.get(), surface.get());
+
+ // Set position to 20, 10.
+ gfx::Point child_position(20, 10);
+ sub_surface->SetPosition(child_position);
+
+ child_surface->Attach(child_buffer.get());
+ child_surface->SetBufferTransform(Transform::ROTATE_180);
+ const int kChildBufferScale = 2;
+ child_surface->SetBufferScale(kChildBufferScale);
+ child_surface->Commit();
+ surface->Commit();
+ EXPECT_EQ(
+ gfx::ScaleToRoundedSize(child_buffer_size, 1.0f / kChildBufferScale),
+ child_surface->window()->bounds().size());
+ EXPECT_EQ(
+ gfx::ScaleToRoundedSize(child_buffer_size, 1.0f / kChildBufferScale),
+ child_surface->content_size());
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const cc::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(2u, quad_list.size());
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(child_position,
+ gfx::ScaleToRoundedSize(child_buffer_size,
+ 1.0f / kChildBufferScale))),
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad_list.front()->shared_quad_state->quad_to_target_transform,
+ quad_list.front()->rect));
+ }
+}
+
+TEST_P(SurfaceTest, MirrorLayers) {
gfx::Size buffer_size(512, 512);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
surface->Commit();
- EXPECT_EQ(buffer_size, surface->window()->bounds().size());
- EXPECT_EQ(buffer_size, surface->window()->layer()->bounds().size());
- std::unique_ptr<ui::LayerTreeOwner> old_layer_owner =
- ::wm::MirrorLayers(surface->window(), false /* sync_bounds */);
- EXPECT_EQ(buffer_size, surface->window()->bounds().size());
- EXPECT_EQ(buffer_size, surface->window()->layer()->bounds().size());
+ auto* layer_owner = shell_surface->surface_host();
+ EXPECT_EQ(buffer_size, layer_owner->bounds().size());
+ EXPECT_EQ(buffer_size, layer_owner->layer()->bounds().size());
+
+ std::unique_ptr<ui::LayerTreeOwner> old_layer_owner = ::wm::MirrorLayers(
+ shell_surface->surface_host(), false /* sync_bounds */);
+
+ EXPECT_EQ(buffer_size, layer_owner->bounds().size());
+ EXPECT_EQ(buffer_size, layer_owner->layer()->bounds().size());
EXPECT_EQ(buffer_size, old_layer_owner->root()->bounds().size());
- EXPECT_TRUE(surface->window()->layer()->has_external_content());
+
+ EXPECT_TRUE(layer_owner->layer()->has_external_content());
EXPECT_TRUE(old_layer_owner->root()->has_external_content());
}
-TEST_F(SurfaceTest, SetViewport) {
+TEST_P(SurfaceTest, SetViewport) {
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
// This will update the bounds of the surface and take the viewport into
// account.
@@ -256,17 +379,18 @@ TEST_F(SurfaceTest, SetViewport) {
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
- EXPECT_EQ(gfx::Rect(0, 0, 512, 512),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 512, 512)),
frame.render_pass_list.back()->damage_rect);
}
-TEST_F(SurfaceTest, SetCrop) {
+TEST_P(SurfaceTest, SetCrop) {
gfx::Size buffer_size(16, 16);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
gfx::Size crop_size(12, 12);
@@ -278,24 +402,208 @@ TEST_F(SurfaceTest, SetCrop) {
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
- EXPECT_EQ(gfx::Rect(0, 0, 12, 12),
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 12, 12)),
frame.render_pass_list.back()->damage_rect);
}
-TEST_F(SurfaceTest, SetBlendMode) {
+TEST_P(SurfaceTest, SetCropAndBufferTransform) {
+ gfx::Size buffer_size(128, 64);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
+
+ const gfx::RectF crop_0(
+ gfx::SkRectToRectF(SkRect::MakeLTRB(0.03125f, 0.1875f, 0.4375f, 0.25f)));
+ const gfx::RectF crop_90(
+ gfx::SkRectToRectF(SkRect::MakeLTRB(0.875f, 0.0625f, 0.90625f, 0.875f)));
+ const gfx::RectF crop_180(
+ gfx::SkRectToRectF(SkRect::MakeLTRB(0.5625f, 0.75f, 0.96875f, 0.8125f)));
+ const gfx::RectF crop_270(
+ gfx::SkRectToRectF(SkRect::MakeLTRB(0.09375f, 0.125f, 0.125f, 0.9375f)));
+ const gfx::Rect target_with_no_viewport(ToPixel(gfx::Rect(gfx::Size(52, 4))));
+ const gfx::Rect target_with_viewport(ToPixel(gfx::Rect(gfx::Size(128, 64))));
+
+ surface->Attach(buffer.get());
+ gfx::Size crop_size(52, 4);
+ surface->SetCrop(gfx::RectF(gfx::PointF(4, 12), gfx::SizeF(crop_size)));
+ surface->SetBufferTransform(Transform::NORMAL);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_0.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_0.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(0, 0, 52, 4)),
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_90);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_90.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_90.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(0, 0, 52, 4)),
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_180);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_180.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_180.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ ToPixel(gfx::Rect(0, 0, 52, 4)),
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_270);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_270.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_270.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ target_with_no_viewport,
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetViewport(gfx::Size(128, 64));
+ surface->SetBufferTransform(Transform::NORMAL);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_0.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_0.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ target_with_viewport,
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_90);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_90.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_90.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ target_with_viewport,
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_180);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_180.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_180.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ target_with_viewport,
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+
+ surface->SetBufferTransform(Transform::ROTATE_270);
+ surface->Commit();
+
+ RunAllPendingInMessageLoop();
+
+ {
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ ASSERT_EQ(1u, frame.render_pass_list.size());
+ const viz::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
+ ASSERT_EQ(1u, quad_list.size());
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(quad_list.front());
+ EXPECT_EQ(crop_270.origin(), quad->uv_top_left);
+ EXPECT_EQ(crop_270.bottom_right(), quad->uv_bottom_right);
+ EXPECT_EQ(
+ target_with_viewport,
+ cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->rect));
+ }
+}
+
+TEST_P(SurfaceTest, SetBlendMode) {
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
surface->SetBlendMode(SkBlendMode::kSrc);
surface->Commit();
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
EXPECT_FALSE(frame.render_pass_list.back()
@@ -303,17 +611,19 @@ TEST_F(SurfaceTest, SetBlendMode) {
->ShouldDrawWithBlending());
}
-TEST_F(SurfaceTest, OverlayCandidate) {
+TEST_P(SurfaceTest, OverlayCandidate) {
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(new Buffer(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), 0, 0, true, true));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D, 0,
+ true, true);
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
surface->Commit();
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
cc::DrawQuad* draw_quad = frame.render_pass_list.back()->quad_list.back();
@@ -324,36 +634,41 @@ TEST_F(SurfaceTest, OverlayCandidate) {
EXPECT_FALSE(texture_quad->resource_size_in_pixels().IsEmpty());
}
-TEST_F(SurfaceTest, SetAlpha) {
+TEST_P(SurfaceTest, SetAlpha) {
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D, 0,
+ true, true);
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
surface->SetAlpha(0.5f);
surface->Commit();
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
ASSERT_EQ(1u, frame.render_pass_list.size());
- EXPECT_EQ(gfx::Rect(0, 0, 1, 1), frame.render_pass_list.back()->damage_rect);
+ EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 1, 1)),
+ frame.render_pass_list.back()->damage_rect);
}
-TEST_F(SurfaceTest, Commit) {
+TEST_P(SurfaceTest, Commit) {
std::unique_ptr<Surface> surface(new Surface);
// Calling commit without a buffer should succeed.
surface->Commit();
}
-TEST_F(SurfaceTest, SendsBeginFrameAcks) {
- cc::FakeExternalBeginFrameSource source(0.f, false);
+TEST_P(SurfaceTest, SendsBeginFrameAcks) {
+ viz::FakeExternalBeginFrameSource source(0.f, false);
gfx::Size buffer_size(1, 1);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
- surface->SetBeginFrameSource(&source);
+ auto buffer = base::MakeUnique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D, 0,
+ true, true);
+ auto surface = base::MakeUnique<Surface>();
+ auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
+ shell_surface->SetBeginFrameSource(&source);
surface->Attach(buffer.get());
// Request a frame callback so that Surface now needs BeginFrames.
@@ -365,10 +680,10 @@ TEST_F(SurfaceTest, SendsBeginFrameAcks) {
// Surface should add itself as observer during
// DidReceiveCompositorFrameAck().
- surface->DidReceiveCompositorFrameAck();
+ shell_surface->DidReceiveCompositorFrameAck();
EXPECT_EQ(1u, source.num_observers());
- cc::BeginFrameArgs args(source.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE));
+ viz::BeginFrameArgs args(source.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE));
args.frame_time = base::TimeTicks::FromInternalValue(100);
source.TestOnBeginFrame(args); // Runs the frame callback.
EXPECT_EQ(args.frame_time, frame_time);
@@ -376,12 +691,38 @@ TEST_F(SurfaceTest, SendsBeginFrameAcks) {
surface->Commit(); // Acknowledges the BeginFrame via CompositorFrame.
RunAllPendingInMessageLoop();
- const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
- cc::BeginFrameAck expected_ack(args.source_id, args.sequence_number, true);
+ const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+ viz::BeginFrameAck expected_ack(args.source_id, args.sequence_number, true);
EXPECT_EQ(expected_ack, frame.metadata.begin_frame_ack);
// TODO(eseckler): Add test for DidNotProduceFrame plumbing.
}
+TEST_P(SurfaceTest, RemoveSubSurface) {
+ 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 = std::make_unique<ShellSurface>(surface.get());
+ surface->Attach(buffer.get());
+
+ // Create a subsurface:
+ 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());
+ sub_surface->SetPosition(gfx::Point(20, 10));
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ RunAllPendingInMessageLoop();
+
+ // Remove the subsurface by destroying it. This should damage |surface|.
+ sub_surface.reset();
+ EXPECT_TRUE(surface->HasPendingDamageForTesting(gfx::Rect(20, 10, 64, 128)));
+}
+
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index dc01f9428bf..f1bae38194e 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -91,6 +91,7 @@ source_set("unit_tests") {
"//third_party/wayland:wayland_client",
]
}
+
source_set("client_lib") {
sources = [
"clients/client_base.cc",
@@ -128,6 +129,7 @@ executable("wayland_rects_client") {
deps = [
":client_lib",
"//base",
+ "//build/config:exe_and_shlib_deps",
"//skia",
"//third_party/wayland:wayland_client",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
@@ -154,6 +156,34 @@ executable("wayland_simple_client") {
deps = [
":client_lib",
"//base",
+ "//build/config:exe_and_shlib_deps",
+ "//skia",
+ "//third_party/wayland:wayland_client",
+ "//third_party/wayland-protocols:linux_dmabuf_protocol",
+ "//third_party/wayland-protocols:presentation_time_protocol",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ ]
+
+ if (ozone_platform_gbm) {
+ configs += [
+ ":libdrm",
+ "//ui/gl:gl_config",
+ ]
+ defines = [ "OZONE_PLATFORM_GBM" ]
+ deps += [ "//third_party/minigbm" ]
+ }
+}
+
+executable("wayland_subsurface_client") {
+ sources = [
+ "clients/subsurface.cc",
+ ]
+
+ deps = [
+ ":client_lib",
+ "//base",
+ "//build/config:exe_and_shlib_deps",
"//skia",
"//third_party/wayland:wayland_client",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
diff --git a/chromium/components/exo/wayland/clients/client_base.cc b/chromium/components/exo/wayland/clients/client_base.cc
index ddc142a1aec..df7898b8ef6 100644
--- a/chromium/components/exo/wayland/clients/client_base.cc
+++ b/chromium/components/exo/wayland/clients/client_base.cc
@@ -26,6 +26,7 @@
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface_egl.h"
@@ -50,6 +51,9 @@ const char kSize[] = "size";
// Specifies the client scale factor (ie. number of physical pixels per DIP).
const char kScale[] = "scale";
+// Specifies the client transform (ie. rotation).
+const char kTransform[] = "transform";
+
// Specifies if the background should be transparent.
const char kTransparentBackground[] = "transparent-background";
@@ -101,6 +105,9 @@ void RegistryHandler(void* data,
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>(
wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1)));
+ } else if (strcmp(interface, "wl_subcompositor") == 0) {
+ globals->subcompositor.reset(static_cast<wl_subcompositor*>(
+ wl_registry_bind(registry, id, &wl_subcompositor_interface, 1)));
}
}
@@ -133,6 +140,7 @@ wl_buffer_listener g_buffer_listener = {BufferRelease};
ClientBase::InitParams::InitParams() {
#if defined(OZONE_PLATFORM_GBM)
drm_format = DRM_FORMAT_ABGR8888;
+ bo_usage = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING | GBM_BO_USE_TEXTURING;
#endif
}
@@ -155,6 +163,23 @@ bool ClientBase::InitParams::FromCommandLine(
return false;
}
+ if (command_line.HasSwitch(switches::kTransform)) {
+ std::string transform_str =
+ command_line.GetSwitchValueASCII(switches::kTransform);
+ if (transform_str == "0") {
+ transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ } else if (transform_str == "90") {
+ transform = WL_OUTPUT_TRANSFORM_90;
+ } else if (transform_str == "180") {
+ transform = WL_OUTPUT_TRANSFORM_180;
+ } else if (transform_str == "270") {
+ transform = WL_OUTPUT_TRANSFORM_270;
+ } else {
+ LOG(ERROR) << "Invalid value for " << switches::kTransform;
+ return false;
+ }
+ }
+
use_drm = command_line.HasSwitch(switches::kUseDrm);
if (use_drm)
use_drm_value = command_line.GetSwitchValueASCII(switches::kUseDrm);
@@ -183,9 +208,24 @@ ClientBase::Buffer::~Buffer() {}
// ClientBase, public:
bool ClientBase::Init(const InitParams& params) {
- width_ = params.width;
- height_ = params.height;
+ size_.SetSize(params.width, params.height);
scale_ = params.scale;
+ transform_ = params.transform;
+ switch (params.transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ case WL_OUTPUT_TRANSFORM_180:
+ surface_size_.SetSize(params.width, params.height);
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ surface_size_.SetSize(params.height, params.width);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ surface_size_ = gfx::ToCeiledSize(
+ gfx::ScaleSize(gfx::SizeF(surface_size_), 1.0f / params.scale));
fullscreen_ = params.fullscreen;
transparent_background_ = params.transparent_background;
@@ -293,7 +333,7 @@ bool ClientBase::Init(const InitParams& params) {
}
#endif
for (size_t i = 0; i < params.num_buffers; ++i) {
- auto buffer = CreateBuffer(params.drm_format);
+ auto buffer = CreateBuffer(size_, params.drm_format, params.bo_usage);
if (!buffer) {
LOG(ERROR) << "Failed to create buffer";
return false;
@@ -308,9 +348,6 @@ bool ClientBase::Init(const InitParams& params) {
LOG(ERROR) << "buffer handle uninitialized.";
return false;
}
-
- wl_buffer_add_listener(buffers_[i]->buffer.get(), &g_buffer_listener,
- buffers_[i].get());
}
surface_.reset(static_cast<wl_surface*>(
@@ -328,7 +365,7 @@ bool ClientBase::Init(const InitParams& params) {
return false;
}
- wl_region_add(opaque_region.get(), 0, 0, width_, height_);
+ wl_region_add(opaque_region.get(), 0, 0, size_.width(), size_.height());
wl_surface_set_opaque_region(surface_.get(), opaque_region.get());
}
std::unique_ptr<wl_shell_surface> shell_surface(
@@ -363,12 +400,53 @@ ClientBase::~ClientBase() {}
// ClientBase, private:
std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
- int32_t drm_format) {
- std::unique_ptr<Buffer> buffer(new Buffer());
+ const gfx::Size& size,
+ int32_t drm_format,
+ int32_t bo_usage) {
+ std::unique_ptr<Buffer> buffer;
+ if (device_) {
+ buffer = CreateDrmBuffer(size, drm_format, bo_usage);
+ CHECK(buffer) << "Can't create drm buffer";
+ } else {
+ buffer = base::MakeUnique<Buffer>();
+
+ size_t stride = size.width() * kBytesPerPixel;
+ buffer->shared_memory.reset(new base::SharedMemory());
+ buffer->shared_memory->CreateAndMapAnonymous(stride * size.height());
+ buffer->shm_pool.reset(wl_shm_create_pool(
+ globals_.shm.get(), buffer->shared_memory->handle().GetHandle(),
+ buffer->shared_memory->requested_size()));
+
+ buffer->buffer.reset(static_cast<wl_buffer*>(
+ wl_shm_pool_create_buffer(buffer->shm_pool.get(), 0, size.width(),
+ size.height(), stride, kShmFormat)));
+ if (!buffer->buffer) {
+ LOG(ERROR) << "Can't create buffer";
+ return nullptr;
+ }
+
+ buffer->sk_surface = SkSurface::MakeRasterDirect(
+ SkImageInfo::Make(size.width(), size.height(), kColorType,
+ kOpaque_SkAlphaType),
+ static_cast<uint8_t*>(buffer->shared_memory->memory()), stride);
+ DCHECK(buffer->sk_surface);
+ }
+
+ wl_buffer_add_listener(buffer->buffer.get(), &g_buffer_listener,
+ buffer.get());
+ return buffer;
+}
+
+std::unique_ptr<ClientBase::Buffer> ClientBase::CreateDrmBuffer(
+ const gfx::Size& size,
+ int32_t drm_format,
+ int32_t bo_usage) {
+ std::unique_ptr<Buffer> buffer;
#if defined(OZONE_PLATFORM_GBM)
if (device_) {
- buffer->bo.reset(gbm_bo_create(device_.get(), width_, height_, drm_format,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
+ buffer = base::MakeUnique<Buffer>();
+ buffer->bo.reset(gbm_bo_create(device_.get(), size.width(), size.height(),
+ drm_format, bo_usage));
if (!buffer->bo) {
LOG(ERROR) << "Can't create gbm buffer";
return nullptr;
@@ -385,7 +463,7 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
stride, 0, 0);
}
buffer->buffer.reset(zwp_linux_buffer_params_v1_create_immed(
- buffer->params.get(), width_, height_, drm_format, 0));
+ buffer->params.get(), size.width(), size.height(), drm_format, 0));
if (gbm_bo_get_num_planes(buffer->bo.get()) != 1)
return buffer;
@@ -393,9 +471,9 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
EGLint khr_image_attrs[] = {EGL_DMA_BUF_PLANE0_FD_EXT,
fd.get(),
EGL_WIDTH,
- width_,
+ size.width(),
EGL_HEIGHT,
- height_,
+ size.height(),
EGL_LINUX_DRM_FOURCC_EXT,
drm_format,
EGL_DMA_BUF_PLANE0_PITCH_EXT,
@@ -419,34 +497,14 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
GrGLTextureInfo texture_info;
texture_info.fID = buffer->texture->get();
texture_info.fTarget = GL_TEXTURE_2D;
- GrBackendTexture backend_texture(width_, height_, kGrPixelConfig,
- texture_info);
+ GrBackendTexture backend_texture(size.width(), size.height(),
+ kGrPixelConfig, texture_info);
buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
gr_context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
/* sampleCnt */ 0, /* colorSpace */ nullptr, /* props */ nullptr);
DCHECK(buffer->sk_surface);
- return buffer;
}
#endif
-
- size_t stride = width_ * kBytesPerPixel;
- buffer->shared_memory.reset(new base::SharedMemory());
- buffer->shared_memory->CreateAndMapAnonymous(stride * height_);
- buffer->shm_pool.reset(wl_shm_create_pool(
- globals_.shm.get(), buffer->shared_memory->handle().GetHandle(),
- buffer->shared_memory->requested_size()));
-
- buffer->buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer(
- buffer->shm_pool.get(), 0, width_, height_, stride, kShmFormat)));
- if (!buffer->buffer) {
- LOG(ERROR) << "Can't create buffer";
- return nullptr;
- }
-
- buffer->sk_surface = SkSurface::MakeRasterDirect(
- SkImageInfo::Make(width_, height_, kColorType, kOpaque_SkAlphaType),
- static_cast<uint8_t*>(buffer->shared_memory->memory()), stride);
- DCHECK(buffer->sk_surface);
return buffer;
}
diff --git a/chromium/components/exo/wayland/clients/client_base.h b/chromium/components/exo/wayland/clients/client_base.h
index 2fef99afd61..1ae68e4ade4 100644
--- a/chromium/components/exo/wayland/clients/client_base.h
+++ b/chromium/components/exo/wayland/clients/client_base.h
@@ -13,6 +13,7 @@
#include "components/exo/wayland/clients/client_helper.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/scoped_make_current.h"
@@ -39,11 +40,13 @@ class ClientBase {
size_t width = 256;
size_t height = 256;
int scale = 1;
+ int transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool fullscreen = false;
bool transparent_background = false;
bool use_drm = false;
std::string use_drm_value;
int32_t drm_format = 0;
+ int32_t bo_usage = 0;
};
struct Globals {
@@ -56,6 +59,7 @@ class ClientBase {
std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf;
std::unique_ptr<wl_shell> shell;
std::unique_ptr<wl_seat> seat;
+ std::unique_ptr<wl_subcompositor> subcompositor;
};
struct Buffer {
@@ -81,10 +85,17 @@ class ClientBase {
protected:
ClientBase();
virtual ~ClientBase();
-
- size_t width_ = 256;
- size_t height_ = 256;
+ std::unique_ptr<Buffer> CreateBuffer(const gfx::Size& size,
+ int32_t drm_format,
+ int32_t bo_usage);
+ std::unique_ptr<Buffer> CreateDrmBuffer(const gfx::Size& size,
+ int32_t drm_format,
+ int32_t bo_usage);
+
+ gfx::Size size_ = gfx::Size(256, 256);
int scale_ = 1;
+ int transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
+ gfx::Size surface_size_ = gfx::Size(256, 256);
bool fullscreen_ = false;
bool transparent_background_ = false;
@@ -104,9 +115,6 @@ class ClientBase {
std::vector<std::unique_ptr<Buffer>> buffers_;
sk_sp<GrContext> gr_context_;
- private:
- std::unique_ptr<Buffer> CreateBuffer(int32_t drm_format);
-
DISALLOW_COPY_AND_ASSIGN(ClientBase);
};
diff --git a/chromium/components/exo/wayland/clients/client_helper.cc b/chromium/components/exo/wayland/clients/client_helper.cc
index 51ccd7754f0..b7c859dd7e6 100644
--- a/chromium/components/exo/wayland/clients/client_helper.cc
+++ b/chromium/components/exo/wayland/clients/client_helper.cc
@@ -25,19 +25,21 @@
} \
}
-DEFAULT_DELETER(wl_display, wl_display_disconnect)
-DEFAULT_DELETER(wl_compositor, wl_compositor_destroy)
-DEFAULT_DELETER(wl_shm, wl_shm_destroy)
-DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy)
DEFAULT_DELETER(wl_buffer, wl_buffer_destroy)
-DEFAULT_DELETER(wl_surface, wl_surface_destroy)
+DEFAULT_DELETER(wl_callback, wl_callback_destroy)
+DEFAULT_DELETER(wl_compositor, wl_compositor_destroy)
+DEFAULT_DELETER(wl_display, wl_display_disconnect)
+DEFAULT_DELETER(wl_pointer, wl_pointer_destroy)
DEFAULT_DELETER(wl_region, wl_region_destroy)
+DEFAULT_DELETER(wl_seat, wl_seat_destroy)
DEFAULT_DELETER(wl_shell, wl_shell_destroy)
DEFAULT_DELETER(wl_shell_surface, wl_shell_surface_destroy)
-DEFAULT_DELETER(wl_seat, wl_seat_destroy)
-DEFAULT_DELETER(wl_pointer, wl_pointer_destroy)
+DEFAULT_DELETER(wl_shm, wl_shm_destroy)
+DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy)
+DEFAULT_DELETER(wl_subcompositor, wl_subcompositor_destroy)
+DEFAULT_DELETER(wl_subsurface, wl_subsurface_destroy)
+DEFAULT_DELETER(wl_surface, wl_surface_destroy)
DEFAULT_DELETER(wl_touch, wl_touch_destroy)
-DEFAULT_DELETER(wl_callback, wl_callback_destroy)
DEFAULT_DELETER(wp_presentation, wp_presentation_destroy)
DEFAULT_DELETER(struct wp_presentation_feedback,
wp_presentation_feedback_destroy)
@@ -45,8 +47,8 @@ DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy)
DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy)
#if defined(OZONE_PLATFORM_GBM)
-DEFAULT_DELETER(gbm_device, gbm_device_destroy)
DEFAULT_DELETER(gbm_bo, gbm_bo_destroy)
+DEFAULT_DELETER(gbm_device, gbm_device_destroy)
#endif
namespace exo {
diff --git a/chromium/components/exo/wayland/clients/client_helper.h b/chromium/components/exo/wayland/clients/client_helper.h
index c9a59529487..cbb7039d2c4 100644
--- a/chromium/components/exo/wayland/clients/client_helper.h
+++ b/chromium/components/exo/wayland/clients/client_helper.h
@@ -27,27 +27,29 @@
}; \
}
-DEFAULT_DELETER_FDECL(wl_display)
-DEFAULT_DELETER_FDECL(wl_compositor)
-DEFAULT_DELETER_FDECL(wl_shm)
-DEFAULT_DELETER_FDECL(wl_shm_pool)
DEFAULT_DELETER_FDECL(wl_buffer)
-DEFAULT_DELETER_FDECL(wl_surface)
+DEFAULT_DELETER_FDECL(wl_callback)
+DEFAULT_DELETER_FDECL(wl_compositor)
+DEFAULT_DELETER_FDECL(wl_display)
+DEFAULT_DELETER_FDECL(wl_pointer)
DEFAULT_DELETER_FDECL(wl_region)
+DEFAULT_DELETER_FDECL(wl_seat)
DEFAULT_DELETER_FDECL(wl_shell)
DEFAULT_DELETER_FDECL(wl_shell_surface)
-DEFAULT_DELETER_FDECL(wl_seat)
-DEFAULT_DELETER_FDECL(wl_pointer)
+DEFAULT_DELETER_FDECL(wl_shm)
+DEFAULT_DELETER_FDECL(wl_shm_pool)
+DEFAULT_DELETER_FDECL(wl_subcompositor)
+DEFAULT_DELETER_FDECL(wl_subsurface)
+DEFAULT_DELETER_FDECL(wl_surface)
DEFAULT_DELETER_FDECL(wl_touch)
-DEFAULT_DELETER_FDECL(wl_callback)
DEFAULT_DELETER_FDECL(wp_presentation)
DEFAULT_DELETER_FDECL(struct wp_presentation_feedback)
DEFAULT_DELETER_FDECL(zwp_linux_buffer_params_v1)
DEFAULT_DELETER_FDECL(zwp_linux_dmabuf_v1)
#if defined(OZONE_PLATFORM_GBM)
-DEFAULT_DELETER_FDECL(gbm_device)
DEFAULT_DELETER_FDECL(gbm_bo)
+DEFAULT_DELETER_FDECL(gbm_device)
#endif
namespace exo {
diff --git a/chromium/components/exo/wayland/clients/rects.cc b/chromium/components/exo/wayland/clients/rects.cc
index 342d8e66142..bfb6b5223a2 100644
--- a/chromium/components/exo/wayland/clients/rects.cc
+++ b/chromium/components/exo/wayland/clients/rects.cc
@@ -12,13 +12,13 @@
#include <wayland-client-protocol.h>
#include <cmath>
-#include <deque>
#include <iostream>
#include <string>
#include <vector>
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/containers/circular_deque.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -149,7 +149,7 @@ struct Frame {
};
struct Presentation {
- std::deque<std::unique_ptr<Frame>> scheduled_frames;
+ base::circular_deque<std::unique_ptr<Frame>> scheduled_frames;
base::TimeDelta wall_time;
base::TimeDelta cpu_time;
base::TimeDelta latency_time;
@@ -261,7 +261,7 @@ int RectsClient::Run(const ClientBase::InitParams& params,
wl_callback_listener frame_listener = {FrameCallback};
Presentation presentation;
- std::deque<std::unique_ptr<Frame>> pending_frames;
+ base::circular_deque<std::unique_ptr<Frame>> pending_frames;
size_t num_benchmark_runs_left = num_benchmark_runs;
base::TimeTicks benchmark_start_time;
@@ -343,9 +343,10 @@ int RectsClient::Run(const ClientBase::InitParams& params,
// since last frame. Latest event at the top.
int y = 0;
// Note: Rounding up to ensure we cover the whole canvas.
- int h = (height_ + (event_times.size() / 2)) / event_times.size();
+ int h =
+ (size_.height() + (event_times.size() / 2)) / event_times.size();
while (!event_times.empty()) {
- SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h);
+ SkIRect rect = SkIRect::MakeXYWH(0, y, size_.width(), h);
SkPaint paint;
paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0,
(event_times.back() & 0x00ff00) >> 8,
@@ -361,8 +362,8 @@ int RectsClient::Run(const ClientBase::InitParams& params,
}
// Draw rotating rects.
- SkScalar half_width = SkScalarHalf(width_);
- SkScalar half_height = SkScalarHalf(height_);
+ SkScalar half_width = SkScalarHalf(size_.width());
+ SkScalar half_height = SkScalarHalf(size_.height());
SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width),
-SkScalarHalf(half_height), half_width,
half_height);
@@ -383,7 +384,7 @@ int RectsClient::Run(const ClientBase::InitParams& params,
// Draw FPS counter.
if (show_fps_counter) {
canvas->drawText(fps_counter_text.c_str(), fps_counter_text.length(),
- width_ - 48, 32, text_paint);
+ size_.width() - 48, 32, text_paint);
}
GrContext* gr_context = gr_context_.get();
if (gr_context) {
@@ -417,7 +418,9 @@ int RectsClient::Run(const ClientBase::InitParams& params,
wl_surface* surface = surface_.get();
wl_surface_set_buffer_scale(surface, scale_);
- wl_surface_damage(surface, 0, 0, width_ / scale_, height_ / scale_);
+ wl_surface_set_buffer_transform(surface_.get(), transform_);
+ wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
+ surface_size_.height());
wl_surface_attach(surface, frame->buffer->buffer.get(), 0, 0);
#if defined(OZONE_PLATFORM_GBM)
diff --git a/chromium/components/exo/wayland/clients/simple.cc b/chromium/components/exo/wayland/clients/simple.cc
index a437c076336..83866622d7b 100644
--- a/chromium/components/exo/wayland/clients/simple.cc
+++ b/chromium/components/exo/wayland/clients/simple.cc
@@ -56,7 +56,9 @@ void SimpleClient::Run(const ClientBase::InitParams& params) {
glFinish();
}
wl_surface_set_buffer_scale(surface_.get(), scale_);
- wl_surface_damage(surface_.get(), 0, 0, width_ / scale_, height_ / scale_);
+ wl_surface_set_buffer_transform(surface_.get(), transform_);
+ wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
+ surface_size_.height());
wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
frame_callback.reset(wl_surface_frame(surface_.get()));
diff --git a/chromium/components/exo/wayland/clients/subsurface.cc b/chromium/components/exo/wayland/clients/subsurface.cc
new file mode 100644
index 00000000000..ad413afe554
--- /dev/null
+++ b/chromium/components/exo/wayland/clients/subsurface.cc
@@ -0,0 +1,158 @@
+// 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 "base/at_exit.h"
+#include "base/command_line.h"
+#include "components/exo/wayland/clients/client_base.h"
+#include "components/exo/wayland/clients/client_helper.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace exo {
+namespace wayland {
+namespace clients {
+namespace {
+
+void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
+ bool* callback_pending = static_cast<bool*>(data);
+ *callback_pending = false;
+}
+
+} // namespace
+
+// This demo testes subsurface features of exo.
+// For the first 200 frames: we animate parent surface, child_surface and
+// child_surface's position.
+// For 200-400 frames: we animate parent surface and child_surface's position.
+// For 400-600 frames: we only animate child_surface's position.
+// After 600 frames: we still animate child_surface's position, but don't call
+// commit on parent surface. So the window will stop updating.
+class SubSurfaceClient : public ClientBase {
+ public:
+ SubSurfaceClient() = default;
+ ~SubSurfaceClient() override = default;
+
+ void Run(const ClientBase::InitParams& params);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SubSurfaceClient);
+};
+
+void SubSurfaceClient::Run(const ClientBase::InitParams& params) {
+ if (!ClientBase::Init(params))
+ return;
+
+ std::unique_ptr<wl_surface> child_surface(static_cast<wl_surface*>(
+ wl_compositor_create_surface(globals_.compositor.get())));
+
+ std::unique_ptr<wl_subsurface> subsurface(
+ static_cast<wl_subsurface*>(wl_subcompositor_get_subsurface(
+ globals_.subcompositor.get(), child_surface.get(), surface_.get())));
+
+ if (!child_surface || !subsurface) {
+ LOG(ERROR) << "Can't create subsurface";
+ return;
+ }
+
+ constexpr int32_t kSubsurfaceWidth = 128;
+ constexpr int32_t kSubsurfaceHeight = 128;
+ auto subbuffer = CreateBuffer(gfx::Size(kSubsurfaceWidth, kSubsurfaceHeight),
+ params.drm_format, params.bo_usage);
+ if (!subbuffer) {
+ LOG(ERROR) << "Failed to create subbuffer";
+ return;
+ }
+
+ bool callback_pending = false;
+ std::unique_ptr<wl_callback> frame_callback;
+ wl_callback_listener frame_listener = {FrameCallback};
+
+ size_t frame_count = 0;
+ do {
+ if (callback_pending && frame_count < 600)
+ continue;
+
+ // Only generate frames to child surface for the first 200 frames.
+ if (frame_count < 200) {
+ SkScalar half_width = SkScalarHalf(kSubsurfaceWidth);
+ SkScalar half_height = SkScalarHalf(kSubsurfaceHeight);
+ SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width),
+ -SkScalarHalf(half_height), half_width,
+ half_height);
+ // Rotation speed (degrees/frame).
+ const double kRotationSpeed = 5.;
+ SkScalar rotation = frame_count * kRotationSpeed;
+ SkCanvas* canvas = subbuffer->sk_surface->getCanvas();
+ canvas->save();
+ canvas->clear(SK_ColorBLACK);
+ SkPaint paint;
+ paint.setColor(SkColorSetA(SK_ColorYELLOW, 0xA0));
+ canvas->translate(half_width, half_height);
+ canvas->rotate(rotation);
+ canvas->drawIRect(rect, paint);
+ canvas->restore();
+ if (gr_context_) {
+ gr_context_->flush();
+ glFinish();
+ }
+ wl_surface_damage(child_surface.get(), 0, 0, kSubsurfaceWidth,
+ kSubsurfaceHeight);
+ wl_surface_attach(child_surface.get(), subbuffer->buffer.get(), 0, 0);
+ wl_surface_commit(child_surface.get());
+ }
+
+ // Only generate frames to parent surface for the first 400 frames.
+ if (frame_count < 400) {
+ Buffer* buffer = buffers_.front().get();
+ SkCanvas* canvas = buffer->sk_surface->getCanvas();
+ static const SkColor kColors[] = {SK_ColorRED, SK_ColorBLACK};
+ canvas->clear(kColors[frame_count % arraysize(kColors)]);
+ if (gr_context_) {
+ gr_context_->flush();
+ glFinish();
+ }
+ wl_surface_set_buffer_scale(surface_.get(), scale_);
+ wl_surface_set_buffer_transform(surface_.get(), transform_);
+ wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
+ surface_size_.height());
+ wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
+
+ callback_pending = true;
+ frame_callback.reset(wl_surface_frame(surface_.get()));
+ wl_callback_add_listener(frame_callback.get(), &frame_listener,
+ &callback_pending);
+ }
+
+ // Always animate subsurface position.
+ wl_subsurface_set_position(subsurface.get(), frame_count % 50,
+ frame_count % 50);
+
+ // Only commit changes for the first 600 frames.
+ if (frame_count < 600)
+ wl_surface_commit(surface_.get());
+
+ wl_display_flush(display_.get());
+ ++frame_count;
+ } while (wl_display_dispatch(display_.get()) != -1);
+}
+
+} // namespace clients
+} // namespace wayland
+} // namespace exo
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+ exo::wayland::clients::ClientBase::InitParams params;
+ if (!params.FromCommandLine(*command_line))
+ return 1;
+
+ exo::wayland::clients::SubSurfaceClient client;
+ client.Run(params);
+ return 1;
+}
diff --git a/chromium/components/exo/wayland/clients/yuv.cc b/chromium/components/exo/wayland/clients/yuv.cc
index 2c33be576fd..c13feeba3d7 100644
--- a/chromium/components/exo/wayland/clients/yuv.cc
+++ b/chromium/components/exo/wayland/clients/yuv.cc
@@ -54,14 +54,14 @@ bool YuvClient::WriteSolidColor(gbm_bo* bo, SkColor color) {
(0.439 * SkColorGetR(color)) - (0.368 * SkColorGetG(color)) -
(0.071 * SkColorGetB(color)) + 128};
if (i == 0) {
- for (uint32_t y = 0; y < height_; ++y) {
- for (uint32_t x = 0; x < width_; ++x) {
+ for (int y = 0; y < size_.height(); ++y) {
+ for (int x = 0; x < size_.width(); ++x) {
data[stride * y + x] = yuv[0];
}
}
} else {
- for (uint32_t y = 0; y < height_ / 2; ++y) {
- for (uint32_t x = 0; x < width_ / 2; ++x) {
+ for (int y = 0; y < size_.height() / 2; ++y) {
+ for (int x = 0; x < size_.width() / 2; ++x) {
data[stride * y + x * 2] = yuv[1];
data[stride * y + x * 2 + 1] = yuv[2];
}
@@ -107,7 +107,9 @@ void YuvClient::Run(const ClientBase::InitParams& params) {
return;
wl_surface_set_buffer_scale(surface_.get(), scale_);
- wl_surface_damage(surface_.get(), 0, 0, width_ / scale_, height_ / scale_);
+ wl_surface_set_buffer_transform(surface_.get(), transform_);
+ wl_surface_damage(surface_.get(), 0, 0, surface_size_.width(),
+ surface_size_.height());
wl_surface_attach(surface_.get(), buffer->buffer.get(), 0, 0);
frame_callback.reset(wl_surface_frame(surface_.get()));
@@ -135,6 +137,8 @@ int main(int argc, char* argv[]) {
// TODO(dcastagna): Support other YUV formats.
params.drm_format = DRM_FORMAT_NV12;
+ params.bo_usage =
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR | GBM_BO_USE_TEXTURING;
exo::wayland::clients::YuvClient client;
client.Run(params);
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 9890dd5e6bd..9bbe5203623 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -29,8 +29,10 @@
#include <algorithm>
#include <cstdlib>
#include <iterator>
+#include <map>
#include <string>
#include <utility>
+#include <vector>
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
@@ -38,12 +40,14 @@
#include "ash/shell.h"
#include "base/bind.h"
#include "base/cancelable_callback.h"
+#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/free_deleter.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
@@ -89,6 +93,7 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/wm/core/coordinate_conversion.h"
+#include "ui/wm/core/window_animations.h"
#if defined(USE_OZONE)
#include <drm_fourcc.h>
@@ -110,6 +115,11 @@ DECLARE_UI_CLASS_PROPERTY_TYPE(wl_resource*);
namespace exo {
namespace wayland {
+namespace switches {
+
+constexpr char kForceRemoteShellScaleSwitch[] = "force-remote-shell-scale";
+}
+
namespace {
// We don't send configure immediately after tablet mode switch
@@ -147,6 +157,20 @@ void SetImplementation(wl_resource* resource,
DestroyUserData<T>);
}
+// Returns the scale factor to be used by remote shell clients.
+double GetDefaultDeviceScaleFactor() {
+ // A flag used by VM to emulate a device scale for a partiular board.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kForceRemoteShellScaleSwitch)) {
+ std::string value = command_line->GetSwitchValueASCII(
+ switches::kForceRemoteShellScaleSwitch);
+ double scale = 1.0;
+ if (base::StringToDouble(value, &scale))
+ return std::max(1.0, scale);
+ }
+ return WMHelper::GetInstance()->GetDefaultDeviceScaleFactor();
+}
+
// Convert a timestamp to a time value that can be used when interfacing
// with wayland. Note that we cast a int64_t value to uint32_t which can
// potentially overflow.
@@ -333,8 +357,36 @@ void surface_commit(wl_client* client, wl_resource* resource) {
void surface_set_buffer_transform(wl_client* client,
wl_resource* resource,
- int transform) {
- NOTIMPLEMENTED();
+ int32_t transform) {
+ Transform buffer_transform;
+ switch (transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ buffer_transform = Transform::NORMAL;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ buffer_transform = Transform::ROTATE_90;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ buffer_transform = Transform::ROTATE_180;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ buffer_transform = Transform::ROTATE_270;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ NOTIMPLEMENTED();
+ return;
+ default:
+ wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM,
+ "buffer transform must be one of the values from "
+ "the wl_output.transform enum ('%d' specified)",
+ transform);
+ return;
+ }
+
+ GetUserDataAs<Surface>(resource)->SetBufferTransform(buffer_transform);
}
void surface_set_buffer_scale(wl_client* client,
@@ -1223,16 +1275,21 @@ void bind_shell(wl_client* client, void* data, uint32_t version, uint32_t id) {
////////////////////////////////////////////////////////////////////////////////
// wl_output_interface:
+// Returns the transform that a compositor will apply to a surface to
+// compensate for the rotation of an output device.
wl_output_transform OutputTransform(display::Display::Rotation rotation) {
+ // Note: |rotation| describes the counter clockwise rotation that a
+ // display's output is currently adjusted for, which is the inverse
+ // of what we need to return.
switch (rotation) {
case display::Display::ROTATE_0:
return WL_OUTPUT_TRANSFORM_NORMAL;
case display::Display::ROTATE_90:
- return WL_OUTPUT_TRANSFORM_90;
+ return WL_OUTPUT_TRANSFORM_270;
case display::Display::ROTATE_180:
return WL_OUTPUT_TRANSFORM_180;
case display::Display::ROTATE_270:
- return WL_OUTPUT_TRANSFORM_270;
+ return WL_OUTPUT_TRANSFORM_90;
}
NOTREACHED();
return WL_OUTPUT_TRANSFORM_NORMAL;
@@ -1240,7 +1297,7 @@ wl_output_transform OutputTransform(display::Display::Rotation rotation) {
class WaylandPrimaryDisplayObserver : public display::DisplayObserver {
public:
- WaylandPrimaryDisplayObserver(wl_resource* output_resource)
+ explicit WaylandPrimaryDisplayObserver(wl_resource* output_resource)
: output_resource_(output_resource) {
display::Screen::GetScreen()->AddObserver(this);
SendDisplayMetrics();
@@ -2182,8 +2239,12 @@ void remote_surface_set_window_type(wl_client* client,
uint32_t type) {
if (type == ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_SYSTEM_UI) {
auto* widget = GetUserDataAs<ShellSurface>(resource)->GetWidget();
- if (widget)
+ if (widget) {
widget->GetNativeWindow()->SetProperty(ash::kShowInOverviewKey, false);
+
+ wm::SetWindowVisibilityAnimationType(
+ widget->GetNativeWindow(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+ }
}
}
@@ -2247,6 +2308,16 @@ class WaylandRemoteShell : public WMHelper::TabletModeObserver,
? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
: ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
+ if (wl_resource_get_version(remote_shell_resource_) >= 8) {
+ double scale_factor = GetDefaultDeviceScaleFactor();
+ // Send using 16.16 fixed point.
+ const int kDecimalBits = 24;
+ int32_t fixed_scale =
+ static_cast<int32_t>(scale_factor * (1 << kDecimalBits));
+ zcr_remote_shell_v1_send_default_device_scale_factor(
+ remote_shell_resource_, fixed_scale);
+ }
+
SendDisplayMetrics();
SendActivated(helper->GetActiveWindow(), nullptr);
}
@@ -2261,9 +2332,12 @@ class WaylandRemoteShell : public WMHelper::TabletModeObserver,
return wl_resource_get_version(remote_shell_resource_) >= 5;
}
- std::unique_ptr<ShellSurface> CreateShellSurface(Surface* surface,
- int container) {
- return display_->CreateRemoteShellSurface(surface, container);
+ std::unique_ptr<ShellSurface> CreateShellSurface(
+ Surface* surface,
+ int container,
+ double default_device_scale_factor) {
+ return display_->CreateRemoteShellSurface(surface, container,
+ default_device_scale_factor);
}
std::unique_ptr<NotificationSurface> CreateNotificationSurface(
@@ -2325,6 +2399,22 @@ class WaylandRemoteShell : public WMHelper::TabletModeObserver,
base::TimeDelta::FromMilliseconds(delay_ms));
}
+ // Returns the transform that a display's output is currently adjusted for.
+ wl_output_transform DisplayTransform(display::Display::Rotation rotation) {
+ switch (rotation) {
+ case display::Display::ROTATE_0:
+ return WL_OUTPUT_TRANSFORM_NORMAL;
+ case display::Display::ROTATE_90:
+ return WL_OUTPUT_TRANSFORM_90;
+ case display::Display::ROTATE_180:
+ return WL_OUTPUT_TRANSFORM_180;
+ case display::Display::ROTATE_270:
+ return WL_OUTPUT_TRANSFORM_270;
+ }
+ NOTREACHED();
+ return WL_OUTPUT_TRANSFORM_NORMAL;
+ }
+
void SendDisplayMetrics() {
if (!needs_send_display_metrics_)
return;
@@ -2342,14 +2432,12 @@ class WaylandRemoteShell : public WMHelper::TabletModeObserver,
.device_scale_factor();
zcr_remote_shell_v1_send_workspace(
- remote_shell_resource_,
- static_cast<uint32_t>(display.id() >> 32),
- static_cast<uint32_t>(display.id()),
- bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- insets.left(), insets.top(), insets.right(), insets.bottom(),
- OutputTransform(display.rotation()),
- wl_fixed_from_double(device_scale_factor),
- display.IsInternal());
+ remote_shell_resource_, static_cast<uint32_t>(display.id() >> 32),
+ static_cast<uint32_t>(display.id()), bounds.x(), bounds.y(),
+ bounds.width(), bounds.height(), insets.left(), insets.top(),
+ insets.right(), insets.bottom(),
+ DisplayTransform(display.rotation()),
+ wl_fixed_from_double(device_scale_factor), display.IsInternal());
}
zcr_remote_shell_v1_send_configure(remote_shell_resource_, layout_mode_);
@@ -2359,10 +2447,9 @@ class WaylandRemoteShell : public WMHelper::TabletModeObserver,
const gfx::Insets& insets = primary_display.GetWorkAreaInsets();
zcr_remote_shell_v1_send_configuration_changed(
- remote_shell_resource_,
- primary_display.size().width(),
+ remote_shell_resource_, primary_display.size().width(),
primary_display.size().height(),
- OutputTransform(primary_display.rotation()),
+ DisplayTransform(primary_display.rotation()),
wl_fixed_from_double(primary_display.device_scale_factor()),
insets.left(), insets.top(), insets.right(), insets.bottom(),
layout_mode_);
@@ -2495,8 +2582,13 @@ void remote_shell_get_remote_surface(wl_client* client,
wl_resource* surface,
uint32_t container) {
WaylandRemoteShell* shell = GetUserDataAs<WaylandRemoteShell>(resource);
+ double default_scale_factor = wl_resource_get_version(resource) >= 8
+ ? GetDefaultDeviceScaleFactor()
+ : 1.0;
+
std::unique_ptr<ShellSurface> shell_surface = shell->CreateShellSurface(
- GetUserDataAs<Surface>(surface), RemoteSurfaceContainer(container));
+ GetUserDataAs<Surface>(surface), RemoteSurfaceContainer(container),
+ default_scale_factor);
if (!shell_surface) {
wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
"surface has already been assigned a role");
@@ -2556,7 +2648,7 @@ const struct zcr_remote_shell_v1_interface remote_shell_implementation = {
remote_shell_destroy, remote_shell_get_remote_surface,
remote_shell_get_notification_surface};
-const uint32_t remote_shell_version = 7;
+const uint32_t remote_shell_version = 8;
void bind_remote_shell(wl_client* client,
void* data,
@@ -3078,7 +3170,7 @@ const struct wl_pointer_interface pointer_implementation = {pointer_set_cursor,
class WaylandKeyboardDelegate
: public KeyboardDelegate,
public KeyboardObserver
-#if defined(USE_OZONE) && defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
,
public chromeos::input_method::ImeKeyboard::Observer
#endif
@@ -3087,7 +3179,7 @@ class WaylandKeyboardDelegate
explicit WaylandKeyboardDelegate(wl_resource* keyboard_resource)
: keyboard_resource_(keyboard_resource),
xkb_context_(xkb_context_new(XKB_CONTEXT_NO_FLAGS)) {
-#if defined(USE_OZONE) && defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
chromeos::input_method::ImeKeyboard* keyboard =
chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
if (keyboard) {
@@ -3098,7 +3190,7 @@ class WaylandKeyboardDelegate
SendLayout(nullptr);
#endif
}
-#if defined(USE_OZONE) && defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
~WaylandKeyboardDelegate() override {
chromeos::input_method::ImeKeyboard* keyboard =
chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
@@ -3164,7 +3256,7 @@ class WaylandKeyboardDelegate
wl_client_flush(client());
}
-#if defined(USE_OZONE) && defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
// Overridden from input_method::ImeKeyboard::Observer:
void OnCapsLockChanged(bool enabled) override {}
void OnLayoutChanging(const std::string& layout_name) override {
@@ -3209,8 +3301,7 @@ class WaylandKeyboardDelegate
return xkb_modifiers;
}
-
-#if defined(USE_OZONE) && defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS)
// Send the named keyboard layout to the client.
void SendNamedLayout(const std::string& layout_name) {
std::string layout_id, layout_variant;
@@ -4332,7 +4423,8 @@ void bind_stylus_tools(wl_client* client,
class WaylandExtendedKeyboardImpl : public KeyboardObserver {
public:
- WaylandExtendedKeyboardImpl(Keyboard* keyboard) : keyboard_(keyboard) {
+ explicit WaylandExtendedKeyboardImpl(Keyboard* keyboard)
+ : keyboard_(keyboard) {
keyboard_->AddObserver(this);
keyboard_->SetNeedKeyboardKeyAcks(true);
}
diff --git a/chromium/components/exo/wm_helper.h b/chromium/components/exo/wm_helper.h
index 8a8332d0833..69d72cf9342 100644
--- a/chromium/components/exo/wm_helper.h
+++ b/chromium/components/exo/wm_helper.h
@@ -5,8 +5,6 @@
#ifndef COMPONENTS_EXO_WM_HELPER_H_
#define COMPONENTS_EXO_WM_HELPER_H_
-#include <memory>
-
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/aura/client/drag_drop_delegate.h"
@@ -133,6 +131,7 @@ class WMHelper : public aura::client::DragDropDelegate {
virtual void AddPostTargetHandler(ui::EventHandler* handler) = 0;
virtual void RemovePostTargetHandler(ui::EventHandler* handler) = 0;
virtual bool IsTabletModeWindowManagerEnabled() const = 0;
+ virtual double GetDefaultDeviceScaleFactor() const = 0;
// Overridden from aura::client::DragDropDelegate:
void OnDragEntered(const ui::DropTargetEvent& event) override;
diff --git a/chromium/components/exo/wm_helper_ash.cc b/chromium/components/exo/wm_helper_ash.cc
index 1d4caa1bc68..3a6cd897df4 100644
--- a/chromium/components/exo/wm_helper_ash.cc
+++ b/chromium/components/exo/wm_helper_ash.cc
@@ -112,6 +112,26 @@ bool WMHelperAsh::IsTabletModeWindowManagerEnabled() const {
->IsTabletModeWindowManagerEnabled();
}
+double WMHelperAsh::GetDefaultDeviceScaleFactor() const {
+ if (!display::Display::HasInternalDisplay())
+ return 1.0;
+
+ if (display::Display::HasForceDeviceScaleFactor())
+ return display::Display::GetForcedDeviceScaleFactor();
+
+ display::DisplayManager* display_manager =
+ ash::Shell::Get()->display_manager();
+ const display::ManagedDisplayInfo& display_info =
+ display_manager->GetDisplayInfo(display::Display::InternalDisplayId());
+ for (auto& mode : display_info.display_modes()) {
+ if (mode->is_default())
+ return mode->device_scale_factor();
+ }
+
+ NOTREACHED();
+ return 1.0f;
+}
+
void WMHelperAsh::OnWindowActivated(
wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
diff --git a/chromium/components/exo/wm_helper_ash.h b/chromium/components/exo/wm_helper_ash.h
index f557484a836..4a951b7f143 100644
--- a/chromium/components/exo/wm_helper_ash.h
+++ b/chromium/components/exo/wm_helper_ash.h
@@ -42,6 +42,7 @@ class WMHelperAsh : public WMHelper,
void AddPostTargetHandler(ui::EventHandler* handler) override;
void RemovePostTargetHandler(ui::EventHandler* handler) override;
bool IsTabletModeWindowManagerEnabled() const override;
+ double GetDefaultDeviceScaleFactor() const override;
// Overridden from wm::ActivationChangeObserver:
void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason,
diff --git a/chromium/components/exo/wm_helper_mus.cc b/chromium/components/exo/wm_helper_mus.cc
index 8f8e8c2edeb..678e2a81298 100644
--- a/chromium/components/exo/wm_helper_mus.cc
+++ b/chromium/components/exo/wm_helper_mus.cc
@@ -95,6 +95,11 @@ bool WMHelperMus::IsTabletModeWindowManagerEnabled() const {
return false;
}
+double WMHelperMus::GetDefaultDeviceScaleFactor() const {
+ NOTIMPLEMENTED();
+ return 1.0;
+}
+
void WMHelperMus::OnActiveFocusClientChanged(
aura::client::FocusClient* focus_client,
aura::Window* focus_client_root) {
diff --git a/chromium/components/exo/wm_helper_mus.h b/chromium/components/exo/wm_helper_mus.h
index 820db7a929c..f883c12c0e8 100644
--- a/chromium/components/exo/wm_helper_mus.h
+++ b/chromium/components/exo/wm_helper_mus.h
@@ -41,6 +41,7 @@ class WMHelperMus : public WMHelper,
void AddPostTargetHandler(ui::EventHandler* handler) override;
void RemovePostTargetHandler(ui::EventHandler* handler) override;
bool IsTabletModeWindowManagerEnabled() const override;
+ double GetDefaultDeviceScaleFactor() const override;
// Overridden from aura::FocusSynchronizerObserver:
void OnActiveFocusClientChanged(aura::client::FocusClient* focus_client,
diff --git a/chromium/components/favicon/content/content_favicon_driver.cc b/chromium/components/favicon/content/content_favicon_driver.cc
index 09b45ef2953..97d3501077e 100644
--- a/chromium/components/favicon/content/content_favicon_driver.cc
+++ b/chromium/components/favicon/content/content_favicon_driver.cc
@@ -244,7 +244,7 @@ void ContentFaviconDriver::DidFinishNavigation(
bypass_cache_page_url_ = GURL();
// Get the favicon, either from history or request it from the net.
- FetchFavicon(url);
+ FetchFavicon(url, navigation_handle->IsSameDocument());
}
} // namespace favicon
diff --git a/chromium/components/favicon/core/favicon_driver.h b/chromium/components/favicon/core/favicon_driver.h
index 55c05c091f4..b5856a2f70d 100644
--- a/chromium/components/favicon/core/favicon_driver.h
+++ b/chromium/components/favicon/core/favicon_driver.h
@@ -28,8 +28,10 @@ class FaviconDriver {
void AddObserver(FaviconDriverObserver* observer);
void RemoveObserver(FaviconDriverObserver* observer);
- // Initiates loading the favicon for the specified url.
- virtual void FetchFavicon(const GURL& url) = 0;
+ // Initiates loading the favicon for the specified url. |is_same_document|
+ // is true for cases where this page URL follows a navigation within the same
+ // document (e.g. fragment navigation).
+ virtual void FetchFavicon(const GURL& page_url, bool is_same_document) = 0;
// Returns the favicon for this tab, or IDR_DEFAULT_FAVICON if the tab does
// not have a favicon. The default implementation uses the current navigation
diff --git a/chromium/components/favicon/core/favicon_driver_impl.cc b/chromium/components/favicon/core/favicon_driver_impl.cc
index 891772eaab9..6dd1a7a3126 100644
--- a/chromium/components/favicon/core/favicon_driver_impl.cc
+++ b/chromium/components/favicon/core/favicon_driver_impl.cc
@@ -70,9 +70,10 @@ FaviconDriverImpl::FaviconDriverImpl(FaviconService* favicon_service,
FaviconDriverImpl::~FaviconDriverImpl() {
}
-void FaviconDriverImpl::FetchFavicon(const GURL& url) {
+void FaviconDriverImpl::FetchFavicon(const GURL& page_url,
+ bool is_same_document) {
for (const std::unique_ptr<FaviconHandler>& handler : handlers_)
- handler->FetchFavicon(url);
+ handler->FetchFavicon(page_url, is_same_document);
}
bool FaviconDriverImpl::IsBookmarked(const GURL& url) {
diff --git a/chromium/components/favicon/core/favicon_driver_impl.h b/chromium/components/favicon/core/favicon_driver_impl.h
index a64a9f313f2..53619f1f0bb 100644
--- a/chromium/components/favicon/core/favicon_driver_impl.h
+++ b/chromium/components/favicon/core/favicon_driver_impl.h
@@ -38,7 +38,7 @@ class FaviconDriverImpl : public FaviconDriver,
public FaviconHandler::Delegate {
public:
// FaviconDriver implementation.
- void FetchFavicon(const GURL& url) override;
+ void FetchFavicon(const GURL& page_url, bool is_same_document) override;
// FaviconHandler::Delegate implementation.
bool IsBookmarked(const GURL& url) override;
diff --git a/chromium/components/favicon/core/favicon_handler.cc b/chromium/components/favicon/core/favicon_handler.cc
index 52b7f267cdd..42b17daa027 100644
--- a/chromium/components/favicon/core/favicon_handler.cc
+++ b/chromium/components/favicon/core/favicon_handler.cc
@@ -189,6 +189,7 @@ FaviconHandler::FaviconHandler(
download_largest_icon_(
handler_type == FaviconDriverObserver::NON_TOUCH_LARGEST ||
handler_type == FaviconDriverObserver::TOUCH_LARGEST),
+ candidates_received_(false),
notification_icon_type_(favicon_base::INVALID_ICON),
service_(service),
delegate_(delegate),
@@ -214,17 +215,27 @@ int FaviconHandler::GetIconTypesFromHandlerType(
return 0;
}
-void FaviconHandler::FetchFavicon(const GURL& url) {
+void FaviconHandler::FetchFavicon(const GURL& page_url, bool is_same_document) {
cancelable_task_tracker_for_page_url_.TryCancelAll();
cancelable_task_tracker_for_candidates_.TryCancelAll();
- url_ = url;
+ // We generally clear |page_urls_| and start clean unless there are obvious
+ // reasons to think URLs share favicons: the navigation must be within the
+ // same document (e.g. fragment navigation) AND it happened so early that no
+ // candidates were received for the previous URL(s) (e.g. redirect-like
+ // history.replaceState() during page load).
+ if (!is_same_document || candidates_received_) {
+ page_urls_.clear();
+ }
+ page_urls_.insert(page_url);
+ last_page_url_ = page_url;
initial_history_result_expired_or_incomplete_ = false;
redownload_icons_ = false;
got_favicon_from_history_ = false;
manifest_download_request_.Cancel();
image_download_request_.Cancel();
+ candidates_received_ = false;
manifest_url_ = GURL();
non_manifest_original_candidates_.clear();
candidates_.clear();
@@ -236,9 +247,12 @@ void FaviconHandler::FetchFavicon(const GURL& url) {
// Request the favicon from the history service. In parallel to this the
// renderer is going to notify us (well WebContents) when the favicon url is
- // available.
+ // available. We use |last_page_url_| specifically (regardless of other
+ // possible values in |page_urls_|) because we want to use the most
+ // up-to-date / latest URL for DB lookups, which is the page URL for which
+ // we get <link rel="icon"> candidates (FaviconHandler::OnUpdateCandidates()).
service_->GetFaviconForPageURL(
- url_, icon_types_, preferred_icon_size(),
+ last_page_url_, icon_types_, preferred_icon_size(),
base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
base::Unretained(this)),
&cancelable_task_tracker_for_page_url_);
@@ -272,8 +286,13 @@ bool FaviconHandler::UpdateFaviconCandidate(
void FaviconHandler::SetFavicon(const GURL& icon_url,
const gfx::Image& image,
favicon_base::IconType icon_type) {
- if (ShouldSaveFavicon())
- service_->SetFavicons(url_, icon_url, icon_type, image);
+ // Associate the icon to all URLs in |page_urls_|, which contains page URLs
+ // within the same site/document that have been considered to reliably share
+ // the same icon candidates.
+ for (const GURL& page_url : page_urls_) {
+ if (ShouldSaveFavicon(page_url))
+ service_->SetFavicons(page_url, icon_url, icon_type, image);
+ }
NotifyFaviconUpdated(icon_url, icon_type, image);
}
@@ -304,7 +323,7 @@ void FaviconHandler::NotifyFaviconUpdated(const GURL& icon_url,
gfx::Image image_with_adjusted_colorspace = image;
favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace);
- delegate_->OnFaviconUpdated(url_, handler_type_, icon_url,
+ delegate_->OnFaviconUpdated(last_page_url_, handler_type_, icon_url,
icon_url != notification_icon_url_,
image_with_adjusted_colorspace);
@@ -316,7 +335,7 @@ void FaviconHandler::OnUpdateCandidates(
const GURL& page_url,
const std::vector<FaviconURL>& candidates,
const GURL& manifest_url) {
- if (page_url != url_)
+ if (last_page_url_ != page_url)
return;
bool manifests_feature_enabled =
@@ -325,13 +344,14 @@ void FaviconHandler::OnUpdateCandidates(
// |candidates| or |manifest_url| could have been modified via Javascript. If
// neither changed, ignore the call.
if ((!manifests_feature_enabled || manifest_url_ == manifest_url) &&
- non_manifest_original_candidates_.size() == candidates.size() &&
- std::equal(candidates.begin(), candidates.end(),
- non_manifest_original_candidates_.begin(),
- &FaviconURLEquals)) {
+ (non_manifest_original_candidates_.size() == candidates.size() &&
+ std::equal(candidates.begin(), candidates.end(),
+ non_manifest_original_candidates_.begin(),
+ &FaviconURLEquals))) {
return;
}
+ candidates_received_ = true;
non_manifest_original_candidates_ = candidates;
cancelable_task_tracker_for_candidates_.TryCancelAll();
manifest_download_request_.Cancel();
@@ -561,12 +581,12 @@ bool FaviconHandler::HasPendingTasksForTest() {
cancelable_task_tracker_for_candidates_.HasTrackedTasks();
}
-bool FaviconHandler::ShouldSaveFavicon() {
+bool FaviconHandler::ShouldSaveFavicon(const GURL& page_url) const {
if (!delegate_->IsOffTheRecord())
return true;
// Always save favicon if the page is bookmarked.
- return delegate_->IsBookmarked(url_);
+ return delegate_->IsBookmarked(page_url);
}
void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
@@ -587,6 +607,12 @@ void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
// url) we'll fetch later on. This way the user doesn't see a flash of the
// default favicon.
NotifyFaviconUpdated(favicon_bitmap_results);
+
+ // For strict correctness, we should also set the database icon mappings for
+ // other URLs in |page_urls_| (same-document navigations like fragment
+ // navigations) because there is no guarantee that there is a mapping for
+ // the other page URLs (e.g. |last_page_url_| has a mapping because it's
+ // bookmarked but the rest don't).
}
if (current_candidate())
@@ -626,7 +652,7 @@ void FaviconHandler::GetFaviconAndUpdateMappingsUnlessIncognito(
// include the mapping between the page url and the favicon url.
// This is asynchronous. The history service will call back when done.
service_->UpdateFaviconMappingsAndFetch(
- url_, icon_url, icon_type, preferred_icon_size(), callback,
+ page_urls_, icon_url, icon_type, preferred_icon_size(), callback,
&cancelable_task_tracker_for_candidates_);
}
}
diff --git a/chromium/components/favicon/core/favicon_handler.h b/chromium/components/favicon/core/favicon_handler.h
index fce615f2b29..875da2abaf9 100644
--- a/chromium/components/favicon/core/favicon_handler.h
+++ b/chromium/components/favicon/core/favicon_handler.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <set>
#include <vector>
#include "base/callback_forward.h"
@@ -142,8 +143,10 @@ class FaviconHandler {
FaviconDriverObserver::NotificationIconType handler_type);
~FaviconHandler();
- // Initiates loading the favicon for the specified url.
- void FetchFavicon(const GURL& url);
+ // Initiates loading the favicon for the specified url. |is_same_document| is
+ // true for fragment navigations and history pushState/replaceState, see
+ // NavigationHandle::IsSameDocument().
+ void FetchFavicon(const GURL& page_url, bool is_same_document);
// Collects the candidate favicons as listed in the HTML head, as well as
// the WebManifest URL if available (or empty URL otherwise).
@@ -250,7 +253,7 @@ class FaviconHandler {
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& original_bitmap_sizes);
- bool ShouldSaveFavicon();
+ bool ShouldSaveFavicon(const GURL& page_url) const;
// Updates |best_favicon_| and returns true if it was considered a satisfying
// image (e.g. exact size match).
@@ -296,8 +299,11 @@ class FaviconHandler {
const FaviconDriverObserver::NotificationIconType handler_type_;
- // URL of the page we're requesting the favicon for.
- GURL url_;
+ // URL of the page(s) we're requesting the favicon for. They can be multiple
+ // in case of in-page navigations (e.g. fragment navigations).
+ std::set<GURL> page_urls_;
+ // The last page URL reported via FetchFavicon().
+ GURL last_page_url_;
// Whether we got data back for the initial request to the FaviconService.
bool got_favicon_from_history_;
@@ -328,6 +334,10 @@ class FaviconHandler {
// Whether the largest icon should be downloaded.
const bool download_largest_icon_;
+ // Whether candidates have been received (OnUpdateCandidates() has been
+ // called, regardless of whether the provided list was empty).
+ bool candidates_received_;
+
// The manifest URL from the renderer (or empty URL if none).
GURL manifest_url_;
diff --git a/chromium/components/favicon/core/favicon_handler_unittest.cc b/chromium/components/favicon/core/favicon_handler_unittest.cc
index af8a73cb194..68c104599dd 100644
--- a/chromium/components/favicon/core/favicon_handler_unittest.cc
+++ b/chromium/components/favicon/core/favicon_handler_unittest.cc
@@ -376,7 +376,7 @@ class FakeFaviconService {
}
base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
int desired_size_in_dip,
@@ -506,11 +506,11 @@ class FaviconHandlerTest : public testing::Test {
// Returns the handler in case tests want to exercise further steps.
std::unique_ptr<FaviconHandler> RunHandlerWithCandidates(
FaviconDriverObserver::NotificationIconType handler_type,
- const std::vector<favicon::FaviconURL>& candidates,
+ const std::vector<FaviconURL>& candidates,
const GURL& manifest_url = GURL()) {
auto handler = base::MakeUnique<FaviconHandler>(&favicon_service_,
&delegate_, handler_type);
- handler->FetchFavicon(kPageURL);
+ handler->FetchFavicon(kPageURL, /*is_same_document=*/false);
// The first RunUntilIdle() causes the FaviconService lookups be faster than
// OnUpdateCandidates(), which is the most likely scenario.
base::RunLoop().RunUntilIdle();
@@ -561,15 +561,42 @@ TEST_F(FaviconHandlerTest, GetFaviconFromHistory) {
}
// Test that UpdateFaviconsAndFetch() is called with the appropriate parameters
-// when there is data in the database for neither the page URL nor the icon URL.
+// when there is no data in the database for the page URL.
TEST_F(FaviconHandlerTest, UpdateFaviconMappingsAndFetch) {
EXPECT_CALL(favicon_service_,
- UpdateFaviconMappingsAndFetch(kPageURL, kIconURL16x16, FAVICON,
+ UpdateFaviconMappingsAndFetch(std::set<GURL>{kPageURL},
+ kIconURL16x16, FAVICON,
/*desired_size_in_dip=*/16, _, _));
RunHandlerWithSimpleFaviconCandidates({kIconURL16x16});
}
+// Test that UpdateFaviconsAndFetch() is called with the appropriate parameters
+// when there is no data in the database for the page URL, for the case where
+// multiple page URLs exist due to a quick in-same-document navigation (e.g.
+// fragment navigation).
+TEST_F(FaviconHandlerTest, UpdateFaviconMappingsAndFetchWithMultipleURLs) {
+ const GURL kDifferentPageURL = GURL("http://www.google.com/other");
+
+ EXPECT_CALL(favicon_service_, UpdateFaviconMappingsAndFetch(
+ std::set<GURL>{kPageURL, kDifferentPageURL},
+ kIconURL16x16, _, _, _, _));
+
+ std::unique_ptr<FaviconHandler> handler = base::MakeUnique<FaviconHandler>(
+ &favicon_service_, &delegate_, FaviconDriverObserver::NON_TOUCH_16_DIP);
+ handler->FetchFavicon(kPageURL, /*is_same_document=*/false);
+ base::RunLoop().RunUntilIdle();
+ // Load a new URL (same document) without feeding any candidates for the first
+ // URL.
+ handler->FetchFavicon(kDifferentPageURL, /*is_same_document=*/true);
+ base::RunLoop().RunUntilIdle();
+ // Feed in candidates for the second URL.
+ handler->OnUpdateCandidates(kDifferentPageURL,
+ {FaviconURL(kIconURL16x16, FAVICON, kEmptySizes)},
+ /*manifest_url=*/GURL());
+ base::RunLoop().RunUntilIdle();
+}
+
// Test that the FaviconHandler process finishes when:
// - There is data in the database for neither the page URL nor the icon URL.
// AND
@@ -584,7 +611,7 @@ TEST_F(FaviconHandlerTest, DownloadUnknownFaviconIfCandidatesSlower) {
FaviconHandler handler(&favicon_service_, &delegate_,
FaviconDriverObserver::NON_TOUCH_16_DIP);
- handler.FetchFavicon(kPageURL);
+ handler.FetchFavicon(kPageURL, /*is_same_document=*/false);
base::RunLoop().RunUntilIdle();
// Database lookup for |kPageURL| is ongoing.
ASSERT_TRUE(favicon_service_.fake()->HasPendingManualCallback());
@@ -621,7 +648,7 @@ TEST_F(FaviconHandlerTest, DownloadUnknownFaviconIfCandidatesFaster) {
FaviconHandler handler(&favicon_service_, &delegate_,
FaviconDriverObserver::NON_TOUCH_16_DIP);
- handler.FetchFavicon(kPageURL);
+ handler.FetchFavicon(kPageURL, /*is_same_document=*/false);
base::RunLoop().RunUntilIdle();
// Feed in favicons before completing the database lookup.
handler.OnUpdateCandidates(
@@ -1462,6 +1489,61 @@ TEST_F(FaviconHandlerTest, TestRecordSkippedDownloadForKnownFailingUrl) {
/*expected_count=*/1)));
}
+// Test that if a page URL is followed by another page URL which is not
+// considered the same document, favicon candidates listed in the second page
+// get associated to that second page only.
+TEST_F(FaviconHandlerTest, SetFaviconsForLastPageUrlOnly) {
+ const GURL kDifferentPageURL = GURL("http://www.google.com/other");
+
+ EXPECT_CALL(favicon_service_,
+ SetFavicons(kDifferentPageURL, kIconURL12x12, _, _));
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(kDifferentPageURL,
+ FaviconDriverObserver::NON_TOUCH_16_DIP,
+ kIconURL12x12, _, _));
+
+ std::unique_ptr<FaviconHandler> handler = base::MakeUnique<FaviconHandler>(
+ &favicon_service_, &delegate_, FaviconDriverObserver::NON_TOUCH_16_DIP);
+ handler->FetchFavicon(kPageURL, /*is_same_document=*/false);
+ base::RunLoop().RunUntilIdle();
+ // Load a new URL (different document) without feeding any candidates for the
+ // first URL.
+ handler->FetchFavicon(kDifferentPageURL, /*is_same_document=*/false);
+ base::RunLoop().RunUntilIdle();
+ handler->OnUpdateCandidates(kDifferentPageURL,
+ {FaviconURL(kIconURL12x12, FAVICON, kEmptySizes)},
+ /*manifest_url=*/GURL());
+ base::RunLoop().RunUntilIdle();
+}
+
+// Test that if a page URL is followed by another page URL which is considered
+// the same document (e.g. fragment navigation), favicon candidates listed in
+// the second page get associated to both page URLs.
+TEST_F(FaviconHandlerTest, SetFaviconsForMultipleUrlsWithinDocument) {
+ const GURL kDifferentPageURL = GURL("http://www.google.com/other");
+
+ EXPECT_CALL(favicon_service_, SetFavicons(kPageURL, kIconURL12x12, _, _));
+ EXPECT_CALL(favicon_service_,
+ SetFavicons(kDifferentPageURL, kIconURL12x12, _, _));
+ EXPECT_CALL(delegate_,
+ OnFaviconUpdated(kDifferentPageURL,
+ FaviconDriverObserver::NON_TOUCH_16_DIP,
+ kIconURL12x12, _, _));
+
+ std::unique_ptr<FaviconHandler> handler = base::MakeUnique<FaviconHandler>(
+ &favicon_service_, &delegate_, FaviconDriverObserver::NON_TOUCH_16_DIP);
+ handler->FetchFavicon(kPageURL, /*is_same_document=*/false);
+ base::RunLoop().RunUntilIdle();
+ // Load a new URL (same document) without feeding any candidates for the first
+ // URL.
+ handler->FetchFavicon(kDifferentPageURL, /*is_same_document=*/true);
+ base::RunLoop().RunUntilIdle();
+ handler->OnUpdateCandidates(kDifferentPageURL,
+ {FaviconURL(kIconURL12x12, FAVICON, kEmptySizes)},
+ /*manifest_url=*/GURL());
+ base::RunLoop().RunUntilIdle();
+}
+
// Manifests are currently enabled by default. Leaving this fixture for
// logical grouping and blame layer.
class FaviconHandlerManifestsEnabledTest : public FaviconHandlerTest {
@@ -1602,8 +1684,7 @@ TEST_F(FaviconHandlerManifestsEnabledTest, Prefer192x192IconFromManifest) {
delegate_.fake_manifest_downloader().Add(kManifestURL, kManifestIcons);
- RunHandlerWithCandidates(FaviconDriverObserver::TOUCH_LARGEST,
- std::vector<favicon::FaviconURL>(), kManifestURL);
+ RunHandlerWithSimpleTouchIconCandidates(URLVector(), kManifestURL);
EXPECT_THAT(delegate_.downloads(),
ElementsAre(kManifestURL, kIconURL192x192));
diff --git a/chromium/components/favicon/core/favicon_service.h b/chromium/components/favicon/core/favicon_service.h
index 60552b13691..1958ce4f8ef 100644
--- a/chromium/components/favicon/core/favicon_service.h
+++ b/chromium/components/favicon/core/favicon_service.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <set>
#include <vector>
#include "base/callback.h"
@@ -113,14 +114,14 @@ class FaviconService : public KeyedService {
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) = 0;
- // Maps |page_url| to the favicon at |icon_url| if there is an entry in the
+ // Maps |page_urls| to the favicon at |icon_url| if there is an entry in the
// database for |icon_url| and |icon_type|. This occurs when there is a
// mapping from a different page URL to |icon_url|. The favicon bitmaps whose
// edge sizes most closely match |desired_size_in_dip| from the favicons which
- // were just mapped to |page_url| are returned. If |desired_size_in_dip| has a
- // '0' entry, the largest favicon bitmap is returned.
+ // were just mapped to |page_urls| are returned. If |desired_size_in_dip| has
+ // a '0' entry, the largest favicon bitmap is returned.
virtual base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
int desired_size_in_dip,
diff --git a/chromium/components/favicon/core/favicon_service_impl.cc b/chromium/components/favicon/core/favicon_service_impl.cc
index e267981e81e..aed6e95b05d 100644
--- a/chromium/components/favicon/core/favicon_service_impl.cc
+++ b/chromium/components/favicon/core/favicon_service_impl.cc
@@ -175,14 +175,14 @@ base::CancelableTaskTracker::TaskId FaviconServiceImpl::GetFaviconForPageURL(
base::CancelableTaskTracker::TaskId
FaviconServiceImpl::UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
int desired_size_in_dip,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
return history_service_->UpdateFaviconMappingsAndFetch(
- page_url, icon_url, icon_type,
+ page_urls, icon_url, icon_type,
GetPixelSizesForFaviconScales(desired_size_in_dip), callback, tracker);
}
diff --git a/chromium/components/favicon/core/favicon_service_impl.h b/chromium/components/favicon/core/favicon_service_impl.h
index 7ad2d0ac53e..314708deda5 100644
--- a/chromium/components/favicon/core/favicon_service_impl.h
+++ b/chromium/components/favicon/core/favicon_service_impl.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <set>
#include <vector>
#include "base/callback.h"
@@ -80,7 +81,7 @@ class FaviconServiceImpl : public FaviconService {
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) override;
base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
int desired_size_in_dip,
diff --git a/chromium/components/favicon/core/large_icon_service.cc b/chromium/components/favicon/core/large_icon_service.cc
index 72886e7e838..893b2f05507 100644
--- a/chromium/components/favicon/core/large_icon_service.cc
+++ b/chromium/components/favicon/core/large_icon_service.cc
@@ -17,6 +17,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
@@ -182,7 +183,6 @@ class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
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);
// Must run on the owner (UI) thread in production.
@@ -221,13 +221,14 @@ LargeIconWorker::LargeIconWorker(
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)
: min_source_size_in_pixel_(min_source_size_in_pixel),
desired_size_in_pixel_(desired_size_in_pixel),
raw_bitmap_callback_(raw_bitmap_callback),
image_callback_(image_callback),
- background_task_runner_(background_task_runner),
+ background_task_runner_(base::CreateTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
tracker_(tracker),
fallback_icon_style_(
base::MakeUnique<favicon_base::FallbackIconStyle>()) {}
@@ -326,10 +327,8 @@ void OnFetchIconFromGoogleServerComplete(
LargeIconService::LargeIconService(
FaviconService* favicon_service,
- const scoped_refptr<base::TaskRunner>& background_task_runner,
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher)
: favicon_service_(favicon_service),
- background_task_runner_(background_task_runner),
image_fetcher_(std::move(image_fetcher)) {
large_icon_types_.push_back(favicon_base::IconType::WEB_MANIFEST_ICON);
large_icon_types_.push_back(favicon_base::IconType::FAVICON);
@@ -433,9 +432,9 @@ LargeIconService::GetLargeIconOrFallbackStyleImpl(
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, raw_bitmap_callback,
- image_callback, background_task_runner_, tracker);
+ scoped_refptr<LargeIconWorker> worker =
+ new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel,
+ raw_bitmap_callback, image_callback, tracker);
int max_size_in_pixel =
std::max(desired_size_in_pixel, min_source_size_in_pixel);
diff --git a/chromium/components/favicon/core/large_icon_service.h b/chromium/components/favicon/core/large_icon_service.h
index ec79fd54da1..38245915cd3 100644
--- a/chromium/components/favicon/core/large_icon_service.h
+++ b/chromium/components/favicon/core/large_icon_service.h
@@ -16,10 +16,6 @@
class GURL;
-namespace base {
-class TaskRunner;
-}
-
namespace image_fetcher {
class ImageFetcher;
}
@@ -34,7 +30,6 @@ class LargeIconService : public KeyedService {
public:
LargeIconService(
FaviconService* favicon_service,
- const scoped_refptr<base::TaskRunner>& background_task_runner,
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher);
~LargeIconService() override;
@@ -120,7 +115,6 @@ class LargeIconService : public KeyedService {
base::CancelableTaskTracker* tracker);
FaviconService* favicon_service_;
- scoped_refptr<base::TaskRunner> background_task_runner_;
// 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
diff --git a/chromium/components/favicon/core/large_icon_service_unittest.cc b/chromium/components/favicon/core/large_icon_service_unittest.cc
index 9646cd98ebe..46b1c841732 100644
--- a/chromium/components/favicon/core/large_icon_service_unittest.cc
+++ b/chromium/components/favicon/core/large_icon_service_unittest.cc
@@ -11,11 +11,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/histogram_tester.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_client.h"
#include "components/favicon/core/test/mock_favicon_service.h"
@@ -126,14 +125,12 @@ class LargeIconServiceTest : public testing::Test {
LargeIconServiceTest()
: mock_image_fetcher_(new NiceMock<MockImageFetcher>()),
large_icon_service_(&mock_favicon_service_,
- base::ThreadTaskRunnerHandle::Get(),
base::WrapUnique(mock_image_fetcher_)) {}
~LargeIconServiceTest() override {}
protected:
- base::MessageLoopForIO loop_;
-
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
NiceMock<MockImageFetcher>* mock_image_fetcher_;
testing::NiceMock<MockFaviconService> mock_favicon_service_;
LargeIconService large_icon_service_;
@@ -169,7 +166,7 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServer) {
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
histogram_tester_.ExpectUniqueSample(
"Favicons.LargeIconService.DownloadedSize", 64, /*expected_count=*/1);
}
@@ -207,7 +204,7 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithCustomUrl) {
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) {
@@ -239,7 +236,7 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) {
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
TEST_F(LargeIconServiceTest, ShouldTrimQueryParametersForGoogleServer) {
@@ -264,7 +261,7 @@ TEST_F(LargeIconServiceTest, ShouldTrimQueryParametersForGoogleServer) {
TRAFFIC_ANNOTATION_FOR_TESTS,
favicon_base::GoogleFaviconServerCallback());
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
TEST_F(LargeIconServiceTest, ShouldNotCheckOnPublicUrls) {
@@ -285,7 +282,7 @@ TEST_F(LargeIconServiceTest, ShouldNotCheckOnPublicUrls) {
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_CONNECTION_ERROR));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
TEST_F(LargeIconServiceTest, ShouldNotQueryGoogleServerIfInvalidScheme) {
@@ -305,7 +302,7 @@ TEST_F(LargeIconServiceTest, ShouldNotQueryGoogleServerIfInvalidScheme) {
EXPECT_CALL(
callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::FAILURE_INVALID));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_THAT(histogram_tester_.GetAllSamples(
"Favicons.LargeIconService.DownloadedSize"),
IsEmpty());
@@ -336,7 +333,7 @@ TEST_F(LargeIconServiceTest, ShouldReportUnavailableIfFetchFromServerFails) {
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_CONNECTION_ERROR));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
// Verify that download failure gets recorded.
histogram_tester_.ExpectUniqueSample(
"Favicons.LargeIconService.DownloadedSize", 0, /*expected_count=*/1);
@@ -366,7 +363,7 @@ TEST_F(LargeIconServiceTest, ShouldNotGetFromGoogleServerIfUnavailable) {
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_HTTP_ERROR_CACHED));
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_THAT(histogram_tester_.GetAllSamples(
"Favicons.LargeIconService.DownloadedSize"),
IsEmpty());
@@ -396,7 +393,7 @@ class LargeIconServiceGetterTest : public LargeIconServiceTest,
base::Unretained(this)),
&cancelable_task_tracker_);
}
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
void RawBitmapResultCallback(const favicon_base::LargeIconResult& result) {
diff --git a/chromium/components/favicon/ios/web_favicon_driver.h b/chromium/components/favicon/ios/web_favicon_driver.h
index 5006975b335..8e6abd376d5 100644
--- a/chromium/components/favicon/ios/web_favicon_driver.h
+++ b/chromium/components/favicon/ios/web_favicon_driver.h
@@ -32,7 +32,7 @@ class WebFaviconDriver : public web::WebStateObserver,
bookmarks::BookmarkModel* bookmark_model);
// FaviconDriver implementation.
- void FetchFavicon(const GURL& url) override;
+ void FetchFavicon(const GURL& page_url, bool is_same_document) override;
gfx::Image GetFavicon() const override;
bool FaviconIsValid() const override;
GURL GetActiveURL() override;
diff --git a/chromium/components/favicon/ios/web_favicon_driver.mm b/chromium/components/favicon/ios/web_favicon_driver.mm
index 0025341b757..889d2ed96e4 100644
--- a/chromium/components/favicon/ios/web_favicon_driver.mm
+++ b/chromium/components/favicon/ios/web_favicon_driver.mm
@@ -14,7 +14,6 @@
#include "ios/web/public/navigation_item.h"
#include "ios/web/public/navigation_manager.h"
#include "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
#include "skia/ext/skia_utils_ios.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
@@ -49,9 +48,10 @@ void WebFaviconDriver::CreateForWebState(
history_service, bookmark_model)));
}
-void WebFaviconDriver::FetchFavicon(const GURL& url) {
- fetch_favicon_url_ = url;
- FaviconDriverImpl::FetchFavicon(url);
+void WebFaviconDriver::FetchFavicon(const GURL& page_url,
+ bool is_same_document) {
+ fetch_favicon_url_ = page_url;
+ FaviconDriverImpl::FetchFavicon(page_url, is_same_document);
}
gfx::Image WebFaviconDriver::GetFavicon() const {
@@ -137,8 +137,7 @@ WebFaviconDriver::WebFaviconDriver(web::WebState* web_state,
bookmarks::BookmarkModel* bookmark_model)
: web::WebStateObserver(web_state),
FaviconDriverImpl(favicon_service, history_service, bookmark_model),
- image_fetcher_(web_state->GetBrowserState()->GetRequestContext(),
- web::WebThread::GetBlockingPool()) {}
+ image_fetcher_(web_state->GetBrowserState()->GetRequestContext()) {}
WebFaviconDriver::~WebFaviconDriver() {
}
diff --git a/chromium/components/favicon_base/select_favicon_frames.cc b/chromium/components/favicon_base/select_favicon_frames.cc
index 8bc63e8d0ec..e076dd57263 100644
--- a/chromium/components/favicon_base/select_favicon_frames.cc
+++ b/chromium/components/favicon_base/select_favicon_frames.cc
@@ -9,8 +9,10 @@
#include <limits>
#include <map>
#include <set>
+#include <utility>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "components/favicon_base/favicon_util.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -243,7 +245,7 @@ gfx::ImageSkia CreateFaviconImageSkia(
return gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1.0f));
}
- FaviconImageSource* image_source = new FaviconImageSource;
+ auto image_source = base::MakeUnique<FaviconImageSource>();
for (size_t i = 0; i < results.size(); ++i) {
size_t index = results[i].index;
@@ -253,7 +255,7 @@ gfx::ImageSkia CreateFaviconImageSkia(
desired_sizes[i]),
favicon_scales[i]));
}
- return gfx::ImageSkia(image_source,
+ return gfx::ImageSkia(std::move(image_source),
gfx::Size(desired_size_in_dip, desired_size_in_dip));
}
diff --git a/chromium/components/feature_engagement_tracker/BUILD.gn b/chromium/components/feature_engagement/BUILD.gn
index cb24ce6c0c9..c79a97afc70 100644
--- a/chromium/components/feature_engagement_tracker/BUILD.gn
+++ b/chromium/components/feature_engagement/BUILD.gn
@@ -7,13 +7,13 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-group("feature_engagement_tracker") {
+group("feature_engagement") {
public_deps = [
- "//components/feature_engagement_tracker/public",
+ "//components/feature_engagement/public",
]
deps = [
- "//components/feature_engagement_tracker/internal",
+ "//components/feature_engagement/internal",
]
}
@@ -21,7 +21,7 @@ group("unit_tests") {
testonly = true
deps = [
- "//components/feature_engagement_tracker/internal:unit_tests",
+ "//components/feature_engagement/internal:unit_tests",
]
data_deps = [
@@ -38,10 +38,10 @@ source_set("components_unittests_gtest_filter") {
}
if (is_android) {
- java_group("feature_engagement_tracker_java") {
+ java_group("feature_engagement_java") {
deps = [
- "//components/feature_engagement_tracker/internal:internal_java",
- "//components/feature_engagement_tracker/public:public_java",
+ "//components/feature_engagement/internal:internal_java",
+ "//components/feature_engagement/public:public_java",
]
}
}
diff --git a/chromium/components/feature_engagement_tracker/DEPS b/chromium/components/feature_engagement/DEPS
index 48edfa45a2c..48edfa45a2c 100644
--- a/chromium/components/feature_engagement_tracker/DEPS
+++ b/chromium/components/feature_engagement/DEPS
diff --git a/chromium/components/feature_engagement/OWNERS b/chromium/components/feature_engagement/OWNERS
new file mode 100644
index 00000000000..f3889057fbe
--- /dev/null
+++ b/chromium/components/feature_engagement/OWNERS
@@ -0,0 +1,5 @@
+dtrainor@chromium.org
+nyquist@chromium.org
+
+# COMPONENT: Internals>FeatureEngagement
+
diff --git a/chromium/components/feature_engagement_tracker/README.md b/chromium/components/feature_engagement/README.md
index 9c560d92f0f..f632bc19184 100644
--- a/chromium/components/feature_engagement_tracker/README.md
+++ b/chromium/components/feature_engagement/README.md
@@ -1,6 +1,6 @@
-# Feature Engagement Tracker
+# Feature Engagement
-The Feature Engagement Tracker provides a client-side backend for displaying
+The Feature Engagement component provides a client-side backend for displaying
feature enlightenment or in-product help (IPH) with a clean and easy to use API
to be consumed by the UI frontend. The backend behaves as a black box and takes
input about user behavior. Whenever the frontend gives a trigger signal that
@@ -97,8 +97,8 @@ You need to do the following things to enable your feature, all described in
detail below.
* [Declare your feature](#Declaring-your-feature) and make it available to the
- `FeatureEngagementTracker`.
-* [Start using the `FeatureEngagementTracker` class](#Using-the-FeatureEngagementTracker)
+ `feature_engagement::Tracker`.
+* [Start using the `feature_engagement::Tracker` class](#Using-the-feature_engagement_Tracker)
by notifying about events, and checking whether In-Product Help should be
displayed.
* [Configure UMA](#Configuring-UMA).
@@ -122,40 +122,40 @@ and be on the form:
There are also a few more places where the feature should be added, so overall
you would have to add it to the following places:
-* `//components/feature_engagement_tracker/public/feature_constants.cc`:
+* `//components/feature_engagement/public/feature_constants.cc`:
```c++
const base::Feature kIPHMyFunFeature{"IPH_MyFun",
base::FEATURE_DISABLED_BY_DEFAULT};
```
-* `//components/feature_engagement_tracker/public/feature_constants.h`:
+* `//components/feature_engagement/public/feature_constants.h`:
```c++
extern const base::Feature kIPHMyFunFeature;
```
-* `//components/feature_engagement_tracker/public/feature_list.cc`:
+* `//components/feature_engagement/public/feature_list.cc`:
* Add to `const base::Feature* kAllFeatures[]`.
-* `//components/feature_engagement_tracker/public/feature_list.h`:
+* `//components/feature_engagement/public/feature_list.h`:
* `DEFINE_VARIATION_PARAM(kIPHMyFunFeature, "IPH_MyFun");`
* `VARIATION_ENTRY(kIPHMyFunFeature)`
If the feature will also be used from Java, also add it to:
-`org.chromium.components.feature_engagement_tracker.FeatureConstants` as a
+`org.chromium.components.feature_engagement.FeatureConstants` as a
`String` constant.
-### Using the FeatureEngagementTracker
+### Using the feature_engagement::Tracker
-To retrieve the `FeatureEngagementTracker` you need to use your platform
+To retrieve the `feature_engagement::Tracker` you need to use your platform
specific way for how to retrieve a `KeyedService`. For example for desktop
-platforms and Android, you can use the `FeatureEngagementTrackerFactory` in
-`//chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h`
+platforms and Android, you can use the `feature_engagement::TrackerFactory` in
+`//chrome/browser/feature_engagement/tracker_factory.h`
to retrieve it from the `Profile` or `BrowserContext`:
```c++
-feature_engagement_tracker::FeatureEngagementTracker* tracker =
- FeatureEngagementTrackerFactory::GetForBrowserContext(profile);
+feature_engagement::Tracker* tracker =
+ feature_engagement::TrackerFactory::GetForBrowserContext(profile);
```
That service can be first of all used to notify the backend about events:
@@ -168,20 +168,55 @@ In addition, it can tell you whether it is a good time to trigger the help UI:
```c++
bool trigger_help_ui =
- tracker->ShouldTriggerHelpUI(feature_engagement_tracker::kIPHMyFunFeature);
+ tracker->ShouldTriggerHelpUI(feature_engagement::kIPHMyFunFeature);
if (trigger_help_ui) {
// Show IPH UI.
}
```
-If `FeatureEngagementTracker::ShouldTriggerHelpUI` return `true` you must
+If `feature_engagement::Tracker::ShouldTriggerHelpUI` return `true` you must
display the In-Product Help, as it will be tracked as if you showed it. In
addition you are required to inform when the feature has been dismissed:
```c++
-tracker->Dismissed(feature_engagement_tracker::kIPHMyFunFeature);
+tracker->Dismissed(feature_engagement::kIPHMyFunFeature);
```
+#### Inspecting whether IPH has already been triggered for a feature
+
+Sometimes additional tracking is required to figure out if in-product help for a
+particular feature should be shown, and sometimes this is costly. If the
+in-product help has already been shown for that feature, it might not be
+necessary any more to do the additional tracking of state.
+
+To check if the triggering condition has already been fulfilled (i.e. can not
+currently be triggered again), you can call:
+
+```c++
+// TriggerState is { HAS_BEEN_DISPLAYED, HAS_NOT_BEEN_DISPLAYED, NOT_READY }.
+Tracker::TriggerState trigger_state =
+ GetTriggerState(feature_engagement::kIPHMyFunFeature);
+```
+
+Inspecting this state requires the Tracker to already have been initialized,
+else `NOT_READY` is always returned. See `IsInitialized()` and
+`AddOnInitializedCallback(...)` for how to ensure the call to this is delayed.
+
+##### A note about TriggerState naming
+
+Typically, the `FeatureConfig` (see below) for any particular in-product help
+requires the configuration for `event_trigger` to have a comparator value of
+`==0`, i.e. that it is a requirement that the particular in-product help has
+never been shown within the search window. The values of the `TriggerState` enum
+reflects this typical usage, whereas technically, this is the correct
+interpretation of the states:
+
+* `HAS_BEEN_DISPLAYED`: `event_trigger` condition is NOT met and in-product
+ help will not be displayed if `Tracker` is asked.
+* `HAS_NOT_BEEN_DISPLAYED`: `event_trigger` condition is met and in-product
+ help might be displayed if `Tracker` is asked.
+* `NOT_READY`: `Tracker` not fully initialized yet, so it is unable to
+ inspect the state.
### Configuring UMA
@@ -204,7 +239,7 @@ configuration:
## Demo mode
-The Feature Engagement Tracker supports a special demo mode, which enables a
+The feature_engagement::Tracker supports a special demo mode, which enables a
developer or testers to see how the UI looks like without using Chrome
Variations configuration.
@@ -434,10 +469,10 @@ available. To see if the current checked in code covers your needs, try starting
a debug build of chrome with the following command line arguments:
```bash
---vmodule=feature_engagement_tracker_impl*=2,model_impl*=2,availability_store*=2,chrome_variations_configuration*=3
+--vmodule=tracker_impl*=2,event_model_impl*=2,persistent_availability_store*=2,chrome_variations_configuration*=3
```
-## Development of `//components/feature_engagement_tracker`
+## Development of `//components/feature_engagement`
### Testing
@@ -447,8 +482,8 @@ use:
```bash
ninja -C out/Debug components_unittests ;
./out/Debug/components_unittests \
- --test-launcher-filter-file=components/feature_engagement_tracker/components_unittests.filter
+ --test-launcher-filter-file=components/feature_engagement/components_unittests.filter
```
When adding new test suites, also remember to add the suite to the filter file:
-`//components/feature_engagement_tracker/components_unittests.filter`.
+`//components/feature_engagement/components_unittests.filter`.
diff --git a/chromium/components/feature_engagement/components_unittests.filter b/chromium/components/feature_engagement/components_unittests.filter
new file mode 100644
index 00000000000..ad53cb611c4
--- /dev/null
+++ b/chromium/components/feature_engagement/components_unittests.filter
@@ -0,0 +1,22 @@
+AvailabilityModelImplTest.*
+ChromeVariationsConfigurationTest.*
+ComparatorTest.*
+ConditionValidatorResultTest.*
+EditableConfigurationTest.*
+EventModelImplTest.*
+FailingAvailabilityModelInitTrackerImplTest.*
+FailingStoreInitTrackerImplTest.*
+FeatureConfigConditionValidatorTest.*
+FeatureConfigEventStorageValidatorTest.*
+TrackerImplTest.*
+InitAwareEventModelTest.*
+InMemoryEventStoreTest.*
+LoadFailingEventModelImplTest.*
+NeverAvailabilityModelTest.*
+NeverConditionValidatorTest.*
+NeverEventStorageValidatorTest.*
+OnceConditionValidatorTest.*
+PersistentAvailabilityStoreTest.*
+PersistentEventStoreTest.*
+SingleInvalidConfigurationTest.*
+SystemTimeProviderTest.*
diff --git a/chromium/components/feature_engagement_tracker/internal/BUILD.gn b/chromium/components/feature_engagement/internal/BUILD.gn
index 0c084430e27..3e5b25b6521 100644
--- a/chromium/components/feature_engagement_tracker/internal/BUILD.gn
+++ b/chromium/components/feature_engagement/internal/BUILD.gn
@@ -10,16 +10,14 @@ if (is_android) {
static_library("internal") {
visibility = [
":*",
- "//components/feature_engagement_tracker",
- "//components/feature_engagement_tracker/test:test_support",
+ "//components/feature_engagement",
+ "//components/feature_engagement/test:test_support",
]
sources = [
"availability_model.h",
"availability_model_impl.cc",
"availability_model_impl.h",
- "availability_store.cc",
- "availability_store.h",
"chrome_variations_configuration.cc",
"chrome_variations_configuration.h",
"condition_validator.cc",
@@ -28,56 +26,57 @@ static_library("internal") {
"configuration.h",
"editable_configuration.cc",
"editable_configuration.h",
+ "event_model.h",
+ "event_model_impl.cc",
+ "event_model_impl.h",
+ "event_storage_validator.h",
+ "event_store.h",
"feature_config_condition_validator.cc",
"feature_config_condition_validator.h",
- "feature_config_storage_validator.cc",
- "feature_config_storage_validator.h",
- "feature_engagement_tracker_impl.cc",
- "feature_engagement_tracker_impl.h",
- "in_memory_store.cc",
- "in_memory_store.h",
- "init_aware_model.cc",
- "init_aware_model.h",
- "model.h",
- "model_impl.cc",
- "model_impl.h",
+ "feature_config_event_storage_validator.cc",
+ "feature_config_event_storage_validator.h",
+ "in_memory_event_store.cc",
+ "in_memory_event_store.h",
+ "init_aware_event_model.cc",
+ "init_aware_event_model.h",
"never_availability_model.cc",
"never_availability_model.h",
"never_condition_validator.cc",
"never_condition_validator.h",
- "never_storage_validator.cc",
- "never_storage_validator.h",
+ "never_event_storage_validator.cc",
+ "never_event_storage_validator.h",
"once_condition_validator.cc",
"once_condition_validator.h",
- "persistent_store.cc",
- "persistent_store.h",
+ "persistent_availability_store.cc",
+ "persistent_availability_store.h",
+ "persistent_event_store.cc",
+ "persistent_event_store.h",
"single_invalid_configuration.cc",
"single_invalid_configuration.h",
"stats.cc",
"stats.h",
- "storage_validator.h",
- "store.h",
"system_time_provider.cc",
"system_time_provider.h",
"time_provider.h",
+ "tracker_impl.cc",
+ "tracker_impl.h",
]
public_deps = [
- "//components/feature_engagement_tracker/internal/proto",
+ "//components/feature_engagement/internal/proto",
]
deps = [
"//base",
- "//components/feature_engagement_tracker/public",
+ "//components/feature_engagement/public",
"//components/keyed_service/core",
"//components/leveldb_proto",
]
if (is_android) {
sources += [
- "android/feature_engagement_tracker_impl_android.cc",
- "android/feature_engagement_tracker_impl_android.h",
- "android/feature_engagement_tracker_jni_registrar.cc",
+ "android/tracker_impl_android.cc",
+ "android/tracker_impl_android.h",
]
deps += [ ":jni_headers" ]
@@ -87,37 +86,37 @@ static_library("internal") {
source_set("unit_tests") {
testonly = true
- visibility = [ "//components/feature_engagement_tracker:unit_tests" ]
+ visibility = [ "//components/feature_engagement:unit_tests" ]
# IMPORTANT NOTE: When adding new tests, also remember to update the list of
- # tests in //components/feature_engagement_tracker/components_unittests.filter
+ # tests in //components/feature_engagement/components_unittests.filter
sources = [
"availability_model_impl_unittest.cc",
- "availability_store_unittest.cc",
"chrome_variations_configuration_unittest.cc",
"condition_validator_unittest.cc",
"configuration_unittest.cc",
"editable_configuration_unittest.cc",
+ "event_model_impl_unittest.cc",
"feature_config_condition_validator_unittest.cc",
- "feature_config_storage_validator_unittest.cc",
- "feature_engagement_tracker_impl_unittest.cc",
- "in_memory_store_unittest.cc",
- "init_aware_model_unittest.cc",
- "model_impl_unittest.cc",
+ "feature_config_event_storage_validator_unittest.cc",
+ "in_memory_event_store_unittest.cc",
+ "init_aware_event_model_unittest.cc",
"never_availability_model_unittest.cc",
"never_condition_validator_unittest.cc",
- "never_storage_validator_unittest.cc",
+ "never_event_storage_validator_unittest.cc",
"once_condition_validator_unittest.cc",
- "persistent_store_unittest.cc",
+ "persistent_availability_store_unittest.cc",
+ "persistent_event_store_unittest.cc",
"single_invalid_configuration_unittest.cc",
"system_time_provider_unittest.cc",
+ "tracker_impl_unittest.cc",
]
deps = [
":internal",
"//base/test:test_support",
- "//components/feature_engagement_tracker/internal/test:test_support",
- "//components/feature_engagement_tracker/public",
+ "//components/feature_engagement/internal/test:test_support",
+ "//components/feature_engagement/public",
"//components/leveldb_proto:test_support",
"//testing/gmock",
"//testing/gtest",
@@ -126,21 +125,21 @@ source_set("unit_tests") {
if (is_android) {
android_library("internal_java") {
- visibility = [ "//components/feature_engagement_tracker:feature_engagement_tracker_java" ]
+ visibility = [ "//components/feature_engagement:feature_engagement_java" ]
- java_files = [ "android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java" ]
+ java_files = [ "android/java/src/org/chromium/components/feature_engagement/internal/TrackerImpl.java" ]
deps = [
"//base:base_java",
- "//components/feature_engagement_tracker/public:public_java",
+ "//components/feature_engagement/public:public_java",
]
}
generate_jni("jni_headers") {
visibility = [ ":*" ]
sources = [
- "android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java",
+ "android/java/src/org/chromium/components/feature_engagement/internal/TrackerImpl.java",
]
- jni_package = "components/feature_engagement_tracker/internal"
+ jni_package = "components/feature_engagement/internal"
}
}
diff --git a/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
new file mode 100644
index 00000000000..0dc6aab10ec
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
@@ -0,0 +1,141 @@
+// 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/feature_engagement/internal/android/tracker_impl_android.h"
+
+#include <vector>
+
+#include "base/android/callback_android.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "components/feature_engagement/public/feature_list.h"
+#include "components/feature_engagement/public/tracker.h"
+#include "jni/TrackerImpl_jni.h"
+
+namespace feature_engagement {
+
+namespace {
+
+const char kTrackerImplAndroidKey[] = "tracker_impl_android";
+
+// Create mapping from feature name to base::Feature.
+TrackerImplAndroid::FeatureMap CreateMapFromNameToFeature(
+ FeatureVector features) {
+ TrackerImplAndroid::FeatureMap feature_map;
+ for (auto it = features.begin(); it != features.end(); ++it) {
+ feature_map[(*it)->name] = *it;
+ }
+ return feature_map;
+}
+
+TrackerImplAndroid* FromTrackerImpl(Tracker* feature_engagement) {
+ TrackerImpl* impl = static_cast<TrackerImpl*>(feature_engagement);
+ TrackerImplAndroid* impl_android = static_cast<TrackerImplAndroid*>(
+ impl->GetUserData(kTrackerImplAndroidKey));
+ if (!impl_android) {
+ impl_android = new TrackerImplAndroid(impl, GetAllFeatures());
+ impl->SetUserData(kTrackerImplAndroidKey, base::WrapUnique(impl_android));
+ }
+ return impl_android;
+}
+
+} // namespace
+
+// static
+TrackerImplAndroid* TrackerImplAndroid::FromJavaObject(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj) {
+ return reinterpret_cast<TrackerImplAndroid*>(
+ Java_TrackerImpl_getNativePtr(env, jobj));
+}
+
+// This function is declared in //components/feature_engagement/public/tracker.h
+// and should be linked in to any binary using Tracker::GetJavaObject.
+// static
+base::android::ScopedJavaLocalRef<jobject> Tracker::GetJavaObject(
+ Tracker* feature_engagement) {
+ return FromTrackerImpl(feature_engagement)->GetJavaObject();
+}
+
+TrackerImplAndroid::TrackerImplAndroid(TrackerImpl* tracker_impl,
+ FeatureVector features)
+ : features_(CreateMapFromNameToFeature(features)),
+ tracker_impl_(tracker_impl) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ java_obj_.Reset(
+ env,
+ Java_TrackerImpl_create(env, reinterpret_cast<intptr_t>(this)).obj());
+}
+
+TrackerImplAndroid::~TrackerImplAndroid() {
+ Java_TrackerImpl_clearNativePtr(base::android::AttachCurrentThread(),
+ java_obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> TrackerImplAndroid::GetJavaObject() {
+ return base::android::ScopedJavaLocalRef<jobject>(java_obj_);
+}
+
+void TrackerImplAndroid::NotifyEvent(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jevent) {
+ std::string event = ConvertJavaStringToUTF8(env, jevent);
+ tracker_impl_->NotifyEvent(event);
+}
+
+bool TrackerImplAndroid::ShouldTriggerHelpUI(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ return tracker_impl_->ShouldTriggerHelpUI(*features_[feature]);
+}
+
+jint TrackerImplAndroid::GetTriggerState(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ return static_cast<int>(tracker_impl_->GetTriggerState(*features_[feature]));
+}
+
+void TrackerImplAndroid::Dismissed(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ tracker_impl_->Dismissed(*features_[feature]);
+}
+
+bool TrackerImplAndroid::IsInitialized(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj) {
+ return tracker_impl_->IsInitialized();
+}
+
+void TrackerImplAndroid::AddOnInitializedCallback(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jobject>& j_callback_obj) {
+ // Disambiguate RunCallbackAndroid to get the reference to the bool version.
+ void (*runBoolCallback)(const base::android::JavaRef<jobject>&, bool) =
+ &base::android::RunCallbackAndroid;
+ tracker_impl_->AddOnInitializedCallback(
+ base::Bind(runBoolCallback,
+ base::android::ScopedJavaGlobalRef<jobject>(j_callback_obj)));
+}
+
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h b/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
index 88184741ae8..f429a1fba7c 100644
--- a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ANDROID_TRACKER_IMPL_ANDROID_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ANDROID_TRACKER_IMPL_ANDROID_H_
#include <string>
#include <unordered_map>
@@ -13,38 +13,32 @@
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
#include "base/supports_user_data.h"
-#include "components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/tracker_impl.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-// JNI bridge between FeatureEngagementTrackerImpl in Java and C++. See the
-// public API of FeatureEngagementTracker for documentation for all methods.
-class FeatureEngagementTrackerImplAndroid
- : public base::SupportsUserData::Data {
+// JNI bridge between TrackerImpl in Java and C++. See the
+// public API of Tracker for documentation for all methods.
+class TrackerImplAndroid : public base::SupportsUserData::Data {
public:
using FeatureMap = std::unordered_map<std::string, const base::Feature*>;
- static bool RegisterJni(JNIEnv* env);
- static FeatureEngagementTrackerImplAndroid* FromJavaObject(
+ static TrackerImplAndroid* FromJavaObject(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj);
- FeatureEngagementTrackerImplAndroid(
- FeatureEngagementTrackerImpl* feature_engagement_tracker_impl,
- FeatureVector features);
- ~FeatureEngagementTrackerImplAndroid() override;
+ TrackerImplAndroid(TrackerImpl* tracker_impl, FeatureVector features);
+ ~TrackerImplAndroid() override;
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
- FeatureEngagementTrackerImpl* feature_engagement_tracker_impl() {
- return feature_engagement_tracker_impl_;
- }
+ TrackerImpl* tracker_impl() { return tracker_impl_; }
- // FeatureEngagementTracker JNI bridge implementation.
+ // Tracker JNI bridge implementation.
virtual void NotifyEvent(JNIEnv* env,
const base::android::JavaRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jevent);
@@ -52,6 +46,10 @@ class FeatureEngagementTrackerImplAndroid
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jfeature);
+ virtual jint GetTriggerState(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature);
virtual void Dismissed(JNIEnv* env,
const base::android::JavaRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jfeature);
@@ -68,15 +66,15 @@ class FeatureEngagementTrackerImplAndroid
// class as well, we should remove this mapping.
FeatureMap features_;
- // The FeatureEngagementTrackerImpl this is a JNI bridge for.
- FeatureEngagementTrackerImpl* feature_engagement_tracker_impl_;
+ // The TrackerImpl this is a JNI bridge for.
+ TrackerImpl* tracker_impl_;
// The Java-side of this JNI bridge.
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
- DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImplAndroid);
+ DISALLOW_COPY_AND_ASSIGN(TrackerImplAndroid);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ANDROID_FEATURE_ENGAGEMENT_TRACKER_IMPL_ANDROID_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ANDROID_TRACKER_IMPL_ANDROID_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_model.h b/chromium/components/feature_engagement/internal/availability_model.h
index 55011825431..27aea7e653a 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_model.h
+++ b/chromium/components/feature_engagement/internal/availability_model.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_H_
#include <stdint.h>
@@ -15,7 +15,7 @@ namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// An AvailabilityModel tracks when each feature was made available to an
// end user.
@@ -49,6 +49,6 @@ class AvailabilityModel {
DISALLOW_COPY_AND_ASSIGN(AvailabilityModel);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_model_impl.cc b/chromium/components/feature_engagement/internal/availability_model_impl.cc
index 994a9bfaa4a..4844799f78b 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_model_impl.cc
+++ b/chromium/components/feature_engagement/internal/availability_model_impl.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/feature_engagement_tracker/internal/availability_model_impl.h"
+#include "components/feature_engagement/internal/availability_model_impl.h"
#include <memory>
#include <utility>
@@ -10,9 +10,9 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
-#include "components/feature_engagement_tracker/internal/availability_store.h"
+#include "components/feature_engagement/internal/persistent_availability_store.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
AvailabilityModelImpl::AvailabilityModelImpl(
StoreLoadCallback store_load_callback)
@@ -59,4 +59,4 @@ void AvailabilityModelImpl::OnStoreLoadComplete(
std::move(on_initialized_callback).Run(true);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_model_impl.h b/chromium/components/feature_engagement/internal/availability_model_impl.h
index a94d63c0f5d..7bd159695c2 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_model_impl.h
+++ b/chromium/components/feature_engagement/internal/availability_model_impl.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
#include <stdint.h>
@@ -14,21 +14,20 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/feature_engagement_tracker/internal/availability_model.h"
-#include "components/feature_engagement_tracker/internal/availability_store.h"
+#include "components/feature_engagement/internal/availability_model.h"
+#include "components/feature_engagement/internal/persistent_availability_store.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
-class AvailabilityStore;
-
-// An AvailabilityModel which supports loading data from an AvailabilityStore.
+namespace feature_engagement {
+// An AvailabilityModel which supports loading data from an
+// PersistentAvailabilityStore.
class AvailabilityModelImpl : public AvailabilityModel {
public:
using StoreLoadCallback =
- base::OnceCallback<void(AvailabilityStore::OnLoadedCallback,
+ base::OnceCallback<void(PersistentAvailabilityStore::OnLoadedCallback,
uint32_t current_day)>;
explicit AvailabilityModelImpl(StoreLoadCallback load_callback);
@@ -53,7 +52,7 @@ class AvailabilityModelImpl : public AvailabilityModel {
// name.
std::map<std::string, uint32_t> feature_availabilities_;
- // Whether the model has successfully initialied.
+ // Whether the model has successfully initialized.
bool ready_;
// A callback for loading availability data from the store. This is reset
@@ -65,6 +64,6 @@ class AvailabilityModelImpl : public AvailabilityModel {
DISALLOW_COPY_AND_ASSIGN(AvailabilityModelImpl);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_AVAILABILITY_MODEL_IMPL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_model_impl_unittest.cc b/chromium/components/feature_engagement/internal/availability_model_impl_unittest.cc
index 37c3672e3bd..6c19feec6ed 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_model_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/availability_model_impl_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/feature_engagement_tracker/internal/availability_model_impl.h"
+#include "components/feature_engagement/internal/availability_model_impl.h"
#include <memory>
#include <utility>
@@ -13,10 +13,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
-#include "components/feature_engagement_tracker/internal/availability_store.h"
+#include "components/feature_engagement/internal/persistent_availability_store.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -54,7 +54,7 @@ class AvailabilityModelImplTest : public testing::Test {
void StoreLoader(
bool success,
std::unique_ptr<std::map<std::string, uint32_t>> store_content,
- AvailabilityStore::OnLoadedCallback callback,
+ PersistentAvailabilityStore::OnLoadedCallback callback,
uint32_t current_day) {
current_day_ = current_day;
std::move(callback).Run(success, std::move(store_content));
@@ -131,4 +131,4 @@ TEST_F(AvailabilityModelImplTest, FailToLoadThreeFeatures) {
availability_model_->GetAvailability(kTestFeatureQux));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc b/chromium/components/feature_engagement/internal/chrome_variations_configuration.cc
index bb1f35fa19b..c913e48ce3e 100644
--- a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc
+++ b/chromium/components/feature_engagement/internal/chrome_variations_configuration.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/feature_engagement_tracker/internal/chrome_variations_configuration.h"
+#include "components/feature_engagement/internal/chrome_variations_configuration.h"
#include <map>
#include <memory>
@@ -17,9 +17,9 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/stats.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace {
@@ -45,7 +45,7 @@ const char kEventConfigDataStorageKey[] = "storage";
} // namespace
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -331,4 +331,4 @@ ChromeVariationsConfiguration::GetRegisteredFeatures() const {
return configs_;
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.h b/chromium/components/feature_engagement/internal/chrome_variations_configuration.h
index b4664a749b4..cfdf79b37ba 100644
--- a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration.h
+++ b/chromium/components/feature_engagement/internal/chrome_variations_configuration.h
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// A ChromeVariationsConfiguration provides a configuration that is parsed from
// Chrome variations feature params. It is required to call
@@ -43,6 +43,6 @@ class ChromeVariationsConfiguration : public Configuration {
DISALLOW_COPY_AND_ASSIGN(ChromeVariationsConfiguration);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CHROME_VARIATIONS_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration_unittest.cc b/chromium/components/feature_engagement/internal/chrome_variations_configuration_unittest.cc
index d8027dd970a..729837471b2 100644
--- a/chromium/components/feature_engagement_tracker/internal/chrome_variations_configuration_unittest.cc
+++ b/chromium/components/feature_engagement/internal/chrome_variations_configuration_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/feature_engagement_tracker/internal/chrome_variations_configuration.h"
+#include "components/feature_engagement/internal/chrome_variations_configuration.h"
#include <map>
#include <string>
@@ -14,11 +14,11 @@
#include "base/metrics/field_trial_params.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/stats.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -628,4 +628,4 @@ TEST_F(ChromeVariationsConfigurationTest, ParseMultipleFeatures) {
EXPECT_EQ(expected_qux, qux);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/condition_validator.cc b/chromium/components/feature_engagement/internal/condition_validator.cc
index 38b59b4c098..61a57e20ef2 100644
--- a/chromium/components/feature_engagement_tracker/internal/condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/condition_validator.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/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement/internal/condition_validator.h"
#include <ostream>
-namespace feature_engagement_tracker {
+namespace feature_engagement {
ConditionValidator::Result::Result(bool initial_values)
: event_model_ready_ok(initial_values),
@@ -54,4 +54,4 @@ std::ostream& operator<<(std::ostream& os,
<< ", availability_ok=" << result.availability_ok << " }";
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/condition_validator.h b/chromium/components/feature_engagement/internal/condition_validator.h
index fcefb4b3f5e..809f4579c6e 100644
--- a/chromium/components/feature_engagement_tracker/internal/condition_validator.h
+++ b/chromium/components/feature_engagement/internal/condition_validator.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONDITION_VALIDATOR_H_
#include <stdint.h>
@@ -11,16 +11,16 @@
#include <string>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
struct FeatureConfig;
class AvailabilityModel;
-class Model;
+class EventModel;
// A ConditionValidator checks the requred conditions for a given feature,
// and checks if all conditions are met.
@@ -74,7 +74,7 @@ class ConditionValidator {
// Returns a Result object that describes whether each condition has been met.
virtual Result MeetsConditions(const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const = 0;
@@ -94,6 +94,6 @@ class ConditionValidator {
std::ostream& operator<<(std::ostream& os,
const ConditionValidator::Result& result);
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONDITION_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/condition_validator_unittest.cc
index a6f8cb59994..381632fe15e 100644
--- a/chromium/components/feature_engagement_tracker/internal/condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/condition_validator_unittest.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/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement/internal/condition_validator.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
TEST(ConditionValidatorResultTest, TestAllOK) {
EXPECT_TRUE(ConditionValidator::Result(true).NoErrors());
@@ -83,4 +83,4 @@ TEST(ConditionValidatorResultTest, TestMultipleErrors) {
EXPECT_FALSE(result.NoErrors());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/configuration.cc b/chromium/components/feature_engagement/internal/configuration.cc
index 60b3023011b..048eb63d79d 100644
--- a/chromium/components/feature_engagement_tracker/internal/configuration.cc
+++ b/chromium/components/feature_engagement/internal/configuration.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
#include <string>
#include "base/logging.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
Comparator::Comparator() : type(ANY), value(0) {}
@@ -132,4 +132,4 @@ std::ostream& operator<<(std::ostream& os,
<< ", availability: " << feature_config.availability << " }";
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/configuration.h b/chromium/components/feature_engagement/internal/configuration.h
index f9ebb7338ce..891a62e2362 100644
--- a/chromium/components/feature_engagement_tracker/internal/configuration.h
+++ b/chromium/components/feature_engagement/internal/configuration.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONFIGURATION_H_
#include <map>
#include <ostream>
@@ -17,7 +17,7 @@ namespace base {
struct Feature;
}
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// A ComparatorType describes the relationship between two numbers.
enum ComparatorType {
@@ -144,6 +144,6 @@ class Configuration {
DISALLOW_COPY_AND_ASSIGN(Configuration);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_CONFIGURATION_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/configuration_unittest.cc b/chromium/components/feature_engagement/internal/configuration_unittest.cc
index 20be6474803..540950e4918 100644
--- a/chromium/components/feature_engagement_tracker/internal/configuration_unittest.cc
+++ b/chromium/components/feature_engagement/internal/configuration_unittest.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/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
TEST(ComparatorTest, Any) {
EXPECT_TRUE(Comparator(ANY, 0).MeetsCriteria(0));
@@ -78,4 +78,4 @@ TEST(ComparatorTest, NotEqual) {
EXPECT_TRUE(Comparator(NOT_EQUAL, 10).MeetsCriteria(11));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration.cc b/chromium/components/feature_engagement/internal/editable_configuration.cc
index 6ebbd7186b3..cdce5386a2f 100644
--- a/chromium/components/feature_engagement_tracker/internal/editable_configuration.cc
+++ b/chromium/components/feature_engagement/internal/editable_configuration.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
#include <map>
#include "base/feature_list.h"
#include "base/logging.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
EditableConfiguration::EditableConfiguration() = default;
@@ -41,4 +41,4 @@ const Configuration::ConfigMap& EditableConfiguration::GetRegisteredFeatures()
return configs_;
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration.h b/chromium/components/feature_engagement/internal/editable_configuration.h
index b0168acc9f7..b92b3da5140 100644
--- a/chromium/components/feature_engagement_tracker/internal/editable_configuration.h
+++ b/chromium/components/feature_engagement/internal/editable_configuration.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EDITABLE_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EDITABLE_CONFIGURATION_H_
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// An EditableConfiguration provides a configuration that can be configured
// by calling SetConfiguration(...) for each feature, which makes it well
@@ -41,6 +41,6 @@ class EditableConfiguration : public Configuration {
DISALLOW_COPY_AND_ASSIGN(EditableConfiguration);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_EDITABLE_CONFIGURATION_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EDITABLE_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc b/chromium/components/feature_engagement/internal/editable_configuration_unittest.cc
index ee347bdd40f..817d9881c9d 100644
--- a/chromium/components/feature_engagement_tracker/internal/editable_configuration_unittest.cc
+++ b/chromium/components/feature_engagement/internal/editable_configuration_unittest.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
#include <string>
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -74,4 +74,4 @@ TEST_F(EditableConfigurationTest, ConfigShouldBeEditable) {
EXPECT_EQ(invalid_foo_config, invalid_foo_config_result);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/model.h b/chromium/components/feature_engagement/internal/event_model.h
index f122b9a976e..5a2df54768f 100644
--- a/chromium/components/feature_engagement_tracker/internal/model.h
+++ b/chromium/components/feature_engagement/internal/event_model.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_H_
#include <map>
#include <string>
@@ -11,18 +11,17 @@
#include "base/callback.h"
#include "base/macros.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class Event;
-// A Model provides all necessary runtime state.
-// TODO(nyquist): Rename to EventModel.
-class Model {
+// A EventModel provides all necessary runtime state.
+class EventModel {
public:
// Callback for when model initialization has finished. The |success|
// argument denotes whether the model was successfully initialized.
using OnModelInitializationFinished = base::Callback<void(bool success)>;
- virtual ~Model() = default;
+ virtual ~EventModel() = default;
// Initialize the model, including all underlying sub systems. When all
// required operations have been finished, a callback is posted.
@@ -35,7 +34,7 @@ class Model {
// Retrieves the Event object for the event with the given name. If the event
// is not found, a nullptr will be returned. Calling this before the
- // Model has finished initializing will result in undefined behavior.
+ // EventModel has finished initializing will result in undefined behavior.
virtual const Event* GetEvent(const std::string& event_name) const = 0;
// Increments the counter for today for how many times the event has happened.
@@ -46,12 +45,12 @@ class Model {
uint32_t current_day) = 0;
protected:
- Model() = default;
+ EventModel() = default;
private:
- DISALLOW_COPY_AND_ASSIGN(Model);
+ DISALLOW_COPY_AND_ASSIGN(EventModel);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl.cc b/chromium/components/feature_engagement/internal/event_model_impl.cc
index aa1df6e246f..2fd365c9c5a 100644
--- a/chromium/components/feature_engagement_tracker/internal/model_impl.cc
+++ b/chromium/components/feature_engagement/internal/event_model_impl.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/feature_engagement_tracker/internal/model_impl.h"
+#include "components/feature_engagement/internal/event_model_impl.h"
#include <map>
#include <memory>
@@ -15,33 +15,34 @@
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/storage_validator.h"
-#include "components/feature_engagement_tracker/internal/store.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/event_storage_validator.h"
+#include "components/feature_engagement/internal/event_store.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-ModelImpl::ModelImpl(std::unique_ptr<Store> store,
- std::unique_ptr<StorageValidator> storage_validator)
- : Model(),
+EventModelImpl::EventModelImpl(
+ std::unique_ptr<EventStore> store,
+ std::unique_ptr<EventStorageValidator> storage_validator)
+ : EventModel(),
store_(std::move(store)),
storage_validator_(std::move(storage_validator)),
ready_(false),
weak_factory_(this) {}
-ModelImpl::~ModelImpl() = default;
+EventModelImpl::~EventModelImpl() = default;
-void ModelImpl::Initialize(const OnModelInitializationFinished& callback,
- uint32_t current_day) {
- store_->Load(base::Bind(&ModelImpl::OnStoreLoaded, weak_factory_.GetWeakPtr(),
- callback, current_day));
+void EventModelImpl::Initialize(const OnModelInitializationFinished& callback,
+ uint32_t current_day) {
+ store_->Load(base::Bind(&EventModelImpl::OnStoreLoaded,
+ weak_factory_.GetWeakPtr(), callback, current_day));
}
-bool ModelImpl::IsReady() const {
+bool EventModelImpl::IsReady() const {
return ready_;
}
-const Event* ModelImpl::GetEvent(const std::string& event_name) const {
+const Event* EventModelImpl::GetEvent(const std::string& event_name) const {
auto search = events_.find(event_name);
if (search == events_.end())
return nullptr;
@@ -49,8 +50,8 @@ const Event* ModelImpl::GetEvent(const std::string& event_name) const {
return &search->second;
}
-void ModelImpl::IncrementEvent(const std::string& event_name,
- uint32_t current_day) {
+void EventModelImpl::IncrementEvent(const std::string& event_name,
+ uint32_t current_day) {
DCHECK(ready_);
if (!storage_validator_->ShouldStore(event_name)) {
@@ -79,10 +80,11 @@ void ModelImpl::IncrementEvent(const std::string& event_name,
store_->WriteEvent(event);
}
-void ModelImpl::OnStoreLoaded(const OnModelInitializationFinished& callback,
- uint32_t current_day,
- bool success,
- std::unique_ptr<std::vector<Event>> events) {
+void EventModelImpl::OnStoreLoaded(
+ const OnModelInitializationFinished& callback,
+ uint32_t current_day,
+ bool success,
+ std::unique_ptr<std::vector<Event>> events) {
if (!success) {
callback.Run(false);
return;
@@ -121,7 +123,7 @@ void ModelImpl::OnStoreLoaded(const OnModelInitializationFinished& callback,
callback.Run(true);
}
-Event& ModelImpl::GetNonConstEvent(const std::string& event_name) {
+Event& EventModelImpl::GetNonConstEvent(const std::string& event_name) {
if (events_.find(event_name) == events_.end()) {
// Event does not exist yet, so create it.
events_[event_name].set_name(event_name);
@@ -130,4 +132,4 @@ Event& ModelImpl::GetNonConstEvent(const std::string& event_name) {
return events_[event_name];
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl.h b/chromium/components/feature_engagement/internal/event_model_impl.h
index adef3e04302..1c70bddcc3a 100644
--- a/chromium/components/feature_engagement_tracker/internal/model_impl.h
+++ b/chromium/components/feature_engagement/internal/event_model_impl.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_IMPL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_IMPL_H_
#include <map>
#include <memory>
@@ -12,21 +12,21 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
-namespace feature_engagement_tracker {
-class StorageValidator;
-class Store;
+namespace feature_engagement {
+class EventStorageValidator;
+class EventStore;
-// A ModelImpl provides the default implementation of the Model.
-class ModelImpl : public Model {
+// A EventModelImpl provides the default implementation of the EventModel.
+class EventModelImpl : public EventModel {
public:
- ModelImpl(std::unique_ptr<Store> store,
- std::unique_ptr<StorageValidator> storage_validator);
- ~ModelImpl() override;
+ EventModelImpl(std::unique_ptr<EventStore> store,
+ std::unique_ptr<EventStorageValidator> storage_validator);
+ ~EventModelImpl() override;
- // Model implementation.
+ // EventModel implementation.
void Initialize(const OnModelInitializationFinished& callback,
uint32_t current_day) override;
bool IsReady() const override;
@@ -46,11 +46,11 @@ class ModelImpl : public Model {
Event& GetNonConstEvent(const std::string& event_name);
// The underlying store for all events.
- std::unique_ptr<Store> store_;
+ std::unique_ptr<EventStore> store_;
// A utility for checking whether new events should be stored and for whether
// old events should be kept.
- std::unique_ptr<StorageValidator> storage_validator_;
+ std::unique_ptr<EventStorageValidator> storage_validator_;
// An in-memory representation of all events.
std::map<std::string, Event> events_;
@@ -58,11 +58,11 @@ class ModelImpl : public Model {
// Whether the model has been fully initialized.
bool ready_;
- base::WeakPtrFactory<ModelImpl> weak_factory_;
+ base::WeakPtrFactory<EventModelImpl> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(ModelImpl);
+ DISALLOW_COPY_AND_ASSIGN(EventModelImpl);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_MODEL_IMPL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc b/chromium/components/feature_engagement/internal/event_model_impl_unittest.cc
index 43bae9a4ee7..818dd48042e 100644
--- a/chromium/components/feature_engagement_tracker/internal/model_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/event_model_impl_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/feature_engagement_tracker/internal/model_impl.h"
+#include "components/feature_engagement/internal/event_model_impl.h"
#include <memory>
@@ -12,24 +12,24 @@
#include "base/memory/ptr_util.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/in_memory_store.h"
-#include "components/feature_engagement_tracker/internal/never_storage_validator.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/internal/test/event_util.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/in_memory_event_store.h"
+#include "components/feature_engagement/internal/never_event_storage_validator.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/test/event_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
-// A test-only implementation of InMemoryStore that tracks calls to
+// A test-only implementation of InMemoryEventStore that tracks calls to
// WriteEvent(...).
-class TestInMemoryStore : public InMemoryStore {
+class TestInMemoryEventStore : public InMemoryEventStore {
public:
- TestInMemoryStore(std::unique_ptr<std::vector<Event>> events,
- bool load_should_succeed)
- : InMemoryStore(std::move(events)),
+ TestInMemoryEventStore(std::unique_ptr<std::vector<Event>> events,
+ bool load_should_succeed)
+ : InMemoryEventStore(std::move(events)),
store_operation_count_(0),
load_should_succeed_(load_should_succeed) {}
@@ -68,9 +68,9 @@ class TestInMemoryStore : public InMemoryStore {
bool load_should_succeed_;
};
-class TestStorageValidator : public StorageValidator {
+class TestEventStorageValidator : public EventStorageValidator {
public:
- TestStorageValidator() : should_store_(true) {}
+ TestEventStorageValidator() : should_store_(true) {}
bool ShouldStore(const std::string& event_name) const override {
return should_store_;
@@ -96,11 +96,11 @@ class TestStorageValidator : public StorageValidator {
bool should_store_;
std::map<std::string, uint32_t> max_keep_ages_;
- DISALLOW_COPY_AND_ASSIGN(TestStorageValidator);
+ DISALLOW_COPY_AND_ASSIGN(TestEventStorageValidator);
};
-// Creates a TestInMemoryStore containing three hard coded events.
-std::unique_ptr<TestInMemoryStore> CreatePrefilledStore() {
+// Creates a TestInMemoryEventStore containing three hard coded events.
+std::unique_ptr<TestInMemoryEventStore> CreatePrefilledStore() {
std::unique_ptr<std::vector<Event>> events =
base::MakeUnique<std::vector<Event>>();
@@ -123,25 +123,26 @@ std::unique_ptr<TestInMemoryStore> CreatePrefilledStore() {
test::SetEventCountForDay(&qux, 3, 2);
events->push_back(qux);
- return base::MakeUnique<TestInMemoryStore>(std::move(events), true);
+ return base::MakeUnique<TestInMemoryEventStore>(std::move(events), true);
}
-class ModelImplTest : public ::testing::Test {
+class EventModelImplTest : public ::testing::Test {
public:
- ModelImplTest()
+ EventModelImplTest()
: task_runner_(new base::TestSimpleTaskRunner),
handle_(task_runner_),
got_initialize_callback_(false),
initialize_callback_result_(false) {}
void SetUp() override {
- std::unique_ptr<TestInMemoryStore> store = CreateStore();
+ std::unique_ptr<TestInMemoryEventStore> store = CreateStore();
store_ = store.get();
- auto storage_validator = base::MakeUnique<TestStorageValidator>();
+ auto storage_validator = base::MakeUnique<TestEventStorageValidator>();
storage_validator_ = storage_validator.get();
- model_.reset(new ModelImpl(std::move(store), std::move(storage_validator)));
+ model_.reset(
+ new EventModelImpl(std::move(store), std::move(storage_validator)));
// By default store all events for a very long time.
storage_validator_->SetMaxKeepAge("foo", 10000u);
@@ -149,7 +150,7 @@ class ModelImplTest : public ::testing::Test {
storage_validator_->SetMaxKeepAge("qux", 10000u);
}
- virtual std::unique_ptr<TestInMemoryStore> CreateStore() {
+ virtual std::unique_ptr<TestInMemoryEventStore> CreateStore() {
return CreatePrefilledStore();
}
@@ -162,29 +163,30 @@ class ModelImplTest : public ::testing::Test {
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle handle_;
- std::unique_ptr<ModelImpl> model_;
- TestInMemoryStore* store_;
- TestStorageValidator* storage_validator_;
+ std::unique_ptr<EventModelImpl> model_;
+ TestInMemoryEventStore* store_;
+ TestEventStorageValidator* storage_validator_;
bool got_initialize_callback_;
bool initialize_callback_result_;
};
-class LoadFailingModelImplTest : public ModelImplTest {
+class LoadFailingEventModelImplTest : public EventModelImplTest {
public:
- LoadFailingModelImplTest() : ModelImplTest() {}
+ LoadFailingEventModelImplTest() : EventModelImplTest() {}
- std::unique_ptr<TestInMemoryStore> CreateStore() override {
- return base::MakeUnique<TestInMemoryStore>(
+ std::unique_ptr<TestInMemoryEventStore> CreateStore() override {
+ return base::MakeUnique<TestInMemoryEventStore>(
base::MakeUnique<std::vector<Event>>(), false);
}
};
} // namespace
-TEST_F(ModelImplTest, InitializeShouldBeReadyImmediatelyAfterCallback) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, InitializeShouldBeReadyImmediatelyAfterCallback) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
// Only run pending tasks on the queue. Do not run any subsequently queued
// tasks that result from running the current pending tasks.
@@ -194,10 +196,11 @@ TEST_F(ModelImplTest, InitializeShouldBeReadyImmediatelyAfterCallback) {
EXPECT_TRUE(model_->IsReady());
}
-TEST_F(ModelImplTest, InitializeShouldLoadEntries) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, InitializeShouldLoadEntries) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
EXPECT_TRUE(got_initialize_callback_);
@@ -225,7 +228,7 @@ TEST_F(ModelImplTest, InitializeShouldLoadEntries) {
test::VerifyEventCount(qux_event, 3u, 2u);
}
-TEST_F(ModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
+TEST_F(EventModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
// Back to day 5, i.e. no entries.
storage_validator_->SetMaxKeepAge("foo", 1u);
@@ -235,9 +238,10 @@ TEST_F(ModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
// Back to day epoch, i.e. all events.
storage_validator_->SetMaxKeepAge("qux", 10u);
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 5u);
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 5u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
EXPECT_TRUE(got_initialize_callback_);
@@ -256,7 +260,7 @@ TEST_F(ModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
test::VerifyEventCount(bar_event, 5u, 5u);
test::VerifyEventsEqual(bar_event, store_->GetLastWrittenEvent());
- // Nothing has changed for 'qux', so nothing will be written to Store.
+ // Nothing has changed for 'qux', so nothing will be written to EventStore.
const Event* qux_event = model_->GetEvent("qux");
EXPECT_EQ("qux", qux_event->name());
EXPECT_EQ(3, qux_event->events_size());
@@ -269,10 +273,11 @@ TEST_F(ModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
EXPECT_EQ(2u, store_->GetStoreOperationCount());
}
-TEST_F(ModelImplTest, RetrievingNewEventsShouldYieldNullptr) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, RetrievingNewEventsShouldYieldNullptr) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -281,10 +286,11 @@ TEST_F(ModelImplTest, RetrievingNewEventsShouldYieldNullptr) {
test::VerifyEventsEqual(nullptr, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingNonExistingEvent) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingNonExistingEvent) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -308,10 +314,11 @@ TEST_F(ModelImplTest, IncrementingNonExistingEvent) {
test::VerifyEventsEqual(event2, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingNonExistingEventMultipleDays) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingNonExistingEventMultipleDays) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -328,10 +335,11 @@ TEST_F(ModelImplTest, IncrementingNonExistingEventMultipleDays) {
test::VerifyEventsEqual(event, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingNonExistingEventWithoutStoring) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingNonExistingEventWithoutStoring) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -344,10 +352,11 @@ TEST_F(ModelImplTest, IncrementingNonExistingEventWithoutStoring) {
test::VerifyEventsEqual(nullptr, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingExistingEventWithoutStoring) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingExistingEventWithoutStoring) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -366,10 +375,11 @@ TEST_F(ModelImplTest, IncrementingExistingEventWithoutStoring) {
test::VerifyEventsEqual(first_event, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingSingleDayExistingEvent) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingSingleDayExistingEvent) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -387,10 +397,11 @@ TEST_F(ModelImplTest, IncrementingSingleDayExistingEvent) {
test::VerifyEventsEqual(foo_event2, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingSingleDayExistingEventTwice) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingSingleDayExistingEventTwice) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -404,10 +415,11 @@ TEST_F(ModelImplTest, IncrementingSingleDayExistingEventTwice) {
test::VerifyEventsEqual(foo_event, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingExistingMultiDayEvent) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingExistingMultiDayEvent) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -421,10 +433,11 @@ TEST_F(ModelImplTest, IncrementingExistingMultiDayEvent) {
test::VerifyEventsEqual(bar_event2, store_->GetLastWrittenEvent());
}
-TEST_F(ModelImplTest, IncrementingExistingMultiDayEventNewDay) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(EventModelImplTest, IncrementingExistingMultiDayEventNewDay) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_TRUE(model_->IsReady());
@@ -440,14 +453,15 @@ TEST_F(ModelImplTest, IncrementingExistingMultiDayEventNewDay) {
test::VerifyEventsEqual(bar_event2, store_->GetLastWrittenEvent());
}
-TEST_F(LoadFailingModelImplTest, FailedInitializeInformsCaller) {
- model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
- base::Unretained(this)),
- 1000u);
+TEST_F(LoadFailingEventModelImplTest, FailedInitializeInformsCaller) {
+ model_->Initialize(
+ base::Bind(&EventModelImplTest::OnModelInitializationFinished,
+ base::Unretained(this)),
+ 1000u);
task_runner_->RunUntilIdle();
EXPECT_FALSE(model_->IsReady());
EXPECT_TRUE(got_initialize_callback_);
EXPECT_FALSE(initialize_callback_result_);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/storage_validator.h b/chromium/components/feature_engagement/internal/event_storage_validator.h
index 15d2d3dc62b..db41c843b74 100644
--- a/chromium/components/feature_engagement_tracker/internal/storage_validator.h
+++ b/chromium/components/feature_engagement/internal/event_storage_validator.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORAGE_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORAGE_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_STORAGE_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_STORAGE_VALIDATOR_H_
#include <string>
#include "base/macros.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-// A StorageValidator checks the required storage conditions for a given event,
-// and checks if all conditions are met for storing it.
-class StorageValidator {
+// A EventStorageValidator checks the required storage conditions for a given
+// event, and checks if all conditions are met for storing it.
+class EventStorageValidator {
public:
- virtual ~StorageValidator() = default;
+ virtual ~EventStorageValidator() = default;
// Returns true iff new events of this type should be stored.
// This is typically called before storing each incoming event.
@@ -29,12 +29,12 @@ class StorageValidator {
uint32_t current_day) const = 0;
protected:
- StorageValidator() = default;
+ EventStorageValidator() = default;
private:
- DISALLOW_COPY_AND_ASSIGN(StorageValidator);
+ DISALLOW_COPY_AND_ASSIGN(EventStorageValidator);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORAGE_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_EVENT_STORAGE_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/store.h b/chromium/components/feature_engagement/internal/event_store.h
index cc546ad3e61..a70820ab8dd 100644
--- a/chromium/components/feature_engagement_tracker/internal/store.h
+++ b/chromium/components/feature_engagement/internal/event_store.h
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STORE_H_
#include <string>
#include "base/callback.h"
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-// Store represents the storage engine behind the FeatureEngagementTracker.
-class Store {
+// EventStore represents the storage engine behind the EventModel.
+class EventStore {
public:
using OnLoadedCallback =
base::Callback<void(bool success, std::unique_ptr<std::vector<Event>>)>;
- virtual ~Store() = default;
+ virtual ~EventStore() = default;
// Loads the database from storage and asynchronously posts the result back
// on the caller's thread.
@@ -37,12 +37,12 @@ class Store {
virtual void DeleteEvent(const std::string& event_name) = 0;
protected:
- Store() = default;
+ EventStore() = default;
private:
- DISALLOW_COPY_AND_ASSIGN(Store);
+ DISALLOW_COPY_AND_ASSIGN(EventStore);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STORE_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.cc b/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc
index ff6e1ad5ef1..2ec5b835153 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/feature_config_condition_validator.h"
+#include "components/feature_engagement/internal/feature_config_condition_validator.h"
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/availability_model.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/availability_model.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/feature_engagement/public/feature_list.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
FeatureConfigConditionValidator::FeatureConfigConditionValidator()
: currently_showing_(false), times_shown_(0u) {}
@@ -21,21 +21,22 @@ FeatureConfigConditionValidator::~FeatureConfigConditionValidator() = default;
ConditionValidator::Result FeatureConfigConditionValidator::MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const {
ConditionValidator::Result result(true);
- result.event_model_ready_ok = model.IsReady();
+ result.event_model_ready_ok = event_model.IsReady();
result.currently_showing_ok = !currently_showing_;
result.feature_enabled_ok = base::FeatureList::IsEnabled(feature);
result.config_ok = config.valid;
- result.used_ok = EventConfigMeetsConditions(config.used, model, current_day);
+ result.used_ok =
+ EventConfigMeetsConditions(config.used, event_model, current_day);
result.trigger_ok =
- EventConfigMeetsConditions(config.trigger, model, current_day);
+ EventConfigMeetsConditions(config.trigger, event_model, current_day);
for (const auto& event_config : config.event_configs) {
result.preconditions_ok &=
- EventConfigMeetsConditions(event_config, model, current_day);
+ EventConfigMeetsConditions(event_config, event_model, current_day);
}
result.session_rate_ok = config.session_rate.MeetsCriteria(times_shown_);
@@ -64,9 +65,9 @@ void FeatureConfigConditionValidator::NotifyDismissed(
bool FeatureConfigConditionValidator::EventConfigMeetsConditions(
const EventConfig& event_config,
- const Model& model,
+ const EventModel& event_model,
uint32_t current_day) const {
- const Event* event = model.GetEvent(event_config.name);
+ const Event* event = event_model.GetEvent(event_config.name);
// If no events are found, the requirement must be met with 0 elements.
// Also, if the window is 0 days, there will never be any events.
@@ -118,4 +119,4 @@ bool FeatureConfigConditionValidator::AvailabilityMeetsConditions(
return comparator.MeetsCriteria(days_available);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.h b/chromium/components/feature_engagement/internal/feature_config_condition_validator.h
index 02f719597bb..949eaa792bf 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator.h
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
#include <stdint.h>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/condition_validator.h"
+#include "components/feature_engagement/internal/condition_validator.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class AvailabilityModel;
struct Comparator;
struct EventConfig;
-class Model;
+class EventModel;
// A ConditionValidator that uses the FeatureConfigs as the source of truth.
class FeatureConfigConditionValidator : public ConditionValidator {
@@ -26,7 +26,7 @@ class FeatureConfigConditionValidator : public ConditionValidator {
ConditionValidator::Result MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const override;
void NotifyIsShowing(const base::Feature& feature) override;
@@ -34,7 +34,7 @@ class FeatureConfigConditionValidator : public ConditionValidator {
private:
bool EventConfigMeetsConditions(const EventConfig& event_config,
- const Model& model,
+ const EventModel& event_model,
uint32_t current_day) const;
bool AvailabilityMeetsConditions(const base::Feature& feature,
@@ -51,6 +51,6 @@ class FeatureConfigConditionValidator : public ConditionValidator {
DISALLOW_COPY_AND_ASSIGN(FeatureConfigConditionValidator);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc
index 652e8450b8e..5f6420f8925 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator_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/feature_engagement_tracker/internal/feature_config_condition_validator.h"
+#include "components/feature_engagement/internal/feature_config_condition_validator.h"
#include <map>
#include <string>
@@ -10,14 +10,14 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/test/scoped_feature_list.h"
-#include "components/feature_engagement_tracker/internal/availability_model.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/internal/test/event_util.h"
+#include "components/feature_engagement/internal/availability_model.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/test/event_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -42,9 +42,9 @@ FeatureConfig GetAcceptingFeatureConfig() {
return config;
}
-class TestModel : public Model {
+class TestEventModel : public EventModel {
public:
- TestModel() : ready_(true) {}
+ TestEventModel() : ready_(true) {}
void Initialize(const OnModelInitializationFinished& callback,
uint32_t current_day) override {}
@@ -115,22 +115,22 @@ class FeatureConfigConditionValidatorTest : public ::testing::Test {
uint32_t current_day) {
FeatureConfig config = GetAcceptingFeatureConfig();
config.event_configs.insert(EventConfig("event1", comparator, window, 0));
- return validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ return validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
}
ConditionValidator::Result GetResultForDay(const FeatureConfig& config,
uint32_t current_day) {
- return validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ return validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
}
ConditionValidator::Result GetResultForDayZero(const FeatureConfig& config) {
- return validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ return validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, 0);
}
- TestModel model_;
+ TestEventModel event_model_;
TestAvailabilityModel availability_model_;
FeatureConfigConditionValidator validator_;
uint32_t current_day_;
@@ -145,7 +145,7 @@ TEST_F(FeatureConfigConditionValidatorTest, ModelNotReadyShouldFail) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures({kTestFeatureFoo}, {});
- model_.SetIsReady(false);
+ event_model_.SetIsReady(false);
ConditionValidator::Result result =
GetResultForDayZero(GetValidFeatureConfig());
@@ -166,7 +166,7 @@ TEST_F(FeatureConfigConditionValidatorTest, MultipleErrorsShouldBeSet) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures({kTestFeatureFoo}, {});
- model_.SetIsReady(false);
+ event_model_.SetIsReady(false);
ConditionValidator::Result result = GetResultForDayZero(FeatureConfig());
EXPECT_FALSE(result.NoErrors());
@@ -373,7 +373,7 @@ TEST_F(FeatureConfigConditionValidatorTest, SingleEventChangingComparator) {
test::SetEventCountForDay(&event1, 100u, 10u);
test::SetEventCountForDay(&event1, 101u, 10u);
test::SetEventCountForDay(&event1, 102u, 10u);
- model_.SetEvent(event1);
+ event_model_.SetEvent(event1);
EXPECT_TRUE(GetResultForDayAndEventWindow(Comparator(LESS_THAN, 50u), window,
current_day)
@@ -397,7 +397,7 @@ TEST_F(FeatureConfigConditionValidatorTest, SingleEventChangingWindow) {
test::SetEventCountForDay(&event1, 102u, 10u);
test::SetEventCountForDay(&event1, 103u, 10u);
test::SetEventCountForDay(&event1, 104u, 10u);
- model_.SetEvent(event1);
+ event_model_.SetEvent(event1);
uint32_t current_day = 104u;
@@ -430,7 +430,7 @@ TEST_F(FeatureConfigConditionValidatorTest, CapEarliestAcceptedDayAtEpoch) {
test::SetEventCountForDay(&event1, 0, 10u);
test::SetEventCountForDay(&event1, 1u, 10u);
test::SetEventCountForDay(&event1, 2u, 10u);
- model_.SetEvent(event1);
+ event_model_.SetEvent(event1);
uint32_t current_day = 100u;
@@ -457,14 +457,14 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
test::SetEventCountForDay(&event1, 0, 10u);
test::SetEventCountForDay(&event1, 1u, 10u);
test::SetEventCountForDay(&event1, 2u, 10u);
- model_.SetEvent(event1);
+ event_model_.SetEvent(event1);
Event event2;
event2.set_name("event2");
test::SetEventCountForDay(&event2, 0, 5u);
test::SetEventCountForDay(&event2, 1u, 5u);
test::SetEventCountForDay(&event2, 2u, 5u);
- model_.SetEvent(event2);
+ event_model_.SetEvent(event2);
uint32_t current_day = 100u;
@@ -475,7 +475,7 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 5u), 99u, 0));
ConditionValidator::Result result = validator_.MeetsConditions(
- kTestFeatureFoo, config, model_, availability_model_, current_day);
+ kTestFeatureFoo, config, event_model_, availability_model_, current_day);
EXPECT_TRUE(result.NoErrors());
// Verify validator counts correctly for two events last 100 days.
@@ -484,7 +484,7 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
EventConfig("event1", Comparator(EQUAL, 20u), 100u, 0));
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 10u), 100u, 0));
- result = validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ result = validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
EXPECT_TRUE(result.NoErrors());
@@ -494,7 +494,7 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
EventConfig("event1", Comparator(EQUAL, 30u), 101u, 0));
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 15u), 101u, 0));
- result = validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ result = validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
EXPECT_TRUE(result.NoErrors());
@@ -505,7 +505,7 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
EventConfig("event1", Comparator(EQUAL, 0), 101u, 0));
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 15u), 101u, 0));
- result = validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ result = validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.preconditions_ok);
@@ -517,7 +517,7 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
EventConfig("event1", Comparator(EQUAL, 30u), 101u, 0));
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 0), 101u, 0));
- result = validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ result = validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.preconditions_ok);
@@ -529,10 +529,10 @@ TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
EventConfig("event1", Comparator(EQUAL, 0), 101u, 0));
config.event_configs.insert(
EventConfig("event2", Comparator(EQUAL, 0), 101u, 0));
- result = validator_.MeetsConditions(kTestFeatureFoo, config, model_,
+ result = validator_.MeetsConditions(kTestFeatureFoo, config, event_model_,
availability_model_, current_day);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.preconditions_ok);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator.cc
index 5dc27e3289b..588d6a83f00 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator.cc
@@ -2,30 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/feature_config_storage_validator.h"
+#include "components/feature_engagement/internal/feature_config_event_storage_validator.h"
#include <unordered_map>
#include <unordered_set>
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/public/feature_list.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-FeatureConfigStorageValidator::FeatureConfigStorageValidator() = default;
+FeatureConfigEventStorageValidator::FeatureConfigEventStorageValidator() =
+ default;
-FeatureConfigStorageValidator::~FeatureConfigStorageValidator() = default;
+FeatureConfigEventStorageValidator::~FeatureConfigEventStorageValidator() =
+ default;
-bool FeatureConfigStorageValidator::ShouldStore(
+bool FeatureConfigEventStorageValidator::ShouldStore(
const std::string& event_name) const {
return should_store_event_names_.find(event_name) !=
should_store_event_names_.end();
}
-bool FeatureConfigStorageValidator::ShouldKeep(const std::string& event_name,
- uint32_t event_day,
- uint32_t current_day) const {
+bool FeatureConfigEventStorageValidator::ShouldKeep(
+ const std::string& event_name,
+ uint32_t event_day,
+ uint32_t current_day) const {
// Should not keep events that will happen in the future.
if (event_day > current_day)
return false;
@@ -44,7 +47,7 @@ bool FeatureConfigStorageValidator::ShouldKeep(const std::string& event_name,
return true;
}
-void FeatureConfigStorageValidator::InitializeFeatures(
+void FeatureConfigEventStorageValidator::InitializeFeatures(
FeatureVector features,
const Configuration& configuration) {
for (const auto* feature : features) {
@@ -55,12 +58,12 @@ void FeatureConfigStorageValidator::InitializeFeatures(
}
}
-void FeatureConfigStorageValidator::ClearForTesting() {
+void FeatureConfigEventStorageValidator::ClearForTesting() {
should_store_event_names_.clear();
longest_storage_times_.clear();
}
-void FeatureConfigStorageValidator::InitializeFeatureConfig(
+void FeatureConfigEventStorageValidator::InitializeFeatureConfig(
const FeatureConfig& feature_config) {
InitializeEventConfig(feature_config.used);
InitializeEventConfig(feature_config.trigger);
@@ -69,7 +72,7 @@ void FeatureConfigStorageValidator::InitializeFeatureConfig(
InitializeEventConfig(event_config);
}
-void FeatureConfigStorageValidator::InitializeEventConfig(
+void FeatureConfigEventStorageValidator::InitializeEventConfig(
const EventConfig& event_config) {
// Minimum storage time is 1 day.
if (event_config.storage < 1u)
@@ -84,4 +87,4 @@ void FeatureConfigStorageValidator::InitializeEventConfig(
longest_storage_times_[event_config.name] = event_config.storage;
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.h b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator.h
index c4a4fc555f1..b7dd0683a1f 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator.h
+++ b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator.h
@@ -2,29 +2,29 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_STORAGE_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_STORAGE_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_EVENT_STORAGE_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_EVENT_STORAGE_VALIDATOR_H_
#include <string>
#include <unordered_map>
#include <unordered_set>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/storage_validator.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/event_storage_validator.h"
+#include "components/feature_engagement/public/feature_list.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class Configuration;
struct EventConfig;
struct FeatureConfig;
-// A StorageValidator that uses the FeatureConfig as the source of truth.
-class FeatureConfigStorageValidator : public StorageValidator {
+// A EventStorageValidator that uses the FeatureConfig as the source of truth.
+class FeatureConfigEventStorageValidator : public EventStorageValidator {
public:
- FeatureConfigStorageValidator();
- ~FeatureConfigStorageValidator() override;
+ FeatureConfigEventStorageValidator();
+ ~FeatureConfigEventStorageValidator() override;
- // StorageValidator implementation.
+ // EventStorageValidator implementation.
bool ShouldStore(const std::string& event_name) const override;
bool ShouldKeep(const std::string& event_name,
uint32_t event_day,
@@ -34,8 +34,8 @@ class FeatureConfigStorageValidator : public StorageValidator {
void InitializeFeatures(FeatureVector features,
const Configuration& configuration);
- // Resets the full state of this StorageValidator. After calling this method
- // it is valid to call InitializeFeatures() again.
+ // Resets the full state of this EventStorageValidator. After calling this
+ // method it is valid to call InitializeFeatures() again.
void ClearForTesting();
private:
@@ -55,9 +55,9 @@ class FeatureConfigStorageValidator : public StorageValidator {
// as a number of days.
std::unordered_map<std::string, uint32_t> longest_storage_times_;
- DISALLOW_COPY_AND_ASSIGN(FeatureConfigStorageValidator);
+ DISALLOW_COPY_AND_ASSIGN(FeatureConfigEventStorageValidator);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_CONFIG_STORAGE_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_FEATURE_CONFIG_EVENT_STORAGE_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator_unittest.cc b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator_unittest.cc
index 3e7f8024b27..6ec6afe5376 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_config_storage_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_event_storage_validator_unittest.cc
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/feature_config_storage_validator.h"
+#include "components/feature_engagement/internal/feature_config_event_storage_validator.h"
#include <string>
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/test/scoped_feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -98,9 +98,9 @@ void InitializeStorageFeatureConfigs() {
EventConfig("unrelated_event", Comparator(ANY, 0), 0, 100));
}
-class FeatureConfigStorageValidatorTest : public ::testing::Test {
+class FeatureConfigEventStorageValidatorTest : public ::testing::Test {
public:
- FeatureConfigStorageValidatorTest() : current_day_(100) {
+ FeatureConfigEventStorageValidatorTest() : current_day_(100) {
InitializeStorageFeatureConfigs();
}
@@ -169,17 +169,17 @@ class FeatureConfigStorageValidatorTest : public ::testing::Test {
}
protected:
- FeatureConfigStorageValidator validator_;
+ FeatureConfigEventStorageValidator validator_;
uint32_t current_day_;
base::test::ScopedFeatureList scoped_feature_list_;
private:
- DISALLOW_COPY_AND_ASSIGN(FeatureConfigStorageValidatorTest);
+ DISALLOW_COPY_AND_ASSIGN(FeatureConfigEventStorageValidatorTest);
};
} // namespace
-TEST_F(FeatureConfigStorageValidatorTest,
+TEST_F(FeatureConfigEventStorageValidatorTest,
ShouldOnlyUseConfigFromEnabledFeatures) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {kTestFeatureBar});
@@ -194,7 +194,7 @@ TEST_F(FeatureConfigStorageValidatorTest,
EXPECT_FALSE(validator_.ShouldStore("barevent"));
}
-TEST_F(FeatureConfigStorageValidatorTest,
+TEST_F(FeatureConfigEventStorageValidatorTest,
ShouldStoreIfSingleConfigHasMinimum1DayStorage) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
@@ -213,7 +213,7 @@ TEST_F(FeatureConfigStorageValidatorTest,
}
}
-TEST_F(FeatureConfigStorageValidatorTest,
+TEST_F(FeatureConfigEventStorageValidatorTest,
ShouldStoreIfAnyConfigHasMinimum1DayStorage) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, {});
@@ -232,7 +232,7 @@ TEST_F(FeatureConfigStorageValidatorTest,
}
}
-TEST_F(FeatureConfigStorageValidatorTest,
+TEST_F(FeatureConfigEventStorageValidatorTest,
ShouldKeepIfSingleConfigMeetsEventAge) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo}, {});
@@ -262,7 +262,8 @@ TEST_F(FeatureConfigStorageValidatorTest,
}
}
-TEST_F(FeatureConfigStorageValidatorTest, ShouldKeepIfAnyConfigMeetsEventAge) {
+TEST_F(FeatureConfigEventStorageValidatorTest,
+ ShouldKeepIfAnyConfigMeetsEventAge) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar}, {});
UseConfigs(kNeverStored, kNeverStored);
@@ -291,4 +292,4 @@ TEST_F(FeatureConfigStorageValidatorTest, ShouldKeepIfAnyConfigMeetsEventAge) {
}
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/in_memory_event_store.cc b/chromium/components/feature_engagement/internal/in_memory_event_store.cc
new file mode 100644
index 00000000000..a19b41076fc
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/in_memory_event_store.cc
@@ -0,0 +1,51 @@
+// 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/feature_engagement/internal/in_memory_event_store.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/feature_engagement/internal/event_store.h"
+
+namespace feature_engagement {
+
+InMemoryEventStore::InMemoryEventStore(
+ std::unique_ptr<std::vector<Event>> events)
+ : EventStore(), events_(std::move(events)), ready_(false) {}
+
+InMemoryEventStore::InMemoryEventStore()
+ : InMemoryEventStore(base::MakeUnique<std::vector<Event>>()) {}
+
+InMemoryEventStore::~InMemoryEventStore() = default;
+
+void InMemoryEventStore::Load(const OnLoadedCallback& callback) {
+ HandleLoadResult(callback, true);
+}
+
+bool InMemoryEventStore::IsReady() const {
+ return ready_;
+}
+
+void InMemoryEventStore::WriteEvent(const Event& event) {
+ // Intentionally ignore all writes.
+}
+
+void InMemoryEventStore::DeleteEvent(const std::string& event_name) {
+ // Intentionally ignore all deletes.
+}
+
+void InMemoryEventStore::HandleLoadResult(const OnLoadedCallback& callback,
+ bool success) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, success, base::Passed(&events_)));
+ ready_ = success;
+}
+
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store.h b/chromium/components/feature_engagement/internal/in_memory_event_store.h
index 45652d63a0a..cf6da5016fc 100644
--- a/chromium/components/feature_engagement_tracker/internal/in_memory_store.h
+++ b/chromium/components/feature_engagement/internal/in_memory_event_store.h
@@ -2,25 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_IN_MEMORY_EVENT_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_IN_MEMORY_EVENT_STORE_H_
#include <vector>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/store.h"
+#include "components/feature_engagement/internal/event_store.h"
-namespace feature_engagement_tracker {
-// An InMemoryStore provides a DB layer that stores all data in-memory.
+namespace feature_engagement {
+// An InMemoryEventStore provides a DB layer that stores all data in-memory.
// All data is made available to this class during construction, and can be
// loaded once by a caller. All calls to WriteEvent(...) are ignored.
-class InMemoryStore : public Store {
+class InMemoryEventStore : public EventStore {
public:
- explicit InMemoryStore(std::unique_ptr<std::vector<Event>> events);
- InMemoryStore();
- ~InMemoryStore() override;
+ explicit InMemoryEventStore(std::unique_ptr<std::vector<Event>> events);
+ InMemoryEventStore();
+ ~InMemoryEventStore() override;
- // Store implementation.
+ // EventStore implementation.
void Load(const OnLoadedCallback& callback) override;
bool IsReady() const override;
void WriteEvent(const Event& event) override;
@@ -40,9 +40,9 @@ class InMemoryStore : public Store {
// invoked.
bool ready_;
- DISALLOW_COPY_AND_ASSIGN(InMemoryStore);
+ DISALLOW_COPY_AND_ASSIGN(InMemoryEventStore);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_IN_MEMORY_EVENT_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc b/chromium/components/feature_engagement/internal/in_memory_event_store_unittest.cc
index 593f866113d..e3c48510b30 100644
--- a/chromium/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
+++ b/chromium/components/feature_engagement/internal/in_memory_event_store_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/feature_engagement_tracker/internal/in_memory_store.h"
+#include "components/feature_engagement/internal/in_memory_event_store.h"
#include <memory>
#include <utility>
@@ -15,13 +15,13 @@
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
-class InMemoryStoreTest : public ::testing::Test {
+class InMemoryEventStoreTest : public ::testing::Test {
public:
- InMemoryStoreTest()
+ InMemoryEventStoreTest()
: load_callback_has_been_invoked_(false), last_result_(false) {}
void LoadCallback(bool success, std::unique_ptr<std::vector<Event>> events) {
@@ -38,7 +38,7 @@ class InMemoryStoreTest : public ::testing::Test {
};
} // namespace
-TEST_F(InMemoryStoreTest, LoadShouldProvideEventsAsCallback) {
+TEST_F(InMemoryEventStoreTest, LoadShouldProvideEventsAsCallback) {
std::unique_ptr<std::vector<Event>> events =
base::MakeUnique<std::vector<Event>>();
Event foo;
@@ -47,13 +47,13 @@ TEST_F(InMemoryStoreTest, LoadShouldProvideEventsAsCallback) {
events->push_back(bar);
// Create a new store and verify it's not ready yet.
- InMemoryStore store(std::move(events));
+ InMemoryEventStore store(std::move(events));
EXPECT_FALSE(store.IsReady());
// Load the data and ensure the callback is not immediately invoked, since the
// result should be posted.
- store.Load(
- base::Bind(&InMemoryStoreTest::LoadCallback, base::Unretained(this)));
+ store.Load(base::Bind(&InMemoryEventStoreTest::LoadCallback,
+ base::Unretained(this)));
EXPECT_FALSE(load_callback_has_been_invoked_);
// Run the message loop until it's idle to finish to ensure the result is
@@ -67,4 +67,4 @@ TEST_F(InMemoryStoreTest, LoadShouldProvideEventsAsCallback) {
EXPECT_TRUE(last_result_);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/init_aware_event_model.cc b/chromium/components/feature_engagement/internal/init_aware_event_model.cc
new file mode 100644
index 00000000000..9d53ab94bcc
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/init_aware_event_model.cc
@@ -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.
+
+#include "components/feature_engagement/internal/init_aware_event_model.h"
+
+#include "base/bind.h"
+
+namespace feature_engagement {
+
+InitAwareEventModel::InitAwareEventModel(
+ std::unique_ptr<EventModel> event_model)
+ : event_model_(std::move(event_model)),
+ initialization_complete_(false),
+ weak_ptr_factory_(this) {
+ DCHECK(event_model_);
+}
+
+InitAwareEventModel::~InitAwareEventModel() = default;
+
+void InitAwareEventModel::Initialize(
+ const OnModelInitializationFinished& callback,
+ uint32_t current_day) {
+ event_model_->Initialize(
+ base::Bind(&InitAwareEventModel::OnInitializeComplete,
+ weak_ptr_factory_.GetWeakPtr(), callback),
+ current_day);
+}
+
+bool InitAwareEventModel::IsReady() const {
+ return event_model_->IsReady();
+}
+
+const Event* InitAwareEventModel::GetEvent(
+ const std::string& event_name) const {
+ return event_model_->GetEvent(event_name);
+}
+
+void InitAwareEventModel::IncrementEvent(const std::string& event_name,
+ uint32_t current_day) {
+ if (IsReady()) {
+ event_model_->IncrementEvent(event_name, current_day);
+ return;
+ }
+
+ if (initialization_complete_)
+ return;
+
+ queued_events_.push_back(std::tie(event_name, current_day));
+}
+
+void InitAwareEventModel::OnInitializeComplete(
+ const OnModelInitializationFinished& callback,
+ bool success) {
+ initialization_complete_ = true;
+ if (success) {
+ for (auto& event : queued_events_)
+ event_model_->IncrementEvent(std::get<0>(event), std::get<1>(event));
+ }
+ queued_events_.clear();
+
+ callback.Run(success);
+}
+
+size_t InitAwareEventModel::GetQueuedEventCountForTesting() {
+ return queued_events_.size();
+}
+
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/init_aware_model.h b/chromium/components/feature_engagement/internal/init_aware_event_model.h
index 89b0e4513fc..ed034b7cca4 100644
--- a/chromium/components/feature_engagement_tracker/internal/init_aware_model.h
+++ b/chromium/components/feature_engagement/internal/init_aware_event_model.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_INIT_AWARE_MODEL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_INIT_AWARE_MODEL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_INIT_AWARE_EVENT_MODEL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_INIT_AWARE_EVENT_MODEL_H_
#include <stdint.h>
@@ -13,16 +13,16 @@
#include <vector>
#include "base/memory/weak_ptr.h"
-#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement/internal/event_model.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-class InitAwareModel : public Model {
+class InitAwareEventModel : public EventModel {
public:
- InitAwareModel(std::unique_ptr<Model> model);
- ~InitAwareModel() override;
+ InitAwareEventModel(std::unique_ptr<EventModel> event_model);
+ ~InitAwareEventModel() override;
- // Model implementation.
+ // EventModel implementation.
void Initialize(const OnModelInitializationFinished& callback,
uint32_t current_day) override;
bool IsReady() const override;
@@ -36,19 +36,19 @@ class InitAwareModel : public Model {
void OnInitializeComplete(const OnModelInitializationFinished& callback,
bool success);
- std::unique_ptr<Model> model_;
+ std::unique_ptr<EventModel> event_model_;
std::vector<std::tuple<std::string, uint32_t>> queued_events_;
// Whether the initialization has completed. This will be set to true once
- // the underlying model has been initialized, regardless of whether the
+ // the underlying event model has been initialized, regardless of whether the
// result was a success or not.
bool initialization_complete_;
- base::WeakPtrFactory<InitAwareModel> weak_ptr_factory_;
+ base::WeakPtrFactory<InitAwareEventModel> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(InitAwareModel);
+ DISALLOW_COPY_AND_ASSIGN(InitAwareEventModel);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_INIT_AWARE_MODEL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_INIT_AWARE_EVENT_MODEL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc b/chromium/components/feature_engagement/internal/init_aware_event_model_unittest.cc
index 00f38943f14..b3129588b8f 100644
--- a/chromium/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc
+++ b/chromium/components/feature_engagement/internal/init_aware_event_model_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/feature_engagement_tracker/internal/init_aware_model.h"
+#include "components/feature_engagement/internal/init_aware_event_model.h"
#include <memory>
@@ -10,8 +10,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/internal/test/event_util.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/test/event_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,16 +20,16 @@ using testing::Return;
using testing::SaveArg;
using testing::Sequence;
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
-class MockModel : public Model {
+class MockEventModel : public EventModel {
public:
- MockModel() = default;
- ~MockModel() override = default;
+ MockEventModel() = default;
+ ~MockEventModel() override = default;
- // Model implementation.
+ // EventModel implementation.
MOCK_METHOD2(Initialize,
void(const OnModelInitializationFinished&, uint32_t));
MOCK_CONST_METHOD0(IsReady, bool());
@@ -37,46 +37,46 @@ class MockModel : public Model {
MOCK_METHOD2(IncrementEvent, void(const std::string&, uint32_t));
private:
- DISALLOW_COPY_AND_ASSIGN(MockModel);
+ DISALLOW_COPY_AND_ASSIGN(MockEventModel);
};
-class InitAwareModelTest : public testing::Test {
+class InitAwareEventModelTest : public testing::Test {
public:
- InitAwareModelTest() : mocked_model_(nullptr) {
- load_callback_ = base::Bind(&InitAwareModelTest::OnModelInitialized,
+ InitAwareEventModelTest() : mocked_model_(nullptr) {
+ load_callback_ = base::Bind(&InitAwareEventModelTest::OnModelInitialized,
base::Unretained(this));
}
- ~InitAwareModelTest() override = default;
+ ~InitAwareEventModelTest() override = default;
void SetUp() override {
- auto mocked_model = base::MakeUnique<MockModel>();
+ auto mocked_model = base::MakeUnique<MockEventModel>();
mocked_model_ = mocked_model.get();
- model_ = base::MakeUnique<InitAwareModel>(std::move(mocked_model));
+ model_ = base::MakeUnique<InitAwareEventModel>(std::move(mocked_model));
}
protected:
void OnModelInitialized(bool success) { load_success_ = success; }
- std::unique_ptr<InitAwareModel> model_;
- MockModel* mocked_model_;
+ std::unique_ptr<InitAwareEventModel> model_;
+ MockEventModel* mocked_model_;
// Load callback tracking.
base::Optional<bool> load_success_;
- Model::OnModelInitializationFinished load_callback_;
+ EventModel::OnModelInitializationFinished load_callback_;
private:
- DISALLOW_COPY_AND_ASSIGN(InitAwareModelTest);
+ DISALLOW_COPY_AND_ASSIGN(InitAwareEventModelTest);
};
} // namespace
-TEST_F(InitAwareModelTest, PassThroughIsReady) {
+TEST_F(InitAwareEventModelTest, PassThroughIsReady) {
EXPECT_CALL(*mocked_model_, IsReady()).Times(1);
model_->IsReady();
}
-TEST_F(InitAwareModelTest, PassThroughGetEvent) {
+TEST_F(InitAwareEventModelTest, PassThroughGetEvent) {
Event foo;
foo.set_name("foo");
test::SetEventCountForDay(&foo, 1, 1);
@@ -89,7 +89,7 @@ TEST_F(InitAwareModelTest, PassThroughGetEvent) {
EXPECT_EQ(nullptr, model_->GetEvent("bar"));
}
-TEST_F(InitAwareModelTest, PassThroughIncrementEvent) {
+TEST_F(InitAwareEventModelTest, PassThroughIncrementEvent) {
EXPECT_CALL(*mocked_model_, IsReady()).WillRepeatedly(Return(true));
Sequence sequence;
@@ -101,7 +101,7 @@ TEST_F(InitAwareModelTest, PassThroughIncrementEvent) {
EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting());
}
-TEST_F(InitAwareModelTest, QueuedIncrementEvent) {
+TEST_F(InitAwareEventModelTest, QueuedIncrementEvent) {
{
EXPECT_CALL(*mocked_model_, IsReady()).WillRepeatedly(Return(false));
EXPECT_CALL(*mocked_model_, IncrementEvent(_, _)).Times(0);
@@ -110,7 +110,7 @@ TEST_F(InitAwareModelTest, QueuedIncrementEvent) {
model_->IncrementEvent("bar", 1U);
}
- Model::OnModelInitializationFinished callback;
+ EventModel::OnModelInitializationFinished callback;
EXPECT_CALL(*mocked_model_, Initialize(_, 2U))
.WillOnce(SaveArg<0>(&callback));
model_->Initialize(load_callback_, 2U);
@@ -134,7 +134,7 @@ TEST_F(InitAwareModelTest, QueuedIncrementEvent) {
EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting());
}
-TEST_F(InitAwareModelTest, QueuedIncrementEventWithUnsuccessfulInit) {
+TEST_F(InitAwareEventModelTest, QueuedIncrementEventWithUnsuccessfulInit) {
{
EXPECT_CALL(*mocked_model_, IsReady()).WillRepeatedly(Return(false));
EXPECT_CALL(*mocked_model_, IncrementEvent(_, _)).Times(0);
@@ -143,7 +143,7 @@ TEST_F(InitAwareModelTest, QueuedIncrementEventWithUnsuccessfulInit) {
model_->IncrementEvent("bar", 1U);
}
- Model::OnModelInitializationFinished callback;
+ EventModel::OnModelInitializationFinished callback;
EXPECT_CALL(*mocked_model_, Initialize(_, 2U))
.WillOnce(SaveArg<0>(&callback));
model_->Initialize(load_callback_, 2U);
@@ -167,4 +167,4 @@ TEST_F(InitAwareModelTest, QueuedIncrementEventWithUnsuccessfulInit) {
EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/never_availability_model.cc b/chromium/components/feature_engagement/internal/never_availability_model.cc
index 55ecbe545dd..1b4615d8382 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_availability_model.cc
+++ b/chromium/components/feature_engagement/internal/never_availability_model.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/feature_engagement_tracker/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
#include <utility>
@@ -12,7 +12,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
NeverAvailabilityModel::NeverAvailabilityModel() : ready_(false) {}
@@ -42,4 +42,4 @@ void NeverAvailabilityModel::ForwardedOnInitializedCallback(
ready_ = true;
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/never_availability_model.h b/chromium/components/feature_engagement/internal/never_availability_model.h
index 1a64a5deb81..9d30f1a83ad 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_availability_model.h
+++ b/chromium/components/feature_engagement/internal/never_availability_model.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
#include <stdint.h>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/availability_model.h"
+#include "components/feature_engagement/internal/availability_model.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// An AvailabilityModel that never has any data, and is ready after having been
// initialized.
@@ -38,6 +38,6 @@ class NeverAvailabilityModel : public AvailabilityModel {
DISALLOW_COPY_AND_ASSIGN(NeverAvailabilityModel);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_AVAILABILITY_MODEL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/never_availability_model_unittest.cc b/chromium/components/feature_engagement/internal/never_availability_model_unittest.cc
index a1c143c3ab6..099df237f2e 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_availability_model_unittest.cc
+++ b/chromium/components/feature_engagement/internal/never_availability_model_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/feature_engagement_tracker/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
#include "base/bind.h"
#include "base/feature_list.h"
@@ -11,7 +11,7 @@
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -70,4 +70,4 @@ TEST_F(NeverAvailabilityModelTest, ShouldBeReadyAfterInitialization) {
EXPECT_TRUE(success_.value());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc b/chromium/components/feature_engagement/internal/never_condition_validator.cc
index 535a51717e7..038eedf610e 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/never_condition_validator.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/feature_engagement_tracker/internal/never_condition_validator.h"
+#include "components/feature_engagement/internal/never_condition_validator.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
NeverConditionValidator::NeverConditionValidator() = default;
@@ -13,7 +13,7 @@ NeverConditionValidator::~NeverConditionValidator() = default;
ConditionValidator::Result NeverConditionValidator::MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const {
return ConditionValidator::Result(false);
@@ -23,4 +23,4 @@ void NeverConditionValidator::NotifyIsShowing(const base::Feature& feature) {}
void NeverConditionValidator::NotifyDismissed(const base::Feature& feature) {}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.h b/chromium/components/feature_engagement/internal/never_condition_validator.h
index bf4dc18ff89..b915f838096 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/never_condition_validator.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/condition_validator.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/condition_validator.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class AvailabilityModel;
-class Model;
+class EventModel;
// An ConditionValidator that never acknowledges that a feature has met its
// conditions.
@@ -28,7 +28,7 @@ class NeverConditionValidator : public ConditionValidator {
ConditionValidator::Result MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const override;
void NotifyIsShowing(const base::Feature& feature) override;
@@ -38,6 +38,6 @@ class NeverConditionValidator : public ConditionValidator {
DISALLOW_COPY_AND_ASSIGN(NeverConditionValidator);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc
index 956998f92cc..bcf1b52cb80 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/never_condition_validator.h"
+#include "components/feature_engagement/internal/never_condition_validator.h"
#include <string>
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/never_availability_model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -22,10 +22,10 @@ const base::Feature kTestFeatureFoo{"test_foo",
const base::Feature kTestFeatureBar{"test_bar",
base::FEATURE_DISABLED_BY_DEFAULT};
-// A Model that is always postive to show in-product help.
-class TestModel : public Model {
+// A EventModel that is always postive to show in-product help.
+class TestEventModel : public EventModel {
public:
- TestModel() = default;
+ TestEventModel() = default;
void Initialize(const OnModelInitializationFinished& callback,
uint32_t current_day) override {}
@@ -39,7 +39,7 @@ class TestModel : public Model {
void IncrementEvent(const std::string& event_name, uint32_t day) override {}
private:
- DISALLOW_COPY_AND_ASSIGN(TestModel);
+ DISALLOW_COPY_AND_ASSIGN(TestEventModel);
};
class NeverConditionValidatorTest : public ::testing::Test {
@@ -47,7 +47,7 @@ class NeverConditionValidatorTest : public ::testing::Test {
NeverConditionValidatorTest() = default;
protected:
- TestModel model_;
+ TestEventModel event_model_;
NeverAvailabilityModel availability_model_;
NeverConditionValidator validator_;
@@ -59,13 +59,13 @@ class NeverConditionValidatorTest : public ::testing::Test {
TEST_F(NeverConditionValidatorTest, ShouldNeverMeetConditions) {
EXPECT_FALSE(validator_
- .MeetsConditions(kTestFeatureFoo, FeatureConfig(), model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, FeatureConfig(),
+ event_model_, availability_model_, 0u)
.NoErrors());
EXPECT_FALSE(validator_
- .MeetsConditions(kTestFeatureBar, FeatureConfig(), model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureBar, FeatureConfig(),
+ event_model_, availability_model_, 0u)
.NoErrors());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/never_event_storage_validator.cc b/chromium/components/feature_engagement/internal/never_event_storage_validator.cc
new file mode 100644
index 00000000000..521cb5532c9
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/never_event_storage_validator.cc
@@ -0,0 +1,24 @@
+// 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/feature_engagement/internal/never_event_storage_validator.h"
+
+namespace feature_engagement {
+
+NeverEventStorageValidator::NeverEventStorageValidator() = default;
+
+NeverEventStorageValidator::~NeverEventStorageValidator() = default;
+
+bool NeverEventStorageValidator::ShouldStore(
+ const std::string& event_name) const {
+ return false;
+}
+
+bool NeverEventStorageValidator::ShouldKeep(const std::string& event_name,
+ uint32_t event_day,
+ uint32_t current_day) const {
+ return false;
+}
+
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/never_event_storage_validator.h b/chromium/components/feature_engagement/internal/never_event_storage_validator.h
new file mode 100644
index 00000000000..10ed6798176
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/never_event_storage_validator.h
@@ -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.
+
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_EVENT_STORAGE_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_EVENT_STORAGE_VALIDATOR_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/feature_engagement/internal/event_storage_validator.h"
+
+namespace feature_engagement {
+
+// A EventStorageValidator that never acknowledges that an event should be kept
+// or stored.
+class NeverEventStorageValidator : public EventStorageValidator {
+ public:
+ NeverEventStorageValidator();
+ ~NeverEventStorageValidator() override;
+
+ // EventStorageValidator implementation.
+ bool ShouldStore(const std::string& event_name) const override;
+ bool ShouldKeep(const std::string& event_name,
+ uint32_t event_day,
+ uint32_t current_day) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NeverEventStorageValidator);
+};
+
+} // namespace feature_engagement
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_NEVER_EVENT_STORAGE_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/never_storage_validator_unittest.cc b/chromium/components/feature_engagement/internal/never_event_storage_validator_unittest.cc
index a2d77281ae7..42157625e76 100644
--- a/chromium/components/feature_engagement_tracker/internal/never_storage_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/never_event_storage_validator_unittest.cc
@@ -2,35 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/never_storage_validator.h"
+#include "components/feature_engagement/internal/never_event_storage_validator.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
-class NeverStorageValidatorTest : public ::testing::Test {
+class NeverEventStorageValidatorTest : public ::testing::Test {
public:
- NeverStorageValidatorTest() = default;
+ NeverEventStorageValidatorTest() = default;
protected:
- NeverStorageValidator validator_;
+ NeverEventStorageValidator validator_;
private:
- DISALLOW_COPY_AND_ASSIGN(NeverStorageValidatorTest);
+ DISALLOW_COPY_AND_ASSIGN(NeverEventStorageValidatorTest);
};
} // namespace
-TEST_F(NeverStorageValidatorTest, ShouldNeverKeep) {
+TEST_F(NeverEventStorageValidatorTest, ShouldNeverKeep) {
EXPECT_FALSE(validator_.ShouldStore("dummy event"));
}
-TEST_F(NeverStorageValidatorTest, ShouldNeverStore) {
+TEST_F(NeverEventStorageValidatorTest, ShouldNeverStore) {
EXPECT_FALSE(validator_.ShouldKeep("dummy event", 99, 100));
EXPECT_FALSE(validator_.ShouldKeep("dummy event", 100, 100));
EXPECT_FALSE(validator_.ShouldKeep("dummy event", 101, 100));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc b/chromium/components/feature_engagement/internal/once_condition_validator.cc
index 1ae562aaf55..f3068f318e3 100644
--- a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/once_condition_validator.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/feature_engagement_tracker/internal/once_condition_validator.h"
+#include "components/feature_engagement/internal/once_condition_validator.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
OnceConditionValidator::OnceConditionValidator() = default;
@@ -16,16 +16,18 @@ OnceConditionValidator::~OnceConditionValidator() = default;
ConditionValidator::Result OnceConditionValidator::MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const {
ConditionValidator::Result result(true);
- result.event_model_ready_ok = model.IsReady();
+ result.event_model_ready_ok = event_model.IsReady();
result.currently_showing_ok = currently_showing_feature_.empty();
result.config_ok = config.valid;
+ result.trigger_ok =
+ shown_features_.find(feature.name) == shown_features_.end();
result.session_rate_ok =
shown_features_.find(feature.name) == shown_features_.end();
@@ -44,4 +46,4 @@ void OnceConditionValidator::NotifyDismissed(const base::Feature& feature) {
currently_showing_feature_.clear();
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.h b/chromium/components/feature_engagement/internal/once_condition_validator.h
index 53cca7bc521..0bafc34e13c 100644
--- a/chromium/components/feature_engagement_tracker/internal/once_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/once_condition_validator.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
#include <unordered_set>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/condition_validator.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/condition_validator.h"
+#include "components/feature_engagement/public/feature_list.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class AvailabilityModel;
-class Model;
+class EventModel;
// An ConditionValidator that will ensure that each base::Feature will meet
// conditions maximum one time for any given session.
// It has the following requirements:
-// - The Model is ready.
+// - The EventModel is ready.
// - No other in-product help is currently showing.
// - FeatureConfig for the feature is valid.
// - This is the first time the given base::Feature meets all above stated
@@ -41,7 +41,7 @@ class OnceConditionValidator : public ConditionValidator {
ConditionValidator::Result MeetsConditions(
const base::Feature& feature,
const FeatureConfig& config,
- const Model& model,
+ const EventModel& event_model,
const AvailabilityModel& availability_model,
uint32_t current_day) const override;
void NotifyIsShowing(const base::Feature& feature) override;
@@ -58,6 +58,6 @@ class OnceConditionValidator : public ConditionValidator {
DISALLOW_COPY_AND_ASSIGN(OnceConditionValidator);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_ONCE_CONDITION_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc
index a60f6a6ed66..cdfc1a6da9d 100644
--- a/chromium/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/once_condition_validator.h"
+#include "components/feature_engagement/internal/once_condition_validator.h"
#include <string>
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/model.h"
-#include "components/feature_engagement_tracker/internal/never_availability_model.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/event_model.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -25,10 +25,10 @@ const base::Feature kTestFeatureBar{"test_bar",
FeatureConfig kValidFeatureConfig;
FeatureConfig kInvalidFeatureConfig;
-// A Model that is easily configurable at runtime.
-class TestModel : public Model {
+// A EventModel that is easily configurable at runtime.
+class TestEventModel : public EventModel {
public:
- TestModel() : ready_(false) { kValidFeatureConfig.valid = true; }
+ TestEventModel() : ready_(false) { kValidFeatureConfig.valid = true; }
void Initialize(const OnModelInitializationFinished& callback,
uint32_t current_day) override {}
@@ -50,13 +50,13 @@ class TestModel : public Model {
class OnceConditionValidatorTest : public ::testing::Test {
public:
OnceConditionValidatorTest() {
- // By default, model should be ready.
- model_.SetIsReady(true);
+ // By default, event model should be ready.
+ event_model_.SetIsReady(true);
}
protected:
EditableConfiguration configuration_;
- TestModel model_;
+ TestEventModel event_model_;
NeverAvailabilityModel availability_model_;
OnceConditionValidator validator_;
@@ -69,14 +69,16 @@ class OnceConditionValidatorTest : public ::testing::Test {
TEST_F(OnceConditionValidatorTest, EnabledFeatureShouldTriggerOnce) {
// Only the first call to MeetsConditions() should lead to enlightenment.
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
validator_.NotifyIsShowing(kTestFeatureFoo);
- ConditionValidator::Result result = validator_.MeetsConditions(
- kTestFeatureFoo, kValidFeatureConfig, model_, availability_model_, 0u);
+ ConditionValidator::Result result =
+ validator_.MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.session_rate_ok);
+ EXPECT_FALSE(result.trigger_ok);
}
TEST_F(OnceConditionValidatorTest,
@@ -86,65 +88,68 @@ TEST_F(OnceConditionValidatorTest,
// captures a different behavior than the
// OnlyOneFeatureShouldTriggerPerSession test below.
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureBar, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureBar, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
}
TEST_F(OnceConditionValidatorTest, StillTriggerWhenAllFeaturesDisabled) {
// No features should get to show enlightenment.
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureBar, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureBar, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
}
TEST_F(OnceConditionValidatorTest, OnlyTriggerWhenModelIsReady) {
- model_.SetIsReady(false);
- ConditionValidator::Result result = validator_.MeetsConditions(
- kTestFeatureFoo, kValidFeatureConfig, model_, availability_model_, 0u);
+ event_model_.SetIsReady(false);
+ ConditionValidator::Result result =
+ validator_.MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.event_model_ready_ok);
- model_.SetIsReady(true);
+ event_model_.SetIsReady(true);
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
}
TEST_F(OnceConditionValidatorTest, OnlyTriggerIfNothingElseIsShowing) {
validator_.NotifyIsShowing(kTestFeatureBar);
- ConditionValidator::Result result = validator_.MeetsConditions(
- kTestFeatureFoo, kValidFeatureConfig, model_, availability_model_, 0u);
+ ConditionValidator::Result result =
+ validator_.MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.currently_showing_ok);
validator_.NotifyDismissed(kTestFeatureBar);
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
}
TEST_F(OnceConditionValidatorTest, DoNotTriggerForInvalidConfig) {
- ConditionValidator::Result result = validator_.MeetsConditions(
- kTestFeatureFoo, kInvalidFeatureConfig, model_, availability_model_, 0u);
+ ConditionValidator::Result result =
+ validator_.MeetsConditions(kTestFeatureFoo, kInvalidFeatureConfig,
+ event_model_, availability_model_, 0u);
EXPECT_FALSE(result.NoErrors());
EXPECT_FALSE(result.config_ok);
EXPECT_TRUE(validator_
- .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig, model_,
- availability_model_, 0u)
+ .MeetsConditions(kTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_, 0u)
.NoErrors());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_store.cc b/chromium/components/feature_engagement/internal/persistent_availability_store.cc
index b1086579a11..d5f4fd0e450 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_store.cc
+++ b/chromium/components/feature_engagement/internal/persistent_availability_store.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/feature_engagement_tracker/internal/availability_store.h"
+#include "components/feature_engagement/internal/persistent_availability_store.h"
#include <memory>
#include <string>
@@ -13,12 +13,12 @@
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
-#include "components/feature_engagement_tracker/internal/proto/availability.pb.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/proto/availability.pb.h"
+#include "components/feature_engagement/internal/stats.h"
+#include "components/feature_engagement/public/feature_list.h"
#include "components/leveldb_proto/proto_database.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -31,7 +31,7 @@ const char kDatabaseUMAName[] = "FeatureEngagementTrackerAvailabilityStore";
void OnDBUpdateComplete(
std::unique_ptr<leveldb_proto::ProtoDatabase<Availability>> db,
- AvailabilityStore::OnLoadedCallback on_loaded_callback,
+ PersistentAvailabilityStore::OnLoadedCallback on_loaded_callback,
std::unique_ptr<std::map<std::string, uint32_t>> feature_availabilities,
bool success) {
stats::RecordDbUpdate(success, stats::StoreType::AVAILABILITY_STORE);
@@ -41,7 +41,7 @@ void OnDBUpdateComplete(
void OnDBLoadComplete(
std::unique_ptr<leveldb_proto::ProtoDatabase<Availability>> db,
FeatureVector feature_filter,
- AvailabilityStore::OnLoadedCallback on_loaded_callback,
+ PersistentAvailabilityStore::OnLoadedCallback on_loaded_callback,
uint32_t current_day,
bool success,
std::unique_ptr<std::vector<Availability>> availabilities) {
@@ -122,7 +122,7 @@ void OnDBLoadComplete(
void OnDBInitComplete(
std::unique_ptr<leveldb_proto::ProtoDatabase<Availability>> db,
FeatureVector feature_filter,
- AvailabilityStore::OnLoadedCallback on_loaded_callback,
+ PersistentAvailabilityStore::OnLoadedCallback on_loaded_callback,
uint32_t current_day,
bool success) {
stats::RecordDbInitEvent(success, stats::StoreType::AVAILABILITY_STORE);
@@ -142,11 +142,11 @@ void OnDBInitComplete(
} // namespace
// static
-void AvailabilityStore::LoadAndUpdateStore(
+void PersistentAvailabilityStore::LoadAndUpdateStore(
const base::FilePath& storage_dir,
std::unique_ptr<leveldb_proto::ProtoDatabase<Availability>> db,
FeatureVector feature_filter,
- AvailabilityStore::OnLoadedCallback on_loaded_callback,
+ PersistentAvailabilityStore::OnLoadedCallback on_loaded_callback,
uint32_t current_day) {
auto* db_ptr = db.get();
db_ptr->Init(kDatabaseUMAName, storage_dir,
@@ -155,4 +155,4 @@ void AvailabilityStore::LoadAndUpdateStore(
std::move(on_loaded_callback), current_day));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_store.h b/chromium/components/feature_engagement/internal/persistent_availability_store.h
index 9326940fadd..808d0cfb3fb 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_store.h
+++ b/chromium/components/feature_engagement/internal/persistent_availability_store.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_STORE_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_STORE_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_AVAILABILITY_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_AVAILABILITY_STORE_H_
#include <stdint.h>
@@ -12,19 +12,19 @@
#include "base/callback_forward.h"
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/proto/availability.pb.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/proto/availability.pb.h"
+#include "components/feature_engagement/public/feature_list.h"
#include "components/leveldb_proto/proto_database.h"
namespace base {
class FilePath;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-// An AvailabilityStore provides a way to load and update the availability date
-// for all registered features.
-class AvailabilityStore {
+// An PersistentAvailabilityStore provides a way to load and update the
+// availability date for all registered features.
+class PersistentAvailabilityStore {
public:
// Invoked when the availability data has finished loading, and whether the
// load was a success. In the case of a failure, the map argument will be
@@ -50,12 +50,12 @@ class AvailabilityStore {
uint32_t current_day);
private:
- AvailabilityStore() = default;
- ~AvailabilityStore() = default;
+ PersistentAvailabilityStore() = default;
+ ~PersistentAvailabilityStore() = default;
- DISALLOW_COPY_AND_ASSIGN(AvailabilityStore);
+ DISALLOW_COPY_AND_ASSIGN(PersistentAvailabilityStore);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_AVAILABILITY_STORE_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_AVAILABILITY_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc b/chromium/components/feature_engagement/internal/persistent_availability_store_unittest.cc
index cfa4a5831c7..8e204e92bae 100644
--- a/chromium/components/feature_engagement_tracker/internal/availability_store_unittest.cc
+++ b/chromium/components/feature_engagement/internal/persistent_availability_store_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/feature_engagement_tracker/internal/availability_store.h"
+#include "components/feature_engagement/internal/persistent_availability_store.h"
#include <stdint.h>
@@ -18,13 +18,13 @@
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/test/scoped_feature_list.h"
-#include "components/feature_engagement_tracker/internal/proto/availability.pb.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/proto/availability.pb.h"
+#include "components/feature_engagement/public/feature_list.h"
#include "components/leveldb_proto/proto_database.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
const base::Feature kTestFeatureFoo{"test_foo",
@@ -43,16 +43,16 @@ Availability CreateAvailability(const base::Feature& feature, uint32_t day) {
return availability;
}
-class AvailabilityStoreTest : public testing::Test {
+class PersistentAvailabilityStoreTest : public testing::Test {
public:
- AvailabilityStoreTest()
+ PersistentAvailabilityStoreTest()
: db_(nullptr),
storage_dir_(FILE_PATH_LITERAL("/persistent/store/lalala")) {
- load_callback_ = base::Bind(&AvailabilityStoreTest::LoadCallback,
+ load_callback_ = base::Bind(&PersistentAvailabilityStoreTest::LoadCallback,
base::Unretained(this));
}
- ~AvailabilityStoreTest() override = default;
+ ~PersistentAvailabilityStoreTest() override = default;
// Creates a DB and stores off a pointer to it as a member.
std::unique_ptr<leveldb_proto::test::FakeDB<Availability>> CreateDB() {
@@ -73,7 +73,7 @@ class AvailabilityStoreTest : public testing::Test {
base::test::ScopedFeatureList scoped_feature_list_;
// The end result of the store pipeline.
- AvailabilityStore::OnLoadedCallback load_callback_;
+ PersistentAvailabilityStore::OnLoadedCallback load_callback_;
// Callback results.
base::Optional<bool> load_successful_;
@@ -90,15 +90,15 @@ class AvailabilityStoreTest : public testing::Test {
base::FilePath storage_dir_;
private:
- DISALLOW_COPY_AND_ASSIGN(AvailabilityStoreTest);
+ DISALLOW_COPY_AND_ASSIGN(PersistentAvailabilityStoreTest);
};
} // namespace
-TEST_F(AvailabilityStoreTest, StorageDirectory) {
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+TEST_F(PersistentAvailabilityStoreTest, StorageDirectory) {
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(true);
EXPECT_EQ(storage_dir_, db_->GetDirectory());
@@ -106,10 +106,10 @@ TEST_F(AvailabilityStoreTest, StorageDirectory) {
db_->LoadCallback(false);
}
-TEST_F(AvailabilityStoreTest, InitFail) {
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+TEST_F(PersistentAvailabilityStoreTest, InitFail) {
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(false);
@@ -119,10 +119,10 @@ TEST_F(AvailabilityStoreTest, InitFail) {
EXPECT_EQ(0u, db_availabilities_.size());
}
-TEST_F(AvailabilityStoreTest, LoadFail) {
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+TEST_F(PersistentAvailabilityStoreTest, LoadFail) {
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(true);
EXPECT_FALSE(load_successful_.has_value());
@@ -135,10 +135,10 @@ TEST_F(AvailabilityStoreTest, LoadFail) {
EXPECT_EQ(0u, db_availabilities_.size());
}
-TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateFailed) {
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+TEST_F(PersistentAvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateFailed) {
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(true);
EXPECT_FALSE(load_successful_.has_value());
@@ -154,10 +154,10 @@ TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateFailed) {
EXPECT_EQ(0u, db_availabilities_.size());
}
-TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateOK) {
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+TEST_F(PersistentAvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateOK) {
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(true);
EXPECT_FALSE(load_successful_.has_value());
@@ -173,7 +173,7 @@ TEST_F(AvailabilityStoreTest, EmptyDBEmptyFeatureFilterUpdateOK) {
EXPECT_EQ(0u, db_availabilities_.size());
}
-TEST_F(AvailabilityStoreTest, AllNewFeatures) {
+TEST_F(PersistentAvailabilityStoreTest, AllNewFeatures) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar},
{kTestFeatureQux});
@@ -182,7 +182,7 @@ TEST_F(AvailabilityStoreTest, AllNewFeatures) {
feature_filter.push_back(&kTestFeatureBar); // Enabled. Not in DB.
feature_filter.push_back(&kTestFeatureQux); // Disabled. Not in DB.
- AvailabilityStore::LoadAndUpdateStore(
+ PersistentAvailabilityStore::LoadAndUpdateStore(
storage_dir_, CreateDB(), feature_filter, std::move(load_callback_), 14u);
db_->InitCallback(true);
@@ -213,7 +213,7 @@ TEST_F(AvailabilityStoreTest, AllNewFeatures) {
EXPECT_EQ(14u, db_availabilities_[kTestFeatureBar.name].day());
}
-TEST_F(AvailabilityStoreTest, TestAllFilterCombinations) {
+TEST_F(PersistentAvailabilityStoreTest, TestAllFilterCombinations) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar},
{kTestFeatureQux, kTestFeatureNop});
@@ -228,7 +228,7 @@ TEST_F(AvailabilityStoreTest, TestAllFilterCombinations) {
db_availabilities_[kTestFeatureNop.name] =
CreateAvailability(kTestFeatureNop, 8u);
- AvailabilityStore::LoadAndUpdateStore(
+ PersistentAvailabilityStore::LoadAndUpdateStore(
storage_dir_, CreateDB(), feature_filter, std::move(load_callback_), 14u);
db_->InitCallback(true);
@@ -259,7 +259,7 @@ TEST_F(AvailabilityStoreTest, TestAllFilterCombinations) {
EXPECT_EQ(10u, db_availabilities_[kTestFeatureBar.name].day());
}
-TEST_F(AvailabilityStoreTest, TestAllCombinationsEmptyFilter) {
+TEST_F(PersistentAvailabilityStoreTest, TestAllCombinationsEmptyFilter) {
scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar},
{kTestFeatureQux, kTestFeatureNop});
@@ -274,9 +274,9 @@ TEST_F(AvailabilityStoreTest, TestAllCombinationsEmptyFilter) {
db_availabilities_[kTestFeatureNop.name] =
CreateAvailability(kTestFeatureNop, 8u);
- AvailabilityStore::LoadAndUpdateStore(storage_dir_, CreateDB(),
- FeatureVector(),
- std::move(load_callback_), 14u);
+ PersistentAvailabilityStore::LoadAndUpdateStore(
+ storage_dir_, CreateDB(), FeatureVector(), std::move(load_callback_),
+ 14u);
db_->InitCallback(true);
EXPECT_FALSE(load_successful_.has_value());
@@ -292,4 +292,4 @@ TEST_F(AvailabilityStoreTest, TestAllCombinationsEmptyFilter) {
EXPECT_EQ(0u, db_availabilities_.size());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/persistent_store.cc b/chromium/components/feature_engagement/internal/persistent_event_store.cc
index 9be61087b9c..6dfccc25a70 100644
--- a/chromium/components/feature_engagement_tracker/internal/persistent_store.cc
+++ b/chromium/components/feature_engagement/internal/persistent_event_store.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/persistent_store.h"
+#include "components/feature_engagement/internal/persistent_event_store.h"
#include <vector>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
+#include "components/feature_engagement/internal/stats.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
// Corresponds to a UMA suffix "LevelDBOpenResults" in histograms.xml.
// Please do not change.
@@ -25,7 +25,7 @@ void NoopUpdateCallback(bool success) {
} // namespace
-PersistentStore::PersistentStore(
+PersistentEventStore::PersistentEventStore(
const base::FilePath& storage_dir,
std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db)
: storage_dir_(storage_dir),
@@ -33,21 +33,21 @@ PersistentStore::PersistentStore(
ready_(false),
weak_ptr_factory_(this) {}
-PersistentStore::~PersistentStore() = default;
+PersistentEventStore::~PersistentEventStore() = default;
-void PersistentStore::Load(const OnLoadedCallback& callback) {
+void PersistentEventStore::Load(const OnLoadedCallback& callback) {
DCHECK(!ready_);
db_->Init(kDatabaseUMAName, storage_dir_,
- base::Bind(&PersistentStore::OnInitComplete,
+ base::Bind(&PersistentEventStore::OnInitComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
}
-bool PersistentStore::IsReady() const {
+bool PersistentEventStore::IsReady() const {
return ready_;
}
-void PersistentStore::WriteEvent(const Event& event) {
+void PersistentEventStore::WriteEvent(const Event& event) {
DCHECK(IsReady());
std::unique_ptr<KeyEventList> entries = base::MakeUnique<KeyEventList>();
entries->push_back(KeyEventPair(event.name(), event));
@@ -57,7 +57,7 @@ void PersistentStore::WriteEvent(const Event& event) {
base::Bind(&NoopUpdateCallback));
}
-void PersistentStore::DeleteEvent(const std::string& event_name) {
+void PersistentEventStore::DeleteEvent(const std::string& event_name) {
DCHECK(IsReady());
auto deletes = base::MakeUnique<std::vector<std::string>>();
deletes->push_back(event_name);
@@ -66,8 +66,8 @@ void PersistentStore::DeleteEvent(const std::string& event_name) {
base::Bind(&NoopUpdateCallback));
}
-void PersistentStore::OnInitComplete(const OnLoadedCallback& callback,
- bool success) {
+void PersistentEventStore::OnInitComplete(const OnLoadedCallback& callback,
+ bool success) {
stats::RecordDbInitEvent(success, stats::StoreType::EVENTS_STORE);
if (!success) {
@@ -75,11 +75,11 @@ void PersistentStore::OnInitComplete(const OnLoadedCallback& callback,
return;
}
- db_->LoadEntries(base::Bind(&PersistentStore::OnLoadComplete,
+ db_->LoadEntries(base::Bind(&PersistentEventStore::OnLoadComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
}
-void PersistentStore::OnLoadComplete(
+void PersistentEventStore::OnLoadComplete(
const OnLoadedCallback& callback,
bool success,
std::unique_ptr<std::vector<Event>> entries) {
@@ -88,4 +88,4 @@ void PersistentStore::OnLoadComplete(
callback.Run(success, std::move(entries));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/persistent_event_store.h b/chromium/components/feature_engagement/internal/persistent_event_store.h
new file mode 100644
index 00000000000..753ced32af3
--- /dev/null
+++ b/chromium/components/feature_engagement/internal/persistent_event_store.h
@@ -0,0 +1,59 @@
+// 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_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_EVENT_STORE_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_EVENT_STORE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/feature_engagement/internal/event_store.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/leveldb_proto/proto_database.h"
+
+namespace feature_engagement {
+
+// A PersistentEventStore provides a DB layer that persists the data to disk.
+// The data is retrieved once during the load process and after that this store
+// is write only. Data will be persisted asynchronously so it is not guaranteed
+// to always save every write during shutdown.
+class PersistentEventStore : public EventStore {
+ public:
+ // Builds a PersistentEventStore backed by the ProtoDatabase |db|. The
+ // database will be loaded and/or created at |storage_dir|.
+ PersistentEventStore(const base::FilePath& storage_dir,
+ std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db);
+ ~PersistentEventStore() override;
+
+ // EventStore implementation.
+ void Load(const OnLoadedCallback& callback) override;
+ bool IsReady() const override;
+ void WriteEvent(const Event& event) override;
+ void DeleteEvent(const std::string& event_name) override;
+
+ private:
+ void OnInitComplete(const OnLoadedCallback& callback, bool success);
+ void OnLoadComplete(const OnLoadedCallback& callback,
+ bool success,
+ std::unique_ptr<std::vector<Event>> entries);
+
+ const base::FilePath storage_dir_;
+ std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db_;
+
+ // Whether or not the underlying ProtoDatabase is ready. This will be false
+ // until the OnLoadedCallback is broadcast. It will also be false if loading
+ // fails.
+ bool ready_;
+
+ base::WeakPtrFactory<PersistentEventStore> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentEventStore);
+};
+
+} // namespace feature_engagement
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_PERSISTENT_EVENT_STORE_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/persistent_store_unittest.cc b/chromium/components/feature_engagement/internal/persistent_event_store_unittest.cc
index 290d2b5fc42..46e48cd7a95 100644
--- a/chromium/components/feature_engagement_tracker/internal/persistent_store_unittest.cc
+++ b/chromium/components/feature_engagement/internal/persistent_event_store_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/feature_engagement_tracker/internal/persistent_store.h"
+#include "components/feature_engagement/internal/persistent_event_store.h"
#include <map>
@@ -10,14 +10,14 @@
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/test/histogram_tester.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
-#include "components/feature_engagement_tracker/internal/test/event_util.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/stats.h"
+#include "components/feature_engagement/internal/test/event_util.h"
#include "components/leveldb_proto/proto_database.h"
#include "components/leveldb_proto/testing/fake_db.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -32,13 +32,13 @@ void VerifyEventsInListAndMap(const std::map<std::string, Event>& map,
}
}
-class PersistentStoreTest : public ::testing::Test {
+class PersistentEventStoreTest : public ::testing::Test {
public:
- PersistentStoreTest()
+ PersistentEventStoreTest()
: db_(nullptr),
storage_dir_(FILE_PATH_LITERAL("/persistent/store/lalala")) {
- load_callback_ =
- base::Bind(&PersistentStoreTest::LoadCallback, base::Unretained(this));
+ load_callback_ = base::Bind(&PersistentEventStoreTest::LoadCallback,
+ base::Unretained(this));
}
void TearDown() override {
@@ -54,7 +54,7 @@ class PersistentStoreTest : public ::testing::Test {
auto db = base::MakeUnique<leveldb_proto::test::FakeDB<Event>>(&db_events_);
db_ = db.get();
- store_.reset(new PersistentStore(storage_dir_, std::move(db)));
+ store_.reset(new PersistentEventStore(storage_dir_, std::move(db)));
}
void LoadCallback(bool success, std::unique_ptr<std::vector<Event>> events) {
@@ -66,10 +66,10 @@ class PersistentStoreTest : public ::testing::Test {
base::Optional<bool> load_successful_;
std::unique_ptr<std::vector<Event>> load_results_;
- Store::OnLoadedCallback load_callback_;
+ EventStore::OnLoadedCallback load_callback_;
std::map<std::string, Event> db_events_;
leveldb_proto::test::FakeDB<Event>* db_;
- std::unique_ptr<Store> store_;
+ std::unique_ptr<EventStore> store_;
// Constant test data.
base::FilePath storage_dir_;
@@ -77,13 +77,13 @@ class PersistentStoreTest : public ::testing::Test {
} // namespace
-TEST_F(PersistentStoreTest, StorageDirectory) {
+TEST_F(PersistentEventStoreTest, StorageDirectory) {
SetUpDB();
store_->Load(load_callback_);
EXPECT_EQ(storage_dir_, db_->GetDirectory());
}
-TEST_F(PersistentStoreTest, SuccessfulInitAndLoadEmptyStore) {
+TEST_F(PersistentEventStoreTest, SuccessfulInitAndLoadEmptyStore) {
SetUpDB();
base::HistogramTester histogram_tester;
@@ -109,7 +109,7 @@ TEST_F(PersistentStoreTest, SuccessfulInitAndLoadEmptyStore) {
histogram_tester.ExpectBucketCount("InProductHelp.Db.TotalEvents", 0, 1);
}
-TEST_F(PersistentStoreTest, SuccessfulInitAndLoadWithEvents) {
+TEST_F(PersistentEventStoreTest, SuccessfulInitAndLoadWithEvents) {
// Populate fake Event entries.
Event event1;
event1.set_name("event1");
@@ -148,7 +148,7 @@ TEST_F(PersistentStoreTest, SuccessfulInitAndLoadWithEvents) {
histogram_tester.ExpectBucketCount("InProductHelp.Db.TotalEvents", 3, 1);
}
-TEST_F(PersistentStoreTest, SuccessfulInitBadLoad) {
+TEST_F(PersistentEventStoreTest, SuccessfulInitBadLoad) {
base::HistogramTester histogram_tester;
SetUpDB();
@@ -171,7 +171,7 @@ TEST_F(PersistentStoreTest, SuccessfulInitBadLoad) {
histogram_tester.ExpectTotalCount("InProductHelp.Db.TotalEvents", 0);
}
-TEST_F(PersistentStoreTest, BadInit) {
+TEST_F(PersistentEventStoreTest, BadInit) {
base::HistogramTester histogram_tester;
SetUpDB();
@@ -190,7 +190,7 @@ TEST_F(PersistentStoreTest, BadInit) {
histogram_tester.ExpectTotalCount("InProductHelp.Db.TotalEvents", 0);
}
-TEST_F(PersistentStoreTest, IsReady) {
+TEST_F(PersistentEventStoreTest, IsReady) {
SetUpDB();
EXPECT_FALSE(store_->IsReady());
@@ -204,7 +204,7 @@ TEST_F(PersistentStoreTest, IsReady) {
EXPECT_TRUE(store_->IsReady());
}
-TEST_F(PersistentStoreTest, WriteEvent) {
+TEST_F(PersistentEventStoreTest, WriteEvent) {
SetUpDB();
store_->Load(load_callback_);
@@ -225,7 +225,7 @@ TEST_F(PersistentStoreTest, WriteEvent) {
test::VerifyEventsEqual(&event, &it->second);
}
-TEST_F(PersistentStoreTest, WriteAndDeleteEvent) {
+TEST_F(PersistentEventStoreTest, WriteAndDeleteEvent) {
SetUpDB();
store_->Load(load_callback_);
@@ -248,4 +248,4 @@ TEST_F(PersistentStoreTest, WriteAndDeleteEvent) {
EXPECT_EQ(db_events_.end(), it);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn b/chromium/components/feature_engagement/internal/proto/BUILD.gn
index e4063482e90..e4063482e90 100644
--- a/chromium/components/feature_engagement_tracker/internal/proto/BUILD.gn
+++ b/chromium/components/feature_engagement/internal/proto/BUILD.gn
diff --git a/chromium/components/feature_engagement_tracker/internal/proto/availability.proto b/chromium/components/feature_engagement/internal/proto/availability.proto
index 97dfd4b3c84..cc389da159c 100644
--- a/chromium/components/feature_engagement_tracker/internal/proto/availability.proto
+++ b/chromium/components/feature_engagement/internal/proto/availability.proto
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// FeatureEngagementTracker content.
+// feature_engagement::AvailabilityModel content.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
-package feature_engagement_tracker;
+package feature_engagement;
// Availability stores state for the availability of a particular feature.
message Availability {
diff --git a/chromium/components/feature_engagement_tracker/internal/proto/event.proto b/chromium/components/feature_engagement/internal/proto/event.proto
index 9b619a23a78..9f59b5266f5 100644
--- a/chromium/components/feature_engagement_tracker/internal/proto/event.proto
+++ b/chromium/components/feature_engagement/internal/proto/event.proto
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// FeatureEngagementTracker content.
+// feature_engagement::EventModel content.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
-package feature_engagement_tracker;
+package feature_engagement;
// Event stores state for a specific event a count per day it has happened.
message Event {
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc b/chromium/components/feature_engagement/internal/single_invalid_configuration.cc
index 518fd632f6c..5d06652ac8b 100644
--- a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.cc
+++ b/chromium/components/feature_engagement/internal/single_invalid_configuration.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/feature_engagement_tracker/internal/single_invalid_configuration.h"
+#include "components/feature_engagement/internal/single_invalid_configuration.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
SingleInvalidConfiguration::SingleInvalidConfiguration() {
invalid_feature_config_.valid = false;
@@ -30,4 +30,4 @@ SingleInvalidConfiguration::GetRegisteredFeatures() const {
return configs_;
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h b/chromium/components/feature_engagement/internal/single_invalid_configuration.h
index 1e069be895e..de6ce42caa6 100644
--- a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration.h
+++ b/chromium/components/feature_engagement/internal/single_invalid_configuration.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
#include <string>
#include <unordered_set>
#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
namespace base {
struct Feature;
} // namespace base
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// An Configuration that always returns the same single invalid configuration,
// regardless of which feature. Also holds an empty ConfigMap.
@@ -41,6 +41,6 @@ class SingleInvalidConfiguration : public Configuration {
DISALLOW_COPY_AND_ASSIGN(SingleInvalidConfiguration);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SINGLE_INVALID_CONFIGURATION_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc b/chromium/components/feature_engagement/internal/single_invalid_configuration_unittest.cc
index ed6ebba3b47..c8f369ce07d 100644
--- a/chromium/components/feature_engagement_tracker/internal/single_invalid_configuration_unittest.cc
+++ b/chromium/components/feature_engagement/internal/single_invalid_configuration_unittest.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/single_invalid_configuration.h"
+#include "components/feature_engagement/internal/single_invalid_configuration.h"
#include "base/feature_list.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
+#include "components/feature_engagement/internal/configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -38,4 +38,4 @@ TEST_F(SingleInvalidConfigurationTest, AllConfigurationsAreInvalid) {
EXPECT_FALSE(bar_config.valid);
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/stats.cc b/chromium/components/feature_engagement/internal/stats.cc
index ac780251eda..5cc79b2604c 100644
--- a/chromium/components/feature_engagement_tracker/internal/stats.cc
+++ b/chromium/components/feature_engagement/internal/stats.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/stats.h"
+#include "components/feature_engagement/internal/stats.h"
#include <string>
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/public/feature_list.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace stats {
namespace {
@@ -121,8 +121,10 @@ void RecordShouldTriggerHelpUI(const base::Feature& feature,
}
// Histogram about the failure reasons.
- if (!result.event_model_ready_ok)
- LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_MODEL_NOT_READY);
+ if (!result.event_model_ready_ok) {
+ LogTriggerHelpUIResult(name,
+ TriggerHelpUIResult::FAILURE_EVENT_MODEL_NOT_READY);
+ }
if (!result.currently_showing_ok) {
LogTriggerHelpUIResult(name,
TriggerHelpUIResult::FAILURE_CURRENTLY_SHOWING);
@@ -205,4 +207,4 @@ void RecordConfigParsingEvent(ConfigParsingEvent event) {
}
} // namespace stats
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/stats.h b/chromium/components/feature_engagement/internal/stats.h
index 7171a3201f2..1a4022023ba 100644
--- a/chromium/components/feature_engagement_tracker/internal/stats.h
+++ b/chromium/components/feature_engagement/internal/stats.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STATS_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STATS_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STATS_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STATS_H_
#include <string>
#include <vector>
-#include "components/feature_engagement_tracker/internal/condition_validator.h"
-#include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
+#include "components/feature_engagement/internal/condition_validator.h"
+#include "components/feature_engagement/internal/configuration.h"
+#include "components/feature_engagement/internal/proto/event.pb.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace stats {
// Enum used in the metrics to record the result when in-product help UI is
@@ -27,8 +27,8 @@ enum class TriggerHelpUIResult {
// The help UI is not triggered.
FAILURE = 1,
- // Data layer is not ready.
- FAILURE_MODEL_NOT_READY = 2,
+ // Event model is not ready.
+ FAILURE_EVENT_MODEL_NOT_READY = 2,
// Some other help UI is currently showing.
FAILURE_CURRENTLY_SHOWING = 3,
@@ -51,7 +51,7 @@ enum class TriggerHelpUIResult {
// Session rate does not meet the requirement.
FAILURE_SESSION_RATE = 9,
- // Availability mode is not ready.
+ // Availability model is not ready.
FAILURE_AVAILABILITY_MODEL_NOT_READY = 10,
// Availability precondition is not satisfied.
@@ -145,6 +145,6 @@ void RecordAvailabilityDbLoadEvent(bool success);
void RecordConfigParsingEvent(ConfigParsingEvent event);
} // namespace stats
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_STATS_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_STATS_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/system_time_provider.cc b/chromium/components/feature_engagement/internal/system_time_provider.cc
index 6e00ee98129..8e6d83d88ed 100644
--- a/chromium/components/feature_engagement_tracker/internal/system_time_provider.cc
+++ b/chromium/components/feature_engagement/internal/system_time_provider.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/feature_engagement_tracker/internal/system_time_provider.h"
+#include "components/feature_engagement/internal/system_time_provider.h"
#include "base/time/time.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
SystemTimeProvider::SystemTimeProvider() = default;
@@ -21,4 +21,4 @@ base::Time SystemTimeProvider::Now() const {
return base::Time::Now();
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/system_time_provider.h b/chromium/components/feature_engagement/internal/system_time_provider.h
index 9f6a849867c..bd48c687f21 100644
--- a/chromium/components/feature_engagement_tracker/internal/system_time_provider.h
+++ b/chromium/components/feature_engagement/internal/system_time_provider.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SYSTEM_TIME_PROVIDER_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SYSTEM_TIME_PROVIDER_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SYSTEM_TIME_PROVIDER_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SYSTEM_TIME_PROVIDER_H_
#include "base/macros.h"
#include "base/time/time.h"
-#include "components/feature_engagement_tracker/internal/time_provider.h"
+#include "components/feature_engagement/internal/time_provider.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// A TimeProvider that uses the system time.
class SystemTimeProvider : public TimeProvider {
@@ -29,6 +29,6 @@ class SystemTimeProvider : public TimeProvider {
DISALLOW_COPY_AND_ASSIGN(SystemTimeProvider);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_SYSTEM_TIME_PROVIDER_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_SYSTEM_TIME_PROVIDER_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc b/chromium/components/feature_engagement/internal/system_time_provider_unittest.cc
index e9d08c08ea0..d1ab4720d23 100644
--- a/chromium/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc
+++ b/chromium/components/feature_engagement/internal/system_time_provider_unittest.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/internal/system_time_provider.h"
+#include "components/feature_engagement/internal/system_time_provider.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
@@ -110,4 +110,4 @@ TEST_F(SystemTimeProviderTest, TestManualDatesAroundGoogleIO2017) {
EXPECT_EQ(17305u, time_provider_.GetCurrentDay());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/test/BUILD.gn b/chromium/components/feature_engagement/internal/test/BUILD.gn
index 83001382c22..961c1f6066b 100644
--- a/chromium/components/feature_engagement_tracker/internal/test/BUILD.gn
+++ b/chromium/components/feature_engagement/internal/test/BUILD.gn
@@ -5,7 +5,7 @@
source_set("test_support") {
testonly = true
- visibility = [ "//components/feature_engagement_tracker/internal:unit_tests" ]
+ visibility = [ "//components/feature_engagement/internal:unit_tests" ]
sources = [
"event_util.cc",
@@ -13,7 +13,7 @@ source_set("test_support") {
]
deps = [
- "//components/feature_engagement_tracker/internal/proto",
+ "//components/feature_engagement/internal/proto",
"//testing/gtest",
]
}
diff --git a/chromium/components/feature_engagement_tracker/internal/time_provider.h b/chromium/components/feature_engagement/internal/time_provider.h
index da3b61da3bc..50c73eeee69 100644
--- a/chromium/components/feature_engagement_tracker/internal/time_provider.h
+++ b/chromium/components/feature_engagement/internal/time_provider.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_TIME_PROVIDER_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_TIME_PROVIDER_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TIME_PROVIDER_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TIME_PROVIDER_H_
#include <stdint.h>
#include "base/macros.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// A TimeProvider provides functionality related to time.
class TimeProvider {
@@ -26,6 +26,6 @@ class TimeProvider {
DISALLOW_COPY_AND_ASSIGN(TimeProvider);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_TIME_PROVIDER_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TIME_PROVIDER_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc b/chromium/components/feature_engagement/internal/tracker_impl.cc
index f9ccba5354d..8dc508a5caa 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl.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/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
+#include "components/feature_engagement/internal/tracker_impl.h"
#include <memory>
#include <utility>
@@ -15,26 +15,26 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/user_metrics.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/feature_engagement_tracker/internal/availability_model_impl.h"
-#include "components/feature_engagement_tracker/internal/chrome_variations_configuration.h"
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/feature_config_condition_validator.h"
-#include "components/feature_engagement_tracker/internal/feature_config_storage_validator.h"
-#include "components/feature_engagement_tracker/internal/in_memory_store.h"
-#include "components/feature_engagement_tracker/internal/init_aware_model.h"
-#include "components/feature_engagement_tracker/internal/model_impl.h"
-#include "components/feature_engagement_tracker/internal/never_availability_model.h"
-#include "components/feature_engagement_tracker/internal/never_storage_validator.h"
-#include "components/feature_engagement_tracker/internal/once_condition_validator.h"
-#include "components/feature_engagement_tracker/internal/persistent_store.h"
-#include "components/feature_engagement_tracker/internal/proto/availability.pb.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
-#include "components/feature_engagement_tracker/internal/system_time_provider.h"
-#include "components/feature_engagement_tracker/public/feature_constants.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/internal/availability_model_impl.h"
+#include "components/feature_engagement/internal/chrome_variations_configuration.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/event_model_impl.h"
+#include "components/feature_engagement/internal/feature_config_condition_validator.h"
+#include "components/feature_engagement/internal/feature_config_event_storage_validator.h"
+#include "components/feature_engagement/internal/in_memory_event_store.h"
+#include "components/feature_engagement/internal/init_aware_event_model.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/never_event_storage_validator.h"
+#include "components/feature_engagement/internal/once_condition_validator.h"
+#include "components/feature_engagement/internal/persistent_event_store.h"
+#include "components/feature_engagement/internal/proto/availability.pb.h"
+#include "components/feature_engagement/internal/stats.h"
+#include "components/feature_engagement/internal/system_time_provider.h"
+#include "components/feature_engagement/public/feature_constants.h"
+#include "components/feature_engagement/public/feature_list.h"
#include "components/leveldb_proto/proto_database_impl.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
const base::FilePath::CharType kEventDBStorageDir[] =
@@ -42,9 +42,8 @@ const base::FilePath::CharType kEventDBStorageDir[] =
const base::FilePath::CharType kAvailabilityDBStorageDir[] =
FILE_PATH_LITERAL("AvailabilityDB");
-// Creates a FeatureEngagementTrackerImpl that is usable for a demo mode.
-std::unique_ptr<FeatureEngagementTracker>
-CreateDemoModeFeatureEngagementTracker() {
+// Creates a TrackerImpl that is usable for a demo mode.
+std::unique_ptr<Tracker> CreateDemoModeTracker() {
// GetFieldTrialParamValueByFeature returns an empty string if the param is
// not set.
std::string chosen_feature_name = base::GetFieldTrialParamValueByFeature(
@@ -71,12 +70,12 @@ CreateDemoModeFeatureEngagementTracker() {
configuration->SetConfiguration(feature, feature_config);
}
- auto raw_model =
- base::MakeUnique<ModelImpl>(base::MakeUnique<InMemoryStore>(),
- base::MakeUnique<NeverStorageValidator>());
+ auto raw_event_model = base::MakeUnique<EventModelImpl>(
+ base::MakeUnique<InMemoryEventStore>(),
+ base::MakeUnique<NeverEventStorageValidator>());
- return base::MakeUnique<FeatureEngagementTrackerImpl>(
- base::MakeUnique<InitAwareModel>(std::move(raw_model)),
+ return base::MakeUnique<TrackerImpl>(
+ base::MakeUnique<InitAwareEventModel>(std::move(raw_event_model)),
base::MakeUnique<NeverAvailabilityModel>(), std::move(configuration),
base::MakeUnique<OnceConditionValidator>(),
base::MakeUnique<SystemTimeProvider>());
@@ -84,35 +83,37 @@ CreateDemoModeFeatureEngagementTracker() {
} // namespace
-// This method is declared in //components/feature_engagement_tracker/public/
-// feature_engagement_tracker.h
-// and should be linked in to any binary using FeatureEngagementTracker::Create.
+// This method is declared in //components/feature_engagement/public/
+// feature_engagement.h
+// and should be linked in to any binary using Tracker::Create.
// static
-FeatureEngagementTracker* FeatureEngagementTracker::Create(
+Tracker* Tracker::Create(
const base::FilePath& storage_dir,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
- DVLOG(2) << "Creating FeatureEngagementTracker";
+ DVLOG(2) << "Creating Tracker";
if (base::FeatureList::IsEnabled(kIPHDemoMode))
- return CreateDemoModeFeatureEngagementTracker().release();
+ return CreateDemoModeTracker().release();
- std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db =
+ std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> event_db =
base::MakeUnique<leveldb_proto::ProtoDatabaseImpl<Event>>(
background_task_runner);
base::FilePath event_storage_dir = storage_dir.Append(kEventDBStorageDir);
- auto store =
- base::MakeUnique<PersistentStore>(event_storage_dir, std::move(db));
+ auto event_store = base::MakeUnique<PersistentEventStore>(
+ event_storage_dir, std::move(event_db));
auto configuration = base::MakeUnique<ChromeVariationsConfiguration>();
configuration->ParseFeatureConfigs(GetAllFeatures());
- auto storage_validator = base::MakeUnique<FeatureConfigStorageValidator>();
- storage_validator->InitializeFeatures(GetAllFeatures(), *configuration);
+ auto event_storage_validator =
+ base::MakeUnique<FeatureConfigEventStorageValidator>();
+ event_storage_validator->InitializeFeatures(GetAllFeatures(), *configuration);
- auto raw_model = base::MakeUnique<ModelImpl>(std::move(store),
- std::move(storage_validator));
+ auto raw_event_model = base::MakeUnique<EventModelImpl>(
+ std::move(event_store), std::move(event_storage_validator));
- auto model = base::MakeUnique<InitAwareModel>(std::move(raw_model));
+ auto event_model =
+ base::MakeUnique<InitAwareEventModel>(std::move(raw_event_model));
auto condition_validator =
base::MakeUnique<FeatureConfigConditionValidator>();
auto time_provider = base::MakeUnique<SystemTimeProvider>();
@@ -123,24 +124,25 @@ FeatureEngagementTracker* FeatureEngagementTracker::Create(
base::MakeUnique<leveldb_proto::ProtoDatabaseImpl<Availability>>(
background_task_runner);
auto availability_store_loader = base::BindOnce(
- &AvailabilityStore::LoadAndUpdateStore, availability_storage_dir,
- std::move(availability_db), GetAllFeatures());
+ &PersistentAvailabilityStore::LoadAndUpdateStore,
+ availability_storage_dir, std::move(availability_db), GetAllFeatures());
auto availability_model = base::MakeUnique<AvailabilityModelImpl>(
std::move(availability_store_loader));
- return new FeatureEngagementTrackerImpl(
- std::move(model), std::move(availability_model), std::move(configuration),
- std::move(condition_validator), std::move(time_provider));
+ return new TrackerImpl(std::move(event_model), std::move(availability_model),
+ std::move(configuration),
+ std::move(condition_validator),
+ std::move(time_provider));
}
-FeatureEngagementTrackerImpl::FeatureEngagementTrackerImpl(
- std::unique_ptr<Model> model,
+TrackerImpl::TrackerImpl(
+ std::unique_ptr<EventModel> event_model,
std::unique_ptr<AvailabilityModel> availability_model,
std::unique_ptr<Configuration> configuration,
std::unique_ptr<ConditionValidator> condition_validator,
std::unique_ptr<TimeProvider> time_provider)
- : model_(std::move(model)),
+ : event_model_(std::move(event_model)),
availability_model_(std::move(availability_model)),
configuration_(std::move(configuration)),
condition_validator_(std::move(condition_validator)),
@@ -148,37 +150,35 @@ FeatureEngagementTrackerImpl::FeatureEngagementTrackerImpl(
event_model_initialization_finished_(false),
availability_model_initialization_finished_(false),
weak_ptr_factory_(this) {
- model_->Initialize(
- base::Bind(
- &FeatureEngagementTrackerImpl::OnEventModelInitializationFinished,
- weak_ptr_factory_.GetWeakPtr()),
+ event_model_->Initialize(
+ base::Bind(&TrackerImpl::OnEventModelInitializationFinished,
+ weak_ptr_factory_.GetWeakPtr()),
time_provider_->GetCurrentDay());
availability_model_->Initialize(
- base::Bind(&FeatureEngagementTrackerImpl::
- OnAvailabilityModelInitializationFinished,
+ base::Bind(&TrackerImpl::OnAvailabilityModelInitializationFinished,
weak_ptr_factory_.GetWeakPtr()),
time_provider_->GetCurrentDay());
}
-FeatureEngagementTrackerImpl::~FeatureEngagementTrackerImpl() = default;
+TrackerImpl::~TrackerImpl() = default;
-void FeatureEngagementTrackerImpl::NotifyEvent(const std::string& event) {
- model_->IncrementEvent(event, time_provider_->GetCurrentDay());
- stats::RecordNotifyEvent(event, configuration_.get(), model_->IsReady());
+void TrackerImpl::NotifyEvent(const std::string& event) {
+ event_model_->IncrementEvent(event, time_provider_->GetCurrentDay());
+ stats::RecordNotifyEvent(event, configuration_.get(),
+ event_model_->IsReady());
}
-bool FeatureEngagementTrackerImpl::ShouldTriggerHelpUI(
- const base::Feature& feature) {
+bool TrackerImpl::ShouldTriggerHelpUI(const base::Feature& feature) {
ConditionValidator::Result result = condition_validator_->MeetsConditions(
- feature, configuration_->GetFeatureConfig(feature), *model_,
+ feature, configuration_->GetFeatureConfig(feature), *event_model_,
*availability_model_, time_provider_->GetCurrentDay());
if (result.NoErrors()) {
condition_validator_->NotifyIsShowing(feature);
FeatureConfig feature_config = configuration_->GetFeatureConfig(feature);
DCHECK_NE("", feature_config.trigger.name);
- model_->IncrementEvent(feature_config.trigger.name,
- time_provider_->GetCurrentDay());
+ event_model_->IncrementEvent(feature_config.trigger.name,
+ time_provider_->GetCurrentDay());
}
stats::RecordShouldTriggerHelpUI(feature, result);
@@ -187,18 +187,40 @@ bool FeatureEngagementTrackerImpl::ShouldTriggerHelpUI(
return result.NoErrors();
}
-void FeatureEngagementTrackerImpl::Dismissed(const base::Feature& feature) {
+Tracker::TriggerState TrackerImpl::GetTriggerState(
+ const base::Feature& feature) {
+ if (!IsInitialized()) {
+ DVLOG(2) << "TriggerState for " << feature.name << ": "
+ << static_cast<int>(Tracker::TriggerState::NOT_READY);
+ return Tracker::TriggerState::NOT_READY;
+ }
+
+ ConditionValidator::Result result = condition_validator_->MeetsConditions(
+ feature, configuration_->GetFeatureConfig(feature), *event_model_,
+ *availability_model_, time_provider_->GetCurrentDay());
+
+ if (result.trigger_ok) {
+ DVLOG(2) << "TriggerState for " << feature.name << ": "
+ << static_cast<int>(Tracker::TriggerState::HAS_NOT_BEEN_DISPLAYED);
+ return Tracker::TriggerState::HAS_NOT_BEEN_DISPLAYED;
+ }
+
+ DVLOG(2) << "TriggerState for " << feature.name << ": "
+ << static_cast<int>(Tracker::TriggerState::HAS_BEEN_DISPLAYED);
+ return Tracker::TriggerState::HAS_BEEN_DISPLAYED;
+}
+
+void TrackerImpl::Dismissed(const base::Feature& feature) {
DVLOG(2) << "Dismissing " << feature.name;
condition_validator_->NotifyDismissed(feature);
stats::RecordUserDismiss();
}
-bool FeatureEngagementTrackerImpl::IsInitialized() {
- return model_->IsReady() && availability_model_->IsReady();
+bool TrackerImpl::IsInitialized() {
+ return event_model_->IsReady() && availability_model_->IsReady();
}
-void FeatureEngagementTrackerImpl::AddOnInitializedCallback(
- OnInitializedCallback callback) {
+void TrackerImpl::AddOnInitializedCallback(OnInitializedCallback callback) {
if (IsInitializationFinished()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, IsInitialized()));
@@ -208,9 +230,8 @@ void FeatureEngagementTrackerImpl::AddOnInitializedCallback(
on_initialized_callbacks_.push_back(callback);
}
-void FeatureEngagementTrackerImpl::OnEventModelInitializationFinished(
- bool success) {
- DCHECK_EQ(success, model_->IsReady());
+void TrackerImpl::OnEventModelInitializationFinished(bool success) {
+ DCHECK_EQ(success, event_model_->IsReady());
event_model_initialization_finished_ = true;
DVLOG(2) << "Event model initialization result = " << success;
@@ -218,8 +239,7 @@ void FeatureEngagementTrackerImpl::OnEventModelInitializationFinished(
MaybePostInitializedCallbacks();
}
-void FeatureEngagementTrackerImpl::OnAvailabilityModelInitializationFinished(
- bool success) {
+void TrackerImpl::OnAvailabilityModelInitializationFinished(bool success) {
DCHECK_EQ(success, availability_model_->IsReady());
availability_model_initialization_finished_ = true;
@@ -228,12 +248,12 @@ void FeatureEngagementTrackerImpl::OnAvailabilityModelInitializationFinished(
MaybePostInitializedCallbacks();
}
-bool FeatureEngagementTrackerImpl::IsInitializationFinished() const {
+bool TrackerImpl::IsInitializationFinished() const {
return event_model_initialization_finished_ &&
availability_model_initialization_finished_;
}
-void FeatureEngagementTrackerImpl::MaybePostInitializedCallbacks() {
+void TrackerImpl::MaybePostInitializedCallbacks() {
if (!IsInitializationFinished())
return;
@@ -247,4 +267,4 @@ void FeatureEngagementTrackerImpl::MaybePostInitializedCallbacks() {
on_initialized_callbacks_.clear();
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h b/chromium/components/feature_engagement/internal/tracker_impl.h
index 3b0abcee50a..c9d37023601 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
+++ b/chromium/components/feature_engagement/internal/tracker_impl.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_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TRACKER_IMPL_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TRACKER_IMPL_H_
#include <string>
#include <vector>
@@ -12,36 +12,35 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
-#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
+#include "components/feature_engagement/public/tracker.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
class AvailabilityModel;
class Configuration;
class ConditionValidator;
-class Model;
+class EventModel;
class TimeProvider;
-// The internal implementation of the FeatureEngagementTracker.
-class FeatureEngagementTrackerImpl : public FeatureEngagementTracker,
- public base::SupportsUserData {
+// The internal implementation of the Tracker.
+class TrackerImpl : public Tracker, public base::SupportsUserData {
public:
- FeatureEngagementTrackerImpl(
- std::unique_ptr<Model> store,
- std::unique_ptr<AvailabilityModel> availability_model,
- std::unique_ptr<Configuration> configuration,
- std::unique_ptr<ConditionValidator> condition_validator,
- std::unique_ptr<TimeProvider> time_provider);
- ~FeatureEngagementTrackerImpl() override;
-
- // FeatureEngagementTracker implementation.
+ TrackerImpl(std::unique_ptr<EventModel> event_model,
+ std::unique_ptr<AvailabilityModel> availability_model,
+ std::unique_ptr<Configuration> configuration,
+ std::unique_ptr<ConditionValidator> condition_validator,
+ std::unique_ptr<TimeProvider> time_provider);
+ ~TrackerImpl() override;
+
+ // Tracker implementation.
void NotifyEvent(const std::string& event) override;
bool ShouldTriggerHelpUI(const base::Feature& feature) override;
+ Tracker::TriggerState GetTriggerState(const base::Feature& feature) override;
void Dismissed(const base::Feature& feature) override;
bool IsInitialized() override;
void AddOnInitializedCallback(OnInitializedCallback callback) override;
private:
- // Invoked by the Model when it has been initialized.
+ // Invoked by the EventModel when it has been initialized.
void OnEventModelInitializationFinished(bool success);
// Invoked by the AvailabilityModel when it has been initialized.
@@ -56,8 +55,8 @@ class FeatureEngagementTrackerImpl : public FeatureEngagementTracker,
// IsInitializationFinished() returns true.
void MaybePostInitializedCallbacks();
- // The current model.
- std::unique_ptr<Model> model_;
+ // The current model for all events.
+ std::unique_ptr<EventModel> event_model_;
// The current model for when particular features were enabled.
std::unique_ptr<AvailabilityModel> availability_model_;
@@ -72,10 +71,10 @@ class FeatureEngagementTrackerImpl : public FeatureEngagementTracker,
// A utility for retriving time-related information.
std::unique_ptr<TimeProvider> time_provider_;
- // Whether the initialization of the underlying event model has finished.
+ // Whether the initialization of the underlying EventModel has finished.
bool event_model_initialization_finished_;
- // Whether the initialization of the underlying availability model has
+ // Whether the initialization of the underlying AvailabilityModel has
// finished.
bool availability_model_initialization_finished_;
@@ -83,11 +82,11 @@ class FeatureEngagementTrackerImpl : public FeatureEngagementTracker,
// is cleared after the initialization has happened.
std::vector<OnInitializedCallback> on_initialized_callbacks_;
- base::WeakPtrFactory<FeatureEngagementTrackerImpl> weak_ptr_factory_;
+ base::WeakPtrFactory<TrackerImpl> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImpl);
+ DISALLOW_COPY_AND_ASSIGN(TrackerImpl);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_FEATURE_ENGAGEMENT_TRACKER_IMPL_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_INTERNAL_TRACKER_IMPL_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
index 3b7fd924c22..078059b7017 100644
--- a/chromium/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl_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/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
+#include "components/feature_engagement/internal/tracker_impl.h"
#include <memory>
@@ -16,18 +16,18 @@
#include "base/test/histogram_tester.h"
#include "base/test/user_action_tester.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/feature_engagement_tracker/internal/availability_model_impl.h"
-#include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/in_memory_store.h"
-#include "components/feature_engagement_tracker/internal/model_impl.h"
-#include "components/feature_engagement_tracker/internal/never_availability_model.h"
-#include "components/feature_engagement_tracker/internal/never_storage_validator.h"
-#include "components/feature_engagement_tracker/internal/once_condition_validator.h"
-#include "components/feature_engagement_tracker/internal/stats.h"
-#include "components/feature_engagement_tracker/internal/time_provider.h"
+#include "components/feature_engagement/internal/availability_model_impl.h"
+#include "components/feature_engagement/internal/editable_configuration.h"
+#include "components/feature_engagement/internal/event_model_impl.h"
+#include "components/feature_engagement/internal/in_memory_event_store.h"
+#include "components/feature_engagement/internal/never_availability_model.h"
+#include "components/feature_engagement/internal/never_event_storage_validator.h"
+#include "components/feature_engagement/internal/once_condition_validator.h"
+#include "components/feature_engagement/internal/stats.h"
+#include "components/feature_engagement/internal/time_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
const base::Feature kTestFeatureFoo{"test_foo",
@@ -70,12 +70,12 @@ class StoringInitializedCallback {
DISALLOW_COPY_AND_ASSIGN(StoringInitializedCallback);
};
-// An InMemoryStore that is able to fake successful and unsuccessful
+// An InMemoryEventStore that is able to fake successful and unsuccessful
// loading of state.
-class TestInMemoryStore : public InMemoryStore {
+class TestInMemoryEventStore : public InMemoryEventStore {
public:
- explicit TestInMemoryStore(bool load_should_succeed)
- : InMemoryStore(), load_should_succeed_(load_should_succeed) {}
+ explicit TestInMemoryEventStore(bool load_should_succeed)
+ : InMemoryEventStore(), load_should_succeed_(load_should_succeed) {}
void Load(const OnLoadedCallback& callback) override {
HandleLoadResult(callback, load_should_succeed_);
@@ -94,13 +94,13 @@ class TestInMemoryStore : public InMemoryStore {
std::map<std::string, Event> events_;
- DISALLOW_COPY_AND_ASSIGN(TestInMemoryStore);
+ DISALLOW_COPY_AND_ASSIGN(TestInMemoryEventStore);
};
-class StoreEverythingStorageValidator : public StorageValidator {
+class StoreEverythingEventStorageValidator : public EventStorageValidator {
public:
- StoreEverythingStorageValidator() = default;
- ~StoreEverythingStorageValidator() override = default;
+ StoreEverythingEventStorageValidator() = default;
+ ~StoreEverythingEventStorageValidator() override = default;
bool ShouldStore(const std::string& event_name) const override {
return true;
@@ -113,7 +113,7 @@ class StoreEverythingStorageValidator : public StorageValidator {
};
private:
- DISALLOW_COPY_AND_ASSIGN(StoreEverythingStorageValidator);
+ DISALLOW_COPY_AND_ASSIGN(StoreEverythingEventStorageValidator);
};
class TestTimeProvider : public TimeProvider {
@@ -154,9 +154,9 @@ class TestAvailabilityModel : public AvailabilityModel {
DISALLOW_COPY_AND_ASSIGN(TestAvailabilityModel);
};
-class FeatureEngagementTrackerImplTest : public ::testing::Test {
+class TrackerImplTest : public ::testing::Test {
public:
- FeatureEngagementTrackerImplTest() = default;
+ TrackerImplTest() = default;
void SetUp() override {
std::unique_ptr<EditableConfiguration> configuration =
@@ -167,24 +167,25 @@ class FeatureEngagementTrackerImplTest : public ::testing::Test {
RegisterFeatureConfig(configuration.get(), kTestFeatureBar, true);
RegisterFeatureConfig(configuration.get(), kTestFeatureQux, false);
- std::unique_ptr<TestInMemoryStore> store = CreateStore();
- store_ = store.get();
+ std::unique_ptr<TestInMemoryEventStore> event_store = CreateEventStore();
+ event_store_ = event_store.get();
- auto model = base::MakeUnique<ModelImpl>(
- std::move(store), base::MakeUnique<StoreEverythingStorageValidator>());
+ auto event_model = base::MakeUnique<EventModelImpl>(
+ std::move(event_store),
+ base::MakeUnique<StoreEverythingEventStorageValidator>());
auto availability_model = base::MakeUnique<TestAvailabilityModel>();
availability_model_ = availability_model.get();
availability_model_->SetIsReady(ShouldAvailabilityStoreBeReady());
- tracker_.reset(new FeatureEngagementTrackerImpl(
- std::move(model), std::move(availability_model),
+ tracker_.reset(new TrackerImpl(
+ std::move(event_model), std::move(availability_model),
std::move(configuration), base::MakeUnique<OnceConditionValidator>(),
base::MakeUnique<TestTimeProvider>()));
}
void VerifyEventTriggerEvents(const base::Feature& feature, uint32_t count) {
- Event trigger_event = store_->GetEvent(
+ Event trigger_event = event_store_->GetEvent(
configuration_->GetFeatureConfig(feature).trigger.name);
if (count == 0) {
EXPECT_EQ(0, trigger_event.events_size());
@@ -306,57 +307,54 @@ class FeatureEngagementTrackerImplTest : public ::testing::Test {
}
protected:
- virtual std::unique_ptr<TestInMemoryStore> CreateStore() {
- // Returns a Store that will successfully initialize.
- return base::MakeUnique<TestInMemoryStore>(true);
+ virtual std::unique_ptr<TestInMemoryEventStore> CreateEventStore() {
+ // Returns a EventStore that will successfully initialize.
+ return base::MakeUnique<TestInMemoryEventStore>(true);
}
virtual bool ShouldAvailabilityStoreBeReady() { return true; }
base::MessageLoop message_loop_;
- std::unique_ptr<FeatureEngagementTrackerImpl> tracker_;
- TestInMemoryStore* store_;
+ std::unique_ptr<TrackerImpl> tracker_;
+ TestInMemoryEventStore* event_store_;
TestAvailabilityModel* availability_model_;
Configuration* configuration_;
base::HistogramTester histogram_tester_;
private:
- DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImplTest);
+ DISALLOW_COPY_AND_ASSIGN(TrackerImplTest);
};
// A top-level test class where the store fails to initialize.
-class FailingStoreInitFeatureEngagementTrackerImplTest
- : public FeatureEngagementTrackerImplTest {
+class FailingStoreInitTrackerImplTest : public TrackerImplTest {
public:
- FailingStoreInitFeatureEngagementTrackerImplTest() = default;
+ FailingStoreInitTrackerImplTest() = default;
protected:
- std::unique_ptr<TestInMemoryStore> CreateStore() override {
- // Returns a Store that will fail to initialize.
- return base::MakeUnique<TestInMemoryStore>(false);
+ std::unique_ptr<TestInMemoryEventStore> CreateEventStore() override {
+ // Returns a EventStore that will fail to initialize.
+ return base::MakeUnique<TestInMemoryEventStore>(false);
}
private:
- DISALLOW_COPY_AND_ASSIGN(FailingStoreInitFeatureEngagementTrackerImplTest);
+ DISALLOW_COPY_AND_ASSIGN(FailingStoreInitTrackerImplTest);
};
// A top-level test class where the AvailabilityModel fails to initialize.
-class FailingAvailabilityModelInitFeatureEngagementTrackerImplTest
- : public FeatureEngagementTrackerImplTest {
+class FailingAvailabilityModelInitTrackerImplTest : public TrackerImplTest {
public:
- FailingAvailabilityModelInitFeatureEngagementTrackerImplTest() = default;
+ FailingAvailabilityModelInitTrackerImplTest() = default;
protected:
bool ShouldAvailabilityStoreBeReady() override { return false; }
private:
- DISALLOW_COPY_AND_ASSIGN(
- FailingAvailabilityModelInitFeatureEngagementTrackerImplTest);
+ DISALLOW_COPY_AND_ASSIGN(FailingAvailabilityModelInitTrackerImplTest);
};
} // namespace
-TEST_F(FeatureEngagementTrackerImplTest, TestInitialization) {
+TEST_F(TrackerImplTest, TestInitialization) {
EXPECT_FALSE(tracker_->IsInitialized());
StoringInitializedCallback callback;
@@ -372,7 +370,7 @@ TEST_F(FeatureEngagementTrackerImplTest, TestInitialization) {
EXPECT_TRUE(callback.success());
}
-TEST_F(FeatureEngagementTrackerImplTest, TestInitializationMultipleCallbacks) {
+TEST_F(TrackerImplTest, TestInitializationMultipleCallbacks) {
EXPECT_FALSE(tracker_->IsInitialized());
StoringInitializedCallback callback1;
@@ -397,7 +395,7 @@ TEST_F(FeatureEngagementTrackerImplTest, TestInitializationMultipleCallbacks) {
EXPECT_TRUE(callback2.success());
}
-TEST_F(FeatureEngagementTrackerImplTest, TestAddingCallbackAfterInitFinished) {
+TEST_F(TrackerImplTest, TestAddingCallbackAfterInitFinished) {
EXPECT_FALSE(tracker_->IsInitialized());
// Ensure all initialization is finished.
@@ -415,8 +413,7 @@ TEST_F(FeatureEngagementTrackerImplTest, TestAddingCallbackAfterInitFinished) {
EXPECT_TRUE(callback.invoked());
}
-TEST_F(FeatureEngagementTrackerImplTest,
- TestAddingCallbackBeforeAndAfterInitFinished) {
+TEST_F(TrackerImplTest, TestAddingCallbackBeforeAndAfterInitFinished) {
EXPECT_FALSE(tracker_->IsInitialized());
// Ensure all initialization is finished.
@@ -445,8 +442,7 @@ TEST_F(FeatureEngagementTrackerImplTest,
EXPECT_TRUE(callback_after.invoked());
}
-TEST_F(FailingStoreInitFeatureEngagementTrackerImplTest,
- TestFailingInitialization) {
+TEST_F(FailingStoreInitTrackerImplTest, TestFailingInitialization) {
EXPECT_FALSE(tracker_->IsInitialized());
StoringInitializedCallback callback;
@@ -462,7 +458,7 @@ TEST_F(FailingStoreInitFeatureEngagementTrackerImplTest,
EXPECT_FALSE(callback.success());
}
-TEST_F(FailingStoreInitFeatureEngagementTrackerImplTest,
+TEST_F(FailingStoreInitTrackerImplTest,
TestFailingInitializationMultipleCallbacks) {
EXPECT_FALSE(tracker_->IsInitialized());
@@ -487,8 +483,7 @@ TEST_F(FailingStoreInitFeatureEngagementTrackerImplTest,
EXPECT_FALSE(callback2.success());
}
-TEST_F(FailingAvailabilityModelInitFeatureEngagementTrackerImplTest,
- AvailabilityModelNotReady) {
+TEST_F(FailingAvailabilityModelInitTrackerImplTest, AvailabilityModelNotReady) {
EXPECT_FALSE(tracker_->IsInitialized());
StoringInitializedCallback callback;
@@ -504,7 +499,7 @@ TEST_F(FailingAvailabilityModelInitFeatureEngagementTrackerImplTest,
EXPECT_FALSE(callback.success());
}
-TEST_F(FeatureEngagementTrackerImplTest, TestTriggering) {
+TEST_F(TrackerImplTest, TestTriggering) {
// Ensure all initialization is finished.
StoringInitializedCallback callback;
tracker_->AddOnInitializedCallback(base::Bind(
@@ -568,7 +563,55 @@ TEST_F(FeatureEngagementTrackerImplTest, TestTriggering) {
VerifyHistograms(true, 1, 3, true, 1, 2, true, 0, 4);
}
-TEST_F(FeatureEngagementTrackerImplTest, TestNotifyEvent) {
+TEST_F(TrackerImplTest, TestTriggerStateInspection) {
+ // Before initialization has finished, NOT_READY should always be returned.
+ EXPECT_EQ(Tracker::TriggerState::NOT_READY,
+ tracker_->GetTriggerState(kTestFeatureFoo));
+ EXPECT_EQ(Tracker::TriggerState::NOT_READY,
+ tracker_->GetTriggerState(kTestFeatureQux));
+
+ // Ensure all initialization is finished.
+ StoringInitializedCallback callback;
+ tracker_->AddOnInitializedCallback(base::Bind(
+ &StoringInitializedCallback::OnInitialized, base::Unretained(&callback)));
+ base::RunLoop().RunUntilIdle();
+ base::UserActionTester user_action_tester;
+
+ EXPECT_EQ(Tracker::TriggerState::HAS_NOT_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureFoo));
+ EXPECT_EQ(Tracker::TriggerState::HAS_NOT_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureBar));
+
+ // The first time a feature triggers it should be shown.
+ EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ VerifyEventTriggerEvents(kTestFeatureFoo, 1u);
+ EXPECT_EQ(Tracker::TriggerState::HAS_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureFoo));
+
+ // Trying to show again should keep state as displayed.
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
+ VerifyEventTriggerEvents(kTestFeatureFoo, 1u);
+ EXPECT_EQ(Tracker::TriggerState::HAS_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureFoo));
+
+ // Other features should also be kept at not having been displayed.
+ EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
+ VerifyEventTriggerEvents(kTestFeatureBar, 0);
+ EXPECT_EQ(Tracker::TriggerState::HAS_NOT_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureBar));
+
+ // Dismiss foo and show qux, which should update TriggerState of bar, and keep
+ // TriggerState for foo.
+ tracker_->Dismissed(kTestFeatureFoo);
+ EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
+ VerifyEventTriggerEvents(kTestFeatureBar, 1);
+ EXPECT_EQ(Tracker::TriggerState::HAS_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureFoo));
+ EXPECT_EQ(Tracker::TriggerState::HAS_BEEN_DISPLAYED,
+ tracker_->GetTriggerState(kTestFeatureBar));
+}
+
+TEST_F(TrackerImplTest, TestNotifyEvent) {
StoringInitializedCallback callback;
tracker_->AddOnInitializedCallback(base::Bind(
&StoringInitializedCallback::OnInitialized, base::Unretained(&callback)));
@@ -592,15 +635,15 @@ TEST_F(FeatureEngagementTrackerImplTest, TestNotifyEvent) {
EXPECT_EQ(0, user_action_tester.GetActionCount(
"InProductHelp.NotifyEvent.test_bar"));
- Event foo_event = store_->GetEvent("foo");
+ Event foo_event = event_store_->GetEvent("foo");
ASSERT_EQ(1, foo_event.events_size());
EXPECT_EQ(1u, foo_event.events(0).day());
EXPECT_EQ(2u, foo_event.events(0).count());
- Event bar_event = store_->GetEvent("bar");
+ Event bar_event = event_store_->GetEvent("bar");
ASSERT_EQ(1, bar_event.events_size());
EXPECT_EQ(1u, bar_event.events(0).day());
EXPECT_EQ(1u, bar_event.events(0).count());
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/public/BUILD.gn b/chromium/components/feature_engagement/public/BUILD.gn
index 55bd9ead819..82fffd5bc4d 100644
--- a/chromium/components/feature_engagement_tracker/public/BUILD.gn
+++ b/chromium/components/feature_engagement/public/BUILD.gn
@@ -13,9 +13,9 @@ source_set("public") {
"event_constants.h",
"feature_constants.cc",
"feature_constants.h",
- "feature_engagement_tracker.h",
"feature_list.cc",
"feature_list.h",
+ "tracker.h",
]
deps = [
@@ -23,23 +23,29 @@ source_set("public") {
"//components/flags_ui",
"//components/keyed_service/core",
]
-
- if (is_android) {
- sources += [ "android/feature_engagement_tracker_jni_registrar.h" ]
- }
}
if (is_android) {
android_library("public_java") {
java_files = [
- "android/java/src/org/chromium/components/feature_engagement_tracker/EventConstants.java",
- "android/java/src/org/chromium/components/feature_engagement_tracker/FeatureConstants.java",
- "android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.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 = [
"//base:base_java",
"//third_party/android_tools:android_support_annotations_java",
]
+
+ srcjar_deps = [ ":public_java_enums_srcjar" ]
+ }
+
+ java_cpp_enum("public_java_enums_srcjar") {
+ visibility = [ ":*" ]
+
+ sources = [
+ "tracker.h",
+ ]
}
}
diff --git a/chromium/components/feature_engagement_tracker/public/event_constants.cc b/chromium/components/feature_engagement/public/event_constants.cc
index 1638095c4e2..b2fb65c5a6f 100644
--- a/chromium/components/feature_engagement_tracker/public/event_constants.cc
+++ b/chromium/components/feature_engagement/public/event_constants.cc
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/public/event_constants.h"
+#include "components/feature_engagement/public/event_constants.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace events {
#if defined(OS_WIN) || defined(OS_LINUX)
const char kOmniboxInteraction[] = "omnibox_used";
+const char kNewTabSessionTimeMet[] = "new_tab_session_time_met";
const char kHistoryDeleted[] = "history_deleted";
const char kIncognitoWindowOpened[] = "incognito_window_opened";
-const char kSessionTime[] = "session_time";
#endif // defined(OS_WIN) || defined(OS_LINUX)
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_IOS)
@@ -30,4 +30,4 @@ const char kViewedReadingList[] = "viewed_reading_list";
} // namespace events
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/public/event_constants.h b/chromium/components/feature_engagement/public/event_constants.h
index fbe217c3f3b..e6d514b2f41 100644
--- a/chromium/components/feature_engagement_tracker/public/event_constants.h
+++ b/chromium/components/feature_engagement/public/event_constants.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_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_EVENT_CONSTANTS_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_EVENT_CONSTANTS_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_EVENT_CONSTANTS_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_EVENT_CONSTANTS_H_
#include "build/build_config.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace events {
@@ -17,6 +17,9 @@ namespace events {
// The user has interacted with the omnibox.
extern const char kOmniboxInteraction[];
+// The user has satisfied the session time requirement to show the NewTabPromo
+// by accumulating 2 hours of active session time (one-off event).
+extern const char kNewTabSessionTimeMet[];
// All the events declared below are the string names
// of deferred onboarding events for the Incognito Window
@@ -26,12 +29,6 @@ extern const char kHistoryDeleted[];
// The user has opened an incognito window.
extern const char kIncognitoWindowOpened[];
-// All the events declared below are the string names
-// of common deferred onboarding events
-
-// The user has accumulated 2 hours of active session time (one-off event).
-extern const char kSessionTime[];
-
#endif // defined(OS_WIN) || defined(OS_LINUX)
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_IOS)
@@ -39,7 +36,8 @@ extern const char kSessionTime[];
// described above, but it is also used on iOS, so it must be compiled
// separately.
-// The user has opened a new tab.
+// The user has explicitly opened a new tab via an entry point from inside of
+// Chrome.
extern const char kNewTabOpened[];
#endif // defined(OS_WIN) || defined(OS_LINUX) || defined(OS_IOS)
@@ -62,6 +60,6 @@ extern const char kViewedReadingList[];
} // namespace events
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_EVENT_CONSTANTS_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_EVENT_CONSTANTS_H_
diff --git a/chromium/components/feature_engagement_tracker/public/feature_constants.cc b/chromium/components/feature_engagement/public/feature_constants.cc
index 066bcdf28f5..eb66d1f38a3 100644
--- a/chromium/components/feature_engagement_tracker/public/feature_constants.cc
+++ b/chromium/components/feature_engagement/public/feature_constants.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/feature_engagement_tracker/public/feature_constants.h"
+#include "components/feature_engagement/public/feature_constants.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
const base::Feature kIPHDemoMode{"IPH_DemoMode",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -23,6 +23,10 @@ const base::Feature kIPHDownloadPageFeature{"IPH_DownloadPage",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHDownloadPageScreenshotFeature{
"IPH_DownloadPageScreenshot", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHChromeHomeExpandFeature{
+ "IPH_ChromeHomeExpand", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHMediaDownloadFeature{"IPH_MediaDownload",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_ANDROID)
#if defined(OS_WIN) || defined(OS_LINUX)
@@ -41,4 +45,4 @@ const base::Feature kIPHBadgedReadingListFeature{
"IPH_BadgedReadingList", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_IOS)
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/public/feature_constants.h b/chromium/components/feature_engagement/public/feature_constants.h
index c0440fc919a..52052f50cd5 100644
--- a/chromium/components/feature_engagement_tracker/public/feature_constants.h
+++ b/chromium/components/feature_engagement/public/feature_constants.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_CONSTANTS_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_CONSTANTS_H_
#include "base/feature_list.h"
#include "build/build_config.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
// A feature for enabling a demonstration mode for In-Product Help (IPH).
extern const base::Feature kIPHDemoMode;
@@ -18,13 +18,15 @@ extern const base::Feature kIPHDummyFeature;
// All the features declared for Android below that are also used in Java,
// should also be declared in:
-// org.chromium.components.feature_engagement_tracker.FeatureConstants.
+// org.chromium.components.feature_engagement.FeatureConstants.
#if defined(OS_ANDROID)
extern const base::Feature kIPHDataSaverDetailFeature;
extern const base::Feature kIPHDataSaverPreviewFeature;
extern const base::Feature kIPHDownloadHomeFeature;
extern const base::Feature kIPHDownloadPageFeature;
extern const base::Feature kIPHDownloadPageScreenshotFeature;
+extern const base::Feature kIPHChromeHomeExpandFeature;
+extern const base::Feature kIPHMediaDownloadFeature;
#endif // defined(OS_ANDROID)
#if defined(OS_WIN) || defined(OS_LINUX)
@@ -38,6 +40,6 @@ extern const base::Feature kIPHNewIncognitoTabTipFeature;
extern const base::Feature kIPHBadgedReadingListFeature;
#endif // defined(OS_IOS)
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_CONSTANTS_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_CONSTANTS_H_
diff --git a/chromium/components/feature_engagement_tracker/public/feature_list.cc b/chromium/components/feature_engagement/public/feature_list.cc
index 92e2fd309c7..d2971fe97ec 100644
--- a/chromium/components/feature_engagement_tracker/public/feature_list.cc
+++ b/chromium/components/feature_engagement/public/feature_list.cc
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/feature_engagement_tracker/public/feature_list.h"
+#include "components/feature_engagement/public/feature_list.h"
-#include "components/feature_engagement_tracker/public/feature_constants.h"
+#include "components/feature_engagement/public/feature_constants.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
namespace {
// Whenever a feature is added to |kAllFeatures|, it should also be added as
// DEFINE_VARIATION_PARAM in the header, and also added to the
// |kIPHDemoModeChoiceVariations| array.
-const base::Feature* kAllFeatures[] = {
+const base::Feature* const kAllFeatures[] = {
&kIPHDummyFeature, // Ensures non-empty array for all platforms.
#if defined(OS_ANDROID)
&kIPHDataSaverDetailFeature,
@@ -20,6 +20,8 @@ const base::Feature* kAllFeatures[] = {
&kIPHDownloadHomeFeature,
&kIPHDownloadPageFeature,
&kIPHDownloadPageScreenshotFeature,
+ &kIPHChromeHomeExpandFeature,
+ &kIPHMediaDownloadFeature,
#endif // defined(OS_ANDROID)
#if defined(OS_WIN) || defined(OS_LINUX)
&kIPHIncognitoWindowFeature,
@@ -40,4 +42,4 @@ std::vector<const base::Feature*> GetAllFeatures() {
kAllFeatures, kAllFeatures + arraysize(kAllFeatures));
}
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement_tracker/public/feature_list.h b/chromium/components/feature_engagement/public/feature_list.h
index a815e40e484..b260327ff22 100644
--- a/chromium/components/feature_engagement_tracker/public/feature_list.h
+++ b/chromium/components/feature_engagement/public/feature_list.h
@@ -2,23 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_LIST_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_LIST_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_LIST_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_LIST_H_
#include <vector>
#include "base/feature_list.h"
#include "build/build_config.h"
-#include "components/feature_engagement_tracker/public/feature_constants.h"
+#include "components/feature_engagement/public/feature_constants.h"
#include "components/flags_ui/feature_entry.h"
-namespace feature_engagement_tracker {
+namespace feature_engagement {
using FeatureVector = std::vector<const base::Feature*>;
// The param name for the FeatureVariation configuration, which is used by
-// chrome://flags to set the variable name for the selected feature. The
-// FeatureEngagementTracker backend will then read this to figure out which
-// feature (if any) was selected by the end user.
+// chrome://flags to set the variable name for the selected feature. The Tracker
+// backend will then read this to figure out which feature (if any) was selected
+// by the end user.
extern const char kIPHDemoModeFeatureChoiceParam[];
namespace {
@@ -51,6 +51,8 @@ DEFINE_VARIATION_PARAM(kIPHDownloadHomeFeature, "IPH_DownloadHome");
DEFINE_VARIATION_PARAM(kIPHDownloadPageFeature, "IPH_DownloadPage");
DEFINE_VARIATION_PARAM(kIPHDownloadPageScreenshotFeature,
"IPH_DownloadPageScreenshot");
+DEFINE_VARIATION_PARAM(kIPHChromeHomeExpandFeature, "IPH_ChromeHomeExpand");
+DEFINE_VARIATION_PARAM(kIPHMediaDownloadFeature, "IPH_MediaDownload");
#endif // defined(OS_ANDROID)
#if defined(OS_WIN) || defined(OS_LINUX)
DEFINE_VARIATION_PARAM(kIPHIncognitoWindowFeature, "IPH_IncognitoWindow");
@@ -75,6 +77,8 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHDownloadHomeFeature),
VARIATION_ENTRY(kIPHDownloadPageFeature),
VARIATION_ENTRY(kIPHDownloadPageScreenshotFeature),
+ VARIATION_ENTRY(kIPHChromeHomeExpandFeature),
+ VARIATION_ENTRY(kIPHMediaDownloadFeature),
#elif defined(OS_WIN) || defined(OS_LINUX)
VARIATION_ENTRY(kIPHIncognitoWindowFeature),
VARIATION_ENTRY(kIPHNewTabFeature),
@@ -93,6 +97,6 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
// Returns all the features that are in use for engagement tracking.
FeatureVector GetAllFeatures();
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_LIST_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_FEATURE_LIST_H_
diff --git a/chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h b/chromium/components/feature_engagement/public/tracker.h
index 53f82b2cbba..22040a51ac8 100644
--- a/chromium/components/feature_engagement_tracker/public/feature_engagement_tracker.h
+++ b/chromium/components/feature_engagement/public/tracker.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_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
+#ifndef COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_
#include <string>
@@ -13,27 +13,38 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#endif // defined(OS_ANDROID)
-namespace feature_engagement_tracker {
+namespace feature_engagement {
-// The FeatureEngagementTracker provides a backend for displaying feature
+// The Tracker provides a backend for displaying feature
// enlightenment or in-product help (IPH) with a clean and easy to use API to be
// consumed by the UI frontend. The backend behaves as a black box and takes
// 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 FeatureEngagementTracker : public KeyedService {
+class Tracker : public KeyedService {
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
+ // base::Feature. NOT_READY is returned if the Tracker has not been
+ // initialized yet before the call to GetTriggerState(...).
+ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.feature_engagement
+ enum class TriggerState : int {
+ HAS_BEEN_DISPLAYED = 0,
+ HAS_NOT_BEEN_DISPLAYED = 1,
+ NOT_READY = 2
+ };
+
#if defined(OS_ANDROID)
- // Returns a Java object of the type FeatureEngagementTracker for the given
- // FeatureEngagementTracker.
+ // Returns a Java object of the type Tracker for the given Tracker.
static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
- FeatureEngagementTracker* feature_engagement_tracker);
+ Tracker* feature_engagement);
#endif // defined(OS_ANDROID)
// Invoked when the tracker has been initialized. The |success| parameter
@@ -43,7 +54,7 @@ class FeatureEngagementTracker : public KeyedService {
// The |storage_dir| is the path to where all local storage will be.
// The |bakground_task_runner| will be used for all disk reads and writes.
- static FeatureEngagementTracker* Create(
+ static Tracker* Create(
const base::FilePath& storage_dir,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
@@ -58,12 +69,23 @@ class FeatureEngagementTracker : public KeyedService {
virtual bool ShouldTriggerHelpUI(const base::Feature& feature)
WARN_UNUSED_RESULT = 0;
+ // This function can be called to query if a particular |feature| meets its
+ // particular precondition for triggering within the bounds of the current
+ // feature configuration.
+ // Calling this method requires the Tracker to already have been initialized.
+ // See IsInitialized() and AddOnInitializedCallback(...) for how to ensure
+ // the call to this is delayed.
+ // This function can typically be used to ensure that expensive operations
+ // for tracking other state related to in-product help do not happen if
+ // in-product help has already been displayed for the given |feature|.
+ virtual TriggerState GetTriggerState(const base::Feature& feature) = 0;
+
// Must be called after display of feature enlightenment finishes for a
// particular |feature|.
virtual void Dismissed(const base::Feature& feature) = 0;
// Returns whether the tracker has been successfully initialized. During
- // startup, this will be false until the internal model has been loaded at
+ // startup, this will be false until the internal models have been loaded at
// which point it is set to true if the initialization was successful. The
// state will never change from initialized to uninitialized.
// Callers can invoke AddOnInitializedCallback(...) to be notified when the
@@ -78,12 +100,12 @@ class FeatureEngagementTracker : public KeyedService {
virtual void AddOnInitializedCallback(OnInitializedCallback callback) = 0;
protected:
- FeatureEngagementTracker() = default;
+ Tracker() = default;
private:
- DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTracker);
+ DISALLOW_COPY_AND_ASSIGN(Tracker);
};
-} // namespace feature_engagement_tracker
+} // namespace feature_engagement
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_PUBLIC_FEATURE_ENGAGEMENT_TRACKER_H_
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_TRACKER_H_
diff --git a/chromium/components/feature_engagement_tracker/test/BUILD.gn b/chromium/components/feature_engagement/test/BUILD.gn
index 41a0b9b6b1f..1c9986b7413 100644
--- a/chromium/components/feature_engagement_tracker/test/BUILD.gn
+++ b/chromium/components/feature_engagement/test/BUILD.gn
@@ -6,13 +6,13 @@ source_set("test_support") {
testonly = true
sources = [
- "test_feature_engagement_tracker.cc",
- "test_feature_engagement_tracker.h",
+ "test_tracker.cc",
+ "test_tracker.h",
]
deps = [
"//base",
- "//components/feature_engagement_tracker/internal",
- "//components/feature_engagement_tracker/public",
+ "//components/feature_engagement/internal",
+ "//components/feature_engagement/public",
]
}
diff --git a/chromium/components/feature_engagement_tracker/OWNERS b/chromium/components/feature_engagement_tracker/OWNERS
deleted file mode 100644
index 6b65e3713b5..00000000000
--- a/chromium/components/feature_engagement_tracker/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-dtrainor@chromium.org
-nyquist@chromium.org
-
-# COMPONENT: Internals>FeatureEngagementTracker
-
diff --git a/chromium/components/feature_engagement_tracker/components_unittests.filter b/chromium/components/feature_engagement_tracker/components_unittests.filter
deleted file mode 100644
index aa34f4a6045..00000000000
--- a/chromium/components/feature_engagement_tracker/components_unittests.filter
+++ /dev/null
@@ -1,21 +0,0 @@
-AvailabilityModelImplTest.*
-AvailabilityStoreTest.*
-ChromeVariationsConfigurationTest.*
-ComparatorTest.*
-ConditionValidatorResultTest.*
-EditableConfigurationTest.*
-FailingStoreInitFeatureEngagementTrackerImplTest.*
-FailingAvailabilityModelInitFeatureEngagementTrackerImplTest.*
-FeatureConfigConditionValidatorTest.*
-FeatureConfigStorageValidatorTest.*
-FeatureEngagementTrackerImplTest.*
-InitAwareModelTest.*
-InMemoryStoreTest.*
-LoadFailingModelImplTest.*
-ModelImplTest.*
-NeverAvailabilityModelTest.*
-NeverConditionValidatorTest.*
-OnceConditionValidatorTest.*
-PersistentStoreTest.*
-SingleInvalidConfigurationTest.*
-SystemTimeProviderTest.*
diff --git a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc b/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
deleted file mode 100644
index c2dd33f74c3..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h"
-
-#include <vector>
-
-#include "base/android/callback_android.h"
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
-#include "components/feature_engagement_tracker/public/feature_list.h"
-#include "jni/FeatureEngagementTrackerImpl_jni.h"
-
-namespace feature_engagement_tracker {
-
-namespace {
-
-const char kFeatureEngagementTrackerImplAndroidKey[] =
- "feature_engagement_tracker_impl_android";
-
-// Create mapping from feature name to base::Feature.
-FeatureEngagementTrackerImplAndroid::FeatureMap CreateMapFromNameToFeature(
- FeatureVector features) {
- FeatureEngagementTrackerImplAndroid::FeatureMap feature_map;
- for (auto it = features.begin(); it != features.end(); ++it) {
- feature_map[(*it)->name] = *it;
- }
- return feature_map;
-}
-
-FeatureEngagementTrackerImplAndroid* FromFeatureEngagementTrackerImpl(
- FeatureEngagementTracker* feature_engagement_tracker) {
- FeatureEngagementTrackerImpl* impl =
- static_cast<FeatureEngagementTrackerImpl*>(feature_engagement_tracker);
- FeatureEngagementTrackerImplAndroid* impl_android =
- static_cast<FeatureEngagementTrackerImplAndroid*>(
- impl->GetUserData(kFeatureEngagementTrackerImplAndroidKey));
- if (!impl_android) {
- impl_android =
- new FeatureEngagementTrackerImplAndroid(impl, GetAllFeatures());
- impl->SetUserData(kFeatureEngagementTrackerImplAndroidKey,
- base::WrapUnique(impl_android));
- }
- return impl_android;
-}
-
-} // namespace
-
-// static
-bool FeatureEngagementTrackerImplAndroid::RegisterJni(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-// static
-FeatureEngagementTrackerImplAndroid*
-FeatureEngagementTrackerImplAndroid::FromJavaObject(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj) {
- return reinterpret_cast<FeatureEngagementTrackerImplAndroid*>(
- Java_FeatureEngagementTrackerImpl_getNativePtr(env, jobj));
-}
-
-// This function is declared in
-// //components/feature_engagement_tracker/public/feature_engagement_tracker.h
-// and should be linked in to any binary using
-// FeatureEngagementTracker::GetJavaObject.
-// static
-base::android::ScopedJavaLocalRef<jobject>
-FeatureEngagementTracker::GetJavaObject(
- FeatureEngagementTracker* feature_engagement_tracker) {
- return FromFeatureEngagementTrackerImpl(feature_engagement_tracker)
- ->GetJavaObject();
-}
-
-FeatureEngagementTrackerImplAndroid::FeatureEngagementTrackerImplAndroid(
- FeatureEngagementTrackerImpl* feature_engagement_tracker_impl,
- FeatureVector features)
- : features_(CreateMapFromNameToFeature(features)),
- feature_engagement_tracker_impl_(feature_engagement_tracker_impl) {
- JNIEnv* env = base::android::AttachCurrentThread();
-
- java_obj_.Reset(env, Java_FeatureEngagementTrackerImpl_create(
- env, reinterpret_cast<intptr_t>(this))
- .obj());
-}
-
-FeatureEngagementTrackerImplAndroid::~FeatureEngagementTrackerImplAndroid() {
- Java_FeatureEngagementTrackerImpl_clearNativePtr(
- base::android::AttachCurrentThread(), java_obj_);
-}
-
-base::android::ScopedJavaLocalRef<jobject>
-FeatureEngagementTrackerImplAndroid::GetJavaObject() {
- return base::android::ScopedJavaLocalRef<jobject>(java_obj_);
-}
-
-void FeatureEngagementTrackerImplAndroid::NotifyEvent(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj,
- const base::android::JavaParamRef<jstring>& jevent) {
- std::string event = ConvertJavaStringToUTF8(env, jevent);
- feature_engagement_tracker_impl_->NotifyEvent(event);
-}
-
-bool FeatureEngagementTrackerImplAndroid::ShouldTriggerHelpUI(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj,
- const base::android::JavaParamRef<jstring>& jfeature) {
- std::string feature = ConvertJavaStringToUTF8(env, jfeature);
- DCHECK(features_.find(feature) != features_.end());
-
- return feature_engagement_tracker_impl_->ShouldTriggerHelpUI(
- *features_[feature]);
-}
-
-void FeatureEngagementTrackerImplAndroid::Dismissed(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj,
- const base::android::JavaParamRef<jstring>& jfeature) {
- std::string feature = ConvertJavaStringToUTF8(env, jfeature);
- DCHECK(features_.find(feature) != features_.end());
-
- feature_engagement_tracker_impl_->Dismissed(*features_[feature]);
-}
-
-bool FeatureEngagementTrackerImplAndroid::IsInitialized(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj) {
- return feature_engagement_tracker_impl_->IsInitialized();
-}
-
-void FeatureEngagementTrackerImplAndroid::AddOnInitializedCallback(
- JNIEnv* env,
- const base::android::JavaRef<jobject>& jobj,
- const base::android::JavaParamRef<jobject>& j_callback_obj) {
- // Disambiguate RunCallbackAndroid to get the reference to the bool version.
- void (*runBoolCallback)(const base::android::JavaRef<jobject>&, bool) =
- &base::android::RunCallbackAndroid;
- feature_engagement_tracker_impl_->AddOnInitializedCallback(
- base::Bind(runBoolCallback,
- base::android::ScopedJavaGlobalRef<jobject>(j_callback_obj)));
-}
-
-} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc b/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc
deleted file mode 100644
index 2e78551d117..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/in_memory_store.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/feature_engagement_tracker/internal/in_memory_store.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/feature_engagement_tracker/internal/store.h"
-
-namespace feature_engagement_tracker {
-
-InMemoryStore::InMemoryStore(std::unique_ptr<std::vector<Event>> events)
- : Store(), events_(std::move(events)), ready_(false) {}
-
-InMemoryStore::InMemoryStore()
- : InMemoryStore(base::MakeUnique<std::vector<Event>>()) {}
-
-InMemoryStore::~InMemoryStore() = default;
-
-void InMemoryStore::Load(const OnLoadedCallback& callback) {
- HandleLoadResult(callback, true);
-}
-
-bool InMemoryStore::IsReady() const {
- return ready_;
-}
-
-void InMemoryStore::WriteEvent(const Event& event) {
- // Intentionally ignore all writes.
-}
-
-void InMemoryStore::DeleteEvent(const std::string& event_name) {
- // Intentionally ignore all deletes.
-}
-
-void InMemoryStore::HandleLoadResult(const OnLoadedCallback& callback,
- bool success) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, success, base::Passed(&events_)));
- ready_ = success;
-}
-
-} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/init_aware_model.cc b/chromium/components/feature_engagement_tracker/internal/init_aware_model.cc
deleted file mode 100644
index c514a705f05..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/init_aware_model.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/feature_engagement_tracker/internal/init_aware_model.h"
-
-#include "base/bind.h"
-
-namespace feature_engagement_tracker {
-
-InitAwareModel::InitAwareModel(std::unique_ptr<Model> model)
- : model_(std::move(model)),
- initialization_complete_(false),
- weak_ptr_factory_(this) {
- DCHECK(model_);
-}
-
-InitAwareModel::~InitAwareModel() = default;
-
-void InitAwareModel::Initialize(const OnModelInitializationFinished& callback,
- uint32_t current_day) {
- model_->Initialize(base::Bind(&InitAwareModel::OnInitializeComplete,
- weak_ptr_factory_.GetWeakPtr(), callback),
- current_day);
-}
-
-bool InitAwareModel::IsReady() const {
- return model_->IsReady();
-}
-
-const Event* InitAwareModel::GetEvent(const std::string& event_name) const {
- return model_->GetEvent(event_name);
-}
-
-void InitAwareModel::IncrementEvent(const std::string& event_name,
- uint32_t current_day) {
- if (IsReady()) {
- model_->IncrementEvent(event_name, current_day);
- return;
- }
-
- if (initialization_complete_)
- return;
-
- queued_events_.push_back(std::tie(event_name, current_day));
-}
-
-void InitAwareModel::OnInitializeComplete(
- const OnModelInitializationFinished& callback,
- bool success) {
- initialization_complete_ = true;
- if (success) {
- for (auto& event : queued_events_)
- model_->IncrementEvent(std::get<0>(event), std::get<1>(event));
- }
- queued_events_.clear();
-
- callback.Run(success);
-}
-
-size_t InitAwareModel::GetQueuedEventCountForTesting() {
- return queued_events_.size();
-}
-
-} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/never_storage_validator.cc b/chromium/components/feature_engagement_tracker/internal/never_storage_validator.cc
deleted file mode 100644
index c919dbc6cdd..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/never_storage_validator.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/feature_engagement_tracker/internal/never_storage_validator.h"
-
-namespace feature_engagement_tracker {
-
-NeverStorageValidator::NeverStorageValidator() = default;
-
-NeverStorageValidator::~NeverStorageValidator() = default;
-
-bool NeverStorageValidator::ShouldStore(const std::string& event_name) const {
- return false;
-}
-
-bool NeverStorageValidator::ShouldKeep(const std::string& event_name,
- uint32_t event_day,
- uint32_t current_day) const {
- return false;
-}
-
-} // namespace feature_engagement_tracker
diff --git a/chromium/components/feature_engagement_tracker/internal/never_storage_validator.h b/chromium/components/feature_engagement_tracker/internal/never_storage_validator.h
deleted file mode 100644
index 0194bf29608..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/never_storage_validator.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_STORAGE_VALIDATOR_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_STORAGE_VALIDATOR_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/storage_validator.h"
-
-namespace feature_engagement_tracker {
-
-// A StorageValidator that never acknowledges that an event should be kept or
-// stored.
-class NeverStorageValidator : public StorageValidator {
- public:
- NeverStorageValidator();
- ~NeverStorageValidator() override;
-
- // StorageValidator implementation.
- bool ShouldStore(const std::string& event_name) const override;
- bool ShouldKeep(const std::string& event_name,
- uint32_t event_day,
- uint32_t current_day) const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NeverStorageValidator);
-};
-
-} // namespace feature_engagement_tracker
-
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_NEVER_STORAGE_VALIDATOR_H_
diff --git a/chromium/components/feature_engagement_tracker/internal/persistent_store.h b/chromium/components/feature_engagement_tracker/internal/persistent_store.h
deleted file mode 100644
index bbbf0fc8b17..00000000000
--- a/chromium/components/feature_engagement_tracker/internal/persistent_store.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_PERSISTENT_STORE_H_
-#define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_PERSISTENT_STORE_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
-#include "components/feature_engagement_tracker/internal/store.h"
-#include "components/leveldb_proto/proto_database.h"
-
-namespace feature_engagement_tracker {
-
-// A PersistentStore provides a DB layer that persists the data to disk. The
-// data is retrieved once during the load process and after that this store is
-// write only. Data will be persisted asynchronously so it is not guaranteed to
-// always save every write during shutdown.
-class PersistentStore : public Store {
- public:
- // Builds a PersistentStore backed by the ProtoDatabase |db|. The database
- // will be loaded and/or created at |storage_dir|.
- PersistentStore(const base::FilePath& storage_dir,
- std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db);
- ~PersistentStore() override;
-
- // Store implementation.
- void Load(const OnLoadedCallback& callback) override;
- bool IsReady() const override;
- void WriteEvent(const Event& event) override;
- void DeleteEvent(const std::string& event_name) override;
-
- private:
- void OnInitComplete(const OnLoadedCallback& callback, bool success);
- void OnLoadComplete(const OnLoadedCallback& callback,
- bool success,
- std::unique_ptr<std::vector<Event>> entries);
-
- const base::FilePath storage_dir_;
- std::unique_ptr<leveldb_proto::ProtoDatabase<Event>> db_;
-
- // Whether or not the underlying ProtoDatabase is ready. This will be false
- // until the OnLoadedCallback is broadcast. It will also be false if loading
- // fails.
- bool ready_;
-
- base::WeakPtrFactory<PersistentStore> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PersistentStore);
-};
-
-} // namespace feature_engagement_tracker
-
-#endif // COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_PERSISTENT_STORE_H_
diff --git a/chromium/components/feedback/BUILD.gn b/chromium/components/feedback/BUILD.gn
index e92d5d0e4ee..a3fa1d102b3 100644
--- a/chromium/components/feedback/BUILD.gn
+++ b/chromium/components/feedback/BUILD.gn
@@ -16,8 +16,6 @@ static_library("feedback") {
"feedback_switches.h",
"feedback_uploader.cc",
"feedback_uploader.h",
- "feedback_uploader_chrome.cc",
- "feedback_uploader_chrome.h",
"feedback_uploader_delegate.cc",
"feedback_uploader_delegate.h",
"feedback_uploader_factory.cc",
@@ -53,7 +51,7 @@ source_set("unit_tests") {
"anonymizer_tool_unittest.cc",
"feedback_common_unittest.cc",
"feedback_data_unittest.cc",
- "feedback_uploader_chrome_unittest.cc",
+ "feedback_uploader_dispatch_unittest.cc",
"feedback_uploader_unittest.cc",
]
deps = [
diff --git a/chromium/components/feedback/feedback_data.cc b/chromium/components/feedback/feedback_data.cc
index d46b8b182b1..5beccf77eca 100644
--- a/chromium/components/feedback/feedback_data.cc
+++ b/chromium/components/feedback/feedback_data.cc
@@ -15,6 +15,7 @@
#include "base/task_scheduler/post_task.h"
#include "base/values.h"
#include "components/feedback/feedback_util.h"
+#include "components/feedback/proto/extension.pb.h"
#include "components/feedback/tracing_manager.h"
#include "content/public/browser/browser_thread.h"
@@ -33,9 +34,14 @@ const char kHistogramsAttachmentName[] = "histograms.zip";
} // namespace
-FeedbackData::FeedbackData()
- : send_report_(base::Bind(&feedback_util::SendReport)), context_(NULL),
- trace_id_(0), pending_op_count_(1), report_sent_(false) {}
+FeedbackData::FeedbackData(feedback::FeedbackUploader* uploader)
+ : uploader_(uploader),
+ context_(nullptr),
+ trace_id_(0),
+ pending_op_count_(1),
+ report_sent_(false) {
+ CHECK(uploader_);
+}
FeedbackData::~FeedbackData() {
}
@@ -135,7 +141,11 @@ void FeedbackData::SendReport() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (IsDataComplete() && !report_sent_) {
report_sent_ = true;
- send_report_.Run(this);
+ userfeedback::ExtensionSubmit feedback_data;
+ PrepareReport(&feedback_data);
+ std::string post_body;
+ feedback_data.SerializeToString(&post_body);
+ uploader_->QueueReport(post_body);
}
}
diff --git a/chromium/components/feedback/feedback_data.h b/chromium/components/feedback/feedback_data.h
index 0a3bcfa2e59..fa2d2c98d3b 100644
--- a/chromium/components/feedback/feedback_data.h
+++ b/chromium/components/feedback/feedback_data.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "components/feedback/feedback_common.h"
+#include "components/feedback/feedback_uploader.h"
#include "url/gurl.h"
namespace base {
@@ -24,7 +25,7 @@ namespace feedback {
class FeedbackData : public FeedbackCommon {
public:
- FeedbackData();
+ FeedbackData(feedback::FeedbackUploader* uploader);
// Called once we've updated all the data from the feedback page.
void OnFeedbackPageDataComplete();
@@ -66,10 +67,6 @@ class FeedbackData : public FeedbackCommon {
screenshot_uuid_ = uuid;
}
void set_trace_id(int trace_id) { trace_id_ = trace_id; }
- void set_send_report_callback(
- const base::Callback<void(scoped_refptr<FeedbackData>)>& send_report) {
- send_report_ = send_report;
- }
private:
~FeedbackData() override;
@@ -80,7 +77,7 @@ class FeedbackData : public FeedbackCommon {
void OnGetTraceData(int trace_id,
scoped_refptr<base::RefCountedString> trace_data);
- base::Callback<void(scoped_refptr<FeedbackData>)> send_report_;
+ feedback::FeedbackUploader* uploader_; // Not owned.
content::BrowserContext* context_;
diff --git a/chromium/components/feedback/feedback_data_unittest.cc b/chromium/components/feedback/feedback_data_unittest.cc
index 5171b75af2e..6b15c186c57 100644
--- a/chromium/components/feedback/feedback_data_unittest.cc
+++ b/chromium/components/feedback/feedback_data_unittest.cc
@@ -5,20 +5,16 @@
#include "components/feedback/feedback_data.h"
#include <memory>
-#include <set>
-#include <utility>
#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "components/feedback/feedback_report.h"
#include "components/feedback/feedback_uploader.h"
#include "components/feedback/feedback_uploader_factory.h"
-#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/user_prefs/user_prefs.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace feedback {
@@ -29,23 +25,23 @@ constexpr char kHistograms[] = "";
constexpr char kImageData[] = "";
constexpr char kFileData[] = "";
-class MockUploader : public feedback::FeedbackUploader, public KeyedService {
+class MockUploader : public FeedbackUploader {
public:
MockUploader(content::BrowserContext* context,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : FeedbackUploader(context ? context->GetPath() : base::FilePath(),
- task_runner) {}
+ const base::Closure& on_report_sent)
+ : FeedbackUploader(context,
+ FeedbackUploaderFactory::CreateUploaderTaskRunner()),
+ on_report_sent_(on_report_sent) {}
+ ~MockUploader() override {}
- MOCK_METHOD1(DispatchReport, void(scoped_refptr<FeedbackReport>));
-};
+ // feedback::FeedbackUploader:
+ void StartDispatchingReport() override { on_report_sent_.Run(); }
-std::unique_ptr<KeyedService> CreateFeedbackUploaderService(
- content::BrowserContext* context) {
- auto uploader = base::MakeUnique<MockUploader>(
- context, FeedbackUploaderFactory::CreateUploaderTaskRunner());
- EXPECT_CALL(*uploader, DispatchReport(testing::_)).Times(1);
- return std::move(uploader);
-}
+ private:
+ base::Closure on_report_sent_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockUploader);
+};
std::unique_ptr<std::string> MakeScoped(const char* str) {
return base::MakeUnique<std::string>(str);
@@ -56,17 +52,11 @@ std::unique_ptr<std::string> MakeScoped(const char* str) {
class FeedbackDataTest : public testing::Test {
protected:
FeedbackDataTest()
- : context_(new content::TestBrowserContext()),
- prefs_(new TestingPrefServiceSimple()),
- data_(new FeedbackData()) {
- user_prefs::UserPrefs::Set(context_.get(), prefs_.get());
- data_->set_context(context_.get());
- data_->set_send_report_callback(base::Bind(
- &FeedbackDataTest::set_send_report_callback, base::Unretained(this)));
-
- FeedbackUploaderFactory::GetInstance()->SetTestingFactory(
- context_.get(), &CreateFeedbackUploaderService);
- }
+ : uploader_(&context_,
+ base::Bind(&FeedbackDataTest::set_send_report_callback,
+ base::Unretained(this))),
+ data_(base::MakeRefCounted<FeedbackData>(&uploader_)) {}
+ ~FeedbackDataTest() override = default;
void Send() {
bool attached_file_completed =
@@ -85,16 +75,14 @@ class FeedbackDataTest : public testing::Test {
run_loop_->Run();
}
- void set_send_report_callback(scoped_refptr<FeedbackData> data) {
- quit_closure_.Run();
- }
+ void set_send_report_callback() { quit_closure_.Run(); }
base::Closure quit_closure_;
std::unique_ptr<base::RunLoop> run_loop_;
- std::unique_ptr<content::TestBrowserContext> context_;
- std::unique_ptr<PrefService> prefs_;
- scoped_refptr<FeedbackData> data_;
content::TestBrowserThreadBundle test_browser_thread_bundle_;
+ content::TestBrowserContext context_;
+ MockUploader uploader_;
+ scoped_refptr<FeedbackData> data_;
};
TEST_F(FeedbackDataTest, ReportSending) {
diff --git a/chromium/components/feedback/feedback_report.cc b/chromium/components/feedback/feedback_report.cc
index 48f825ec66f..984ba9c10c1 100644
--- a/chromium/components/feedback/feedback_report.cc
+++ b/chromium/components/feedback/feedback_report.cc
@@ -83,6 +83,8 @@ void FeedbackReport::DeleteReportOnDisk() {
base::Bind(base::IgnoreResult(&base::DeleteFile), file_, false));
}
-FeedbackReport::~FeedbackReport() {}
+FeedbackReport::~FeedbackReport() {
+ DeleteReportOnDisk();
+}
} // namespace feedback
diff --git a/chromium/components/feedback/feedback_uploader.cc b/chromium/components/feedback/feedback_uploader.cc
index a17c9a7df03..3f36feb30f6 100644
--- a/chromium/components/feedback/feedback_uploader.cc
+++ b/chromium/components/feedback/feedback_uploader.cc
@@ -4,22 +4,29 @@
#include "components/feedback/feedback_uploader.h"
-#include <stdint.h>
-
#include "base/callback.h"
#include "base/command_line.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/feedback/feedback_report.h"
#include "components/feedback/feedback_switches.h"
+#include "components/feedback/feedback_uploader_delegate.h"
+#include "components/variations/net/variations_http_headers.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_fetcher.h"
namespace feedback {
namespace {
+constexpr base::FilePath::CharType kFeedbackReportPath[] =
+ FILE_PATH_LITERAL("Feedback Reports");
+
constexpr char kFeedbackPostUrl[] =
"https://www.google.com/tools/feedback/chrome/__submit";
-constexpr base::FilePath::CharType kFeedbackReportPath[] =
- FILE_PATH_LITERAL("Feedback Reports");
+constexpr char kProtoBufMimeType[] = "application/x-protobuf";
// The minimum time to wait before uploading reports are retried. Exponential
// backoff delay is applied on successive failures.
@@ -27,6 +34,14 @@ constexpr base::FilePath::CharType kFeedbackReportPath[] =
// FeedbackUploader::SetMinimumRetryDelayForTesting().
base::TimeDelta g_minimum_retry_delay = base::TimeDelta::FromMinutes(60);
+// If a new report is queued to be dispatched immediately while another is being
+// dispatched, this is the time to wait for the on-going dispatching to finish.
+base::TimeDelta g_dispatching_wait_delay = base::TimeDelta::FromSeconds(4);
+
+base::FilePath GetPathFromContext(content::BrowserContext* context) {
+ return context->GetPath().Append(kFeedbackReportPath);
+}
+
GURL GetFeedbackPostGURL() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -38,13 +53,16 @@ GURL GetFeedbackPostGURL() {
} // namespace
FeedbackUploader::FeedbackUploader(
- const base::FilePath& path,
+ content::BrowserContext* context,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : feedback_reports_path_(path.Append(kFeedbackReportPath)),
+ : context_(context),
+ feedback_reports_path_(GetPathFromContext(context)),
task_runner_(task_runner),
+ feedback_post_url_(GetFeedbackPostGURL()),
retry_delay_(g_minimum_retry_delay),
- feedback_post_url_(GetFeedbackPostGURL()) {
+ is_dispatching_(false) {
DCHECK(task_runner_);
+ DCHECK(context_);
}
FeedbackUploader::~FeedbackUploader() {}
@@ -58,17 +76,32 @@ void FeedbackUploader::QueueReport(const std::string& data) {
QueueReportWithDelay(data, base::TimeDelta());
}
+void FeedbackUploader::StartDispatchingReport() {
+ DispatchReport();
+}
+
void FeedbackUploader::OnReportUploadSuccess() {
retry_delay_ = g_minimum_retry_delay;
+ is_dispatching_ = false;
+ // Explicitly release the successfully dispatched report.
+ report_being_dispatched_ = nullptr;
UpdateUploadTimer();
}
-void FeedbackUploader::OnReportUploadFailure(
- scoped_refptr<FeedbackReport> report) {
- // Implement a backoff delay by doubling the retry delay on each failure.
- retry_delay_ *= 2;
- report->set_upload_at(retry_delay_ + base::Time::Now());
- reports_queue_.emplace(report);
+void FeedbackUploader::OnReportUploadFailure(bool should_retry) {
+ if (should_retry) {
+ // Implement a backoff delay by doubling the retry delay on each failure.
+ retry_delay_ *= 2;
+ report_being_dispatched_->set_upload_at(retry_delay_ + base::Time::Now());
+ reports_queue_.emplace(report_being_dispatched_);
+ }
+
+ // The report dispatching failed, and should either be retried or not. In all
+ // cases, we need to release |report_being_dispatched_|. If it was up for
+ // retry, then it has already been re-enqueued and will be kept alive.
+ // Otherwise we're done with it and it should destruct.
+ report_being_dispatched_ = nullptr;
+ is_dispatching_ = false;
UpdateUploadTimer();
}
@@ -78,22 +111,92 @@ bool FeedbackUploader::ReportsUploadTimeComparator::operator()(
return a->upload_at() > b->upload_at();
}
+void FeedbackUploader::AppendExtraHeadersToUploadRequest(
+ net::URLFetcher* fetcher) {}
+
+void FeedbackUploader::DispatchReport() {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("chrome_feedback_report_app", R"(
+ semantics {
+ sender: "Chrome Feedback Report App"
+ description:
+ "Users can press Alt+Shift+i to report a bug or a feedback in "
+ "general. Along with the free-form text they entered, system logs "
+ "that helps in diagnosis of the issue are sent to Google. This "
+ "service uploads the report to Google Feedback server."
+ trigger:
+ "When user chooses to send a feedback to Google."
+ data:
+ "The free-form text that user has entered and useful debugging "
+ "logs (UI logs, Chrome logs, kernel logs, auto update engine logs, "
+ "ARC++ logs, etc.). The logs are anonymized to remove any "
+ "user-private data. The user can view the system information "
+ "before sending, and choose to send the feedback report without "
+ "system information and the logs (unchecking 'Send system "
+ "information' prevents sending logs as well), the screenshot, or "
+ "even his/her email address."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This feature cannot be disabled by settings and is only activated "
+ "by direct user request."
+ policy_exception_justification: "Not implemented."
+ })");
+ // Note: FeedbackUploaderDelegate deletes itself and the fetcher.
+ net::URLFetcher* fetcher =
+ net::URLFetcher::Create(
+ feedback_post_url_, net::URLFetcher::POST,
+ new FeedbackUploaderDelegate(
+ base::Bind(&FeedbackUploader::OnReportUploadSuccess, AsWeakPtr()),
+ base::Bind(&FeedbackUploader::OnReportUploadFailure,
+ AsWeakPtr())),
+ traffic_annotation)
+ .release();
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher, data_use_measurement::DataUseUserData::FEEDBACK_UPLOADER);
+ // Tell feedback server about the variation state of this install.
+ net::HttpRequestHeaders headers;
+ // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does
+ // not affect transmission of experiments coming from the variations server.
+ const bool is_signed_in = false;
+ variations::AppendVariationHeaders(fetcher->GetOriginalURL(),
+ context_->IsOffTheRecord(), false,
+ is_signed_in, &headers);
+ fetcher->SetExtraRequestHeaders(headers.ToString());
+
+ fetcher->SetUploadData(kProtoBufMimeType, report_being_dispatched_->data());
+ fetcher->SetRequestContext(
+ content::BrowserContext::GetDefaultStoragePartition(context_)
+ ->GetURLRequestContext());
+
+ AppendExtraHeadersToUploadRequest(fetcher);
+
+ fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_COOKIES);
+ fetcher->Start();
+}
+
void FeedbackUploader::UpdateUploadTimer() {
if (reports_queue_.empty())
return;
scoped_refptr<FeedbackReport> report = reports_queue_.top();
const base::Time now = base::Time::Now();
- if (report->upload_at() <= now) {
+ if (report->upload_at() <= now && !is_dispatching_) {
reports_queue_.pop();
- DispatchReport(report);
- report->DeleteReportOnDisk();
+ is_dispatching_ = true;
+ report_being_dispatched_ = report;
+ StartDispatchingReport();
} else {
// Stop the old timer and start an updated one.
+ const base::TimeDelta delay = (is_dispatching_ || now > report->upload_at())
+ ? g_dispatching_wait_delay
+ : report->upload_at() - now;
upload_timer_.Stop();
- upload_timer_.Start(
- FROM_HERE, report->upload_at() - now, this,
- &FeedbackUploader::UpdateUploadTimer);
+ upload_timer_.Start(FROM_HERE, delay, this,
+ &FeedbackUploader::UpdateUploadTimer);
}
}
diff --git a/chromium/components/feedback/feedback_uploader.h b/chromium/components/feedback/feedback_uploader.h
index eaed704ddd1..dc06ea05297 100644
--- a/chromium/components/feedback/feedback_uploader.h
+++ b/chromium/components/feedback/feedback_uploader.h
@@ -15,8 +15,17 @@
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "components/keyed_service/core/keyed_service.h"
#include "url/gurl.h"
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace net {
+class URLFetcher;
+} // namespace net
+
namespace feedback {
class FeedbackReport;
@@ -24,11 +33,12 @@ class FeedbackReport;
// FeedbackUploader is used to add a feedback report to the queue of reports
// being uploaded. In case uploading a report fails, it is written to disk and
// tried again when it's turn comes up next in the queue.
-class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
+class FeedbackUploader : public KeyedService,
+ public base::SupportsWeakPtr<FeedbackUploader> {
public:
- FeedbackUploader(const base::FilePath& path,
+ FeedbackUploader(content::BrowserContext* context,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- virtual ~FeedbackUploader();
+ ~FeedbackUploader() override;
static void SetMinimumRetryDelayForTesting(base::TimeDelta delay);
@@ -37,6 +47,8 @@ class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
bool QueueEmpty() const { return reports_queue_.empty(); }
+ content::BrowserContext* context() { return context_; }
+
const base::FilePath& feedback_reports_path() const {
return feedback_reports_path_;
}
@@ -47,18 +59,27 @@ class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
base::TimeDelta retry_delay() const { return retry_delay_; }
- const GURL& feedback_post_url() const { return feedback_post_url_; }
-
protected:
+ // Virtual to give implementers a chance to do work before the report is
+ // disptached. Implementers can then call
+ // FeedbackUploader::StartSendingReport() when ready so that the report is
+ // dispatched.
+ virtual void StartDispatchingReport();
+
// Invoked when a feedback report upload succeeds. It will reset the
// |retry_delay_| to its minimum value and schedules the next report upload if
// any.
void OnReportUploadSuccess();
- // Invoked when |report| fails to upload. It will double the |retry_delay_|
- // and reenqueue |report| with the new delay. All subsequent retries will keep
- // increasing the delay until a successful upload is encountered.
- void OnReportUploadFailure(scoped_refptr<FeedbackReport> report);
+ // Invoked when |report_being_dispatched_| fails to upload. If |should_retry|
+ // is true, it will double the |retry_delay_| and reenqueue
+ // |report_being_dispatched_| with the new delay. All subsequent retries will
+ // keep increasing the delay until a successful upload is encountered.
+ void OnReportUploadFailure(bool should_retry);
+
+ const scoped_refptr<FeedbackReport>& report_being_dispatched() const {
+ return report_being_dispatched_;
+ }
private:
friend class FeedbackUploaderTest;
@@ -68,14 +89,23 @@ class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
const scoped_refptr<FeedbackReport>& b) const;
};
- // Dispatches the report to be uploaded.
- virtual void DispatchReport(scoped_refptr<FeedbackReport> report) = 0;
+ // Called from DispatchReport() to give implementers a chance to add extra
+ // headers to the upload request before it's sent.
+ virtual void AppendExtraHeadersToUploadRequest(net::URLFetcher* fetcher);
+
+ // Uploads the |report_being_dispatched_| to be uploaded. It must
+ // call either OnReportUploadSuccess() or OnReportUploadFailure() so that
+ // dispatching reports can progress.
+ void DispatchReport();
// Update our timer for uploading the next report.
void UpdateUploadTimer();
void QueueReportWithDelay(const std::string& data, base::TimeDelta delay);
+ // Browser context this uploader was created for.
+ content::BrowserContext* context_;
+
const base::FilePath feedback_reports_path_;
// Timer to upload the next report at.
@@ -84,6 +114,10 @@ class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
// See comment of |FeedbackUploaderFactory::task_runner_|.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<FeedbackReport> report_being_dispatched_;
+
+ const GURL feedback_post_url_;
+
// Priority queue of reports prioritized by the time the report is supposed
// to be uploaded at.
std::priority_queue<scoped_refptr<FeedbackReport>,
@@ -92,7 +126,10 @@ class FeedbackUploader : public base::SupportsWeakPtr<FeedbackUploader> {
reports_queue_;
base::TimeDelta retry_delay_;
- const GURL feedback_post_url_;
+
+ // True when a report is currently being dispatched. Only a single report
+ // at-a-time should be dispatched.
+ bool is_dispatching_;
DISALLOW_COPY_AND_ASSIGN(FeedbackUploader);
};
diff --git a/chromium/components/feedback/feedback_uploader_chrome.cc b/chromium/components/feedback/feedback_uploader_chrome.cc
deleted file mode 100644
index ff8f7caee65..00000000000
--- a/chromium/components/feedback/feedback_uploader_chrome.cc
+++ /dev/null
@@ -1,100 +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 "components/feedback/feedback_uploader_chrome.h"
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/feedback/feedback_report.h"
-#include "components/feedback/feedback_uploader_delegate.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/load_flags.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "url/gurl.h"
-
-namespace feedback {
-namespace {
-
-const char kProtoBufMimeType[] = "application/x-protobuf";
-
-} // namespace
-
-FeedbackUploaderChrome::FeedbackUploaderChrome(
- content::BrowserContext* context,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : FeedbackUploader(context ? context->GetPath() : base::FilePath(),
- task_runner),
- context_(context) {
- CHECK(context_);
-}
-
-void FeedbackUploaderChrome::DispatchReport(
- scoped_refptr<FeedbackReport> report) {
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("chrome_feedback_report_app", R"(
- semantics {
- sender: "Chrome Feedback Report App"
- description:
- "Users can press Alt+Shift+i to report a bug or a feedback in "
- "general. Along with the free-form text they entered, system logs "
- "that helps in diagnosis of the issue are sent to Google. This "
- "service uploads the report to Google Feedback server."
- trigger:
- "When user chooses to send a feedback to Google."
- data:
- "The free-form text that user has entered and useful debugging "
- "logs (UI logs, Chrome logs, kernel logs, auto update engine logs, "
- "ARC++ logs, etc.). The logs are anonymized to remove any "
- "user-private data. The user can view the system information "
- "before sending, and choose to send the feedback report without "
- "system information and the logs (unchecking 'Send system "
- "information' prevents sending logs as well), the screenshot, or "
- "even his/her email address."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: false
- setting:
- "This feature cannot be disabled by settings and is only activated "
- "by direct user request."
- policy_exception_justification: "Not implemented."
- })");
- // Note: FeedbackUploaderDelegate deletes itself and the fetcher.
- net::URLFetcher* fetcher =
- net::URLFetcher::Create(
- feedback_post_url(), net::URLFetcher::POST,
- new FeedbackUploaderDelegate(
- report,
- base::Bind(&FeedbackUploaderChrome::OnReportUploadSuccess,
- AsWeakPtr()),
- base::Bind(&FeedbackUploaderChrome::OnReportUploadFailure,
- AsWeakPtr())),
- traffic_annotation)
- .release();
- data_use_measurement::DataUseUserData::AttachToFetcher(
- fetcher, data_use_measurement::DataUseUserData::FEEDBACK_UPLOADER);
- // Tell feedback server about the variation state of this install.
- net::HttpRequestHeaders headers;
- // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does
- // not affect transmission of experiments coming from the variations server.
- const bool is_signed_in = false;
- variations::AppendVariationHeaders(fetcher->GetOriginalURL(),
- context_->IsOffTheRecord(), false,
- is_signed_in, &headers);
- fetcher->SetExtraRequestHeaders(headers.ToString());
-
- fetcher->SetUploadData(kProtoBufMimeType, report->data());
- fetcher->SetRequestContext(
- content::BrowserContext::GetDefaultStoragePartition(context_)->
- GetURLRequestContext());
- fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES);
- fetcher->Start();
-}
-
-} // namespace feedback
diff --git a/chromium/components/feedback/feedback_uploader_chrome.h b/chromium/components/feedback/feedback_uploader_chrome.h
deleted file mode 100644
index 21cf13835fb..00000000000
--- a/chromium/components/feedback/feedback_uploader_chrome.h
+++ /dev/null
@@ -1,37 +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.
-
-#ifndef COMPONENTS_FEEDBACK_FEEDBACK_UPLOADER_CHROME_H_
-#define COMPONENTS_FEEDBACK_FEEDBACK_UPLOADER_CHROME_H_
-
-#include "base/macros.h"
-#include "components/feedback/feedback_uploader.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace feedback {
-
-class FeedbackUploaderChrome : public FeedbackUploader,
- public KeyedService {
- public:
- FeedbackUploaderChrome(
- content::BrowserContext* context,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- private:
- // feedback::FeedbackUploader:
- void DispatchReport(scoped_refptr<FeedbackReport> report) override;
-
- // Browser context this uploader was created for.
- content::BrowserContext* context_;
-
- DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderChrome);
-};
-
-} // namespace feedback
-
-#endif // COMPONENTS_FEEDBACK_FEEDBACK_UPLOADER_CHROME_H_
diff --git a/chromium/components/feedback/feedback_uploader_delegate.cc b/chromium/components/feedback/feedback_uploader_delegate.cc
index 3f0c3533652..fd7e475aa00 100644
--- a/chromium/components/feedback/feedback_uploader_delegate.cc
+++ b/chromium/components/feedback/feedback_uploader_delegate.cc
@@ -23,12 +23,9 @@ constexpr int kHttpPostFailServerError = 500;
} // namespace
FeedbackUploaderDelegate::FeedbackUploaderDelegate(
- scoped_refptr<FeedbackReport> pending_report,
const base::Closure& success_callback,
const ReportFailureCallback& error_callback)
- : pending_report_(pending_report),
- success_callback_(success_callback),
- error_callback_(error_callback) {}
+ : success_callback_(success_callback), error_callback_(error_callback) {}
FeedbackUploaderDelegate::~FeedbackUploaderDelegate() {}
@@ -61,8 +58,7 @@ void FeedbackUploaderDelegate::OnURLFetchComplete(
error_stream << "Unknown error: HTTP response code " << response_code;
}
- if (should_retry)
- error_callback_.Run(pending_report_);
+ error_callback_.Run(should_retry);
}
LOG(WARNING) << "FEEDBACK: Submission to feedback server ("
diff --git a/chromium/components/feedback/feedback_uploader_delegate.h b/chromium/components/feedback/feedback_uploader_delegate.h
index ca858ebb164..817b53fc2f6 100644
--- a/chromium/components/feedback/feedback_uploader_delegate.h
+++ b/chromium/components/feedback/feedback_uploader_delegate.h
@@ -13,16 +13,18 @@
namespace feedback {
-using ReportFailureCallback =
- base::Callback<void(scoped_refptr<FeedbackReport>)>;
+// Type of the callback that gets invoked when uploading a feedback report
+// fails. |should_retry| is set to true when it's OK to retry sending the
+// report; e.g. when the failure is not a client error and retries is likely to
+// fail again.
+using ReportFailureCallback = base::Callback<void(bool should_retry)>;
// FeedbackUploaderDelegate is a simple HTTP uploader for a feedback report.
// When finished, it runs the appropriate callback passed in via the
// constructor, and then deletes itself.
class FeedbackUploaderDelegate : public net::URLFetcherDelegate {
public:
- FeedbackUploaderDelegate(scoped_refptr<FeedbackReport> pending_report,
- const base::Closure& success_callback,
+ FeedbackUploaderDelegate(const base::Closure& success_callback,
const ReportFailureCallback& error_callback);
~FeedbackUploaderDelegate() override;
@@ -30,7 +32,6 @@ class FeedbackUploaderDelegate : public net::URLFetcherDelegate {
// Overridden from net::URLFetcherDelegate.
void OnURLFetchComplete(const net::URLFetcher* source) override;
- scoped_refptr<FeedbackReport> pending_report_;
base::Closure success_callback_;
ReportFailureCallback error_callback_;
diff --git a/chromium/components/feedback/feedback_uploader_chrome_unittest.cc b/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc
index 0f631b17ee2..7883d68f4f3 100644
--- a/chromium/components/feedback/feedback_uploader_chrome_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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/feedback/feedback_uploader_chrome.h"
+#include "components/feedback/feedback_uploader.h"
#include <string>
@@ -33,12 +33,12 @@ constexpr int kHttpPostFailServerError = 500;
} // namespace
-class FeedbackUploaderChromeTest : public ::testing::Test {
+class FeedbackUploaderDispatchTest : public ::testing::Test {
protected:
- FeedbackUploaderChromeTest()
+ FeedbackUploaderDispatchTest()
: browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
- ~FeedbackUploaderChromeTest() override {
+ ~FeedbackUploaderDispatchTest() override {
// Clean up registered ids.
variations::testing::ClearAllVariationIDs();
}
@@ -54,13 +54,16 @@ class FeedbackUploaderChromeTest : public ::testing::Test {
base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
}
+ content::BrowserContext* context() { return &context_; }
+
private:
content::TestBrowserThreadBundle browser_thread_bundle_;
+ content::TestBrowserContext context_;
- DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderChromeTest);
+ DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderDispatchTest);
};
-TEST_F(FeedbackUploaderChromeTest, VariationHeaders) {
+TEST_F(FeedbackUploaderDispatchTest, VariationHeaders) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
@@ -68,9 +71,8 @@ TEST_F(FeedbackUploaderChromeTest, VariationHeaders) {
base::FieldTrialList field_trial_list_(NULL);
CreateFieldTrialWithId("Test", "Group1", 123);
- content::TestBrowserContext context;
- FeedbackUploaderChrome uploader(
- &context, FeedbackUploaderFactory::CreateUploaderTaskRunner());
+ FeedbackUploader uploader(
+ context(), FeedbackUploaderFactory::CreateUploaderTaskRunner());
net::TestURLFetcherFactory factory;
uploader.QueueReport("test");
@@ -87,11 +89,10 @@ TEST_F(FeedbackUploaderChromeTest, VariationHeaders) {
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
-TEST_F(FeedbackUploaderChromeTest, TestVariousServerResponses) {
- content::TestBrowserContext context;
+TEST_F(FeedbackUploaderDispatchTest, TestVariousServerResponses) {
FeedbackUploader::SetMinimumRetryDelayForTesting(kTestRetryDelay);
- FeedbackUploaderChrome uploader(
- &context, FeedbackUploaderFactory::CreateUploaderTaskRunner());
+ FeedbackUploader uploader(
+ context(), FeedbackUploaderFactory::CreateUploaderTaskRunner());
EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
// Successful reports should not introduce any retries, and should not
diff --git a/chromium/components/feedback/feedback_uploader_factory.cc b/chromium/components/feedback/feedback_uploader_factory.cc
index 59023cc3576..5445e1dd4e0 100644
--- a/chromium/components/feedback/feedback_uploader_factory.cc
+++ b/chromium/components/feedback/feedback_uploader_factory.cc
@@ -9,7 +9,6 @@
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "components/feedback/feedback_uploader.h"
-#include "components/feedback/feedback_uploader_chrome.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace feedback {
@@ -22,7 +21,7 @@ FeedbackUploaderFactory* FeedbackUploaderFactory::GetInstance() {
// static
FeedbackUploader* FeedbackUploaderFactory::GetForBrowserContext(
content::BrowserContext* context) {
- return static_cast<FeedbackUploaderChrome*>(
+ return static_cast<FeedbackUploader*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
@@ -36,6 +35,12 @@ FeedbackUploaderFactory::CreateUploaderTaskRunner() {
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
}
+FeedbackUploaderFactory::FeedbackUploaderFactory(const char* service_name)
+ : BrowserContextKeyedServiceFactory(
+ service_name,
+ BrowserContextDependencyManager::GetInstance()),
+ task_runner_(CreateUploaderTaskRunner()) {}
+
FeedbackUploaderFactory::FeedbackUploaderFactory()
: BrowserContextKeyedServiceFactory(
"feedback::FeedbackUploader",
@@ -46,7 +51,7 @@ FeedbackUploaderFactory::~FeedbackUploaderFactory() {}
KeyedService* FeedbackUploaderFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
- return new FeedbackUploaderChrome(context, task_runner_);
+ return new FeedbackUploader(context, task_runner_);
}
content::BrowserContext* FeedbackUploaderFactory::GetBrowserContextToUse(
diff --git a/chromium/components/feedback/feedback_uploader_factory.h b/chromium/components/feedback/feedback_uploader_factory.h
index b04df4acbbf..2a9bd64351e 100644
--- a/chromium/components/feedback/feedback_uploader_factory.h
+++ b/chromium/components/feedback/feedback_uploader_factory.h
@@ -10,9 +10,10 @@
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
namespace base {
-template<typename T> struct DefaultSingletonTraits;
+template <typename T>
+struct DefaultSingletonTraits;
class SingleThreadTaskRunner;
-}
+} // namespace base
namespace content {
class BrowserContext;
@@ -37,11 +38,19 @@ class FeedbackUploaderFactory : public BrowserContextKeyedServiceFactory {
// that's actually used in production code to simulate the same behavior.
static scoped_refptr<base::SingleThreadTaskRunner> CreateUploaderTaskRunner();
+ protected:
+ FeedbackUploaderFactory(const char* service_name);
+ ~FeedbackUploaderFactory() override;
+
+ // The task runner used to handle all blocking background feedback-reports
+ // work. It involves reading / writing reports from / to disk. Those
+ // operations must not interleave and thread affinity is required.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
private:
friend struct base::DefaultSingletonTraits<FeedbackUploaderFactory>;
FeedbackUploaderFactory();
- ~FeedbackUploaderFactory() override;
// BrowserContextKeyedServiceFactory overrides:
KeyedService* BuildServiceInstanceFor(
@@ -49,11 +58,6 @@ class FeedbackUploaderFactory : public BrowserContextKeyedServiceFactory {
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
- // The task runner used to handle all blocking background feedback-reports
- // work. It involves reading / writing reports from / to disk. Those
- // operations must not interleave and thread affinity is required.
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderFactory);
};
diff --git a/chromium/components/feedback/feedback_uploader_unittest.cc b/chromium/components/feedback/feedback_uploader_unittest.cc
index 515847847f7..90c6a0a5b02 100644
--- a/chromium/components/feedback/feedback_uploader_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_unittest.cc
@@ -4,21 +4,18 @@
#include "components/feedback/feedback_uploader.h"
-#include <stddef.h>
-
#include <memory>
#include <set>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
-#include "build/build_config.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
#include "components/feedback/feedback_report.h"
-#include "components/feedback/feedback_uploader_chrome.h"
#include "components/feedback/feedback_uploader_factory.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "components/user_prefs/user_prefs.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,11 +33,11 @@ constexpr char kReportFive[] = "five";
constexpr base::TimeDelta kRetryDelayForTest =
base::TimeDelta::FromMilliseconds(100);
-class MockFeedbackUploader : public FeedbackUploaderChrome {
+class MockFeedbackUploader : public FeedbackUploader {
public:
- MockFeedbackUploader(content::BrowserContext* context,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : FeedbackUploaderChrome(context, task_runner) {}
+ MockFeedbackUploader(content::BrowserContext* context)
+ : FeedbackUploader(context,
+ FeedbackUploaderFactory::CreateUploaderTaskRunner()) {}
~MockFeedbackUploader() override {}
void RunMessageLoop() {
@@ -58,16 +55,17 @@ class MockFeedbackUploader : public FeedbackUploaderChrome {
private:
// FeedbackUploaderChrome:
- void DispatchReport(scoped_refptr<FeedbackReport> report) override {
- if (base::ContainsKey(dispatched_reports_, report->data()))
- dispatched_reports_[report->data()]++;
+ void StartDispatchingReport() override {
+ if (base::ContainsKey(dispatched_reports_,
+ report_being_dispatched()->data()))
+ dispatched_reports_[report_being_dispatched()->data()]++;
else
- dispatched_reports_[report->data()] = 1;
+ dispatched_reports_[report_being_dispatched()->data()] = 1;
dispatched_reports_count_++;
if (simulate_failure_)
- OnReportUploadFailure(report);
+ OnReportUploadFailure(true /* should_retry */);
else
OnReportUploadSuccess();
@@ -90,46 +88,27 @@ class MockFeedbackUploader : public FeedbackUploaderChrome {
DISALLOW_COPY_AND_ASSIGN(MockFeedbackUploader);
};
-std::unique_ptr<KeyedService> CreateFeedbackUploaderService(
- content::BrowserContext* context) {
- return base::MakeUnique<MockFeedbackUploader>(
- context, FeedbackUploaderFactory::CreateUploaderTaskRunner());
-}
-
} // namespace
class FeedbackUploaderTest : public testing::Test {
public:
- FeedbackUploaderTest()
- : context_(base::MakeUnique<content::TestBrowserContext>()),
- prefs_(
- base::MakeUnique<sync_preferences::TestingPrefServiceSyncable>()) {
- user_prefs::UserPrefs::Set(context_.get(), prefs_.get());
- FeedbackUploaderFactory::GetInstance()->SetTestingFactory(
- context_.get(), &CreateFeedbackUploaderService);
-
+ FeedbackUploaderTest() {
FeedbackUploader::SetMinimumRetryDelayForTesting(kRetryDelayForTest);
- uploader_ = static_cast<MockFeedbackUploader*>(
- FeedbackUploaderFactory::GetForBrowserContext(context_.get()));
+ uploader_ = base::MakeUnique<MockFeedbackUploader>(&context_);
}
- ~FeedbackUploaderTest() override {
- FeedbackUploaderFactory::GetInstance()->SetTestingFactory(
- context_.get(), NULL);
- }
+ ~FeedbackUploaderTest() override = default;
void QueueReport(const std::string& data) {
uploader_->QueueReport(data);
}
- MockFeedbackUploader* uploader() const { return uploader_; }
+ MockFeedbackUploader* uploader() const { return uploader_.get(); }
private:
content::TestBrowserThreadBundle test_browser_thread_bundle_;
- std::unique_ptr<content::TestBrowserContext> context_;
- std::unique_ptr<PrefService> prefs_;
-
- MockFeedbackUploader* uploader_;
+ content::TestBrowserContext context_;
+ std::unique_ptr<MockFeedbackUploader> uploader_;
DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderTest);
};
diff --git a/chromium/components/feedback/feedback_util.cc b/chromium/components/feedback/feedback_util.cc
index aa2615c3bd8..1bc7bd83013 100644
--- a/chromium/components/feedback/feedback_util.cc
+++ b/chromium/components/feedback/feedback_util.cc
@@ -8,37 +8,10 @@
#include "base/bind.h"
#include "base/files/file_util.h"
-#include "build/build_config.h"
-#include "components/feedback/feedback_data.h"
-#include "components/feedback/feedback_uploader.h"
-#include "components/feedback/feedback_uploader_factory.h"
-#include "components/feedback/proto/extension.pb.h"
#include "third_party/zlib/google/zip.h"
-using feedback::FeedbackData;
-
namespace feedback_util {
-void SendReport(scoped_refptr<FeedbackData> data) {
- if (!data.get()) {
- LOG(ERROR) << "SendReport called with NULL data!";
- NOTREACHED();
- return;
- }
-
- userfeedback::ExtensionSubmit feedback_data;
- data->PrepareReport(&feedback_data);
-
- // This pointer will eventually get deleted by the PostCleanup class, after
- // we've either managed to successfully upload the report or died trying.
- std::string post_body;
- feedback_data.SerializeToString(&post_body);
-
- feedback::FeedbackUploader *uploader =
- feedback::FeedbackUploaderFactory::GetForBrowserContext(data->context());
- uploader->QueueReport(post_body);
-}
-
bool ZipString(const base::FilePath& filename,
const std::string& data, std::string* compressed_logs) {
base::FilePath temp_path;
diff --git a/chromium/components/feedback/feedback_util.h b/chromium/components/feedback/feedback_util.h
index 7d50ee57ad7..8cb4012d6a9 100644
--- a/chromium/components/feedback/feedback_util.h
+++ b/chromium/components/feedback/feedback_util.h
@@ -8,28 +8,12 @@
#include <string>
#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-
-#if defined(OS_MACOSX)
-#include "base/sys_info.h"
-#elif defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-namespace chrome {
-extern const char kAppLauncherCategoryTag[];
-} // namespace chrome
-
-namespace feedback {
-class FeedbackData;
-}
namespace feedback_util {
- void SendReport(scoped_refptr<feedback::FeedbackData> data);
- bool ZipString(const base::FilePath& filename,
- const std::string& data, std::string* compressed_data);
+bool ZipString(const base::FilePath& filename,
+ const std::string& data,
+ std::string* compressed_data);
} // namespace feedback_util
diff --git a/chromium/components/feedback/system_logs/system_logs_fetcher.h b/chromium/components/feedback/system_logs/system_logs_fetcher.h
index 1799d4f4304..8211668b36e 100644
--- a/chromium/components/feedback/system_logs/system_logs_fetcher.h
+++ b/chromium/components/feedback/system_logs/system_logs_fetcher.h
@@ -30,7 +30,7 @@ using SysLogsFetcherCallback =
// EXAMPLE:
// class Example {
// public:
-// void ProcessLogs(SystemLogsResponse* response) {
+// void ProcessLogs(std::unique_ptr<SystemLogsResponse> response) {
// // do something with the logs
// }
// void GetLogs() {
@@ -51,7 +51,8 @@ class SystemLogsFetcher {
// Adds a source to use when fetching.
void AddSource(std::unique_ptr<SystemLogsSource> source);
- // Starts the fetch process.
+ // Starts the fetch process. After the fetch completes, this instance calls
+ // |callback|, then schedules itself to be deleted.
void Fetch(const SysLogsFetcherCallback& callback);
private:
diff --git a/chromium/components/filesystem/OWNERS b/chromium/components/filesystem/OWNERS
index 4733a4f06bf..771a70f0147 100644
--- a/chromium/components/filesystem/OWNERS
+++ b/chromium/components/filesystem/OWNERS
@@ -1 +1,7 @@
erg@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file test_manifest.json=set noparent
+per-file test_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/flags_ui/flags_storage.h b/chromium/components/flags_ui/flags_storage.h
index 67d3dfe11f7..67cb8338455 100644
--- a/chromium/components/flags_ui/flags_storage.h
+++ b/chromium/components/flags_ui/flags_storage.h
@@ -21,6 +21,8 @@ class FlagsStorage {
virtual std::set<std::string> GetFlags() = 0;
// Stores the |flags| and returns true on success.
virtual bool SetFlags(const std::set<std::string>& flags) = 0;
+ // Lands pending changes to disk immediately.
+ virtual void CommitPendingWrites() = 0;
};
} // namespace flags_ui
diff --git a/chromium/components/flags_ui/pref_service_flags_storage.cc b/chromium/components/flags_ui/pref_service_flags_storage.cc
index 2153c1bf6be..a8b1d8ccc68 100644
--- a/chromium/components/flags_ui/pref_service_flags_storage.cc
+++ b/chromium/components/flags_ui/pref_service_flags_storage.cc
@@ -48,6 +48,10 @@ bool PrefServiceFlagsStorage::SetFlags(const std::set<std::string>& flags) {
return true;
}
+void PrefServiceFlagsStorage::CommitPendingWrites() {
+ prefs_->CommitPendingWrite();
+}
+
// static
void PrefServiceFlagsStorage::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(prefs::kEnabledLabsExperiments);
diff --git a/chromium/components/flags_ui/pref_service_flags_storage.h b/chromium/components/flags_ui/pref_service_flags_storage.h
index b230ac11eed..3a98c8b5861 100644
--- a/chromium/components/flags_ui/pref_service_flags_storage.h
+++ b/chromium/components/flags_ui/pref_service_flags_storage.h
@@ -27,6 +27,7 @@ class PrefServiceFlagsStorage : public FlagsStorage {
std::set<std::string> GetFlags() override;
bool SetFlags(const std::set<std::string>& flags) override;
+ void CommitPendingWrites() override;
static void RegisterPrefs(PrefRegistrySimple* registry);
diff --git a/chromium/components/font_service/OWNERS b/chromium/components/font_service/OWNERS
index 4733a4f06bf..0447911a6c3 100644
--- a/chromium/components/font_service/OWNERS
+++ b/chromium/components/font_service/OWNERS
@@ -1 +1,4 @@
erg@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/gcm_driver/instance_id/android/BUILD.gn b/chromium/components/gcm_driver/instance_id/android/BUILD.gn
index 54e49e44ac0..2fdc248b317 100644
--- a/chromium/components/gcm_driver/instance_id/android/BUILD.gn
+++ b/chromium/components/gcm_driver/instance_id/android/BUILD.gn
@@ -20,8 +20,8 @@ generate_jni("test_support_jni_headers") {
android_library("instance_id_driver_java") {
deps = [
+ "$google_play_services_package:google_play_services_iid_java",
"//base:base_java",
- google_play_services_library,
]
java_files = [
@@ -33,8 +33,8 @@ android_library("instance_id_driver_java") {
android_library("instance_id_driver_test_support_java") {
deps = [
":instance_id_driver_java",
+ "$google_play_services_package:google_play_services_iid_java",
"//base:base_java",
- google_play_services_library,
]
java_files = [ "javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java" ]
diff --git a/chromium/components/google/core/browser/google_url_tracker.cc b/chromium/components/google/core/browser/google_url_tracker.cc
index e16f3277604..94edfa1d623 100644
--- a/chromium/components/google/core/browser/google_url_tracker.cc
+++ b/chromium/components/google/core/browser/google_url_tracker.cc
@@ -178,7 +178,7 @@ void GoogleURLTracker::StartFetchIfDesirable() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "user"
setting:
"To disable this check, users can change the default search engine "
@@ -190,8 +190,11 @@ void GoogleURLTracker::StartFetchIfDesirable() {
"requests.\nFinally, running Chromium with "
"--disable-background-networking will disable this, as well as "
"various other features that make network requests automatically."
- policy_exception_justification:
- "Not implemented."
+ policy_exception_justification:
+ "Setting DefaultSearchProviderEnabled Chrome settings policy to "
+ "false suffices as a way of setting the default search engine to "
+ "not be Google. But there is no policy that controls navigation "
+ "error resolution."
})");
fetcher_ =
net::URLFetcher::Create(fetcher_id_, GURL(kSearchDomainCheckURL),
diff --git a/chromium/components/guest_view/browser/BUILD.gn b/chromium/components/guest_view/browser/BUILD.gn
index 96b43908d41..00bd7eb473b 100644
--- a/chromium/components/guest_view/browser/BUILD.gn
+++ b/chromium/components/guest_view/browser/BUILD.gn
@@ -11,6 +11,8 @@ assert(!is_android && !is_ios)
static_library("browser") {
output_name = "guest_view_browser"
sources = [
+ "//components/guest_view/browser/bad_message.cc",
+ "//components/guest_view/browser/bad_message.h",
"//components/guest_view/browser/guest_view.h",
"//components/guest_view/browser/guest_view_base.cc",
"//components/guest_view/browser/guest_view_base.h",
diff --git a/chromium/components/guest_view/browser/PRESUBMIT.py b/chromium/components/guest_view/browser/PRESUBMIT.py
new file mode 100644
index 00000000000..57effd158bd
--- /dev/null
+++ b/chromium/components/guest_view/browser/PRESUBMIT.py
@@ -0,0 +1,27 @@
+# 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.
+
+"""Chromium presubmit script to check that BadMessage enums in histograms.xml
+match the corresponding bad_message.h file.
+"""
+
+def _RunHistogramChecks(input_api, output_api, histogram_name):
+ try:
+ # Setup sys.path so that we can call histograms code.
+ import sys
+ original_sys_path = sys.path
+ sys.path = sys.path + [input_api.os_path.join(
+ input_api.change.RepositoryRoot(),
+ 'tools', 'metrics', 'histograms')]
+
+ import presubmit_bad_message_reasons
+ return presubmit_bad_message_reasons.PrecheckBadMessage(input_api,
+ output_api, histogram_name)
+ except:
+ return [output_api.PresubmitError('Could not verify histogram!')]
+ finally:
+ sys.path = original_sys_path
+
+def CheckChangeOnUpload(input_api, output_api):
+ return _RunHistogramChecks(input_api, output_api, "BadMessageReasonGuestView")
diff --git a/chromium/components/guest_view/browser/bad_message.cc b/chromium/components/guest_view/browser/bad_message.cc
new file mode 100644
index 00000000000..f16f0862bc9
--- /dev/null
+++ b/chromium/components/guest_view/browser/bad_message.cc
@@ -0,0 +1,48 @@
+// 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/guest_view/browser/bad_message.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace guest_view {
+namespace bad_message {
+
+namespace {
+
+void LogBadMessage(BadMessageReason reason) {
+ LOG(ERROR) << "Terminating renderer for bad IPC message, reason " << reason;
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.GuestView",
+ reason);
+}
+
+} // namespace
+
+void ReceivedBadMessage(content::RenderProcessHost* host,
+ BadMessageReason reason) {
+ LogBadMessage(reason);
+ host->ShutdownForBadMessage(
+ content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
+}
+
+void ReceivedBadMessage(int render_process_id, BadMessageReason reason) {
+ content::RenderProcessHost* rph =
+ content::RenderProcessHost::FromID(render_process_id);
+ if (!rph)
+ return;
+
+ ReceivedBadMessage(rph, reason);
+}
+
+void ReceivedBadMessage(content::BrowserMessageFilter* filter,
+ BadMessageReason reason) {
+ LogBadMessage(reason);
+ filter->ShutdownForBadMessage();
+}
+
+} // namespace bad_message
+} // namespace guest_view
diff --git a/chromium/components/guest_view/browser/bad_message.h b/chromium/components/guest_view/browser/bad_message.h
new file mode 100644
index 00000000000..1a38fa6daa9
--- /dev/null
+++ b/chromium/components/guest_view/browser/bad_message.h
@@ -0,0 +1,53 @@
+// 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_GUEST_VIEW_BROWSER_BAD_MESSAGE_H_
+#define COMPONENTS_GUEST_VIEW_BROWSER_BAD_MESSAGE_H_
+
+namespace content {
+class BrowserMessageFilter;
+class RenderProcessHost;
+} // namespace content
+
+namespace guest_view {
+namespace bad_message {
+
+// The browser process often chooses to terminate a renderer if it receives
+// a bad IPC message. The reasons are tracked for metrics.
+//
+// See also content/browser/bad_message.h.
+//
+// NOTE: Do not remove or reorder elements in this list. Add new entries at the
+// end. Items may be renamed but do not change the values. We rely on the enum
+// values in histograms.
+enum BadMessageReason {
+ GVM_EMBEDDER_FORBIDDEN_ACCESS_TO_GUEST = 0,
+ GVM_INVALID_GUESTVIEW_TYPE = 1,
+ GVMF_UNEXPECTED_MESSAGE_BEFORE_GVM_CREATION = 2,
+
+ // Please add new elements here. The naming convention is abbreviated class
+ // name (e.g. GuestViewManager becomes GVM) plus a unique description of
+ // the reason. After making changes, you MUST update histograms.xml by
+ // running:
+ // "python tools/metrics/histograms/update_bad_message_reasons.py"
+ BAD_MESSAGE_MAX
+};
+
+// Called when the browser receives a bad IPC message from a renderer.
+// Logs the event, records a histogram metric for the |reason|,
+// and terminates the process for |host| / |render_process_id|.
+void ReceivedBadMessage(content::RenderProcessHost* host,
+ BadMessageReason reason);
+void ReceivedBadMessage(int render_process_id, BadMessageReason reason);
+
+// Called when a browser message filter receives a bad IPC message from a
+// renderer process. Logs the event, records a histogram metric for the
+// |reason|, and terminates the process for |filter|.
+void ReceivedBadMessage(content::BrowserMessageFilter* filter,
+ BadMessageReason reason);
+
+} // namespace bad_message
+} // namespace guest_view
+
+#endif // COMPONENTS_GUEST_VIEW_BROWSER_BAD_MESSAGE_H_
diff --git a/chromium/components/guest_view/browser/guest_view_base.h b/chromium/components/guest_view/browser/guest_view_base.h
index 8b7d21dfa7d..0fb03b86f0d 100644
--- a/chromium/components/guest_view/browser/guest_view_base.h
+++ b/chromium/components/guest_view/browser/guest_view_base.h
@@ -6,8 +6,8 @@
#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_BASE_H_
#include <memory>
-#include <queue>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/values.h"
@@ -439,7 +439,7 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
// This is a queue of Events that are destined to be sent to the embedder once
// the guest is attached to a particular embedder.
- std::deque<std::unique_ptr<GuestViewEvent>> pending_events_;
+ base::circular_deque<std::unique_ptr<GuestViewEvent>> pending_events_;
// The opener guest view.
base::WeakPtr<GuestViewBase> opener_;
diff --git a/chromium/components/guest_view/browser/guest_view_manager.cc b/chromium/components/guest_view/browser/guest_view_manager.cc
index bc36a92f4ad..12b34750d3b 100644
--- a/chromium/components/guest_view/browser/guest_view_manager.cc
+++ b/chromium/components/guest_view/browser/guest_view_manager.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/user_metrics.h"
+#include "components/guest_view/browser/bad_message.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
#include "components/guest_view/browser/guest_view_manager_factory.h"
@@ -20,7 +20,6 @@
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/child_process_host.h"
-#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "url/gurl.h"
@@ -305,8 +304,11 @@ void GuestViewManager::ViewCreated(int embedder_process_id,
if (guest_view_registry_.empty())
RegisterGuestViewTypes();
auto view_it = guest_view_registry_.find(view_type);
- CHECK(view_it != guest_view_registry_.end())
- << "Invalid GuestView created of type \"" << view_type << "\"";
+ if (view_it == guest_view_registry_.end()) {
+ bad_message::ReceivedBadMessage(embedder_process_id,
+ bad_message::GVM_INVALID_GUESTVIEW_TYPE);
+ return;
+ }
// Register the cleanup callback for when this view is destroyed.
RegisterViewDestructionCallback(embedder_process_id,
@@ -421,9 +423,9 @@ bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
guest_instance_id)) {
// The embedder process is trying to access a guest it does not own.
- base::RecordAction(base::UserMetricsAction("BadMessageTerminate_BPGM"));
- content::RenderProcessHost::FromID(embedder_render_process_id)
- ->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
+ bad_message::ReceivedBadMessage(
+ embedder_render_process_id,
+ bad_message::GVM_EMBEDDER_FORBIDDEN_ACCESS_TO_GUEST);
return false;
}
return true;
diff --git a/chromium/components/guest_view/browser/guest_view_message_filter.cc b/chromium/components/guest_view/browser/guest_view_message_filter.cc
index c2124ed258f..e830b1ec1d3 100644
--- a/chromium/components/guest_view/browser/guest_view_message_filter.cc
+++ b/chromium/components/guest_view/browser/guest_view_message_filter.cc
@@ -5,6 +5,7 @@
#include "components/guest_view/browser/guest_view_message_filter.h"
#include "base/memory/ptr_util.h"
+#include "components/guest_view/browser/bad_message.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
@@ -57,6 +58,15 @@ GuestViewManager* GuestViewMessageFilter::GetOrCreateGuestViewManager() {
return manager;
}
+GuestViewManager* GuestViewMessageFilter::GetGuestViewManagerOrKill() {
+ auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
+ if (!manager) {
+ bad_message::ReceivedBadMessage(
+ this, bad_message::GVMF_UNEXPECTED_MESSAGE_BEFORE_GVM_CREATION);
+ }
+ return manager;
+}
+
void GuestViewMessageFilter::OverrideThreadForMessage(
const IPC::Message& message,
BrowserThread::ID* thread) {
@@ -102,9 +112,9 @@ void GuestViewMessageFilter::OnAttachGuest(
int guest_instance_id,
const base::DictionaryValue& params) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
// We should have a GuestViewManager at this point. If we don't then the
// embedder is misbehaving.
+ auto* manager = GetGuestViewManagerOrKill();
if (!manager)
return;
@@ -119,8 +129,12 @@ void GuestViewMessageFilter::OnAttachToEmbedderFrame(
int element_instance_id,
int guest_instance_id,
const base::DictionaryValue& params) {
- auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
- DCHECK(manager);
+ // We should have a GuestViewManager at this point. If we don't then the
+ // embedder is misbehaving.
+ auto* manager = GetGuestViewManagerOrKill();
+ if (!manager)
+ return;
+
content::WebContents* guest_web_contents =
manager->GetGuestByInstanceIDSafely(guest_instance_id,
render_process_id_);
diff --git a/chromium/components/guest_view/browser/guest_view_message_filter.h b/chromium/components/guest_view/browser/guest_view_message_filter.h
index 1a24bf2cacd..a6587f90bee 100644
--- a/chromium/components/guest_view/browser/guest_view_message_filter.h
+++ b/chromium/components/guest_view/browser/guest_view_message_filter.h
@@ -45,6 +45,12 @@ class GuestViewMessageFilter : public content::BrowserMessageFilter {
// or creates and returns one for |browser_context_| otherwise.
virtual GuestViewManager* GetOrCreateGuestViewManager();
+ // Returns the GuestViewManager for |browser_context_| if it exists.
+ // Callers consider the renderer to be misbehaving if we don't have a
+ // GuestViewManager at this point, in which case we kill the renderer and
+ // return nullptr.
+ GuestViewManager* GetGuestViewManagerOrKill();
+
// content::BrowserMessageFilter implementation.
void OverrideThreadForMessage(const IPC::Message& message,
content::BrowserThread::ID* thread) override;
diff --git a/chromium/components/guest_view/renderer/guest_view_container.h b/chromium/components/guest_view/renderer/guest_view_container.h
index 7025d95908f..7ecaf115e18 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.h
+++ b/chromium/components/guest_view/renderer/guest_view_container.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "content/public/renderer/browser_plugin_delegate.h"
#include "ipc/ipc_message.h"
@@ -97,7 +98,7 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
bool in_destruction_;
- std::deque<std::unique_ptr<GuestViewRequest>> pending_requests_;
+ base::circular_deque<std::unique_ptr<GuestViewRequest>> pending_requests_;
std::unique_ptr<GuestViewRequest> pending_response_;
v8::Global<v8::Function> destruction_callback_;
diff --git a/chromium/components/history/core/browser/BUILD.gn b/chromium/components/history/core/browser/BUILD.gn
index a8cd984f57e..f9c88c8c106 100644
--- a/chromium/components/history/core/browser/BUILD.gn
+++ b/chromium/components/history/core/browser/BUILD.gn
@@ -4,6 +4,9 @@
static_library("browser") {
sources = [
+ "browsing_history_driver.h",
+ "browsing_history_service.cc",
+ "browsing_history_service.h",
"delete_directive_handler.cc",
"delete_directive_handler.h",
"download_constants.h",
@@ -185,6 +188,7 @@ bundle_data("unit_tests_bundle_data") {
source_set("unit_tests") {
testonly = true
sources = [
+ "browsing_history_service_unittest.cc",
"download_slice_info_unittest.cc",
"expire_history_backend_unittest.cc",
"history_backend_db_unittest.cc",
@@ -219,6 +223,7 @@ source_set("unit_tests") {
"//components/signin/core/browser",
"//components/signin/core/browser:test_support",
"//components/sync",
+ "//components/sync:test_support_driver",
"//components/sync:test_support_model",
"//sql",
"//sql:test_support",
diff --git a/chromium/components/history/core/browser/OWNERS b/chromium/components/history/core/browser/OWNERS
index e1bfe9b18f3..a09694a874b 100644
--- a/chromium/components/history/core/browser/OWNERS
+++ b/chromium/components/history/core/browser/OWNERS
@@ -1 +1,3 @@
+per-file typed_url_sync_bridge*=gangwu@chromium.org
+per-file typed_url_syncable_service*=gangwu@chromium.org
per-file typed_url_syncable_service*=zea@chromium.org
diff --git a/chromium/components/history/core/browser/browsing_history_driver.h b/chromium/components/history/core/browser/browsing_history_driver.h
new file mode 100644
index 00000000000..ea5db19d8c5
--- /dev/null
+++ b/chromium/components/history/core/browser/browsing_history_driver.h
@@ -0,0 +1,83 @@
+// 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_HISTORY_CORE_BROWSER_BROWSING_HISTORY_DRIVER_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_BROWSING_HISTORY_DRIVER_H_
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "components/history/core/browser/browsing_history_service.h"
+#include "components/history/core/browser/history_types.h"
+
+class GURL;
+
+namespace syncer {
+class SyncService;
+} // namespace syncer
+
+namespace history {
+
+class WebHistoryService;
+
+// Interface serves as an abstraction layer BrowsingHistoryService and more
+// platform logic and classes, facilitating both sending an receiving data.
+class BrowsingHistoryDriver {
+ public:
+ // Callback for QueryHistory().
+ virtual void OnQueryComplete(
+ const std::vector<BrowsingHistoryService::HistoryEntry>& results,
+ const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+ base::OnceClosure continuation_closure) = 0;
+
+ // Callback for RemoveVisits().
+ virtual void OnRemoveVisitsComplete() = 0;
+
+ // Callback for RemoveVisits() that fails.
+ virtual void OnRemoveVisitsFailed() = 0;
+
+ // Callback for RemoveVisits() with the list of expire arguments. This gives
+ // the driver a chance to perform embedder specific removal logic.
+ virtual void OnRemoveVisits(
+ const std::vector<ExpireHistoryArgs>& expire_list) = 0;
+
+ // Called when HistoryService or WebHistoryService deletes one or more
+ // items.
+ virtual void HistoryDeleted() = 0;
+
+ // Whether other forms of browsing history were found on the history
+ // service.
+ virtual void HasOtherFormsOfBrowsingHistory(bool has_other_forms,
+ bool has_synced_results) = 0;
+
+ // If history deletions are currently allowed.
+ virtual bool AllowHistoryDeletions() = 0;
+
+ // If the given url from web history is allowed to be shown to the user.
+ virtual bool ShouldHideWebHistoryUrl(const GURL& url) = 0;
+
+ // Retrieve the WebHistory service, which may or may not currently exist or be
+ // accessible.
+ virtual WebHistoryService* GetWebHistoryService() = 0;
+
+ // Whether the Clear Browsing Data UI should show a notice about the existence
+ // of other forms of browsing history stored in user's account. The response
+ // is returned in a |callback|.
+ virtual void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ WebHistoryService* history_service,
+ base::Callback<void(bool)> callback) = 0;
+
+ protected:
+ BrowsingHistoryDriver() {}
+ virtual ~BrowsingHistoryDriver() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryDriver);
+};
+
+} // namespace history
+
+#endif // COMPONENTS_HISTORY_CORE_BROWSER_BROWSING_HISTORY_DRIVER_H_
diff --git a/chromium/components/history/core/browser/browsing_history_service.cc b/chromium/components/history/core/browser/browsing_history_service.cc
new file mode 100644
index 00000000000..8041ce6a165
--- /dev/null
+++ b/chromium/components/history/core/browser/browsing_history_service.cc
@@ -0,0 +1,749 @@
+// 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/history/core/browser/browsing_history_service.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <map>
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/history/core/browser/browsing_history_driver.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_service_observer.h"
+
+namespace history {
+
+namespace {
+
+// The amount of time to wait for a response from the WebHistoryService.
+static const int kWebHistoryTimeoutSeconds = 3;
+
+// Buckets for UMA histograms.
+enum WebHistoryQueryBuckets {
+ WEB_HISTORY_QUERY_FAILED = 0,
+ WEB_HISTORY_QUERY_SUCCEEDED,
+ WEB_HISTORY_QUERY_TIMED_OUT,
+ NUM_WEB_HISTORY_QUERY_BUCKETS
+};
+
+void RecordMetricsForNoticeAboutOtherFormsOfBrowsingHistory(bool shown) {
+ UMA_HISTOGRAM_BOOLEAN("History.ShownHeaderAboutOtherFormsOfBrowsingHistory",
+ shown);
+}
+
+QueryOptions OptionsWithEndTime(QueryOptions original_options,
+ base::Time end_time) {
+ QueryOptions options(original_options);
+ options.end_time = end_time;
+ return options;
+}
+
+// The status of the result from a particular history source.
+enum QuerySourceStatus {
+ // Not a continuation and no response yet.
+ UNINITIALIZED,
+ // Could not query the particular source.
+ NO_DEPENDENCY,
+ // Only used for web, when we stop waiting for a response due to timeout.
+ TIMED_OUT,
+ // Only used for remote, response was error or empty.
+ FAILURE,
+ // Successfully retrieved results, but there are more left.
+ MORE_RESULTS,
+ // Successfully retrieved results and we reached the end of results.
+ REACHED_BEGINNING,
+};
+
+bool CanRetry(QuerySourceStatus status) {
+ // TODO(skym): Should we be retrying on FAILURE?
+ return status == MORE_RESULTS || status == FAILURE || status == TIMED_OUT;
+}
+
+} // namespace
+
+struct BrowsingHistoryService::QueryHistoryState
+ : public base::RefCounted<BrowsingHistoryService::QueryHistoryState> {
+ QueryHistoryState() = default;
+
+ base::string16 search_text;
+ QueryOptions original_options;
+
+ QuerySourceStatus local_status = UNINITIALIZED;
+ // Should always be sorted in reverse chronological order.
+ std::vector<HistoryEntry> local_results;
+ base::Time local_end_time_for_continuation;
+
+ QuerySourceStatus remote_status = UNINITIALIZED;
+ // Should always be sorted in reverse chronological order.
+ std::vector<HistoryEntry> remote_results;
+ base::Time remote_end_time_for_continuation;
+
+ private:
+ friend class base::RefCounted<BrowsingHistoryService::QueryHistoryState>;
+ ~QueryHistoryState() = default;
+};
+
+BrowsingHistoryService::HistoryEntry::HistoryEntry(
+ BrowsingHistoryService::HistoryEntry::EntryType entry_type,
+ const GURL& url,
+ const base::string16& title,
+ base::Time time,
+ const std::string& client_id,
+ bool is_search_result,
+ const base::string16& snippet,
+ bool blocked_visit) {
+ this->entry_type = entry_type;
+ this->url = url;
+ this->title = title;
+ this->time = time;
+ this->client_id = client_id;
+ all_timestamps.insert(time.ToInternalValue());
+ this->is_search_result = is_search_result;
+ this->snippet = snippet;
+ this->blocked_visit = blocked_visit;
+}
+
+BrowsingHistoryService::HistoryEntry::HistoryEntry()
+ : entry_type(EMPTY_ENTRY), is_search_result(false), blocked_visit(false) {}
+
+BrowsingHistoryService::HistoryEntry::HistoryEntry(const HistoryEntry& other) =
+ default;
+
+BrowsingHistoryService::HistoryEntry::~HistoryEntry() {}
+
+bool BrowsingHistoryService::HistoryEntry::SortByTimeDescending(
+ const BrowsingHistoryService::HistoryEntry& entry1,
+ const BrowsingHistoryService::HistoryEntry& entry2) {
+ return entry1.time > entry2.time;
+}
+
+BrowsingHistoryService::QueryResultsInfo::~QueryResultsInfo() {}
+
+BrowsingHistoryService::BrowsingHistoryService(
+ BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service)
+ : BrowsingHistoryService(driver,
+ local_history,
+ sync_service,
+ std::make_unique<base::OneShotTimer>()) {}
+
+BrowsingHistoryService::BrowsingHistoryService(
+ BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service,
+ std::unique_ptr<base::Timer> web_history_timer)
+ : web_history_timer_(std::move(web_history_timer)),
+ history_service_observer_(this),
+ web_history_service_observer_(this),
+ sync_service_observer_(this),
+ driver_(driver),
+ local_history_(local_history),
+ sync_service_(sync_service),
+ clock_(new base::DefaultClock()),
+ weak_factory_(this) {
+ DCHECK(driver_);
+
+ // Get notifications when history is cleared.
+ if (local_history_)
+ history_service_observer_.Add(local_history_);
+
+ // Get notifications when web history is deleted.
+ WebHistoryService* web_history = driver_->GetWebHistoryService();
+ if (web_history) {
+ web_history_service_observer_.Add(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
+ // possible, and that history sync/web history may become enabled later, so
+ // attach start observing. If |sync_service_| is null then we cannot start
+ // 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_);
+ }
+}
+
+BrowsingHistoryService::~BrowsingHistoryService() {
+ query_task_tracker_.TryCancelAll();
+ web_history_request_.reset();
+}
+
+void BrowsingHistoryService::OnStateChanged(syncer::SyncService* sync) {
+ // If the history sync was enabled, start observing WebHistoryService.
+ // 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();
+ }
+}
+
+void BrowsingHistoryService::WebHistoryTimeout(
+ scoped_refptr<QueryHistoryState> state) {
+ state->remote_status = TIMED_OUT;
+
+ // Don't reset |web_history_request_| so we can still record histogram.
+ // TODO(dubroy): Communicate the failure to the front end.
+ if (!query_task_tracker_.HasTrackedTasks())
+ ReturnResultsToDriver(std::move(state));
+
+ UMA_HISTOGRAM_ENUMERATION("WebHistory.QueryCompletion",
+ WEB_HISTORY_QUERY_TIMED_OUT,
+ NUM_WEB_HISTORY_QUERY_BUCKETS);
+}
+
+void BrowsingHistoryService::QueryHistory(const base::string16& search_text,
+ const QueryOptions& options) {
+ scoped_refptr<QueryHistoryState> state =
+ base::MakeRefCounted<QueryHistoryState>();
+ state->search_text = search_text;
+ state->original_options = options;
+ state->local_end_time_for_continuation = options.end_time;
+ state->remote_end_time_for_continuation = options.end_time;
+ QueryHistoryInternal(std::move(state));
+}
+
+void BrowsingHistoryService::QueryHistoryInternal(
+ scoped_refptr<QueryHistoryState> state) {
+ // Anything in-flight is invalid.
+ query_task_tracker_.TryCancelAll();
+ web_history_request_.reset();
+
+ bool should_return_results_immediately = true;
+ size_t desired_count =
+ static_cast<size_t>(state->original_options.EffectiveMaxCount());
+
+ if (local_history_) {
+ if (state->local_results.size() < desired_count &&
+ state->local_status != REACHED_BEGINNING) {
+ should_return_results_immediately = false;
+ local_history_->QueryHistory(
+ state->search_text,
+ OptionsWithEndTime(state->original_options,
+ state->local_end_time_for_continuation),
+ base::Bind(&BrowsingHistoryService::QueryComplete,
+ weak_factory_.GetWeakPtr(), state),
+ &query_task_tracker_);
+ }
+ } else {
+ state->local_status = NO_DEPENDENCY;
+ }
+
+ WebHistoryService* web_history = driver_->GetWebHistoryService();
+ if (web_history) {
+ if (state->remote_results.size() < desired_count &&
+ state->remote_status != REACHED_BEGINNING) {
+ // Start a timer with timeout before we make the actual query, otherwise
+ // tests get confused when completion callback is run synchronously.
+ web_history_timer_->Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kWebHistoryTimeoutSeconds),
+ base::Bind(&BrowsingHistoryService::WebHistoryTimeout,
+ weak_factory_.GetWeakPtr(), state));
+
+ net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
+ net::DefinePartialNetworkTrafficAnnotation("web_history_query",
+ "web_history_service",
+ R"(
+ semantics {
+ description:
+ "If history sync is enabled, this downloads the synced "
+ "history from history.google.com."
+ trigger:
+ "Synced history is downloaded when user opens the history "
+ "page, searches on the history page, or scrolls down the "
+ "history page to see more results. This is only the case if "
+ "the user is signed in and history sync is enabled."
+ data:
+ "The history query text (or empty strings if all results are "
+ "to be fetched), the begin and end timestamps, and the maximum "
+ "number of results to be fetched. The request also includes a "
+ "version info token to resolve transaction conflicts, and an "
+ "OAuth2 token authenticating the user."
+ }
+ policy {
+ chrome_policy {
+ SyncDisabled {
+ SyncDisabled: true
+ }
+ }
+ })");
+ should_return_results_immediately = false;
+ web_history_request_ = web_history->QueryHistory(
+ state->search_text,
+ OptionsWithEndTime(state->original_options,
+ state->remote_end_time_for_continuation),
+ base::Bind(&BrowsingHistoryService::WebHistoryQueryComplete,
+ weak_factory_.GetWeakPtr(), state, clock_->Now()),
+ partial_traffic_annotation);
+
+ // Test the existence of other forms of browsing history.
+ driver_->ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ sync_service_, web_history,
+ base::Bind(
+ &BrowsingHistoryService::OtherFormsOfBrowsingHistoryQueryComplete,
+ weak_factory_.GetWeakPtr()));
+ }
+ } else {
+ state->remote_status = NO_DEPENDENCY;
+ // The notice could not have been shown, because there is no web history.
+ RecordMetricsForNoticeAboutOtherFormsOfBrowsingHistory(false);
+ has_synced_results_ = false;
+ has_other_forms_of_browsing_history_ = false;
+ }
+
+ // If we avoid assuming delegated queries are returning asynchronous, then we
+ // cannot check tracker/timer, and instead have to rely on local logic for
+ // this choice. Note that in unit tests Web History returns synchronously.
+ if (should_return_results_immediately) {
+ ReturnResultsToDriver(std::move(state));
+ }
+}
+
+void BrowsingHistoryService::RemoveVisits(
+ const std::vector<BrowsingHistoryService::HistoryEntry>& items) {
+ if (delete_task_tracker_.HasTrackedTasks() || has_pending_delete_request_ ||
+ !driver_->AllowHistoryDeletions()) {
+ driver_->OnRemoveVisitsFailed();
+ return;
+ }
+
+ WebHistoryService* web_history = driver_->GetWebHistoryService();
+ base::Time now = clock_->Now();
+ std::vector<ExpireHistoryArgs> expire_list;
+ expire_list.reserve(items.size());
+
+ DCHECK(urls_to_be_deleted_.empty());
+ for (const BrowsingHistoryService::HistoryEntry& entry : items) {
+ // In order to ensure that visits will be deleted from the server and other
+ // clients (even if they are offline), create a sync delete directive for
+ // each visit to be deleted.
+ sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
+ sync_pb::GlobalIdDirective* global_id_directive =
+ delete_directive.mutable_global_id_directive();
+ ExpireHistoryArgs* expire_args = nullptr;
+
+ for (int64_t timestamp : entry.all_timestamps) {
+ if (!expire_args) {
+ GURL gurl(entry.url);
+ expire_list.resize(expire_list.size() + 1);
+ expire_args = &expire_list.back();
+ expire_args->SetTimeRangeForOneDay(
+ base::Time::FromInternalValue(timestamp));
+ expire_args->urls.insert(gurl);
+ urls_to_be_deleted_.insert(gurl);
+ }
+ // The local visit time is treated as a global ID for the visit.
+ global_id_directive->add_global_id(timestamp);
+ }
+
+ // Set the start and end time in microseconds since the Unix epoch.
+ global_id_directive->set_start_time_usec(
+ (expire_args->begin_time - base::Time::UnixEpoch()).InMicroseconds());
+
+ // Delete directives shouldn't have an end time in the future.
+ // TODO(dubroy): Use sane time (crbug.com/146090) here when it's ready.
+ base::Time end_time = std::min(expire_args->end_time, now);
+
+ // -1 because end time in delete directives is inclusive.
+ global_id_directive->set_end_time_usec(
+ (end_time - base::Time::UnixEpoch()).InMicroseconds() - 1);
+
+ // TODO(dubroy): Figure out the proper way to handle an error here.
+ if (web_history && local_history_)
+ local_history_->ProcessLocalDeleteDirective(delete_directive);
+ }
+
+ if (local_history_) {
+ local_history_->ExpireHistory(
+ expire_list,
+ base::Bind(&BrowsingHistoryService::RemoveComplete,
+ weak_factory_.GetWeakPtr()),
+ &delete_task_tracker_);
+ }
+
+ if (web_history) {
+ has_pending_delete_request_ = true;
+ net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
+ net::DefinePartialNetworkTrafficAnnotation("web_history_expire",
+ "web_history_service",
+ R"(
+ semantics {
+ description:
+ "If a user who syncs their browsing history deletes one or more "
+ "history item(s), Chrome sends a request to history.google.com "
+ "to execute the corresponding deletion serverside."
+ trigger:
+ "Deleting one or more history items form the history page."
+ data:
+ "The selected items represented by a URL and timestamp. The "
+ "request also includes a version info token to resolve "
+ "transaction conflicts, and an OAuth2 token authenticating the "
+ "user."
+ }
+ policy {
+ chrome_policy {
+ AllowDeletingBrowserHistory {
+ AllowDeletingBrowserHistory: false
+ }
+ }
+ })");
+ web_history->ExpireHistory(
+ expire_list,
+ base::Bind(&BrowsingHistoryService::RemoveWebHistoryComplete,
+ weak_factory_.GetWeakPtr()),
+ partial_traffic_annotation);
+ }
+
+ driver_->OnRemoveVisits(expire_list);
+}
+
+// static
+void BrowsingHistoryService::MergeDuplicateResults(
+ QueryHistoryState* state,
+ std::vector<HistoryEntry>* results) {
+ DCHECK(state);
+ DCHECK(results);
+ DCHECK(results->empty());
+
+ // Will be used later to decide if we need to hold back results. This requires
+ // results to be sorted.
+ base::Time youngest_local = state->local_results.empty()
+ ? base::Time()
+ : state->local_results.rbegin()->time;
+ base::Time youngest_remote = state->remote_results.empty()
+ ? base::Time()
+ : state->remote_results.rbegin()->time;
+
+ std::vector<HistoryEntry> sorted;
+ sorted.assign(std::make_move_iterator(state->local_results.begin()),
+ std::make_move_iterator(state->local_results.end()));
+ state->local_results.clear();
+ sorted.insert(sorted.end(),
+ std::make_move_iterator(state->remote_results.begin()),
+ std::make_move_iterator(state->remote_results.end()));
+ state->remote_results.clear();
+ std::sort(sorted.begin(), sorted.end(), HistoryEntry::SortByTimeDescending);
+
+ // Pre-reserve the size of the new vector. Since we're working with pointers
+ // later on not doing this could lead to the vector being resized and to
+ // pointers to invalid locations.
+ std::vector<HistoryEntry> deduped;
+ deduped.reserve(sorted.size());
+
+ // Maps a URL to the most recent entry on a particular day.
+ std::map<GURL, HistoryEntry*> current_day_entries;
+
+ // Keeps track of the day that |current_day_urls| is holding the URLs for,
+ // in order to handle removing per-day duplicates.
+ base::Time current_day_midnight;
+
+ for (HistoryEntry& entry : sorted) {
+ // Reset the list of found URLs when a visit from a new day is encountered.
+ if (current_day_midnight != entry.time.LocalMidnight()) {
+ current_day_entries.clear();
+ current_day_midnight = entry.time.LocalMidnight();
+ }
+
+ // Keep this visit if it's the first visit to this URL on the current day.
+ if (current_day_entries.count(entry.url) == 0) {
+ deduped.push_back(std::move(entry));
+ current_day_entries[entry.url] = &deduped.back();
+ } else {
+ // Keep track of the timestamps of all visits to the URL on the same day.
+ HistoryEntry* matching_entry = current_day_entries[entry.url];
+ matching_entry->all_timestamps.insert(entry.all_timestamps.begin(),
+ entry.all_timestamps.end());
+
+ if (matching_entry->entry_type != entry.entry_type) {
+ matching_entry->entry_type = HistoryEntry::COMBINED_ENTRY;
+ }
+ }
+ }
+
+ // If the beginning of either source was not reached, that means there are
+ // more results from that source, and then other source needs to have its data
+ // held back until the former source catches up. This only send the UI history
+ // entries in the correct order. Subsequent continuation requests will get the
+ // delayed entries.
+ base::Time youngest_allowed = base::Time();
+ if (state->local_status == MORE_RESULTS) {
+ youngest_allowed = std::max(youngest_allowed, youngest_local);
+ state->local_end_time_for_continuation = youngest_local;
+ }
+ if (state->remote_status == MORE_RESULTS) {
+ youngest_allowed = std::max(youngest_allowed, youngest_remote);
+ state->remote_end_time_for_continuation = youngest_remote;
+ } else if (CanRetry(state->remote_status)) {
+ // TODO(skym): It is unclear if this is the best behavior. The UI is going
+ // to behave incorrectly if out of order results are received. So to
+ // guarantee that doesn't happen, use |youngest_local| for continuation
+ // calls. This will result in missing history entries for the failed calls.
+ // crbug.com/685866 is related to this problem.
+ state->remote_end_time_for_continuation = youngest_local;
+ }
+
+ HistoryEntry search_entry;
+ search_entry.time = youngest_allowed;
+ auto threshold_iter =
+ std::upper_bound(deduped.begin(), deduped.end(), search_entry,
+ HistoryEntry::SortByTimeDescending);
+
+ // Everything from threshold_iter to deduped.end() should either be all local
+ // or all remote, never a mix.
+ if (threshold_iter != deduped.end()) {
+ if (threshold_iter->entry_type == HistoryEntry::LOCAL_ENTRY) {
+ state->local_results.assign(std::make_move_iterator(threshold_iter),
+ std::make_move_iterator(deduped.end()));
+ } else if (threshold_iter->entry_type == HistoryEntry::REMOTE_ENTRY) {
+ state->remote_results.assign(std::make_move_iterator(threshold_iter),
+ std::make_move_iterator(deduped.end()));
+ } else {
+ NOTREACHED();
+ }
+ deduped.erase(threshold_iter, deduped.end());
+ }
+ *results = std::move(deduped);
+}
+
+void BrowsingHistoryService::QueryComplete(
+ scoped_refptr<QueryHistoryState> state,
+ QueryResults* results) {
+ std::vector<HistoryEntry>& output = state->local_results;
+ output.reserve(output.size() + results->size());
+
+ for (size_t i = 0; i < results->size(); ++i) {
+ URLResult const& page = (*results)[i];
+ // TODO(dubroy): Use sane time (crbug.com/146090) here when it's ready.
+ output.push_back(HistoryEntry(HistoryEntry::LOCAL_ENTRY, page.url(),
+ page.title(), page.visit_time(),
+ std::string(), !state->search_text.empty(),
+ page.snippet().text(), page.blocked_visit()));
+ }
+
+ state->local_status =
+ results->reached_beginning() ? REACHED_BEGINNING : MORE_RESULTS;
+
+ if (!web_history_timer_->IsRunning())
+ ReturnResultsToDriver(std::move(state));
+}
+
+void BrowsingHistoryService::ReturnResultsToDriver(
+ scoped_refptr<QueryHistoryState> state) {
+ std::vector<HistoryEntry> results;
+
+ // Always merge remote results, because Web History does not deduplicate .
+ // Local history should be using per-query deduplication, but if we are in a
+ // continuation, it's possible that we have carried over pending entries along
+ // with new results, and these two sets may contain duplicates. Assuming every
+ // call to Web History is successful, we shouldn't be able to have empty sync
+ // results at the same time as we have pending local.
+ if (state->remote_results.size()) {
+ int local_result_count = state->local_results.size();
+ MergeDuplicateResults(state.get(), &results);
+
+ if (local_result_count) {
+ // In the best case, we expect that all local results are duplicated on
+ // the server. Keep track of how many are missing.
+ int missing_count = 0;
+ for (const HistoryEntry& entry : results) {
+ missing_count +=
+ entry.entry_type ==
+ BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY
+ ? entry.all_timestamps.size()
+ : 0;
+ }
+ DCHECK_GE(local_result_count, missing_count);
+ UMA_HISTOGRAM_PERCENTAGE("WebHistory.LocalResultMissingOnServer",
+ missing_count * 100.0 / local_result_count);
+ }
+ } else {
+ // TODO(skym): Is the optimization to skip merge on local only results worth
+ // the complexity increase here?
+ if (state->local_status == MORE_RESULTS && !state->local_results.empty()) {
+ state->local_end_time_for_continuation =
+ state->local_results.rbegin()->time;
+ }
+ results = std::move(state->local_results);
+ }
+
+ QueryResultsInfo info;
+ info.search_text = state->search_text;
+ info.reached_beginning =
+ !CanRetry(state->local_status) && !CanRetry(state->remote_status);
+ info.sync_timed_out = state->remote_status == TIMED_OUT;
+ info.has_synced_results = state->remote_status == MORE_RESULTS ||
+ state->remote_status == REACHED_BEGINNING;
+ base::OnceClosure continuation =
+ base::Bind(&BrowsingHistoryService::QueryHistoryInternal,
+ weak_factory_.GetWeakPtr(), std::move(state));
+ driver_->OnQueryComplete(results, info, std::move(continuation));
+ driver_->HasOtherFormsOfBrowsingHistory(has_other_forms_of_browsing_history_,
+ has_synced_results_);
+}
+
+void BrowsingHistoryService::WebHistoryQueryComplete(
+ scoped_refptr<QueryHistoryState> state,
+ base::Time start_time,
+ WebHistoryService::Request* request,
+ const base::DictionaryValue* results_value) {
+ base::TimeDelta delta = clock_->Now() - start_time;
+ UMA_HISTOGRAM_TIMES("WebHistory.ResponseTime", delta);
+
+ // If the response came in too late, do nothing.
+ // TODO(dubroy): Maybe show a banner, and prompt the user to reload?
+ if (!web_history_timer_->IsRunning())
+ return;
+ web_history_timer_->Stop();
+ web_history_request_.reset();
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "WebHistory.QueryCompletion",
+ results_value ? WEB_HISTORY_QUERY_SUCCEEDED : WEB_HISTORY_QUERY_FAILED,
+ NUM_WEB_HISTORY_QUERY_BUCKETS);
+
+ if (results_value) {
+ has_synced_results_ = true;
+ const base::ListValue* events = nullptr;
+ if (results_value->GetList("event", &events)) {
+ state->remote_results.reserve(state->remote_results.size() +
+ events->GetSize());
+ for (unsigned int i = 0; i < events->GetSize(); ++i) {
+ const base::DictionaryValue* event = nullptr;
+ const base::DictionaryValue* result = nullptr;
+ const base::ListValue* results = nullptr;
+ const base::ListValue* ids = nullptr;
+ base::string16 url;
+ base::string16 title;
+ base::Time visit_time;
+
+ if (!(events->GetDictionary(i, &event) &&
+ event->GetList("result", &results) &&
+ results->GetDictionary(0, &result) &&
+ result->GetString("url", &url) && result->GetList("id", &ids) &&
+ ids->GetSize() > 0)) {
+ continue;
+ }
+
+ // Ignore any URLs that should not be shown in the history page.
+ GURL gurl(url);
+ if (driver_->ShouldHideWebHistoryUrl(gurl))
+ continue;
+
+ // Title is optional, so the return value is ignored here.
+ result->GetString("title", &title);
+
+ // Extract the timestamps of all the visits to this URL.
+ // They are referred to as "IDs" by the server.
+ for (int j = 0; j < static_cast<int>(ids->GetSize()); ++j) {
+ const base::DictionaryValue* id = nullptr;
+ std::string timestamp_string;
+ int64_t timestamp_usec = 0;
+
+ if (!ids->GetDictionary(j, &id) ||
+ !id->GetString("timestamp_usec", &timestamp_string) ||
+ !base::StringToInt64(timestamp_string, &timestamp_usec)) {
+ NOTREACHED() << "Unable to extract timestamp.";
+ continue;
+ }
+ // The timestamp on the server is a Unix time.
+ base::Time time = base::Time::UnixEpoch() +
+ base::TimeDelta::FromMicroseconds(timestamp_usec);
+
+ // Get the ID of the client that this visit came from.
+ std::string client_id;
+ id->GetString("client_id", &client_id);
+
+ state->remote_results.push_back(HistoryEntry(
+ HistoryEntry::REMOTE_ENTRY, gurl, title, time, client_id,
+ !state->search_text.empty(), base::string16(),
+ /* blocked_visit */ false));
+ }
+ }
+ }
+ std::string continuation_token;
+ results_value->GetString("continuation_token", &continuation_token);
+ state->remote_status =
+ continuation_token.empty() ? REACHED_BEGINNING : MORE_RESULTS;
+ } else {
+ has_synced_results_ = false;
+ state->remote_status = FAILURE;
+ }
+
+ if (!query_task_tracker_.HasTrackedTasks())
+ ReturnResultsToDriver(std::move(state));
+}
+
+void BrowsingHistoryService::OtherFormsOfBrowsingHistoryQueryComplete(
+ bool found_other_forms_of_browsing_history) {
+ has_other_forms_of_browsing_history_ = found_other_forms_of_browsing_history;
+
+ RecordMetricsForNoticeAboutOtherFormsOfBrowsingHistory(
+ has_other_forms_of_browsing_history_);
+
+ driver_->HasOtherFormsOfBrowsingHistory(has_other_forms_of_browsing_history_,
+ has_synced_results_);
+}
+
+void BrowsingHistoryService::RemoveComplete() {
+ urls_to_be_deleted_.clear();
+
+ // Notify the driver that the deletion request is complete, but only if
+ // web history delete request is not still pending.
+ if (!has_pending_delete_request_)
+ driver_->OnRemoveVisitsComplete();
+}
+
+void BrowsingHistoryService::RemoveWebHistoryComplete(bool success) {
+ has_pending_delete_request_ = false;
+ // TODO(dubroy): Should we handle failure somehow? Delete directives will
+ // ensure that the visits are eventually deleted, so maybe it's not necessary.
+ if (!delete_task_tracker_.HasTrackedTasks())
+ RemoveComplete();
+}
+
+// Helper function for Observe that determines if there are any differences
+// between the URLs noticed for deletion and the ones we are expecting.
+static bool DeletionsDiffer(const URLRows& deleted_rows,
+ const std::set<GURL>& urls_to_be_deleted) {
+ if (deleted_rows.size() != urls_to_be_deleted.size())
+ return true;
+ for (const auto& i : deleted_rows) {
+ if (urls_to_be_deleted.find(i.url()) == urls_to_be_deleted.end())
+ return true;
+ }
+ return false;
+}
+
+void BrowsingHistoryService::OnURLsDeleted(HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) {
+ if (all_history || DeletionsDiffer(deleted_rows, urls_to_be_deleted_))
+ driver_->HistoryDeleted();
+}
+
+void BrowsingHistoryService::OnWebHistoryDeleted() {
+ // TODO(calamity): Only ignore web history deletions when they are actually
+ // initiated by us, rather than ignoring them whenever we are deleting.
+ if (!has_pending_delete_request_)
+ driver_->HistoryDeleted();
+}
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/browsing_history_service.h b/chromium/components/history/core/browser/browsing_history_service.h
new file mode 100644
index 00000000000..41d15e9dae2
--- /dev/null
+++ b/chromium/components/history/core/browser/browsing_history_service.h
@@ -0,0 +1,266 @@
+// 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_HISTORY_CORE_BROWSER_BROWSING_HISTORY_SERVICE_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_BROWSING_HISTORY_SERVICE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/strings/string16.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/time/clock.h"
+#include "base/timer/timer.h"
+#include "base/values.h"
+#include "components/history/core/browser/history_service_observer.h"
+#include "components/history/core/browser/url_row.h"
+#include "components/history/core/browser/web_history_service.h"
+#include "components/history/core/browser/web_history_service_observer.h"
+#include "components/sync/driver/sync_service_observer.h"
+#include "url/gurl.h"
+
+namespace syncer {
+class SyncService;
+class SyncServiceObserver;
+} // namespace syncer
+
+FORWARD_DECLARE_TEST(BrowsingHistoryHandlerTest, ObservingWebHistoryDeletions);
+
+namespace history {
+
+class BrowsingHistoryDriver;
+class HistoryService;
+class QueryResults;
+struct QueryOptions;
+
+// Interacts with HistoryService, WebHistoryService, and SyncService to query
+// history and provide results to the associated BrowsingHistoryDriver.
+class BrowsingHistoryService : public HistoryServiceObserver,
+ public WebHistoryServiceObserver,
+ public syncer::SyncServiceObserver {
+ public:
+ // Represents a history entry to be shown to the user, representing either
+ // a local or remote visit. A single entry can represent multiple visits,
+ // since only the most recent visit on a particular day is shown.
+ struct HistoryEntry {
+ // Values indicating whether an entry represents only local visits, only
+ // remote visits, or a mixture of both.
+ enum EntryType {
+ EMPTY_ENTRY = 0,
+ LOCAL_ENTRY,
+ REMOTE_ENTRY,
+ COMBINED_ENTRY
+ };
+
+ HistoryEntry(EntryType type,
+ const GURL& url,
+ const base::string16& title,
+ base::Time time,
+ const std::string& client_id,
+ bool is_search_result,
+ const base::string16& snippet,
+ bool blocked_visit);
+ HistoryEntry();
+ HistoryEntry(const HistoryEntry& other);
+ virtual ~HistoryEntry();
+
+ // Comparison function for sorting HistoryEntries from newest to oldest.
+ static bool SortByTimeDescending(const HistoryEntry& entry1,
+ const HistoryEntry& entry2);
+
+ // The type of visits this entry represents: local, remote, or both.
+ EntryType entry_type;
+
+ GURL url;
+
+ base::string16 title; // Title of the entry. May be empty.
+
+ // The time of the entry. Usually this will be the time of the most recent
+ // visit to |url| on a particular day as defined in the local timezone.
+ base::Time time;
+
+ // The sync ID of the client on which the most recent visit occurred.
+ std::string client_id;
+
+ // Timestamps of all local or remote visits the same URL on the same day.
+ // TODO(skym): These should probably be converted to base::Time.
+ std::set<int64_t> all_timestamps;
+
+ // If true, this entry is a search result.
+ bool is_search_result;
+
+ // The entry's search snippet, if this entry is a search result.
+ base::string16 snippet;
+
+ // Whether this entry was blocked when it was attempted.
+ bool blocked_visit;
+ };
+
+ // Contains information about a completed history query.
+ struct QueryResultsInfo {
+ ~QueryResultsInfo();
+
+ // The query search text.
+ base::string16 search_text;
+
+ // Whether this query reached the end of all results, or if there are more
+ // history entries that can be fetched through paging.
+ bool reached_beginning = false;
+
+ // Whether the last call to Web History timed out.
+ bool sync_timed_out = false;
+
+ // Whether the last call to Web History returned successfully with a message
+ // body. During continuation queries we are not guaranteed to always make a
+ // call to WebHistory, and this value could reflect the state from previous
+ // queries.
+ bool has_synced_results = false;
+ };
+
+ BrowsingHistoryService(BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service);
+ ~BrowsingHistoryService() override;
+
+ // Start a new query with the given parameters.
+ void QueryHistory(const base::string16& search_text,
+ const QueryOptions& options);
+
+ // Removes |items| from history.
+ void RemoveVisits(const std::vector<HistoryEntry>& items);
+
+ // SyncServiceObserver implementation.
+ void OnStateChanged(syncer::SyncService* sync) override;
+
+ protected:
+ // Constructor that allows specifying more dependencies for unit tests.
+ BrowsingHistoryService(BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service,
+ std::unique_ptr<base::Timer> web_history_timer);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(::BrowsingHistoryHandlerTest,
+ ObservingWebHistoryDeletions);
+
+ // Used to hold and track query state between asynchronous calls.
+ struct QueryHistoryState;
+
+ // Moves results from |state| into |results|, merging both remote and local
+ // results together and maintaining reverse chronological order. Any results
+ // with the same URL will be merged together for each day. Often holds back
+ // some results in |state| from one of the two sources to ensure that they're
+ // always returned to the driver in correct order. This function also updates
+ // the end times in |state| for both sources that the next query should be
+ // made against.
+ static void MergeDuplicateResults(QueryHistoryState* state,
+ std::vector<HistoryEntry>* results);
+
+ // Core implementation of history querying.
+ void QueryHistoryInternal(scoped_refptr<QueryHistoryState> state);
+
+ // Callback from the history system when a history query has completed.
+ void QueryComplete(scoped_refptr<QueryHistoryState> state,
+ QueryResults* results);
+
+ // Combines the query results from the local history database and the history
+ // server, and sends the combined results to the
+ // BrowsingHistoryDriver.
+ void ReturnResultsToDriver(scoped_refptr<QueryHistoryState> state);
+
+ // Callback from |web_history_timer_| when a response from web history has
+ // not been received in time.
+ void WebHistoryTimeout(scoped_refptr<QueryHistoryState> state);
+
+ // Callback from the WebHistoryService when a query has completed.
+ void WebHistoryQueryComplete(scoped_refptr<QueryHistoryState> state,
+ base::Time start_time,
+ WebHistoryService::Request* request,
+ const base::DictionaryValue* results_value);
+
+ // Callback telling us whether other forms of browsing history were found
+ // on the history server.
+ void OtherFormsOfBrowsingHistoryQueryComplete(
+ bool found_other_forms_of_browsing_history);
+
+ // Callback from the history system when visits were deleted.
+ void RemoveComplete();
+
+ // Callback from history server when visits were deleted.
+ void RemoveWebHistoryComplete(bool success);
+
+ // HistoryServiceObserver implementation.
+ void OnURLsDeleted(HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) override;
+
+ // WebHistoryServiceObserver implementation.
+ void OnWebHistoryDeleted() override;
+
+ // Tracker for search requests to the history service.
+ base::CancelableTaskTracker query_task_tracker_;
+
+ // The currently-executing request for synced history results.
+ // Deleting the request will cancel it.
+ std::unique_ptr<WebHistoryService::Request> web_history_request_;
+
+ // True if there is a pending delete requests to the history service.
+ bool has_pending_delete_request_ = false;
+
+ // Tracker for delete requests to the history service.
+ base::CancelableTaskTracker delete_task_tracker_;
+
+ // The list of URLs that are in the process of being deleted.
+ std::set<GURL> urls_to_be_deleted_;
+
+ // Timer used to implement a timeout on a Web History response.
+ std::unique_ptr<base::Timer> web_history_timer_;
+
+ // HistoryService (local history) observer.
+ ScopedObserver<HistoryService, HistoryServiceObserver>
+ history_service_observer_;
+
+ // WebHistoryService (synced history) observer.
+ ScopedObserver<WebHistoryService, WebHistoryServiceObserver>
+ web_history_service_observer_;
+
+ // SyncService observer listens to late initialization of history sync.
+ ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
+ sync_service_observer_;
+
+ // Whether the last call to Web History returned synced results.
+ bool has_synced_results_ = false;
+
+ // Whether there are other forms of browsing history on the history server.
+ bool has_other_forms_of_browsing_history_ = false;
+
+ BrowsingHistoryDriver* driver_;
+
+ HistoryService* local_history_;
+
+ syncer::SyncService* sync_service_;
+
+ // The clock used to vend times.
+ std::unique_ptr<base::Clock> clock_;
+
+ base::WeakPtrFactory<BrowsingHistoryService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryService);
+};
+
+} // namespace history
+
+#endif // COMPONENTS_HISTORY_CORE_BROWSER_BROWSING_HISTORY_SERVICE_H_
diff --git a/chromium/components/history/core/browser/browsing_history_service_unittest.cc b/chromium/components/history/core/browser/browsing_history_service_unittest.cc
new file mode 100644
index 00000000000..f20b5d40e98
--- /dev/null
+++ b/chromium/components/history/core/browser/browsing_history_service_unittest.cc
@@ -0,0 +1,698 @@
+// 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/history/core/browser/browsing_history_service.h"
+
+#include <utility>
+
+#include "base/callback_forward.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/timer/mock_timer.h"
+#include "base/values.h"
+#include "components/history/core/browser/browsing_history_driver.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/test/fake_web_history_service.h"
+#include "components/history/core/test/history_service_test_util.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/driver/sync_service_observer.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace history {
+
+using HistoryEntry = BrowsingHistoryService::HistoryEntry;
+
+namespace {
+
+const char kUrl1[] = "http://www.one.com";
+const char kUrl2[] = "http://www.two.com";
+const char kUrl3[] = "http://www.three.com";
+const char kUrl4[] = "http://www.four.com";
+const char kUrl5[] = "http://www.five.com";
+const char kUrl6[] = "http://www.six.com";
+const char kUrl7[] = "http://www.seven.com";
+
+const HistoryEntry::EntryType kLocal = HistoryEntry::LOCAL_ENTRY;
+const HistoryEntry::EntryType kRemote = HistoryEntry::REMOTE_ENTRY;
+const HistoryEntry::EntryType kBoth = HistoryEntry::COMBINED_ENTRY;
+
+struct TestResult {
+ std::string url;
+ int64_t hour_offset; // Visit time in hours past the baseline time.
+ HistoryEntry::EntryType type;
+};
+
+// Used to bind a callback.
+void DoNothing(bool ignored) {}
+
+class QuittingHistoryDBTask : public HistoryDBTask {
+ public:
+ explicit QuittingHistoryDBTask(base::OnceClosure done_closure)
+ : done_closure_(std::move(done_closure)) {}
+
+ // HistoryDBTask implementation.
+ bool RunOnDBThread(history::HistoryBackend* backend,
+ history::HistoryDatabase* db) override {
+ return true;
+ }
+ void DoneRunOnMainThread() override { std::move(done_closure_).Run(); }
+
+ private:
+ base::OnceClosure done_closure_;
+ DISALLOW_COPY_AND_ASSIGN(QuittingHistoryDBTask);
+};
+
+class TestSyncService : public syncer::FakeSyncService {
+ public:
+ int GetObserverCount() { return observer_count_; }
+
+ private:
+ void AddObserver(syncer::SyncServiceObserver* observer) override {
+ observer_count_++;
+ }
+ void RemoveObserver(syncer::SyncServiceObserver* observer) override {
+ observer_count_--;
+ }
+
+ int observer_count_ = 0;
+};
+
+class TestBrowsingHistoryDriver : public BrowsingHistoryDriver {
+ public:
+ explicit TestBrowsingHistoryDriver(WebHistoryService* web_history)
+ : web_history_(web_history) {}
+
+ void SetWebHistory(WebHistoryService* web_history) {
+ web_history_ = web_history;
+ }
+
+ using QueryResult = std::pair<std::vector<HistoryEntry>,
+ BrowsingHistoryService::QueryResultsInfo>;
+ std::vector<QueryResult> GetQueryResults() { return query_results_; }
+
+ int GetHistoryDeletedCount() { return history_deleted_count_; }
+
+ void RunContinuation() {
+ EXPECT_TRUE(continuation_closure_);
+ std::move(continuation_closure_).Run();
+ }
+
+ private:
+ // BrowsingHistoryDriver implementation.
+ void OnQueryComplete(
+ const std::vector<HistoryEntry>& results,
+ const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+ base::OnceClosure continuation_closure) override {
+ query_results_.push_back(QueryResult(results, query_results_info));
+ continuation_closure_ = std::move(continuation_closure);
+ }
+ void OnRemoveVisitsComplete() override {}
+ void OnRemoveVisitsFailed() override {}
+ void OnRemoveVisits(
+ const std::vector<ExpireHistoryArgs>& expire_list) override {}
+ void HistoryDeleted() override { history_deleted_count_++; }
+ void HasOtherFormsOfBrowsingHistory(bool has_other_forms,
+ bool has_synced_results) override {}
+ bool AllowHistoryDeletions() override { return true; }
+ bool ShouldHideWebHistoryUrl(const GURL& url) override { return false; }
+ WebHistoryService* GetWebHistoryService() override { return web_history_; }
+ void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ WebHistoryService* local_history,
+ base::Callback<void(bool)> callback) override {}
+
+ int history_deleted_count_ = 0;
+ std::vector<QueryResult> query_results_;
+ base::OnceClosure continuation_closure_;
+ WebHistoryService* web_history_;
+};
+
+class TestWebHistoryService : public FakeWebHistoryService {
+ public:
+ TestWebHistoryService()
+ : FakeWebHistoryService(nullptr,
+ nullptr,
+ scoped_refptr<net::URLRequestContextGetter>()) {}
+
+ void TriggerOnWebHistoryDeleted() {
+ TestRequest request;
+ ExpireHistoryCompletionCallback(base::Bind(&DoNothing), &request, true);
+ }
+
+ protected:
+ class TestRequest : public WebHistoryService::Request {
+ private:
+ // WebHistoryService::Request implementation.
+ bool IsPending() override { return false; }
+ int GetResponseCode() override { return net::HTTP_OK; }
+ const std::string& GetResponseBody() override { return body_; }
+ void SetPostData(const std::string& post_data) override{};
+ void SetPostDataAndType(const std::string& post_data,
+ const std::string& mime_type) override{};
+ void SetUserAgent(const std::string& user_agent) override{};
+ void Start() override{};
+
+ std::string body_ = "{}";
+ };
+};
+
+class TimeoutWebHistoryService : public TestWebHistoryService {
+ private:
+ // WebHistoryService implementation.
+ Request* CreateRequest(const GURL& url,
+ const CompletionCallback& callback,
+ const net::PartialNetworkTrafficAnnotationTag&
+ partial_traffic_annotation) override {
+ return new TestWebHistoryService::TestRequest();
+ }
+};
+
+class TestBrowsingHistoryService : public BrowsingHistoryService {
+ public:
+ TestBrowsingHistoryService(BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service,
+ std::unique_ptr<base::Timer> timer)
+ : BrowsingHistoryService(driver,
+ local_history,
+ sync_service,
+ std::move(timer)) {}
+};
+
+class BrowsingHistoryServiceTest : public ::testing::Test {
+ protected:
+ // WebHistory API is to pass time ranges as the number of microseconds since
+ // Time::UnixEpoch() as a query parameter. This becomes a problem when we use
+ // Time::LocalMidnight(), which rounds _down_, and will result in a time
+ // before Time::UnixEpoch() that cannot be represented. By adding 1 day we
+ // ensure all test data is after Time::UnixEpoch().
+ BrowsingHistoryServiceTest()
+ : baseline_time_(Time::UnixEpoch().LocalMidnight() +
+ TimeDelta::FromDays(1)),
+ driver_(&web_history_) {
+ EXPECT_TRUE(history_dir_.CreateUniqueTempDir());
+ local_history_ = CreateHistoryService(history_dir_.GetPath(), true);
+ ResetService(driver(), local_history(), sync());
+ }
+
+ void ResetService(BrowsingHistoryDriver* driver,
+ HistoryService* local_history,
+ syncer::SyncService* sync_service) {
+ std::unique_ptr<base::MockTimer> timer =
+ std::make_unique<base::MockTimer>(false, false);
+ timer_ = timer.get();
+ browsing_history_service_ = std::make_unique<TestBrowsingHistoryService>(
+ driver, local_history, sync_service, std::move(timer));
+ }
+
+ void BlockUntilHistoryProcessesPendingRequests() {
+ base::CancelableTaskTracker tracker;
+ base::RunLoop run_loop;
+ local_history_->ScheduleDBTask(
+ std::make_unique<QuittingHistoryDBTask>(run_loop.QuitWhenIdleClosure()),
+ &tracker);
+ run_loop.Run();
+ }
+
+ Time OffsetToTime(int64_t hour_offset) {
+ return baseline_time_ + TimeDelta::FromHours(hour_offset);
+ }
+
+ void AddHistory(const std::vector<TestResult>& data) {
+ for (const TestResult& entry : data) {
+ if (entry.type == kLocal) {
+ local_history()->AddPage(GURL(entry.url),
+ OffsetToTime(entry.hour_offset),
+ VisitSource::SOURCE_BROWSED);
+ } else if (entry.type == kRemote) {
+ web_history()->AddSyncedVisit(entry.url,
+ OffsetToTime(entry.hour_offset));
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+
+ void VerifyEntry(const TestResult& expected, const HistoryEntry& actual) {
+ EXPECT_EQ(GURL(expected.url), actual.url);
+ EXPECT_EQ(OffsetToTime(expected.hour_offset), actual.time);
+ EXPECT_EQ(static_cast<int>(expected.type),
+ static_cast<int>(actual.entry_type));
+ }
+
+ TestBrowsingHistoryDriver::QueryResult QueryHistory(size_t max_count = 0) {
+ QueryOptions options;
+ options.max_count = max_count;
+ return QueryHistory(options);
+ }
+
+ TestBrowsingHistoryDriver::QueryResult QueryHistory(
+ const QueryOptions& options) {
+ size_t previous_results_count = driver()->GetQueryResults().size();
+ service()->QueryHistory(base::string16(), options);
+ BlockUntilHistoryProcessesPendingRequests();
+ const std::vector<TestBrowsingHistoryDriver::QueryResult> all_results =
+ driver()->GetQueryResults();
+ EXPECT_EQ(previous_results_count + 1, all_results.size());
+ return *all_results.rbegin();
+ }
+
+ TestBrowsingHistoryDriver::QueryResult ContinueQuery() {
+ size_t previous_results_count = driver()->GetQueryResults().size();
+ driver()->RunContinuation();
+ BlockUntilHistoryProcessesPendingRequests();
+ const std::vector<TestBrowsingHistoryDriver::QueryResult> all_results =
+ driver()->GetQueryResults();
+ EXPECT_EQ(previous_results_count + 1, all_results.size());
+ return *all_results.rbegin();
+ }
+
+ void VerifyQueryResult(bool reached_beginning,
+ bool has_synced_results,
+ const std::vector<TestResult>& expected_entries,
+ TestBrowsingHistoryDriver::QueryResult result) {
+ EXPECT_EQ(reached_beginning, result.second.reached_beginning);
+ EXPECT_EQ(has_synced_results, result.second.has_synced_results);
+ EXPECT_FALSE(result.second.sync_timed_out);
+ EXPECT_EQ(expected_entries.size(), result.first.size());
+ for (size_t i = 0; i < expected_entries.size(); ++i) {
+ VerifyEntry(expected_entries[i], result.first[i]);
+ }
+ }
+
+ HistoryService* local_history() { return local_history_.get(); }
+ TestWebHistoryService* web_history() { return &web_history_; }
+ TestSyncService* sync() { return &sync_service_; }
+ TestBrowsingHistoryDriver* driver() { return &driver_; }
+ base::MockTimer* timer() { return timer_; }
+ TestBrowsingHistoryService* service() {
+ return browsing_history_service_.get();
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ // Duplicates on the same day in the local timezone are removed, so set a
+ // baseline time in local time.
+ Time baseline_time_;
+
+ base::ScopedTempDir history_dir_;
+ std::unique_ptr<HistoryService> local_history_;
+ TestWebHistoryService web_history_;
+ TestSyncService sync_service_;
+ TestBrowsingHistoryDriver driver_;
+ base::MockTimer* timer_;
+ std::unique_ptr<TestBrowsingHistoryService> browsing_history_service_;
+};
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryNoSources) {
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), nullptr, nullptr);
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ false, {}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryJustLocal) {
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), local_history(), nullptr);
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ false, {}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryJustLocal) {
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), local_history(), nullptr);
+ AddHistory({{kUrl1, 1, kLocal}});
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ false, {{kUrl1, 1, kLocal}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryJustWeb) {
+ ResetService(driver(), nullptr, nullptr);
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ true, {}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryDelayedWeb) {
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), nullptr, sync());
+ driver()->SetWebHistory(web_history());
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ true, {}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryJustWeb) {
+ ResetService(driver(), nullptr, sync());
+ AddHistory({{kUrl1, 1, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ true, {{kUrl1, 1, kRemote}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryBothSources) {
+ ResetService(driver(), local_history(), sync());
+ VerifyQueryResult(/*reached_beginning*/ true,
+ /*has_synced_results*/ true, {}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryAllSources) {
+ ResetService(driver(), local_history(), sync());
+ AddHistory({{kUrl1, 1, kLocal},
+ {kUrl2, 2, kLocal},
+ {kUrl3, 3, kRemote},
+ {kUrl1, 4, kRemote}});
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 4, kBoth}, {kUrl3, 3, kRemote}, {kUrl2, 2, kLocal}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalTimeRanges) {
+ AddHistory({{kUrl1, 1, kLocal},
+ {kUrl2, 2, kLocal},
+ {kUrl3, 3, kLocal},
+ {kUrl4, 4, kLocal}});
+ QueryOptions options;
+ options.begin_time = OffsetToTime(2);
+ options.end_time = OffsetToTime(4);
+ // Having a |reached_beginning| value of false here seems
+ // counterintuitive. Seems to be for paging by |begin_time| instead of
+ // |count|. If the local history implementation changes, feel free to update
+ // this value, all this test cares about is that BrowsingHistoryService passes
+ // the values through correctly.
+ VerifyQueryResult(/*reached_beginning*/ false,
+ /*has_synced_results*/ true,
+ {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}},
+ QueryHistory(options));
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemoteTimeRanges) {
+ AddHistory({{kUrl1, 1, kRemote},
+ {kUrl2, 2, kRemote},
+ {kUrl3, 3, kRemote},
+ {kUrl4, 4, kRemote}});
+ QueryOptions options;
+ options.begin_time = OffsetToTime(2);
+ options.end_time = OffsetToTime(4);
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}}, QueryHistory(options));
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalPagingPartial) {
+ AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+ VerifyQueryResult(/*reached_beginning*/ false,
+ /*has_synced_results*/ true,
+ {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}}, QueryHistory(2));
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 1, kLocal}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalPagingFull) {
+ AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}, {kUrl1, 1, kLocal}},
+ QueryHistory(3));
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true, {},
+ ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemotePagingPartial) {
+ AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ false,
+ /*has_synced_results*/ true,
+ {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}},
+ QueryHistory(2));
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemotePagingFull) {
+ AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}, {kUrl1, 1, kRemote}},
+ QueryHistory(3));
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true, {},
+ ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesSameDay) {
+ AddHistory({{kUrl1, 0, kRemote},
+ {kUrl2, 1, kRemote},
+ {kUrl1, 2, kRemote},
+ {kUrl1, 3, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 3, kRemote}, {kUrl2, 1, kRemote}}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesNextDayNotRemoved) {
+ AddHistory({{kUrl1, 0, kRemote}, {kUrl1, 23, kRemote}, {kUrl1, 24, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 24, kRemote}, {kUrl1, 23, kRemote}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesMultipleDays) {
+ AddHistory({{kUrl2, 0, kRemote},
+ {kUrl1, 1, kRemote},
+ {kUrl2, 2, kRemote},
+ {kUrl1, 3, kRemote},
+ {kUrl2, 24, kRemote},
+ {kUrl1, 25, kRemote},
+ {kUrl2, 26, kRemote},
+ {kUrl1, 27, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 27, kRemote},
+ {kUrl2, 26, kRemote},
+ {kUrl1, 3, kRemote},
+ {kUrl2, 2, kRemote}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesVerifyTimestamps) {
+ AddHistory({{kUrl1, 0, kRemote},
+ {kUrl2, 1, kRemote},
+ {kUrl1, 2, kRemote},
+ {kUrl1, 3, kRemote}});
+ auto results = QueryHistory();
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 3, kRemote}, {kUrl2, 1, kRemote}}, results);
+ EXPECT_EQ(3U, results.first[0].all_timestamps.size());
+ EXPECT_EQ(1U, results.first[1].all_timestamps.size());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryMerge) {
+ AddHistory({{kUrl1, 1, kRemote},
+ {kUrl2, 2, kRemote},
+ {kUrl3, 3, kLocal},
+ {kUrl1, 4, kLocal}});
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 4, kBoth}, {kUrl3, 3, kLocal}, {kUrl2, 2, kRemote}},
+ QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPending) {
+ AddHistory({{kUrl1, 1, kRemote},
+ {kUrl2, 2, kRemote},
+ {kUrl3, 3, kLocal},
+ {kUrl4, 4, kLocal}});
+ VerifyQueryResult(
+ /*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl4, 4, kLocal}}, QueryHistory(1));
+ VerifyQueryResult(
+ /*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl3, 3, kLocal}, {kUrl2, 2, kRemote}}, ContinueQuery());
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+// A full request worth of local results will sit in pending, resulting in us
+// being able to delete local history before our next query and we should still
+// see the local entry.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryFullLocalPending) {
+ AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+ VerifyQueryResult(
+ /*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl3, 3, kRemote}}, QueryHistory(1));
+
+ local_history()->DeleteURL(GURL(kUrl1));
+ VerifyQueryResult(
+ /*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl2, 2, kRemote}, {kUrl1, 1, kLocal}}, ContinueQuery());
+}
+
+// Part of a request worth of local results will sit in pending, resulting in us
+// seeing extra local results on our next request.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPartialLocalPending) {
+ AddHistory({{kUrl1, 1, kLocal},
+ {kUrl2, 2, kLocal},
+ {kUrl3, 3, kRemote},
+ {kUrl4, 4, kLocal},
+ {kUrl5, 5, kRemote},
+ {kUrl6, 6, kRemote},
+ {kUrl7, 7, kLocal}});
+ VerifyQueryResult(
+ /*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl7, 7, kLocal}, {kUrl6, 6, kRemote}, {kUrl5, 5, kRemote}},
+ QueryHistory(2));
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl4, 4, kLocal},
+ {kUrl3, 3, kRemote},
+ {kUrl2, 2, kLocal},
+ {kUrl1, 1, kLocal}},
+ ContinueQuery());
+}
+
+// A full request worth of remote results will sit in pending, resulting in us
+// being able to delete remote history before our next query and we should still
+// see the remote entry.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryFullRemotePending) {
+ AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+ VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl3, 3, kLocal}}, QueryHistory(1));
+
+ web_history()->ClearSyncedVisits();
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl2, 2, kLocal}, {kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+// Part of a request worth of remote results will sit in pending, resulting in
+// us seeing extra remote results on our next request.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPartialRemotePending) {
+ AddHistory({{kUrl1, 1, kRemote},
+ {kUrl2, 2, kRemote},
+ {kUrl3, 3, kLocal},
+ {kUrl4, 4, kRemote},
+ {kUrl5, 5, kLocal},
+ {kUrl6, 6, kLocal},
+ {kUrl7, 7, kRemote}});
+ VerifyQueryResult(
+ /*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl7, 7, kRemote}, {kUrl6, 6, kLocal}, {kUrl5, 5, kLocal}},
+ QueryHistory(2));
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl4, 4, kRemote},
+ {kUrl3, 3, kLocal},
+ {kUrl2, 2, kRemote},
+ {kUrl1, 1, kRemote}},
+ ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailureEmpty) {
+ web_history()->SetupFakeResponse(false, 0);
+ VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+ {}, QueryHistory());
+ web_history()->SetupFakeResponse(true, net::HTTP_OK);
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true, {},
+ ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailurePagingRemote) {
+ AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+ VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ true,
+ {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}},
+ QueryHistory(2));
+
+ web_history()->SetupFakeResponse(false, 0);
+ VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+ {}, ContinueQuery());
+
+ web_history()->SetupFakeResponse(true, net::HTTP_OK);
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailurePagingLocal) {
+ AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+ web_history()->SetupFakeResponse(false, 0);
+ VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+ {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}}, QueryHistory(2));
+
+ web_history()->SetupFakeResponse(true, net::HTTP_OK);
+ VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+ {{kUrl1, 1, kLocal}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, WebHistoryTimeout) {
+ TimeoutWebHistoryService timeout;
+ driver()->SetWebHistory(&timeout);
+ ResetService(driver(), local_history(), sync());
+ EXPECT_EQ(0U, driver()->GetQueryResults().size());
+ service()->QueryHistory(base::string16(), QueryOptions());
+ EXPECT_EQ(0U, driver()->GetQueryResults().size());
+ BlockUntilHistoryProcessesPendingRequests();
+ timer()->Fire();
+ EXPECT_EQ(1U, driver()->GetQueryResults().size());
+ EXPECT_FALSE(driver()->GetQueryResults()[0].second.reached_beginning);
+ EXPECT_FALSE(driver()->GetQueryResults()[0].second.has_synced_results);
+ EXPECT_TRUE(driver()->GetQueryResults()[0].second.sync_timed_out);
+
+ // WebHistoryService will DCHECK if we destroy it before the observer in
+ // BrowsingHistoryService is removed, so reset our first
+ // BrowsingHistoryService before |timeout| goes out of scope.
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), nullptr, nullptr);
+}
+
+TEST_F(BrowsingHistoryServiceTest, ObservingWebHistory) {
+ ResetService(driver(), nullptr, sync());
+
+ // No need to observe SyncService since we have a WebHistory already.
+ EXPECT_EQ(0, sync()->GetObserverCount());
+
+ web_history()->TriggerOnWebHistoryDeleted();
+ EXPECT_EQ(1, driver()->GetHistoryDeletedCount());
+}
+
+TEST_F(BrowsingHistoryServiceTest, ObservingWebHistoryDelayedWeb) {
+ driver()->SetWebHistory(nullptr);
+ ResetService(driver(), nullptr, sync());
+
+ // Since there's no WebHistory, observations should have been setup on Sync.
+ EXPECT_EQ(1, sync()->GetObserverCount());
+
+ // OnStateChanged() is a no-op if WebHistory is still inaccessible.
+ service()->OnStateChanged(sync());
+ EXPECT_EQ(1, sync()->GetObserverCount());
+
+ driver()->SetWebHistory(web_history());
+ // Since WebHistory is currently not being observed, triggering a history
+ // deletion will not be propagated to the driver.
+ web_history()->TriggerOnWebHistoryDeleted();
+ EXPECT_EQ(0, driver()->GetHistoryDeletedCount());
+
+ // Once OnStateChanged() gets called, the BrowsingHistoryService switches from
+ // observing SyncService to WebHistoryService. As such, RemoveObserver should
+ // have been called on SyncService, so lets verify.
+ service()->OnStateChanged(sync());
+ EXPECT_EQ(0, sync()->GetObserverCount());
+
+ // Only now should deletion should be propagated through.
+ web_history()->TriggerOnWebHistoryDeleted();
+ EXPECT_EQ(1, driver()->GetHistoryDeletedCount());
+}
+
+} // namespace
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/expire_history_backend.cc b/chromium/components/history/core/browser/expire_history_backend.cc
index d57a60432af..2e69c9286c2 100644
--- a/chromium/components/history/core/browser/expire_history_backend.cc
+++ b/chromium/components/history/core/browser/expire_history_backend.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/feature_list.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/location.h"
@@ -114,8 +115,27 @@ const int kExpirationDelaySec = 30;
// iteration, so we want to wait longer before checking to avoid wasting CPU.
const int kExpirationEmptyDelayMin = 5;
+// The minimum number of hours between checking for old on-demand favicons that
+// should be cleared.
+const int kClearOnDemandFaviconsIntervalHours = 24;
+
+bool IsAnyURLBookmarked(HistoryBackendClient* backend_client,
+ const std::vector<GURL>& urls) {
+ for (const GURL& url : urls) {
+ if (backend_client->IsBookmarked(url))
+ return true;
+ }
+ return false;
+}
+
} // namespace
+namespace internal {
+
+const base::Feature kClearOldOnDemandFavicons{
+ "ClearOldOnDemandFavicons", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace internal
// ExpireHistoryBackend::DeleteEffects ----------------------------------------
@@ -473,14 +493,54 @@ void ExpireHistoryBackend::DoExpireIteration() {
GetCurrentExpirationTime(), reader, kNumExpirePerIteration);
work_queue_.pop();
- // If there are more items to expire, add the reader back to the queue, thus
- // creating a new task for future iterations.
- if (more_to_expire)
+ if (more_to_expire) {
+ // If there are more items to expire, add the reader back to the queue, thus
+ // creating a new task for future iterations.
work_queue_.push(reader);
+ } else {
+ // Otherwise do a final clean-up - remove old favicons not bound to visits.
+ ClearOldOnDemandFavicons(GetCurrentExpirationTime());
+ }
ScheduleExpire();
}
+void ExpireHistoryBackend::ClearOldOnDemandFavicons(
+ base::Time expiration_threshold) {
+ if (!base::FeatureList::IsEnabled(internal::kClearOldOnDemandFavicons))
+ return;
+
+ // Extra precaution to avoid repeated calls to GetOldOnDemandFavicons() close
+ // in time, since it can be fairly expensive.
+ if (expiration_threshold <
+ last_on_demand_expiration_threshold_ +
+ base::TimeDelta::FromHours(kClearOnDemandFaviconsIntervalHours)) {
+ return;
+ }
+
+ last_on_demand_expiration_threshold_ = expiration_threshold;
+
+ std::map<favicon_base::FaviconID, IconMappingsForExpiry> icon_mappings =
+ thumb_db_->GetOldOnDemandFavicons(expiration_threshold);
+ DeleteEffects effects;
+
+ for (auto id_and_mappings_pair : icon_mappings) {
+ favicon_base::FaviconID icon_id = id_and_mappings_pair.first;
+ const IconMappingsForExpiry& mappings = id_and_mappings_pair.second;
+
+ if (backend_client_ &&
+ IsAnyURLBookmarked(backend_client_, mappings.page_urls)) {
+ continue;
+ }
+
+ thumb_db_->DeleteFavicon(icon_id);
+ thumb_db_->DeleteIconMappingsForFaviconId(icon_id);
+ effects.deleted_favicons.insert(mappings.icon_url);
+ }
+
+ BroadcastNotifications(&effects, DELETION_EXPIRED);
+}
+
bool ExpireHistoryBackend::ExpireSomeOldHistory(
base::Time end_time,
const ExpiringVisitsReader* reader,
diff --git a/chromium/components/history/core/browser/expire_history_backend.h b/chromium/components/history/core/browser/expire_history_backend.h
index ebffc5b62e4..f47666e4dd6 100644
--- a/chromium/components/history/core/browser/expire_history_backend.h
+++ b/chromium/components/history/core/browser/expire_history_backend.h
@@ -20,6 +20,7 @@ class GURL;
class TestingProfile;
namespace base {
+struct Feature;
class SequencedTaskRunner;
}
@@ -42,6 +43,11 @@ class ExpiringVisitsReader {
typedef std::vector<const ExpiringVisitsReader*> ExpiringVisitsReaders;
+namespace internal {
+// Feature that enables clearing old on-demand favicons.
+extern const base::Feature kClearOldOnDemandFavicons;
+} // namespace internal
+
// Helper component to HistoryBackend that manages expiration and deleting of
// history.
//
@@ -102,6 +108,16 @@ class ExpireHistoryBackend {
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistory);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistoryWithSource);
+ FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
+ ClearOldOnDemandFaviconsDoesNotDeleteStarred);
+ FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
+ ClearOldOnDemandFaviconsDoesDeleteUnstarred);
+ FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
+ ClearOldOnDemandFaviconsDoesDeleteAfterLongDelay);
+ FRIEND_TEST_ALL_PREFIXES(
+ ExpireHistoryTest,
+ ClearOldOnDemandFaviconsDoesNotDeleteAfterShortDelay);
+
friend class ::TestingProfile;
struct DeleteEffects {
@@ -206,6 +222,9 @@ class ExpireHistoryBackend {
// future.
void DoExpireIteration();
+ // Clears all old on-demand favicons from thumbnail database.
+ void ClearOldOnDemandFavicons(base::Time expiration_threshold);
+
// Tries to expire the oldest |max_visits| visits from history that are older
// than |time_threshold|. The return value indicates if we think there might
// be more history to expire with the current time threshold (it does not
@@ -240,6 +259,9 @@ class ExpireHistoryBackend {
// The threshold for "old" history where we will automatically delete it.
base::TimeDelta expiration_threshold_;
+ // The lastly used threshold for "old" on-demand favicons.
+ base::Time last_on_demand_expiration_threshold_;
+
// List of all distinct types of readers. This list is used to populate the
// work queue.
ExpiringVisitsReaders readers_;
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 0a554fa8895..be6bc13ac33 100644
--- a/chromium/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
@@ -16,10 +16,12 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "components/history/core/browser/history_backend_client.h"
#include "components/history/core/browser/history_backend_notifier.h"
@@ -891,6 +893,151 @@ TEST_F(ExpireHistoryTest, ExpiringVisitsReader) {
EXPECT_EQ(1U, visits.size());
}
+// Test that ClearOldOnDemandFavicons() deletes favicons associated only to
+// unstarred page URLs.
+TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteUnstarred) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
+
+ // The blob does not encode any real bitmap, obviously.
+ const unsigned char kBlob[] = "0";
+ scoped_refptr<base::RefCountedBytes> favicon(
+ new base::RefCountedBytes(kBlob, sizeof(kBlob)));
+
+ // Icon: old and not bookmarked case.
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon_id = thumb_db_->AddFavicon(
+ url, favicon_base::FAVICON, favicon, FaviconBitmapType::ON_DEMAND,
+ base::Time::Now() - base::TimeDelta::FromDays(100), gfx::Size());
+ ASSERT_NE(0, icon_id);
+ GURL page_url("http://google.com/");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url, icon_id));
+
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(90));
+
+ // The icon gets deleted.
+ EXPECT_FALSE(thumb_db_->GetIconMappingsForPageURL(page_url, nullptr));
+ EXPECT_FALSE(thumb_db_->GetFaviconHeader(icon_id, nullptr, nullptr));
+ EXPECT_FALSE(thumb_db_->GetFaviconBitmaps(icon_id, nullptr));
+}
+
+// Test that ClearOldOnDemandFavicons() deletes favicons associated to at least
+// one starred page URL.
+TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesNotDeleteStarred) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
+
+ // The blob does not encode any real bitmap, obviously.
+ const unsigned char kBlob[] = "0";
+ scoped_refptr<base::RefCountedBytes> favicon(
+ new base::RefCountedBytes(kBlob, sizeof(kBlob)));
+
+ // Icon: old but bookmarked case.
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon_id = thumb_db_->AddFavicon(
+ url, favicon_base::FAVICON, favicon, FaviconBitmapType::ON_DEMAND,
+ base::Time::Now() - base::TimeDelta::FromDays(100), gfx::Size());
+ ASSERT_NE(0, icon_id);
+ GURL page_url1("http://google.com/1");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url1, icon_id));
+ StarURL(page_url1);
+ GURL page_url2("http://google.com/2");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url2, icon_id));
+
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(90));
+
+ // Nothing gets deleted.
+ EXPECT_TRUE(thumb_db_->GetFaviconHeader(icon_id, nullptr, nullptr));
+ std::vector<FaviconBitmap> favicon_bitmaps;
+ EXPECT_TRUE(thumb_db_->GetFaviconBitmaps(icon_id, &favicon_bitmaps));
+ EXPECT_EQ(1u, favicon_bitmaps.size());
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(thumb_db_->GetIconMappingsForPageURL(page_url1, &icon_mapping));
+ EXPECT_TRUE(thumb_db_->GetIconMappingsForPageURL(page_url2, &icon_mapping));
+ EXPECT_EQ(2u, icon_mapping.size());
+ EXPECT_EQ(icon_id, icon_mapping[0].icon_id);
+ EXPECT_EQ(icon_id, icon_mapping[1].icon_id);
+}
+
+// Test that ClearOldOnDemandFavicons() has effect if the last clearing was long
+// time age (such as 2 days ago).
+TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteAfterLongDelay) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
+
+ // Previous clearing (2 days ago).
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(92));
+
+ // The blob does not encode any real bitmap, obviously.
+ const unsigned char kBlob[] = "0";
+ scoped_refptr<base::RefCountedBytes> favicon(
+ new base::RefCountedBytes(kBlob, sizeof(kBlob)));
+
+ // Icon: old and not bookmarked case.
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon_id = thumb_db_->AddFavicon(
+ url, favicon_base::FAVICON, favicon, FaviconBitmapType::ON_DEMAND,
+ base::Time::Now() - base::TimeDelta::FromDays(100), gfx::Size());
+ ASSERT_NE(0, icon_id);
+ GURL page_url("http://google.com/");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url, icon_id));
+
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(90));
+
+ // The icon gets deleted.
+ EXPECT_FALSE(thumb_db_->GetIconMappingsForPageURL(page_url, nullptr));
+ EXPECT_FALSE(thumb_db_->GetFaviconHeader(icon_id, nullptr, nullptr));
+ EXPECT_FALSE(thumb_db_->GetFaviconBitmaps(icon_id, nullptr));
+}
+
+// Test that ClearOldOnDemandFavicons() deletes favicons associated to at least
+// one starred page URL.
+TEST_F(ExpireHistoryTest,
+ ClearOldOnDemandFaviconsDoesNotDeleteAfterShortDelay) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
+
+ // Previous clearing (5 minutes ago).
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(90) -
+ base::TimeDelta::FromMinutes(5));
+
+ // The blob does not encode any real bitmap, obviously.
+ const unsigned char kBlob[] = "0";
+ scoped_refptr<base::RefCountedBytes> favicon(
+ new base::RefCountedBytes(kBlob, sizeof(kBlob)));
+
+ // Icon: old but bookmarked case.
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon_id = thumb_db_->AddFavicon(
+ url, favicon_base::FAVICON, favicon, FaviconBitmapType::ON_DEMAND,
+ base::Time::Now() - base::TimeDelta::FromDays(100), gfx::Size());
+ ASSERT_NE(0, icon_id);
+ GURL page_url1("http://google.com/1");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url1, icon_id));
+ GURL page_url2("http://google.com/2");
+ ASSERT_NE(0, thumb_db_->AddIconMapping(page_url2, icon_id));
+
+ expirer_.ClearOldOnDemandFavicons(base::Time::Now() -
+ base::TimeDelta::FromDays(90));
+
+ // Nothing gets deleted.
+ EXPECT_TRUE(thumb_db_->GetFaviconHeader(icon_id, nullptr, nullptr));
+ std::vector<FaviconBitmap> favicon_bitmaps;
+ EXPECT_TRUE(thumb_db_->GetFaviconBitmaps(icon_id, &favicon_bitmaps));
+ EXPECT_EQ(1u, favicon_bitmaps.size());
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(thumb_db_->GetIconMappingsForPageURL(page_url1, &icon_mapping));
+ EXPECT_TRUE(thumb_db_->GetIconMappingsForPageURL(page_url2, &icon_mapping));
+ EXPECT_EQ(2u, icon_mapping.size());
+ EXPECT_EQ(icon_id, icon_mapping[0].icon_id);
+ EXPECT_EQ(icon_id, icon_mapping[1].icon_id);
+}
+
// TODO(brettw) add some visits with no URL to make sure everything is updated
// properly. Have the visits also refer to nonexistent FTS rows.
//
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index bd7d01dc097..dec7e10fc08 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -516,6 +516,15 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
ui::PageTransition redirect_info = ui::PAGE_TRANSITION_CHAIN_START;
RedirectList redirects = request.redirects;
+ // In the presence of client redirects, |request.redirects| can be a partial
+ // chain because previous calls to this function may have reported a
+ // redirect chain already. This is fine for the visits database where we'll
+ // just append data but insufficient for |recent_redirects_|
+ // (backpropagation of favicons and titles), where we'd like the full
+ // (extended) redirect chain. We use |extended_redirect_chain| to represent
+ // this.
+ RedirectList extended_redirect_chain;
+
if (redirects[0].SchemeIs(url::kAboutScheme)) {
// When the redirect source + referrer is "about" we skip it. This
// happens when a page opens a new frame/window to about:blank and then
@@ -554,6 +563,8 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
visit_row.transition & ~ui::PAGE_TRANSITION_CHAIN_END);
db_->UpdateVisitRow(visit_row);
}
+
+ GetCachedRecentRedirects(request.referrer, &extended_redirect_chain);
}
}
@@ -588,8 +599,12 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
}
// Last, save this redirect chain for later so we can set titles & favicons
- // on the redirected pages properly.
- recent_redirects_.Put(request.url, redirects);
+ // on the redirected pages properly. For this we use the extended redirect
+ // chain, which includes URLs from chained redirects.
+ extended_redirect_chain.insert(extended_redirect_chain.end(),
+ std::make_move_iterator(redirects.begin()),
+ std::make_move_iterator(redirects.end()));
+ recent_redirects_.Put(request.url, extended_redirect_chain);
}
// TODO(brettw) bug 1140015: Add an "add page" notification so the history
@@ -1042,6 +1057,12 @@ bool HistoryBackend::GetURL(const GURL& url, URLRow* url_row) {
return false;
}
+bool HistoryBackend::GetURLByID(URLID url_id, URLRow* url_row) {
+ if (db_)
+ return db_->GetURLRow(url_id, url_row);
+ return false;
+}
+
void HistoryBackend::QueryURL(const GURL& url,
bool want_visits,
QueryURLResult* result) {
@@ -1432,8 +1453,8 @@ void HistoryBackend::GetFavicon(
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
- UpdateFaviconMappingsAndFetchImpl(nullptr, icon_url, icon_type, desired_sizes,
- bitmap_results);
+ UpdateFaviconMappingsAndFetchImpl(std::set<GURL>(), icon_url, icon_type,
+ desired_sizes, bitmap_results);
}
void HistoryBackend::GetLargestFaviconForURL(
@@ -1564,12 +1585,12 @@ void HistoryBackend::GetFaviconForID(
}
void HistoryBackend::UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
- UpdateFaviconMappingsAndFetchImpl(&page_url, icon_url, icon_type,
+ UpdateFaviconMappingsAndFetchImpl(page_urls, icon_url, icon_type,
desired_sizes, bitmap_results);
}
@@ -1885,7 +1906,7 @@ bool HistoryBackend::SetFaviconsImpl(const GURL& page_url,
}
void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
- const GURL* page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
@@ -1903,12 +1924,14 @@ void HistoryBackend::UpdateFaviconMappingsAndFetchImpl(
if (favicon_id)
favicon_ids.push_back(favicon_id);
- if (page_url && !favicon_ids.empty()) {
- bool mappings_updated = SetFaviconMappingsForPageAndRedirects(
- *page_url, icon_type, favicon_ids);
- if (mappings_updated) {
- SendFaviconChangedNotificationForPageAndRedirects(*page_url);
- ScheduleCommit();
+ if (!favicon_ids.empty()) {
+ for (const GURL& page_url : page_urls) {
+ bool mappings_updated = SetFaviconMappingsForPageAndRedirects(
+ page_url, icon_type, favicon_ids);
+ if (mappings_updated) {
+ SendFaviconChangedNotificationForPageAndRedirects(page_url);
+ ScheduleCommit();
+ }
}
}
@@ -2105,6 +2128,8 @@ bool HistoryBackend::SetFaviconMappingsForPageAndRedirects(
if (page_url.has_ref()) {
// Refs often gets added by Javascript, but the redirect chain is keyed to
// the URL without a ref.
+ // TODO(crbug.com/746268): This can cause orphan favicons, i.e. without a
+ // matching history URL, which will never be cleaned up by the expirer.
GURL::Replacements replacements;
replacements.ClearRef();
GURL page_url_without_ref = page_url.ReplaceComponents(replacements);
diff --git a/chromium/components/history/core/browser/history_backend.h b/chromium/components/history/core/browser/history_backend.h
index 85c5fb83f05..1a698364b8c 100644
--- a/chromium/components/history/core/browser/history_backend.h
+++ b/chromium/components/history/core/browser/history_backend.h
@@ -309,7 +309,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results);
void UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
@@ -399,6 +399,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual bool GetURL(const GURL& url, URLRow* url_row);
+ bool GetURLByID(URLID url_id, URLRow* url_row);
+
// Returns the syncable service for syncing typed urls. The returned service
// is owned by |this| object.
virtual TypedUrlSyncableService* GetTypedUrlSyncableService() const;
@@ -525,6 +527,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
SetFaviconMappingsForPageAndRedirectsWithFragment);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
+ RecentRedirectsForClientRedirects);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
SetFaviconMappingsForPageDuplicates);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetFaviconsDeleteBitmaps);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetFaviconsReplaceBitmapData);
@@ -689,11 +693,11 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FaviconBitmapType type);
// Used by both UpdateFaviconMappingsAndFetch() and GetFavicon().
- // If |page_url| is non-null and there is a favicon stored in the database
- // for |icon_url|, a mapping is added to the database from |page_url| (and all
- // redirects) to |icon_url|.
+ // If there is a favicon stored in the database for |icon_url|, a mapping is
+ // added to the database from each element in |page_urls| (and all redirects)
+ // to |icon_url|.
void UpdateFaviconMappingsAndFetchImpl(
- const GURL* page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
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 939e1c874d8..53e128ee7c9 100644
--- a/chromium/components/history/core/browser/history_backend_db_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_db_unittest.cc
@@ -533,13 +533,13 @@ bool IsValidRFC4122Ver4GUID(const std::string& guid) {
// => guid[14] == '4'
//
// * Bits 6-7 of clk_seq_hi_res should be set to 0b10
- // => guid[19] in {'8','9','A','B'}
+ // => guid[19] in {'8','9','A','B','a','b'}
//
// * All other bits should be random or pseudo random.
// => http://dilbert.com/strip/2001-10-25
return base::IsValidGUID(guid) && guid[14] == '4' &&
(guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' ||
- guid[19] == 'B');
+ guid[19] == 'B' || guid[19] == 'a' || guid[19] == 'b');
}
TEST_F(HistoryBackendDBTest, MigrateHashHttpMethodAndGenerateGuids) {
@@ -608,7 +608,6 @@ TEST_F(HistoryBackendDBTest, MigrateHashHttpMethodAndGenerateGuids) {
std::string guid = s.ColumnString(0);
uint32_t id = static_cast<uint32_t>(s.ColumnInt64(1));
EXPECT_TRUE(IsValidRFC4122Ver4GUID(guid));
- EXPECT_EQ(guid, base::ToUpperASCII(guid));
// Id is used as time_low in RFC 4122 to guarantee unique GUIDs
EXPECT_EQ(guid.substr(0, 8), base::StringPrintf("%08" PRIX32, id));
guids.insert(guid);
diff --git a/chromium/components/history/core/browser/history_backend_unittest.cc b/chromium/components/history/core/browser/history_backend_unittest.cc
index c92e97e4d24..79b79003ad1 100644
--- a/chromium/components/history/core/browser/history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_unittest.cc
@@ -367,8 +367,8 @@ class HistoryBackendTest : public HistoryBackendTestBase {
// |did_replace| is true if the transition is non-user initiated and the
// navigation entry for |url2| has replaced that for |url1|. The possibly
// updated transition code of the visit records for |url1| and |url2| is
- // returned by filling in |*transition1| and |*transition2|, respectively.
- // |time| is a time of the redirect.
+ // returned by filling in |*transition1| and |*transition2|, respectively,
+ // unless null. |time| is a time of the redirect.
void AddClientRedirect(const GURL& url1,
const GURL& url2,
bool did_replace,
@@ -387,8 +387,11 @@ class HistoryBackendTest : public HistoryBackendTestBase {
history::SOURCE_BROWSED, did_replace, true);
backend_->AddPage(request);
- *transition1 = GetTransition(url1);
- *transition2 = GetTransition(url2);
+ if (transition1)
+ *transition1 = GetTransition(url1);
+
+ if (transition2)
+ *transition2 = GetTransition(url2);
}
int GetTransition(const GURL& url) {
@@ -1808,7 +1811,6 @@ TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirects) {
EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, favicon_base::FAVICON));
}
-
// Test that SetFaviconMappingsForPageAndRedirects correctly updates icon
// mappings when the final URL has a fragment.
TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirectsWithFragment) {
@@ -1868,6 +1870,31 @@ TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirectsWithFragment) {
EXPECT_EQ(1u, NumIconMappingsForPageURL(url3, favicon_base::FAVICON));
}
+// Test that |recent_redirects_| stores the full redirect chain in case of
+// client redirects. In this case, a server-side redirect is followed by a
+// client-side one.
+TEST_F(HistoryBackendTest, RecentRedirectsForClientRedirects) {
+ GURL server_redirect_url("http://google.com/a");
+ GURL client_redirect_url("http://google.com/b");
+ GURL landing_url("http://google.com/c");
+
+ // Page A is browsed by user and server redirects to B.
+ HistoryAddPageArgs request(
+ client_redirect_url, base::Time::Now(), NULL, 0, GURL(),
+ /*redirects=*/{server_redirect_url, client_redirect_url},
+ ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false, true);
+ backend_->AddPage(request);
+
+ // Client redirect to page C.
+ AddClientRedirect(client_redirect_url, landing_url, /*did_replace=*/false,
+ base::Time(), /*transition1=*/nullptr,
+ /*transition2=*/nullptr);
+
+ EXPECT_THAT(
+ backend_->recent_redirects_.Get(landing_url)->second,
+ ElementsAre(server_redirect_url, client_redirect_url, landing_url));
+}
+
// Test that there is no churn in icon mappings from calling
// SetFavicons() twice with the same |bitmaps| parameter.
TEST_F(HistoryBackendTest, SetFaviconMappingsForPageDuplicates) {
@@ -2022,8 +2049,8 @@ TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) {
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
backend_->UpdateFaviconMappingsAndFetch(
- page_url2, icon_url, favicon_base::FAVICON, GetEdgeSizesSmallAndLarge(),
- &bitmap_results);
+ std::set<GURL>{page_url2}, icon_url, favicon_base::FAVICON,
+ GetEdgeSizesSmallAndLarge(), &bitmap_results);
// Check that the same FaviconID is mapped to both page URLs.
std::vector<IconMapping> icon_mappings;
@@ -2587,23 +2614,23 @@ TEST_F(HistoryBackendTest, FaviconChangedNotificationIconMappingChanged) {
// favicon at |icon_url1|.
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
backend_->UpdateFaviconMappingsAndFetch(
- page_url3, icon_url1, favicon_base::FAVICON,
+ std::set<GURL>{page_url3}, icon_url1, favicon_base::FAVICON,
GetEdgeSizesSmallAndLarge(), &bitmap_results);
ClearBroadcastedNotifications();
}
// SetFavicons()
backend_->SetFavicons(page_url1, favicon_base::FAVICON, icon_url2, bitmaps);
- ASSERT_EQ(1u, favicon_changed_notifications_page_urls().size());
- EXPECT_EQ(page_url1, favicon_changed_notifications_page_urls()[0]);
+ EXPECT_THAT(favicon_changed_notifications_page_urls(),
+ ElementsAre(page_url1));
EXPECT_EQ(0u, favicon_changed_notifications_icon_urls().size());
ClearBroadcastedNotifications();
// MergeFavicon()
backend_->MergeFavicon(page_url1, icon_url1, favicon_base::FAVICON,
new base::RefCountedBytes(png_bytes), kSmallSize);
- ASSERT_EQ(1u, favicon_changed_notifications_page_urls().size());
- EXPECT_EQ(page_url1, favicon_changed_notifications_page_urls()[0]);
+ EXPECT_THAT(favicon_changed_notifications_page_urls(),
+ ElementsAre(page_url1));
EXPECT_EQ(0u, favicon_changed_notifications_icon_urls().size());
ClearBroadcastedNotifications();
@@ -2611,14 +2638,61 @@ TEST_F(HistoryBackendTest, FaviconChangedNotificationIconMappingChanged) {
{
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
backend_->UpdateFaviconMappingsAndFetch(
- page_url1, icon_url2, favicon_base::FAVICON,
+ std::set<GURL>{page_url1}, icon_url2, favicon_base::FAVICON,
GetEdgeSizesSmallAndLarge(), &bitmap_results);
- ASSERT_EQ(1u, favicon_changed_notifications_page_urls().size());
- EXPECT_EQ(page_url1, favicon_changed_notifications_page_urls()[0]);
+ EXPECT_THAT(favicon_changed_notifications_page_urls(),
+ ElementsAre(page_url1));
EXPECT_EQ(0u, favicon_changed_notifications_icon_urls().size());
}
}
+// Test that changing the page URL -> icon URL mapping for multiple page URLs
+// sends notifications that the favicon for each page URL has changed.
+TEST_F(HistoryBackendTest,
+ FaviconChangedNotificationIconMappingChangedForMultiplePages) {
+ GURL page_url1("http://www.google.com/a");
+ GURL page_url2("http://www.google.com/b");
+ GURL page_url3("http://www.google.com/c");
+ GURL page_url4("http://www.google.com/d");
+ GURL icon_url("http://www.google.com/favicon.ico");
+
+ SkBitmap bitmap(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize));
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.push_back(bitmap);
+ std::vector<unsigned char> png_bytes;
+ ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_bytes));
+
+ // Setup
+ {
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize));
+ backend_->SetFavicons(page_url4, favicon_base::FAVICON, icon_url, bitmaps);
+ ClearBroadcastedNotifications();
+ }
+
+ // UpdateFaviconMappingsAndFetch() for two page URLs.
+ {
+ std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
+ backend_->UpdateFaviconMappingsAndFetch(
+ {page_url1, page_url2}, icon_url, favicon_base::FAVICON,
+ GetEdgeSizesSmallAndLarge(), &bitmap_results);
+ EXPECT_THAT(favicon_changed_notifications_page_urls(),
+ ElementsAre(page_url1, page_url2));
+ ClearBroadcastedNotifications();
+ }
+
+ // UpdateFaviconMappingsAndFetch() for two page URLs, but only one needs an
+ // update.
+ {
+ std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
+ backend_->UpdateFaviconMappingsAndFetch(
+ {page_url3, page_url4}, icon_url, favicon_base::FAVICON,
+ GetEdgeSizesSmallAndLarge(), &bitmap_results);
+ EXPECT_THAT(favicon_changed_notifications_page_urls(),
+ ElementsAre(page_url3));
+ }
+}
+
// Test that changing both:
// - The page URL -> icon URL mapping
// - The favicon's bitmap data
@@ -2643,7 +2717,7 @@ TEST_F(HistoryBackendTest,
// favicon at |icon_url1|.
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
backend_->UpdateFaviconMappingsAndFetch(
- page_url3, icon_url1, favicon_base::FAVICON,
+ std::set<GURL>{page_url3}, icon_url1, favicon_base::FAVICON,
GetEdgeSizesSmallAndLarge(), &bitmap_results);
ClearBroadcastedNotifications();
}
@@ -2790,8 +2864,8 @@ TEST_F(HistoryBackendTest, NoFaviconChangedNotifications) {
{
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
backend_->UpdateFaviconMappingsAndFetch(
- page_url, icon_url, favicon_base::FAVICON, GetEdgeSizesSmallAndLarge(),
- &bitmap_results);
+ std::set<GURL>{page_url}, icon_url, favicon_base::FAVICON,
+ GetEdgeSizesSmallAndLarge(), &bitmap_results);
}
EXPECT_EQ(0u, favicon_changed_notifications_page_urls().size());
@@ -3067,9 +3141,9 @@ TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) {
std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
- backend_->UpdateFaviconMappingsAndFetch(GURL(), GURL(), favicon_base::FAVICON,
- GetEdgeSizesSmallAndLarge(),
- &bitmap_results);
+ backend_->UpdateFaviconMappingsAndFetch(
+ std::set<GURL>{GURL()}, GURL(), favicon_base::FAVICON,
+ GetEdgeSizesSmallAndLarge(), &bitmap_results);
EXPECT_TRUE(bitmap_results.empty());
}
diff --git a/chromium/components/history/core/browser/history_querying_unittest.cc b/chromium/components/history/core/browser/history_querying_unittest.cc
index da3a53633e4..fede4e3f9e6 100644
--- a/chromium/components/history/core/browser/history_querying_unittest.cc
+++ b/chromium/components/history/core/browser/history_querying_unittest.cc
@@ -192,8 +192,8 @@ class HistoryQueryTest : public testing::Test {
void QueryHistoryComplete(QueryResults* results) {
results->Swap(&last_query_results_);
- base::MessageLoop::current()
- ->QuitWhenIdle(); // Will return out to QueryHistory.
+ // Will return out to QueryHistory.
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
base::ScopedTempDir temp_dir_;
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index 6e8b789018b..982a8b1f455 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -574,7 +574,7 @@ base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
base::CancelableTaskTracker::TaskId
HistoryService::UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
@@ -588,8 +588,8 @@ HistoryService::UpdateFaviconMappingsAndFetch(
return tracker->PostTaskAndReply(
backend_task_runner_.get(), FROM_HERE,
base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
- history_backend_, page_url, icon_url, icon_type, desired_sizes,
- results),
+ history_backend_, page_urls, icon_url, icon_type,
+ desired_sizes, results),
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
diff --git a/chromium/components/history/core/browser/history_service.h b/chromium/components/history/core/browser/history_service.h
index 710ac708a86..140bbd353af 100644
--- a/chromium/components/history/core/browser/history_service.h
+++ b/chromium/components/history/core/browser/history_service.h
@@ -700,14 +700,14 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker);
- // Maps |page_url| to the favicon at |icon_url| if there is an entry in the
+ // Maps |page_urls| to the favicon at |icon_url| if there is an entry in the
// database for |icon_url| and |icon_type|. This occurs when there is a
// mapping from a different page URL to |icon_url|. The favicon bitmaps whose
// edge sizes most closely match |desired_sizes| from the favicons which were
- // just mapped to |page_url| are returned. If |desired_sizes| has a '0' entry,
- // the largest favicon bitmap is returned.
+ // just mapped to |page_urls| are returned. If |desired_sizes| has a '0'
+ // entry, the largest favicon bitmap is returned.
base::CancelableTaskTracker::TaskId UpdateFaviconMappingsAndFetch(
- const GURL& page_url,
+ const std::set<GURL>& page_urls,
const GURL& icon_url,
favicon_base::IconType icon_type,
const std::vector<int>& desired_sizes,
diff --git a/chromium/components/history/core/browser/history_service_unittest.cc b/chromium/components/history/core/browser/history_service_unittest.cc
index 29ac63f24d0..6e05213879c 100644
--- a/chromium/components/history/core/browser/history_service_unittest.cc
+++ b/chromium/components/history/core/browser/history_service_unittest.cc
@@ -61,7 +61,7 @@ class HistoryServiceTest : public testing::Test {
void OnMostVisitedURLsAvailable(const MostVisitedURLList* url_list) {
most_visited_urls_ = *url_list;
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
protected:
@@ -132,7 +132,7 @@ class HistoryServiceTest : public testing::Test {
query_url_row_ = URLRow();
query_url_visits_.clear();
}
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
// Fills in saved_redirects_ with the redirect information for the given URL,
@@ -153,7 +153,7 @@ class HistoryServiceTest : public testing::Test {
saved_redirects_.insert(
saved_redirects_.end(), redirects->begin(), redirects->end());
}
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
base::ScopedTempDir temp_dir_;
@@ -614,7 +614,7 @@ class HistoryDBTaskImpl : public HistoryDBTask {
void DoneRunOnMainThread() override {
*done_invoked_ = true;
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
int* invoke_count_;
diff --git a/chromium/components/history/core/browser/history_types.cc b/chromium/components/history/core/browser/history_types.cc
index 1624e636b2a..7365619b0a8 100644
--- a/chromium/components/history/core/browser/history_types.cc
+++ b/chromium/components/history/core/browser/history_types.cc
@@ -299,6 +299,15 @@ FaviconBitmapIDSize::FaviconBitmapIDSize() {}
FaviconBitmapIDSize::~FaviconBitmapIDSize() {}
+// IconMappingsForExpiry ------------------------------------------------------
+
+IconMappingsForExpiry::IconMappingsForExpiry() {}
+
+IconMappingsForExpiry::IconMappingsForExpiry(
+ const IconMappingsForExpiry& other) = default;
+
+IconMappingsForExpiry::~IconMappingsForExpiry() {}
+
// FaviconBitmap --------------------------------------------------------------
FaviconBitmap::FaviconBitmap() {}
diff --git a/chromium/components/history/core/browser/history_types.h b/chromium/components/history/core/browser/history_types.h
index 17b97b4a038..00b6cb00aa8 100644
--- a/chromium/components/history/core/browser/history_types.h
+++ b/chromium/components/history/core/browser/history_types.h
@@ -524,6 +524,18 @@ enum FaviconBitmapType {
ON_DEMAND
};
+// Defines all associated mappings of a given favicon.
+struct IconMappingsForExpiry {
+ IconMappingsForExpiry();
+ IconMappingsForExpiry(const IconMappingsForExpiry& other);
+ ~IconMappingsForExpiry();
+
+ // URL of a given favicon.
+ GURL icon_url;
+ // URLs of all pages mapped to a given favicon
+ std::vector<GURL> page_urls;
+};
+
// Defines a favicon bitmap stored in the history backend.
struct FaviconBitmap {
FaviconBitmap();
diff --git a/chromium/components/history/core/browser/thumbnail_database.cc b/chromium/components/history/core/browser/thumbnail_database.cc
index c8b430f4f71..d452bd5d744 100644
--- a/chromium/components/history/core/browser/thumbnail_database.cc
+++ b/chromium/components/history/core/browser/thumbnail_database.cc
@@ -412,11 +412,42 @@ void ThumbnailDatabase::TrimMemory(bool aggressively) {
db_.TrimMemory(aggressively);
}
+std::map<favicon_base::FaviconID, IconMappingsForExpiry>
+ThumbnailDatabase::GetOldOnDemandFavicons(base::Time threshold) {
+ // Restrict to on-demand bitmaps (i.e. with last_requested != 0). This is
+ // called rarely during history expiration cleanup and hence not worth
+ // caching.
+ // TODO(jkrcal): In M63, remove the "(last_requested=0 AND last_updated=0)"
+ // clause which is only transitional - to clean up expired icons (previously,
+ // on-demand favicons were stored as expired on-visit favicons).
+ sql::Statement old_icons(db_.GetUniqueStatement(
+ "SELECT favicons.id, favicons.url, icon_mapping.page_url "
+ "FROM favicons "
+ "JOIN favicon_bitmaps ON (favicon_bitmaps.icon_id = favicons.id) "
+ "JOIN icon_mapping ON (icon_mapping.icon_id = favicon_bitmaps.icon_id) "
+ "WHERE ((favicon_bitmaps.last_requested = 0 AND "
+ " favicon_bitmaps.last_updated = 0) OR "
+ " (favicon_bitmaps.last_requested > 0 AND "
+ " favicon_bitmaps.last_requested < ?))"));
+ old_icons.BindInt64(0, threshold.ToInternalValue());
+
+ std::map<favicon_base::FaviconID, IconMappingsForExpiry> icon_mappings;
+
+ while (old_icons.Step()) {
+ favicon_base::FaviconID id = old_icons.ColumnInt64(0);
+ icon_mappings[id].icon_url = GURL(old_icons.ColumnString(1));
+ icon_mappings[id].page_urls.push_back(GURL(old_icons.ColumnString(2)));
+ }
+
+ return icon_mappings;
+}
+
bool ThumbnailDatabase::GetFaviconBitmapIDSizes(
favicon_base::FaviconID icon_id,
std::vector<FaviconBitmapIDSize>* bitmap_id_sizes) {
DCHECK(icon_id);
- sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ sql::Statement statement(db_.GetCachedStatement(
+ SQL_FROM_HERE,
"SELECT id, width, height FROM favicon_bitmaps WHERE icon_id=?"));
statement.BindInt64(0, icon_id);
@@ -778,6 +809,16 @@ bool ThumbnailDatabase::DeleteIconMappings(const GURL& page_url) {
return statement.Run();
}
+bool ThumbnailDatabase::DeleteIconMappingsForFaviconId(
+ favicon_base::FaviconID id) {
+ // This is called rarely during history expiration cleanup and hence not
+ // worth caching.
+ sql::Statement statement(
+ db_.GetUniqueStatement("DELETE FROM icon_mapping WHERE icon_id=?"));
+ statement.BindInt64(0, id);
+ return statement.Run();
+}
+
bool ThumbnailDatabase::DeleteIconMapping(IconMappingID mapping_id) {
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM icon_mapping WHERE id=?"));
diff --git a/chromium/components/history/core/browser/thumbnail_database.h b/chromium/components/history/core/browser/thumbnail_database.h
index 697faf3abec..f9ba1c71de4 100644
--- a/chromium/components/history/core/browser/thumbnail_database.h
+++ b/chromium/components/history/core/browser/thumbnail_database.h
@@ -66,6 +66,11 @@ class ThumbnailDatabase {
// true try to trim all unused cache, otherwise trim by half.
void TrimMemory(bool aggressively);
+ // Get all on-demand favicon bitmaps that have been last requested prior to
+ // |threshold|.
+ std::map<favicon_base::FaviconID, IconMappingsForExpiry>
+ GetOldOnDemandFavicons(base::Time threshold);
+
// Favicon Bitmaps -----------------------------------------------------------
// Returns true if there are favicon bitmaps for |icon_id|. If
@@ -200,6 +205,10 @@ class ThumbnailDatabase {
// Returns true if the deletion succeeded.
bool DeleteIconMappings(const GURL& page_url);
+ // Deletes the icon mapping entries for the given favicon ID.
+ // Returns true if the deletion succeeded.
+ bool DeleteIconMappingsForFaviconId(favicon_base::FaviconID id);
+
// Deletes the icon mapping with |mapping_id|.
// Returns true if the deletion succeeded.
bool DeleteIconMapping(IconMappingID mapping_id);
diff --git a/chromium/components/history/core/browser/thumbnail_database_unittest.cc b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
index 4dbd0c6f64e..ffbf876080c 100644
--- a/chromium/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
@@ -12,16 +12,25 @@
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "components/history/core/browser/thumbnail_database.h"
#include "components/history/core/test/database_test_utils.h"
#include "sql/connection.h"
#include "sql/recovery.h"
#include "sql/test/scoped_error_expecter.h"
#include "sql/test/test_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
#include "url/gurl.h"
+using testing::AllOf;
+using testing::ElementsAre;
+using testing::Field;
+using testing::Pair;
+using testing::Return;
+
namespace history {
namespace {
@@ -367,6 +376,127 @@ TEST_F(ThumbnailDatabaseTest, TouchDoesNotUpdateStandardFavicons) {
EXPECT_EQ(base::Time(), last_requested); // No update.
}
+// Test that ThumbnailDatabase::GetOldOnDemandFavicons() returns on-demand icons
+// which were requested prior to the passed in timestamp.
+TEST_F(ThumbnailDatabaseTest, GetOldOnDemandFaviconsReturnsOld) {
+ ThumbnailDatabase db(nullptr);
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+ db.BeginTransaction();
+
+ base::Time start;
+ ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon =
+ db.AddFavicon(url, favicon_base::FAVICON, favicon,
+ FaviconBitmapType::ON_DEMAND, start, gfx::Size());
+ ASSERT_NE(0, icon);
+ // Associate two different URLs with the icon.
+ GURL page_url1("http://google.com/1");
+ ASSERT_NE(0, db.AddIconMapping(page_url1, icon));
+ GURL page_url2("http://google.com/2");
+ ASSERT_NE(0, db.AddIconMapping(page_url2, icon));
+
+ base::Time get_older_than = start + base::TimeDelta::FromSeconds(1);
+ auto map = db.GetOldOnDemandFavicons(get_older_than);
+
+ // The icon is returned.
+ EXPECT_THAT(map, ElementsAre(Pair(
+ icon, AllOf(Field(&IconMappingsForExpiry::icon_url, url),
+ Field(&IconMappingsForExpiry::page_urls,
+ ElementsAre(page_url1, page_url2))))));
+}
+
+// Test that ThumbnailDatabase::GetOldOnDemandFavicons() returns on-visit icons
+// if the on-visit icons have expired. We need this behavior in order to delete
+// icons stored via HistoryService::SetOnDemandFavicons() prior to on-demand
+// icons setting the "last_requested" time.
+TEST_F(ThumbnailDatabaseTest, GetOldOnDemandFaviconsReturnsExpired) {
+ ThumbnailDatabase db(nullptr);
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+ db.BeginTransaction();
+
+ base::Time start;
+ ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon =
+ db.AddFavicon(url, favicon_base::FAVICON, favicon,
+ FaviconBitmapType::ON_VISIT, start, gfx::Size());
+ ASSERT_NE(0, icon);
+ GURL page_url("http://google.com/");
+ ASSERT_NE(0, db.AddIconMapping(page_url, icon));
+ ASSERT_TRUE(db.SetFaviconOutOfDate(icon));
+
+ // The threshold is ignored for expired icons.
+ auto map = db.GetOldOnDemandFavicons(/*threshold=*/base::Time::Now());
+
+ // The icon is returned.
+ EXPECT_THAT(map, ElementsAre(Pair(
+ icon, AllOf(Field(&IconMappingsForExpiry::icon_url, url),
+ Field(&IconMappingsForExpiry::page_urls,
+ ElementsAre(page_url))))));
+}
+
+// Test that ThumbnailDatabase::GetOldOnDemandFavicons() does not return
+// on-demand icons which were requested after the passed in timestamp.
+TEST_F(ThumbnailDatabaseTest, GetOldOnDemandFaviconsDoesNotReturnFresh) {
+ ThumbnailDatabase db(nullptr);
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+ db.BeginTransaction();
+
+ base::Time start;
+ ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+ GURL url("http://google.com/favicon.ico");
+ favicon_base::FaviconID icon =
+ db.AddFavicon(url, favicon_base::FAVICON, favicon,
+ FaviconBitmapType::ON_DEMAND, start, gfx::Size());
+ ASSERT_NE(0, icon);
+ ASSERT_NE(0, db.AddIconMapping(GURL("http://google.com/"), icon));
+
+ // Touch the icon 3 weeks later.
+ base::Time now = start + base::TimeDelta::FromDays(21);
+ EXPECT_TRUE(db.TouchOnDemandFavicon(url, now));
+
+ base::Time get_older_than = start + base::TimeDelta::FromSeconds(1);
+ auto map = db.GetOldOnDemandFavicons(get_older_than);
+
+ // No icon is returned.
+ EXPECT_TRUE(map.empty());
+}
+
+// Test that ThumbnailDatabase::GetOldOnDemandFavicons() does not return
+// non-expired on-visit icons.
+TEST_F(ThumbnailDatabaseTest, GetOldOnDemandFaviconsDoesNotDeleteStandard) {
+ ThumbnailDatabase db(nullptr);
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+ db.BeginTransaction();
+
+ base::Time start;
+ ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+ std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+ scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+ favicon_base::FaviconID icon = db.AddFavicon(
+ GURL("http://google.com/favicon.ico"), favicon_base::FAVICON, favicon,
+ FaviconBitmapType::ON_VISIT, start, gfx::Size());
+ ASSERT_NE(0, icon);
+ ASSERT_NE(0, db.AddIconMapping(GURL("http://google.com/"), icon));
+
+ base::Time get_older_than = start + base::TimeDelta::FromSeconds(1);
+ auto map = db.GetOldOnDemandFavicons(get_older_than);
+
+ // No icon is returned.
+ EXPECT_TRUE(map.empty());
+}
+
TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) {
ThumbnailDatabase db(NULL);
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
diff --git a/chromium/components/history/core/browser/top_sites_backend.cc b/chromium/components/history/core/browser/top_sites_backend.cc
index f343d5b3e3a..aa107e9fc85 100644
--- a/chromium/components/history/core/browser/top_sites_backend.cc
+++ b/chromium/components/history/core/browser/top_sites_backend.cc
@@ -26,7 +26,8 @@ namespace history {
TopSitesBackend::TopSitesBackend()
: db_(new TopSitesDatabase()),
db_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
- {base::TaskPriority::USER_VISIBLE, base::MayBlock()})) {
+ {base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()})) {
DCHECK(db_task_runner_);
}
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge.cc b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
index 150ae7c5058..9a437f71686 100644
--- a/chromium/components/history/core/browser/typed_url_sync_bridge.cc
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
@@ -36,6 +36,14 @@ static const int kMaxTypedUrlVisits = 100;
// RELOAD visits, which will be stripped.
static const int kMaxVisitsToFetch = 1000;
+// This is the threshold at which we start throttling sync updates for typed
+// URLs - any URLs with a typed_count >= this threshold will be throttled.
+static const int kTypedUrlVisitThrottleThreshold = 10;
+
+// This is the multiple we use when throttling sync updates. If the multiple is
+// N, we sync up every Nth update (i.e. when typed_count % N == 0).
+static const int kTypedUrlVisitThrottleMultiple = 10;
+
// Enforce oldest to newest visit order.
static bool CheckVisitOrdering(const VisitVector& visits) {
int64_t previous_visit_time = 0;
@@ -51,14 +59,15 @@ static bool CheckVisitOrdering(const VisitVector& visits) {
}
std::string GetStorageKeyFromURLRow(const URLRow& row) {
+ DCHECK_NE(row.id(), 0);
std::string storage_key(sizeof(row.id()), 0);
base::WriteBigEndian<URLID>(&storage_key[0], row.id());
return storage_key;
}
bool HasTypedUrl(const VisitVector& visits) {
- auto typed_url_visit = std::find_if(
- visits.begin(), visits.end(), [](const history::VisitRow& visit) {
+ auto typed_url_visit =
+ std::find_if(visits.begin(), visits.end(), [](const VisitRow& visit) {
return ui::PageTransitionCoreTypeIs(visit.transition,
ui::PAGE_TRANSITION_TYPED);
});
@@ -98,7 +107,7 @@ base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData(
DCHECK(sequence_checker_.CalledOnValidSequence());
// Create a mapping of all local data by URLID. These will be narrowed down
- // by CreateOrUpdateUrl() to include only the entries different from sync
+ // by MergeURLWithSync() to include only the entries different from sync
// server data.
TypedURLMap new_db_urls;
@@ -111,12 +120,12 @@ base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData(
}
// New sync data organized for different write operations to history backend.
- history::URLRows new_synced_urls;
- history::URLRows updated_synced_urls;
+ URLRows new_synced_urls;
+ URLRows updated_synced_urls;
TypedURLVisitVector new_synced_visits;
// Iterate through entity_data and check for all the urls that
- // sync already knows about. CreateOrUpdateUrl() will remove urls that
+ // sync already knows about. MergeURLWithSync() will remove urls that
// are the same as the synced ones from |new_db_urls|.
for (const EntityChange& entity_change : entity_data) {
DCHECK(entity_change.data().specifics.has_typed_url());
@@ -137,20 +146,14 @@ base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData(
continue;
}
- UpdateUrlFromServer(specifics, &new_db_urls, &local_visit_vectors,
- &new_synced_urls, &new_synced_visits,
- &updated_synced_urls);
+ MergeURLWithSync(specifics, &new_db_urls, &local_visit_vectors,
+ &new_synced_urls, &new_synced_visits,
+ &updated_synced_urls);
}
for (const auto& kv : new_db_urls) {
- if (!HasTypedUrl(local_visit_vectors[kv.first])) {
- // This URL has no TYPED visits, don't sync it
- continue;
- }
- std::string storage_key = GetStorageKeyFromURLRow(kv.second);
- change_processor()->Put(
- storage_key, CreateEntityData(kv.second, local_visit_vectors[kv.first]),
- metadata_change_list.get());
+ SendTypedURLToProcessor(kv.second, local_visit_vectors[kv.first],
+ metadata_change_list.get());
}
base::Optional<ModelError> error = WriteToHistoryBackend(
@@ -165,6 +168,7 @@ base::Optional<ModelError> TypedURLSyncBridge::MergeSyncData(
GetStorageKeyInternal(entity_change.data().specifics.typed_url().url());
if (storage_key.empty()) {
// ignore entity change
+ change_processor()->UntrackEntity(entity_change.data());
} else {
change_processor()->UpdateStorageKey(entity_change.data(), storage_key,
metadata_change_list.get());
@@ -184,20 +188,106 @@ base::Optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
std::unique_ptr<MetadataChangeList> metadata_change_list,
EntityChangeList entity_changes) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- NOTIMPLEMENTED();
+ DCHECK(sync_metadata_database_);
+
+ std::vector<GURL> pending_deleted_urls;
+ TypedURLVisitVector new_synced_visits;
+ VisitVector deleted_visits;
+ URLRows updated_synced_urls;
+ URLRows new_synced_urls;
+
+ for (const EntityChange& entity_change : entity_changes) {
+ if (entity_change.type() == EntityChange::ACTION_DELETE) {
+ URLRow url_row;
+ int64_t url_id = sync_metadata_database_->StorageKeyToURLID(
+ entity_change.storage_key());
+ if (!history_backend_->GetURLByID(url_id, &url_row)) {
+ // Ignoring the case that there is no matching URLRow with URLID
+ // |url_id|.
+ continue;
+ }
+
+ pending_deleted_urls.push_back(url_row.url());
+ continue;
+ }
+
+ DCHECK(entity_change.data().specifics.has_typed_url());
+ const TypedUrlSpecifics& specifics =
+ entity_change.data().specifics.typed_url();
+
+ GURL url(specifics.url());
+
+ if (ShouldIgnoreUrl(url))
+ continue;
+
+ DCHECK(specifics.visits_size());
+ sync_pb::TypedUrlSpecifics filtered_url = FilterExpiredVisits(specifics);
+ if (filtered_url.visits_size() == 0)
+ continue;
+
+ UpdateFromSync(filtered_url, &new_synced_visits, &deleted_visits,
+ &updated_synced_urls, &new_synced_urls);
+ }
+
+ WriteToHistoryBackend(&new_synced_urls, &updated_synced_urls,
+ &pending_deleted_urls, &new_synced_visits,
+ &deleted_visits);
+
+ // New entities were either ignored or written to history DB and assigned a
+ // storage key. Notify processor about updated storage keys.
+ for (const EntityChange& entity_change : entity_changes) {
+ if (entity_change.type() == EntityChange::ACTION_ADD) {
+ std::string storage_key = GetStorageKeyInternal(
+ entity_change.data().specifics.typed_url().url());
+ if (storage_key.empty()) {
+ // ignore entity change
+ change_processor()->UntrackEntity(entity_change.data());
+ } else {
+ change_processor()->UpdateStorageKey(entity_change.data(), storage_key,
+ metadata_change_list.get());
+ }
+ }
+ }
+
return {};
}
void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
DataCallback callback) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- NOTIMPLEMENTED();
+ DCHECK(sync_metadata_database_);
+
+ auto batch = base::MakeUnique<MutableDataBatch>();
+ for (const std::string& key : storage_keys) {
+ URLRow url_row;
+ URLID url_id = sync_metadata_database_->StorageKeyToURLID(key);
+
+ ++num_db_accesses_;
+ if (!history_backend_->GetURLByID(url_id, &url_row)) {
+ // Ignoring the case which no matching URLRow with URLID |url_id|.
+ DLOG(ERROR) << "Could not find URL for id: " << url_id;
+ continue;
+ }
+
+ VisitVector visits_vector;
+ FixupURLAndGetVisits(&url_row, &visits_vector);
+ std::unique_ptr<syncer::EntityData> entity_data =
+ CreateEntityData(url_row, visits_vector);
+ if (!entity_data.get()) {
+ // Cannot create EntityData, ex. no TYPED visits.
+ continue;
+ }
+
+ batch->Put(key, std::move(entity_data));
+ }
+
+ callback.Run(std::move(batch));
}
void TypedURLSyncBridge::GetAllData(DataCallback callback) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- history::URLRows typed_urls;
+ URLRows typed_urls;
++num_db_accesses_;
if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
++num_db_errors_;
@@ -207,12 +297,19 @@ void TypedURLSyncBridge::GetAllData(DataCallback callback) {
}
auto batch = base::MakeUnique<MutableDataBatch>();
- for (history::URLRow& url : typed_urls) {
+ for (URLRow& url : typed_urls) {
VisitVector visits_vector;
FixupURLAndGetVisits(&url, &visits_vector);
- batch->Put(GetStorageKeyFromURLRow(url),
- CreateEntityData(url, visits_vector));
+ std::unique_ptr<syncer::EntityData> entity_data =
+ CreateEntityData(url, visits_vector);
+ if (!entity_data.get()) {
+ // Cannot create EntityData, ex. no TYPED visits.
+ continue;
+ }
+
+ batch->Put(GetStorageKeyFromURLRow(url), std::move(entity_data));
}
+
callback.Run(std::move(batch));
}
@@ -239,29 +336,84 @@ bool TypedURLSyncBridge::SupportsGetStorageKey() const {
return false;
}
-void TypedURLSyncBridge::OnURLVisited(history::HistoryBackend* history_backend,
+void TypedURLSyncBridge::OnURLVisited(HistoryBackend* history_backend,
ui::PageTransition transition,
- const history::URLRow& row,
- const history::RedirectList& redirects,
+ const URLRow& row,
+ const RedirectList& redirects,
base::Time visit_time) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- NOTIMPLEMENTED();
+
+ if (!change_processor()->IsTrackingMetadata())
+ return; // Sync processor not yet ready, don't sync.
+ if (!ShouldSyncVisit(row.typed_count(), transition))
+ return;
+
+ std::unique_ptr<MetadataChangeList> metadata_change_list =
+ CreateMetadataChangeList();
+
+ UpdateSyncFromLocal(row, metadata_change_list.get());
}
-void TypedURLSyncBridge::OnURLsModified(
- history::HistoryBackend* history_backend,
- const history::URLRows& changed_urls) {
+void TypedURLSyncBridge::OnURLsModified(HistoryBackend* history_backend,
+ const URLRows& changed_urls) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- NOTIMPLEMENTED();
+
+ if (!change_processor()->IsTrackingMetadata())
+ return; // Sync processor not yet ready, don't sync.
+
+ std::unique_ptr<MetadataChangeList> metadata_change_list =
+ CreateMetadataChangeList();
+
+ for (const auto& row : changed_urls) {
+ // Only care if the modified URL is typed.
+ if (row.typed_count() >= 0) {
+ // If there were any errors updating the sync node, just ignore them and
+ // continue on to process the next URL.
+ UpdateSyncFromLocal(row, metadata_change_list.get());
+ }
+ }
}
-void TypedURLSyncBridge::OnURLsDeleted(history::HistoryBackend* history_backend,
+void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
bool all_history,
bool expired,
- const history::URLRows& deleted_rows,
+ const URLRows& deleted_rows,
const std::set<GURL>& favicon_urls) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- NOTIMPLEMENTED();
+ if (!change_processor()->IsTrackingMetadata())
+ return; // Sync processor not yet ready, don't sync.
+
+ // Ignore URLs expired due to old age (we don't want to sync them as deletions
+ // to avoid extra traffic up to the server, and also to make sure that a
+ // client with a bad clock setting won't go on an expiration rampage and
+ // delete all history from every client). The server will gracefully age out
+ // the sync DB entries when they've been idle for long enough.
+ if (expired)
+ return;
+
+ std::unique_ptr<MetadataChangeList> metadata_change_list =
+ CreateMetadataChangeList();
+
+ if (all_history) {
+ auto batch = base::MakeUnique<syncer::MetadataBatch>();
+ if (!sync_metadata_database_->GetAllSyncMetadata(batch.get())) {
+ change_processor()->ReportError(FROM_HERE,
+ "Failed reading typed url metadata from "
+ "TypedURLSyncMetadataDatabase.");
+ return;
+ }
+
+ syncer::EntityMetadataMap metadata_map(batch->TakeAllMetadata());
+ for (const auto& kv : metadata_map) {
+ change_processor()->Delete(kv.first, metadata_change_list.get());
+ }
+ } else {
+ // Delete rows.
+ for (const auto& row : deleted_rows) {
+ std::string storage_key = GetStorageKeyFromURLRow(row);
+ change_processor()->Delete(storage_key, metadata_change_list.get());
+ }
+ }
}
void TypedURLSyncBridge::Init() {
@@ -275,6 +427,7 @@ int TypedURLSyncBridge::GetErrorPercentage() const {
return num_db_accesses_ ? (100 * num_db_errors_ / num_db_accesses_) : 0;
}
+// static
bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
const URLRow& url,
const VisitVector& visits,
@@ -293,11 +446,7 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
bool only_typed = false;
int skip_count = 0;
- if (std::find_if(visits.begin(), visits.end(),
- [](const history::VisitRow& visit) {
- return ui::PageTransitionCoreTypeIs(
- visit.transition, ui::PAGE_TRANSITION_TYPED);
- }) == visits.end()) {
+ if (!HasTypedUrl(visits)) {
// This URL has no TYPED visits, don't sync it
return false;
}
@@ -368,10 +517,10 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
// static
TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
const TypedUrlSpecifics& sync_url,
- const history::URLRow& url,
- history::VisitVector* visits,
- history::URLRow* new_url,
- std::vector<history::VisitInfo>* new_visits) {
+ const URLRow& url,
+ VisitVector* visits,
+ URLRow* new_url,
+ std::vector<VisitInfo>* new_visits) {
DCHECK(new_url);
DCHECK_EQ(sync_url.url(), url.url().spec());
DCHECK_EQ(sync_url.url(), new_url->url().spec());
@@ -445,7 +594,7 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
// check should be removed.
if (sync_url_time > earliest_history_time) {
different |= DIFF_LOCAL_VISITS_ADDED;
- new_visits->push_back(history::VisitInfo(
+ new_visits->push_back(VisitInfo(
sync_url_time, ui::PageTransitionFromInt(sync_url.visit_transitions(
sync_url_visit_index))));
}
@@ -464,17 +613,15 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
// new visits from the server need to be added to the vector containing
// local visits. These visits will be passed to the server.
// Insert new visits into the appropriate place in the visits vector.
- history::VisitVector::iterator visit_ix = visits->begin();
- for (std::vector<history::VisitInfo>::iterator new_visit =
- new_visits->begin();
+ VisitVector::iterator visit_ix = visits->begin();
+ for (std::vector<VisitInfo>::iterator new_visit = new_visits->begin();
new_visit != new_visits->end(); ++new_visit) {
while (visit_ix != visits->end() &&
new_visit->first > visit_ix->visit_time) {
++visit_ix;
}
- visit_ix =
- visits->insert(visit_ix, history::VisitRow(url.id(), new_visit->first,
- 0, new_visit->second, 0));
+ visit_ix = visits->insert(visit_ix, VisitRow(url.id(), new_visit->first,
+ 0, new_visit->second, 0));
++visit_ix;
}
}
@@ -485,9 +632,57 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
}
// static
+void TypedURLSyncBridge::DiffVisits(
+ const VisitVector& history_visits,
+ const sync_pb::TypedUrlSpecifics& sync_specifics,
+ std::vector<VisitInfo>* new_visits,
+ VisitVector* removed_visits) {
+ DCHECK(new_visits);
+ size_t old_visit_count = history_visits.size();
+ size_t new_visit_count = sync_specifics.visits_size();
+ size_t old_index = 0;
+ size_t new_index = 0;
+ while (old_index < old_visit_count && new_index < new_visit_count) {
+ base::Time new_visit_time =
+ base::Time::FromInternalValue(sync_specifics.visits(new_index));
+ if (history_visits[old_index].visit_time < new_visit_time) {
+ if (new_index > 0 && removed_visits) {
+ // If there are visits missing from the start of the node, that
+ // means that they were probably clipped off due to our code that
+ // limits the size of the sync nodes - don't delete them from our
+ // local history.
+ removed_visits->push_back(history_visits[old_index]);
+ }
+ ++old_index;
+ } else if (history_visits[old_index].visit_time > new_visit_time) {
+ new_visits->push_back(VisitInfo(
+ new_visit_time, ui::PageTransitionFromInt(
+ sync_specifics.visit_transitions(new_index))));
+ ++new_index;
+ } else {
+ ++old_index;
+ ++new_index;
+ }
+ }
+
+ if (removed_visits) {
+ for (; old_index < old_visit_count; ++old_index) {
+ removed_visits->push_back(history_visits[old_index]);
+ }
+ }
+
+ for (; new_index < new_visit_count; ++new_index) {
+ new_visits->push_back(VisitInfo(
+ base::Time::FromInternalValue(sync_specifics.visits(new_index)),
+ ui::PageTransitionFromInt(
+ sync_specifics.visit_transitions(new_index))));
+ }
+}
+
+// static
void TypedURLSyncBridge::UpdateURLRowFromTypedUrlSpecifics(
const TypedUrlSpecifics& typed_url,
- history::URLRow* new_url) {
+ URLRow* new_url) {
DCHECK_GT(typed_url.visits_size(), 0);
CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
if (!new_url->url().is_valid()) {
@@ -525,13 +720,13 @@ void TypedURLSyncBridge::ClearErrorStats() {
num_db_errors_ = 0;
}
-void TypedURLSyncBridge::UpdateUrlFromServer(
+void TypedURLSyncBridge::MergeURLWithSync(
const sync_pb::TypedUrlSpecifics& server_typed_url,
TypedURLMap* local_typed_urls,
URLVisitVectorMap* local_visit_vectors,
- history::URLRows* new_synced_urls,
+ URLRows* new_synced_urls,
TypedURLVisitVector* new_synced_visits,
- history::URLRows* updated_synced_urls) {
+ URLRows* updated_synced_urls) {
DCHECK(server_typed_url.visits_size() != 0);
DCHECK_EQ(server_typed_url.visits_size(),
server_typed_url.visit_transitions_size());
@@ -553,7 +748,7 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
TypedURLMap::iterator it = local_typed_urls->find(GURL(sync_url.url()));
if (it == local_typed_urls->end()) {
// There are no matching typed urls from the local db, check for untyped
- history::URLRow untyped_url(GURL(sync_url.url()));
+ URLRow untyped_url(GURL(sync_url.url()));
// The URL may still exist in the local db if it is an untyped url.
// An untyped url will transition to a typed url after receiving visits
@@ -563,7 +758,7 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
history_backend_->GetURL(untyped_url.url(), &untyped_url);
if (is_existing_url) {
// Add a new entry to |local_typed_urls|, and set the iterator to it.
- history::VisitVector untyped_visits;
+ VisitVector untyped_visits;
if (!FixupURLAndGetVisits(&untyped_url, &untyped_visits)) {
return;
}
@@ -579,12 +774,12 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
} else {
// The url is new to the local history DB.
// Create new db entry for url.
- history::URLRow new_url(GURL(sync_url.url()));
+ URLRow new_url(GURL(sync_url.url()));
UpdateURLRowFromTypedUrlSpecifics(sync_url, &new_url);
new_synced_urls->push_back(new_url);
// Add entries for url visits.
- std::vector<history::VisitInfo> added_visits;
+ std::vector<VisitInfo> added_visits;
size_t visit_count = sync_url.visits_size();
for (size_t index = 0; index < visit_count; ++index) {
@@ -592,19 +787,18 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
base::Time::FromInternalValue(sync_url.visits(index));
ui::PageTransition transition =
ui::PageTransitionFromInt(sync_url.visit_transitions(index));
- added_visits.push_back(history::VisitInfo(visit_time, transition));
+ added_visits.push_back(VisitInfo(visit_time, transition));
}
new_synced_visits->push_back(
- std::pair<GURL, std::vector<history::VisitInfo>>(new_url.url(),
- added_visits));
+ std::pair<GURL, std::vector<VisitInfo>>(new_url.url(), added_visits));
return;
}
}
// Same URL exists in sync data and in history data - compare the
// entries to see if there's any difference.
- history::VisitVector& visits = (*local_visit_vectors)[it->first];
- std::vector<history::VisitInfo> added_visits;
+ VisitVector& visits = (*local_visit_vectors)[it->first];
+ std::vector<VisitInfo> added_visits;
// Empty URLs should be filtered out by ShouldIgnoreUrl() previously.
DCHECK(!it->second.url().spec().empty());
@@ -613,7 +807,7 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
// the existing URLRow in the history DB. This is needed because we
// overwrite the existing value in WriteToHistoryBackend(), but some of
// the values in that structure are not synced (like typed_count).
- history::URLRow new_url(it->second);
+ URLRow new_url(it->second);
MergeResult difference =
MergeUrls(sync_url, it->second, &visits, &new_url, &added_visits);
@@ -632,7 +826,7 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
if (sync_url.visits_size() > 0) {
base::Time earliest_visit =
base::Time::FromInternalValue(sync_url.visits(0));
- for (history::VisitVector::iterator i = visits.begin();
+ for (VisitVector::iterator i = visits.begin();
i != visits.end() && i->visit_time < earliest_visit;) {
i = visits.erase(i);
}
@@ -652,8 +846,7 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
if (difference & DIFF_LOCAL_VISITS_ADDED) {
// Add entry with new visits to new_synced_visits to update the local db.
new_synced_visits->push_back(
- std::pair<GURL, std::vector<history::VisitInfo>>(it->first,
- added_visits));
+ std::pair<GURL, std::vector<VisitInfo>>(it->first, added_visits));
}
} else {
// No difference in urls, erase from map
@@ -661,17 +854,69 @@ void TypedURLSyncBridge::UpdateUrlFromServer(
}
}
+void TypedURLSyncBridge::UpdateFromSync(
+ const sync_pb::TypedUrlSpecifics& typed_url,
+ TypedURLVisitVector* visits_to_add,
+ VisitVector* visits_to_remove,
+ URLRows* updated_urls,
+ URLRows* new_urls) {
+ URLRow new_url(GURL(typed_url.url()));
+ VisitVector existing_visits;
+ bool existing_url = history_backend_->GetURL(new_url.url(), &new_url);
+ if (existing_url) {
+ // This URL already exists locally - fetch the visits so we can
+ // merge them below.
+ if (!FixupURLAndGetVisits(&new_url, &existing_visits)) {
+ return;
+ }
+ }
+ visits_to_add->push_back(std::pair<GURL, std::vector<VisitInfo>>(
+ new_url.url(), std::vector<VisitInfo>()));
+
+ // Update the URL with information from the typed URL.
+ UpdateURLRowFromTypedUrlSpecifics(typed_url, &new_url);
+
+ // Figure out which visits we need to add.
+ DiffVisits(existing_visits, typed_url, &visits_to_add->back().second,
+ visits_to_remove);
+
+ if (existing_url) {
+ updated_urls->push_back(new_url);
+ } else {
+ new_urls->push_back(new_url);
+ }
+}
+
+void TypedURLSyncBridge::UpdateSyncFromLocal(
+ URLRow row,
+ MetadataChangeList* metadata_change_list) {
+ DCHECK_GE(row.typed_count(), 0);
+
+ if (ShouldIgnoreUrl(row.url()))
+ return;
+
+ // Get the visits for this node.
+ VisitVector visit_vector;
+ if (!FixupURLAndGetVisits(&row, &visit_vector)) {
+ return;
+ }
+
+ SendTypedURLToProcessor(row, visit_vector, metadata_change_list);
+
+ return;
+}
+
base::Optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
- const history::URLRows* new_urls,
- const history::URLRows* updated_urls,
+ const URLRows* new_urls,
+ const URLRows* updated_urls,
const std::vector<GURL>* deleted_urls,
const TypedURLVisitVector* new_visits,
- const history::VisitVector* deleted_visits) {
+ const VisitVector* deleted_visits) {
if (deleted_urls && !deleted_urls->empty())
history_backend_->DeleteURLs(*deleted_urls);
if (new_urls) {
- history_backend_->AddPagesWithDetails(*new_urls, history::SOURCE_SYNCED);
+ history_backend_->AddPagesWithDetails(*new_urls, SOURCE_SYNCED);
}
if (updated_urls) {
@@ -694,7 +939,7 @@ base::Optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
continue;
++num_db_accesses_;
if (!history_backend_->AddVisits(visits.first, visits.second,
- history::SOURCE_SYNCED)) {
+ SOURCE_SYNCED)) {
++num_db_errors_;
return ModelError(FROM_HERE, "Could not add visits to HistoryBackend.");
}
@@ -748,7 +993,7 @@ bool TypedURLSyncBridge::ShouldIgnoreUrl(const GURL& url) {
if (net::IsLocalhost(url.host_piece()))
return true;
- // Ignore username and password, sonce history backend will remove user name
+ // Ignore username and password, since history backend will remove user name
// and password in URLDatabase::GURLToDatabaseURL and send username/password
// removed url to sync later.
if (url.has_username() || url.has_password())
@@ -757,12 +1002,11 @@ bool TypedURLSyncBridge::ShouldIgnoreUrl(const GURL& url) {
return false;
}
-bool TypedURLSyncBridge::ShouldIgnoreVisits(
- const history::VisitVector& visits) {
+bool TypedURLSyncBridge::ShouldIgnoreVisits(const VisitVector& visits) {
// We ignore URLs that were imported, but have never been visited by
// chromium.
- static const int kFirstImportedSource = history::SOURCE_FIREFOX_IMPORTED;
- history::VisitSourceMap map;
+ static const int kFirstImportedSource = SOURCE_FIREFOX_IMPORTED;
+ VisitSourceMap map;
if (!history_backend_->GetVisitsSource(visits, &map))
return false; // If we can't read the visit, assume it's not imported.
@@ -777,6 +1021,21 @@ bool TypedURLSyncBridge::ShouldIgnoreVisits(
return true;
}
+bool TypedURLSyncBridge::ShouldSyncVisit(int typed_count,
+ ui::PageTransition transition) {
+ // Just use an ad-hoc criteria to determine whether to ignore this
+ // notification. For most users, the distribution of visits is roughly a bell
+ // curve with a long tail - there are lots of URLs with < 5 visits so we want
+ // to make sure we sync up every visit to ensure the proper ordering of
+ // suggestions. But there are relatively few URLs with > 10 visits, and those
+ // tend to be more broadly distributed such that there's no need to sync up
+ // every visit to preserve their relative ordering.
+ return (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) &&
+ typed_count >= 0 &&
+ (typed_count < kTypedUrlVisitThrottleThreshold ||
+ (typed_count % kTypedUrlVisitThrottleMultiple) == 0));
+}
+
bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url,
VisitVector* visits) {
++num_db_accesses_;
@@ -852,10 +1111,9 @@ std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData(
if (!WriteToTypedUrlSpecifics(row, visits, specifics)) {
// Cannot write to specifics, ex. no TYPED visits.
- return base::MakeUnique<EntityData>();
+ return nullptr;
}
entity_data->non_unique_name = row.url().spec();
-
return entity_data;
}
@@ -864,13 +1122,13 @@ bool TypedURLSyncBridge::GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit,
DCHECK(url_to_visit);
DCHECK(url_to_urlrow);
- history::URLRows local_typed_urls;
+ URLRows local_typed_urls;
++num_db_accesses_;
if (!history_backend_->GetAllTypedURLs(&local_typed_urls)) {
++num_db_errors_;
return false;
}
- for (history::URLRow& url : local_typed_urls) {
+ for (URLRow& url : local_typed_urls) {
DCHECK_EQ(0U, url_to_visit->count(url.url()));
if (!FixupURLAndGetVisits(&url, &((*url_to_visit)[url.url()])) ||
ShouldIgnoreUrl(url.url()) ||
@@ -901,4 +1159,23 @@ std::string TypedURLSyncBridge::GetStorageKeyInternal(const std::string& url) {
return GetStorageKeyFromURLRow(existing_url);
}
+void TypedURLSyncBridge::SendTypedURLToProcessor(
+ const URLRow& row,
+ const VisitVector& visits,
+ MetadataChangeList* metadata_change_list) {
+ DCHECK(!visits.empty());
+ DCHECK(metadata_change_list);
+
+ std::unique_ptr<syncer::EntityData> entity_data =
+ CreateEntityData(row, visits);
+ if (!entity_data.get()) {
+ // Cannot create EntityData, ex. no TYPED visits.
+ return;
+ }
+
+ std::string storage_key = GetStorageKeyFromURLRow(row);
+ change_processor()->Put(storage_key, std::move(entity_data),
+ metadata_change_list);
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge.h b/chromium/components/history/core/browser/typed_url_sync_bridge.h
index 13a8bbd9bc5..01f25ee19b3 100644
--- a/chromium/components/history/core/browser/typed_url_sync_bridge.h
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge.h
@@ -40,17 +40,17 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
bool SupportsGetStorageKey() const override;
// history::HistoryBackendObserver:
- void OnURLVisited(history::HistoryBackend* history_backend,
+ void OnURLVisited(HistoryBackend* history_backend,
ui::PageTransition transition,
- const history::URLRow& row,
- const history::RedirectList& redirects,
+ const URLRow& row,
+ const RedirectList& redirects,
base::Time visit_time) override;
- void OnURLsModified(history::HistoryBackend* history_backend,
- const history::URLRows& changed_urls) override;
- void OnURLsDeleted(history::HistoryBackend* history_backend,
+ void OnURLsModified(HistoryBackend* history_backend,
+ const URLRows& changed_urls) override;
+ void OnURLsDeleted(HistoryBackend* history_backend,
bool all_history,
bool expired,
- const history::URLRows& deleted_rows,
+ const URLRows& deleted_rows,
const std::set<GURL>& favicon_urls) override;
// Must be called after creation and before any operations.
@@ -97,15 +97,25 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// should be written to the history DB for this URL. Deletions are not
// written to the DB - each client is left to age out visits on their own.
static MergeResult MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
- const history::URLRow& url,
- history::VisitVector* visits,
- history::URLRow* new_url,
- std::vector<history::VisitInfo>* new_visits);
+ const URLRow& url,
+ VisitVector* visits,
+ URLRow* new_url,
+ std::vector<VisitInfo>* new_visits);
+
+ // Diffs the set of visits between the history DB and the sync DB, using the
+ // sync DB as the canonical copy. Result is the set of |new_visits| and
+ // |removed_visits| that can be applied to the history DB to make it match
+ // the sync DB version. |removed_visits| can be null if the caller does not
+ // care about which visits to remove.
+ static void DiffVisits(const VisitVector& history_visits,
+ const sync_pb::TypedUrlSpecifics& sync_specifics,
+ std::vector<VisitInfo>* new_visits,
+ VisitVector* removed_visits);
// Fills |new_url| with formatted data from |typed_url|.
static void UpdateURLRowFromTypedUrlSpecifics(
const sync_pb::TypedUrlSpecifics& typed_url,
- history::URLRow* new_url);
+ URLRow* new_url);
// Synchronously load sync metadata from the TypedURLSyncMetadataDatabase and
// pass it to the processor so that it can start tracking changes.
@@ -118,20 +128,38 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Compares |server_typed_url| from the server against local history to decide
// how to merge any existing data, and updates appropriate data containers to
// write to server and backend.
- void UpdateUrlFromServer(const sync_pb::TypedUrlSpecifics& server_typed_url,
- TypedURLMap* local_typed_urls,
- URLVisitVectorMap* visit_vectors,
- history::URLRows* new_synced_urls,
- TypedURLVisitVector* new_synced_visits,
- history::URLRows* updated_synced_urls);
+ void MergeURLWithSync(const sync_pb::TypedUrlSpecifics& server_typed_url,
+ TypedURLMap* local_typed_urls,
+ URLVisitVectorMap* visit_vectors,
+ URLRows* new_synced_urls,
+ TypedURLVisitVector* new_synced_visits,
+ URLRows* updated_synced_urls);
+
+ // Given a typed URL in the sync DB, looks for an existing entry in the
+ // local history DB and generates a list of visits to add to the
+ // history DB to bring it up to date (avoiding duplicates).
+ // Updates the passed |visits_to_add| and |visits_to_remove| vectors with the
+ // visits to add to/remove from the history DB, and adds a new entry to either
+ // |updated_urls| or |new_urls| depending on whether the URL already existed
+ // in the history DB.
+ void UpdateFromSync(const sync_pb::TypedUrlSpecifics& typed_url,
+ TypedURLVisitVector* visits_to_add,
+ VisitVector* visits_to_remove,
+ URLRows* updated_urls,
+ URLRows* new_urls);
+
+ // Utility routine that either updates an existing sync node or creates a
+ // new one for the passed |typed_url| if one does not already exist.
+ void UpdateSyncFromLocal(URLRow typed_url,
+ syncer::MetadataChangeList* metadata_change_list);
// Writes new typed url data from sync server to history backend.
base::Optional<syncer::ModelError> WriteToHistoryBackend(
- const history::URLRows* new_urls,
- const history::URLRows* updated_urls,
+ const URLRows* new_urls,
+ const URLRows* updated_urls,
const std::vector<GURL>* deleted_urls,
const TypedURLVisitVector* new_visits,
- const history::VisitVector* deleted_visits);
+ const VisitVector* deleted_visits);
// Given a TypedUrlSpecifics object, removes all visits that are older than
// the current expiration time. Note that this can result in having no visits
@@ -145,7 +173,13 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Helper function that determines if we should ignore a URL for the purposes
// of sync, based on the visits the URL had.
- bool ShouldIgnoreVisits(const history::VisitVector& visits);
+ bool ShouldIgnoreVisits(const VisitVector& visits);
+
+ // Returns true if the caller should sync as a result of the passed visit
+ // notification. We use this to throttle the number of sync changes we send
+ // to the server so we don't hit the server for every
+ // single typed URL visit.
+ bool ShouldSyncVisit(int typed_count, ui::PageTransition transition);
// Fetches visits from the history DB corresponding to the passed URL. This
// function compensates for the fact that the history DB has rather poor data
@@ -173,6 +207,12 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Get URLID from HistoryBackend, and return URLID as storage key.
std::string GetStorageKeyInternal(const std::string& url);
+ // Send local typed url to processor().
+ void SendTypedURLToProcessor(
+ const URLRow& row,
+ const VisitVector& visits,
+ syncer::MetadataChangeList* metadata_change_list);
+
// A non-owning pointer to the backend, which we're syncing local changes from
// and sync changes to.
HistoryBackend* const history_backend_;
@@ -192,7 +232,7 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Tracks observed history backend, for receiving updates from history
// backend.
- ScopedObserver<history::HistoryBackend, history::HistoryBackendObserver>
+ ScopedObserver<HistoryBackend, HistoryBackendObserver>
history_backend_observer_;
DISALLOW_COPY_AND_ASSIGN(TypedURLSyncBridge);
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc b/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
index 4a36d3aca53..e598864298f 100644
--- a/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
@@ -4,6 +4,7 @@
#include "components/history/core/browser/typed_url_sync_bridge.h"
+#include "base/big_endian.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
@@ -26,12 +27,19 @@ using syncer::EntityData;
using syncer::EntityDataPtr;
using syncer::KeyAndData;
using syncer::MetadataBatch;
+using syncer::MetadataChangeList;
using syncer::RecordingModelTypeChangeProcessor;
namespace history {
namespace {
+// Constants used to limit size of visits processed. See
+// equivalent constants in typed_url_sync_bridge.cc for descriptions.
+const int kMaxTypedUrlVisits = 100;
+const int kVisitThrottleThreshold = 10;
+const int kVisitThrottleMultiple = 10;
+
// Visits with this timestamp are treated as expired.
const int kExpiredVisit = -1;
@@ -41,6 +49,49 @@ const char kTitle2[] = "cookie";
const char kURL[] = "http://pie.com/";
const char kURL2[] = "http://cookie.com/";
+bool URLsEqual(URLRow& row, sync_pb::TypedUrlSpecifics& specifics) {
+ return ((row.url().spec().compare(specifics.url()) == 0) &&
+ (base::UTF16ToUTF8(row.title()).compare(specifics.title()) == 0) &&
+ (row.hidden() == specifics.hidden()));
+}
+
+bool URLsEqual(URLRow& lhs, URLRow& rhs) {
+ // Only compare synced fields (ignore typed_count and visit_count as those
+ // are maintained by the history subsystem).
+ return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
+ (lhs.title().compare(rhs.title()) == 0) &&
+ (lhs.hidden() == rhs.hidden());
+}
+
+void AddNewestVisit(ui::PageTransition transition,
+ int64_t visit_time,
+ URLRow* url,
+ VisitVector* visits) {
+ base::Time time = base::Time::FromInternalValue(visit_time);
+ visits->insert(visits->begin(), VisitRow(url->id(), time, 0, transition, 0));
+
+ if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) {
+ url->set_typed_count(url->typed_count() + 1);
+ }
+
+ url->set_last_visit(time);
+ url->set_visit_count(visits->size());
+}
+
+void AddOldestVisit(ui::PageTransition transition,
+ int64_t visit_time,
+ URLRow* url,
+ VisitVector* visits) {
+ base::Time time = base::Time::FromInternalValue(visit_time);
+ visits->push_back(VisitRow(url->id(), time, 0, transition, 0));
+
+ if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) {
+ url->set_typed_count(url->typed_count() + 1);
+ }
+
+ url->set_visit_count(visits->size());
+}
+
// Create a new row object and the typed visit çorresponding with the time at
// |last_visit| in the |visits| vector.
URLRow MakeTypedUrlRow(const std::string& url,
@@ -104,6 +155,12 @@ void VerifyDataBatch(std::map<std::string, TypedUrlSpecifics> expected,
EXPECT_TRUE(expected.empty());
}
+std::string IntToStroageKey(int id) {
+ std::string storage_key(sizeof(URLID), 0);
+ base::WriteBigEndian<URLID>(&storage_key[0], id);
+ return storage_key;
+}
+
class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
public:
TestHistoryBackendDelegate() {}
@@ -149,16 +206,17 @@ class TestHistoryBackend : public HistoryBackend {
}
void SetVisitsForUrl(URLRow& new_url, const VisitVector visits) {
- std::vector<history::VisitInfo> added_visits;
- URLRows new_urls;
- DeleteURL(new_url.url());
+ if (!GetURL(new_url.url(), nullptr)) {
+ URLRows new_urls;
+ new_urls.push_back(new_url);
+ AddPagesWithDetails(new_urls, SOURCE_SYNCED);
+ }
+
+ std::vector<VisitInfo> added_visits;
for (const auto& visit : visits) {
- added_visits.push_back(
- history::VisitInfo(visit.visit_time, visit.transition));
+ added_visits.push_back(VisitInfo(visit.visit_time, visit.transition));
}
- new_urls.push_back(new_url);
- AddPagesWithDetails(new_urls, history::SOURCE_SYNCED);
- AddVisits(new_url.url(), added_visits, history::SOURCE_SYNCED);
+ AddVisits(new_url.url(), added_visits, SOURCE_SYNCED);
new_url.set_id(GetIdByUrl(new_url.url()));
}
@@ -189,7 +247,10 @@ class TypedURLSyncBridgeTest : public testing::Test {
fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge));
}
- void TearDown() override { fake_history_backend_->Closing(); }
+ void TearDown() override {
+ VerifyProcessorReceivedValidEntityData();
+ fake_history_backend_->Closing();
+ }
// Starts sync for |typed_url_sync_bridge_| with |initial_data| as the
// initial sync data.
@@ -202,6 +263,80 @@ class TypedURLSyncBridgeTest : public testing::Test {
EXPECT_FALSE(error);
}
+ bool BuildAndPushLocalChanges(unsigned int num_typed_urls,
+ unsigned int 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;
+ DCHECK(urls.size() >= total_urls);
+ if (!bridge())
+ return false;
+
+ 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;
+ VisitVector visits;
+ visit_vectors->push_back(visits);
+ rows->push_back(MakeTypedUrlRow(urls[i], kTitle, typed, i + 3, false,
+ &visit_vectors->back()));
+ fake_history_backend_->SetVisitsForUrl(rows->back(),
+ visit_vectors->back());
+ changed_urls.push_back(rows->back());
+ }
+
+ bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls);
+ }
+
+ // 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,
+ const std::string& title,
+ int typed_count,
+ int64_t last_visit,
+ bool hidden,
+ EntityChange::ChangeType change_type) {
+ VisitVector visits;
+ URLRow row =
+ MakeTypedUrlRow(url, title, typed_count, last_visit, hidden, &visits);
+ sync_pb::TypedUrlSpecifics typed_url_specifics;
+ WriteToTypedUrlSpecifics(row, visits, &typed_url_specifics);
+ std::unique_ptr<MetadataChangeList> metadata_changes =
+ bridge()->CreateMetadataChangeList();
+ EntityChangeList entity_changes;
+ switch (change_type) {
+ case EntityChange::ACTION_ADD:
+ entity_changes.push_back(EntityChange::CreateAdd(
+ std::string(), SpecificsToEntity(typed_url_specifics)));
+ break;
+ case EntityChange::ACTION_UPDATE:
+ entity_changes.push_back(
+ EntityChange::CreateUpdate(GetStorageKey(typed_url_specifics.url()),
+ SpecificsToEntity(typed_url_specifics)));
+ break;
+ case EntityChange::ACTION_DELETE:
+ entity_changes.push_back(EntityChange::CreateDelete(
+ GetStorageKey(typed_url_specifics.url())));
+ break;
+ }
+ bridge()->ApplySyncChanges(std::move(metadata_changes), entity_changes);
+ return visits;
+ }
+
+ void AddObserver() {
+ bridge()->history_backend_observer_.Add(fake_history_backend_.get());
+ }
+
+ void RemoveObserver() { bridge()->history_backend_observer_.RemoveAll(); }
+
// Fills |specifics| with the sync data for |url| and |visits|.
static bool WriteToTypedUrlSpecifics(const URLRow& url,
const VisitVector& visits,
@@ -209,9 +344,8 @@ class TypedURLSyncBridgeTest : public testing::Test {
return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics);
}
- std::string GetStorageKey(const TypedUrlSpecifics& specifics) {
- std::string key = bridge()->GetStorageKeyInternal(specifics.url());
- return key;
+ std::string GetStorageKey(const std::string& url) {
+ return bridge()->GetStorageKeyInternal(url);
}
EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) {
@@ -226,7 +360,7 @@ class TypedURLSyncBridgeTest : public testing::Test {
EntityChangeList entity_change_list;
for (const auto& specifics : specifics_vector) {
entity_change_list.push_back(EntityChange::CreateAdd(
- GetStorageKey(specifics), SpecificsToEntity(specifics)));
+ GetStorageKey(specifics.url()), SpecificsToEntity(specifics)));
}
return entity_change_list;
}
@@ -235,15 +369,86 @@ class TypedURLSyncBridgeTest : public testing::Test {
const std::vector<TypedUrlSpecifics>& specifics_vector) {
std::map<std::string, TypedUrlSpecifics> map;
for (const auto& specifics : specifics_vector) {
- map[GetStorageKey(specifics)] = specifics;
+ map[GetStorageKey(specifics.url())] = specifics;
}
return map;
}
- void VerifyLocalHistoryData(const std::vector<TypedUrlSpecifics>& expected) {
+ void VerifyAllLocalHistoryData(
+ const std::vector<TypedUrlSpecifics>& expected) {
bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected)));
}
+ void VerifyGetData(TypedURLSyncBridge::StorageKeyList storage_keys,
+ const std::vector<TypedUrlSpecifics>& expected) {
+ bridge()->GetData(storage_keys,
+ base::Bind(&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,
+ VisitVector* removed_visits) {
+ TypedURLSyncBridge::DiffVisits(history_visits, sync_specifics, new_visits,
+ removed_visits);
+ }
+
+ static VisitRow CreateVisit(ui::PageTransition type, int64_t timestamp) {
+ return VisitRow(0, base::Time::FromInternalValue(timestamp), 0, type, 0);
+ }
+
+ static TypedURLSyncBridge::MergeResult MergeUrls(
+ const sync_pb::TypedUrlSpecifics& typed_url,
+ const URLRow& url,
+ VisitVector* visits,
+ URLRow* new_url,
+ std::vector<VisitInfo>* new_visits) {
+ return TypedURLSyncBridge::MergeUrls(typed_url, url, visits, new_url,
+ new_visits);
+ }
+
+ static sync_pb::TypedUrlSpecifics MakeTypedUrlSpecifics(const char* url,
+ const char* title,
+ int64_t last_visit,
+ bool hidden) {
+ sync_pb::TypedUrlSpecifics typed_url;
+ typed_url.set_url(url);
+ typed_url.set_title(title);
+ typed_url.set_hidden(hidden);
+ typed_url.add_visits(last_visit);
+ typed_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ return typed_url;
+ }
+
+ static const TypedURLSyncBridge::MergeResult DIFF_NONE =
+ TypedURLSyncBridge::DIFF_NONE;
+ static const TypedURLSyncBridge::MergeResult DIFF_UPDATE_NODE =
+ TypedURLSyncBridge::DIFF_UPDATE_NODE;
+ static const TypedURLSyncBridge::MergeResult DIFF_LOCAL_ROW_CHANGED =
+ TypedURLSyncBridge::DIFF_LOCAL_ROW_CHANGED;
+ static const TypedURLSyncBridge::MergeResult DIFF_LOCAL_VISITS_ADDED =
+ TypedURLSyncBridge::DIFF_LOCAL_VISITS_ADDED;
+
TypedURLSyncBridge* bridge() { return typed_url_sync_bridge_; }
TypedURLSyncMetadataDatabase* metadata_store() {
@@ -277,7 +482,26 @@ TEST_F(TypedURLSyncBridgeTest, GetAllData) {
WriteToTypedUrlSpecifics(row2, visits2, &typed_url2);
// Check that the local cache is still correct.
- VerifyLocalHistoryData({typed_url1, typed_url2});
+ VerifyAllLocalHistoryData({typed_url1, typed_url2});
+}
+
+// Add two typed urls locally and verify bridge can get them from GetData.
+TEST_F(TypedURLSyncBridgeTest, GetData) {
+ // Add two urls to backend.
+ VisitVector visits1, visits2;
+ URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1);
+ URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2);
+ fake_history_backend_->SetVisitsForUrl(row1, visits1);
+ fake_history_backend_->SetVisitsForUrl(row2, visits2);
+
+ // Create the same data in sync.
+ TypedUrlSpecifics typed_url1, typed_url2;
+ WriteToTypedUrlSpecifics(row1, visits1, &typed_url1);
+ WriteToTypedUrlSpecifics(row2, visits2, &typed_url2);
+
+ // Check that the local cache is still correct.
+ VerifyGetData({IntToStroageKey(1)}, {typed_url1});
+ VerifyGetData({IntToStroageKey(2)}, {typed_url2});
}
// Add a typed url locally and one to sync with the same data. Starting sync
@@ -296,8 +520,19 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) {
StartSyncing({*typed_url});
EXPECT_TRUE(processor().put_multimap().empty());
+ // 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);
+
// Check that the local cache was is still correct.
- VerifyLocalHistoryData({*typed_url});
+ VerifyAllLocalHistoryData({*typed_url});
}
// Add a corupted typed url locally, has typed url count 1, but no real typed
@@ -332,12 +567,12 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptySync) {
sync_pb::EntitySpecifics entity_specifics;
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(row, visits, typed_url);
- VerifyLocalHistoryData({*typed_url});
+ 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));
+ 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();
@@ -361,6 +596,14 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
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;
@@ -374,6 +617,129 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
all_visits[0].transition, visits[0].transition));
}
+// Add a url to the local and sync data before sync begins, with the sync data
+// having more recent visits. Check that starting sync updates the backend
+// with the sync visit, while the older local visit is not pushed to sync.
+// The title should be updated to the sync version due to the more recent
+// timestamp.
+TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
+ // Add a url to backend.
+ VisitVector visits;
+ URLRow local_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(local_row, visits);
+
+ // Create sync data for the same url with a more recent visit.
+ VisitVector server_visits;
+ URLRow server_row =
+ MakeTypedUrlRow(kURL, kTitle2, 1, 6, false, &server_visits);
+ server_row.set_id(fake_history_backend_->GetIdByUrl(GURL(kURL)));
+ sync_pb::EntitySpecifics entity_specifics;
+ sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
+ WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+ StartSyncing({*typed_url});
+
+ // Check that the backend was updated correctly.
+ VisitVector all_visits;
+ base::Time server_time = base::Time::FromInternalValue(6);
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+ ASSERT_EQ(2U, all_visits.size());
+ EXPECT_EQ(server_time, all_visits.back().visit_time);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ all_visits.back().transition, server_visits[0].transition));
+ URLRow url_row;
+ EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
+ EXPECT_EQ(kTitle2, base::UTF16ToUTF8(url_row.title()));
+
+ // 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);
+ ASSERT_EQ(1, url_specifics.visits_size());
+ EXPECT_EQ(6, url_specifics.visits(0));
+ ASSERT_EQ(1, url_specifics.visit_transitions_size());
+ EXPECT_EQ(static_cast<const int>(visits[0].transition),
+ url_specifics.visit_transitions(0));
+}
+
+// Add a url to the local and sync data before sync begins, with the local data
+// having more recent visits. Check that starting sync updates the sync
+// with the local visits, while the older sync visit is not pushed to the
+// backend. Sync's title should be updated to the local version due to the more
+// recent timestamp.
+TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) {
+ // Add a url to backend.
+ VisitVector visits;
+ URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(local_row, visits);
+
+ // Create sync data for the same url with an older visit.
+ VisitVector server_visits;
+ URLRow server_row =
+ MakeTypedUrlRow(kURL, kTitle, 1, 2, false, &server_visits);
+ sync_pb::EntitySpecifics entity_specifics;
+ sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
+ WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+ StartSyncing({*typed_url});
+
+ // Check that the backend was not updated.
+ VisitVector all_visits;
+ base::Time local_visit_time = base::Time::FromInternalValue(3);
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+ ASSERT_EQ(1U, all_visits.size());
+ EXPECT_EQ(local_visit_time, all_visits[0].visit_time);
+
+ // 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);
+ ASSERT_EQ(1, url_specifics.visits_size());
+ EXPECT_EQ(3, url_specifics.visits(0));
+ EXPECT_EQ(kTitle2, url_specifics.title());
+ ASSERT_EQ(1, url_specifics.visit_transitions_size());
+ EXPECT_EQ(static_cast<const int>(visits[0].transition),
+ url_specifics.visit_transitions(0));
+}
+
+// Check that there is no crash during start sync, if history backend and sync
+// have same url, but sync has username/password in it.
+// Also check sync will not accept url with username and password.
+TEST_F(TypedURLSyncBridgeTest, MergeUrlsWithUsernameAndPassword) {
+ const char kURLWithUsernameAndPassword[] =
+ "http://username:password@pie.com/";
+
+ // Add a url to backend.
+ VisitVector visits;
+ URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(local_row, visits);
+
+ // Create sync data for the same url but contain username and password.
+ VisitVector server_visits;
+ URLRow server_row = MakeTypedUrlRow(kURLWithUsernameAndPassword, kTitle, 1, 3,
+ false, &server_visits);
+ sync_pb::EntitySpecifics entity_specifics;
+ sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
+ WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+
+ // 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(),
+ base::Time::FromInternalValue(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
// visit. After merge, both local and sync should have two same visits.
TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
@@ -406,4 +772,795 @@ TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
all_visits[1].transition, visits2[0].transition));
}
+// Create a local typed URL with one TYPED visit after sync has started. Check
+// that sync is sent an ADD change for the new URL.
+TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) {
+ // Create a local typed URL (simulate a typed visit) that is not already
+ // in sync. Check that sync is sent an ADD change for the existing URL.
+ 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));
+
+ 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();
+
+ EXPECT_TRUE(URLsEqual(url_row, url_specifics));
+ ASSERT_EQ(1, url_specifics.visits_size());
+ ASSERT_EQ(static_cast<const int>(visits.size()), url_specifics.visits_size());
+ EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(0));
+ EXPECT_EQ(static_cast<const int>(visits[0].transition),
+ url_specifics.visit_transitions(0));
+}
+
+// Update a local typed URL that is already synced. Check that sync is sent an
+// UPDATE for the existing url, but RELOAD visits aren't synced.
+TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) {
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back(kURL);
+
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+
+ // Update the URL row, adding another typed visit to the visit vector.
+ URLRows changed_urls;
+ VisitVector visits;
+ URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
+ AddNewestVisit(ui::PAGE_TRANSITION_TYPED, 7, &url_row, &visits);
+ AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 8, &url_row, &visits);
+ AddNewestVisit(ui::PAGE_TRANSITION_LINK, 9, &url_row, &visits);
+ fake_history_backend_->SetVisitsForUrl(url_row, visits);
+ 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());
+ bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls);
+ ASSERT_EQ(1U, changes_multimap.size());
+
+ sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ EXPECT_TRUE(URLsEqual(url_row, url_specifics));
+ ASSERT_EQ(3, url_specifics.visits_size());
+
+ // Check that each visit has been translated/communicated correctly.
+ // Note that the specifics record visits in chronological order, and the
+ // visits from the db are in reverse chronological order.
+ EXPECT_EQ(visits[0].visit_time.ToInternalValue(), url_specifics.visits(2));
+ EXPECT_EQ(static_cast<const int>(visits[0].transition),
+ url_specifics.visit_transitions(2));
+ EXPECT_EQ(visits[2].visit_time.ToInternalValue(), url_specifics.visits(1));
+ EXPECT_EQ(static_cast<const int>(visits[2].transition),
+ url_specifics.visit_transitions(1));
+ EXPECT_EQ(visits[3].visit_time.ToInternalValue(), url_specifics.visits(0));
+ EXPECT_EQ(static_cast<const int>(visits[3].transition),
+ url_specifics.visit_transitions(0));
+}
+
+// Append a RELOAD visit to a typed url that is already synced. Check that sync
+// does not receive any updates.
+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());
+
+ // Update the URL row, adding another typed visit to the visit vector.
+ URLRow url_row = url_rows.front();
+ URLRows changed_urls;
+ VisitVector new_visits;
+ AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 7, &url_row, &new_visits);
+ fake_history_backend_->SetVisitsForUrl(url_row, new_visits);
+ changed_urls.push_back(url_row);
+
+ // Notify typed url sync service of the update.
+ bridge()->OnURLVisited(fake_history_backend_.get(),
+ ui::PAGE_TRANSITION_RELOAD, url_row, RedirectList(),
+ base::Time::FromInternalValue(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
+// receive any changes.
+TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
+ 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());
+
+ // Update the URL row, adding a non-typed visit to the visit vector.
+ URLRow url_row = url_rows.front();
+ VisitVector new_visits;
+ AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &new_visits);
+ fake_history_backend_->SetVisitsForUrl(url_row, new_visits);
+
+ ui::PageTransition transition = ui::PAGE_TRANSITION_LINK;
+ // Notify typed url sync service of non-typed visit, expect no change.
+ bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
+ RedirectList(), base::Time::FromInternalValue(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
+// url. Check that sync receives an UPDATE with the newest visit data.
+TEST_F(TypedURLSyncBridgeTest, TypedVisitLocalTypedUrl) {
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back(kURL);
+
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+
+ // Update the URL row, adding another typed visit to the visit vector.
+ VisitVector visits;
+ URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
+ AddOldestVisit(ui::PAGE_TRANSITION_LINK, 1, &url_row, &visits);
+ AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &visits);
+ AddNewestVisit(ui::PAGE_TRANSITION_TYPED, 7, &url_row, &visits);
+ 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());
+ ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
+ RedirectList(), base::Time::Now());
+
+ ASSERT_EQ(1U, changes_multimap.size());
+ sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+
+ EXPECT_TRUE(URLsEqual(url_row, url_specifics));
+ EXPECT_EQ(4, url_specifics.visits_size());
+
+ // Check that each visit has been translated/communicated correctly.
+ // Note that the specifics record visits in chronological order, and the
+ // visits from the db are in reverse chronological order.
+ int r = url_specifics.visits_size() - 1;
+ for (int i = 0; i < url_specifics.visits_size(); ++i, --r) {
+ EXPECT_EQ(visits[i].visit_time.ToInternalValue(), url_specifics.visits(r));
+ EXPECT_EQ(static_cast<const int>(visits[i].transition),
+ url_specifics.visit_transitions(r));
+ }
+}
+
+// Delete several (but not all) local typed urls. Check that sync receives the
+// DELETE changes, and the non-deleted urls remain synced.
+TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back("http://pie.com/");
+ urls.push_back("http://cake.com/");
+ urls.push_back("http://google.com/");
+ urls.push_back("http://foo.com/");
+ urls.push_back("http://bar.com/");
+
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+ ASSERT_TRUE(BuildAndPushLocalChanges(4, 1, urls, &url_rows, &visit_vectors));
+ const auto& changes_multimap = processor().put_multimap();
+ ASSERT_EQ(4U, changes_multimap.size());
+
+ // Simulate visit expiry of typed visit, no syncing is done
+ // This is to test that sync relies on the in-memory cache to know
+ // which urls were typed and synced, and should be deleted.
+ url_rows[0].set_typed_count(0);
+ VisitVector visits;
+ fake_history_backend_->SetVisitsForUrl(url_rows[0], visits);
+
+ // 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());
+ 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.
+ 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());
+}
+
+// Saturate the visits for a typed url with both TYPED and LINK navigations.
+// Check that no more than kMaxTypedURLVisits are synced, and that LINK visits
+// are dropped rather than TYPED ones.
+TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back(kURL);
+
+ 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());
+
+ URLRow url_row = url_rows.front();
+ VisitVector visits;
+
+ // Add |kMaxTypedUrlVisits| + 10 visits to the url. The 10 oldest
+ // non-typed visits are expected to be skipped.
+ int i = 1;
+ for (; i <= kMaxTypedUrlVisits - 20; ++i)
+ AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits);
+ for (; i <= kMaxTypedUrlVisits; ++i)
+ AddNewestVisit(ui::PAGE_TRANSITION_LINK, i, &url_row, &visits);
+ for (; i <= kMaxTypedUrlVisits + 10; ++i)
+ AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits);
+
+ fake_history_backend_->SetVisitsForUrl(url_row, visits);
+
+ // Notify typed url sync service of typed visit.
+ ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
+ RedirectList(), base::Time::Now());
+
+ ASSERT_EQ(1U, changes_multimap.size());
+ sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ ASSERT_EQ(kMaxTypedUrlVisits, url_specifics.visits_size());
+
+ // Check that each visit has been translated/communicated correctly.
+ // Note that the specifics records visits in chronological order, and the
+ // visits from the db are in reverse chronological order.
+ int num_typed_visits_synced = 0;
+ int num_other_visits_synced = 0;
+ int r = url_specifics.visits_size() - 1;
+ for (int i = 0; i < url_specifics.visits_size(); ++i, --r) {
+ if (url_specifics.visit_transitions(i) ==
+ static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED)) {
+ ++num_typed_visits_synced;
+ } else {
+ ++num_other_visits_synced;
+ }
+ }
+ EXPECT_EQ(kMaxTypedUrlVisits - 10, num_typed_visits_synced);
+ EXPECT_EQ(10, num_other_visits_synced);
+}
+
+// Add enough visits to trigger throttling of updates to a typed url. Check that
+// sync does not receive an update until the proper throttle interval has been
+// reached.
+TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back(kURL);
+
+ 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());
+
+ URLRow url_row = url_rows.front();
+ VisitVector visits;
+
+ // Add enough visits to the url so that typed count is above the throttle
+ // limit, and not right on the interval that gets synced.
+ int i = 1;
+ for (; i < kVisitThrottleThreshold + kVisitThrottleMultiple / 2; ++i)
+ AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits);
+ fake_history_backend_->SetVisitsForUrl(url_row, visits);
+
+ // Notify typed url sync service of typed visit.
+ ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
+ RedirectList(), base::Time::Now());
+
+ // 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);
+ --i; // Account for the increment before the condition ends.
+ fake_history_backend_->SetVisitsForUrl(url_row, visits);
+
+ // Notify typed url sync service of typed visit.
+ bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
+ RedirectList(), base::Time::Now());
+
+ ASSERT_EQ(1U, changes_multimap.size());
+ sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ ASSERT_EQ(i, url_specifics.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>());
+ VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
+ EntityChange::ACTION_ADD);
+
+ ASSERT_EQ(0U, processor().put_multimap().size());
+ ASSERT_EQ(1U, processor().update_multimap().size());
+ ASSERT_EQ(0U, processor().untrack_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);
+
+ base::Time visit_time = base::Time::FromInternalValue(3);
+ VisitVector all_visits;
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+ EXPECT_EQ(1U, all_visits.size());
+ EXPECT_EQ(visit_time, all_visits[0].visit_time);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ all_visits[0].transition, visits[0].transition));
+ URLRow url_row;
+ EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
+ EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title()));
+}
+
+// Create a remote typed URL with expired visit, then send to sync bridge after
+// sync has started. Check that local DB did not receive the expired URL and
+// visit.
+TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) {
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+ VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, kExpiredVisit,
+ false, EntityChange::ACTION_ADD);
+
+ ASSERT_EQ(0U, processor().put_multimap().size());
+ ASSERT_EQ(0U, processor().update_multimap().size());
+ ASSERT_EQ(1U, processor().untrack_set().size());
+
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_EQ(0, url_id);
+}
+
+// Update a remote typed URL and create a new visit that is already synced, then
+// send the update to sync bridge. Check that local DB is received an
+// UPDATE for the existing url and new visit.
+TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+
+ VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
+ EntityChange::ACTION_ADD);
+ base::Time visit_time = base::Time::FromInternalValue(3);
+ VisitVector all_visits;
+ URLRow url_row;
+
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+
+ EXPECT_EQ(1U, all_visits.size());
+ EXPECT_EQ(visit_time, all_visits[0].visit_time);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ all_visits[0].transition, visits[0].transition));
+ EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
+ EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title()));
+
+ VisitVector new_visits = ApplyUrlAndVisitsChange(kURL, kTitle2, 2, 6, false,
+ EntityChange::ACTION_UPDATE);
+
+ base::Time new_visit_time = base::Time::FromInternalValue(6);
+ url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+
+ EXPECT_EQ(2U, all_visits.size());
+ EXPECT_EQ(new_visit_time, all_visits.back().visit_time);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ all_visits.back().transition, new_visits[0].transition));
+ EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
+ EXPECT_EQ(kTitle2, base::UTF16ToUTF8(url_row.title()));
+}
+
+// Delete a typed urls which already synced. Check that local DB receives the
+// DELETE changes.
+TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
+ 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());
+
+ base::Time visit_time = base::Time::FromInternalValue(3);
+ VisitVector all_visits;
+ URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
+ ASSERT_NE(0, url_id);
+ fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
+ EXPECT_EQ(1U, all_visits.size());
+ EXPECT_EQ(visit_time, all_visits[0].visit_time);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ all_visits[0].transition, visit_vectors[0][0].transition));
+ URLRow url_row;
+ EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
+ EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title()));
+
+ // Add observer back to check if TypedUrlSyncBridge receive delete
+ // changes back from fake_history_backend_.
+ AddObserver();
+
+ ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
+ EntityChange::ACTION_DELETE);
+
+ 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
+// are same. Check DiffVisits will return empty set of diff visits.
+TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) {
+ VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64_t visits[] = {1024, 2065, 65534, 1237684};
+
+ for (int64_t visit : visits) {
+ old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ new_url.add_visits(visit);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<VisitInfo> new_visits;
+ VisitVector removed_visits;
+
+ DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ EXPECT_TRUE(removed_visits.empty());
+}
+
+// Create two set of visits for history DB and sync DB. Check DiffVisits will
+// return correct set of diff visits.
+TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) {
+ VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64_t visits_left[] = {1, 2, 1024, 1500, 2065,
+ 6000, 65534, 1237684, 2237684};
+ const int64_t visits_right[] = {1024, 2065, 65534, 1237684};
+
+ // DiffVisits will not remove the first visit, because we never delete visits
+ // from the start of the array (since those visits can get truncated by the
+ // size-limiting code).
+ const int64_t visits_removed[] = {1500, 6000, 2237684};
+
+ for (int64_t visit : visits_left) {
+ old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ }
+
+ for (int64_t visit : visits_right) {
+ new_url.add_visits(visit);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<VisitInfo> new_visits;
+ VisitVector removed_visits;
+
+ DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
+ EXPECT_TRUE(new_visits.empty());
+ ASSERT_EQ(removed_visits.size(), arraysize(visits_removed));
+ for (size_t i = 0; i < arraysize(visits_removed); ++i) {
+ EXPECT_EQ(removed_visits[i].visit_time.ToInternalValue(),
+ visits_removed[i]);
+ }
+}
+
+// Create two set of visits for history DB and sync DB. Check DiffVisits will
+// return correct set of diff visits.
+TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) {
+ VisitVector old_visits;
+ sync_pb::TypedUrlSpecifics new_url;
+
+ const int64_t visits_left[] = {1024, 2065, 65534, 1237684};
+ const int64_t visits_right[] = {1, 1024, 1500, 2065,
+ 6000, 65534, 1237684, 2237684};
+
+ const int64_t visits_added[] = {1, 1500, 6000, 2237684};
+
+ for (int64_t visit : visits_left) {
+ old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ }
+
+ for (int64_t visit : visits_right) {
+ new_url.add_visits(visit);
+ new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
+ }
+
+ std::vector<VisitInfo> new_visits;
+ VisitVector removed_visits;
+
+ DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
+ EXPECT_TRUE(removed_visits.empty());
+ ASSERT_TRUE(new_visits.size() == arraysize(visits_added));
+ for (size_t i = 0; i < arraysize(visits_added); ++i) {
+ EXPECT_EQ(new_visits[i].first.ToInternalValue(), visits_added[i]);
+ EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ new_visits[i].second, ui::PAGE_TRANSITION_TYPED));
+ }
+}
+
+// Create three visits, check RELOAD visit is removed by
+// WriteToTypedUrlSpecifics so it won't apply to sync DB.
+TEST_F(TypedURLSyncBridgeTest, WriteTypedUrlSpecifics) {
+ VisitVector visits;
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, 1));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, 2));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, 3));
+
+ URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 100, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // RELOAD visits should be removed.
+ EXPECT_EQ(2, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ EXPECT_EQ(1, typed_url.visits(0));
+ EXPECT_EQ(3, typed_url.visits(1));
+ EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED),
+ typed_url.visit_transitions(0));
+ EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_LINK),
+ typed_url.visit_transitions(1));
+}
+
+// Create 101 visits, check WriteToTypedUrlSpecifics will only keep 100 visits.
+TEST_F(TypedURLSyncBridgeTest, TooManyVisits) {
+ VisitVector visits;
+ int64_t timestamp = 1000;
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
+ for (int i = 0; i < 100; ++i) {
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
+ }
+ URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, timestamp++, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // # visits should be capped at 100.
+ EXPECT_EQ(100, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ EXPECT_EQ(1000, typed_url.visits(0));
+ // Visit with timestamp of 1001 should be omitted since we should have
+ // skipped that visit to stay under the cap.
+ EXPECT_EQ(1002, typed_url.visits(1));
+ EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED),
+ typed_url.visit_transitions(0));
+ EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_LINK),
+ typed_url.visit_transitions(1));
+}
+
+// Create 306 visits, check WriteToTypedUrlSpecifics will only keep 100 typed
+// visits.
+TEST_F(TypedURLSyncBridgeTest, TooManyTypedVisits) {
+ VisitVector visits;
+ int64_t timestamp = 1000;
+ for (int i = 0; i < 102; ++i) {
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, timestamp++));
+ visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, timestamp++));
+ }
+ URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, timestamp++, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ // # visits should be capped at 100.
+ EXPECT_EQ(100, typed_url.visits_size());
+ EXPECT_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
+ // First two typed visits should be skipped.
+ EXPECT_EQ(1006, typed_url.visits(0));
+
+ // Ensure there are no non-typed visits since that's all that should fit.
+ for (int i = 0; i < typed_url.visits_size(); ++i) {
+ EXPECT_EQ(static_cast<int32_t>(ui::PAGE_TRANSITION_TYPED),
+ typed_url.visit_transitions(i));
+ }
+}
+
+// Create a typed url without visit, check WriteToTypedUrlSpecifics will return
+// false for it.
+TEST_F(TypedURLSyncBridgeTest, NoTypedVisits) {
+ VisitVector visits;
+ URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 1000, false, &visits));
+ sync_pb::TypedUrlSpecifics typed_url;
+ EXPECT_FALSE(WriteToTypedUrlSpecifics(url, visits, &typed_url));
+ // URLs with no typed URL visits should not been written to specifics.
+ EXPECT_EQ(0, typed_url.visits_size());
+}
+
+TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
+ VisitVector visits1;
+ URLRow row1(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits1));
+ sync_pb::TypedUrlSpecifics specs1(
+ MakeTypedUrlSpecifics(kURL, kTitle, 3, false));
+ URLRow new_row1((GURL(kURL)));
+ std::vector<VisitInfo> new_visits1;
+ EXPECT_TRUE(TypedURLSyncBridgeTest::MergeUrls(specs1, row1, &visits1,
+ &new_row1, &new_visits1) ==
+ TypedURLSyncBridgeTest::DIFF_NONE);
+
+ VisitVector visits2;
+ URLRow row2(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits2));
+ sync_pb::TypedUrlSpecifics specs2(
+ MakeTypedUrlSpecifics(kURL, kTitle, 3, true));
+ VisitVector expected_visits2;
+ URLRow expected2(
+ MakeTypedUrlRow(kURL, kTitle, 2, 3, true, &expected_visits2));
+ URLRow new_row2((GURL(kURL)));
+ std::vector<VisitInfo> new_visits2;
+ EXPECT_TRUE(TypedURLSyncBridgeTest::MergeUrls(specs2, row2, &visits2,
+ &new_row2, &new_visits2) ==
+ TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED);
+ EXPECT_TRUE(URLsEqual(new_row2, expected2));
+
+ VisitVector visits3;
+ URLRow row3(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits3));
+ sync_pb::TypedUrlSpecifics specs3(
+ MakeTypedUrlSpecifics(kURL, kTitle2, 3, true));
+ VisitVector expected_visits3;
+ URLRow expected3(
+ MakeTypedUrlRow(kURL, kTitle2, 2, 3, true, &expected_visits3));
+ URLRow new_row3((GURL(kURL)));
+ std::vector<VisitInfo> new_visits3;
+ EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED |
+ TypedURLSyncBridgeTest::DIFF_NONE,
+ TypedURLSyncBridgeTest::MergeUrls(specs3, row3, &visits3, &new_row3,
+ &new_visits3));
+ EXPECT_TRUE(URLsEqual(new_row3, expected3));
+
+ // Create one node in history DB with timestamp of 3, and one node in sync
+ // DB with timestamp of 4. Result should contain one new item (4).
+ VisitVector visits4;
+ URLRow row4(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits4));
+ sync_pb::TypedUrlSpecifics specs4(
+ MakeTypedUrlSpecifics(kURL, kTitle2, 4, false));
+ VisitVector expected_visits4;
+ URLRow expected4(
+ MakeTypedUrlRow(kURL, kTitle2, 2, 4, false, &expected_visits4));
+ URLRow new_row4((GURL(kURL)));
+ std::vector<VisitInfo> new_visits4;
+ EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_UPDATE_NODE |
+ TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED |
+ TypedURLSyncBridgeTest::DIFF_LOCAL_VISITS_ADDED,
+ TypedURLSyncBridgeTest::MergeUrls(specs4, row4, &visits4, &new_row4,
+ &new_visits4));
+ EXPECT_EQ(1U, new_visits4.size());
+ EXPECT_EQ(specs4.visits(0), new_visits4[0].first.ToInternalValue());
+ EXPECT_TRUE(URLsEqual(new_row4, expected4));
+ EXPECT_EQ(2U, visits4.size());
+
+ VisitVector visits5;
+ URLRow row5(MakeTypedUrlRow(kURL, kTitle, 1, 4, false, &visits5));
+ sync_pb::TypedUrlSpecifics specs5(
+ MakeTypedUrlSpecifics(kURL, kTitle, 3, false));
+ VisitVector expected_visits5;
+ URLRow expected5(
+ MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &expected_visits5));
+ URLRow new_row5((GURL(kURL)));
+ std::vector<VisitInfo> new_visits5;
+
+ // UPDATE_NODE should be set because row5 has a newer last_visit timestamp.
+ EXPECT_EQ(TypedURLSyncBridgeTest::DIFF_UPDATE_NODE |
+ TypedURLSyncBridgeTest::DIFF_NONE,
+ TypedURLSyncBridgeTest::MergeUrls(specs5, row5, &visits5, &new_row5,
+ &new_visits5));
+ EXPECT_TRUE(URLsEqual(new_row5, expected5));
+ EXPECT_EQ(0U, new_visits5.size());
+}
+
+// Tests to ensure that we don't resurrect expired URLs (URLs that have been
+// deleted from the history DB but still exist in the sync DB).
+TEST_F(TypedURLSyncBridgeTest, MergeUrlsAfterExpiration) {
+ // First, create a history row that has two visits, with timestamps 2 and 3.
+ VisitVector(history_visits);
+ history_visits.push_back(VisitRow(0, base::Time::FromInternalValue(2), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ URLRow history_url(
+ MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &history_visits));
+
+ // Now, create a sync node with visits at timestamps 1, 2, 3, 4.
+ sync_pb::TypedUrlSpecifics node(
+ MakeTypedUrlSpecifics(kURL, kTitle, 1, false));
+ node.add_visits(2);
+ node.add_visits(3);
+ node.add_visits(4);
+ node.add_visit_transitions(2);
+ node.add_visit_transitions(3);
+ node.add_visit_transitions(4);
+ URLRow new_history_url(history_url.url());
+ std::vector<VisitInfo> new_visits;
+ EXPECT_EQ(
+ TypedURLSyncBridgeTest::DIFF_NONE |
+ TypedURLSyncBridgeTest::DIFF_LOCAL_VISITS_ADDED,
+ TypedURLSyncBridgeTest::MergeUrls(node, history_url, &history_visits,
+ &new_history_url, &new_visits));
+ EXPECT_TRUE(URLsEqual(history_url, new_history_url));
+ EXPECT_EQ(1U, new_visits.size());
+ EXPECT_EQ(4U, new_visits[0].first.ToInternalValue());
+ // We should not sync the visit with timestamp #1 since it is earlier than
+ // any other visit for this URL in the history DB. But we should sync visit
+ // #4.
+ EXPECT_EQ(3U, history_visits.size());
+ EXPECT_EQ(2U, history_visits[0].visit_time.ToInternalValue());
+ EXPECT_EQ(3U, history_visits[1].visit_time.ToInternalValue());
+ EXPECT_EQ(4U, history_visits[2].visit_time.ToInternalValue());
+}
+
+// Create a local typed URL with one expired TYPED visit,
+// MergeSyncData should not pass it to sync. And then add a non
+// expired visit, OnURLsModified should only send the non expired visit to sync.
+TEST_F(TypedURLSyncBridgeTest, LocalExpiredTypedUrlDoNotSync) {
+ URLRow row;
+ URLRows changed_urls;
+ VisitVector visits;
+
+ // Add an expired typed URL to local.
+ 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());
+
+ // 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);
+ // Notify typed url sync service of the update.
+ bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls);
+
+ // 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);
+
+ EXPECT_TRUE(URLsEqual(row, url_specifics));
+ ASSERT_EQ(1, url_specifics.visits_size());
+ ASSERT_EQ(static_cast<const int>(visits.size() - 1),
+ url_specifics.visits_size());
+ EXPECT_EQ(visits[1].visit_time.ToInternalValue(), url_specifics.visits(0));
+ EXPECT_EQ(static_cast<const int>(visits[1].transition),
+ url_specifics.visit_transitions(0));
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc b/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc
index 81e9da0a8e9..f216e89f1e5 100644
--- a/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc
+++ b/chromium/components/history/core/browser/typed_url_sync_metadata_database.cc
@@ -6,7 +6,6 @@
#include "base/big_endian.h"
#include "base/logging.h"
-#include "components/history/core/browser/url_row.h"
#include "sql/statement.h"
namespace history {
@@ -55,16 +54,10 @@ bool TypedURLSyncMetadataDatabase::UpdateSyncMetadata(
DCHECK_EQ(model_type, syncer::TYPED_URLS)
<< "Only the TYPED_URLS model type is supported";
- int64_t storage_key_int = 0;
- DCHECK_EQ(storage_key.size(), sizeof(storage_key_int));
- base::ReadBigEndian(storage_key.data(), &storage_key_int);
- // Make sure storage_key_int is set.
- DCHECK_NE(storage_key_int, 0);
-
sql::Statement s(GetDB().GetUniqueStatement(
"INSERT OR REPLACE INTO typed_url_sync_metadata "
"(storage_key, value) VALUES(?, ?)"));
- s.BindInt64(0, storage_key_int);
+ s.BindInt64(0, StorageKeyToURLID(storage_key));
s.BindString(1, metadata.SerializeAsString());
return s.Run();
@@ -76,15 +69,9 @@ bool TypedURLSyncMetadataDatabase::ClearSyncMetadata(
DCHECK_EQ(model_type, syncer::TYPED_URLS)
<< "Only the TYPED_URLS model type is supported";
- int64_t storage_key_int = 0;
- DCHECK_EQ(storage_key.size(), sizeof(storage_key_int));
- base::ReadBigEndian(storage_key.data(), &storage_key_int);
- // Make sure storage_key_int is set.
- DCHECK_NE(storage_key_int, 0);
-
sql::Statement s(GetDB().GetUniqueStatement(
"DELETE FROM typed_url_sync_metadata WHERE storage_key=?"));
- s.BindInt64(0, storage_key_int);
+ s.BindInt64(0, StorageKeyToURLID(storage_key));
return s.Run();
}
@@ -108,6 +95,17 @@ bool TypedURLSyncMetadataDatabase::ClearModelTypeState(
return GetMetaTable().DeleteKey(kTypedURLModelTypeStateKey);
}
+// static
+URLID TypedURLSyncMetadataDatabase::StorageKeyToURLID(
+ const std::string& storage_key) {
+ URLID storage_key_int = 0;
+ DCHECK_EQ(storage_key.size(), sizeof(storage_key_int));
+ base::ReadBigEndian(storage_key.data(), &storage_key_int);
+ // Make sure storage_key_int is set.
+ DCHECK_NE(storage_key_int, 0);
+ return storage_key_int;
+}
+
bool TypedURLSyncMetadataDatabase::InitSyncTable() {
if (!GetDB().DoesTableExist("typed_url_sync_metadata")) {
if (!GetDB().Execute("CREATE TABLE typed_url_sync_metadata ("
diff --git a/chromium/components/history/core/browser/typed_url_sync_metadata_database.h b/chromium/components/history/core/browser/typed_url_sync_metadata_database.h
index 6967f48642d..a48548cfd8f 100644
--- a/chromium/components/history/core/browser/typed_url_sync_metadata_database.h
+++ b/chromium/components/history/core/browser/typed_url_sync_metadata_database.h
@@ -6,6 +6,7 @@
#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_METADATA_DATABASE_H_
#include "base/macros.h"
+#include "components/history/core/browser/url_row.h"
#include "components/sync/base/model_type.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/sync_metadata_store.h"
@@ -43,6 +44,8 @@ class TypedURLSyncMetadataDatabase : public syncer::SyncMetadataStore {
const sync_pb::ModelTypeState& model_type_state) override;
bool ClearModelTypeState(syncer::ModelType model_type) override;
+ static URLID StorageKeyToURLID(const std::string& storage_key);
+
protected:
// Returns the database for the functions in this interface.
virtual sql::Connection& GetDB() = 0;
diff --git a/chromium/components/history/core/browser/web_history_service.cc b/chromium/components/history/core/browser/web_history_service.cc
index f2516b3010d..199ed0e1621 100644
--- a/chromium/components/history/core/browser/web_history_service.cc
+++ b/chromium/components/history/core/browser/web_history_service.cc
@@ -189,7 +189,7 @@ class RequestImpl : public WebHistoryService::Request,
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"To disable this feature, users can either sign out or disable "
"history sync via unchecking 'History' setting under 'Advanced "
diff --git a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
index 57806b0adba..428be06bc39 100644
--- a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
+++ b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
@@ -11,10 +11,6 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/image_fetcher/core/image_data_fetcher.h"
-namespace base {
-class TaskRunner;
-}
-
namespace net {
class URLRequestContextGetter;
}
@@ -34,9 +30,8 @@ class IOSImageDataFetcherWrapper {
using DataUseServiceName = data_use_measurement::DataUseUserData::ServiceName;
// The TaskRunner is used to decode the image if it is WebP-encoded.
- IOSImageDataFetcherWrapper(
- net::URLRequestContextGetter* url_request_context_getter,
- const scoped_refptr<base::TaskRunner>& task_runner);
+ explicit IOSImageDataFetcherWrapper(
+ net::URLRequestContextGetter* url_request_context_getter);
virtual ~IOSImageDataFetcherWrapper();
// Helper to start downloading and possibly decoding the image without a
@@ -63,8 +58,6 @@ class IOSImageDataFetcherWrapper {
ImageDataFetcher::ImageDataFetcherCallback CallbackForImageDataFetcher(
IOSImageDataFetcherCallback callback);
- // The task runner used to decode images if necessary.
- const scoped_refptr<base::TaskRunner> task_runner_;
ImageDataFetcher image_data_fetcher_;
DISALLOW_COPY_AND_ASSIGN(IOSImageDataFetcherWrapper);
diff --git a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.mm b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.mm
index 973abb755d6..6ba8b6a75b8 100644
--- a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.mm
+++ b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.mm
@@ -6,8 +6,7 @@
#import "base/mac/bind_objc_block.h"
#include "base/memory/ptr_util.h"
-#include "base/task_runner.h"
-#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
#import "components/image_fetcher/ios/webp_decoder.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
@@ -24,12 +23,8 @@
namespace image_fetcher {
IOSImageDataFetcherWrapper::IOSImageDataFetcherWrapper(
- net::URLRequestContextGetter* url_request_context_getter,
- const scoped_refptr<base::TaskRunner>& task_runner)
- : task_runner_(task_runner),
- image_data_fetcher_(url_request_context_getter) {
- DCHECK(task_runner_.get());
-}
+ net::URLRequestContextGetter* url_request_context_getter)
+ : image_data_fetcher_(url_request_context_getter) {}
IOSImageDataFetcherWrapper::~IOSImageDataFetcherWrapper() {}
@@ -61,8 +56,6 @@ void IOSImageDataFetcherWrapper::SetDataUseServiceName(
ImageDataFetcher::ImageDataFetcherCallback
IOSImageDataFetcherWrapper::CallbackForImageDataFetcher(
IOSImageDataFetcherCallback callback) {
- scoped_refptr<base::TaskRunner> task_runner = task_runner_;
-
return base::BindBlockArc(^(const std::string& image_data,
const RequestMetadata& metadata) {
// Create a NSData from the returned data and notify the callback.
@@ -77,12 +70,17 @@ IOSImageDataFetcherWrapper::CallbackForImageDataFetcher(
// The image is a webp image.
RequestMetadata webp_metadata = metadata;
- base::PostTaskAndReplyWithResult(
- task_runner.get(), FROM_HERE, base::BindBlockArc(^NSData*() {
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE,
+ {
+ base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+ },
+ base::BindBlockArc(^NSData*() {
return webp_transcode::WebpDecoder::DecodeWebpImage(data);
}),
- base::BindBlockArc(^(NSData* decodedData) {
- callback(decodedData, webp_metadata);
+ base::BindBlockArc(^(NSData* decoded_data) {
+ callback(decoded_data, webp_metadata);
}));
});
}
diff --git a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
index 27224a2aeef..6cedad9ca2b 100644
--- a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
+++ b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
@@ -11,8 +11,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -113,8 +112,8 @@ class IOSImageDataFetcherWrapperTest : public PlatformTest {
called_ = true;
} copy]) {
image_fetcher_ = base::MakeUnique<IOSImageDataFetcherWrapper>(
- new net::TestURLRequestContextGetter(message_loop_.task_runner()),
- message_loop_.task_runner());
+ new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get()));
}
net::TestURLFetcher* SetupFetcher() {
@@ -128,7 +127,7 @@ class IOSImageDataFetcherWrapperTest : public PlatformTest {
}
// Message loop for the main test thread.
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment environment_;
base::mac::ScopedBlock<IOSImageDataFetcherCallback> callback_;
net::TestURLFetcherFactory factory_;
@@ -178,7 +177,7 @@ TEST_F(IOSImageDataFetcherWrapperTest, TestGoodWebP) {
std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
fetcher->set_response_headers(headers);
fetcher->delegate()->OnURLFetchComplete(fetcher);
- base::RunLoop().RunUntilIdle();
+ environment_.RunUntilIdle();
EXPECT_NE(nil, result_);
EXPECT_TRUE(called_);
}
@@ -189,7 +188,7 @@ TEST_F(IOSImageDataFetcherWrapperTest, TestGoodWebPNoHeader) {
fetcher->SetResponseString(std::string(
reinterpret_cast<const char*>(kWEBPImage), sizeof(kWEBPImage)));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- base::RunLoop().RunUntilIdle();
+ environment_.RunUntilIdle();
EXPECT_TRUE([DecodedWebpImage() isEqualToData:result_data_]);
EXPECT_TRUE(called_);
}
@@ -202,7 +201,7 @@ TEST_F(IOSImageDataFetcherWrapperTest, TestBadWebP) {
std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
fetcher->set_response_headers(headers);
fetcher->delegate()->OnURLFetchComplete(fetcher);
- base::RunLoop().RunUntilIdle();
+ environment_.RunUntilIdle();
EXPECT_EQ(nil, result_);
EXPECT_TRUE(called_);
}
@@ -215,7 +214,7 @@ TEST_F(IOSImageDataFetcherWrapperTest, DeleteDuringWebPDecoding) {
fetcher->delegate()->OnURLFetchComplete(fetcher);
// Delete the image fetcher, and check that the callback is called.
image_fetcher_.reset();
- base::RunLoop().RunUntilIdle();
+ environment_.RunUntilIdle();
EXPECT_TRUE([DecodedWebpImage() isEqualToData:result_data_]);
EXPECT_TRUE(called_);
}
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
index 2bb5db145d5..da7398ce40f 100644
--- a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
@@ -5,18 +5,14 @@
#ifndef COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
#define COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
-#include "base/memory/ref_counted.h"
-#include "components/image_fetcher/core/image_decoder.h"
+#include <memory>
-namespace base {
-class TaskRunner;
-}
+#include "components/image_fetcher/core/image_decoder.h"
namespace image_fetcher {
// Factory for iOS specific implementation of ImageDecoder.
-std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
- scoped_refptr<base::TaskRunner> task_runner);
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder();
} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
index 38edf0b6fde..0b9bce1ac7d 100644
--- a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
+#include "base/task_scheduler/post_task.h"
#import "components/image_fetcher/ios/webp_decoder.h"
#include "ios/web/public/web_thread.h"
#include "ui/gfx/geometry/size.h"
@@ -24,7 +25,7 @@ namespace image_fetcher {
class IOSImageDecoderImpl : public ImageDecoder {
public:
- explicit IOSImageDecoderImpl(scoped_refptr<base::TaskRunner> task_runner);
+ explicit IOSImageDecoderImpl();
~IOSImageDecoderImpl() override;
// Note, that |desired_image_frame_size| is not supported
@@ -38,7 +39,11 @@ class IOSImageDecoderImpl : public ImageDecoder {
NSData* image_data);
// The task runner used to decode images if necessary.
- const scoped_refptr<base::TaskRunner> task_runner_;
+ const scoped_refptr<base::TaskRunner> task_runner_ =
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+ ;
// The WeakPtrFactory is used to cancel callbacks if ImageFetcher is
// destroyed during WebP decoding.
@@ -47,9 +52,7 @@ class IOSImageDecoderImpl : public ImageDecoder {
DISALLOW_COPY_AND_ASSIGN(IOSImageDecoderImpl);
};
-IOSImageDecoderImpl::IOSImageDecoderImpl(
- scoped_refptr<base::TaskRunner> task_runner)
- : task_runner_(std::move(task_runner)), weak_factory_(this) {
+IOSImageDecoderImpl::IOSImageDecoderImpl() : weak_factory_(this) {
DCHECK(task_runner_.get());
}
@@ -102,9 +105,8 @@ void IOSImageDecoderImpl::CreateUIImageAndRunCallback(
callback.Run(empty_image);
}
-std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
- scoped_refptr<base::TaskRunner> task_runner) {
- return base::MakeUnique<IOSImageDecoderImpl>(std::move(task_runner));
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder() {
+ return base::MakeUnique<IOSImageDecoderImpl>();
}
} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
index 29da4e9ecdf..278e1bbf712 100644
--- a/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
@@ -8,10 +8,7 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "ui/gfx/geometry/size.h"
@@ -62,17 +59,13 @@ class IOSImageDecoderImplTest : public PlatformTest {
void OnImageDecoded(const gfx::Image& image) { decoded_image_ = image; }
protected:
- IOSImageDecoderImplTest()
- : pool_(new base::SequencedWorkerPool(2,
- "TestPool",
- base::TaskPriority::USER_VISIBLE)) {
- ios_image_decoder_impl_ = CreateIOSImageDecoder(pool_);
+ IOSImageDecoderImplTest() {
+ ios_image_decoder_impl_ = CreateIOSImageDecoder();
}
- ~IOSImageDecoderImplTest() override { pool_->Shutdown(); }
+ ~IOSImageDecoderImplTest() override {}
- base::MessageLoop loop_;
- scoped_refptr<base::SequencedWorkerPool> pool_;
+ base::test::ScopedTaskEnvironment scoped_task_evironment_;
std::unique_ptr<ImageDecoder> ios_image_decoder_impl_;
gfx::Image decoded_image_;
@@ -88,8 +81,7 @@ TEST_F(IOSImageDecoderImplTest, JPGImage) {
base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
base::Unretained(this)));
- pool_->FlushForTesting();
- base::RunLoop().RunUntilIdle();
+ scoped_task_evironment_.RunUntilIdle();
EXPECT_FALSE(decoded_image_.IsEmpty());
}
@@ -104,8 +96,7 @@ TEST_F(IOSImageDecoderImplTest, WebpImage) {
base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
base::Unretained(this)));
- pool_->FlushForTesting();
- base::RunLoop().RunUntilIdle();
+ scoped_task_evironment_.RunUntilIdle();
EXPECT_FALSE(decoded_image_.IsEmpty());
}
diff --git a/chromium/components/infobars/core/infobar_delegate.h b/chromium/components/infobars/core/infobar_delegate.h
index 1405106b3c7..398cee4f1dd 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -127,7 +127,7 @@ class InfoBarDelegate {
// Removed: NATIVE_APP_OPEN_POLICY_INFOBAR_DELEGATE = 54,
RE_SIGN_IN_INFOBAR_DELEGATE = 55,
SHOW_PASSKIT_INFOBAR_ERROR_DELEGATE = 56,
- READER_MODE_INFOBAR_DELEGATE_IOS = 57,
+ // Removed: READER_MODE_INFOBAR_DELEGATE_IOS = 57,
SYNC_ERROR_INFOBAR_DELEGATE = 58,
UPGRADE_INFOBAR_DELEGATE_IOS = 59,
CHROME_WINDOW_ERROR = 60,
diff --git a/chromium/components/invalidation/impl/BUILD.gn b/chromium/components/invalidation/impl/BUILD.gn
index 9b74d43f16b..ac43ff82d12 100644
--- a/chromium/components/invalidation/impl/BUILD.gn
+++ b/chromium/components/invalidation/impl/BUILD.gn
@@ -235,6 +235,7 @@ if (is_android) {
"//third_party/android_support_test_runner:runner_java",
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
+ "//third_party/junit",
]
java_files = [
"android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java",
diff --git a/chromium/components/keyed_service/core/dependency_graph.cc b/chromium/components/keyed_service/core/dependency_graph.cc
index 3a4a5a1456e..8d500f6851c 100644
--- a/chromium/components/keyed_service/core/dependency_graph.cc
+++ b/chromium/components/keyed_service/core/dependency_graph.cc
@@ -7,9 +7,10 @@
#include <stddef.h>
#include <algorithm>
-#include <deque>
#include <iterator>
+#include "base/containers/circular_deque.h"
+#include "base/stl_util.h"
#include "base/strings/string_piece.h"
namespace {
@@ -46,8 +47,7 @@ void DependencyGraph::AddNode(DependencyNode* node) {
}
void DependencyGraph::RemoveNode(DependencyNode* node) {
- all_nodes_.erase(std::remove(all_nodes_.begin(), all_nodes_.end(), node),
- all_nodes_.end());
+ base::Erase(all_nodes_, node);
// Remove all dependency edges that contain this node.
EdgeMap::iterator it = edges_.begin();
@@ -91,14 +91,10 @@ bool DependencyGraph::GetDestructionOrder(std::vector<DependencyNode*>* order) {
bool DependencyGraph::BuildConstructionOrder() {
// Step 1: Build a set of nodes with no incoming edges.
- std::deque<DependencyNode*> queue;
- std::copy(all_nodes_.begin(), all_nodes_.end(), std::back_inserter(queue));
-
- std::deque<DependencyNode*>::iterator queue_end = queue.end();
- for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
- queue_end = std::remove(queue.begin(), queue_end, it->second);
- }
- queue.erase(queue_end, queue.end());
+ base::circular_deque<DependencyNode*> queue(all_nodes_.begin(),
+ all_nodes_.end());
+ for (const auto& pair : edges_)
+ base::Erase(queue, pair.second);
// Step 2: Do the Kahn topological sort.
std::vector<DependencyNode*> output;
@@ -147,32 +143,28 @@ std::string DependencyGraph::DumpAsGraphviz(
std::string escaped_toplevel_name = Escape(toplevel_name);
// Make a copy of all nodes.
- std::deque<DependencyNode*> nodes;
- std::copy(all_nodes_.begin(), all_nodes_.end(), std::back_inserter(nodes));
+ base::circular_deque<DependencyNode*> nodes(all_nodes_.begin(),
+ all_nodes_.end());
// State all dependencies and remove |second| so we don't generate an
// implicit dependency on the top level node.
- std::deque<DependencyNode*>::iterator nodes_end(nodes.end());
result.append(" /* Dependencies */\n");
- for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
+ for (const auto& pair : edges_) {
result.append(" ");
- result.append(Escape(node_name_callback.Run(it->second)));
+ result.append(Escape(node_name_callback.Run(pair.second)));
result.append(" -> ");
- result.append(Escape(node_name_callback.Run(it->first)));
+ result.append(Escape(node_name_callback.Run(pair.first)));
result.append(";\n");
- nodes_end = std::remove(nodes.begin(), nodes_end, it->second);
+ base::Erase(nodes, pair.second);
}
- nodes.erase(nodes_end, nodes.end());
// Every node that doesn't depend on anything else will implicitly depend on
// the top level node.
result.append("\n /* Toplevel attachments */\n");
- for (std::deque<DependencyNode*>::const_iterator it = nodes.begin();
- it != nodes.end();
- ++it) {
+ for (DependencyNode* node : nodes) {
result.append(" ");
- result.append(Escape(node_name_callback.Run(*it)));
+ result.append(Escape(node_name_callback.Run(node)));
result.append(" -> ");
result.append(escaped_toplevel_name);
result.append(";\n");
diff --git a/chromium/components/keyed_service/core/keyed_service_base_factory.h b/chromium/components/keyed_service/core/keyed_service_base_factory.h
index 94d01d77c7b..0c6d7c59e68 100644
--- a/chromium/components/keyed_service/core/keyed_service_base_factory.h
+++ b/chromium/components/keyed_service/core/keyed_service_base_factory.h
@@ -28,8 +28,7 @@ class PrefRegistrySyncable;
//
// This object describes general dependency management between factories while
// direct subclasses react to lifecycle events and implement memory management.
-class KEYED_SERVICE_EXPORT KeyedServiceBaseFactory
- : NON_EXPORTED_BASE(public DependencyNode) {
+class KEYED_SERVICE_EXPORT KeyedServiceBaseFactory : public DependencyNode {
public:
#ifndef NDEBUG
// Returns our name. We don't keep track of this in release mode.
diff --git a/chromium/components/language/OWNERS b/chromium/components/language/OWNERS
index 019412ab7e6..809be594046 100644
--- a/chromium/components/language/OWNERS
+++ b/chromium/components/language/OWNERS
@@ -1,3 +1,4 @@
+dvallet@chromium.org
sammc@chromium.org
# TEAM: language@chromium.org
diff --git a/chromium/components/leveldb/OWNERS b/chromium/components/leveldb/OWNERS
index 0b74fef95fe..6b664e63ebf 100644
--- a/chromium/components/leveldb/OWNERS
+++ b/chromium/components/leveldb/OWNERS
@@ -1,2 +1,8 @@
erg@chromium.org
mek@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file test_manifest.json=set noparent
+per-file test_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/leveldb/leveldb_service_impl.cc b/chromium/components/leveldb/leveldb_service_impl.cc
index a6406166403..6707026c31a 100644
--- a/chromium/components/leveldb/leveldb_service_impl.cc
+++ b/chromium/components/leveldb/leveldb_service_impl.cc
@@ -47,14 +47,13 @@ void LevelDBServiceImpl::OpenWithOptions(
memory_dump_id,
leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
OpenCallback callback) {
- leveldb::Options options;
+ leveldb_env::Options options;
options.create_if_missing = open_options->create_if_missing;
options.error_if_exists = open_options->error_if_exists;
options.paranoid_checks = open_options->paranoid_checks;
options.write_buffer_size = open_options->write_buffer_size;
options.max_open_files = open_options->max_open_files;
- options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
options.compression = leveldb::kSnappyCompression;
// Register our directory with the file thread.
@@ -64,18 +63,23 @@ void LevelDBServiceImpl::OpenWithOptions(
std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir));
options.env = env_mojo.get();
- std::unique_ptr<leveldb::Cache> cache(
- leveldb::NewLRUCache(open_options->block_cache_size));
- options.block_cache = cache.get();
+ switch (open_options->shared_block_read_cache) {
+ case leveldb::mojom::SharedReadCache::Web:
+ options.block_cache = leveldb_env::SharedWebBlockCache();
+ break;
+ case leveldb::mojom::SharedReadCache::Default:
+ // fallthrough
+ break;
+ }
std::unique_ptr<leveldb::DB> db;
leveldb::Status s = leveldb_env::OpenDB(options, dbname, &db);
if (s.ok()) {
- mojo::MakeStrongAssociatedBinding(base::MakeUnique<LevelDBDatabaseImpl>(
- std::move(env_mojo), std::move(db),
- std::move(cache), memory_dump_id),
- std::move(database));
+ mojo::MakeStrongAssociatedBinding(
+ base::MakeUnique<LevelDBDatabaseImpl>(
+ std::move(env_mojo), std::move(db), nullptr, memory_dump_id),
+ std::move(database));
}
std::move(callback).Run(LeveldbStatusToError(s));
@@ -86,7 +90,7 @@ void LevelDBServiceImpl::OpenInMemory(
memory_dump_id,
leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
OpenCallback callback) {
- leveldb::Options options;
+ leveldb_env::Options options;
options.create_if_missing = true;
options.max_open_files = 0; // Use minimum.
@@ -110,7 +114,7 @@ void LevelDBServiceImpl::OpenInMemory(
void LevelDBServiceImpl::Destroy(filesystem::mojom::DirectoryPtr directory,
const std::string& dbname,
DestroyCallback callback) {
- leveldb::Options options;
+ leveldb_env::Options options;
// Register our directory with the file thread.
LevelDBMojoProxy::OpaqueDir* dir =
thread_->RegisterDirectory(std::move(directory));
diff --git a/chromium/components/leveldb/public/cpp/util.cc b/chromium/components/leveldb/public/cpp/util.cc
index 5ca6864bfb5..d20044d90cf 100644
--- a/chromium/components/leveldb/public/cpp/util.cc
+++ b/chromium/components/leveldb/public/cpp/util.cc
@@ -46,7 +46,8 @@ leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e,
return leveldb::Status::InvalidArgument(msg, msg2);
}
-int GetLevelDBStatusUMAValue(mojom::DatabaseError status) {
+leveldb_env::LevelDBStatusValue GetLevelDBStatusUMAValue(
+ mojom::DatabaseError status) {
switch (status) {
case mojom::DatabaseError::OK:
return leveldb_env::LEVELDB_STATUS_OK;
diff --git a/chromium/components/leveldb/public/cpp/util.h b/chromium/components/leveldb/public/cpp/util.h
index 1054cad126d..4a5618f81fc 100644
--- a/chromium/components/leveldb/public/cpp/util.h
+++ b/chromium/components/leveldb/public/cpp/util.h
@@ -6,6 +6,7 @@
#define COMPONENTS_LEVELDB_PUBLIC_CPP_UTIL_H_
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
+#include "third_party/leveldatabase/env_chromium.h"
namespace leveldb {
@@ -23,7 +24,8 @@ leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e,
const Slice& msg2);
// Returns an UMA value for a mojom::DatabaseError.
-int GetLevelDBStatusUMAValue(mojom::DatabaseError status);
+leveldb_env::LevelDBStatusValue GetLevelDBStatusUMAValue(
+ mojom::DatabaseError status);
// Builds a Slice pointing to the data inside |a|. This is not a type-converter
// as it is not a copy operation; the returned Slice points into |a| and must
diff --git a/chromium/components/leveldb/public/interfaces/leveldb.mojom b/chromium/components/leveldb/public/interfaces/leveldb.mojom
index 938bd730d4a..e7f6ca4bd0f 100644
--- a/chromium/components/leveldb/public/interfaces/leveldb.mojom
+++ b/chromium/components/leveldb/public/interfaces/leveldb.mojom
@@ -34,6 +34,11 @@ struct KeyValue {
array<uint8> value;
};
+enum SharedReadCache {
+ Default,
+ Web,
+};
+
// Options which control the behavior of a database. (This struct corresponds
// with the struct in leveldb's options.h.)
struct OpenOptions {
@@ -60,8 +65,7 @@ struct OpenOptions {
// details.)
int32 max_open_files = 80;
- // Default size is 8 megabytes.
- uint64 block_cache_size = 8388608;
+ SharedReadCache shared_block_read_cache = SharedReadCache.Default;
};
// Service which hands out databases.
diff --git a/chromium/components/leveldb_proto/leveldb_database.cc b/chromium/components/leveldb_proto/leveldb_database.cc
index 073dbec3f51..3317e2af588 100644
--- a/chromium/components/leveldb_proto/leveldb_database.cc
+++ b/chromium/components/leveldb_proto/leveldb_database.cc
@@ -4,22 +4,14 @@
#include "components/leveldb_proto/leveldb_database.h"
-#include <inttypes.h>
-
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram.h"
-#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_checker.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/cache.h"
@@ -36,28 +28,25 @@ namespace leveldb_proto {
// static
bool LevelDB::Destroy(const base::FilePath& database_dir) {
const leveldb::Status s =
- leveldb::DestroyDB(database_dir.AsUTF8Unsafe(), leveldb::Options());
+ leveldb::DestroyDB(database_dir.AsUTF8Unsafe(), leveldb_env::Options());
return s.ok();
}
-LevelDB::LevelDB(const char* client_name)
- : open_histogram_(nullptr), client_name_(client_name) {
+LevelDB::LevelDB(const char* client_name) : open_histogram_(nullptr) {
// Used in lieu of UMA_HISTOGRAM_ENUMERATION because the histogram name is
// not a constant.
open_histogram_ = base::LinearHistogram::FactoryGet(
- std::string("LevelDB.Open.") + client_name_, 1,
+ std::string("LevelDB.Open.") + client_name, 1,
leveldb_env::LEVELDB_STATUS_MAX, leveldb_env::LEVELDB_STATUS_MAX + 1,
base::Histogram::kUmaTargetedHistogramFlag);
}
LevelDB::~LevelDB() {
DFAKE_SCOPED_LOCK(thread_checker_);
- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- this);
}
bool LevelDB::InitWithOptions(const base::FilePath& database_dir,
- const leveldb::Options& options) {
+ const leveldb_env::Options& options) {
DFAKE_SCOPED_LOCK(thread_checker_);
std::string path = database_dir.AsUTF8Unsafe();
@@ -70,46 +59,28 @@ bool LevelDB::InitWithOptions(const base::FilePath& database_dir,
status = leveldb_env::OpenDB(options, path, &db_);
}
- if (status.ok()) {
- base::trace_event::MemoryDumpManager::GetInstance()
- ->RegisterDumpProviderWithSequencedTaskRunner(
- this, "LevelDB", base::SequencedTaskRunnerHandle::Get(),
- base::trace_event::MemoryDumpProvider::Options());
+ if (status.ok())
return true;
- }
LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
<< status.ToString();
return false;
}
-static size_t DefaultBlockCacheSize() {
- if (base::SysInfo::IsLowEndDevice())
- return 512 * 1024; // 512KB
- else
- return 8 * 1024 * 1024; // 8MB
-}
-
bool LevelDB::Init(const leveldb_proto::Options& options) {
- leveldb::Options leveldb_options;
+ leveldb_env::Options leveldb_options;
leveldb_options.create_if_missing = true;
leveldb_options.max_open_files = 0; // Use minimum.
- leveldb_options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
-
- static leveldb::Cache* default_block_cache =
- leveldb::NewLRUCache(DefaultBlockCacheSize());
if (options.write_buffer_size != 0)
leveldb_options.write_buffer_size = options.write_buffer_size;
- if (options.read_cache_size != 0) {
- custom_block_cache_.reset(leveldb::NewLRUCache(options.read_cache_size));
- leveldb_options.block_cache = custom_block_cache_.get();
- } else {
- // By default, allocate a single block cache to be shared across
- // all LevelDB instances created via this method.
- // See also content/browser/indexed_db/leveldb/leveldb_database.cc,
- // which has its own shared block cache for IndexedDB databases.
- leveldb_options.block_cache = default_block_cache;
+ switch (options.shared_cache) {
+ case leveldb_env::SharedReadCache::Web:
+ leveldb_options.block_cache = leveldb_env::SharedWebBlockCache();
+ break;
+ case leveldb_env::SharedReadCache::Default:
+ // fallthrough
+ break;
}
if (options.database_dir.empty()) {
env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
@@ -195,36 +166,4 @@ bool LevelDB::Get(const std::string& key, bool* found, std::string* entry) {
return false;
}
-bool LevelDB::OnMemoryDump(const base::trace_event::MemoryDumpArgs& dump_args,
- base::trace_event::ProcessMemoryDump* pmd) {
- DFAKE_SCOPED_LOCK(thread_checker_);
- if (!db_)
- return false;
-
- std::string value;
- uint64_t size;
- bool res = db_->GetProperty("leveldb.approximate-memory-usage", &value);
- DCHECK(res);
- res = base::StringToUint64(value, &size);
- DCHECK(res);
-
- base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
- base::StringPrintf("leveldb/leveldb_proto/0x%" PRIXPTR,
- reinterpret_cast<uintptr_t>(db_.get())));
- dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
- if (!client_name_.empty() &&
- dump_args.level_of_detail !=
- base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
- dump->AddString("client_name", "", client_name_);
- }
-
- // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
- // an edge to avoid double counting.
- pmd->AddSuballocation(dump->guid(),
- leveldb_env::DBTracker::GetMemoryDumpName(db_.get()));
-
- return true;
-}
-
} // namespace leveldb_proto
diff --git a/chromium/components/leveldb_proto/leveldb_database.h b/chromium/components/leveldb_proto/leveldb_database.h
index 562e6a54dff..f01bf14a417 100644
--- a/chromium/components/leveldb_proto/leveldb_database.h
+++ b/chromium/components/leveldb_proto/leveldb_database.h
@@ -13,8 +13,8 @@
#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/threading/thread_collision_warner.h"
-#include "base/trace_event/memory_dump_provider.h"
#include "components/leveldb_proto/options.h"
+#include "third_party/leveldatabase/env_chromium.h"
namespace base {
class FilePath;
@@ -33,14 +33,14 @@ namespace leveldb_proto {
// Interacts with the LevelDB third party module.
// Once constructed, function calls and destruction should all occur on the
// same thread (not necessarily the same as the constructor).
-class LevelDB : public base::trace_event::MemoryDumpProvider {
+class LevelDB {
public:
// Constructor. Does *not* open a leveldb - only initialize this class.
// |client_name| is the name of the "client" that owns this instance. Used
// for UMA statics as so: LevelDB.<value>.<client name>. It is best to not
// change once shipped.
explicit LevelDB(const char* client_name);
- ~LevelDB() override;
+ virtual ~LevelDB();
// Initializes a leveldb with the given options. If |options.database_dir| is
// empty, this opens an in-memory db.
@@ -54,13 +54,9 @@ class LevelDB : public base::trace_event::MemoryDumpProvider {
static bool Destroy(const base::FilePath& database_dir);
- // base::trace_event::MemoryDumpProvider implementation.
- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& dump_args,
- base::trace_event::ProcessMemoryDump* pmd) override;
-
protected:
virtual bool InitWithOptions(const base::FilePath& database_dir,
- const leveldb::Options& options);
+ const leveldb_env::Options& options);
private:
FRIEND_TEST_ALL_PREFIXES(ProtoDatabaseImplLevelDBTest, TestDBInitFail);
@@ -73,8 +69,6 @@ class LevelDB : public base::trace_event::MemoryDumpProvider {
std::unique_ptr<leveldb::Cache> custom_block_cache_;
std::unique_ptr<leveldb::DB> db_;
base::HistogramBase* open_histogram_;
- // Name of the client shown in chrome://tracing.
- std::string client_name_;
DISALLOW_COPY_AND_ASSIGN(LevelDB);
};
diff --git a/chromium/components/leveldb_proto/options.h b/chromium/components/leveldb_proto/options.h
index 07cd18a2a76..7b8e21ef0ce 100644
--- a/chromium/components/leveldb_proto/options.h
+++ b/chromium/components/leveldb_proto/options.h
@@ -6,25 +6,21 @@
#define COMPONENTS_LEVELDB_PROTO_OPTIONS_H_
#include "base/files/file_path.h"
+#include "third_party/leveldatabase/env_chromium.h"
namespace leveldb_proto {
struct Options {
- // If read_cache_size is specified, a segregated block cache will be
- // created for this LevelDB instance. Otherwise a shared block cache
- // will be used.
- Options(const base::FilePath& database_dir)
- : database_dir(database_dir), write_buffer_size(0), read_cache_size(0) {}
Options(const base::FilePath& database_dir,
- size_t write_buffer_size,
- size_t read_cache_size)
+ leveldb_env::SharedReadCache shared_cache,
+ size_t write_buffer_size = 0)
: database_dir(database_dir),
- write_buffer_size(write_buffer_size),
- read_cache_size(read_cache_size) {}
+ shared_cache(shared_cache),
+ write_buffer_size(write_buffer_size) {}
base::FilePath database_dir;
+ leveldb_env::SharedReadCache shared_cache;
size_t write_buffer_size;
- size_t read_cache_size;
};
} // namespace leveldb_proto
diff --git a/chromium/components/leveldb_proto/proto_database.h b/chromium/components/leveldb_proto/proto_database.h
index a43b20deaa8..a4a8438b178 100644
--- a/chromium/components/leveldb_proto/proto_database.h
+++ b/chromium/components/leveldb_proto/proto_database.h
@@ -45,7 +45,10 @@ class ProtoDatabase {
void Init(const char* client_name,
const base::FilePath& database_dir,
InitCallback callback) {
- InitWithOptions(client_name, Options(database_dir), std::move(callback));
+ InitWithOptions(
+ client_name,
+ Options(database_dir, leveldb_env::SharedReadCache::Default),
+ std::move(callback));
}
// Similar to Init, but takes additional options.
diff --git a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
index 691d774d47a..38915b9aa16 100644
--- a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -18,16 +18,16 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
#include "components/leveldb_proto/leveldb_database.h"
#include "components/leveldb_proto/testing/proto/test.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/options.h"
using base::MessageLoop;
using base::ScopedTempDir;
+using leveldb_env::SharedReadCache;
using testing::Invoke;
using testing::Return;
using testing::UnorderedElementsAre;
@@ -125,13 +125,14 @@ TEST_F(ProtoDatabaseImplTest, TestDBInitSuccess) {
base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
MockDB* mock_db = new MockDB();
- EXPECT_CALL(*mock_db, Init(Options(path))).WillOnce(Return(true));
+ EXPECT_CALL(*mock_db, Init(Options(path, SharedReadCache::Default)))
+ .WillOnce(Return(true));
MockDatabaseCaller caller;
EXPECT_CALL(caller, InitCallback(true));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
base::RunLoop().RunUntilIdle();
@@ -141,13 +142,14 @@ TEST_F(ProtoDatabaseImplTest, TestDBInitFailure) {
base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
MockDB* mock_db = new MockDB();
- EXPECT_CALL(*mock_db, Init(Options(path))).WillOnce(Return(false));
+ EXPECT_CALL(*mock_db, Init(Options(path, SharedReadCache::Default)))
+ .WillOnce(Return(false));
MockDatabaseCaller caller;
EXPECT_CALL(caller, InitCallback(false));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
base::RunLoop().RunUntilIdle();
@@ -180,7 +182,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model));
@@ -201,7 +203,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false));
@@ -241,7 +243,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetSuccess) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
std::string key("1");
@@ -315,7 +317,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetNotFound) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
std::string key("does_not_exist");
@@ -338,7 +340,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetFailure) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
std::string key("does_not_exist");
@@ -383,7 +385,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBSaveSuccess) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
@@ -414,7 +416,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBSaveFailure) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
@@ -439,7 +441,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBRemoveSuccess) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
@@ -470,7 +472,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBRemoveFailure) {
EXPECT_CALL(*mock_db, Init(_));
EXPECT_CALL(caller, InitCallback(_));
db_->InitWithDatabase(
- base::WrapUnique(mock_db), path,
+ base::WrapUnique(mock_db), Options(path, SharedReadCache::Default),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
@@ -546,8 +548,6 @@ TEST(ProtoDatabaseImplThreadingTest, TestDBDestroy) {
// entries. If |close_after_save| is true, the database will be closed after
// saving and then re-opened to ensure that the data is properly persisted.
void TestLevelDBSaveAndLoad(bool close_after_save) {
- base::MessageLoop main_loop;
-
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
@@ -563,12 +563,13 @@ void TestLevelDBSaveAndLoad(bool close_after_save) {
}
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
- EXPECT_TRUE(db->Init(temp_dir.GetPath()));
+ EXPECT_TRUE(db->Init(Options(temp_dir.GetPath(), SharedReadCache::Default)));
EXPECT_TRUE(db->Save(save_entries, remove_keys));
if (close_after_save) {
db.reset(new LevelDB(kTestLevelDBClientName));
- EXPECT_TRUE(db->Init(temp_dir.GetPath()));
+ EXPECT_TRUE(
+ db->Init(Options(temp_dir.GetPath(), SharedReadCache::Default)));
}
EXPECT_TRUE(db->Load(&load_entries));
@@ -596,7 +597,7 @@ TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- leveldb::Options options;
+ leveldb_env::Options options;
options.create_if_missing = false;
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
@@ -610,13 +611,11 @@ TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
}
TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
- base::MessageLoop main_loop;
-
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
std::vector<std::string> load_entries;
- ASSERT_TRUE(db->Init(base::FilePath()));
+ ASSERT_TRUE(db->Init(Options(base::FilePath(), SharedReadCache::Default)));
ASSERT_TRUE(db->Load(&load_entries));
EXPECT_EQ(0u, load_entries.size());
@@ -632,28 +631,4 @@ TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
EXPECT_EQ(1u, second_load_entries.size());
}
-TEST(ProtoDatabaseImplLevelDBTest, TestOnMemoryDumpEmitsData) {
- base::MessageLoop main_loop;
- std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
- std::vector<std::string> load_entries;
- ASSERT_TRUE(db->Init(base::FilePath()));
- KeyValueVector save_entries(1, std::make_pair("foo", "bar"));
- KeyVector remove_keys;
- ASSERT_TRUE(db->Save(save_entries, remove_keys));
-
- base::trace_event::MemoryDumpArgs dump_args = {
- base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
- std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
- new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
- db->OnMemoryDump(dump_args, process_memory_dump.get());
-
- size_t leveldb_dump_count = 0;
- for (const auto& dump : process_memory_dump->allocator_dumps()) {
- if (dump.first.find("leveldb/leveldb_proto/") == 0) {
- leveldb_dump_count++;
- }
- }
- ASSERT_EQ(1u, leveldb_dump_count);
-}
-
} // namespace leveldb_proto
diff --git a/chromium/components/login/base_screen_handler_utils.h b/chromium/components/login/base_screen_handler_utils.h
index fbb74d35d0f..e6224fb31dd 100644
--- a/chromium/components/login/base_screen_handler_utils.h
+++ b/chromium/components/login/base_screen_handler_utils.h
@@ -9,11 +9,11 @@
#include <cstddef>
#include <string>
+#include <utility>
#include "base/callback.h"
#include "base/logging.h"
#include "base/strings/string16.h"
-#include "base/tuple.h"
#include "base/values.h"
#include "components/login/login_export.h"
#include "components/signin/core/account_id/account_id.h"
@@ -86,7 +86,7 @@ typename UnwrapConstRef<Arg>::Type ParseArg(const base::ListValue* args) {
template <typename... Args, size_t... Ns>
inline void DispatchToCallback(const base::Callback<void(Args...)>& callback,
const base::ListValue* args,
- base::IndexSequence<Ns...> indexes) {
+ std::index_sequence<Ns...> indexes) {
DCHECK(args);
DCHECK_EQ(sizeof...(Args), args->GetSize());
@@ -96,8 +96,7 @@ inline void DispatchToCallback(const base::Callback<void(Args...)>& callback,
template <typename... Args>
void CallbackWrapper(const base::Callback<void(Args...)>& callback,
const base::ListValue* args) {
- DispatchToCallback(callback, args,
- base::MakeIndexSequence<sizeof...(Args)>());
+ DispatchToCallback(callback, args, std::index_sequence_for<Args...>());
}
diff --git a/chromium/components/login/screens/screen_context.cc b/chromium/components/login/screens/screen_context.cc
index 343570b87f8..f1ebd76d72f 100644
--- a/chromium/components/login/screens/screen_context.cc
+++ b/chromium/components/login/screens/screen_context.cc
@@ -179,7 +179,7 @@ bool ScreenContext::Set(const KeyType& key, base::Value* value) {
if (in_storage && new_value->Equals(current_value))
return false;
- changes_.Set(key, base::MakeUnique<base::Value>(*new_value));
+ changes_.Set(key, base::MakeUnique<base::Value>(new_value->Clone()));
storage_.Set(key, std::move(new_value));
return true;
}
diff --git a/chromium/components/machine_intelligence/ranker_model_loader_unittest.cc b/chromium/components/machine_intelligence/ranker_model_loader_unittest.cc
index d96d7b2ad5b..4081d6e200d 100644
--- a/chromium/components/machine_intelligence/ranker_model_loader_unittest.cc
+++ b/chromium/components/machine_intelligence/ranker_model_loader_unittest.cc
@@ -4,23 +4,19 @@
#include "components/machine_intelligence/ranker_model_loader.h"
-#include <deque>
#include <initializer_list>
#include <memory>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_scheduler.h"
#include "base/test/scoped_feature_list.h"
-#include "base/test/scoped_task_scheduler.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/machine_intelligence/proto/ranker_model.pb.h"
#include "components/machine_intelligence/proto/translate_ranker_model.pb.h"
@@ -31,7 +27,6 @@
namespace {
-using base::TaskScheduler;
using machine_intelligence::RankerModel;
using machine_intelligence::RankerModelLoader;
using machine_intelligence::RankerModelStatus;
@@ -45,8 +40,6 @@ class RankerModelLoaderTest : public ::testing::Test {
void SetUp() override;
- void TearDown() override;
-
// Returns a copy of |model|.
static std::unique_ptr<RankerModel> Clone(const RankerModel& model);
@@ -82,7 +75,7 @@ class RankerModelLoaderTest : public ::testing::Test {
void OnModelAvailable(std::unique_ptr<RankerModel> model);
// Sets up the task scheduling/task-runner environment for each test.
- base::test::ScopedTaskScheduler scoped_task_scheduler_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
// Override the default URL fetcher to return custom responses for tests.
net::FakeURLFetcherFactory url_fetcher_factory_;
@@ -95,7 +88,7 @@ class RankerModelLoaderTest : public ::testing::Test {
// A queue of responses to return from Validate(). If empty, validate will
// return 'OK'.
- std::deque<RankerModelStatus> validate_model_response_;
+ base::circular_deque<RankerModelStatus> validate_model_response_;
// A cached to remember the model validation calls.
std::vector<std::unique_ptr<RankerModel>> validated_models_;
@@ -147,10 +140,6 @@ void RankerModelLoaderTest::SetUp() {
ASSERT_NO_FATAL_FAILURE(InitLocalModels());
}
-void RankerModelLoaderTest::TearDown() {
- base::RunLoop().RunUntilIdle();
-}
-
// static
std::unique_ptr<RankerModel> RankerModelLoaderTest::Clone(
const RankerModel& model) {
@@ -186,7 +175,7 @@ bool RankerModelLoaderTest::DoLoaderTest(const base::FilePath& model_path,
request_context_getter_.get(), model_path, model_url,
"RankerModelLoaderTest");
loader->NotifyOfRankerActivity();
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
return true;
}
diff --git a/chromium/components/machine_intelligence/ranker_url_fetcher.cc b/chromium/components/machine_intelligence/ranker_url_fetcher.cc
index 965d716d76b..1271bbbe6e9 100644
--- a/chromium/components/machine_intelligence/ranker_url_fetcher.cc
+++ b/chromium/components/machine_intelligence/ranker_url_fetcher.cc
@@ -67,9 +67,11 @@ bool RankerURLFetcher::Request(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"NA"
+ policy_exception_justification:
+ "Not implemented, considered not necessary as no user data is sent."
})");
// Create and initialize the URL fetcher.
fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET, this,
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 319d951e816..8dd663c6733 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -18,6 +18,8 @@ static_library("metrics") {
"daily_event.h",
"data_use_tracker.cc",
"data_use_tracker.h",
+ "delegating_provider.cc",
+ "delegating_provider.h",
"drive_metrics_provider.cc",
"drive_metrics_provider.h",
"drive_metrics_provider_android.cc",
@@ -128,6 +130,30 @@ static_library("metrics") {
sources -= [ "machine_id_provider_stub.cc" ]
deps += [ "//components/browser_watcher:stability_client" ]
}
+
+ if (is_fuchsia) {
+ sources += [ "drive_metrics_provider_fuchsia.cc" ]
+ }
+}
+
+# The component metrics provider is a separate target because it depends upon
+# (the large) component_updater code, and is not needed for some entities that
+# depend on :metrics.
+static_library("component_metrics") {
+ sources = [
+ "component_metrics_provider.cc",
+ "component_metrics_provider.h",
+ ]
+
+ public_deps = [
+ "//components/metrics/proto",
+ ]
+
+ deps = [
+ ":metrics",
+ "//base",
+ "//components/component_updater",
+ ]
}
if (!is_ios) {
@@ -372,6 +398,7 @@ source_set("unit_tests") {
deps = [
":call_stack_profile_params",
":child_call_stacks",
+ ":component_metrics",
":metrics",
":net",
":profiler",
diff --git a/chromium/components/metrics/DEPS b/chromium/components/metrics/DEPS
index 3156f34603d..bd7bd415b7e 100644
--- a/chromium/components/metrics/DEPS
+++ b/chromium/components/metrics/DEPS
@@ -3,6 +3,7 @@
include_rules = [
"-components",
"+components/browser_watcher",
+ "+components/component_updater",
"+components/compression",
"+components/metrics",
"+components/prefs",
diff --git a/chromium/components/metrics/OWNERS b/chromium/components/metrics/OWNERS
index 3b1e0686f43..c9290272739 100644
--- a/chromium/components/metrics/OWNERS
+++ b/chromium/components/metrics/OWNERS
@@ -1,7 +1,3 @@
-asvitkine@chromium.org
-holte@chromium.org
-isherman@chromium.org
-mpearson@chromium.org
-rkaplow@chromium.org
+file://base/metrics/OWNERS
# COMPONENT: Internals>Metrics
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.cc b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
index 472c6c54b6a..a64816e8b0f 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
@@ -98,8 +98,8 @@ ProfilesState& ProfilesState::operator=(ProfilesState&&) = default;
// Singleton class responsible for retaining profiles received via the callback
// created by GetProfilerCallback(). These are then sent to UMA on the
-// invocation of CallStackProfileMetricsProvider::ProvideGeneralMetrics(). We
-// need to store the profiles outside of a CallStackProfileMetricsProvider
+// invocation of CallStackProfileMetricsProvider::ProvideCurrentSessionData().
+// We need to store the profiles outside of a CallStackProfileMetricsProvider
// instance since callers may start profiling before the
// CallStackProfileMetricsProvider is created.
//
@@ -508,9 +508,22 @@ bool CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled() {
// calls base::FeatureList::IsEnabled() internally. While extremely unlikely,
// it is possible that the profiler callback and therefore this function get
// called before FeatureList initialization (e.g. if machine was suspended).
- return base::FeatureList::GetInstance() != nullptr &&
- base::GetFieldTrialParamByFeatureAsBool(kEnableReporting, "periodic",
- false);
+ //
+ // The result is cached in a static to avoid a shutdown hang calling into the
+ // API while FieldTrialList is being destroyed. See also the comment below in
+ // Init().
+ static const bool is_enabled = base::FeatureList::GetInstance() != nullptr &&
+ base::GetFieldTrialParamByFeatureAsBool(
+ kEnableReporting, "periodic", false);
+ return is_enabled;
+}
+
+void CallStackProfileMetricsProvider::Init() {
+ // IsPeriodicSamplingEnabled() caches the result in a local static, so that
+ // future calls will return it directly. Calling it in Init() will cache the
+ // result, which will ensure we won't call into FieldTrialList during
+ // shutdown which can hang if it's in the middle of being destroyed.
+ CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled();
}
void CallStackProfileMetricsProvider::OnRecordingEnabled() {
@@ -521,7 +534,7 @@ void CallStackProfileMetricsProvider::OnRecordingDisabled() {
PendingProfiles::GetInstance()->SetCollectionEnabled(false);
}
-void CallStackProfileMetricsProvider::ProvideGeneralMetrics(
+void CallStackProfileMetricsProvider::ProvideCurrentSessionData(
ChromeUserMetricsExtension* uma_proto) {
std::vector<ProfilesState> pending_profiles;
PendingProfiles::GetInstance()->Swap(&pending_profiles);
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.h b/chromium/components/metrics/call_stack_profile_metrics_provider.h
index d5e4f7e46f0..d778ad34bf7 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.h
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.h
@@ -71,9 +71,11 @@ class CallStackProfileMetricsProvider : public MetricsProvider {
static bool IsPeriodicSamplingEnabled();
// MetricsProvider:
+ void Init() override;
void OnRecordingEnabled() override;
void OnRecordingDisabled() override;
- void ProvideGeneralMetrics(ChromeUserMetricsExtension* uma_proto) override;
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
protected:
// base::Feature for reporting profiles. Provided here for test use.
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
index 11f2ddcbfa0..bf176e40f7a 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -344,7 +344,7 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
CallStackProfileParams::MAY_SHUFFLE);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
uma_proto.sampled_profile().size());
@@ -428,7 +428,7 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
CallStackProfileParams::MAY_SHUFFLE);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
uma_proto.sampled_profile().size());
@@ -514,7 +514,7 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
CallStackProfileParams::PRESERVE_ORDER);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
uma_proto.sampled_profile().size());
@@ -558,7 +558,7 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
CallStackProfileParams::MAY_SHUFFLE);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
uma_proto.sampled_profile().size());
@@ -569,8 +569,8 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
}
}
-// Checks that pending profiles are only passed back to ProvideGeneralMetrics
-// once.
+// Checks that pending profiles are only passed back to
+// ProvideCurrentSessionData once.
TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
CallStackProfileMetricsProvider provider;
for (int r = 0; r < 2; ++r) {
@@ -591,7 +591,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
CallStackProfileParams::MAY_SHUFFLE);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
ASSERT_EQ(1, uma_proto.sampled_profile().size());
const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
@@ -603,7 +603,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
}
}
-// Checks that pending profiles are provided to ProvideGeneralMetrics
+// Checks that pending profiles are provided to ProvideCurrentSessionData
// when collected before CallStackProfileMetricsProvider is instantiated.
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesProvidedWhenCollectedBeforeInstantiation) {
@@ -624,12 +624,12 @@ TEST_F(CallStackProfileMetricsProviderTest,
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
EXPECT_EQ(1, uma_proto.sampled_profile_size());
}
-// Checks that pending profiles are not provided to ProvideGeneralMetrics
+// Checks that pending profiles are not provided to ProvideCurrentSessionData
// while recording is disabled.
TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
Profiles profiles = ProfilesFactory()
@@ -648,12 +648,12 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
CallStackProfileParams::MAY_SHUFFLE);
AppendProfiles(&params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
EXPECT_EQ(0, uma_proto.sampled_profile_size());
}
-// Checks that pending profiles are not provided to ProvideGeneralMetrics
+// Checks that pending profiles are not provided to ProvideCurrentSessionData
// if recording is disabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeToDisabled) {
@@ -674,12 +674,12 @@ TEST_F(CallStackProfileMetricsProviderTest,
.Build();
callback.Run(std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
EXPECT_EQ(0, uma_proto.sampled_profile_size());
}
-// Checks that pending profiles are not provided to ProvideGeneralMetrics if
+// Checks that pending profiles are not provided to ProvideCurrentSessionData if
// recording is enabled, but then disabled and reenabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeToDisabledThenEnabled) {
@@ -701,12 +701,12 @@ TEST_F(CallStackProfileMetricsProviderTest,
.Build();
callback.Run(std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
EXPECT_EQ(0, uma_proto.sampled_profile_size());
}
-// Checks that pending profiles are not provided to ProvideGeneralMetrics
+// Checks that pending profiles are not provided to ProvideCurrentSessionData
// if recording is disabled, but then enabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeFromDisabled) {
@@ -727,7 +727,7 @@ TEST_F(CallStackProfileMetricsProviderTest,
.Build();
callback.Run(std::move(profiles));
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
EXPECT_EQ(0, uma_proto.sampled_profile_size());
}
@@ -815,7 +815,7 @@ TEST_F(CallStackProfileMetricsProviderTest, MAYBE_PeriodicProfiles) {
const base::TimeDelta max_expected_uptime = internal::GetUptime();
ChromeUserMetricsExtension uma_proto;
- provider.ProvideGeneralMetrics(&uma_proto);
+ provider.ProvideCurrentSessionData(&uma_proto);
// We expect duration_ms to be the process uptime. Check that it's within the
// min/max boundary values that were retrieved earlier. Then, set the value
diff --git a/chromium/components/metrics/component_metrics_provider.cc b/chromium/components/metrics/component_metrics_provider.cc
new file mode 100644
index 00000000000..f20f7bc7472
--- /dev/null
+++ b/chromium/components/metrics/component_metrics_provider.cc
@@ -0,0 +1,91 @@
+// 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/metrics/component_metrics_provider.h"
+
+#include <map>
+#include <string>
+#include "base/strings/string_number_conversions.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/metrics/proto/system_profile.pb.h"
+
+namespace metrics {
+
+namespace {
+
+SystemProfileProto_ComponentId CrxIdToComponentId(const std::string& app_id) {
+ const static std::map<std::string, SystemProfileProto_ComponentId>
+ component_map = {
+ {"hfnkpimlhhgieaddgfemjhofmfblmnib",
+ SystemProfileProto_ComponentId_CRL_SET},
+ {"bjbdkfoakgmkndalgpadobhgbhhoanho",
+ SystemProfileProto_ComponentId_EPSON_INKJET_PRINTER_ESCPR},
+ {"khaoiebndkojlmppeemjhbpbandiljpe",
+ SystemProfileProto_ComponentId_FILE_TYPE_POLICIES},
+ {"mimojjlkmoijpicakmndhoigimigcmbb",
+ SystemProfileProto_ComponentId_PEPPER_FLASH},
+ {"ckjlcfmdbdglblbjglepgnoekdnkoklc",
+ SystemProfileProto_ComponentId_PEPPER_FLASH_CHROMEOS},
+ {"kfoklmclfodeliojeaekpoflbkkhojea",
+ SystemProfileProto_ComponentId_ORIGIN_TRIALS},
+ {"llkgjffcdpffmhiakmfcdcblohccpfmo",
+ SystemProfileProto_ComponentId_ORIGIN_TRIALS}, // Alternate ID
+ {"hnimpnehoodheedghdeeijklkeaacbdc",
+ SystemProfileProto_ComponentId_PNACL},
+ {"npdjjkjlcidkjlamlmmdelcjbcpdjocm",
+ SystemProfileProto_ComponentId_RECOVERY},
+ {"ojjgnpkioondelmggbekfhllhdaimnho",
+ SystemProfileProto_ComponentId_STH_SET},
+ {"gcmjkmgdlgnkkcocmoeiminaijmmjnii",
+ SystemProfileProto_ComponentId_SUBRESOURCE_FILTER},
+ {"gkmgaooipdjhmangpemjhigmamcehddo",
+ SystemProfileProto_ComponentId_SW_REPORTER},
+ {"giekcmmlnklenlaomppkphknjmnnpneh",
+ SystemProfileProto_ComponentId_SSL_ERROR_ASSISTANT},
+ {"oimompecagnajdejgnnjijobebaeigek",
+ SystemProfileProto_ComponentId_WIDEVINE_CDM}};
+ const auto result = component_map.find(app_id);
+ if (result == component_map.end())
+ return SystemProfileProto_ComponentId_UNKNOWN;
+ return result->second;
+}
+
+// Extract the first 32 bits of a fingerprint string, excluding the fingerprint
+// format specifier - see the fingerprint format specification at
+// https://github.com/google/omaha/blob/master/doc/ServerProtocolV3.md
+uint32_t Trim(const std::string& fp) {
+ const auto len_prefix = fp.find(".");
+ if (len_prefix == std::string::npos)
+ return 0;
+ uint32_t result = 0;
+ if (base::HexStringToUInt(fp.substr(len_prefix + 1, 8), &result))
+ return result;
+ return 0;
+}
+
+} // namespace
+
+ComponentMetricsProvider::ComponentMetricsProvider(
+ component_updater::ComponentUpdateService* component_update_service)
+ : component_update_service_(component_update_service) {}
+
+ComponentMetricsProvider::~ComponentMetricsProvider() = default;
+
+void ComponentMetricsProvider::ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile) {
+ for (const auto& component : component_update_service_->GetComponents()) {
+ const auto id = CrxIdToComponentId(component.id);
+ // Ignore any unknown components - in practice these are the
+ // SupervisedUserWhitelists, which we do not want to transmit to UMA or
+ // Crash.
+ if (id == SystemProfileProto_ComponentId_UNKNOWN)
+ continue;
+ auto* proto = system_profile->add_chrome_component();
+ proto->set_component_id(id);
+ proto->set_version(component.version.GetString());
+ proto->set_omaha_fingerprint(Trim(component.fingerprint));
+ }
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/component_metrics_provider.h b/chromium/components/metrics/component_metrics_provider.h
new file mode 100644
index 00000000000..7899b97150c
--- /dev/null
+++ b/chromium/components/metrics/component_metrics_provider.h
@@ -0,0 +1,37 @@
+// 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_METRICS_COMPONENT_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_COMPONENT_METRICS_PROVIDER_H_
+
+#include "components/metrics/metrics_provider.h"
+
+namespace component_updater {
+class ComponentUpdateService;
+}
+
+namespace metrics {
+
+class SystemProfileProto;
+
+// Stores and loads system information to prefs for stability logs.
+class ComponentMetricsProvider : public MetricsProvider {
+ public:
+ explicit ComponentMetricsProvider(
+ component_updater::ComponentUpdateService* component_update_service);
+ ~ComponentMetricsProvider() override;
+
+ // MetricsProvider:
+ void ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile_proto) override;
+
+ private:
+ component_updater::ComponentUpdateService* component_update_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(ComponentMetricsProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_COMPONENT_METRICS_PROVIDER_H_
diff --git a/chromium/components/metrics/component_metrics_provider_unittest.cc b/chromium/components/metrics/component_metrics_provider_unittest.cc
new file mode 100644
index 00000000000..b36b1478444
--- /dev/null
+++ b/chromium/components/metrics/component_metrics_provider_unittest.cc
@@ -0,0 +1,58 @@
+// 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/metrics/component_metrics_provider.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/version.h"
+#include "components/component_updater/mock_component_updater_service.h"
+#include "components/metrics/proto/system_profile.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+class ComponentMetricsProviderTest : public testing::Test {
+ public:
+ ComponentMetricsProviderTest() {}
+ ~ComponentMetricsProviderTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ComponentMetricsProviderTest);
+};
+
+using component_updater::ComponentInfo;
+
+TEST_F(ComponentMetricsProviderTest, ProvideComponentMetrics) {
+ std::vector<ComponentInfo> components = {
+ ComponentInfo(
+ "hfnkpimlhhgieaddgfemjhofmfblmnib",
+ "1.0846414bf2025bbc067b6fa5b61b16eda2269d8712b8fec0973b4c71fdc65ca0",
+ base::ASCIIToUTF16("name1"), base::Version("1.2.3.4")),
+ ComponentInfo(
+ "oimompecagnajdejgnnjijobebaeigek",
+ "1.adc9207a4a88ee98bf9ddf0330f35818386f1adc006bc8eee94dc59d43c0f5d6",
+ base::ASCIIToUTF16("name2"), base::Version("5.6.7.8")),
+ ComponentInfo(
+ "thiscomponentfilteredfromresults",
+ "1.b5268dc93e08d68d0be26bd8fbbb15c7b7f805cc06b4abd9d49381bc178e78cf",
+ base::ASCIIToUTF16("name3"), base::Version("9.9.9.9"))};
+ component_updater::MockComponentUpdateService service;
+ EXPECT_CALL(service, GetComponents()).WillOnce(testing::Return(components));
+ ComponentMetricsProvider component_provider(&service);
+ SystemProfileProto system_profile;
+ component_provider.ProvideSystemProfileMetrics(&system_profile);
+
+ EXPECT_EQ(2, system_profile.chrome_component_size());
+ EXPECT_EQ(SystemProfileProto_ComponentId_CRL_SET,
+ system_profile.chrome_component(0).component_id());
+ EXPECT_EQ("1.2.3.4", system_profile.chrome_component(0).version());
+ EXPECT_EQ(138821963u, system_profile.chrome_component(0).omaha_fingerprint());
+ EXPECT_EQ(SystemProfileProto_ComponentId_WIDEVINE_CDM,
+ system_profile.chrome_component(1).component_id());
+ EXPECT_EQ("5.6.7.8", system_profile.chrome_component(1).version());
+ EXPECT_EQ(2915639418u,
+ system_profile.chrome_component(1).omaha_fingerprint());
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/daily_event.cc b/chromium/components/metrics/daily_event.cc
index c289a0977f4..7ae52c0e2b8 100644
--- a/chromium/components/metrics/daily_event.cc
+++ b/chromium/components/metrics/daily_event.cc
@@ -53,7 +53,7 @@ DailyEvent::~DailyEvent() {
// static
void DailyEvent::RegisterPref(PrefRegistrySimple* registry,
const char* pref_name) {
- registry->RegisterInt64Pref(pref_name, base::Time().ToInternalValue());
+ registry->RegisterInt64Pref(pref_name, 0);
}
void DailyEvent::AddObserver(std::unique_ptr<DailyEvent::Observer> observer) {
@@ -66,8 +66,9 @@ void DailyEvent::CheckInterval() {
base::Time now = base::Time::Now();
if (last_fired_.is_null()) {
// The first time we call CheckInterval, we read the time stored in prefs.
- last_fired_ = base::Time::FromInternalValue(
- pref_service_->GetInt64(pref_name_));
+ last_fired_ = base::Time() + base::TimeDelta::FromMicroseconds(
+ pref_service_->GetInt64(pref_name_));
+
DVLOG(1) << "DailyEvent time loaded: " << last_fired_;
if (last_fired_.is_null()) {
DVLOG(1) << "DailyEvent first run.";
@@ -93,7 +94,8 @@ void DailyEvent::CheckInterval() {
void DailyEvent::OnInterval(base::Time now) {
DCHECK(!now.is_null());
last_fired_ = now;
- pref_service_->SetInt64(pref_name_, last_fired_.ToInternalValue());
+ pref_service_->SetInt64(pref_name_,
+ last_fired_.since_origin().InMicroseconds());
// Notify all observers
for (auto it = observers_.begin(); it != observers_.end(); ++it) {
diff --git a/chromium/components/metrics/daily_event_unittest.cc b/chromium/components/metrics/daily_event_unittest.cc
index 6e32c285aa5..8bdf5f31344 100644
--- a/chromium/components/metrics/daily_event_unittest.cc
+++ b/chromium/components/metrics/daily_event_unittest.cc
@@ -63,7 +63,7 @@ TEST_F(DailyEventTest, TestNewFires) {
// The event should fire if the preference is more than a day old.
TEST_F(DailyEventTest, TestOldFires) {
base::Time last_time = base::Time::Now() - base::TimeDelta::FromHours(25);
- prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue());
+ prefs_.SetInt64(kTestPrefName, last_time.since_origin().InMicroseconds());
event_.CheckInterval();
EXPECT_TRUE(observer_->fired());
}
@@ -71,7 +71,7 @@ TEST_F(DailyEventTest, TestOldFires) {
// The event should fire if the preference is more than a day in the future.
TEST_F(DailyEventTest, TestFutureFires) {
base::Time last_time = base::Time::Now() + base::TimeDelta::FromHours(25);
- prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue());
+ prefs_.SetInt64(kTestPrefName, last_time.since_origin().InMicroseconds());
event_.CheckInterval();
EXPECT_TRUE(observer_->fired());
}
@@ -79,7 +79,7 @@ TEST_F(DailyEventTest, TestFutureFires) {
// The event should not fire if the preference is more recent than a day.
TEST_F(DailyEventTest, TestRecentNotFired) {
base::Time last_time = base::Time::Now() - base::TimeDelta::FromMinutes(2);
- prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue());
+ prefs_.SetInt64(kTestPrefName, last_time.since_origin().InMicroseconds());
event_.CheckInterval();
EXPECT_FALSE(observer_->fired());
}
@@ -87,7 +87,7 @@ TEST_F(DailyEventTest, TestRecentNotFired) {
// The event should not fire if the preference is less than a day in the future.
TEST_F(DailyEventTest, TestSoonNotFired) {
base::Time last_time = base::Time::Now() + base::TimeDelta::FromMinutes(2);
- prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue());
+ prefs_.SetInt64(kTestPrefName, last_time.since_origin().InMicroseconds());
event_.CheckInterval();
EXPECT_FALSE(observer_->fired());
}
diff --git a/chromium/components/metrics/data_use_tracker.h b/chromium/components/metrics/data_use_tracker.h
index e5eb2ba25fd..35a80716b18 100644
--- a/chromium/components/metrics/data_use_tracker.h
+++ b/chromium/components/metrics/data_use_tracker.h
@@ -26,7 +26,7 @@ typedef base::Callback<void(const std::string&, int, bool)>
class DataUseTracker {
public:
explicit DataUseTracker(PrefService* local_state);
- ~DataUseTracker();
+ virtual ~DataUseTracker();
// Returns an instance of |DataUseTracker| with provided |local_state| if
// users data use should be tracked and null pointer otherwise.
diff --git a/chromium/components/metrics/delegating_provider.cc b/chromium/components/metrics/delegating_provider.cc
new file mode 100644
index 00000000000..2bb20137e69
--- /dev/null
+++ b/chromium/components/metrics/delegating_provider.cc
@@ -0,0 +1,112 @@
+// 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/metrics/delegating_provider.h"
+
+#include "base/barrier_closure.h"
+
+namespace metrics {
+
+DelegatingProvider::DelegatingProvider() = default;
+
+DelegatingProvider::~DelegatingProvider() = default;
+
+void DelegatingProvider::RegisterMetricsProvider(
+ std::unique_ptr<MetricsProvider> provider) {
+ metrics_providers_.push_back(std::move(provider));
+}
+
+const std::vector<std::unique_ptr<MetricsProvider>>&
+DelegatingProvider::GetProviders() {
+ return metrics_providers_;
+}
+
+void DelegatingProvider::Init() {
+ for (auto& provider : metrics_providers_)
+ provider->Init();
+}
+
+void DelegatingProvider::AsyncInit(const base::Closure& done_callback) {
+ base::Closure barrier =
+ base::BarrierClosure(metrics_providers_.size(), done_callback);
+ for (auto& provider : metrics_providers_) {
+ provider->AsyncInit(barrier);
+ }
+}
+
+void DelegatingProvider::OnDidCreateMetricsLog() {
+ for (auto& provider : metrics_providers_)
+ provider->OnDidCreateMetricsLog();
+}
+
+void DelegatingProvider::OnRecordingEnabled() {
+ for (auto& provider : metrics_providers_)
+ provider->OnRecordingEnabled();
+}
+
+void DelegatingProvider::OnRecordingDisabled() {
+ for (auto& provider : metrics_providers_)
+ provider->OnRecordingDisabled();
+}
+
+void DelegatingProvider::OnAppEnterBackground() {
+ for (auto& provider : metrics_providers_)
+ provider->OnAppEnterBackground();
+}
+
+bool DelegatingProvider::ProvideIndependentMetrics(
+ SystemProfileProto* system_profile_proto,
+ base::HistogramSnapshotManager* snapshot_manager) {
+ // These are collected seperately for each provider.
+ NOTREACHED();
+ return false;
+}
+
+void DelegatingProvider::ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile_proto) {
+ for (auto& provider : metrics_providers_)
+ provider->ProvideSystemProfileMetrics(system_profile_proto);
+}
+
+bool DelegatingProvider::HasPreviousSessionData() {
+ // All providers are queried (rather than stopping after the first "true"
+ // response) in case they do any kind of setup work in preparation for
+ // the later call to RecordInitialHistogramSnapshots().
+ bool has_stability_metrics = false;
+ for (auto& provider : metrics_providers_)
+ has_stability_metrics |= provider->HasPreviousSessionData();
+
+ return has_stability_metrics;
+}
+
+void DelegatingProvider::ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
+ for (const auto& provider : metrics_providers_)
+ provider->ProvidePreviousSessionData(uma_proto);
+}
+
+void DelegatingProvider::ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
+ for (const auto& provider : metrics_providers_)
+ provider->ProvideCurrentSessionData(uma_proto);
+}
+
+void DelegatingProvider::ClearSavedStabilityMetrics() {
+ for (auto& provider : metrics_providers_)
+ provider->ClearSavedStabilityMetrics();
+}
+
+void DelegatingProvider::RecordHistogramSnapshots(
+ base::HistogramSnapshotManager* snapshot_manager) {
+ for (auto& provider : metrics_providers_)
+ provider->RecordHistogramSnapshots(snapshot_manager);
+}
+
+void DelegatingProvider::RecordInitialHistogramSnapshots(
+ base::HistogramSnapshotManager* snapshot_manager) {
+ for (auto& provider : metrics_providers_)
+ provider->RecordInitialHistogramSnapshots(snapshot_manager);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/delegating_provider.h b/chromium/components/metrics/delegating_provider.h
new file mode 100644
index 00000000000..55c7144becc
--- /dev/null
+++ b/chromium/components/metrics/delegating_provider.h
@@ -0,0 +1,60 @@
+// 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_METRICS_DELEGATING_PROVIDER_H_
+#define COMPONENTS_METRICS_DELEGATING_PROVIDER_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/metrics/metrics_provider.h"
+
+namespace metrics {
+
+// A MetricsProvider which manages a set of other MetricsProviders.
+// Calls to this providers methods are forwarded to all of the registered
+// metrics providers, allowing the group to be handled as a single provider.
+class DelegatingProvider final : public MetricsProvider {
+ public:
+ DelegatingProvider();
+ ~DelegatingProvider() override;
+
+ // Registers an additional MetricsProvider to forward calls to.
+ void RegisterMetricsProvider(std::unique_ptr<MetricsProvider> delegate);
+
+ // Gets the list of registered providers.
+ const std::vector<std::unique_ptr<MetricsProvider>>& GetProviders();
+
+ // MetricsProvider:
+ void Init() override;
+ void AsyncInit(const base::Closure& done_callback) override;
+ void OnDidCreateMetricsLog() override;
+ void OnRecordingEnabled() override;
+ void OnRecordingDisabled() override;
+ void OnAppEnterBackground() override;
+ bool ProvideIndependentMetrics(
+ SystemProfileProto* system_profile_proto,
+ base::HistogramSnapshotManager* snapshot_manager) override;
+ void ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile_proto) override;
+ bool HasPreviousSessionData() override;
+ void ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
+ void ClearSavedStabilityMetrics() override;
+ void RecordHistogramSnapshots(
+ base::HistogramSnapshotManager* snapshot_manager) override;
+ void RecordInitialHistogramSnapshots(
+ base::HistogramSnapshotManager* snapshot_manager) override;
+
+ private:
+ std::vector<std::unique_ptr<MetricsProvider>> metrics_providers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelegatingProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_DELEGATING_PROVIDER_H_
diff --git a/chromium/components/metrics/drive_metrics_provider.cc b/chromium/components/metrics/drive_metrics_provider.cc
index b067337a963..4e00b0ad4a0 100644
--- a/chromium/components/metrics/drive_metrics_provider.cc
+++ b/chromium/components/metrics/drive_metrics_provider.cc
@@ -32,7 +32,7 @@ void DriveMetricsProvider::ProvideSystemProfileMetrics(
hardware->mutable_user_data_drive());
}
-void DriveMetricsProvider::GetDriveMetrics(const base::Closure& done_callback) {
+void DriveMetricsProvider::AsyncInit(const base::Closure& done_callback) {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BACKGROUND,
diff --git a/chromium/components/metrics/drive_metrics_provider.h b/chromium/components/metrics/drive_metrics_provider.h
index 280b0ae7eac..a41fec3fa94 100644
--- a/chromium/components/metrics/drive_metrics_provider.h
+++ b/chromium/components/metrics/drive_metrics_provider.h
@@ -28,12 +28,10 @@ class DriveMetricsProvider : public metrics::MetricsProvider {
~DriveMetricsProvider() override;
// metrics::MetricsDataProvider:
+ void AsyncInit(const base::Closure& done_callback) override;
void ProvideSystemProfileMetrics(
metrics::SystemProfileProto* system_profile_proto) override;
- // Called to start gathering metrics.
- void GetDriveMetrics(const base::Closure& done_callback);
-
private:
FRIEND_TEST_ALL_PREFIXES(DriveMetricsProviderTest, HasSeekPenalty);
diff --git a/chromium/components/metrics/drive_metrics_provider_fuchsia.cc b/chromium/components/metrics/drive_metrics_provider_fuchsia.cc
new file mode 100644
index 00000000000..165bc2d3909
--- /dev/null
+++ b/chromium/components/metrics/drive_metrics_provider_fuchsia.cc
@@ -0,0 +1,16 @@
+// 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/metrics/drive_metrics_provider.h"
+
+namespace metrics {
+
+// static
+bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
+ bool* has_seek_penalty) {
+ *has_seek_penalty = false;
+ return true;
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/drive_metrics_provider_linux.cc b/chromium/components/metrics/drive_metrics_provider_linux.cc
index 194e1ee4419..0ba3a9c06ea 100644
--- a/chromium/components/metrics/drive_metrics_provider_linux.cc
+++ b/chromium/components/metrics/drive_metrics_provider_linux.cc
@@ -34,6 +34,8 @@ const char kRotationalFormat[] = "/sys/block/sd%c/queue/rotational";
bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
bool* has_seek_penalty) {
#if defined(OS_CHROMEOS)
+ // TODO(derat): Remove special-casing after October 2017 when parrot (Acer C7
+ // Chromebook) is unsupported.
std::string board = base::SysInfo::GetStrippedReleaseBoard();
// There are "parrot", "parrot_ivb" and "parrot_freon" boards that have
// devices with rotating disks. All other ChromeOS devices have SSDs.
diff --git a/chromium/components/metrics/file_metrics_provider.cc b/chromium/components/metrics/file_metrics_provider.cc
index d6165f238b5..b8bab8c2499 100644
--- a/chromium/components/metrics/file_metrics_provider.cc
+++ b/chromium/components/metrics/file_metrics_provider.cc
@@ -596,7 +596,7 @@ bool FileMetricsProvider::ProvideIndependentMetrics(
return false;
}
-bool FileMetricsProvider::HasInitialStabilityMetrics() {
+bool FileMetricsProvider::HasPreviousSessionData() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Measure the total time spent checking all sources as well as the time
diff --git a/chromium/components/metrics/file_metrics_provider.h b/chromium/components/metrics/file_metrics_provider.h
index 66ce26612fa..0581e996c83 100644
--- a/chromium/components/metrics/file_metrics_provider.h
+++ b/chromium/components/metrics/file_metrics_provider.h
@@ -201,7 +201,7 @@ class FileMetricsProvider : public MetricsProvider,
bool ProvideIndependentMetrics(
SystemProfileProto* system_profile_proto,
base::HistogramSnapshotManager* snapshot_manager) override;
- bool HasInitialStabilityMetrics() override;
+ bool HasPreviousSessionData() override;
void RecordInitialHistogramSnapshots(
base::HistogramSnapshotManager* snapshot_manager) override;
diff --git a/chromium/components/metrics/file_metrics_provider_unittest.cc b/chromium/components/metrics/file_metrics_provider_unittest.cc
index 982e28c06a1..b2081987d3c 100644
--- a/chromium/components/metrics/file_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/file_metrics_provider_unittest.cc
@@ -46,20 +46,6 @@ class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
recorded_delta_histogram_names_.push_back(histogram.histogram_name());
}
- void InconsistencyDetected(base::HistogramBase::Inconsistency problem)
- override {
- ASSERT_TRUE(false);
- }
-
- void UniqueInconsistencyDetected(
- base::HistogramBase::Inconsistency problem) override {
- ASSERT_TRUE(false);
- }
-
- void InconsistencyDetectedInLoggedCount(int amount) override {
- ASSERT_TRUE(false);
- }
-
std::vector<std::string> GetRecordedDeltaHistogramNames() {
return recorded_delta_histogram_names_;
}
@@ -115,9 +101,7 @@ class FileMetricsProviderTest : public testing::TestWithParam<bool> {
provider()->OnDidCreateMetricsLog();
}
- bool HasInitialStabilityMetrics() {
- return provider()->HasInitialStabilityMetrics();
- }
+ bool HasPreviousSessionData() { return provider()->HasPreviousSessionData(); }
void MergeHistogramDeltas() {
provider()->MergeHistogramDeltas();
@@ -143,9 +127,9 @@ class FileMetricsProviderTest : public testing::TestWithParam<bool> {
HistogramFlattenerDeltaRecorder flattener;
base::HistogramSnapshotManager snapshot_manager(&flattener);
// "true" to the begin() includes histograms held in persistent storage.
- snapshot_manager.PrepareDeltas(
- base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
- base::Histogram::kNoFlags, base::Histogram::kNoFlags);
+ base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
+ base::Histogram::kNoFlags,
+ &snapshot_manager);
return flattener.GetRecordedDeltaHistogramNames().size();
}
@@ -434,7 +418,7 @@ TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
kMetricsName);
// Record embedded snapshots via snapshot-manager.
- ASSERT_TRUE(HasInitialStabilityMetrics());
+ ASSERT_TRUE(HasPreviousSessionData());
RunTasks();
{
HistogramFlattenerDeltaRecorder flattener;
@@ -538,7 +522,7 @@ TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithoutProfile) {
kMetricsName);
// Record embedded snapshots via snapshot-manager.
- ASSERT_TRUE(HasInitialStabilityMetrics());
+ ASSERT_TRUE(HasPreviousSessionData());
RunTasks();
{
HistogramFlattenerDeltaRecorder flattener;
@@ -579,7 +563,7 @@ TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithProfile) {
kMetricsName);
// Record embedded snapshots via snapshot-manager.
- EXPECT_FALSE(HasInitialStabilityMetrics());
+ EXPECT_FALSE(HasPreviousSessionData());
RunTasks();
{
HistogramFlattenerDeltaRecorder flattener;
diff --git a/chromium/components/metrics/generate_expired_histograms_array.gni b/chromium/components/metrics/generate_expired_histograms_array.gni
new file mode 100644
index 00000000000..70f8a8eb917
--- /dev/null
+++ b/chromium/components/metrics/generate_expired_histograms_array.gni
@@ -0,0 +1,42 @@
+# 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.
+
+# Runs the resources map generation script other the given header files to
+# 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.
+#
+# namespace (optional):
+# Namespace in which the generated code should be scoped. If left empty,
+# the code will be in the global namespace.
+#
+# header_filename:
+# Name of the generated header file.
+#
+template("generate_expired_histograms_array") {
+ action(target_name) {
+ header_filename = "$target_gen_dir/" + invoker.header_filename
+
+ script = "//tools/metrics/histograms/generate_expired_histograms_array.py"
+ outputs = [
+ header_filename,
+ ]
+
+ inputs = invoker.inputs
+
+ args = []
+
+ if (defined(invoker.namespace) && invoker.namespace != "") {
+ args += [ "-n" + invoker.namespace ]
+ }
+
+ args += [
+ "-o" + rebase_path(root_gen_dir, root_build_dir),
+ "-H" + rebase_path(header_filename, root_gen_dir),
+ ] + rebase_path(inputs, root_build_dir)
+ }
+}
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index 5169ea849a9..02ac223e5c9 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -21,12 +21,12 @@
#include "base/sys_info.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/metrics/delegating_provider.h"
#include "components/metrics/environment_recorder.h"
#include "components/metrics/histogram_encoder.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/metrics_service_client.h"
-#include "components/metrics/persistent_system_profile.h"
#include "components/metrics/proto/histogram_event.pb.h"
#include "components/metrics/proto/system_profile.pb.h"
#include "components/metrics/proto/user_action_event.pb.h"
@@ -63,11 +63,6 @@ class IndependentFlattener : public base::HistogramFlattener {
const base::HistogramSamples& snapshot) override {
log_->RecordHistogramDelta(histogram.histogram_name(), snapshot);
}
- void InconsistencyDetected(
- base::HistogramBase::Inconsistency problem) override {}
- void UniqueInconsistencyDetected(
- base::HistogramBase::Inconsistency problem) override {}
- void InconsistencyDetectedInLoggedCount(int amount) override {}
private:
MetricsLog* const log_;
@@ -80,25 +75,17 @@ bool IsTestingID(const std::string& id) {
return id.size() < 16;
}
-// Round a timestamp measured in seconds since epoch to one with a granularity
-// of an hour. This can be used before uploaded potentially sensitive
-// timestamps.
-int64_t RoundSecondsToHour(int64_t time_in_seconds) {
- return 3600 * (time_in_seconds / 3600);
-}
-
} // namespace
MetricsLog::MetricsLog(const std::string& client_id,
int session_id,
LogType log_type,
- MetricsServiceClient* client,
- PrefService* local_state)
+ MetricsServiceClient* client)
: closed_(false),
log_type_(log_type),
client_(client),
creation_time_(base::TimeTicks::Now()),
- local_state_(local_state) {
+ has_environment_(false) {
if (IsTestingID(client_id))
uma_proto_.set_client_id(0);
else
@@ -113,10 +100,6 @@ MetricsLog::MetricsLog(const std::string& client_id,
SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
RecordCoreSystemProfile(client_, system_profile);
- if (log_type_ == ONGOING_LOG) {
- GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
- *system_profile, /*complete=*/false);
- }
}
MetricsLog::~MetricsLog() {
@@ -160,7 +143,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(GetCurrentTime());
+ user_action->set_time_sec(GetCurrentTime());
}
void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client,
@@ -192,7 +175,7 @@ void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client,
os->set_name(base::SysInfo::OperatingSystemName());
os->set_version(base::SysInfo::OperatingSystemVersion());
#if defined(OS_ANDROID)
- os->set_fingerprint(
+ os->set_build_fingerprint(
base::android::BuildInfo::GetInstance()->android_build_fp());
#endif
}
@@ -203,13 +186,17 @@ void MetricsLog::RecordHistogramDelta(const std::string& histogram_name,
EncodeHistogramDelta(histogram_name, snapshot, &uma_proto_);
}
-void MetricsLog::RecordStabilityMetrics(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers,
+void MetricsLog::RecordPreviousSessionData(
+ DelegatingProvider* delegating_provider) {
+ delegating_provider->ProvidePreviousSessionData(uma_proto());
+}
+
+void MetricsLog::RecordCurrentSessionData(
+ DelegatingProvider* delegating_provider,
base::TimeDelta incremental_uptime,
base::TimeDelta uptime) {
DCHECK(!closed_);
- DCHECK(HasEnvironment());
- DCHECK(!HasStabilityMetrics());
+ DCHECK(has_environment_);
// Record recent delta for critical stability metrics. We can't wait for a
// restart to gather these, as that delay biases our observation away from
@@ -217,25 +204,7 @@ void MetricsLog::RecordStabilityMetrics(
// uma log upload, just as we send histogram data.
WriteRealtimeStabilityAttributes(incremental_uptime, uptime);
- SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
- for (size_t i = 0; i < metrics_providers.size(); ++i) {
- if (log_type() == INITIAL_STABILITY_LOG)
- metrics_providers[i]->ProvideInitialStabilityMetrics(system_profile);
- metrics_providers[i]->ProvideStabilityMetrics(system_profile);
- }
-}
-
-void MetricsLog::RecordGeneralMetrics(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers) {
- if (local_state_->GetBoolean(prefs::kMetricsResetIds))
- UMA_HISTOGRAM_BOOLEAN("UMA.IsClonedInstall", true);
-
- for (size_t i = 0; i < metrics_providers.size(); ++i)
- metrics_providers[i]->ProvideGeneralMetrics(uma_proto());
-}
-
-bool MetricsLog::HasEnvironment() const {
- return uma_proto()->system_profile().has_uma_enabled_date();
+ delegating_provider->ProvideCurrentSessionData(uma_proto());
}
void MetricsLog::WriteMetricsEnableDefault(EnableMetricsDefault metrics_default,
@@ -262,10 +231,6 @@ void MetricsLog::WriteMetricsEnableDefault(EnableMetricsDefault metrics_default,
}
}
-bool MetricsLog::HasStabilityMetrics() const {
- return uma_proto()->system_profile().stability().has_launch_count();
-}
-
void MetricsLog::WriteRealtimeStabilityAttributes(
base::TimeDelta incremental_uptime,
base::TimeDelta uptime) {
@@ -284,11 +249,10 @@ void MetricsLog::WriteRealtimeStabilityAttributes(
stability->set_uptime_sec(uptime_sec);
}
-std::string MetricsLog::RecordEnvironment(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers,
- int64_t install_date,
- int64_t metrics_reporting_enabled_date) {
- DCHECK(!HasEnvironment());
+const SystemProfileProto& MetricsLog::RecordEnvironment(
+ DelegatingProvider* delegating_provider) {
+ DCHECK(!has_environment_);
+ has_environment_ = true;
SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
@@ -299,13 +263,6 @@ std::string MetricsLog::RecordEnvironment(
if (client_->GetBrand(&brand_code))
system_profile->set_brand_code(brand_code);
- // Reduce granularity of the enabled_date field to nearest hour.
- system_profile->set_uma_enabled_date(
- RoundSecondsToHour(metrics_reporting_enabled_date));
-
- // Reduce granularity of the install_date field to nearest hour.
- system_profile->set_install_date(RoundSecondsToHour(install_date));
-
SystemProfileProto::Hardware::CPU* cpu =
system_profile->mutable_hardware()->mutable_cpu();
base::CPU cpu_info;
@@ -313,19 +270,9 @@ std::string MetricsLog::RecordEnvironment(
cpu->set_signature(cpu_info.signature());
cpu->set_num_cores(base::SysInfo::NumberOfProcessors());
- for (size_t i = 0; i < metrics_providers.size(); ++i)
- metrics_providers[i]->ProvideSystemProfileMetrics(system_profile);
-
- EnvironmentRecorder recorder(local_state_);
- std::string serialized_proto =
- recorder.SerializeAndRecordEnvironmentToPrefs(*system_profile);
-
- if (log_type_ == ONGOING_LOG) {
- GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
- serialized_proto, /*complete=*/true);
- }
+ delegating_provider->ProvideSystemProfileMetrics(system_profile);
- return serialized_proto;
+ return *system_profile;
}
bool MetricsLog::LoadIndependentMetrics(MetricsProvider* metrics_provider) {
@@ -337,12 +284,14 @@ bool MetricsLog::LoadIndependentMetrics(MetricsProvider* metrics_provider) {
&snapshot_manager);
}
-bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
- DCHECK(app_version);
+bool MetricsLog::LoadSavedEnvironmentFromPrefs(PrefService* local_state,
+ std::string* app_version) {
+ DCHECK(!has_environment_);
+ has_environment_ = true;
app_version->clear();
SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
- EnvironmentRecorder recorder(local_state_);
+ EnvironmentRecorder recorder(local_state);
bool success = recorder.LoadEnvironmentFromPrefs(system_profile);
if (success)
*app_version = system_profile->app_version();
diff --git a/chromium/components/metrics/metrics_log.h b/chromium/components/metrics/metrics_log.h
index 27e90330444..e68fcc07721 100644
--- a/chromium/components/metrics/metrics_log.h
+++ b/chromium/components/metrics/metrics_log.h
@@ -34,6 +34,7 @@ extern const int kUserActionEventLimit;
class MetricsProvider;
class MetricsServiceClient;
+class DelegatingProvider;
class MetricsLog {
public:
@@ -54,8 +55,7 @@ class MetricsLog {
MetricsLog(const std::string& client_id,
int session_id,
LogType log_type,
- MetricsServiceClient* client,
- PrefService* local_state);
+ MetricsServiceClient* client);
virtual ~MetricsLog();
// Registers local state prefs used by this class.
@@ -87,19 +87,13 @@ class MetricsLog {
void RecordHistogramDelta(const std::string& histogram_name,
const base::HistogramSamples& snapshot);
-
// TODO(rkaplow): I think this can be a little refactored as it currently
// records a pretty arbitrary set of things.
// Records the current operating environment, including metrics provided by
- // the specified set of |metrics_providers|. Takes the list of synthetic
- // trial IDs as a parameter. A synthetic trial is one that is set up
- // dynamically by code in Chrome. For example, a pref may be mapped to a
- // synthetic trial such that the group is determined by the pref value. The
- // current environment is returned serialized as a string.
- std::string RecordEnvironment(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers,
- int64_t install_date,
- int64_t metrics_reporting_enabled_date);
+ // the specified |delegating_provider|. The current environment is
+ // returned as a SystemProfileProto.
+ const SystemProfileProto& RecordEnvironment(
+ DelegatingProvider* delegating_provider);
// Loads a saved system profile and the associated metrics into the log.
// Returns true on success. Keep calling it with fresh logs until it returns
@@ -110,25 +104,16 @@ class MetricsLog {
// call from prefs. On success, returns true and |app_version| contains the
// recovered version. Otherwise (if there was no saved environment in prefs
// or it could not be decoded), returns false and |app_version| is empty.
- bool LoadSavedEnvironmentFromPrefs(std::string* app_version);
-
- // Writes application stability metrics, including stability metrics provided
- // by the specified set of |metrics_providers|. The system profile portion of
- // the log must have already been filled in by a call to RecordEnvironment()
- // or LoadSavedEnvironmentFromPrefs().
- // NOTE: Has the side-effect of clearing the stability prefs..
- //
- // If this log is of type INITIAL_STABILITY_LOG, records additional info such
- // as number of incomplete shutdowns as well as extra breakpad and debugger
- // stats.
- void RecordStabilityMetrics(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers,
- base::TimeDelta incremental_uptime,
- base::TimeDelta uptime);
-
- // Records general metrics based on the specified |metrics_providers|.
- void RecordGeneralMetrics(
- const std::vector<std::unique_ptr<MetricsProvider>>& metrics_providers);
+ bool LoadSavedEnvironmentFromPrefs(PrefService* local_state,
+ std::string* app_version);
+
+ // Record data from providers about the previous session into the log.
+ void RecordPreviousSessionData(DelegatingProvider* delegating_provider);
+
+ // Record data from providers about the current session into the log.
+ void RecordCurrentSessionData(DelegatingProvider* delegating_provider,
+ base::TimeDelta incremental_uptime,
+ base::TimeDelta uptime);
// Stop writing to this record and generate the encoded representation.
// None of the Record* methods can be called after this is called.
@@ -160,18 +145,10 @@ class MetricsLog {
}
private:
- // Returns true if the environment has already been filled in by a call to
- // RecordEnvironment() or LoadSavedEnvironmentFromPrefs().
- bool HasEnvironment() const;
-
// Write the default state of the enable metrics checkbox.
void WriteMetricsEnableDefault(EnableMetricsDefault metrics_default,
SystemProfileProto* system_profile);
- // Returns true if the stability metrics have already been filled in by a
- // call to RecordStabilityMetrics().
- bool HasStabilityMetrics() const;
-
// Within the stability group, write attributes that need to be updated asap
// and can't be delayed until the user decides to restart chromium.
// Delaying these stats would bias metrics away from happy long lived
@@ -196,7 +173,9 @@ class MetricsLog {
// The time when the current log was created.
const base::TimeTicks creation_time_;
- PrefService* local_state_;
+ // True if the environment has already been filled in by a call to
+ // RecordEnvironment() or LoadSavedEnvironmentFromPrefs().
+ bool has_environment_;
DISALLOW_COPY_AND_ASSIGN(MetricsLog);
};
diff --git a/chromium/components/metrics/metrics_log_manager_unittest.cc b/chromium/components/metrics/metrics_log_manager_unittest.cc
index 3dafa34dcd3..4857a9934c7 100644
--- a/chromium/components/metrics/metrics_log_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_log_manager_unittest.cc
@@ -35,7 +35,7 @@ class MetricsLogManagerTest : public testing::Test {
MetricsLogStore* log_store() { return &log_store_; }
MetricsLog* CreateLog(MetricsLog::LogType log_type) {
- return new MetricsLog("id", 0, log_type, &client_, &pref_service_);
+ return new MetricsLog("id", 0, log_type, &client_);
}
private:
diff --git a/chromium/components/metrics/metrics_log_store_unittest.cc b/chromium/components/metrics/metrics_log_store_unittest.cc
index 5c352744d1d..50b78c7cd88 100644
--- a/chromium/components/metrics/metrics_log_store_unittest.cc
+++ b/chromium/components/metrics/metrics_log_store_unittest.cc
@@ -21,7 +21,7 @@ class MetricsLogStoreTest : public testing::Test {
~MetricsLogStoreTest() override {}
MetricsLog* CreateLog(MetricsLog::LogType log_type) {
- return new MetricsLog("id", 0, log_type, &client_, &pref_service_);
+ return new MetricsLog("id", 0, log_type, &client_);
}
// Returns the stored number of logs of the given type.
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index cb48cc0922a..e3eb42214bc 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -17,6 +17,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/sys_info.h"
#include "base/time/time.h"
+#include "components/metrics/delegating_provider.h"
#include "components/metrics/environment_recorder.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_state_manager.h"
@@ -41,10 +42,6 @@ namespace metrics {
namespace {
const char kClientId[] = "bogus client ID";
-const int64_t kInstallDate = 1373051956;
-const int64_t kInstallDateExpected = 1373050800; // Computed from kInstallDate.
-const int64_t kEnabledDate = 1373001211;
-const int64_t kEnabledDateExpected = 1373000400; // Computed from kEnabledDate.
const int kSessionId = 127;
class TestMetricsLog : public MetricsLog {
@@ -52,12 +49,8 @@ class TestMetricsLog : public MetricsLog {
TestMetricsLog(const std::string& client_id,
int session_id,
LogType log_type,
- MetricsServiceClient* client,
- TestingPrefServiceSimple* prefs)
- : MetricsLog(client_id, session_id, log_type, client, prefs),
- prefs_(prefs) {
- InitPrefs();
- }
+ MetricsServiceClient* client)
+ : MetricsLog(client_id, session_id, log_type, client) {}
~TestMetricsLog() override {}
@@ -74,14 +67,6 @@ class TestMetricsLog : public MetricsLog {
}
private:
- void InitPrefs() {
- prefs_->SetString(prefs::kMetricsReportingEnabledTimestamp,
- base::Int64ToString(kEnabledDate));
- }
-
- // Weak pointer to the PrefsService used by this log.
- TestingPrefServiceSimple* prefs_;
-
DISALLOW_COPY_AND_ASSIGN(TestMetricsLog);
};
@@ -89,20 +74,13 @@ class TestMetricsLog : public MetricsLog {
class MetricsLogTest : public testing::Test {
public:
- MetricsLogTest() {
- EnvironmentRecorder::RegisterPrefs(prefs_.registry());
- MetricsStateManager::RegisterPrefs(prefs_.registry());
- }
-
+ MetricsLogTest() {}
~MetricsLogTest() override {}
protected:
// Check that the values in |system_values| correspond to the test data
// defined at the top of this file.
void CheckSystemProfile(const SystemProfileProto& system_profile) {
- EXPECT_EQ(kInstallDateExpected, system_profile.install_date());
- EXPECT_EQ(kEnabledDateExpected, system_profile.uma_enabled_date());
-
EXPECT_EQ(TestMetricsServiceClient::kBrandForTesting,
system_profile.brand_code());
@@ -118,9 +96,6 @@ class MetricsLogTest : public testing::Test {
// of this call.
}
- protected:
- TestingPrefServiceSimple prefs_;
-
private:
DISALLOW_COPY_AND_ASSIGN(MetricsLogTest);
};
@@ -129,10 +104,10 @@ TEST_F(MetricsLogTest, LogType) {
TestMetricsServiceClient client;
TestingPrefServiceSimple prefs;
- MetricsLog log1("id", 0, MetricsLog::ONGOING_LOG, &client, &prefs);
+ MetricsLog log1("id", 0, MetricsLog::ONGOING_LOG, &client);
EXPECT_EQ(MetricsLog::ONGOING_LOG, log1.log_type());
- MetricsLog log2("id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &prefs);
+ MetricsLog log2("id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client);
EXPECT_EQ(MetricsLog::INITIAL_STABILITY_LOG, log2.log_type());
}
@@ -141,7 +116,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
client.set_version_string("bogus version");
TestingPrefServiceSimple prefs;
MetricsLog log("totally bogus client ID", 137, MetricsLog::ONGOING_LOG,
- &client, &prefs);
+ &client);
log.CloseLog();
std::string encoded;
@@ -179,7 +154,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
system_profile->mutable_os()->set_version(
base::SysInfo::OperatingSystemVersion());
#if defined(OS_ANDROID)
- system_profile->mutable_os()->set_fingerprint(
+ system_profile->mutable_os()->set_build_fingerprint(
base::android::BuildInfo::GetInstance()->android_build_fp());
#endif
@@ -211,8 +186,7 @@ TEST_F(MetricsLogTest, HistogramBucketFields) {
TestMetricsServiceClient client;
TestingPrefServiceSimple prefs;
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
log.RecordHistogramDelta("Test", samples);
const ChromeUserMetricsExtension& uma_proto = log.uma_proto();
@@ -252,53 +226,43 @@ TEST_F(MetricsLogTest, HistogramBucketFields) {
TEST_F(MetricsLogTest, RecordEnvironment) {
TestMetricsServiceClient client;
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
- log.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
- kInstallDate, kEnabledDate);
+ DelegatingProvider delegating_provider;
+ log.RecordEnvironment(&delegating_provider);
// Check that the system profile on the log has the correct values set.
CheckSystemProfile(log.system_profile());
-
- // Check that the system profile has also been written to prefs.
- SystemProfileProto decoded_system_profile;
- EnvironmentRecorder recorder(&prefs_);
- EXPECT_TRUE(recorder.LoadEnvironmentFromPrefs(&decoded_system_profile));
- CheckSystemProfile(decoded_system_profile);
}
TEST_F(MetricsLogTest, RecordEnvironmentEnableDefault) {
TestMetricsServiceClient client;
TestMetricsLog log_unknown(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
- &client, &prefs_);
+ &client);
- log_unknown.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
- kInstallDate, kEnabledDate);
+ DelegatingProvider delegating_provider;
+ log_unknown.RecordEnvironment(&delegating_provider);
EXPECT_FALSE(log_unknown.system_profile().has_uma_default_state());
client.set_enable_default(EnableMetricsDefault::OPT_IN);
TestMetricsLog log_opt_in(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
- &client, &prefs_);
- log_opt_in.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
- kInstallDate, kEnabledDate);
+ &client);
+ log_opt_in.RecordEnvironment(&delegating_provider);
EXPECT_TRUE(log_opt_in.system_profile().has_uma_default_state());
EXPECT_EQ(SystemProfileProto_UmaDefaultState_OPT_IN,
log_opt_in.system_profile().uma_default_state());
client.set_enable_default(EnableMetricsDefault::OPT_OUT);
TestMetricsLog log_opt_out(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
- &client, &prefs_);
- log_opt_out.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
- kInstallDate, kEnabledDate);
+ &client);
+ log_opt_out.RecordEnvironment(&delegating_provider);
EXPECT_TRUE(log_opt_out.system_profile().has_uma_default_state());
EXPECT_EQ(SystemProfileProto_UmaDefaultState_OPT_OUT,
log_opt_out.system_profile().uma_default_state());
client.set_reporting_is_managed(true);
TestMetricsLog log_managed(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
- &client, &prefs_);
- log_managed.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
- kInstallDate, kEnabledDate);
+ &client);
+ log_managed.RecordEnvironment(&delegating_provider);
EXPECT_TRUE(log_managed.system_profile().has_uma_default_state());
EXPECT_EQ(SystemProfileProto_UmaDefaultState_POLICY_FORCED_ENABLED,
log_managed.system_profile().uma_default_state());
@@ -306,17 +270,14 @@ TEST_F(MetricsLogTest, RecordEnvironmentEnableDefault) {
TEST_F(MetricsLogTest, InitialLogStabilityMetrics) {
TestMetricsServiceClient client;
- TestMetricsLog log(kClientId,
- kSessionId,
- MetricsLog::INITIAL_STABILITY_LOG,
- &client,
- &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
+ &client);
TestMetricsProvider* test_provider = new TestMetricsProvider();
- std::vector<std::unique_ptr<MetricsProvider>> metrics_providers;
- metrics_providers.push_back(base::WrapUnique<MetricsProvider>(test_provider));
- log.RecordEnvironment(metrics_providers, kInstallDate, kEnabledDate);
- log.RecordStabilityMetrics(metrics_providers, base::TimeDelta(),
- base::TimeDelta());
+ DelegatingProvider delegating_provider;
+ delegating_provider.RegisterMetricsProvider(
+ base::WrapUnique<MetricsProvider>(test_provider));
+ log.RecordEnvironment(&delegating_provider);
+ log.RecordPreviousSessionData(&delegating_provider);
// The test provider should have been called upon to provide initial
// stability and regular stability metrics.
@@ -326,14 +287,14 @@ TEST_F(MetricsLogTest, InitialLogStabilityMetrics) {
TEST_F(MetricsLogTest, OngoingLogStabilityMetrics) {
TestMetricsServiceClient client;
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
TestMetricsProvider* test_provider = new TestMetricsProvider();
- std::vector<std::unique_ptr<MetricsProvider>> metrics_providers;
- metrics_providers.push_back(base::WrapUnique<MetricsProvider>(test_provider));
- log.RecordEnvironment(metrics_providers, kInstallDate, kEnabledDate);
- log.RecordStabilityMetrics(metrics_providers, base::TimeDelta(),
- base::TimeDelta());
+ DelegatingProvider delegating_provider;
+ delegating_provider.RegisterMetricsProvider(
+ base::WrapUnique<MetricsProvider>(test_provider));
+ log.RecordEnvironment(&delegating_provider);
+ log.RecordCurrentSessionData(&delegating_provider, base::TimeDelta(),
+ base::TimeDelta());
// The test provider should have been called upon to provide regular but not
// initial stability metrics.
@@ -343,16 +304,14 @@ TEST_F(MetricsLogTest, OngoingLogStabilityMetrics) {
TEST_F(MetricsLogTest, ChromeChannelWrittenToProtobuf) {
TestMetricsServiceClient client;
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
EXPECT_TRUE(log.uma_proto().system_profile().has_channel());
}
TEST_F(MetricsLogTest, ProductNotSetIfDefault) {
TestMetricsServiceClient client;
EXPECT_EQ(ChromeUserMetricsExtension::CHROME, client.GetProduct());
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
// Check that the product isn't set, since it's default and also verify the
// default value is indeed equal to Chrome.
EXPECT_FALSE(log.uma_proto().has_product());
@@ -365,8 +324,7 @@ TEST_F(MetricsLogTest, ProductSetIfNotDefault) {
TestMetricsServiceClient client;
client.set_product(kTestProduct);
- TestMetricsLog log(
- kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
// Check that the product is set to |kTestProduct|.
EXPECT_TRUE(log.uma_proto().has_product());
EXPECT_EQ(kTestProduct, log.uma_proto().product());
@@ -374,8 +332,7 @@ TEST_F(MetricsLogTest, ProductSetIfNotDefault) {
TEST_F(MetricsLogTest, TruncateEvents) {
TestMetricsServiceClient client;
- TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client,
- &prefs_);
+ TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
for (int i = 0; i < internal::kUserActionEventLimit * 2; ++i) {
log.RecordUserAction("BasicAction");
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index dbec00a0384..7138127e0c9 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -202,5 +202,20 @@ const char kUmaCellDataUse[] = "user_experience_metrics.uma_cell_datause";
// per day.
const char kUserCellDataUse[] = "user_experience_metrics.user_call_datause";
+// Maximum number of tabs that has been opened since the last time it has been
+// reported.
+const char kTabStatsTotalTabCountMax[] = "tab_stats.total_tab_count_max";
+
+// Maximum number of tabs that has been opened in a single window since the last
+// time it has been reported.
+const char kTabStatsMaxTabsPerWindow[] = "tab_stats.max_tabs_per_window";
+
+// Maximum number of windows that has been opened since the last time it has
+// been reported.
+const char kTabStatsWindowCountMax[] = "tab_stats.window_count_max";
+
+// Timestamp of the last time the tab stats daily metrics have been reported.
+const char kTabStatsDailySample[] = "tab_stats.last_daily_sample";
+
} // namespace prefs
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index 5332512238b..f487b6fbbed 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -69,6 +69,12 @@ extern const char kUkmCellDataUse[];
extern const char kUmaCellDataUse[];
extern const char kUserCellDataUse[];
+// Preferences for recording information about the tabs and windows usage.
+extern const char kTabStatsTotalTabCountMax[];
+extern const char kTabStatsMaxTabsPerWindow[];
+extern const char kTabStatsWindowCountMax[];
+extern const char kTabStatsDailySample[];
+
} // namespace prefs
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_provider.cc b/chromium/components/metrics/metrics_provider.cc
index c5ca5853d34..b642258cd13 100644
--- a/chromium/components/metrics/metrics_provider.cc
+++ b/chromium/components/metrics/metrics_provider.cc
@@ -4,6 +4,8 @@
#include "components/metrics/metrics_provider.h"
+#include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
+
namespace metrics {
MetricsProvider::MetricsProvider() {
@@ -15,6 +17,10 @@ MetricsProvider::~MetricsProvider() {
void MetricsProvider::Init() {
}
+void MetricsProvider::AsyncInit(const base::Closure& done_callback) {
+ done_callback.Run();
+}
+
void MetricsProvider::OnDidCreateMetricsLog() {
}
@@ -37,12 +43,18 @@ void MetricsProvider::ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto) {
}
-bool MetricsProvider::HasInitialStabilityMetrics() {
+bool MetricsProvider::HasPreviousSessionData() {
return false;
}
-void MetricsProvider::ProvideInitialStabilityMetrics(
- SystemProfileProto* system_profile_proto) {
+void MetricsProvider::ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
+ ProvideStabilityMetrics(uma_proto->mutable_system_profile());
+}
+
+void MetricsProvider::ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
+ ProvideStabilityMetrics(uma_proto->mutable_system_profile());
}
void MetricsProvider::ProvideStabilityMetrics(
@@ -52,10 +64,6 @@ void MetricsProvider::ProvideStabilityMetrics(
void MetricsProvider::ClearSavedStabilityMetrics() {
}
-void MetricsProvider::ProvideGeneralMetrics(
- ChromeUserMetricsExtension* uma_proto) {
-}
-
void MetricsProvider::RecordHistogramSnapshots(
base::HistogramSnapshotManager* snapshot_manager) {
}
diff --git a/chromium/components/metrics/metrics_provider.h b/chromium/components/metrics/metrics_provider.h
index a867ef45bcc..591c63ff7cc 100644
--- a/chromium/components/metrics/metrics_provider.h
+++ b/chromium/components/metrics/metrics_provider.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_METRICS_METRICS_PROVIDER_H_
#define COMPONENTS_METRICS_METRICS_PROVIDER_H_
+#include "base/callback.h"
#include "base/macros.h"
namespace base {
@@ -26,6 +27,11 @@ class MetricsProvider {
// Called after initialiazation of MetricsService and field trials.
virtual void Init();
+ // Called during service initialization to allow the provider to start any
+ // async initialization tasks. The service will wait for the provider to
+ // call |done_callback| before generating logs for the current session.
+ virtual void AsyncInit(const base::Closure& done_callback);
+
// Called when a new MetricsLog is created.
virtual void OnDidCreateMetricsLog();
@@ -54,19 +60,23 @@ class MetricsProvider {
virtual void ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto);
- // Called once at startup to see whether this provider has critical stability
- // events to share in an initial stability log.
- // Returning true can trigger ProvideInitialStabilityMetrics and
- // ProvideStabilityMetrics on all other registered metrics providers.
+ // Called once at startup to see whether this provider has critical data
+ // to provide about the previous session.
+ // Returning true will trigger ProvidePreviousSessionData on all other
+ // registered metrics providers.
// Default implementation always returns false.
- virtual bool HasInitialStabilityMetrics();
+ virtual bool HasPreviousSessionData();
- // Called at most once at startup when an initial stability log is created.
- // It provides critical statiblity metrics that need to be reported in an
- // initial stability log.
- // Default implementation is a no-op.
- virtual void ProvideInitialStabilityMetrics(
- SystemProfileProto* system_profile_proto);
+ // Called when building a log about the previous session, so the provider
+ // can provide data about it. Stability metrics can be provided
+ // directly into |stability_proto| fields or by logging stability histograms
+ // via the UMA_STABILITY_HISTOGRAM_ENUMERATION() macro.
+ virtual void ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto);
+
+ // Called when building a log about the current session, so the provider
+ // can provide data about it.
+ virtual void ProvideCurrentSessionData(ChromeUserMetricsExtension* uma_proto);
// Provides additional stability metrics. Stability metrics can be provided
// directly into |stability_proto| fields or by logging stability histograms
@@ -78,12 +88,6 @@ class MetricsProvider {
// because they are from an old version and should not be kept.
virtual void ClearSavedStabilityMetrics();
- // Provides general metrics that are neither system profile nor stability
- // metrics. May also be used to add histograms when final metrics are
- // collected right before upload.
- virtual void ProvideGeneralMetrics(
- ChromeUserMetricsExtension* uma_proto);
-
// Called during regular collection to explicitly load histogram snapshots
// using a snapshot manager. PrepareDeltas() will have already been called
// and FinishDeltas() will be called later; calls to only PrepareDelta(),
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index fae8af3ee6e..35ca2858dec 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -145,6 +145,7 @@
#include "base/time/time.h"
#include "base/tracked_objects.h"
#include "build/build_config.h"
+#include "components/metrics/daily_event.h"
#include "components/metrics/environment_recorder.h"
#include "components/metrics/field_trials_provider.h"
#include "components/metrics/metrics_log.h"
@@ -154,6 +155,7 @@
#include "components/metrics/metrics_rotation_scheduler.h"
#include "components/metrics/metrics_service_client.h"
#include "components/metrics/metrics_state_manager.h"
+#include "components/metrics/persistent_system_profile.h"
#include "components/metrics/stability_metrics_provider.h"
#include "components/metrics/url_constants.h"
#include "components/prefs/pref_registry_simple.h"
@@ -201,12 +203,16 @@ void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
ExecutionPhaseManager::RegisterPrefs(registry);
MetricsReportingService::RegisterPrefs(registry);
- registry->RegisterInt64Pref(prefs::kInstallDate, 0);
-
registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
+
+ // Register the tab stats metrics.
+ registry->RegisterIntegerPref(prefs::kTabStatsTotalTabCountMax, 0);
+ registry->RegisterIntegerPref(prefs::kTabStatsMaxTabsPerWindow, 0);
+ registry->RegisterIntegerPref(prefs::kTabStatsWindowCountMax, 0);
+ metrics::DailyEvent::RegisterPref(registry, prefs::kTabStatsDailySample);
}
MetricsService::MetricsService(MetricsStateManager* state_manager,
@@ -228,14 +234,11 @@ MetricsService::MetricsService(MetricsStateManager* state_manager,
DCHECK(client_);
DCHECK(local_state_);
- // Set the install date if this is our first run.
- int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
- if (install_date == 0)
- local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
-
RegisterMetricsProvider(
base::MakeUnique<StabilityMetricsProvider>(local_state_));
+ RegisterMetricsProvider(state_manager_->GetProvider());
+
RegisterMetricsProvider(base::MakeUnique<variations::FieldTrialsProvider>(
&synthetic_trial_registry_, base::StringPiece()));
}
@@ -259,8 +262,7 @@ void MetricsService::InitializeMetricsRecordingState() {
base::Bind(&MetricsServiceClient::GetStandardUploadInterval,
base::Unretained(client_))));
- for (auto& provider : metrics_providers_)
- provider->Init();
+ delegating_provider_.Init();
}
void MetricsService::Start() {
@@ -297,11 +299,7 @@ std::string MetricsService::GetClientId() {
}
int64_t MetricsService::GetInstallDate() {
- return local_state_->GetInt64(prefs::kInstallDate);
-}
-
-int64_t MetricsService::GetMetricsReportingEnabledDate() {
- return local_state_->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
+ return state_manager_->GetInstallDate();
}
bool MetricsService::WasLastShutdownClean() const {
@@ -317,11 +315,16 @@ void MetricsService::EnableRecording() {
state_manager_->ForceClientIdCreation();
client_->SetMetricsClientId(state_manager_->client_id());
+
+ SystemProfileProto system_profile;
+ MetricsLog::RecordCoreSystemProfile(client_, &system_profile);
+ GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
+ system_profile, /*complete=*/false);
+
if (!log_manager_.current_log())
OpenNewLog();
- for (auto& provider : metrics_providers_)
- provider->OnRecordingEnabled();
+ delegating_provider_.OnRecordingEnabled();
base::RemoveActionCallback(action_callback_);
action_callback_ = base::Bind(&MetricsService::OnUserAction,
@@ -338,8 +341,7 @@ void MetricsService::DisableRecording() {
base::RemoveActionCallback(action_callback_);
- for (auto& provider : metrics_providers_)
- provider->OnRecordingDisabled();
+ delegating_provider_.OnRecordingDisabled();
PushPendingLogsToPersistentStorage();
}
@@ -360,25 +362,10 @@ bool MetricsService::has_unsent_logs() const {
void MetricsService::RecordDelta(const base::HistogramBase& histogram,
const base::HistogramSamples& snapshot) {
+ histogram.ValidateHistogramContents(true, -1);
log_manager_.current_log()->RecordHistogramDelta(histogram.histogram_name(),
snapshot);
-}
-
-void MetricsService::InconsistencyDetected(
- base::HistogramBase::Inconsistency problem) {
- UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowser",
- problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
-}
-
-void MetricsService::UniqueInconsistencyDetected(
- base::HistogramBase::Inconsistency problem) {
- UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowserUnique",
- problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
-}
-
-void MetricsService::InconsistencyDetectedInLoggedCount(int amount) {
- UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotBrowser",
- std::abs(amount));
+ histogram.ValidateHistogramContents(true, -2);
}
void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
@@ -413,8 +400,7 @@ void MetricsService::OnAppEnterBackground() {
// Give providers a chance to persist histograms as part of being
// backgrounded.
- for (auto& provider : metrics_providers_)
- provider->OnAppEnterBackground();
+ delegating_provider_.OnAppEnterBackground();
// At this point, there's no way of knowing when the process will be
// killed, so this has to be treated similar to a shutdown, closing and
@@ -458,8 +444,7 @@ void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
}
void MetricsService::ClearSavedStabilityMetrics() {
- for (auto& provider : metrics_providers_)
- provider->ClearSavedStabilityMetrics();
+ delegating_provider_.ClearSavedStabilityMetrics();
}
void MetricsService::PushExternalLog(const std::string& log) {
@@ -509,10 +494,9 @@ void MetricsService::InitializeMetricsState() {
manager.SetExecutionPhase(ExecutionPhase::UNINITIALIZED_PHASE);
}
- // ProvidersHaveInitialStabilityMetrics is called first to ensure it is never
- // bypassed.
+ // HasPreviousSessionData is called first to ensure it is never bypassed.
const bool is_initial_stability_log_required =
- ProvidersHaveInitialStabilityMetrics() ||
+ delegating_provider_.HasPreviousSessionData() ||
!state_manager_->clean_exit_beacon()->exited_cleanly();
bool has_initial_stability_log = false;
if (is_initial_stability_log_required) {
@@ -579,7 +563,7 @@ void MetricsService::FinishedInitTask() {
// Create the initial log.
if (!initial_metrics_log_.get()) {
initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG);
- NotifyOnDidCreateMetricsLog();
+ delegating_provider_.OnDidCreateMetricsLog();
}
rotation_scheduler_->InitTaskComplete();
@@ -607,13 +591,6 @@ void MetricsService::GetUptimes(PrefService* pref,
}
}
-void MetricsService::NotifyOnDidCreateMetricsLog() {
- DCHECK(thread_checker_.CalledOnValidThread());
- for (auto& provider : metrics_providers_)
- provider->OnDidCreateMetricsLog();
-}
-
-
//------------------------------------------------------------------------------
// Recording control methods
@@ -621,7 +598,7 @@ void MetricsService::OpenNewLog() {
DCHECK(!log_manager_.current_log());
log_manager_.BeginLoggingWithLog(CreateLog(MetricsLog::ONGOING_LOG));
- NotifyOnDidCreateMetricsLog();
+ delegating_provider_.OnDidCreateMetricsLog();
if (state_ == INITIALIZED) {
// We only need to schedule that run once.
state_ = INIT_TASK_SCHEDULED;
@@ -640,9 +617,8 @@ void MetricsService::OpenNewLog() {
}
void MetricsService::StartInitTask() {
- client_->InitializeSystemProfileMetrics(
- base::Bind(&MetricsService::FinishedInitTask,
- self_ptr_factory_.GetWeakPtr()));
+ delegating_provider_.AsyncInit(base::Bind(&MetricsService::FinishedInitTask,
+ self_ptr_factory_.GetWeakPtr()));
}
void MetricsService::CloseCurrentLog() {
@@ -666,10 +642,8 @@ void MetricsService::CloseCurrentLog() {
base::TimeDelta incremental_uptime;
base::TimeDelta uptime;
GetUptimes(local_state_, &incremental_uptime, &uptime);
- current_log->RecordStabilityMetrics(metrics_providers_, incremental_uptime,
- uptime);
-
- current_log->RecordGeneralMetrics(metrics_providers_);
+ current_log->RecordCurrentSessionData(&delegating_provider_,
+ incremental_uptime, uptime);
RecordCurrentHistograms();
current_log->TruncateEvents();
DVLOG(1) << "Generated an ongoing log.";
@@ -705,6 +679,7 @@ void MetricsService::StartSchedulerIfNecessary() {
void MetricsService::StartScheduledUpload() {
DVLOG(1) << "StartScheduledUpload";
DCHECK(state_ >= INIT_TASK_DONE);
+
// If we're getting no notifications, then the log won't have much in it, and
// it's possible the computer is about to go to sleep, so don't upload and
// stop the scheduler.
@@ -736,6 +711,7 @@ void MetricsService::StartScheduledUpload() {
void MetricsService::OnFinalLogInfoCollectionDone() {
DVLOG(1) << "OnFinalLogInfoCollectionDone";
+
// Abort if metrics were turned off during the final info gathering.
if (!recording_active()) {
rotation_scheduler_->Stop();
@@ -755,18 +731,6 @@ void MetricsService::OnFinalLogInfoCollectionDone() {
HandleIdleSinceLastTransmission(true);
}
-bool MetricsService::ProvidersHaveInitialStabilityMetrics() {
- // Check whether any metrics provider has initial stability metrics.
- // All providers are queried (rather than stopping after the first "true"
- // response) in case they do any kind of setup work in preparation for
- // the later call to RecordInitialHistogramSnapshots().
- bool has_stability_metrics = false;
- for (auto& provider : metrics_providers_)
- has_stability_metrics |= provider->HasInitialStabilityMetrics();
-
- return has_stability_metrics;
-}
-
bool MetricsService::PrepareInitialStabilityLog(
const std::string& prefs_previous_version) {
DCHECK_EQ(INITIALIZED, state_);
@@ -774,11 +738,11 @@ bool MetricsService::PrepareInitialStabilityLog(
std::unique_ptr<MetricsLog> initial_stability_log(
CreateLog(MetricsLog::INITIAL_STABILITY_LOG));
- // Do not call NotifyOnDidCreateMetricsLog here because the stability
+ // Do not call OnDidCreateMetricsLog here because the stability
// log describes stats from the _previous_ session.
std::string system_profile_app_version;
if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(
- &system_profile_app_version)) {
+ local_state_, &system_profile_app_version)) {
return false;
}
if (system_profile_app_version != prefs_previous_version)
@@ -789,13 +753,9 @@ bool MetricsService::PrepareInitialStabilityLog(
// Note: Some stability providers may record stability stats via histograms,
// so this call has to be after BeginLoggingWithLog().
- log_manager_.current_log()->RecordStabilityMetrics(
- metrics_providers_, base::TimeDelta(), base::TimeDelta());
+ log_manager_.current_log()->RecordPreviousSessionData(&delegating_provider_);
RecordCurrentStabilityHistograms();
- // Note: RecordGeneralMetrics() intentionally not called since this log is for
- // stability stats from a previous session only.
-
DVLOG(1) << "Generated an stability log.";
log_manager_.FinishCurrentLog(log_store());
log_manager_.ResumePausedLog();
@@ -822,10 +782,8 @@ void MetricsService::PrepareInitialMetricsLog() {
// Note: Some stability providers may record stability stats via histograms,
// so this call has to be after BeginLoggingWithLog().
- MetricsLog* current_log = log_manager_.current_log();
- current_log->RecordStabilityMetrics(metrics_providers_, base::TimeDelta(),
- base::TimeDelta());
- current_log->RecordGeneralMetrics(metrics_providers_);
+ log_manager_.current_log()->RecordCurrentSessionData(
+ &delegating_provider_, base::TimeDelta(), base::TimeDelta());
RecordCurrentHistograms();
DVLOG(1) << "Generated an initial log.";
@@ -853,7 +811,7 @@ bool MetricsService::UmaMetricsProperlyShutdown() {
void MetricsService::RegisterMetricsProvider(
std::unique_ptr<MetricsProvider> provider) {
DCHECK_EQ(INITIALIZED, state_);
- metrics_providers_.push_back(std::move(provider));
+ delegating_provider_.RegisterMetricsProvider(std::move(provider));
}
void MetricsService::CheckForClonedInstall() {
@@ -863,38 +821,50 @@ void MetricsService::CheckForClonedInstall() {
std::unique_ptr<MetricsLog> MetricsService::CreateLog(
MetricsLog::LogType log_type) {
return base::MakeUnique<MetricsLog>(state_manager_->client_id(), session_id_,
- log_type, client_, local_state_);
+ log_type, client_);
+}
+
+std::string MetricsService::RecordCurrentEnvironmentHelper(
+ MetricsLog* log,
+ PrefService* local_state,
+ DelegatingProvider* delegating_provider) {
+ const SystemProfileProto& system_profile =
+ log->RecordEnvironment(delegating_provider);
+ EnvironmentRecorder recorder(local_state);
+ return recorder.SerializeAndRecordEnvironmentToPrefs(system_profile);
}
void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
DCHECK(client_);
- std::string serialized_environment = log->RecordEnvironment(
- metrics_providers_, GetInstallDate(), GetMetricsReportingEnabledDate());
- client_->OnEnvironmentUpdate(&serialized_environment);
+ std::string serialized_proto =
+ RecordCurrentEnvironmentHelper(log, local_state_, &delegating_provider_);
+ GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
+ serialized_proto, /*complete=*/true);
+ client_->OnEnvironmentUpdate(&serialized_proto);
}
void MetricsService::RecordCurrentHistograms() {
DCHECK(log_manager_.current_log());
SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.RecordCurrentHistograms.Time");
- // "true" to the begin() call indicates that StatisticsRecorder should include
- // histograms held in persistent storage.
- histogram_snapshot_manager_.PrepareDeltas(
- base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
- base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
- for (auto& provider : metrics_providers_)
- provider->RecordHistogramSnapshots(&histogram_snapshot_manager_);
+ // "true" indicates that StatisticsRecorder should include histograms held in
+ // persistent storage.
+ base::StatisticsRecorder::PrepareDeltas(
+ true, base::Histogram::kNoFlags,
+ base::Histogram::kUmaTargetedHistogramFlag, &histogram_snapshot_manager_);
+ delegating_provider_.RecordHistogramSnapshots(&histogram_snapshot_manager_);
}
void MetricsService::RecordCurrentStabilityHistograms() {
DCHECK(log_manager_.current_log());
- // "true" indicates that StatisticsRecorder should include histograms in
+ // "true" indicates that StatisticsRecorder should include histograms held in
// persistent storage.
- histogram_snapshot_manager_.PrepareDeltas(
- base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
- base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag);
- for (auto& provider : metrics_providers_)
- provider->RecordInitialHistogramSnapshots(&histogram_snapshot_manager_);
+ base::StatisticsRecorder::PrepareDeltas(
+ true, base::Histogram::kNoFlags,
+ base::Histogram::kUmaStabilityHistogramFlag,
+ &histogram_snapshot_manager_);
+ delegating_provider_.RecordInitialHistogramSnapshots(
+ &histogram_snapshot_manager_);
}
bool MetricsService::PrepareProviderMetricsLog() {
@@ -904,7 +874,7 @@ bool MetricsService::PrepareProviderMetricsLog() {
// those will be overwritten when an embedded profile is extracted.
std::unique_ptr<MetricsLog> log = CreateLog(MetricsLog::INDEPENDENT_LOG);
- for (auto& provider : metrics_providers_) {
+ for (auto& provider : delegating_provider_.GetProviders()) {
if (log->LoadIndependentMetrics(provider.get())) {
log_manager_.PauseCurrentLog();
log_manager_.BeginLoggingWithLog(std::move(log));
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index 4bf850b42b5..df1fc044043 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -26,6 +26,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/metrics/clean_exit_beacon.h"
+#include "components/metrics/delegating_provider.h"
#include "components/metrics/execution_phase.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_log_manager.h"
@@ -108,11 +109,6 @@ class MetricsService : public base::HistogramFlattener {
// HistogramFlattener:
void RecordDelta(const base::HistogramBase& histogram,
const base::HistogramSamples& snapshot) override;
- void InconsistencyDetected(
- base::HistogramBase::Inconsistency problem) override;
- void UniqueInconsistencyDetected(
- base::HistogramBase::Inconsistency problem) override;
- void InconsistencyDetectedInLoggedCount(int amount) override;
// This should be called when the application is not idle, i.e. the user seems
// to be interacting with the application.
@@ -187,6 +183,14 @@ class MetricsService : public base::HistogramFlattener {
return reporting_service_.metrics_log_store();
}
+ // Records the current environment (system profile) in |log|, and persists
+ // the results in prefs.
+ // Exposed for testing.
+ static std::string RecordCurrentEnvironmentHelper(
+ MetricsLog* log,
+ PrefService* local_state,
+ DelegatingProvider* delegating_provider);
+
private:
// The MetricsService has a lifecycle that is stored as a state.
// See metrics_service.cc for description of this lifecycle.
@@ -245,9 +249,6 @@ class MetricsService : public base::HistogramFlattener {
// Set up client ID, session ID, etc.
void InitializeMetricsState();
- // Notifies providers when a new metrics log is created.
- void NotifyOnDidCreateMetricsLog();
-
// Opens a new log for recording user experience metrics.
void OpenNewLog();
@@ -269,10 +270,6 @@ class MetricsService : public base::HistogramFlattener {
// complete.
void OnFinalLogInfoCollectionDone();
- // Returns true if any of the registered metrics providers have critical
- // stability metrics to report in an initial stability log.
- bool ProvidersHaveInitialStabilityMetrics();
-
// Prepares the initial stability log, which is only logged when the previous
// run of Chrome crashed. This log contains any stability metrics left over
// from that previous run, and only these stability metrics. It uses the
@@ -295,7 +292,9 @@ class MetricsService : public base::HistogramFlattener {
// Creates a new MetricsLog instance with the given |log_type|.
std::unique_ptr<MetricsLog> CreateLog(MetricsLog::LogType log_type);
- // Records the current environment (system profile) in |log|.
+ // Records the current environment (system profile) in |log|, and persists
+ // the results in prefs and GlobalPersistentSystemProfile.
+ // Exposed for testing.
void RecordCurrentEnvironment(MetricsLog* log);
// Record complete list of histograms into the current log.
@@ -333,7 +332,7 @@ class MetricsService : public base::HistogramFlattener {
MetricsServiceClient* const client_;
// Registered metrics providers.
- std::vector<std::unique_ptr<MetricsProvider>> metrics_providers_;
+ DelegatingProvider delegating_provider_;
PrefService* local_state_;
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 6d2f6d4543d..abc6dce99f0 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -77,11 +77,6 @@ class MetricsServiceClient {
// Called by the metrics service to record a clean shutdown.
virtual void OnLogCleanShutdown() {}
- // Gathers metrics that will be filled into the system profile protobuf,
- // calling |done_callback| when complete.
- virtual void InitializeSystemProfileMetrics(
- const base::Closure& done_callback) = 0;
-
// Called prior to a metrics log being closed, allowing the client to collect
// extra histograms that will go in that log. Asynchronous API - the client
// implementation should call |done_callback| when complete.
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index 6c1497326b9..c4c048ec997 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -56,6 +56,7 @@ class TestMetricsService : public MetricsService {
using MetricsService::log_manager;
using MetricsService::log_store;
+ using MetricsService::RecordCurrentEnvironmentHelper;
private:
DISALLOW_COPY_AND_ASSIGN(TestMetricsService);
@@ -65,13 +66,8 @@ class TestMetricsLog : public MetricsLog {
public:
TestMetricsLog(const std::string& client_id,
int session_id,
- MetricsServiceClient* client,
- PrefService* local_state)
- : MetricsLog(client_id,
- session_id,
- MetricsLog::ONGOING_LOG,
- client,
- local_state) {}
+ MetricsServiceClient* client)
+ : MetricsLog(client_id, session_id, MetricsLog::ONGOING_LOG, client) {}
~TestMetricsLog() override {}
@@ -174,7 +170,7 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) {
// No initial stability log should be generated.
EXPECT_FALSE(service.has_unsent_logs());
- // Ensure that HasInitialStabilityMetrics() is always called on providers,
+ // Ensure that HasPreviousSessionData() is always called on providers,
// for consistency, even if other conditions already indicate their presence.
EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
@@ -190,8 +186,10 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAtProviderRequest) {
// Save an existing system profile to prefs, to correspond to what would be
// saved from a previous session.
TestMetricsServiceClient client;
- TestMetricsLog log("client", 1, &client, GetLocalState());
- log.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(), 0, 0);
+ TestMetricsLog log("client", 1, &client);
+ DelegatingProvider delegating_provider;
+ TestMetricsService::RecordCurrentEnvironmentHelper(&log, GetLocalState(),
+ &delegating_provider);
// Record stability build time and version from previous session, so that
// stability metrics (including exited cleanly flag) won't be cleared.
@@ -218,7 +216,7 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAtProviderRequest) {
EXPECT_TRUE(log_store->has_unsent_logs());
EXPECT_FALSE(log_store->has_staged_log());
- // Ensure that HasInitialStabilityMetrics() is always called on providers,
+ // Ensure that HasPreviousSessionData() is always called on providers,
// for consistency, even if other conditions already indicate their presence.
EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
@@ -260,8 +258,10 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAfterCrash) {
// Save an existing system profile to prefs, to correspond to what would be
// saved from a previous session.
TestMetricsServiceClient client;
- TestMetricsLog log("client", 1, &client, GetLocalState());
- log.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(), 0, 0);
+ TestMetricsLog log("client", 1, &client);
+ DelegatingProvider delegating_provider;
+ TestMetricsService::RecordCurrentEnvironmentHelper(&log, GetLocalState(),
+ &delegating_provider);
// Record stability build time and version from previous session, so that
// stability metrics (including exited cleanly flag) won't be cleared.
@@ -284,7 +284,7 @@ TEST_F(MetricsServiceTest, InitialStabilityLogAfterCrash) {
EXPECT_TRUE(log_store->has_unsent_logs());
EXPECT_FALSE(log_store->has_staged_log());
- // Ensure that HasInitialStabilityMetrics() is always called on providers,
+ // Ensure that HasPreviousSessionData() is always called on providers,
// for consistency, even if other conditions already indicate their presence.
EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index 45c2c48e20a..e2d2109872f 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -20,7 +20,9 @@
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/machine_id_provider.h"
#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_provider.h"
#include "components/metrics/metrics_switches.h"
+#include "components/metrics/proto/system_profile.pb.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/caching_permuted_entropy_provider.h"
@@ -50,6 +52,46 @@ void LogLowEntropyValue(int low_entropy_source_value) {
low_entropy_source_value);
}
+int64_t ReadEnabledDate(PrefService* local_state) {
+ return local_state->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
+}
+
+int64_t ReadInstallDate(PrefService* local_state) {
+ return local_state->GetInt64(prefs::kInstallDate);
+}
+
+// Round a timestamp measured in seconds since epoch to one with a granularity
+// of an hour. This can be used before uploaded potentially sensitive
+// timestamps.
+int64_t RoundSecondsToHour(int64_t time_in_seconds) {
+ return 3600 * (time_in_seconds / 3600);
+}
+
+class MetricsStateMetricsProvider : public MetricsProvider {
+ public:
+ MetricsStateMetricsProvider(PrefService* local_state)
+ : local_state_(local_state) {}
+
+ // MetricsProvider:
+ void ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile) override {
+ system_profile->set_uma_enabled_date(
+ RoundSecondsToHour(ReadEnabledDate(local_state_)));
+ system_profile->set_install_date(
+ RoundSecondsToHour(ReadInstallDate(local_state_)));
+ }
+
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override {
+ if (local_state_->GetBoolean(prefs::kMetricsResetIds))
+ UMA_HISTOGRAM_BOOLEAN("UMA.IsClonedInstall", true);
+ }
+
+ private:
+ PrefService* local_state_;
+ DISALLOW_COPY_AND_ASSIGN(MetricsStateMetricsProvider);
+};
+
} // namespace
// static
@@ -72,6 +114,11 @@ MetricsStateManager::MetricsStateManager(
if (enabled_state_provider_->IsConsentGiven())
ForceClientIdCreation();
+ // Set the install date if this is our first run.
+ int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
+ if (install_date == 0)
+ local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
+
DCHECK(!instance_exists_);
instance_exists_ = true;
}
@@ -81,10 +128,18 @@ MetricsStateManager::~MetricsStateManager() {
instance_exists_ = false;
}
+std::unique_ptr<MetricsProvider> MetricsStateManager::GetProvider() {
+ return base::MakeUnique<MetricsStateMetricsProvider>(local_state_);
+}
+
bool MetricsStateManager::IsMetricsReportingEnabled() {
return enabled_state_provider_->IsReportingEnabled();
}
+int64_t MetricsStateManager::GetInstallDate() const {
+ return ReadInstallDate(local_state_);
+}
+
void MetricsStateManager::ForceClientIdCreation() {
{
std::string client_id_from_prefs =
@@ -215,6 +270,7 @@ void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
kLowEntropySourceNotSet);
+ registry->RegisterInt64Pref(prefs::kInstallDate, 0);
ClonedInstallDetector::RegisterPrefs(registry);
CachingPermutedEntropyProvider::RegisterPrefs(registry);
@@ -223,9 +279,8 @@ void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) {
void MetricsStateManager::BackUpCurrentClientInfo() {
ClientInfo client_info;
client_info.client_id = client_id_;
- client_info.installation_date = local_state_->GetInt64(prefs::kInstallDate);
- client_info.reporting_enabled_date =
- local_state_->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
+ client_info.installation_date = ReadInstallDate(local_state_);
+ client_info.reporting_enabled_date = ReadEnabledDate(local_state_);
store_client_info_.Run(client_info);
}
diff --git a/chromium/components/metrics/metrics_state_manager.h b/chromium/components/metrics/metrics_state_manager.h
index fbb0f595d6e..824597f3db4 100644
--- a/chromium/components/metrics/metrics_state_manager.h
+++ b/chromium/components/metrics/metrics_state_manager.h
@@ -23,6 +23,7 @@ namespace metrics {
class ClonedInstallDetector;
class EnabledStateProvider;
+class MetricsProvider;
// Responsible for managing MetricsService state prefs, specifically the UMA
// client id and low entropy source. Code outside the metrics directory should
@@ -41,11 +42,16 @@ class MetricsStateManager {
virtual ~MetricsStateManager();
+ std::unique_ptr<MetricsProvider> GetProvider();
+
// Returns true if the user has consented to sending metric reports, and there
// is no other reason to disable reporting. One such reason is client
// sampling, and this client isn't in the sample.
bool IsMetricsReportingEnabled();
+ // Returns the install date of the application, in seconds since the epoch.
+ int64_t GetInstallDate() const;
+
// Returns the client ID for this client, or the empty string if the user is
// not opted in to metrics reporting.
const std::string& client_id() const { return client_id_; }
diff --git a/chromium/components/metrics/metrics_state_manager_unittest.cc b/chromium/components/metrics/metrics_state_manager_unittest.cc
index 801f74a2067..6485591859f 100644
--- a/chromium/components/metrics/metrics_state_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_state_manager_unittest.cc
@@ -390,4 +390,26 @@ TEST_F(MetricsStateManagerTest, ResetBackup) {
}
}
+TEST_F(MetricsStateManagerTest, CheckProvider) {
+ int64_t kInstallDate = 1373051956;
+ int64_t kInstallDateExpected = 1373050800; // Computed from kInstallDate.
+ int64_t kEnabledDate = 1373001211;
+ int64_t kEnabledDateExpected = 1373000400; // Computed from kEnabledDate.
+
+ ClientInfo client_info;
+ client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE";
+ client_info.installation_date = kInstallDate;
+ client_info.reporting_enabled_date = kEnabledDate;
+
+ SetFakeClientInfoBackup(client_info);
+ SetClientInfoPrefs(client_info);
+
+ std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+ std::unique_ptr<MetricsProvider> provider = state_manager->GetProvider();
+ SystemProfileProto system_profile;
+ provider->ProvideSystemProfileMetrics(&system_profile);
+ EXPECT_EQ(system_profile.install_date(), kInstallDateExpected);
+ EXPECT_EQ(system_profile.uma_enabled_date(), kEnabledDateExpected);
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/net/net_metrics_log_uploader.cc b/chromium/components/metrics/net/net_metrics_log_uploader.cc
index e7dac872d37..3a941548686 100644
--- a/chromium/components/metrics/net/net_metrics_log_uploader.cc
+++ b/chromium/components/metrics/net/net_metrics_log_uploader.cc
@@ -38,7 +38,7 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature by disabling "
"'Automatically send usage statistics and crash reports to Google' "
@@ -76,7 +76,7 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature by disabling "
"'Automatically send usage statistics and crash reports to Google' "
diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc
index df7a8752f31..a75fdf6070f 100644
--- a/chromium/components/metrics/net/network_metrics_provider.cc
+++ b/chromium/components/metrics/net/network_metrics_provider.cc
@@ -30,18 +30,6 @@
namespace metrics {
-namespace {
-
-// Gets the network quality estimator from |network_quality_estimator_provider|,
-// and provides it to the |callback|.
-void GetAndSetNetworkQualityEstimator(
- const base::Callback<void(net::NetworkQualityEstimator*)>& callback,
- NetworkMetricsProvider::NetworkQualityEstimatorProvider*
- network_quality_estimator_provider) {
- callback.Run(
- network_quality_estimator_provider->GetNetworkQualityEstimator());
-}
-
SystemProfileProto::Network::EffectiveConnectionType
ConvertEffectiveConnectionType(
net::EffectiveConnectionType effective_connection_type) {
@@ -57,6 +45,7 @@ ConvertEffectiveConnectionType(
case net::EFFECTIVE_CONNECTION_TYPE_4G:
return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G;
case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_OFFLINE;
case net::EFFECTIVE_CONNECTION_TYPE_LAST:
NOTREACHED();
return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
@@ -65,8 +54,6 @@ ConvertEffectiveConnectionType(
return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
}
-} // namespace
-
// Listens to the changes in the effective conection type.
class NetworkMetricsProvider::EffectiveConnectionTypeObserver
: public net::EffectiveConnectionTypeObserver {
@@ -143,9 +130,6 @@ NetworkMetricsProvider::NetworkMetricsProvider(
ProbeWifiPHYLayerProtocol();
if (network_quality_estimator_provider_) {
- network_quality_task_runner_ =
- network_quality_estimator_provider_->GetTaskRunner();
- DCHECK(network_quality_task_runner_);
effective_connection_type_observer_.reset(
new EffectiveConnectionTypeObserver(
base::Bind(
@@ -157,39 +141,43 @@ NetworkMetricsProvider::NetworkMetricsProvider(
// |effective_connection_type_observer_| on the same task runner on which
// the network quality estimator lives. It is safe to use base::Unretained
// here since both |network_quality_estimator_provider_| and
- // |effective_connection_type_observer_| are owned by |this|, and are
- // deleted on the |network_quality_task_runner_|.
- network_quality_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&GetAndSetNetworkQualityEstimator,
- base::Bind(&EffectiveConnectionTypeObserver::Init,
- base::Unretained(
- effective_connection_type_observer_.get())),
- network_quality_estimator_provider_.get()));
+ // |effective_connection_type_observer_| are owned by |this|, and
+ // |network_quality_estimator_provider_| is deleted before
+ // |effective_connection_type_observer_|.
+ network_quality_estimator_provider_->PostReplyNetworkQualityEstimator(
+ base::Bind(
+ &EffectiveConnectionTypeObserver::Init,
+ base::Unretained(effective_connection_type_observer_.get())));
}
}
NetworkMetricsProvider::~NetworkMetricsProvider() {
DCHECK(thread_checker_.CalledOnValidThread());
net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
- if (effective_connection_type_observer_ &&
- !network_quality_task_runner_->DeleteSoon(
- FROM_HERE, effective_connection_type_observer_.release())) {
- NOTREACHED() << " ECT observer was not deleted successfully";
- }
- if (network_quality_estimator_provider_ &&
- !network_quality_task_runner_->DeleteSoon(
- FROM_HERE, network_quality_estimator_provider_.release())) {
- NOTREACHED()
- << " Network quality estimate provider was not deleted successfully";
+
+ if (network_quality_estimator_provider_) {
+ scoped_refptr<base::SequencedTaskRunner> network_quality_task_runner =
+ network_quality_estimator_provider_->GetTaskRunner();
+
+ // |network_quality_estimator_provider_| must be deleted before
+ // |effective_connection_type_observer_| since
+ // |effective_connection_type_observer_| may callback into
+ // |effective_connection_type_observer_|.
+ network_quality_estimator_provider_.reset();
+
+ if (network_quality_task_runner &&
+ !network_quality_task_runner->DeleteSoon(
+ FROM_HERE, effective_connection_type_observer_.release())) {
+ NOTREACHED() << " ECT observer was not deleted successfully";
+ }
}
}
-void NetworkMetricsProvider::ProvideGeneralMetrics(
+void NetworkMetricsProvider::ProvideCurrentSessionData(
ChromeUserMetricsExtension*) {
DCHECK(thread_checker_.CalledOnValidThread());
- // ProvideGeneralMetrics is called on the main thread, at the time a metrics
- // record is being finalized.
+ // ProvideCurrentSessionData is called on the main thread, at the time a
+ // metrics record is being finalized.
net::NetworkChangeNotifier::FinalizingMetricsLogRecord();
LogAggregatedMetrics();
}
@@ -448,6 +436,15 @@ void NetworkMetricsProvider::OnEffectiveConnectionTypeChanged(
return;
}
+ if (min_effective_connection_type_ ==
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
+ max_effective_connection_type_ ==
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
+ min_effective_connection_type_ = type;
+ max_effective_connection_type_ = type;
+ return;
+ }
+
min_effective_connection_type_ =
std::min(min_effective_connection_type_, effective_connection_type_);
max_effective_connection_type_ =
@@ -456,6 +453,9 @@ void NetworkMetricsProvider::OnEffectiveConnectionTypeChanged(
DCHECK_EQ(
min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
+ DCHECK_EQ(
+ min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
}
} // namespace metrics
diff --git a/chromium/components/metrics/net/network_metrics_provider.h b/chromium/components/metrics/net/network_metrics_provider.h
index 69d514a9f73..09a2bc24288 100644
--- a/chromium/components/metrics/net/network_metrics_provider.h
+++ b/chromium/components/metrics/net/network_metrics_provider.h
@@ -25,6 +25,10 @@ class NetworkQualityEstimator;
namespace metrics {
+SystemProfileProto::Network::EffectiveConnectionType
+ConvertEffectiveConnectionType(
+ net::EffectiveConnectionType effective_connection_type);
+
// Registers as observer with net::NetworkChangeNotifier and keeps track of
// the network environment.
class NetworkMetricsProvider
@@ -36,8 +40,12 @@ class NetworkMetricsProvider
public:
virtual ~NetworkQualityEstimatorProvider() {}
- // Returns the network quality estimator. May be nullptr.
- virtual net::NetworkQualityEstimator* GetNetworkQualityEstimator() = 0;
+ // Returns the network quality estimator by calling |io_callback|. The
+ // returned network quality estimator may be nullptr. |io_callback| must be
+ // called on the IO thread. |io_callback| can be destroyed on IO thread only
+ // after |this| is destroyed.
+ virtual void PostReplyNetworkQualityEstimator(
+ base::Callback<void(net::NetworkQualityEstimator*)> io_callback) = 0;
// Returns the task runner on which |this| should be used and destroyed.
virtual scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() = 0;
@@ -61,12 +69,15 @@ class NetworkMetricsProvider
FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest, EffectiveConnectionType);
FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest,
ECTAmbiguousOnConnectionTypeChange);
+ FRIEND_TEST_ALL_PREFIXES(NetworkMetricsProviderTest,
+ ECTNotAmbiguousOnOffline);
// Listens to the changes in the effective conection type.
class EffectiveConnectionTypeObserver;
// MetricsProvider:
- void ProvideGeneralMetrics(ChromeUserMetricsExtension* uma_proto) override;
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
void ProvideSystemProfileMetrics(SystemProfileProto* system_profile) override;
// ConnectionTypeObserver:
@@ -120,14 +131,10 @@ class NetworkMetricsProvider
network_quality_estimator_provider_;
// Listens to the changes in the effective connection type. Initialized and
- // destroyed using |network_quality_task_runner_|. May be null.
+ // destroyed on the IO thread. May be null.
std::unique_ptr<EffectiveConnectionTypeObserver>
effective_connection_type_observer_;
- // Task runner using which |effective_connection_type_observer_| is
- // initialized and destroyed. May be null.
- scoped_refptr<base::SequencedTaskRunner> network_quality_task_runner_;
-
// Last known effective connection type.
net::EffectiveConnectionType effective_connection_type_;
diff --git a/chromium/components/metrics/net/network_metrics_provider_unittest.cc b/chromium/components/metrics/net/network_metrics_provider_unittest.cc
index 469a409e165..4b4d04db178 100644
--- a/chromium/components/metrics/net/network_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/net/network_metrics_provider_unittest.cc
@@ -37,8 +37,9 @@ class TestNetworkQualityEstimatorProvider
return base::ThreadTaskRunnerHandle::Get();
}
- net::NetworkQualityEstimator* GetNetworkQualityEstimator() override {
- return estimator_;
+ void PostReplyNetworkQualityEstimator(
+ base::Callback<void(net::NetworkQualityEstimator*)> callback) override {
+ callback.Run(estimator_);
}
net::TestNetworkQualityEstimator* estimator_;
@@ -97,7 +98,6 @@ TEST_F(NetworkMetricsProviderTest, EffectiveConnectionType) {
// Running a request would cause the effective connection type to be computed
// as 2G, and observers to be notified.
estimator.RunOneRequest();
- base::RunLoop().RunUntilIdle();
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
network_metrics_provider.effective_connection_type_);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
@@ -117,7 +117,6 @@ TEST_F(NetworkMetricsProviderTest, EffectiveConnectionType) {
// Running a request would cause the effective connection type to be computed
// as SLOW_2G, and observers to be notified.
estimator.RunOneRequest();
- base::RunLoop().RunUntilIdle();
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
network_metrics_provider.effective_connection_type_);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
@@ -166,7 +165,6 @@ TEST_F(NetworkMetricsProviderTest, ECTAmbiguousOnConnectionTypeChange) {
// Running a request would cause the effective connection type to be computed
// as 2G, and observers to be notified.
estimator.RunOneRequest();
- base::RunLoop().RunUntilIdle();
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
network_metrics_provider.effective_connection_type_);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
@@ -193,4 +191,47 @@ TEST_F(NetworkMetricsProviderTest, ECTAmbiguousOnConnectionTypeChange) {
system_profile.network().max_effective_connection_type());
}
+// Verifies that the effective connection type is not set to UNKNOWN when the
+// connection type is OFFLINE.
+TEST_F(NetworkMetricsProviderTest, ECTNotAmbiguousOnOffline) {
+ for (net::EffectiveConnectionType force_ect :
+ {net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE}) {
+ std::unique_ptr<net::NetworkQualityEstimatorParams> params =
+ base::MakeUnique<net::NetworkQualityEstimatorParams>(
+ std::map<std::string, std::string>());
+ net::NetworkQualityEstimatorParams* params_ptr = params.get();
+ net::TestNetworkQualityEstimator estimator(std::move(params));
+
+ std::unique_ptr<NetworkMetricsProvider::NetworkQualityEstimatorProvider>
+ estimator_provider(base::WrapUnique(
+ new TestNetworkQualityEstimatorProvider(&estimator)));
+ SystemProfileProto system_profile;
+ NetworkMetricsProvider network_metrics_provider(
+ std::move(estimator_provider));
+
+ params_ptr->SetForcedEffectiveConnectionType(
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
+ estimator.RunOneRequest();
+
+ params_ptr->SetForcedEffectiveConnectionType(force_ect);
+ estimator.RunOneRequest();
+ network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
+ EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+ system_profile.network().min_effective_connection_type());
+ EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+ system_profile.network().max_effective_connection_type());
+
+ params_ptr->SetForcedEffectiveConnectionType(
+ net::EFFECTIVE_CONNECTION_TYPE_4G);
+ estimator.RunOneRequest();
+
+ network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
+ EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G,
+ system_profile.network().min_effective_connection_type());
+ EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G,
+ system_profile.network().max_effective_connection_type());
+ }
+}
+
} // namespace metrics \ No newline at end of file
diff --git a/chromium/components/metrics/profiler/profiler_metrics_provider.cc b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
index 3c3ffbad6aa..398626aec85 100644
--- a/chromium/components/metrics/profiler/profiler_metrics_provider.cc
+++ b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
@@ -65,7 +65,7 @@ ProfilerMetricsProvider::ProfilerMetricsProvider(
ProfilerMetricsProvider::~ProfilerMetricsProvider() {
}
-void ProfilerMetricsProvider::ProvideGeneralMetrics(
+void ProfilerMetricsProvider::ProvideCurrentSessionData(
ChromeUserMetricsExtension* uma_proto) {
DCHECK_EQ(0, uma_proto->profiler_event_size());
diff --git a/chromium/components/metrics/profiler/profiler_metrics_provider.h b/chromium/components/metrics/profiler/profiler_metrics_provider.h
index 8585fce5549..efb44c123fd 100644
--- a/chromium/components/metrics/profiler/profiler_metrics_provider.h
+++ b/chromium/components/metrics/profiler/profiler_metrics_provider.h
@@ -28,7 +28,8 @@ class ProfilerMetricsProvider : public MetricsProvider {
~ProfilerMetricsProvider() override;
// MetricsDataProvider:
- void ProvideGeneralMetrics(ChromeUserMetricsExtension* uma_proto) override;
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
// Records the passed profiled data, which should be a snapshot of the
// browser's profiled performance during startup for a single process.
@@ -48,9 +49,9 @@ class ProfilerMetricsProvider : public MetricsProvider {
bool IsCellularLogicEnabled();
// Saved cache of generated Profiler event protos, to be copied into the UMA
- // proto when ProvideGeneralMetrics() is called. The map is from a profiling
- // phase id to the profiler event proto that represents profiler data for the
- // profiling phase.
+ // proto when ProvideCurrentSessionData() is called. The map is from a
+ // profiling phase id to the profiler event proto that represents profiler
+ // data for the profiling phase.
std::map<int, ProfilerEventProto> profiler_events_cache_;
// Returns true if current connection type is cellular and user is assigned to
diff --git a/chromium/components/metrics/profiler/profiler_metrics_provider_unittest.cc b/chromium/components/metrics/profiler/profiler_metrics_provider_unittest.cc
index 050a87ad9fa..84def81949c 100644
--- a/chromium/components/metrics/profiler/profiler_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/profiler/profiler_metrics_provider_unittest.cc
@@ -145,7 +145,7 @@ TEST(ProfilerMetricsProviderTest, RecordData) {
// Capture the data and verify that it is as expected.
ChromeUserMetricsExtension uma_proto;
- profiler_metrics_provider.ProvideGeneralMetrics(&uma_proto);
+ profiler_metrics_provider.ProvideCurrentSessionData(&uma_proto);
// Phase 0
ASSERT_EQ(2, uma_proto.profiler_event_size());
diff --git a/chromium/components/metrics/proto/cast_logs.proto b/chromium/components/metrics/proto/cast_logs.proto
index 171f86d5975..738f7047d1c 100644
--- a/chromium/components/metrics/proto/cast_logs.proto
+++ b/chromium/components/metrics/proto/cast_logs.proto
@@ -18,7 +18,7 @@ message CastLogsProto {
// Next tag: 6
message CastDeviceInfo {
// The product type of Cast device sent from Cast-enabled devices.
- // Next tag: 7
+ // Next tag: 8
enum CastProductType {
CAST_PRODUCT_TYPE_UNKNOWN = 0;
CAST_PRODUCT_TYPE_CHROMECAST = 1;
@@ -27,6 +27,7 @@ message CastLogsProto {
CAST_PRODUCT_TYPE_ANDROID_TV = 4;
CAST_PRODUCT_TYPE_ASSISTANT = 5;
CAST_PRODUCT_TYPE_ANDROID_THINGS = 6;
+ CAST_PRODUCT_TYPE_CHROME_OS = 7;
}
optional CastProductType type = 1;
diff --git a/chromium/components/metrics/proto/omnibox_event.proto b/chromium/components/metrics/proto/omnibox_event.proto
index 1998a08fb21..af81e42b2e1 100644
--- a/chromium/components/metrics/proto/omnibox_event.proto
+++ b/chromium/components/metrics/proto/omnibox_event.proto
@@ -23,7 +23,7 @@ message OmniboxEventProto {
// These numbers are only comparable within a session. To sequence events
// across sessions, order by the |session_id| from the
// ChromeUserMetricsExtension message.
- optional int64 time = 1;
+ optional int64 time_sec = 1;
// The id of the originating tab for this omnibox interaction.
// This is the current tab *unless* the user opened the target in a new tab.
@@ -148,7 +148,7 @@ message OmniboxEventProto {
}
optional PageClassification current_page_classification = 10;
- optional OmniboxInputType.Type input_type = 8;
+ optional OmniboxInputType input_type = 8;
// An enum used in multiple places below.
enum ProviderType {
diff --git a/chromium/components/metrics/proto/omnibox_input_type.proto b/chromium/components/metrics/proto/omnibox_input_type.proto
index c97d4a4e69a..f27f7bd16a2 100644
--- a/chromium/components/metrics/proto/omnibox_input_type.proto
+++ b/chromium/components/metrics/proto/omnibox_input_type.proto
@@ -10,14 +10,14 @@ option optimize_for = LITE_RUNTIME;
option java_outer_classname = "OmniboxInputTypeProtos";
option java_package = "org.chromium.components.metrics";
-package metrics.OmniboxInputType;
+package metrics;
// What kind of input the user provided.
// Note that the type below may be misleading. For example, "http:/" alone
// cannot be opened as a URL, so it is marked as a QUERY; yet the user
// probably intends to type more and have it eventually become a URL, so we
// need to make sure we still run it through inline autocomplete.
-enum Type {
+enum OmniboxInputType {
// Empty input (should not reach here)
INVALID = 0;
diff --git a/chromium/components/metrics/proto/perf_stat.proto b/chromium/components/metrics/proto/perf_stat.proto
index bdfb3c458bf..54fdf27faca 100644
--- a/chromium/components/metrics/proto/perf_stat.proto
+++ b/chromium/components/metrics/proto/perf_stat.proto
@@ -23,7 +23,7 @@ message PerfStatProto {
// Represents one line of "perf stat" output.
// Next tag: 4
- message PerfStatLine{
+ message PerfStatLine {
// Time since the start of the "perf stat" command, in milliseconds.
//
// When running "perf stat" and printing the counters at the end, this is
@@ -47,6 +47,6 @@ message PerfStatProto {
// This string should also appear as part of |PerfStatProto::command_line|.
// "perf stat" will preserve the event name exactly as it is passed in via
// the command line.
- optional string event = 3;
+ optional string event_name = 3;
}
}
diff --git a/chromium/components/metrics/proto/system_profile.proto b/chromium/components/metrics/proto/system_profile.proto
index 6b4dc6f4c8b..9620396554c 100644
--- a/chromium/components/metrics/proto/system_profile.proto
+++ b/chromium/components/metrics/proto/system_profile.proto
@@ -89,7 +89,7 @@ message SystemProfileProto {
optional string version = 2;
// The fingerprint of the build. This field is used only on Android.
- optional string fingerprint = 3;
+ optional string build_fingerprint = 3;
// Whether the version of iOS appears to be "jailbroken". This field is
// used only on iOS. Chrome for iOS detects whether device contains a
@@ -256,7 +256,8 @@ message SystemProfileProto {
optional bool internal_display_supports_touch = 14;
// Vendor ids and product ids of external touchscreens.
- message TouchScreen {
+ // Deprecated as of 8/11/2017.
+ message DeprecatedTouchScreen {
// Touch screen vendor id.
optional uint32 vendor_id = 1;
// Touch screen product id.
@@ -264,7 +265,9 @@ message SystemProfileProto {
}
// Lists vendor and product ids of external touchscreens.
// Logged on ChromeOS only.
- repeated TouchScreen external_touchscreen = 15;
+ // Deprecated as of 8/11/2017.
+ repeated DeprecatedTouchScreen deprecated_external_touchscreen = 15
+ [deprecated = true];
// Drive messages are currently logged on Windows 7+, iOS, and Android.
message Drive {
@@ -375,7 +378,7 @@ message SystemProfileProto {
// Deprecated: Specifies that the connection_type changed during the
// lifetime of the log.
DEPRECATED_EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS = 1 [deprecated = true];
- DEPRECATED_EFFECTIVE_CONNECTION_TYPE_OFFLINE = 2 [deprecated = true];
+ EFFECTIVE_CONNECTION_TYPE_OFFLINE = 2;
EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 3;
EFFECTIVE_CONNECTION_TYPE_2G = 4;
EFFECTIVE_CONNECTION_TYPE_3G = 5;
@@ -899,4 +902,44 @@ message SystemProfileProto {
optional AntiVirusState product_state = 5;
}
repeated AntiVirusProduct antivirus_product = 23;
+
+ enum ComponentId {
+ // Represents any component that is not one of the below.
+ UNKNOWN = 1;
+
+ // All the following are various components.
+ FILE_TYPE_POLICIES = 2;
+ ORIGIN_TRIALS = 3;
+ PEPPER_FLASH = 4;
+ PEPPER_FLASH_CHROMEOS = 5;
+ PNACL = 6;
+ RECOVERY = 7;
+ SSL_ERROR_ASSISTANT = 8;
+ STH_SET = 9;
+ CRL_SET = 10;
+ SUBRESOURCE_FILTER = 11;
+ SW_REPORTER = 12;
+ WIDEVINE_CDM = 13;
+ EPSON_INKJET_PRINTER_ESCPR = 14;
+ }
+
+ // Information about what Chrome components are registered and at which
+ // version.
+ // Next Tag: 4
+ message ChromeComponent {
+ // Which component this information is for.
+ optional ComponentId component_id = 1 [default = UNKNOWN];
+
+ // Human-readable dotted-quad representation of the currently-installed
+ // version of the component, e.g. "1.2.3.4".
+ optional string version = 2;
+
+ // The first 32 bits of the Omaha-style fingerprint of the installed
+ // component, discarding any bits that describe the fingerprint format. In
+ // practice this is the first 32 bits of the SHA256 hash of the package that
+ // was installed as the component. It is a stronger version number that can
+ // vary across platform, architecture, or branches of an A/B component test.
+ optional fixed32 omaha_fingerprint = 3;
+ }
+ repeated ChromeComponent chrome_component = 24;
}
diff --git a/chromium/components/metrics/proto/translate_event.proto b/chromium/components/metrics/proto/translate_event.proto
index c2ced5c8849..c06a6399896 100644
--- a/chromium/components/metrics/proto/translate_event.proto
+++ b/chromium/components/metrics/proto/translate_event.proto
@@ -67,7 +67,7 @@ message TranslateEventProto {
optional RankerResponse ranker_response = 9;
// The action performed by the user in the translate UI.
- // Next tag 27.
+ // Next tag 28.
enum EventType {
// The feedback event does not correspond to any of the enumerated
// cases.
@@ -141,6 +141,9 @@ message TranslateEventProto {
// The translate UI was not shown because the language is in the user's User
// Language Profile.
LANGUAGE_IN_ULP = 24;
+ // Failed to initialize the translate script, this can happen for iOS due
+ // to CSPs.
+ INITIALIZATION_ERROR = 27;
}
// Event received from translate UI.
diff --git a/chromium/components/metrics/proto/ukm/report.proto b/chromium/components/metrics/proto/ukm/report.proto
index 8627d5defed..bca79026db9 100644
--- a/chromium/components/metrics/proto/ukm/report.proto
+++ b/chromium/components/metrics/proto/ukm/report.proto
@@ -25,6 +25,10 @@ message Report {
// that is incremented each time the user relaunches Chrome.
optional int32 session_id = 5;
+ // The report id for this record. Report ids increase sequentially from
+ // one within a session.
+ optional int32 report_id = 6;
+
// Information about the user's browser and system configuration.
optional metrics.SystemProfileProto system_profile = 2;
diff --git a/chromium/components/metrics/proto/ukm/source.proto b/chromium/components/metrics/proto/ukm/source.proto
index d4a00605a98..7b10ae2b526 100644
--- a/chromium/components/metrics/proto/ukm/source.proto
+++ b/chromium/components/metrics/proto/ukm/source.proto
@@ -9,7 +9,7 @@ package ukm;
option optimize_for = LITE_RUNTIME;
// Source contains data related to a top-level navigation.
-// Next tag: 7
+// Next tag: 8
message Source {
// An identifier for the source. This should be unique within a session.
optional int64 id = 1;
@@ -27,6 +27,9 @@ message Source {
// discovered by Google's crawler, it should not be recorded.
optional string initial_url = 6;
+ // Flag indicating if the metric was collected while inside a "custom tab".
+ optional bool is_custom_tab = 7;
+
// Timestamp of navigation to this Source, as seen by the client. Time of
// events related to this Source will generally be relative to this timestamp.
optional int64 navigation_time_msec = 3;
diff --git a/chromium/components/metrics/proto/user_action_event.proto b/chromium/components/metrics/proto/user_action_event.proto
index b7baa17c13c..87f766584d5 100644
--- a/chromium/components/metrics/proto/user_action_event.proto
+++ b/chromium/components/metrics/proto/user_action_event.proto
@@ -25,5 +25,5 @@ message UserActionEventProto {
// These numbers are only comparable within a session. To sequence events
// across sessions, order by the |session_id| from the
// ChromeUserMetricsExtension message.
- optional int64 time = 2;
+ optional int64 time_sec = 2;
}
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 82b31d271eb..1ba27b94987 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -53,7 +53,7 @@ int MapCrashExitCodeForHistogram(int exit_code) {
return std::abs(exit_code);
}
-void RecordChildKills(int histogram_type) {
+void RecordChildKills(RendererType histogram_type) {
UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills",
histogram_type, RENDERER_TYPE_COUNT);
}
@@ -179,7 +179,7 @@ void StabilityMetricsHelper::LogLoadStarted() {
void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
base::TerminationStatus status,
int exit_code) {
- int histogram_type =
+ RendererType histogram_type =
was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
switch (status) {
diff --git a/chromium/components/metrics/test_metrics_provider.cc b/chromium/components/metrics/test_metrics_provider.cc
index ff420b867e4..1c7bb5eaf4a 100644
--- a/chromium/components/metrics/test_metrics_provider.cc
+++ b/chromium/components/metrics/test_metrics_provider.cc
@@ -16,19 +16,20 @@ void TestMetricsProvider::OnRecordingDisabled() {
on_recording_disabled_called_ = true;
}
-bool TestMetricsProvider::HasInitialStabilityMetrics() {
+bool TestMetricsProvider::HasPreviousSessionData() {
has_initial_stability_metrics_called_ = true;
return has_initial_stability_metrics_;
}
-void TestMetricsProvider::ProvideInitialStabilityMetrics(
- SystemProfileProto* system_profile_proto) {
+void TestMetricsProvider::ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
UMA_STABILITY_HISTOGRAM_ENUMERATION("TestMetricsProvider.Initial", 1, 2);
provide_initial_stability_metrics_called_ = true;
+ ProvideCurrentSessionData(nullptr);
}
-void TestMetricsProvider::ProvideStabilityMetrics(
- SystemProfileProto* system_profile_proto) {
+void TestMetricsProvider::ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
UMA_STABILITY_HISTOGRAM_ENUMERATION("TestMetricsProvider.Regular", 1, 2);
provide_stability_metrics_called_ = true;
}
diff --git a/chromium/components/metrics/test_metrics_provider.h b/chromium/components/metrics/test_metrics_provider.h
index 44d8f0c4012..257895400f1 100644
--- a/chromium/components/metrics/test_metrics_provider.h
+++ b/chromium/components/metrics/test_metrics_provider.h
@@ -26,11 +26,11 @@ class TestMetricsProvider : public MetricsProvider {
// MetricsProvider:
void Init() override;
void OnRecordingDisabled() override;
- bool HasInitialStabilityMetrics() override;
- void ProvideInitialStabilityMetrics(
- SystemProfileProto* system_profile_proto) override;
- void ProvideStabilityMetrics(
- SystemProfileProto* system_profile_proto) override;
+ bool HasPreviousSessionData() override;
+ void ProvidePreviousSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
+ void ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) override;
void ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto) override;
diff --git a/chromium/components/metrics/test_metrics_service_client.cc b/chromium/components/metrics/test_metrics_service_client.cc
index 27a822b1674..cea1edffab0 100644
--- a/chromium/components/metrics/test_metrics_service_client.cc
+++ b/chromium/components/metrics/test_metrics_service_client.cc
@@ -54,11 +54,6 @@ std::string TestMetricsServiceClient::GetVersionString() {
return version_string_;
}
-void TestMetricsServiceClient::InitializeSystemProfileMetrics(
- const base::Closure& done_callback) {
- done_callback.Run();
-}
-
void TestMetricsServiceClient::CollectFinalMetricsForLog(
const base::Closure& done_callback) {
done_callback.Run();
diff --git a/chromium/components/metrics/test_metrics_service_client.h b/chromium/components/metrics/test_metrics_service_client.h
index 40342777964..eb5510e4970 100644
--- a/chromium/components/metrics/test_metrics_service_client.h
+++ b/chromium/components/metrics/test_metrics_service_client.h
@@ -33,8 +33,6 @@ class TestMetricsServiceClient : public MetricsServiceClient {
bool GetBrand(std::string* brand_code) override;
SystemProfileProto::Channel GetChannel() override;
std::string GetVersionString() override;
- void InitializeSystemProfileMetrics(
- const base::Closure& done_callback) override;
void CollectFinalMetricsForLog(const base::Closure& done_callback) override;
std::unique_ptr<MetricsLogUploader> CreateUploader(
base::StringPiece server_url,
diff --git a/chromium/components/mime_util/BUILD.gn b/chromium/components/mime_util/BUILD.gn
deleted file mode 100644
index a61ed10fe66..00000000000
--- a/chromium/components/mime_util/BUILD.gn
+++ /dev/null
@@ -1,34 +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.
-
-static_library("mime_util") {
- sources = [
- "mime_util.cc",
- "mime_util.h",
- ]
-
- deps = [
- "//base",
- "//net",
- ]
-
- # iOS doesn't use and must not depend on //media
- if (!is_ios) {
- deps += [ "//media" ]
- }
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "mime_util_unittest.cc",
- ]
-
- deps = [
- ":mime_util",
- "//base",
- "//net",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/mime_util/DEPS b/chromium/components/mime_util/DEPS
deleted file mode 100644
index efe081160c3..00000000000
--- a/chromium/components/mime_util/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+media/base/mime_util.h", # Only for platforms other than iOS
- "+net/base",
-]
diff --git a/chromium/components/mime_util/OWNERS b/chromium/components/mime_util/OWNERS
deleted file mode 100644
index ca45491caa6..00000000000
--- a/chromium/components/mime_util/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-asanka@chromium.org
-cbentzel@chromium.org
-eroman@chromium.org
-mmenke@chromium.org
-rsleevi@chromium.org
-
-# COMPONENT: Internals>Network
diff --git a/chromium/components/mime_util/mime_util.cc b/chromium/components/mime_util/mime_util.cc
deleted file mode 100644
index 5539c83cfac..00000000000
--- a/chromium/components/mime_util/mime_util.cc
+++ /dev/null
@@ -1,203 +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/mime_util/mime_util.h"
-
-#include <stddef.h>
-
-#include "base/containers/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "base/strings/string_util.h"
-#include "build/build_config.h"
-#include "net/base/mime_util.h"
-
-#if !defined(OS_IOS)
-// iOS doesn't use and must not depend on //media
-#include "media/base/mime_util.h"
-#endif
-
-namespace mime_util {
-
-namespace {
-
-// From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
-
-const char* const kSupportedImageTypes[] = {"image/jpeg",
- "image/pjpeg",
- "image/jpg",
- "image/webp",
- "image/png",
- "image/gif",
- "image/bmp",
- "image/vnd.microsoft.icon", // ico
- "image/x-icon", // ico
- "image/x-xbitmap", // xbm
- "image/x-png"};
-
-// Support every script type mentioned in the spec, as it notes that "User
-// agents must recognize all JavaScript MIME types." See
-// https://html.spec.whatwg.org/#javascript-mime-type.
-const char* const kSupportedJavascriptTypes[] = {
- "application/ecmascript",
- "application/javascript",
- "application/x-ecmascript",
- "application/x-javascript",
- "text/ecmascript",
- "text/javascript",
- "text/javascript1.0",
- "text/javascript1.1",
- "text/javascript1.2",
- "text/javascript1.3",
- "text/javascript1.4",
- "text/javascript1.5",
- "text/jscript",
- "text/livescript",
- "text/x-ecmascript",
- "text/x-javascript",
-};
-
-// These types are excluded from the logic that allows all text/ types because
-// while they are technically text, it's very unlikely that a user expects to
-// see them rendered in text form.
-static const char* const kUnsupportedTextTypes[] = {
- "text/calendar",
- "text/x-calendar",
- "text/x-vcalendar",
- "text/vcalendar",
- "text/vcard",
- "text/x-vcard",
- "text/directory",
- "text/ldif",
- "text/qif",
- "text/x-qif",
- "text/x-csv",
- "text/x-vcf",
- "text/rtf",
- "text/comma-separated-values",
- "text/csv",
- "text/tab-separated-values",
- "text/tsv",
- "text/ofx", // http://crbug.com/162238
- "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450
-};
-
-// Note:
-// - does not include javascript types list (see supported_javascript_types)
-// - does not include types starting with "text/" (see
-// IsSupportedNonImageMimeType())
-static const char* const kSupportedNonImageTypes[] = {
- "image/svg+xml", // SVG is text-based XML, even though it has an image/
- // type
- "application/xml",
- "application/atom+xml",
- "application/rss+xml",
- "application/xhtml+xml",
- "application/json",
- "multipart/related", // For MHTML support.
- "multipart/x-mixed-replace"
- // Note: ADDING a new type here will probably render it AS HTML. This can
- // result in cross site scripting.
-};
-
-// Singleton utility class for mime types
-class MimeUtil {
- public:
- bool IsSupportedImageMimeType(const std::string& mime_type) const;
- bool IsSupportedNonImageMimeType(const std::string& mime_type) const;
- bool IsUnsupportedTextMimeType(const std::string& mime_type) const;
- bool IsSupportedJavascriptMimeType(const std::string& mime_type) const;
-
- bool IsSupportedMimeType(const std::string& mime_type) const;
-
- private:
- friend struct base::LazyInstanceTraitsBase<MimeUtil>;
-
- using MimeTypes = base::hash_set<std::string>;
-
- MimeUtil();
-
- MimeTypes image_types_;
- MimeTypes non_image_types_;
- MimeTypes unsupported_text_types_;
- MimeTypes javascript_types_;
-
- DISALLOW_COPY_AND_ASSIGN(MimeUtil);
-};
-
-MimeUtil::MimeUtil() {
- for (size_t i = 0; i < arraysize(kSupportedNonImageTypes); ++i)
- non_image_types_.insert(kSupportedNonImageTypes[i]);
- for (size_t i = 0; i < arraysize(kSupportedImageTypes); ++i)
- image_types_.insert(kSupportedImageTypes[i]);
- for (size_t i = 0; i < arraysize(kUnsupportedTextTypes); ++i)
- unsupported_text_types_.insert(kUnsupportedTextTypes[i]);
- for (size_t i = 0; i < arraysize(kSupportedJavascriptTypes); ++i) {
- javascript_types_.insert(kSupportedJavascriptTypes[i]);
- non_image_types_.insert(kSupportedJavascriptTypes[i]);
- }
-}
-
-bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
- return image_types_.find(base::ToLowerASCII(mime_type)) != image_types_.end();
-}
-
-bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
- return non_image_types_.find(base::ToLowerASCII(mime_type)) !=
- non_image_types_.end() ||
-#if !defined(OS_IOS)
- media::IsSupportedMediaMimeType(mime_type) ||
-#endif
- (base::StartsWith(mime_type, "text/",
- base::CompareCase::INSENSITIVE_ASCII) &&
- !IsUnsupportedTextMimeType(mime_type)) ||
- (base::StartsWith(mime_type, "application/",
- base::CompareCase::INSENSITIVE_ASCII) &&
- net::MatchesMimeType("application/*+json", mime_type));
-}
-
-bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
- return unsupported_text_types_.find(base::ToLowerASCII(mime_type)) !=
- unsupported_text_types_.end();
-}
-
-bool MimeUtil::IsSupportedJavascriptMimeType(
- const std::string& mime_type) const {
- return javascript_types_.find(mime_type) != javascript_types_.end();
-}
-
-bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
- return (base::StartsWith(mime_type, "image/",
- base::CompareCase::INSENSITIVE_ASCII) &&
- IsSupportedImageMimeType(mime_type)) ||
- IsSupportedNonImageMimeType(mime_type);
-}
-
-// This variable is Leaky because it is accessed from WorkerPool threads.
-static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-bool IsSupportedImageMimeType(const std::string& mime_type) {
- return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
-}
-
-bool IsSupportedNonImageMimeType(const std::string& mime_type) {
- return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
-}
-
-bool IsUnsupportedTextMimeType(const std::string& mime_type) {
- return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
-}
-
-bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
- return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
-}
-
-bool IsSupportedMimeType(const std::string& mime_type) {
- return g_mime_util.Get().IsSupportedMimeType(mime_type);
-}
-
-} // namespace mime_util
diff --git a/chromium/components/mime_util/mime_util.h b/chromium/components/mime_util/mime_util.h
deleted file mode 100644
index a10c47eb84e..00000000000
--- a/chromium/components/mime_util/mime_util.h
+++ /dev/null
@@ -1,24 +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.
-
-#ifndef COMPONENTS_MIME_UTIL_MIME_UTIL_H__
-#define COMPONENTS_MIME_UTIL_MIME_UTIL_H__
-
-#include <string>
-
-namespace mime_util {
-
-// Check to see if a particular MIME type is in the list of
-// supported/recognized MIME types.
-bool IsSupportedImageMimeType(const std::string& mime_type);
-bool IsSupportedNonImageMimeType(const std::string& mime_type);
-bool IsUnsupportedTextMimeType(const std::string& mime_type);
-bool IsSupportedJavascriptMimeType(const std::string& mime_type);
-
-// Convenience function.
-bool IsSupportedMimeType(const std::string& mime_type);
-
-} // namespace mime_util
-
-#endif // COMPONENTS_MIME_UTIL_MIME_UTIL_H__
diff --git a/chromium/components/mime_util/mime_util_unittest.cc b/chromium/components/mime_util/mime_util_unittest.cc
deleted file mode 100644
index 42e714d3b1c..00000000000
--- a/chromium/components/mime_util/mime_util_unittest.cc
+++ /dev/null
@@ -1,55 +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/mime_util/mime_util.h"
-
-#include "build/build_config.h"
-#include "net/base/mime_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mime_util {
-
-TEST(MimeUtilTest, LookupTypes) {
- EXPECT_FALSE(IsUnsupportedTextMimeType("text/banana"));
- EXPECT_TRUE(IsUnsupportedTextMimeType("text/vcard"));
-
- EXPECT_TRUE(IsSupportedImageMimeType("image/jpeg"));
- EXPECT_TRUE(IsSupportedImageMimeType("Image/JPEG"));
- EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat"));
- EXPECT_FALSE(IsSupportedImageMimeType("Image/LolCat"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("text/html"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("text/css"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("text/"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("text/banana"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("Text/Banana"));
- EXPECT_FALSE(IsSupportedNonImageMimeType("text/vcard"));
- EXPECT_FALSE(IsSupportedNonImageMimeType("application/virus"));
- EXPECT_FALSE(IsSupportedNonImageMimeType("Application/VIRUS"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("application/json"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("application/+json"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-suggestions+json"));
- EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-s+json;x=2"));
-#if defined(OS_ANDROID)
-#if 0 // Disabled until http://crbug.com/318217 is resolved.
- EXPECT_TRUE(IsSupportedMediaMimeType("application/vnd.apple.mpegurl"));
- EXPECT_TRUE(IsSupportedMediaMimeType("application/x-mpegurl"));
- EXPECT_TRUE(IsSupportedMediaMimeType("Application/X-MPEGURL"));
-#endif
-#endif
-
- EXPECT_TRUE(IsSupportedMimeType("image/jpeg"));
- EXPECT_FALSE(IsSupportedMimeType("image/lolcat"));
- EXPECT_FALSE(IsSupportedMimeType("Image/LOLCAT"));
- EXPECT_TRUE(IsSupportedMimeType("text/html"));
- EXPECT_TRUE(IsSupportedMimeType("text/banana"));
- EXPECT_TRUE(IsSupportedMimeType("Text/BANANA"));
- EXPECT_FALSE(IsSupportedMimeType("text/vcard"));
- EXPECT_FALSE(IsSupportedMimeType("application/virus"));
- EXPECT_FALSE(IsSupportedMimeType("application/x-json"));
- EXPECT_FALSE(IsSupportedMimeType("Application/X-JSON"));
- EXPECT_FALSE(IsSupportedNonImageMimeType("application/vnd.doc;x=y+json"));
- EXPECT_FALSE(IsSupportedNonImageMimeType("Application/VND.DOC;X=Y+JSON"));
-}
-
-} // namespace mime_util
diff --git a/chromium/components/minidump_uploader/BUILD.gn b/chromium/components/minidump_uploader/BUILD.gn
index 056ce6a6305..628bbc62e91 100644
--- a/chromium/components/minidump_uploader/BUILD.gn
+++ b/chromium/components/minidump_uploader/BUILD.gn
@@ -35,7 +35,7 @@ android_library("minidump_uploader_javatests") {
]
java_files = [
"android/javatests/src/org/chromium/components/minidump_uploader/CrashFileManagerTest.java",
- "android/javatests/src/org/chromium/components/minidump_uploader/CrashTestCase.java",
+ "android/javatests/src/org/chromium/components/minidump_uploader/CrashTestRule.java",
"android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java",
"android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java",
"android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploaderImplTest.java",
diff --git a/chromium/components/multidevice/OWNERS b/chromium/components/multidevice/OWNERS
new file mode 100644
index 00000000000..88535c42fb4
--- /dev/null
+++ b/chromium/components/multidevice/OWNERS
@@ -0,0 +1,4 @@
+khorimoto@chromium.org
+tengs@chromium.org
+
+# COMPONENT: UI>ProximityAuth
diff --git a/chromium/components/multidevice/README.md b/chromium/components/multidevice/README.md
new file mode 100644
index 00000000000..328b6434827
--- /dev/null
+++ b/chromium/components/multidevice/README.md
@@ -0,0 +1,14 @@
+[CrOS MultiDevice]
+
+Note: This component is in the process of being built. It will eventually
+ contain implementation that was previously part of
+ //components/cryptauth and //components/proximity_auth.
+
+This component contains the implementation of two APIs:
+(1) DeviceSync API: This API syncs metadata about other devices tied to a given
+ Google account. It contacts the CryptAuth back-end to enroll the current
+ device and sync down new data about other devices.
+(2) SecureChannnel API: This API gives clients the ability to establish
+ connections to remote devices synced via the DeviceSync API. Once a
+ communication channel is established, the API allows clients to send and
+ receive messages through the channel.
diff --git a/chromium/components/multidevice/service/public/interfaces/BUILD.gn b/chromium/components/multidevice/service/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..ed79d326819
--- /dev/null
+++ b/chromium/components/multidevice/service/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "device_sync.mojom",
+ ]
+}
diff --git a/chromium/components/multidevice/service/public/interfaces/OWNERS b/chromium/components/multidevice/service/public/interfaces/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/components/multidevice/service/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/multidevice/service/public/interfaces/device_sync.mojom b/chromium/components/multidevice/service/public/interfaces/device_sync.mojom
new file mode 100644
index 00000000000..18695a9c680
--- /dev/null
+++ b/chromium/components/multidevice/service/public/interfaces/device_sync.mojom
@@ -0,0 +1,101 @@
+// 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.
+
+module device_sync.mojom;
+
+import "mojo/common/time.mojom";
+
+// Used to generate rotating BLE advertisement data, which is necessary to
+// establish a BLE communication channel between two devices. To
+// create the BLE channel, both devices must possess the other's BeaconSeeds.
+struct BeaconSeed {
+ string data;
+ mojo.common.mojom.TimeTicks start_time;
+ mojo.common.mojom.TimeTicks end_time;
+};
+
+// Metadata describing a remote device with which the current device can
+// communicate.
+struct RemoteDevice {
+ // Public key used to authenticate a communication channel.
+ string public_key;
+
+ // Identifier which is unique to each device.
+ string device_id;
+
+ // Identifier for the user to whom this device is registered.
+ string user_id;
+
+ // Human-readable device name; by default, this is the name of the device
+ // model, but this value is editable.
+ string device_name;
+
+ // True if this device has the capability of unlocking another device via
+ // EasyUnlock.
+ bool unlock_key;
+
+ // True if this device can enable a Wi-Fi hotspot to support Instant
+ // Tethering (i.e., the device supports mobile data and its model supports the
+ // feature).
+ bool mobile_hotspot_supported;
+
+ // Seeds belonging to the device. Each seed has start and end timestamps which
+ // indicate how long the seed is valid, and each device has enough associated
+ // seeds to keep the device connectable for over 30 days. If no new device
+ // metadata synced for over 30 days, it is possible that a connection will not
+ // be able to be established over BLE.
+ array<BeaconSeed> beacon_seeds;
+};
+
+enum ResultCode {
+ SUCCESS,
+ ERROR_INTERNAL,
+ ERROR_NO_VALID_ACCESS_TOKEN,
+ ERROR_SERVER_FAILED_TO_RESPOND,
+ ERROR_CANNOT_PARSE_SERVER_RESPONSE,
+};
+
+enum PromotableFeature {
+ EASY_UNLOCK,
+};
+
+struct SetCapabilityResponse {
+ ResultCode result_code;
+};
+
+struct IneligibleDevice {
+ string device_id;
+ string reason; // Reason why the device is not eligible.
+};
+
+struct FindEligibleDevicesResponse {
+ ResultCode result_code;
+
+ // Only set when result_code == SUCCESS.
+ array<string> eligible_device_ids;
+ array<IneligibleDevice> ineligible_devices;
+};
+
+struct IsCapabilityPromotableResponse {
+ ResultCode result_code;
+
+ // Only set when result_code == SUCCESS.
+ bool is_promotable;
+};
+
+// Properties associated with a device which can be set and retrieved by calls
+// to the server.
+// TODO(khorimoto): Add additional capabilities, including the Tether
+// capability.
+enum RemoteDeviceCapability {
+ UNLOCK_KEY,
+};
+
+interface DeviceSyncObserver {
+ // TODO(khorimoto): Flesh out Observer.
+};
+
+interface DeviceSync {
+ // TODO(khorimoto): Flesh out API.
+};
diff --git a/chromium/components/nacl/broker/BUILD.gn b/chromium/components/nacl/broker/BUILD.gn
index bf0bf3a4d48..44db949d94d 100644
--- a/chromium/components/nacl/broker/BUILD.gn
+++ b/chromium/components/nacl/broker/BUILD.gn
@@ -62,7 +62,7 @@ if (current_cpu == "x86") {
# NOTE: This must match what //build/config/BUILDCONFIG.gn uses
# as default toolchain for the corresponding x64 build.
if (is_clang) {
- x64_toolchain = "//build/toolchain/win:clang_nacl_win64"
+ x64_toolchain = "//build/toolchain/win:win_clang_nacl_win64"
} else {
x64_toolchain = "//build/toolchain/win:nacl_win64"
}
diff --git a/chromium/components/nacl/loader/BUILD.gn b/chromium/components/nacl/loader/BUILD.gn
index 1eea0cea4eb..fe78475aaed 100644
--- a/chromium/components/nacl/loader/BUILD.gn
+++ b/chromium/components/nacl/loader/BUILD.gn
@@ -51,7 +51,7 @@ source_set("minimal") {
source_set("minimal_content_dummy") {
check_includes = false
sources = [
- "//content/public/child/child_process_sandbox_support_linux.h",
+ "//content/public/common/common_sandbox_support_linux.h",
"//content/public/common/main_function_params.h",
"//content/public/common/sandbox_init.h",
]
@@ -68,7 +68,6 @@ source_set("loader") {
]
deps = [
"//components/nacl/common",
- "//content/public/child",
"//content/public/common",
"//ppapi/shared_impl",
"//services/service_manager/public/cpp",
@@ -135,6 +134,12 @@ if (is_linux) {
ldflags = [ "-pie" ]
+ if (is_chromeos) {
+ # NaCl is not working with compiler-rt in ChromeOS.
+ # Force libgcc as a workaround. See https://crbug.com/761103
+ ldflags += [ "-rtlib=libgcc" ]
+ }
+
data_deps = [
"//native_client/src/trusted/service_runtime/linux:bootstrap",
]
diff --git a/chromium/components/net_log/net_export_file_writer.cc b/chromium/components/net_log/net_export_file_writer.cc
index 81d34d036fd..0800dfb9503 100644
--- a/chromium/components/net_log/net_export_file_writer.cc
+++ b/chromium/components/net_log/net_export_file_writer.cc
@@ -15,6 +15,7 @@
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -99,6 +100,17 @@ base::FilePath GetPathWithAllPermissions(const base::FilePath& path) {
#endif
}
+scoped_refptr<base::SequencedTaskRunner> CreateFileTaskRunner() {
+ // The tasks posted to this sequenced task runner do synchronous File I/O for
+ // checking paths and setting permissions on files.
+ //
+ // These operations can be skipped on shutdown since FileNetLogObserver's API
+ // doesn't require things to have completed until notified of completion.
+ return base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+}
+
} // namespace
NetExportFileWriter::NetExportFileWriter(ChromeNetLog* chrome_net_log)
@@ -126,15 +138,11 @@ void NetExportFileWriter::RemoveObserver(StateObserver* observer) {
}
void NetExportFileWriter::Initialize(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> net_task_runner) {
+ scoped_refptr<base::TaskRunner> net_task_runner) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(file_task_runner);
DCHECK(net_task_runner);
- if (file_task_runner_)
- DCHECK_EQ(file_task_runner_, file_task_runner);
- file_task_runner_ = file_task_runner;
+ file_task_runner_ = CreateFileTaskRunner();
if (net_task_runner_)
DCHECK_EQ(net_task_runner_, net_task_runner);
net_task_runner_ = net_task_runner;
diff --git a/chromium/components/net_log/net_export_file_writer.h b/chromium/components/net_log/net_export_file_writer.h
index 3d7f162b020..a1b11a58af3 100644
--- a/chromium/components/net_log/net_export_file_writer.h
+++ b/chromium/components/net_log/net_export_file_writer.h
@@ -22,7 +22,7 @@
namespace base {
class DictionaryValue;
-class SingleThreadTaskRunner;
+class TaskRunner;
} // namespace base
namespace net {
@@ -90,13 +90,11 @@ class NetExportFileWriter {
// Detaches a StateObserver.
void RemoveObserver(StateObserver* observer);
- // Initializes NetExportFileWriter if not initialized.
- //
- // Also sets the task runners used by NetExportFileWriter for doing file I/O
- // and network I/O respectively. The task runners must not be changed once
- // set. However, calling this function again with the same parameters is OK.
- void Initialize(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> net_task_runner);
+ // Initializes NetExportFileWriter if not initialized and sets the network
+ // task runner (used by NetExportFileWriter when querying network state).
+ // This task runner must not be changed once set. Calling this function again
+ // with the same parameter is OK.
+ void Initialize(scoped_refptr<base::TaskRunner> net_task_runner);
// Starts collecting NetLog data into the file at |log_path|. If |log_path| is
// empty, the default log path is used. If NetExportFileWriter is already
@@ -212,9 +210,9 @@ class NetExportFileWriter {
base::ThreadChecker thread_checker_;
// Task runners for file-specific and net-specific tasks that must run on a
- // file or net thread.
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> net_task_runner_;
+ // file or net task runner.
+ scoped_refptr<base::TaskRunner> file_task_runner_;
+ scoped_refptr<base::TaskRunner> net_task_runner_;
State state_; // Current logging state of NetExportFileWriter.
diff --git a/chromium/components/net_log/net_export_file_writer_unittest.cc b/chromium/components/net_log/net_export_file_writer_unittest.cc
index 88a1842ca3c..8b32e04a002 100644
--- a/chromium/components/net_log/net_export_file_writer_unittest.cc
+++ b/chromium/components/net_log/net_export_file_writer_unittest.cc
@@ -255,9 +255,7 @@ class NetExportFileWriterTest : public ::testing::Test {
std::vector<scoped_refptr<net::URLRequestContextGetter>>;
NetExportFileWriterTest()
- : file_writer_(&net_log_),
- file_thread_("NetLogFileWriter file thread"),
- net_thread_("NetLogFileWriter net thread") {}
+ : file_writer_(&net_log_), net_thread_("NetLogFileWriter net thread") {}
// ::testing::Test implementation
void SetUp() override {
@@ -270,7 +268,6 @@ class NetExportFileWriterTest : public ::testing::Test {
default_log_path_ = log_temp_dir_.GetPath().Append(kLogRelativePath);
- ASSERT_TRUE(file_thread_.Start());
ASSERT_TRUE(net_thread_.Start());
file_writer_.AddObserver(&test_state_observer_);
@@ -294,8 +291,7 @@ class NetExportFileWriterTest : public ::testing::Test {
WARN_UNUSED_RESULT ::testing::AssertionResult InitializeThenVerifyNewState(
bool expected_initialize_success,
bool expected_log_exists) {
- file_writer_.Initialize(file_thread_.task_runner(),
- net_thread_.task_runner());
+ file_writer_.Initialize(net_thread_.task_runner());
std::unique_ptr<base::DictionaryValue> state =
test_state_observer_.WaitForNewState();
::testing::AssertionResult result =
@@ -431,7 +427,6 @@ class NetExportFileWriterTest : public ::testing::Test {
// The default log path that |file_writer_| will use is cached here.
base::FilePath default_log_path_;
- base::Thread file_thread_;
base::Thread net_thread_;
TestStateObserver test_state_observer_;
@@ -737,8 +732,7 @@ TEST_F(NetExportFileWriterTest, StartWithContextGetters) {
TEST_F(NetExportFileWriterTest, ReceiveStartWhileInitializing) {
// Trigger initialization of |file_writer_|.
- file_writer_.Initialize(file_thread_.task_runner(),
- net_thread_.task_runner());
+ file_writer_.Initialize(net_thread_.task_runner());
// Before running the main message loop, tell |file_writer_| to start
// logging. Not running the main message loop prevents the initialization
diff --git a/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
index 06348354c63..dcaf75941bf 100644
--- a/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
+++ b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
Binary files differ
diff --git a/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
index 3a1e92e7263..366e82a910b 100644
--- a/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
+++ b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
Binary files differ
diff --git a/chromium/components/neterror/resources/neterror.css b/chromium/components/neterror/resources/neterror.css
index c7cd42e70cc..de7fd45dd4e 100644
--- a/chromium/components/neterror/resources/neterror.css
+++ b/chromium/components/neterror/resources/neterror.css
@@ -511,6 +511,7 @@ html[subframe] body {
.arcade-mode,
.arcade-mode .runner-container,
.arcade-mode .runner-canvas {
+ image-rendering: pixelated;
max-width: 100%;
overflow: hidden;
}
diff --git a/chromium/components/neterror/resources/offline.js b/chromium/components/neterror/resources/offline.js
index f7235b3b8a1..61aaeee48ba 100644
--- a/chromium/components/neterror/resources/offline.js
+++ b/chromium/components/neterror/resources/offline.js
@@ -778,7 +778,7 @@ Runner.prototype = {
this.stop();
this.crashed = true;
- this.distanceMeter.acheivement = false;
+ this.distanceMeter.achievement = false;
this.tRex.update(100, Trex.status.CRASHED);
@@ -866,9 +866,9 @@ Runner.prototype = {
var scaledCanvasHeight = this.dimensions.HEIGHT * scale;
// Positions the game container at 10% of the available vertical window
// height minus the game container height.
- var translateY = Math.max(0, (windowHeight - scaledCanvasHeight -
+ var translateY = Math.ceil(Math.max(0, (windowHeight - scaledCanvasHeight -
Runner.config.ARCADE_MODE_INITIAL_TOP_POSITION) *
- Runner.config.ARCADE_MODE_TOP_POSITION_PERCENT);
+ Runner.config.ARCADE_MODE_TOP_POSITION_PERCENT));
this.containerEl.style.transform = 'scale(' + scale + ') translateY(' +
translateY + 'px)';
},
@@ -1905,7 +1905,7 @@ function DistanceMeter(canvas, spritePos, canvasWidth) {
this.container = null;
this.digits = [];
- this.acheivement = false;
+ this.achievement = false;
this.defaultString = '';
this.flashTimer = 0;
this.flashIterations = 0;
@@ -2051,7 +2051,7 @@ DistanceMeter.prototype = {
var paint = true;
var playSound = false;
- if (!this.acheivement) {
+ if (!this.achievement) {
distance = this.getActualDistance(distance);
// Score has gone beyond the initial digit count.
if (distance > this.maxScore && this.maxScoreUnits ==
@@ -2066,7 +2066,7 @@ DistanceMeter.prototype = {
// Acheivement unlocked
if (distance % this.config.ACHIEVEMENT_DISTANCE == 0) {
// Flash score and play sound.
- this.acheivement = true;
+ this.achievement = true;
this.flashTimer = 0;
playSound = true;
}
@@ -2091,7 +2091,7 @@ DistanceMeter.prototype = {
this.flashIterations++;
}
} else {
- this.acheivement = false;
+ this.achievement = false;
this.flashIterations = 0;
this.flashTimer = 0;
}
@@ -2138,7 +2138,7 @@ DistanceMeter.prototype = {
*/
reset: function() {
this.update(0);
- this.acheivement = false;
+ this.achievement = false;
}
};
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 2c34461e6b1..d601712a40a 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
@@ -8,14 +8,18 @@
#include <unordered_set>
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.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 "build/build_config.h"
+#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 "net/base/host_mapping_rules.h"
#include "net/http/http_stream_factory.h"
#include "net/quic/chromium/quic_utils_chromium.h"
#include "net/quic/core/quic_packets.h"
@@ -146,6 +150,17 @@ net::QuicTagVector GetQuicConnectionOptions(
return net::ParseQuicConnectionOptions(it->second);
}
+net::QuicTagVector GetQuicClientConnectionOptions(
+ const VariationParameters& quic_trial_params) {
+ VariationParameters::const_iterator it =
+ quic_trial_params.find("client_connection_options");
+ if (it == quic_trial_params.end()) {
+ return net::QuicTagVector();
+ }
+
+ return net::ParseQuicConnectionOptions(it->second);
+}
+
bool ShouldForceHolBlocking(const VariationParameters& quic_trial_params) {
return base::LowerCaseEqualsASCII(
GetVariationParam(quic_trial_params, "force_hol_blocking"), "true");
@@ -180,18 +195,6 @@ int GetQuicReducedPingTimeoutSeconds(
return 0;
}
-int GetQuicPacketReaderYieldAfterDurationMilliseconds(
- const VariationParameters& quic_trial_params) {
- int value;
- if (base::StringToInt(
- GetVariationParam(quic_trial_params,
- "packet_reader_yield_after_duration_milliseconds"),
- &value)) {
- return value;
- }
- return 0;
-}
-
bool ShouldQuicRaceCertVerification(
const VariationParameters& quic_trial_params) {
return base::LowerCaseEqualsASCII(
@@ -268,6 +271,8 @@ void ConfigureQuicParams(base::StringPiece quic_trial_group,
params->quic_force_hol_blocking = ShouldForceHolBlocking(quic_trial_params);
params->quic_connection_options =
GetQuicConnectionOptions(quic_trial_params);
+ params->quic_client_connection_options =
+ GetQuicClientConnectionOptions(quic_trial_params);
params->quic_close_sessions_on_ip_change =
ShouldQuicCloseSessionsOnIpChange(quic_trial_params);
int idle_connection_timeout_seconds =
@@ -282,12 +287,6 @@ void ConfigureQuicParams(base::StringPiece quic_trial_group,
reduced_ping_timeout_seconds < net::kPingTimeoutSecs) {
params->quic_reduced_ping_timeout_seconds = reduced_ping_timeout_seconds;
}
- int packet_reader_yield_after_duration_milliseconds =
- GetQuicPacketReaderYieldAfterDurationMilliseconds(quic_trial_params);
- if (packet_reader_yield_after_duration_milliseconds != 0) {
- params->quic_packet_reader_yield_after_duration_milliseconds =
- packet_reader_yield_after_duration_milliseconds;
- }
params->quic_race_cert_verification =
ShouldQuicRaceCertVerification(quic_trial_params);
params->quic_estimate_initial_rtt =
@@ -426,6 +425,44 @@ void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line,
params->testing_fixed_https_port =
GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpsPort);
}
+
+ if (command_line.HasSwitch(switches::kHostRules)) {
+ params->host_mapping_rules.SetRulesFromString(
+ command_line.GetSwitchValueASCII(switches::kHostRules));
+ }
+
+ params->enable_token_binding =
+ base::FeatureList::IsEnabled(features::kTokenBinding);
+}
+
+net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType(
+ const base::CommandLine& command_line) {
+#if !defined(OS_ANDROID)
+ if (command_line.HasSwitch(switches::kUseSimpleCacheBackend)) {
+ const std::string opt_value =
+ command_line.GetSwitchValueASCII(switches::kUseSimpleCacheBackend);
+ if (base::LowerCaseEqualsASCII(opt_value, "off"))
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
+ if (opt_value.empty() || base::LowerCaseEqualsASCII(opt_value, "on"))
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+ }
+ const std::string experiment_name =
+ base::FieldTrialList::FindFullName("SimpleCacheTrial");
+ if (base::StartsWith(experiment_name, "Disable",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
+ }
+ if (base::StartsWith(experiment_name, "ExperimentYes",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+ }
+#endif // #if !defined(OS_ANDROID)
+
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+#else
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
+#endif
}
} // namespace network_session_configurator
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator.h b/chromium/components/network_session_configurator/browser/network_session_configurator.h
index 69e064bf364..f9845a240b4 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator.h
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator.h
@@ -8,6 +8,7 @@
#include <string>
#include "net/http/http_network_session.h"
+#include "net/url_request/url_request_context_builder.h"
namespace base {
class CommandLine;
@@ -28,6 +29,11 @@ void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line,
const std::string& quic_user_agent_id,
net::HttpNetworkSession::Params* params);
+// Returns the URLRequestContextBuilder::HttpCacheParams::Type that the disk
+// cache should use.
+net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType(
+ const base::CommandLine& command_line);
+
} // namespace network_session_configurator
#endif // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_BROWSER_NETWORK_SESSION_CONFIGURATOR_H_
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 b04421dd947..eeaf0c1f70e 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
@@ -6,20 +6,27 @@
#include <map>
#include <memory>
+#include <string>
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#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 "net/base/host_mapping_rules.h"
+#include "net/base/host_port_pair.h"
#include "net/http/http_stream_factory.h"
#include "net/quic/core/crypto/crypto_protocol.h"
#include "net/quic/core/quic_packets.h"
#include "net/spdy/core/spdy_protocol.h"
+#include "net/url_request/url_request_context_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace test {
+namespace network_session_configurator {
class NetworkSessionConfiguratorTest : public testing::Test {
public:
@@ -32,8 +39,8 @@ class NetworkSessionConfiguratorTest : public testing::Test {
void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line) {
network_session_configurator::ParseCommandLineAndFieldTrials(
- command_line, /*is_quic_force_disabled=*/false, quic_user_agent_id_,
- &params_);
+ command_line,
+ /*is_quic_force_disabled=*/false, quic_user_agent_id_, &params_);
}
void ParseFieldTrials() {
@@ -82,13 +89,12 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromFieldTrialGroup) {
EXPECT_FALSE(params_.retry_without_alt_svc_on_quic_errors);
EXPECT_EQ(1350u, params_.quic_max_packet_length);
EXPECT_EQ(net::QuicTagVector(), params_.quic_connection_options);
+ EXPECT_EQ(net::QuicTagVector(), params_.quic_client_connection_options);
EXPECT_FALSE(params_.enable_server_push_cancellation);
EXPECT_FALSE(params_.quic_close_sessions_on_ip_change);
EXPECT_EQ(net::kIdleConnectionTimeoutSeconds,
params_.quic_idle_connection_timeout_seconds);
EXPECT_EQ(net::kPingTimeoutSecs, params_.quic_reduced_ping_timeout_seconds);
- EXPECT_EQ(net::kQuicYieldAfterDurationMilliseconds,
- params_.quic_packet_reader_yield_after_duration_milliseconds);
EXPECT_FALSE(params_.quic_race_cert_verification);
EXPECT_FALSE(params_.quic_estimate_initial_rtt);
EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change);
@@ -199,18 +205,6 @@ TEST_F(NetworkSessionConfiguratorTest,
EXPECT_EQ(10, params_.quic_reduced_ping_timeout_seconds);
}
-TEST_F(NetworkSessionConfiguratorTest,
- QuicPacketReaderYieldAfterDurationMillisecondsFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["packet_reader_yield_after_duration_milliseconds"] = "10";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_EQ(10, params_.quic_packet_reader_yield_after_duration_milliseconds);
-}
-
TEST_F(NetworkSessionConfiguratorTest, QuicRaceCertVerification) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["race_cert_verification"] = "true";
@@ -357,6 +351,21 @@ TEST_F(NetworkSessionConfiguratorTest,
EXPECT_EQ(options, params_.quic_connection_options);
}
+TEST_F(NetworkSessionConfiguratorTest,
+ QuicClientConnectionOptionsFromFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["client_connection_options"] = "TBBR,1RTT";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+
+ ParseFieldTrials();
+
+ net::QuicTagVector options;
+ options.push_back(net::kTBBR);
+ options.push_back(net::k1RTT);
+ EXPECT_EQ(options, params_.quic_client_connection_options);
+}
+
TEST_F(NetworkSessionConfiguratorTest, Http2SettingsFromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["http2_settings"] = "7:1234,25:5678";
@@ -495,6 +504,15 @@ TEST_F(NetworkSessionConfiguratorTest, EnableUserAlternateProtocolPorts) {
EXPECT_TRUE(params_.enable_user_alternate_protocol_ports);
}
+TEST_F(NetworkSessionConfiguratorTest, TestingFixedPorts) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitchASCII(switches::kTestingFixedHttpPort, "800");
+ command_line.AppendSwitchASCII(switches::kTestingFixedHttpsPort, "801");
+ ParseCommandLineAndFieldTrials(command_line);
+ EXPECT_EQ(800, params_.testing_fixed_http_port);
+ EXPECT_EQ(801, params_.testing_fixed_https_port);
+}
+
TEST_F(NetworkSessionConfiguratorTest, IgnoreCertificateErrors) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitch(switches::kIgnoreCertificateErrors);
@@ -502,13 +520,89 @@ TEST_F(NetworkSessionConfiguratorTest, IgnoreCertificateErrors) {
EXPECT_TRUE(params_.ignore_certificate_errors);
}
-TEST_F(NetworkSessionConfiguratorTest, TestingFixedPorts) {
+TEST_F(NetworkSessionConfiguratorTest, HostRules) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
- command_line.AppendSwitchASCII(switches::kTestingFixedHttpPort, "800");
- command_line.AppendSwitchASCII(switches::kTestingFixedHttpsPort, "801");
+ command_line.AppendSwitchASCII(switches::kHostRules, "map *.com foo");
ParseCommandLineAndFieldTrials(command_line);
- EXPECT_EQ(800, params_.testing_fixed_http_port);
- EXPECT_EQ(801, params_.testing_fixed_https_port);
+
+ net::HostPortPair host_port_pair("spam.net", 80);
+ EXPECT_FALSE(params_.host_mapping_rules.RewriteHost(&host_port_pair));
+ EXPECT_EQ("spam.net", host_port_pair.host());
+
+ host_port_pair = net::HostPortPair("spam.com", 80);
+ EXPECT_TRUE(params_.host_mapping_rules.RewriteHost(&host_port_pair));
+ EXPECT_EQ("foo", host_port_pair.host());
}
-} // namespace test
+TEST_F(NetworkSessionConfiguratorTest, TokenBindingDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(features::kTokenBinding);
+
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ ParseCommandLineAndFieldTrials(command_line);
+
+ EXPECT_FALSE(params_.enable_token_binding);
+}
+
+TEST_F(NetworkSessionConfiguratorTest, TokenBindingEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kTokenBinding);
+
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ ParseCommandLineAndFieldTrials(command_line);
+
+ EXPECT_TRUE(params_.enable_token_binding);
+}
+
+TEST_F(NetworkSessionConfiguratorTest, DefaultCacheBackend) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ ChooseCacheType(command_line));
+#else
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE,
+ ChooseCacheType(command_line));
+#endif
+}
+
+TEST_F(NetworkSessionConfiguratorTest, UseSimpleCacheBackendOn) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitchASCII(switches::kUseSimpleCacheBackend, "on");
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ ChooseCacheType(command_line));
+}
+
+TEST_F(NetworkSessionConfiguratorTest, UseSimpleCacheBackendOff) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitchASCII(switches::kUseSimpleCacheBackend, "off");
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE,
+ ChooseCacheType(command_line));
+#else // defined(OS_ANDROID)
+ // Android always uses the simple cache.
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ ChooseCacheType(command_line));
+#endif
+}
+
+TEST_F(NetworkSessionConfiguratorTest, SimpleCacheTrialExperimentYes) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial", "ExperimentYes");
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ ChooseCacheType(command_line));
+}
+
+TEST_F(NetworkSessionConfiguratorTest, SimpleCacheTrialDisable) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial", "Disable");
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE,
+ ChooseCacheType(command_line));
+#else // defined(OS_ANDROID)
+ // Android always uses the simple cache.
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ ChooseCacheType(command_line));
+#endif
+}
+
+} // namespace network_session_configurator
diff --git a/chromium/components/network_session_configurator/common/BUILD.gn b/chromium/components/network_session_configurator/common/BUILD.gn
index 60bd2ea64cc..ba484f01380 100644
--- a/chromium/components/network_session_configurator/common/BUILD.gn
+++ b/chromium/components/network_session_configurator/common/BUILD.gn
@@ -4,6 +4,8 @@
static_library("common") {
sources = [
+ "network_features.cc",
+ "network_features.h",
"network_switch_list.h",
"network_switches.cc",
"network_switches.h",
diff --git a/chromium/components/network_session_configurator/common/network_features.cc b/chromium/components/network_session_configurator/common/network_features.cc
new file mode 100644
index 00000000000..abf8b98abde
--- /dev/null
+++ b/chromium/components/network_session_configurator/common/network_features.cc
@@ -0,0 +1,12 @@
+// 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/network_session_configurator/common/network_features.h"
+
+namespace features {
+
+const base::Feature kTokenBinding{"token-binding",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace features
diff --git a/chromium/components/network_session_configurator/common/network_features.h b/chromium/components/network_session_configurator/common/network_features.h
new file mode 100644
index 00000000000..1d6981d774f
--- /dev/null
+++ b/chromium/components/network_session_configurator/common/network_features.h
@@ -0,0 +1,18 @@
+// 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_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_FEATURES_H_
+#define COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace features {
+
+// Enables token binding
+// (https://www.ietf.org/id/draft-ietf-tokbind-protocol-04.txt).
+extern const base::Feature kTokenBinding;
+
+} // namespace features
+
+#endif // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_COMMON_NETWORK_FEATURES_H_
diff --git a/chromium/components/network_session_configurator/common/network_switch_list.h b/chromium/components/network_session_configurator/common/network_switch_list.h
index 76bec0e25c9..f2033c55f41 100644
--- a/chromium/components/network_session_configurator/common/network_switch_list.h
+++ b/chromium/components/network_session_configurator/common/network_switch_list.h
@@ -37,3 +37,27 @@ NETWORK_SWITCH(kQuicVersion, "quic-version")
// Allows for forcing socket connections to http/https to use fixed ports.
NETWORK_SWITCH(kTestingFixedHttpPort, "testing-fixed-http-port")
NETWORK_SWITCH(kTestingFixedHttpsPort, "testing-fixed-https-port")
+
+// Comma-separated list of rules that control how hostnames are mapped.
+//
+// For example:
+// "MAP * 127.0.0.1" --> Forces all hostnames to be mapped to 127.0.0.1
+// "MAP *.google.com proxy" --> Forces all google.com subdomains to be
+// resolved to "proxy".
+// "MAP test.com [::1]:77 --> Forces "test.com" to resolve to IPv6 loopback.
+// Will also force the port of the resulting
+// socket address to be 77.
+// "MAP * baz, EXCLUDE www.google.com" --> Remaps everything to "baz",
+// except for "www.google.com".
+//
+// These mappings apply to the endpoint host in a net::URLRequest (the TCP
+// connect and host resolver in a direct connection, and the CONNECT in an http
+// proxy connection, and the endpoint host in a SOCKS proxy connection).
+//
+// TODO(mmenke): Can we just remove this? host-resolver-rules is more generally
+// useful.
+NETWORK_SWITCH(kHostRules, "host-rules")
+
+// Uses experimental simple cache backend if possible when set to "on", and
+// blockfile backend when set to "off".
+NETWORK_SWITCH(kUseSimpleCacheBackend, "use-simple-cache-backend")
diff --git a/chromium/components/network_time/network_time_tracker.cc b/chromium/components/network_time/network_time_tracker.cc
index 5651b61ca81..ebe2a1ed9f0 100644
--- a/chromium/components/network_time/network_time_tracker.cc
+++ b/chromium/components/network_time/network_time_tracker.cc
@@ -484,7 +484,7 @@ void NetworkTimeTracker::CheckTime() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled by settings."
chrome_policy {
BrowserNetworkTimeQueriesEnabled {
diff --git a/chromium/components/new_or_sad_tab_strings.grdp b/chromium/components/new_or_sad_tab_strings.grdp
index 46e48aaca94..6f334046166 100644
--- a/chromium/components/new_or_sad_tab_strings.grdp
+++ b/chromium/components/new_or_sad_tab_strings.grdp
@@ -34,22 +34,22 @@
<message name="IDS_SAD_TAB_RELOAD_TITLE" desc="The title of the web page displayed if content in Chrome browser does not load for an unknown reason, and a reload failed to fix the issue." formatter_data="android_java">
Can't open this page
</message>
- <message name="IDS_SAD_TAB_OOM_MESSAGE_TABS" desc="The message displayed on the web page if content in Chrome browser does not load due to the browser being out of memory, a reload failed to fix the issue and other tabs are open." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_OOM_MESSAGE_TABS" desc="The message displayed on the web page if content in Chrome browser does not load due to the browser being out of memory, a reload failed to fix the issue and other tabs are open.">
Try closing other tabs or programs to free up memory.
</message>
- <message name="IDS_SAD_TAB_OOM_MESSAGE_NOTABS" desc="The message displayed on the web page if content in Chrome browser does not load due to the browser being out of memory, a reload failed to fix the issue and no other tabs are open." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_OOM_MESSAGE_NOTABS" desc="The message displayed on the web page if content in Chrome browser does not load due to the browser being out of memory, a reload failed to fix the issue and no other tabs are open.">
Try exiting other programs to free up memory.
</message>
<message name="IDS_SAD_TAB_RELOAD_TRY" desc="The message displayed on the web page if content in Chrome browser does not load and a reload failed to fix the issue. Introduces a bulleted list of solutions/tips for the user to try." formatter_data="android_java">
Try the following tips:
</message>
<if expr="is_macosx">
- <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode.">
Open page in a new Incognito window (⇧⌘N)
</message>
</if>
<if expr="is_win or is_linux or chromeos">
- <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode.">
Open page in a new Incognito window (Ctrl-Shift-N)
</message>
</if>
@@ -59,22 +59,22 @@
</message>
</if>
<if expr="is_macosx or chromeos">
- <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or apps running on their computer (Mac, Chrome OS)." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or apps running on their computer (Mac, Chrome OS).">
Close other tabs or apps
</message>
</if>
<if expr="is_linux and not chromeos">
- <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or programs running on their computer." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_CLOSE_TABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other Chrome tabs or programs running on their computer.">
Close other tabs or programs
</message>
</if>
- <if expr="is_macosx or chromeos or is_android or is_ios">
- <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other apps running on their computer or device." formatter_data="android_java">
+ <if expr="is_macosx or chromeos or is_ios">
+ <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other apps running on their computer or device.">
Close other apps
</message>
</if>
<if expr="is_linux and not chromeos">
- <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other programs running on their computer (Linux)." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_CLOSE_NOTABS" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to close other programs running on their computer (Linux).">
Close other programs
</message>
</if>
@@ -89,7 +89,7 @@
</message>
</if>
<if expr="is_win or is_linux or is_macosx or chromeos">
- <message name="IDS_SAD_TAB_RELOAD_RESTART_DEVICE" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to restart their computer." formatter_data="android_java">
+ <message name="IDS_SAD_TAB_RELOAD_RESTART_DEVICE" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to restart their computer.">
Restart your computer
</message>
</if>
@@ -103,9 +103,6 @@
Learn more
</message>
</if>
- <message name="IDS_SAD_TAB_UMA_OPTIN" desc="Text that appears next to a checkbox, allowing the user to opt-in to sending statistics about their Chrome browser usage and reports of crashes to Google." formatter_data="android_java">
- Automatically send usage statistics and crash reports to Google
- </message>
<!-- New Tab -->
<message name="IDS_NEW_TAB_TITLE"
diff --git a/chromium/components/ntp_snippets/BUILD.gn b/chromium/components/ntp_snippets/BUILD.gn
index d783ae7facb..b99c3ac0bb9 100644
--- a/chromium/components/ntp_snippets/BUILD.gn
+++ b/chromium/components/ntp_snippets/BUILD.gn
@@ -15,11 +15,9 @@ static_library("ntp_snippets") {
"bookmarks/bookmark_last_visit_utils.h",
"bookmarks/bookmark_suggestions_provider.cc",
"bookmarks/bookmark_suggestions_provider.h",
- "breaking_news/breaking_news_gcm_app_handler.cc",
- "breaking_news/breaking_news_gcm_app_handler.h",
"breaking_news/breaking_news_listener.h",
- "breaking_news/breaking_news_suggestions_provider.cc",
- "breaking_news/breaking_news_suggestions_provider.h",
+ "breaking_news/breaking_news_metrics.cc",
+ "breaking_news/breaking_news_metrics.h",
"breaking_news/subscription_json_request.cc",
"breaking_news/subscription_json_request.h",
"breaking_news/subscription_manager.cc",
@@ -46,6 +44,13 @@ static_library("ntp_snippets") {
"content_suggestions_provider.h",
"content_suggestions_service.cc",
"content_suggestions_service.h",
+ "contextual/contextual_content_suggestions_service.cc",
+ "contextual/contextual_content_suggestions_service.h",
+ "contextual/contextual_json_request.cc",
+ "contextual/contextual_json_request.h",
+ "contextual/contextual_suggestions_fetcher.h",
+ "contextual/contextual_suggestions_fetcher_impl.cc",
+ "contextual/contextual_suggestions_fetcher_impl.h",
"features.cc",
"features.h",
"ntp_snippets_constants.cc",
@@ -62,8 +67,6 @@ static_library("ntp_snippets") {
"reading_list/reading_list_suggestions_provider.h",
"remote/cached_image_fetcher.cc",
"remote/cached_image_fetcher.h",
- "remote/contextual_json_request.cc",
- "remote/contextual_json_request.h",
"remote/json_request.cc",
"remote/json_request.h",
"remote/json_to_categories.cc",
@@ -87,8 +90,9 @@ static_library("ntp_snippets") {
"remote/remote_suggestions_scheduler.h",
"remote/remote_suggestions_scheduler_impl.cc",
"remote/remote_suggestions_scheduler_impl.h",
- "remote/remote_suggestions_status_service.cc",
"remote/remote_suggestions_status_service.h",
+ "remote/remote_suggestions_status_service_impl.cc",
+ "remote/remote_suggestions_status_service_impl.h",
"remote/request_params.cc",
"remote/request_params.h",
"remote/request_throttler.cc",
@@ -101,10 +105,19 @@ static_library("ntp_snippets") {
"status.h",
"switches.cc",
"switches.h",
+ "time_serialization.cc",
+ "time_serialization.h",
"user_classifier.cc",
"user_classifier.h",
]
+ if (is_android) {
+ sources += [
+ "breaking_news/breaking_news_gcm_app_handler.cc",
+ "breaking_news/breaking_news_gcm_app_handler.h",
+ ]
+ }
+
public_deps = [
"//base",
"//components/keyed_service/core",
@@ -142,6 +155,7 @@ static_library("ntp_snippets") {
"//components/url_formatter",
"//components/variations",
"//components/variations/net",
+ "//components/variations/service",
"//components/web_resource",
"//third_party/icu/",
"//ui/gfx",
@@ -164,7 +178,6 @@ source_set("unit_tests") {
sources = [
"bookmarks/bookmark_last_visit_utils_unittest.cc",
"bookmarks/bookmark_suggestions_provider_unittest.cc",
- "breaking_news/breaking_news_suggestions_provider_unittest.cc",
"breaking_news/subscription_json_request_unittest.cc",
"breaking_news/subscription_manager_impl_unittest.cc",
"category_rankers/click_based_category_ranker_unittest.cc",
@@ -172,11 +185,13 @@ source_set("unit_tests") {
"category_unittest.cc",
"content_suggestions_metrics_unittest.cc",
"content_suggestions_service_unittest.cc",
+ "contextual/contextual_content_suggestions_service_unittest.cc",
+ "contextual/contextual_json_request_unittest.cc",
+ "contextual/contextual_suggestions_fetcher_impl_unittest.cc",
"offline_pages/recent_tab_suggestions_provider_unittest.cc",
"physical_web_pages/physical_web_page_suggestions_provider_unittest.cc",
"reading_list/reading_list_suggestions_provider_unittest.cc",
"remote/cached_image_fetcher_unittest.cc",
- "remote/contextual_json_request_unittest.cc",
"remote/json_request_unittest.cc",
"remote/prefetched_pages_tracker_impl_unittest.cc",
"remote/remote_suggestion_unittest.cc",
@@ -184,7 +199,7 @@ source_set("unit_tests") {
"remote/remote_suggestions_fetcher_impl_unittest.cc",
"remote/remote_suggestions_provider_impl_unittest.cc",
"remote/remote_suggestions_scheduler_impl_unittest.cc",
- "remote/remote_suggestions_status_service_unittest.cc",
+ "remote/remote_suggestions_status_service_impl_unittest.cc",
"remote/request_throttler_unittest.cc",
"remote/test_utils.cc",
"remote/test_utils.h",
@@ -193,6 +208,10 @@ source_set("unit_tests") {
"user_classifier_unittest.cc",
]
+ if (is_android) {
+ sources += [ "breaking_news/breaking_news_gcm_app_handler_unittest.cc" ]
+ }
+
deps = [
":ntp_snippets",
":test_support",
@@ -200,6 +219,8 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/bookmarks/browser",
"//components/bookmarks/test",
+ "//components/gcm_driver",
+ "//components/gcm_driver/instance_id",
"//components/image_fetcher/core",
"//components/leveldb_proto:test_support",
"//components/ntp_snippets/remote/proto",
@@ -220,6 +241,7 @@ source_set("unit_tests") {
"//components/sync_sessions",
"//components/variations:test_support",
"//components/web_resource:web_resource",
+ "//google_apis/gcm",
"//net:test_support",
"//testing/gtest",
"//third_party/icu/",
@@ -242,11 +264,14 @@ source_set("test_support") {
"mock_content_suggestions_provider_observer.h",
"offline_pages/offline_pages_test_utils.cc",
"offline_pages/offline_pages_test_utils.h",
+ "remote/remote_suggestion_builder.cc",
+ "remote/remote_suggestion_builder.h",
]
deps = [
":ntp_snippets",
"//base",
+ "//components/ntp_snippets/remote/proto",
"//components/offline_pages/core",
"//components/offline_pages/core:test_support",
"//testing/gmock",
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index 9b0e2df80d3..1b9b50ff445 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -109,23 +109,23 @@ void BookmarkSuggestionsProvider::DismissSuggestion(
void BookmarkSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
}
void BookmarkSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
LOG(DFATAL) << "BookmarkSuggestionsProvider has no |Fetch| functionality!";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
- callback,
+ base::BindOnce(
+ std::move(callback),
Status(StatusCode::PERMANENT_ERROR,
"BookmarkSuggestionsProvider has no |Fetch| functionality!"),
- base::Passed(std::vector<ContentSuggestion>())));
+ std::vector<ContentSuggestion>()));
}
void BookmarkSuggestionsProvider::ClearHistory(
@@ -150,7 +150,7 @@ void BookmarkSuggestionsProvider::ClearCachedSuggestions(Category category) {
void BookmarkSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
DCHECK_EQ(category, provided_category_);
std::vector<const BookmarkNode*> bookmarks =
GetDismissedBookmarksForDebugging(bookmark_model_);
@@ -159,7 +159,7 @@ void BookmarkSuggestionsProvider::GetDismissedSuggestionsForDebugging(
for (const BookmarkNode* bookmark : bookmarks) {
ConvertBookmark(*bookmark, &suggestions);
}
- callback.Run(std::move(suggestions));
+ std::move(callback).Run(std::move(suggestions));
}
void BookmarkSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
index 404c8d6ada2..1b6aa327ddc 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -31,10 +31,10 @@ class BookmarkSuggestionsProvider : public ContentSuggestionsProvider,
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -42,7 +42,7 @@ class BookmarkSuggestionsProvider : public ContentSuggestionsProvider,
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
// bookmarks::BookmarkModelObserver implementation.
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
index 5a8584131c6..c3350516aee 100644
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
@@ -4,17 +4,26 @@
#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
+#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h"
+#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/time_serialization.h"
+#include "components/variations/variations_associated_data.h"
using instance_id::InstanceID;
namespace ntp_snippets {
+namespace {
+
const char kBreakingNewsGCMAppID[] = "com.google.breakingnews.gcm";
// The sender ID is used in the registration process.
@@ -28,48 +37,121 @@ const char kGCMScope[] = "GCM";
// Key of the news json in the data in the pushed breaking news.
const char kPushedNewsKey[] = "payload";
+// Lower bound time between two token validations when listening.
+const int kTokenValidationPeriodMinutesDefault = 60 * 24;
+const char kTokenValidationPeriodMinutesParamName[] =
+ "token_validation_period_minutes";
+
+base::TimeDelta GetTokenValidationPeriod() {
+ return base::TimeDelta::FromMinutes(
+ variations::GetVariationParamByFeatureAsInt(
+ kBreakingNewsPushFeature, kTokenValidationPeriodMinutesParamName,
+ kTokenValidationPeriodMinutesDefault));
+}
+
+const bool kEnableTokenValidationDefault = true;
+const char kEnableTokenValidationParamName[] = "enable_token_validation";
+
+bool IsTokenValidationEnabled() {
+ return variations::GetVariationParamByFeatureAsBool(
+ kBreakingNewsPushFeature, kEnableTokenValidationParamName,
+ kEnableTokenValidationDefault);
+}
+
+// Lower bound time between two forced subscriptions when listening. A
+// forced subscription is a normal subscription to the content
+// suggestions server, which cannot be omitted.
+const int kForcedSubscriptionPeriodMinutesDefault = 60 * 24 * 7;
+const char kForcedSubscriptionPeriodMinutesParamName[] =
+ "forced_subscription_period_minutes";
+
+base::TimeDelta GetForcedSubscriptionPeriod() {
+ return base::TimeDelta::FromMinutes(
+ variations::GetVariationParamByFeatureAsInt(
+ kBreakingNewsPushFeature, kForcedSubscriptionPeriodMinutesParamName,
+ kForcedSubscriptionPeriodMinutesDefault));
+}
+
+const bool kEnableForcedSubscriptionDefault = true;
+const char kEnableForcedSubscriptionParamName[] = "enable_forced_subscription";
+
+bool IsForcedSubscriptionEnabled() {
+ return variations::GetVariationParamByFeatureAsBool(
+ kBreakingNewsPushFeature, kEnableForcedSubscriptionParamName,
+ kEnableForcedSubscriptionDefault);
+}
+
+} // namespace
+
BreakingNewsGCMAppHandler::BreakingNewsGCMAppHandler(
gcm::GCMDriver* gcm_driver,
instance_id::InstanceIDDriver* instance_id_driver,
PrefService* pref_service,
std::unique_ptr<SubscriptionManager> subscription_manager,
- const ParseJSONCallback& parse_json_callback)
+ const ParseJSONCallback& parse_json_callback,
+ std::unique_ptr<base::Clock> clock,
+ std::unique_ptr<base::OneShotTimer> token_validation_timer,
+ std::unique_ptr<base::OneShotTimer> forced_subscription_timer)
: gcm_driver_(gcm_driver),
instance_id_driver_(instance_id_driver),
pref_service_(pref_service),
subscription_manager_(std::move(subscription_manager)),
parse_json_callback_(parse_json_callback),
- weak_ptr_factory_(this) {}
+ clock_(std::move(clock)),
+ token_validation_timer_(std::move(token_validation_timer)),
+ forced_subscription_timer_(std::move(forced_subscription_timer)),
+ weak_ptr_factory_(this) {
+#if !defined(OS_ANDROID)
+#error The BreakingNewsGCMAppHandler should only be used on Android.
+#endif // !OS_ANDROID
+ DCHECK(token_validation_timer_);
+ DCHECK(!token_validation_timer_->IsRunning());
+}
BreakingNewsGCMAppHandler::~BreakingNewsGCMAppHandler() {
- StopListening();
+ if (IsListening()) {
+ StopListening();
+ }
}
void BreakingNewsGCMAppHandler::StartListening(
- OnNewContentCallback on_new_content_callback) {
-#if !defined(OS_ANDROID)
- NOTREACHED()
- << "The BreakingNewsGCMAppHandler should only be used on Android.";
-#endif
- Subscribe();
- on_new_content_callback_ = std::move(on_new_content_callback);
+ OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback) {
+ DCHECK(!IsListening());
+ DCHECK(!on_new_remote_suggestion_callback.is_null());
+ on_new_remote_suggestion_callback_ =
+ std::move(on_new_remote_suggestion_callback);
+ Subscribe(/*force_token_retrieval=*/false);
gcm_driver_->AddAppHandler(kBreakingNewsGCMAppID, this);
+ if (IsTokenValidationEnabled()) {
+ ScheduleNextTokenValidation();
+ }
+ if (IsForcedSubscriptionEnabled()) {
+ ScheduleNextForcedSubscription();
+ }
}
void BreakingNewsGCMAppHandler::StopListening() {
+ DCHECK(IsListening());
+ token_validation_timer_->Stop();
+ forced_subscription_timer_->Stop();
DCHECK_EQ(gcm_driver_->GetAppHandler(kBreakingNewsGCMAppID), this);
gcm_driver_->RemoveAppHandler(kBreakingNewsGCMAppID);
- on_new_content_callback_ = OnNewContentCallback();
+ on_new_remote_suggestion_callback_ = OnNewRemoteSuggestionCallback();
subscription_manager_->Unsubscribe();
}
-void BreakingNewsGCMAppHandler::Subscribe() {
- // TODO(mamir): This logic should be moved to the SubscriptionManager.
+bool BreakingNewsGCMAppHandler::IsListening() const {
+ return !on_new_remote_suggestion_callback_.is_null();
+}
+
+void BreakingNewsGCMAppHandler::Subscribe(bool force_token_retrieval) {
+ // TODO(mamir): "Whether to subscribe to content suggestions server" logic
+ // should be moved to the SubscriptionManager.
std::string token =
pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache);
// If a token has been already obtained, subscribe directly at the content
// suggestions server. Otherwise, obtain a GCM token first.
- if (!token.empty()) {
+ if (!token.empty() && !force_token_retrieval) {
if (!subscription_manager_->IsSubscribed() ||
subscription_manager_->NeedsToResubscribe()) {
subscription_manager_->Subscribe(token);
@@ -80,15 +162,24 @@ void BreakingNewsGCMAppHandler::Subscribe() {
instance_id_driver_->GetInstanceID(kBreakingNewsGCMAppID)
->GetToken(kBreakingNewsGCMSenderId, kGCMScope,
/*options=*/std::map<std::string, std::string>(),
- base::Bind(&BreakingNewsGCMAppHandler::DidSubscribe,
+ base::Bind(&BreakingNewsGCMAppHandler::DidRetrieveToken,
weak_ptr_factory_.GetWeakPtr()));
}
-void BreakingNewsGCMAppHandler::DidSubscribe(
+void BreakingNewsGCMAppHandler::DidRetrieveToken(
const std::string& subscription_token,
InstanceID::Result result) {
+ metrics::OnTokenRetrieved(result);
+
switch (result) {
case InstanceID::SUCCESS:
+ // The received token is assumed to be valid, therefore, we reschedule
+ // validation.
+ pref_service_->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(clock_->Now()));
+ if (IsTokenValidationEnabled()) {
+ ScheduleNextTokenValidation();
+ }
pref_service_->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
subscription_token);
subscription_manager_->Subscribe(subscription_token);
@@ -107,6 +198,101 @@ void BreakingNewsGCMAppHandler::DidSubscribe(
}
}
+void BreakingNewsGCMAppHandler::ResubscribeIfInvalidToken() {
+ DCHECK(IsListening());
+ DCHECK(IsTokenValidationEnabled());
+
+ // InstanceIDAndroid::ValidateToken just returns |true| on Android. Instead it
+ // is ok to retrieve a token, because it is cached.
+ instance_id_driver_->GetInstanceID(kBreakingNewsGCMAppID)
+ ->GetToken(
+ kBreakingNewsGCMSenderId, kGCMScope,
+ /*options=*/std::map<std::string, std::string>(),
+ base::Bind(&BreakingNewsGCMAppHandler::DidReceiveTokenForValidation,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BreakingNewsGCMAppHandler::DidReceiveTokenForValidation(
+ const std::string& new_token,
+ InstanceID::Result result) {
+ metrics::OnTokenRetrieved(result);
+
+ base::Optional<base::TimeDelta> time_since_last_validation;
+ if (pref_service_->HasPrefPath(
+ prefs::kBreakingNewsGCMLastTokenValidationTime)) {
+ const base::Time last_validation_time =
+ DeserializeTime(pref_service_->GetInt64(
+ prefs::kBreakingNewsGCMLastTokenValidationTime));
+ time_since_last_validation = clock_->Now() - last_validation_time;
+ }
+
+ // We intentionally reschedule as normal even if we don't get a token.
+ pref_service_->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(clock_->Now()));
+ ScheduleNextTokenValidation();
+
+ base::Optional<bool> was_token_valid;
+ if (result == InstanceID::SUCCESS) {
+ const std::string old_token =
+ pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache);
+
+ was_token_valid = old_token == new_token;
+ if (!*was_token_valid) {
+ subscription_manager_->Resubscribe(new_token);
+ }
+ }
+
+ metrics::OnTokenValidationAttempted(time_since_last_validation,
+ was_token_valid);
+}
+
+void BreakingNewsGCMAppHandler::ScheduleNextTokenValidation() {
+ DCHECK(IsListening());
+ DCHECK(IsTokenValidationEnabled());
+
+ const base::Time last_validation_time = DeserializeTime(
+ pref_service_->GetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime));
+ // Timer runs the task immediately if delay is <= 0.
+ token_validation_timer_->Start(
+ FROM_HERE,
+ /*delay=*/last_validation_time + GetTokenValidationPeriod() -
+ clock_->Now(),
+ base::Bind(&BreakingNewsGCMAppHandler::ResubscribeIfInvalidToken,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BreakingNewsGCMAppHandler::ForceSubscribe() {
+ DCHECK(IsForcedSubscriptionEnabled());
+
+ // We intentionally reschedule as normal even if there is no token or
+ // subscription fails.
+ pref_service_->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(clock_->Now()));
+ ScheduleNextForcedSubscription();
+
+ const std::string token =
+ pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache);
+ if (!token.empty()) {
+ subscription_manager_->Subscribe(token);
+ }
+}
+
+void BreakingNewsGCMAppHandler::ScheduleNextForcedSubscription() {
+ DCHECK(IsListening());
+ DCHECK(IsForcedSubscriptionEnabled());
+
+ const base::Time last_forced_subscription_time =
+ DeserializeTime(pref_service_->GetInt64(
+ prefs::kBreakingNewsGCMLastForcedSubscriptionTime));
+ // Timer runs the task immediately if delay is <= 0.
+ forced_subscription_timer_->Start(
+ FROM_HERE,
+ /*delay=*/last_forced_subscription_time + GetForcedSubscriptionPeriod() -
+ clock_->Now(),
+ base::Bind(&BreakingNewsGCMAppHandler::ForceSubscribe,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
void BreakingNewsGCMAppHandler::ShutdownHandler() {}
void BreakingNewsGCMAppHandler::OnStoreReset() {
@@ -118,19 +304,28 @@ void BreakingNewsGCMAppHandler::OnMessage(const std::string& app_id,
DCHECK_EQ(app_id, kBreakingNewsGCMAppID);
gcm::MessageData::const_iterator it = message.data.find(kPushedNewsKey);
- if (it == message.data.end()) {
- LOG(WARNING)
- << "Receiving pushed content failure: Breaking News ID missing.";
+ bool contains_pushed_news = (it != message.data.end());
+ metrics::OnMessageReceived(IsListening(), contains_pushed_news);
+
+ if (!IsListening()) {
+ // The content suggestions server may push a message right when the client
+ // unsubscribes leading to a race condition. Ignore such messages.
+ DLOG(WARNING) << "Received a pushed message while not listening.";
return;
}
- std::string news = it->second;
-
- parse_json_callback_.Run(news,
- base::Bind(&BreakingNewsGCMAppHandler::OnJsonSuccess,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&BreakingNewsGCMAppHandler::OnJsonError,
- weak_ptr_factory_.GetWeakPtr(), news));
+ if (contains_pushed_news) {
+ const std::string& news = it->second;
+ parse_json_callback_.Run(
+ news,
+ base::Bind(&BreakingNewsGCMAppHandler::OnJsonSuccess,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&BreakingNewsGCMAppHandler::OnJsonError,
+ weak_ptr_factory_.GetWeakPtr(), news));
+ } else {
+ LOG(WARNING)
+ << "Receiving pushed content failure: Breaking News ID missing.";
+ }
}
void BreakingNewsGCMAppHandler::OnMessagesDeleted(const std::string& app_id) {
@@ -154,15 +349,60 @@ void BreakingNewsGCMAppHandler::OnSendAcknowledged(
NOTREACHED() << "BreakingNewsGCMAppHandler doesn't send GCM messages.";
}
+// static
void BreakingNewsGCMAppHandler::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kBreakingNewsGCMSubscriptionTokenCache,
- std::string());
+ /*default_value=*/std::string());
+ registry->RegisterInt64Pref(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ /*default_value=*/0);
+ registry->RegisterInt64Pref(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ /*default_value=*/0);
+}
+
+// TODO(vitaliii): Add a test to ensure that this clears everything.
+// static
+void BreakingNewsGCMAppHandler::ClearProfilePrefs(PrefService* pref_service) {
+ pref_service->ClearPref(prefs::kBreakingNewsGCMSubscriptionTokenCache);
+ pref_service->ClearPref(prefs::kBreakingNewsGCMLastTokenValidationTime);
+ pref_service->ClearPref(prefs::kBreakingNewsGCMSubscriptionTokenCache);
}
void BreakingNewsGCMAppHandler::OnJsonSuccess(
std::unique_ptr<base::Value> content) {
- on_new_content_callback_.Run(std::move(content));
+ DCHECK(content);
+
+ if (!IsListening()) {
+ // |StopListening| might be called after JSON parse request is submitted,
+ // but the request cannot be canceled, so we just ignore the parsed JSON.
+ return;
+ }
+
+ std::vector<FetchedCategory> fetched_categories;
+ if (!JsonToCategories(*content, &fetched_categories,
+ /*fetch_time=*/base::Time::Now())) {
+ std::string content_json;
+ base::JSONWriter::Write(*content, &content_json);
+ LOG(WARNING)
+ << "Received invalid breaking news: can't interpret value, json is "
+ << content_json;
+ return;
+ }
+ if (fetched_categories.size() != 1) {
+ LOG(WARNING)
+ << "Received invalid breaking news: expected 1 category, but got "
+ << fetched_categories.size();
+ return;
+ }
+ if (fetched_categories[0].suggestions.size() != 1) {
+ LOG(WARNING)
+ << "Received invalid breaking news: expected 1 suggestion, but got "
+ << fetched_categories[0].suggestions.size();
+ return;
+ }
+
+ on_new_remote_suggestion_callback_.Run(
+ std::move(fetched_categories[0].suggestions[0]));
}
void BreakingNewsGCMAppHandler::OnJsonError(const std::string& json_str,
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
index 59527c39d21..1ddce3d087e 100644
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
@@ -6,6 +6,8 @@
#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_GCM_APP_HANDLER_H_
#include "base/memory/weak_ptr.h"
+#include "base/time/clock.h"
+#include "base/timer/timer.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
@@ -25,9 +27,11 @@ class InstanceIDDriver;
namespace ntp_snippets {
-// Handler for pushed GCM breaking news. It retrieves a subscription token
-// from the GCM server and registers/unregisters itself with the GCM service to
-// be called upon received push breaking news.
+// Handler for pushed GCM breaking news. It retrieves a subscription token from
+// the GCM server and registers/unregisters itself with the GCM service to be
+// called upon received push breaking news. When there is a listener, the token
+// is periodically validated. The validation may happen during StartListening if
+// enough time has passed since the last validation.
class BreakingNewsGCMAppHandler : public BreakingNewsListener,
public gcm::GCMAppHandler {
public:
@@ -40,22 +44,26 @@ class BreakingNewsGCMAppHandler : public BreakingNewsListener,
const SuccessCallback& success_callback,
const ErrorCallback& error_callback)>;
- using OnNewContentCallback =
- base::Callback<void(std::unique_ptr<base::Value> content)>;
-
+ // When provided, |timer_task_runner| and |timer_tick_clock| are used inside
+ // internal validation timer (e.g. for testing).
BreakingNewsGCMAppHandler(
gcm::GCMDriver* gcm_driver,
instance_id::InstanceIDDriver* instance_id_driver,
PrefService* pref_service_,
std::unique_ptr<SubscriptionManager> subscription_manager,
- const ParseJSONCallback& parse_json_callback);
+ const ParseJSONCallback& parse_json_callback,
+ std::unique_ptr<base::Clock> clock,
+ std::unique_ptr<base::OneShotTimer> token_validation_timer,
+ std::unique_ptr<base::OneShotTimer> forced_subscription_timer);
// If still listening, calls StopListening()
~BreakingNewsGCMAppHandler() override;
// BreakingNewsListener overrides.
- void StartListening(OnNewContentCallback on_new_content_callback) override;
+ void StartListening(
+ OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback) override;
void StopListening() override;
+ bool IsListening() const override;
// GCMAppHandler overrides.
void ShutdownHandler() override;
@@ -69,16 +77,36 @@ class BreakingNewsGCMAppHandler : public BreakingNewsListener,
const std::string& message_id) override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+ static void ClearProfilePrefs(PrefService* pref_service);
private:
- // Retrieves a subscription token that allows the content suggestions server
- // to push content via GCM messages. Calling this method multiple times is not
- // necessary but does not harm since the same token is returned everytime.
- void Subscribe();
+ // If there is no subscription token or |force_token_retrieval|, retrieves a
+ // GCM subscription token and subscribes to content suggestions server with
+ // it. Otherwise, subscribes to content suggestions server with the existing
+ // token.
+ void Subscribe(bool force_token_retrieval);
+
+ // Called when a subscription token is obtained from the GCM server.
+ void DidRetrieveToken(const std::string& subscription_token,
+ instance_id::InstanceID::Result result);
+
+ // Called periodically to validate the subscription token (it is stored on
+ // disk and may become corrupted) and resubscribe with the new token if the
+ // old one is invalid.
+ void ResubscribeIfInvalidToken();
+
+ // Called when token obtained from the GCM server for its validation.
+ void DidReceiveTokenForValidation(const std::string& new_token,
+ instance_id::InstanceID::Result result);
- // Called after the subscription is obtained from the GCM server.
- void DidSubscribe(const std::string& subscription_token,
- instance_id::InstanceID::Result result);
+ // If the validation is due, it may be scheduled immediately.
+ void ScheduleNextTokenValidation();
+
+ // Subscribe to content suggestions service using the existing token.
+ void ForceSubscribe();
+
+ // If the subscription is due, it may be scheduled immediately.
+ void ScheduleNextForcedSubscription();
// Called after successfully parsing the received suggestion JSON.
void OnJsonSuccess(std::unique_ptr<base::Value> content);
@@ -92,10 +120,14 @@ class BreakingNewsGCMAppHandler : public BreakingNewsListener,
PrefService* const pref_service_;
const std::unique_ptr<SubscriptionManager> subscription_manager_;
const ParseJSONCallback parse_json_callback_;
+ std::unique_ptr<base::Clock> clock_;
// Called after every time a new message is received in OnMessage() to notify
// the content provider.
- OnNewContentCallback on_new_content_callback_;
+ OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback_;
+
+ std::unique_ptr<base::OneShotTimer> token_validation_timer_;
+ std::unique_ptr<base::OneShotTimer> forced_subscription_timer_;
base::WeakPtrFactory<BreakingNewsGCMAppHandler> weak_ptr_factory_;
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc
new file mode 100644
index 00000000000..05dafb1f1ee
--- /dev/null
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc
@@ -0,0 +1,1028 @@
+// 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/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+#include "base/timer/timer.h"
+#include "build/build_config.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/instance_id/instance_id.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h"
+#include "components/ntp_snippets/breaking_news/subscription_manager.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/test_utils.h"
+#include "components/ntp_snippets/time_serialization.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_params_manager.h"
+#include "google_apis/gcm/engine/account_mapping.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::TestMockTimeTaskRunner;
+using base::TickClock;
+using base::TimeTicks;
+using gcm::InstanceIDHandler;
+using instance_id::InstanceID;
+using instance_id::InstanceIDDriver;
+using testing::_;
+using testing::AnyNumber;
+using testing::AtMost;
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::NiceMock;
+using testing::StrictMock;
+
+namespace ntp_snippets {
+
+namespace {
+
+class MockSubscriptionManager : public SubscriptionManager {
+ public:
+ MockSubscriptionManager() = default;
+ ~MockSubscriptionManager() override = default;
+
+ MOCK_METHOD1(Subscribe, void(const std::string& token));
+ MOCK_METHOD0(Unsubscribe, void());
+ MOCK_METHOD0(IsSubscribed, bool());
+ MOCK_METHOD1(Resubscribe, void(const std::string& new_token));
+ MOCK_METHOD0(NeedsToResubscribe, bool());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubscriptionManager);
+};
+
+class MockInstanceIDDriver : public InstanceIDDriver {
+ public:
+ MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr){};
+ ~MockInstanceIDDriver() override = default;
+
+ MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
+ MOCK_METHOD1(RemoveInstanceID, void(const std::string& app_id));
+ MOCK_CONST_METHOD1(ExistsInstanceID, bool(const std::string& app_id));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockInstanceIDDriver);
+};
+
+class MockInstanceID : public InstanceID {
+ public:
+ MockInstanceID() : InstanceID("app_id", /*gcm_driver=*/nullptr) {}
+ ~MockInstanceID() override = default;
+
+ MOCK_METHOD1(GetID, void(const GetIDCallback& callback));
+ MOCK_METHOD1(GetCreationTime, void(const GetCreationTimeCallback& callback));
+ MOCK_METHOD4(GetToken,
+ void(const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback));
+ MOCK_METHOD4(ValidateToken,
+ void(const std::string& authorized_entity,
+ const std::string& scope,
+ const std::string& token,
+ const ValidateTokenCallback& callback));
+
+ protected:
+ MOCK_METHOD3(DeleteTokenImpl,
+ void(const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback));
+ MOCK_METHOD1(DeleteIDImpl, void(const DeleteIDCallback& callback));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockInstanceID);
+};
+
+class MockGCMDriver : public gcm::GCMDriver {
+ public:
+ MockGCMDriver()
+ : GCMDriver(/*store_path=*/base::FilePath(),
+ /*blocking_task_runner=*/nullptr) {}
+ ~MockGCMDriver() override = default;
+
+ MOCK_METHOD4(ValidateRegistration,
+ void(const std::string& app_id,
+ const std::vector<std::string>& sender_ids,
+ const std::string& registration_id,
+ const ValidateRegistrationCallback& callback));
+ MOCK_METHOD0(OnSignedIn, void());
+ MOCK_METHOD0(OnSignedOut, void());
+ MOCK_METHOD1(AddConnectionObserver,
+ void(gcm::GCMConnectionObserver* observer));
+ MOCK_METHOD1(RemoveConnectionObserver,
+ void(gcm::GCMConnectionObserver* observer));
+ MOCK_METHOD0(Enable, void());
+ MOCK_METHOD0(Disable, void());
+ MOCK_CONST_METHOD0(GetGCMClientForTesting, gcm::GCMClient*());
+ MOCK_CONST_METHOD0(IsStarted, bool());
+ MOCK_CONST_METHOD0(IsConnected, bool());
+ MOCK_METHOD2(GetGCMStatistics,
+ void(const GetGCMStatisticsCallback& callback,
+ ClearActivityLogs clear_logs));
+ MOCK_METHOD2(SetGCMRecording,
+ void(const GetGCMStatisticsCallback& callback, bool recording));
+ MOCK_METHOD1(SetAccountTokens,
+ void(const std::vector<gcm::GCMClient::AccountTokenInfo>&
+ account_tokens));
+ MOCK_METHOD1(UpdateAccountMapping,
+ void(const gcm::AccountMapping& account_mapping));
+ MOCK_METHOD1(RemoveAccountMapping, void(const std::string& account_id));
+ MOCK_METHOD0(GetLastTokenFetchTime, base::Time());
+ MOCK_METHOD1(SetLastTokenFetchTime, void(const base::Time& time));
+ MOCK_METHOD1(WakeFromSuspendForHeartbeat, void(bool wake));
+ MOCK_METHOD0(GetInstanceIDHandlerInternal, InstanceIDHandler*());
+ MOCK_METHOD2(AddHeartbeatInterval,
+ void(const std::string& scope, int interval_ms));
+ MOCK_METHOD1(RemoveHeartbeatInterval, void(const std::string& scope));
+
+ protected:
+ MOCK_METHOD1(EnsureStarted,
+ gcm::GCMClient::Result(gcm::GCMClient::StartMode start_mode));
+ MOCK_METHOD2(RegisterImpl,
+ void(const std::string& app_id,
+ const std::vector<std::string>& sender_ids));
+ MOCK_METHOD1(UnregisterImpl, void(const std::string& app_id));
+ MOCK_METHOD3(SendImpl,
+ void(const std::string& app_id,
+ const std::string& receiver_id,
+ const gcm::OutgoingMessage& message));
+ MOCK_METHOD2(RecordDecryptionFailure,
+ void(const std::string& app_id,
+ gcm::GCMDecryptionResult result));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGCMDriver);
+};
+
+ACTION_TEMPLATE(InvokeCallbackArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(p0)) {
+ ::std::tr1::get<k>(args).Run(p0);
+}
+
+ACTION_TEMPLATE(InvokeCallbackArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_2_VALUE_PARAMS(p0, p1)) {
+ ::std::tr1::get<k>(args).Run(p0, p1);
+}
+
+base::Time GetDummyNow() {
+ base::Time out_time;
+ EXPECT_TRUE(base::Time::FromUTCString("2017-01-02T00:00:01Z", &out_time));
+ return out_time;
+}
+
+base::TimeDelta GetTokenValidationPeriod() {
+ return base::TimeDelta::FromHours(24);
+}
+
+base::TimeDelta GetForcedSubscriptionPeriod() {
+ return base::TimeDelta::FromDays(7);
+}
+
+const char kBreakingNewsGCMAppID[] = "com.google.breakingnews.gcm";
+
+std::string BoolToString(bool value) {
+ return value ? "true" : "false";
+}
+
+} // namespace
+
+class BreakingNewsGCMAppHandlerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ // Our app handler obtains InstanceID through InstanceIDDriver. We mock
+ // InstanceIDDriver and return MockInstanceID through it.
+ mock_instance_id_driver_ =
+ base::MakeUnique<StrictMock<MockInstanceIDDriver>>();
+ mock_instance_id_ = base::MakeUnique<StrictMock<MockInstanceID>>();
+ mock_gcm_driver_ = base::MakeUnique<StrictMock<MockGCMDriver>>();
+ BreakingNewsGCMAppHandler::RegisterProfilePrefs(
+ utils_.pref_service()->registry());
+
+ // This is called in BreakingNewsGCMAppHandler.
+ EXPECT_CALL(*mock_instance_id_driver_, GetInstanceID(kBreakingNewsGCMAppID))
+ .WillRepeatedly(Return(mock_instance_id_.get()));
+ }
+
+ std::unique_ptr<BreakingNewsGCMAppHandler> MakeHandler(
+ scoped_refptr<TestMockTimeTaskRunner> timer_mock_task_runner) {
+ tick_clock_ = timer_mock_task_runner->GetMockTickClock();
+ message_loop_.SetTaskRunner(timer_mock_task_runner);
+
+ // TODO(vitaliii): Initialize MockSubscriptionManager in the constructor, so
+ // that one could set up expectations before creating the handler.
+ auto wrapped_mock_subscription_manager =
+ base::MakeUnique<NiceMock<MockSubscriptionManager>>();
+ mock_subscription_manager_ = wrapped_mock_subscription_manager.get();
+
+ auto token_validation_timer =
+ base::MakeUnique<base::OneShotTimer>(tick_clock_.get());
+ token_validation_timer->SetTaskRunner(timer_mock_task_runner);
+
+ auto forced_subscription_timer =
+ base::MakeUnique<base::OneShotTimer>(tick_clock_.get());
+ forced_subscription_timer->SetTaskRunner(timer_mock_task_runner);
+
+ // TODO(vitaliii): Either parse JSON for real or expose another method to
+ // avoid it completely.
+ return base::MakeUnique<BreakingNewsGCMAppHandler>(
+ mock_gcm_driver_.get(), mock_instance_id_driver_.get(), pref_service(),
+ std::move(wrapped_mock_subscription_manager),
+ /*parse_json_callback=*/
+ base::Bind(
+ [](const std::string& raw_json_string,
+ const BreakingNewsGCMAppHandler::SuccessCallback&
+ success_callback,
+ const BreakingNewsGCMAppHandler::ErrorCallback& error_callback) {
+ error_callback.Run(/*error=*/"Not implemented");
+ }),
+ timer_mock_task_runner->GetMockClock(),
+ std::move(token_validation_timer),
+ std::move(forced_subscription_timer));
+ }
+
+ void SetFeatureParams(bool enable_token_validation,
+ bool enable_forced_subscription) {
+ // VariationParamsManager supports only one
+ // |SetVariationParamsWithFeatureAssociations| at a time, so we clear
+ // previous settings first to make this explicit.
+ params_manager_.ClearAllVariationParams();
+ params_manager_.SetVariationParamsWithFeatureAssociations(
+ kBreakingNewsPushFeature.name,
+ {
+ {"enable_token_validation", BoolToString(enable_token_validation)},
+ {"enable_forced_subscription",
+ BoolToString(enable_forced_subscription)},
+ },
+ {kBreakingNewsPushFeature.name});
+ }
+
+ PrefService* pref_service() { return utils_.pref_service(); }
+ NiceMock<MockSubscriptionManager>* mock_subscription_manager() {
+ return mock_subscription_manager_;
+ }
+ StrictMock<MockInstanceID>* mock_instance_id() {
+ return mock_instance_id_.get();
+ }
+
+ private:
+ variations::testing::VariationParamsManager params_manager_;
+ base::MessageLoop message_loop_;
+ test::RemoteSuggestionsTestUtils utils_;
+ NiceMock<MockSubscriptionManager>* mock_subscription_manager_;
+ std::unique_ptr<StrictMock<MockGCMDriver>> mock_gcm_driver_;
+ std::unique_ptr<StrictMock<MockInstanceIDDriver>> mock_instance_id_driver_;
+ std::unique_ptr<StrictMock<MockInstanceID>> mock_instance_id_;
+ std::unique_ptr<TickClock> tick_clock_;
+};
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldValidateTokenImmediatelyIfValidationIsDue) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // Last validation was long time ago.
+ const base::Time last_validation =
+ GetDummyNow() - 10 * GetTokenValidationPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ // Check that the handler validates the token through GetToken. ValidateToken
+ // always returns true on Android, so it's not useful. Instead, the handler
+ // must check that the result from GetToken is unchanged.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ task_runner->RunUntilIdle();
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldScheduleTokenValidationIfNotYetDue) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ // Check that handler does not validate the token yet.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ task_runner->FastForwardBy(time_to_validation -
+ base::TimeDelta::FromSeconds(1));
+
+ // But when it is time, validation happens.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldNotValidateTokenBeforeListening) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // Last validation was long time ago.
+ const base::Time last_validation =
+ GetDummyNow() - 10 * GetTokenValidationPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+
+ // Check that handler does not validate the token before StartListening even
+ // though a validation is due.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ auto handler = MakeHandler(task_runner);
+ task_runner->FastForwardBy(10 * GetTokenValidationPeriod());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldNotValidateTokenAfterStopListening) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+
+ // Check that handler does not validate the token after StopListening even
+ // though a validation is due.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ handler->StopListening();
+ task_runner->FastForwardBy(10 * GetTokenValidationPeriod());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldRescheduleTokenValidationWhenRetrievingToken) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ // There is no token yet, thus, handler retrieves it on StartListening.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that the validation schedule has changed. "Old validation" should not
+ // happen because the token was retrieved recently.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ task_runner->FastForwardBy(GetTokenValidationPeriod() -
+ base::TimeDelta::FromSeconds(1));
+
+ // The new validation should happen.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldScheduleNewTokenValidationAfterValidation) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Handler validates the token.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ task_runner->FastForwardBy(time_to_validation);
+
+ // Check that the next validation is scheduled in time.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ task_runner->FastForwardBy(GetTokenValidationPeriod() -
+ base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldResubscribeWithNewTokenIfOldIsInvalidAfterValidation) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // Last validation was long time ago.
+ const base::Time last_validation =
+ GetDummyNow() - 10 * GetTokenValidationPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "old_token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that handler resubscribes with the new token after a validation, if
+ // old is invalid.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("new_token", InstanceID::Result::SUCCESS));
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_subscription_manager(), Resubscribe("new_token"));
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe(_)).Times(0);
+ task_runner->RunUntilIdle();
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldDoNothingIfOldTokenIsValidAfterValidation) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // Last validation was long time ago.
+ const base::Time last_validation =
+ GetDummyNow() - 10 * GetTokenValidationPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that provider does not resubscribe if the old token is still valid
+ // after validation.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0);
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe(_)).Times(0);
+ EXPECT_CALL(*mock_subscription_manager(), Resubscribe(_)).Times(0);
+ task_runner->RunUntilIdle();
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ IsListeningShouldReturnFalseBeforeListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ EXPECT_FALSE(handler->IsListening());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ IsListeningShouldReturnTrueAfterStartListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ ASSERT_FALSE(handler->IsListening());
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillRepeatedly(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ EXPECT_TRUE(handler->IsListening());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ IsListeningShouldReturnFalseAfterStopListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ ASSERT_FALSE(handler->IsListening());
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillRepeatedly(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ ASSERT_TRUE(handler->IsListening());
+
+ handler->StopListening();
+
+ EXPECT_FALSE(handler->IsListening());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ IsListeningShouldReturnTrueAfterSecondStartListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ ASSERT_FALSE(handler->IsListening());
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillRepeatedly(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ ASSERT_TRUE(handler->IsListening());
+
+ handler->StopListening();
+ ASSERT_FALSE(handler->IsListening());
+
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ EXPECT_TRUE(handler->IsListening());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldForceSubscribeImmediatelyIfDue) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/true);
+
+ // Last subscription was long time ago.
+ const base::Time last_subscription =
+ GetDummyNow() - 10 * GetForcedSubscriptionPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token"));
+ task_runner->RunUntilIdle();
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldScheduleForcedSubscribtionIfNotYetDue) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/true);
+
+ // The next forced subscription will be soon.
+ const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1);
+ const base::Time last_subscription =
+ GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ // Check that handler does not force subscribe yet.
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ // TODO(vitaliii): Consider making FakeSubscriptionManager, because
+ // IsSubscribed() affects forced subscriptions. Currently we have to carefully
+ // avoid the initial subscription.
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0);
+ task_runner->FastForwardBy(time_to_subscription -
+ base::TimeDelta::FromSeconds(1));
+
+ // But when it is time, forced subscription happens.
+ testing::Mock::VerifyAndClearExpectations(mock_subscription_manager());
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token"));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldNotForceSubscribeBeforeListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/true);
+
+ // Last subscription was long time ago.
+ const base::Time last_subscription =
+ GetDummyNow() - 10 * GetForcedSubscriptionPeriod();
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+
+ // Check that handler does not force subscribe before StartListening even
+ // though a forced subscription is due.
+ auto handler = MakeHandler(task_runner);
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0);
+ task_runner->FastForwardBy(10 * GetForcedSubscriptionPeriod());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldNotForceSubscribeAfterStopListening) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/true);
+
+ // The next forced subscription will be soon.
+ const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1);
+ const base::Time last_subscription =
+ GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+
+ // Check that handler does not force subscribe after StopListening even
+ // though a forced subscription is due.
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ handler->StopListening();
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0);
+ task_runner->FastForwardBy(10 * GetForcedSubscriptionPeriod());
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldScheduleNewForcedSubscriptionAfterForcedSubscription) {
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/true);
+
+ // The next forced subscription will be soon.
+ const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1);
+ const base::Time last_subscription =
+ GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Handler force subscribes.
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token"));
+ task_runner->FastForwardBy(time_to_subscription);
+
+ // Check that the next forced subscription is scheduled in time.
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0);
+ task_runner->FastForwardBy(GetForcedSubscriptionPeriod() -
+ base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token"));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ TokenValidationAndForcedSubscriptionShouldNotAffectEachOther) {
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/true);
+
+ // The next forced subscription will be soon.
+ const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1);
+ const base::Time last_subscription =
+ GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime,
+ SerializeTime(last_subscription));
+
+ // The next validation will be sooner.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromMinutes(30);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that the next validation is scheduled in time.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _)).Times(0);
+ task_runner->FastForwardBy(time_to_validation -
+ base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // Check that the next forced subscription is scheduled in time.
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0);
+ task_runner->FastForwardBy((time_to_subscription - time_to_validation) -
+ base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_subscription_manager(), Subscribe("token"));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportReceivedMessageWithoutNews) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ handler->OnMessage("com.google.breakingnews.gcm", gcm::IncomingMessage());
+
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.MessageReceived"),
+ ElementsAre(base::Bucket(
+ /*min=*/metrics::ReceivedMessageStatus::
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING,
+ /*count=*/1)));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ WhenNotListeningShouldIgnoreAndReportReceivedMessageWithoutNews) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ // We do not verify that the message is not propagated futher, because there
+ // is nowhere to propagate it. The handler just should not crash.
+ handler->OnMessage("com.google.breakingnews.gcm", gcm::IncomingMessage());
+
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.MessageReceived"),
+ ElementsAre(base::Bucket(
+ /*min=*/metrics::ReceivedMessageStatus::
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING,
+ /*count=*/1)));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportReceivedMessageWithNews) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+ gcm::IncomingMessage message;
+ message.data["payload"] = "news";
+
+ handler->OnMessage("com.google.breakingnews.gcm", message);
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.MessageReceived"),
+ ElementsAre(base::Bucket(/*min=*/metrics::ReceivedMessageStatus::
+ WITH_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING,
+ /*count=*/1)));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ WhenNotListeningShouldIgnoreAndReportReceivedMessageWithNews) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ gcm::IncomingMessage message;
+ message.data["payload"] = "news";
+
+ // We do not verify that the message is not propagated futher, because there
+ // is nowhere to propagate it. The handler just should not crash.
+ handler->OnMessage("com.google.breakingnews.gcm", message);
+
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.MessageReceived"),
+ ElementsAre(base::Bucket(
+ /*min=*/metrics::ReceivedMessageStatus::
+ WITH_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING,
+ /*count=*/1)));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportTokenRetrievalResult) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/false,
+ /*enable_forced_subscription=*/false);
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(InvokeCallbackArgument<3>(/*token=*/"",
+ InstanceID::Result::NETWORK_ERROR));
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult"),
+ ElementsAre(base::Bucket(
+ /*min=*/static_cast<int>(InstanceID::Result::NETWORK_ERROR),
+ /*count=*/1)));
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldReportTimeSinceLastTokenValidation) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that handler does not report the metric before the validation.
+ task_runner->FastForwardBy(time_to_validation -
+ base::TimeDelta::FromSeconds(1));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult"),
+ IsEmpty());
+
+ // But when the validation happens, the time is reported.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ histogram_tester.ExpectTimeBucketCount(
+ "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation",
+ GetTokenValidationPeriod(), /*count=*/1);
+ // |ExpectTimeBucketCount| allows other buckets. Let's ensure that there are
+ // none.
+ histogram_tester.ExpectTotalCount(
+ "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation",
+ /*count=*/1);
+}
+
+TEST_F(BreakingNewsGCMAppHandlerTest,
+ ShouldReportWhetherTokenWasValidBeforeValidation) {
+ base::HistogramTester histogram_tester;
+ SetFeatureParams(/*enable_token_validation=*/true,
+ /*enable_forced_subscription=*/false);
+
+ // The next validation will be soon.
+ const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1);
+ const base::Time last_validation =
+ GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation);
+ pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime,
+ SerializeTime(last_validation));
+ // Omit receiving the token by putting it there directly.
+ pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+ "token");
+
+ scoped_refptr<TestMockTimeTaskRunner> task_runner(
+ new TestMockTimeTaskRunner(GetDummyNow(), TimeTicks::Now()));
+ auto handler = MakeHandler(task_runner);
+ handler->StartListening(
+ base::Bind([](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}));
+
+ // Check that handler does not report the metric before the validation.
+ task_runner->FastForwardBy(time_to_validation -
+ base::TimeDelta::FromSeconds(1));
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions."
+ "BreakingNews."
+ "WasTokenValidBeforeValidation"),
+ IsEmpty());
+
+ // But when the validation happens, the old token validness is reported.
+ EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _))
+ .WillOnce(
+ InvokeCallbackArgument<3>("token", InstanceID::Result::SUCCESS));
+ task_runner->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions."
+ "BreakingNews."
+ "WasTokenValidBeforeValidation"),
+ ElementsAre(base::Bucket(
+ /*min=*/1,
+ /*count=*/1)));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_listener.h b/chromium/components/ntp_snippets/breaking_news/breaking_news_listener.h
index e516322db1c..e2fbaaf3f78 100644
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_listener.h
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_listener.h
@@ -5,28 +5,32 @@
#ifndef COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
-#include <memory>
+#include <vector>
#include "base/callback_forward.h"
-#include "base/values.h"
+#include "components/ntp_snippets/remote/json_to_categories.h"
namespace ntp_snippets {
class BreakingNewsListener {
public:
- using OnNewContentCallback =
- base::Callback<void(std::unique_ptr<base::Value> content)>;
+ using OnNewRemoteSuggestionCallback =
+ base::Callback<void(std::unique_ptr<RemoteSuggestion> remote_suggestion)>;
virtual ~BreakingNewsListener() = default;
// Subscribe to the breaking news service and start listening for pushed
// breaking news. Must not be called if already listening.
- virtual void StartListening(OnNewContentCallback on_new_content_callback) = 0;
+ virtual void StartListening(
+ OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback) = 0;
// Stop listening for incoming breaking news. Any further pushed breaking news
// will be ignored. Must be called while listening.
virtual void StopListening() = 0;
+
+ virtual bool IsListening() const = 0;
};
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.cc b/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.cc
new file mode 100644
index 00000000000..cda9465451a
--- /dev/null
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.cc
@@ -0,0 +1,86 @@
+// 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/ntp_snippets/breaking_news/breaking_news_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+
+using instance_id::InstanceID;
+
+namespace ntp_snippets {
+namespace metrics {
+
+namespace {
+
+const char kHistogramSubscriptionRequestStatus[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.SubscriptionRequestStatus";
+const char kHistogramUnsubscriptionRequestStatus[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.UnsubscriptionRequestStatus";
+
+const char kHistogramMessageReceived[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.MessageReceived";
+
+const char kHistogramTokenRetrievalResult[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult";
+
+const char kHistogramTimeSinceLastTokenValidation[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation";
+
+const char kHistogramWasTokenValidBeforeValidation[] =
+ "NewTabPage.ContentSuggestions.BreakingNews.WasTokenValidBeforeValidation";
+
+} // namespace
+
+void OnSubscriptionRequestCompleted(const Status& status) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramSubscriptionRequestStatus, status.code,
+ StatusCode::STATUS_CODE_COUNT);
+}
+
+void OnUnsubscriptionRequestCompleted(const Status& status) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramUnsubscriptionRequestStatus, status.code,
+ StatusCode::STATUS_CODE_COUNT);
+}
+
+void OnMessageReceived(bool is_handler_listening, bool contains_pushed_news) {
+ ReceivedMessageStatus status;
+ if (contains_pushed_news) {
+ status =
+ is_handler_listening
+ ? ReceivedMessageStatus::WITH_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING
+ : ReceivedMessageStatus::
+ WITH_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING;
+ } else {
+ status = is_handler_listening
+ ? ReceivedMessageStatus::
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING
+ : ReceivedMessageStatus::
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING;
+ }
+ UMA_HISTOGRAM_ENUMERATION(kHistogramMessageReceived, status,
+ ReceivedMessageStatus::COUNT);
+}
+
+void OnTokenRetrieved(InstanceID::Result result) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramTokenRetrievalResult, result,
+ InstanceID::Result::LAST_RESULT + 1);
+}
+
+void OnTokenValidationAttempted(
+ const base::Optional<base::TimeDelta>& time_since_last_validation,
+ const base::Optional<bool>& was_token_valid_before_validation) {
+ if (time_since_last_validation.has_value()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(kHistogramTimeSinceLastTokenValidation,
+ *time_since_last_validation,
+ /*min=*/base::TimeDelta::FromSeconds(1),
+ /*max=*/base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ }
+ if (was_token_valid_before_validation.has_value()) {
+ UMA_HISTOGRAM_BOOLEAN(kHistogramWasTokenValidBeforeValidation,
+ *was_token_valid_before_validation);
+ }
+}
+
+} // namespace metrics
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.h b/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.h
new file mode 100644
index 00000000000..13f923f6cbf
--- /dev/null
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_metrics.h
@@ -0,0 +1,47 @@
+// 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_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_
+#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_
+
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "components/gcm_driver/instance_id/instance_id.h"
+#include "components/ntp_snippets/status.h"
+
+namespace ntp_snippets {
+namespace metrics {
+
+void OnSubscriptionRequestCompleted(const Status& status);
+void OnUnsubscriptionRequestCompleted(const Status& status);
+
+void OnMessageReceived(bool is_handler_listening, bool contains_pushed_news);
+
+// Received message status to report whether it contained pushed news and
+// whether the handler was listening when it arrived. This enum is used in a UMA
+// histogram, therefore, don't remove or reorder elements, only add new ones at
+// the end (before COUNT), and keep in sync with
+// ContentSuggestionsBreakingNewsMessageContainsNews in enums.xml.
+enum ReceivedMessageStatus {
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING = 0,
+ WITH_PUSHED_NEWS_AND_HANDLER_WAS_LISTENING = 1,
+ WITHOUT_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING = 2,
+ WITH_PUSHED_NEWS_AND_HANDLER_WAS_NOT_LISTENING = 3,
+ // Insert new values here!
+ COUNT
+};
+
+void OnTokenRetrieved(instance_id::InstanceID::Result result);
+
+// |time_since_last_validation| can be absent for the first validation.
+// |was_token_valid_before_validation| may be absent if it is not known (e.g. an
+// error happened and a token was not received).
+void OnTokenValidationAttempted(
+ const base::Optional<base::TimeDelta>& time_since_last_validation,
+ const base::Optional<bool>& was_token_valid_before_validation);
+
+} // namespace metrics
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc b/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
index d4672ad8f76..57a3d276f67 100644
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
@@ -5,7 +5,6 @@
#include "components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h"
#include "base/bind.h"
-#include "base/json/json_writer.h"
#include "base/time/clock.h"
#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
#include "components/ntp_snippets/category.h"
@@ -36,7 +35,7 @@ BreakingNewsSuggestionsProvider::BreakingNewsSuggestionsProvider(
base::Unretained(this)));
// Unretained because |this| owns |breaking_news_listener_|.
breaking_news_raw_data_provider_->StartListening(
- base::Bind(&BreakingNewsSuggestionsProvider::OnNewContentSuggestion,
+ base::Bind(&BreakingNewsSuggestionsProvider::OnNewRemoteSuggestion,
base::Unretained(this)));
}
@@ -44,29 +43,18 @@ BreakingNewsSuggestionsProvider::~BreakingNewsSuggestionsProvider() {
breaking_news_raw_data_provider_->StopListening();
}
-void BreakingNewsSuggestionsProvider::OnNewContentSuggestion(
- std::unique_ptr<base::Value> content) {
- DCHECK(content);
- const base::Time receive_time = clock_->Now();
- FetchedCategoriesVector categories;
- if (!JsonToCategories(*content, &categories, receive_time)) {
- std::string content_json;
- base::JSONWriter::Write(*content, &content_json);
- LOG(WARNING) << "Received invalid breaking news: " << content_json;
- return;
- }
- DCHECK_EQ(categories.size(), static_cast<size_t>(1));
- auto& fetched_category = categories[0];
- Category category = fetched_category.category;
- DCHECK(category.IsKnownCategory(KnownCategories::BREAKING_NEWS));
+void BreakingNewsSuggestionsProvider::OnNewRemoteSuggestion(
+ std::unique_ptr<RemoteSuggestion> remote_suggestion) {
+ std::vector<std::unique_ptr<RemoteSuggestion>> suggestions;
+ suggestions.push_back(std::move(remote_suggestion));
if (database_->IsInitialized()) {
- database_->SaveSnippets(fetched_category.suggestions);
+ database_->SaveSnippets(suggestions);
} else {
// TODO(mamir): Check how often a breaking news is received before DB is
// initialized.
LOG(WARNING) << "Cannot store breaking news, database is not initialized.";
}
- NotifyNewSuggestions(std::move(fetched_category.suggestions));
+ NotifyNewSuggestions(std::move(suggestions));
}
////////////////////////////////////////////////////////////////////////////////
@@ -94,14 +82,14 @@ void BreakingNewsSuggestionsProvider::DismissSuggestion(
void BreakingNewsSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
// TODO(mamir): implement.
}
void BreakingNewsSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
// TODO(jkrcal): Make Fetch method optional.
}
@@ -121,7 +109,7 @@ void BreakingNewsSuggestionsProvider::ClearCachedSuggestions(
void BreakingNewsSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
// TODO(mamir): implement.
}
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h b/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
index eb62272dbb2..d0b6b21ee67 100644
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
@@ -7,6 +7,7 @@
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/remote/json_to_categories.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/prefs/pref_registry_simple.h"
@@ -39,10 +40,10 @@ class BreakingNewsSuggestionsProvider final
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -50,13 +51,14 @@ class BreakingNewsSuggestionsProvider final
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
private:
// Callback called from the breaking news listener when new content has been
// pushed from the server.
- void OnNewContentSuggestion(std::unique_ptr<base::Value> content);
+ void OnNewRemoteSuggestion(
+ std::unique_ptr<RemoteSuggestion> remote_suggestion);
// Callbacks for the RemoteSuggestionsDatabase.
void OnDatabaseLoaded(
diff --git a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider_unittest.cc
deleted file mode 100644
index bdfbbddaa77..00000000000
--- a/chromium/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider_unittest.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h"
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/simple_test_clock.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
-#include "components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h"
-#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::Eq;
-using testing::Property;
-using testing::SaveArg;
-using testing::SizeIs;
-using testing::StrictMock;
-
-namespace ntp_snippets {
-
-namespace {
-
-class MockBreakingNewsListener : public BreakingNewsListener {
- public:
- MOCK_METHOD1(StartListening, void(OnNewContentCallback callback));
- MOCK_METHOD0(StopListening, void());
-};
-
-class BreakingNewsSuggestionsProviderTest : public testing::Test {
- public:
- BreakingNewsSuggestionsProviderTest() {
- CHECK(database_dir_.CreateUniqueTempDir());
- }
-
- ~BreakingNewsSuggestionsProviderTest() {
- EXPECT_CALL(*listener_, StopListening()).RetiresOnSaturation();
- }
-
- protected:
- void InitializeBreakingNewsSuggestionsProvider() {
- auto listener = base::MakeUnique<StrictMock<MockBreakingNewsListener>>();
- listener_ = listener.get();
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner(
- base::ThreadTaskRunnerHandle::Get());
- // TODO(mamir): Use a mock DB instead of a real one. A DB interface needs to
- // be extracted for that.
- // TODO(mamir): Add tests for database failure once the DB gets mockable.
- auto database = base::MakeUnique<RemoteSuggestionsDatabase>(
- database_dir_.GetPath(), task_runner);
-
- EXPECT_CALL(*listener_, StartListening(_))
- .WillOnce(SaveArg<0>(&on_new_content_callback_))
- .RetiresOnSaturation();
- // The observer will be updated with an empty list upon loading the
- // database.
- EXPECT_CALL(observer_, OnNewSuggestions(_,
- Category::FromKnownCategory(
- KnownCategories::BREAKING_NEWS),
- SizeIs(0)))
- .RetiresOnSaturation();
- provider_ = base::MakeUnique<BreakingNewsSuggestionsProvider>(
- &observer_, std::move(listener),
- base::MakeUnique<base::SimpleTestClock>(), std::move(database));
-
- // TODO(mamir): Find a better way to wait for initialization to finish.
- base::RunLoop().RunUntilIdle();
- }
-
- base::Time StringToTime(const std::string& time_string) {
- base::Time out_time;
- CHECK(base::Time::FromString(time_string.c_str(), &out_time));
- return out_time;
- }
-
- BreakingNewsListener::OnNewContentCallback on_new_content_callback_;
- base::MessageLoop message_loop_;
- StrictMock<MockBreakingNewsListener>* listener_;
- std::unique_ptr<BreakingNewsSuggestionsProvider> provider_;
- StrictMock<MockContentSuggestionsProviderObserver> observer_;
- base::ScopedTempDir database_dir_;
-};
-
-TEST_F(BreakingNewsSuggestionsProviderTest,
- ShouldPropagatePushedNewsWithoutModifyingToObserver) {
- InitializeBreakingNewsSuggestionsProvider();
- std::string json =
- "{\"categories\" : [{"
- " \"id\": 8,"
- " \"localizedTitle\": \"Breaking News\","
- " \"suggestions\" : [{"
- " \"ids\" : [\"http://localhost/id\"],"
- " \"title\" : \"Title string\","
- " \"snippet\" : \"Snippet string\","
- " \"fullPageUrl\" : \"http://localhost/fullUrl\","
- " \"creationTime\" : \"2016-06-30T11:01:37.000Z\","
- " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
- " \"attribution\" : \"Attribution string\","
- " \"imageUrl\" : \"http://localhost/foobar.jpg\" "
- " }]"
- "}]}";
-
- // TODO(mamir): Test imageUrl and expirationTime. They aren't directly
- // testable because they aren't part of ContentSuggestion. However, they could
- // be checked indirectly via FetchImage or by providing an expired suggestion
- // and checking that it is not propagated further.
- EXPECT_CALL(
- observer_,
- OnNewSuggestions(
- _, Eq(Category::FromKnownCategory(KnownCategories::BREAKING_NEWS)),
- ElementsAre(AllOf(
- Property(&ContentSuggestion::id,
- ContentSuggestion::ID(Category::FromRemoteCategory(8),
- "http://localhost/id")),
- Property(&ContentSuggestion::title,
- base::UTF8ToUTF16("Title string")),
- Property(&ContentSuggestion::snippet_text,
- base::UTF8ToUTF16("Snippet string")),
- Property(&ContentSuggestion::url,
- GURL("http://localhost/fullUrl")),
- Property(&ContentSuggestion::publish_date,
- StringToTime("2016-06-30T11:01:37.000Z")),
- Property(&ContentSuggestion::publisher_name,
- base::UTF8ToUTF16("Attribution string"))
-
- ))));
- on_new_content_callback_.Run(base::JSONReader().ReadToValue(json));
-}
-
-TEST_F(BreakingNewsSuggestionsProviderTest,
- ClearHistoryShouldNotifyObserverWithEmptySuggestionsList) {
- InitializeBreakingNewsSuggestionsProvider();
- EXPECT_CALL(observer_, OnNewSuggestions(_,
- Category::FromKnownCategory(
- KnownCategories::BREAKING_NEWS),
- SizeIs(0)));
- provider_->ClearHistory(base::Time::UnixEpoch(), base::Time::Max(),
- base::Callback<bool(const GURL& url)>());
-}
-
-} // namespace
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_json_request.cc b/chromium/components/ntp_snippets/breaking_news/subscription_json_request.cc
index 187e4638852..b28ea54e1bc 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_json_request.cc
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_json_request.cc
@@ -104,6 +104,19 @@ SubscriptionJsonRequest::Builder::SetAuthenticationHeader(
return *this;
}
+SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetLocale(
+ const std::string& locale) {
+ locale_ = locale;
+ return *this;
+}
+
+SubscriptionJsonRequest::Builder&
+SubscriptionJsonRequest::Builder::SetCountryCode(
+ const std::string& country_code) {
+ country_code_ = country_code;
+ return *this;
+}
+
std::string SubscriptionJsonRequest::Builder::BuildHeaders() const {
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kContentType,
@@ -126,6 +139,9 @@ std::string SubscriptionJsonRequest::Builder::BuildBody() const {
base::DictionaryValue request;
request.SetString("token", token_);
+ request.SetString("locale", locale_);
+ request.SetString("country_code", country_code_);
+
std::string request_json;
bool success = base::JSONWriter::Write(request, &request_json);
DCHECK(success);
@@ -150,7 +166,7 @@ std::unique_ptr<URLFetcher> SubscriptionJsonRequest::Builder::BuildURLFetcher(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"This feature cannot be disabled by settings now"
chrome_policy {
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_json_request.h b/chromium/components/ntp_snippets/breaking_news/subscription_json_request.h
index b0aa71c4bad..e6583309e83 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_json_request.h
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_json_request.h
@@ -45,6 +45,16 @@ class SubscriptionJsonRequest : public net::URLFetcherDelegate {
const scoped_refptr<net::URLRequestContextGetter>& context_getter);
Builder& SetAuthenticationHeader(const std::string& auth_header);
+ // The application language represented as an IETF language tag, defined in
+ // BCP 47, e.g. "de", "de-AT".
+ Builder& SetLocale(const std::string& locale);
+
+ // The device country represented as lowercase ISO 3166-1 alpha-2, e.g.
+ // "us", "in".
+ // TODO(vitaliii): Use CLDR. Currently this is not possible, because the
+ // variations permanent country is not provided in CLDR.
+ Builder& SetCountryCode(const std::string& country_code);
+
private:
std::string BuildHeaders() const;
std::string BuildBody() const;
@@ -55,7 +65,9 @@ class SubscriptionJsonRequest : public net::URLFetcherDelegate {
// GCM subscription token obtained from GCM driver (instanceID::getToken()).
std::string token_;
- // TODO(mamir): Additional fields to be added: country, language.
+
+ std::string locale_;
+ std::string country_code_;
GURL url_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc b/chromium/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
index 0f09e8bd204..2625529a0d0 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc
@@ -42,7 +42,7 @@ MATCHER_P(EqualsJSON, json, "equals JSON") {
<< "parse error: " << err_msg;
return false;
}
- return base::Value::Equals(actual.get(), expected.get());
+ return *expected == *actual;
}
} // namespace
@@ -101,6 +101,8 @@ TEST_F(SubscriptionJsonRequestTest, BuildRequest) {
builder.SetToken(token)
.SetUrl(url)
.SetUrlRequestContextGetter(GetRequestContext())
+ .SetLocale("en-US")
+ .SetCountryCode("us")
.Build();
request->Start(callback.Get());
@@ -116,11 +118,13 @@ TEST_F(SubscriptionJsonRequestTest, BuildRequest) {
EXPECT_TRUE(headers.GetHeader("Content-Type", &header));
EXPECT_EQ(header, "application/json; charset=UTF-8");
- std::string expected_body =
- "{"
- " \"token\": "
- " \"1234567890\""
- "}";
+ std::string expected_body = R"(
+ {
+ "token": "1234567890",
+ "locale": "en-US",
+ "country_code": "us"
+ }
+ )";
EXPECT_THAT(url_fetcher->upload_data(), EqualsJSON(expected_body));
}
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
index 22fd71ae6c9..4eb5bca0f6b 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
@@ -8,6 +8,7 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/stringprintf.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h"
#include "components/ntp_snippets/breaking_news/subscription_json_request.h"
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/ntp_snippets_constants.h"
@@ -16,6 +17,7 @@
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/access_token_fetcher.h"
#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/variations/service/variations_service.h"
#include "net/base/url_util.h"
namespace ntp_snippets {
@@ -60,19 +62,23 @@ class SubscriptionManagerImpl::SigninObserver
SubscriptionManagerImpl::SubscriptionManagerImpl(
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
PrefService* pref_service,
+ variations::VariationsService* variations_service,
SigninManagerBase* signin_manager,
OAuth2TokenService* access_token_service,
+ const std::string& locale,
const std::string& api_key,
const GURL& subscribe_url,
const GURL& unsubscribe_url)
: url_request_context_getter_(std::move(url_request_context_getter)),
pref_service_(pref_service),
+ variations_service_(variations_service),
signin_manager_(signin_manager),
signin_observer_(base::MakeUnique<SigninObserver>(
signin_manager,
base::Bind(&SubscriptionManagerImpl::SigninStatusChanged,
base::Unretained(this)))),
access_token_service_(access_token_service),
+ locale_(locale),
api_key_(api_key),
subscribe_url_(subscribe_url),
unsubscribe_url_(unsubscribe_url) {}
@@ -108,6 +114,11 @@ void SubscriptionManagerImpl::SubscribeInternal(
net::AppendQueryParameter(subscribe_url_, kApiKeyParamName, api_key_));
}
+ builder.SetLocale(locale_);
+ builder.SetCountryCode(variations_service_
+ ? variations_service_->GetStoredPermanentCountry()
+ : "");
+
request_ = builder.Build();
request_->Start(base::BindOnce(&SubscriptionManagerImpl::DidSubscribe,
base::Unretained(this), subscription_token,
@@ -149,6 +160,8 @@ void SubscriptionManagerImpl::DidSubscribe(
const std::string& subscription_token,
bool is_authenticated,
const Status& status) {
+ metrics::OnSubscriptionRequestCompleted(status);
+
// Delete the request only after we leave this method (which is called from
// the request itself).
std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
@@ -225,6 +238,8 @@ void SubscriptionManagerImpl::Resubscribe(const std::string& new_token) {
void SubscriptionManagerImpl::DidUnsubscribe(const std::string& new_token,
const Status& status) {
+ metrics::OnUnsubscriptionRequestCompleted(status);
+
// Delete the request only after we leave this method (which is called from
// the request itself).
std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter(
@@ -259,6 +274,7 @@ void SubscriptionManagerImpl::SigninStatusChanged() {
}
}
+// static
void SubscriptionManagerImpl::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kBreakingNewsSubscriptionDataToken,
@@ -267,4 +283,11 @@ void SubscriptionManagerImpl::RegisterProfilePrefs(
prefs::kBreakingNewsSubscriptionDataIsAuthenticated, false);
}
+// TODO(vitaliii): Add a test to ensure that this clears everything.
+// static
+void SubscriptionManagerImpl::ClearProfilePrefs(PrefService* pref_service) {
+ pref_service->ClearPref(prefs::kBreakingNewsSubscriptionDataToken);
+ pref_service->ClearPref(prefs::kBreakingNewsSubscriptionDataIsAuthenticated);
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.h b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.h
index b1fd05bda06..40874fa844a 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.h
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl.h
@@ -20,6 +20,10 @@ class OAuth2TokenService;
class PrefRegistrySimple;
class PrefService;
+namespace variations {
+class VariationsService;
+}
+
namespace ntp_snippets {
// Class that wraps around the functionality of SubscriptionJsonRequest. It uses
@@ -32,8 +36,10 @@ class SubscriptionManagerImpl : public SubscriptionManager {
SubscriptionManagerImpl(
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
PrefService* pref_service,
+ variations::VariationsService* variations_service,
SigninManagerBase* signin_manager,
OAuth2TokenService* access_token_service,
+ const std::string& locale,
const std::string& api_key,
const GURL& subscribe_url,
const GURL& unsubscribe_url);
@@ -52,6 +58,7 @@ class SubscriptionManagerImpl : public SubscriptionManager {
bool NeedsToResubscribe() override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+ static void ClearProfilePrefs(PrefService* pref_service);
private:
class SigninObserver;
@@ -85,11 +92,15 @@ class SubscriptionManagerImpl : public SubscriptionManager {
PrefService* pref_service_;
+ variations::VariationsService* const variations_service_;
+
// Authentication for signed-in users.
SigninManagerBase* signin_manager_;
std::unique_ptr<SigninObserver> signin_observer_;
OAuth2TokenService* access_token_service_;
+ const std::string locale_;
+
// API key to use for non-authenticated requests.
const std::string api_key_;
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
index 2c8cebdb57f..4edcafeed65 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h"
#include "base/message_loop/message_loop.h"
+#include "base/test/histogram_tester.h"
#include "build/build_config.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/remote/test_utils.h"
@@ -13,10 +14,14 @@
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
+#include "net/base/net_errors.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::ElementsAre;
+
namespace ntp_snippets {
const char kTestEmail[] = "test@email.com";
@@ -149,10 +154,12 @@ class SubscriptionManagerImplTest : public testing::Test {
TEST_F(SubscriptionManagerImplTest, SubscribeSuccessfully) {
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), GetOAuth2TokenService(),
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ // TODO(vitaliii): Add a helper to build the manager.
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
ASSERT_TRUE(manager.IsSubscribed());
@@ -174,10 +181,10 @@ TEST_F(SubscriptionManagerImplTest,
// Create manager and subscribe.
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), auth_token_service,
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(), auth_token_service,
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
// Make sure that subscription is pending an access token.
@@ -200,10 +207,11 @@ TEST_F(SubscriptionManagerImplTest,
TEST_F(SubscriptionManagerImplTest, ShouldNotSubscribeIfError) {
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), GetOAuth2TokenService(),
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
RespondToSubscriptionWithError(/*is_signed_in=*/false, net::ERR_TIMED_OUT);
@@ -212,10 +220,11 @@ TEST_F(SubscriptionManagerImplTest, ShouldNotSubscribeIfError) {
TEST_F(SubscriptionManagerImplTest, UnsubscribeSuccessfully) {
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), GetOAuth2TokenService(),
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
ASSERT_TRUE(manager.IsSubscribed());
@@ -229,10 +238,11 @@ TEST_F(SubscriptionManagerImplTest, UnsubscribeSuccessfully) {
TEST_F(SubscriptionManagerImplTest,
ShouldRemainSubscribedIfErrorDuringUnsubscribe) {
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), GetOAuth2TokenService(),
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
ASSERT_TRUE(manager.IsSubscribed());
@@ -251,10 +261,10 @@ TEST_F(SubscriptionManagerImplTest,
// Create manager and subscribe.
FakeProfileOAuth2TokenService* auth_token_service = GetOAuth2TokenService();
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), auth_token_service,
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(), auth_token_service,
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
ASSERT_FALSE(manager.NeedsToResubscribe());
@@ -283,10 +293,10 @@ TEST_F(SubscriptionManagerImplTest,
SignIn();
IssueRefreshToken(auth_token_service);
std::string subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), auth_token_service,
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(), auth_token_service,
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(subscription_token);
ASSERT_EQ(1u, auth_token_service->GetPendingRequests().size());
IssueAccessToken(auth_token_service);
@@ -307,10 +317,11 @@ TEST_F(SubscriptionManagerImplTest,
ShouldUpdateTokenInPrefWhenResubscribeWithChangeInToken) {
// Create manager and subscribe.
std::string old_subscription_token = "1234567890";
- SubscriptionManagerImpl manager(GetRequestContext(), GetPrefService(),
- GetSigninManager(), GetOAuth2TokenService(),
- kAPIKey, GURL(kSubscriptionUrl),
- GURL(kUnsubscriptionUrl));
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
manager.Subscribe(old_subscription_token);
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
EXPECT_EQ(
@@ -331,4 +342,49 @@ TEST_F(SubscriptionManagerImplTest,
GetPrefService()->GetString(prefs::kBreakingNewsSubscriptionDataToken));
}
+TEST_F(SubscriptionManagerImplTest, ShouldReportSubscriptionResult) {
+ base::HistogramTester histogram_tester;
+ // Create manager and subscribe.
+ const std::string subscription_token = "token";
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
+ manager.Subscribe(subscription_token);
+ // TODO(vitaliii): Mock subscription request to avoid this low level errors.
+ RespondToSubscriptionWithError(/*is_signed_in=*/false,
+ /*error_code=*/net::ERR_INVALID_RESPONSE);
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions."
+ "BreakingNews.SubscriptionRequestStatus"),
+ ElementsAre(base::Bucket(
+ /*min=*/static_cast<int>(StatusCode::TEMPORARY_ERROR),
+ /*count=*/1)));
+}
+
+TEST_F(SubscriptionManagerImplTest, ShouldReportUnsubscriptionResult) {
+ base::HistogramTester histogram_tester;
+ // Create manager and subscribe.
+ const std::string subscription_token = "token";
+ SubscriptionManagerImpl manager(
+ GetRequestContext(), GetPrefService(),
+ /*variations_service=*/nullptr, GetSigninManager(),
+ GetOAuth2TokenService(),
+ /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), GURL(kUnsubscriptionUrl));
+ manager.Subscribe(subscription_token);
+ RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false);
+ manager.Unsubscribe();
+
+ RespondToUnsubscriptionWithError(/*is_signed_in=*/false,
+ /*error_code=*/net::ERR_INVALID_RESPONSE);
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions."
+ "BreakingNews."
+ "UnsubscriptionRequestStatus"),
+ ElementsAre(base::Bucket(
+ /*min=*/static_cast<int>(StatusCode::TEMPORARY_ERROR),
+ /*count=*/1)));
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/callbacks.h b/chromium/components/ntp_snippets/callbacks.h
index 4adda04b0b8..2d9efcec22a 100644
--- a/chromium/components/ntp_snippets/callbacks.h
+++ b/chromium/components/ntp_snippets/callbacks.h
@@ -20,21 +20,19 @@ class ContentSuggestion;
struct Status;
-// TODO(treib): All these should probably be OnceCallback.
-
// Returns the result of a |Fetch| call by a ContentSuggestionsProvider.
using FetchDoneCallback =
- base::Callback<void(Status status_code,
- std::vector<ContentSuggestion> suggestions)>;
+ base::OnceCallback<void(Status status_code,
+ std::vector<ContentSuggestion> suggestions)>;
// Returns the resulting image of a |FetchSuggestionImage| call by a
// ContentSuggestionsProvider.
-using ImageFetchedCallback = base::Callback<void(const gfx::Image&)>;
+using ImageFetchedCallback = base::OnceCallback<void(const gfx::Image&)>;
// Returns the list of dismissed suggestions when invoked. Currently only used
// for debugging methods to check the internal state of a provider.
-using DismissedSuggestionsCallback =
- base::Callback<void(std::vector<ContentSuggestion> dismissed_suggestions)>;
+using DismissedSuggestionsCallback = base::OnceCallback<void(
+ std::vector<ContentSuggestion> dismissed_suggestions)>;
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category.h b/chromium/components/ntp_snippets/category.h
index b63c6af935c..59b78b4c971 100644
--- a/chromium/components/ntp_snippets/category.h
+++ b/chromium/components/ntp_snippets/category.h
@@ -37,6 +37,9 @@ enum class KnownCategories {
// Pages from the user reading list.
READING_LIST,
+ // Contextual suggestion.
+ CONTEXTUAL,
+
// ****************** INSERT NEW LOCAL CATEGORIES HERE! ******************
// Existing categories are persisted and they must never be removed. This may
// happen implicitly, e.g. when an older version without some local category
@@ -49,14 +52,15 @@ enum class KnownCategories {
REMOTE_CATEGORIES_OFFSET = 10000,
// Articles for you.
- ARTICLES,
+ ARTICLES = 10001,
+
+ // Categories 10002-10008 are defined on the server.
- // Breaking News
- BREAKING_NEWS = 10008,
// ****************** INSERT NEW REMOTE CATEGORIES HERE! ******************
+ // Update the list on the server first. Here specify the ID explicitly.
// Tracks the last known remote category
- LAST_KNOWN_REMOTE_CATEGORY = BREAKING_NEWS,
+ LAST_KNOWN_REMOTE_CATEGORY = ARTICLES,
};
// A category groups ContentSuggestions which belong together. Use the
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
index d68fe9104d4..c7ab47db3bf 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
@@ -118,6 +118,9 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
std::vector<KnownCategories> categories;
CategoryOrderChoice choice = GetSelectedCategoryOrder();
switch (choice) {
+ // All categories must be present. An exception is
+ // KnownCategories::CONTEXTUAL because it is not handled by
+ // ContentSuggestionsService.
case CategoryOrderChoice::GENERAL:
categories.push_back(KnownCategories::PHYSICAL_WEB_PAGES);
categories.push_back(KnownCategories::READING_LIST);
@@ -140,8 +143,10 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
}
static_assert(
- static_cast<size_t>(KnownCategories::LOCAL_CATEGORIES_COUNT) == 6,
- "All local KnownCategories must be present in all orders.");
+ static_cast<size_t>(KnownCategories::LOCAL_CATEGORIES_COUNT) == 7,
+ "Number of local categories has changed, please update "
+ "ConstantCategoryRanker::GetKnownCategoriesDefaultOrder to list all "
+ "local KnownCategories for all orders.");
// Other remote categories will be ordered after these depending on when
// providers notify us about them using AppendCategoryIfNecessary.
diff --git a/chromium/components/ntp_snippets/content_suggestion.h b/chromium/components/ntp_snippets/content_suggestion.h
index 312c710f062..a3fcf3d3f5d 100644
--- a/chromium/components/ntp_snippets/content_suggestion.h
+++ b/chromium/components/ntp_snippets/content_suggestion.h
@@ -49,8 +49,6 @@ struct RecentTabSuggestionExtra {
// ReadingListSuggestionExtra contains additional data which is only available
// for Reading List suggestions.
struct ReadingListSuggestionExtra {
- // State of the distillation of the suggestion.
- bool distilled = false;
// URL of the page whose favicon should be displayed for this suggestion.
GURL favicon_page_url;
};
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.cc b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
index 3be66f2a0eb..91af0367a45 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
@@ -19,7 +19,7 @@ namespace metrics {
namespace {
-const int kMaxSuggestionsPerCategory = 10;
+const int kMaxSuggestionsPerCategory = 20;
const int kMaxSuggestionsTotal = 50;
const int kMaxCategories = 10;
@@ -63,6 +63,15 @@ const char kHistogramCategoryDismissed[] =
const char kHistogramTimeSinceSuggestionFetched[] =
"NewTabPage.ContentSuggestions.TimeSinceSuggestionFetched";
+// Histograms related to prefetching.
+const char kHistogramPrefetchedArticlesCountOnNtpOpenedIfVisibleAndOffline[] =
+ "NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles."
+ "Prefetched.Offline";
+const char kHistogramPrefetchedArticleOpenedWhenOffline[] =
+ "NewTabPage.ContentSuggestions.Opened.Articles.Prefetched.Offline";
+const char kHistogramPrefetchedArticleShownWhenOffline[] =
+ "NewTabPage.ContentSuggestions.Shown.Articles.Prefetched.Offline";
+
const char kPerCategoryHistogramFormat[] = "%s.%s";
// This mostly corresponds to the KnownCategories enum, but it is contiguous
@@ -78,7 +87,7 @@ enum HistogramCategories {
FOREIGN_TABS,
ARTICLES,
READING_LIST,
- BREAKING_NEWS,
+ CONTEXTUAL,
// Insert new values here!
COUNT
};
@@ -108,8 +117,8 @@ HistogramCategories GetHistogramCategory(Category category) {
return HistogramCategories::ARTICLES;
case KnownCategories::READING_LIST:
return HistogramCategories::READING_LIST;
- case KnownCategories::BREAKING_NEWS:
- return HistogramCategories::BREAKING_NEWS;
+ case KnownCategories::CONTEXTUAL:
+ return HistogramCategories::CONTEXTUAL;
case KnownCategories::LOCAL_CATEGORIES_COUNT:
case KnownCategories::REMOTE_CATEGORIES_OFFSET:
NOTREACHED();
@@ -140,8 +149,8 @@ std::string GetCategorySuffix(Category category) {
return "Experimental";
case HistogramCategories::READING_LIST:
return "ReadingList";
- case HistogramCategories::BREAKING_NEWS:
- return "BreakingNews";
+ case HistogramCategories::CONTEXTUAL:
+ return "Contextual";
case HistogramCategories::COUNT:
NOTREACHED();
break;
@@ -220,18 +229,29 @@ void RecordContentSuggestionsUsage() {
void OnPageShown(const std::vector<Category>& categories,
const std::vector<int>& suggestions_per_category,
- const std::vector<bool>& is_category_visible) {
+ const std::vector<int>& prefetched_suggestions_per_category,
+ const std::vector<bool>& is_category_visible,
+ bool is_offline) {
DCHECK_EQ(categories.size(), suggestions_per_category.size());
+ DCHECK_EQ(categories.size(), prefetched_suggestions_per_category.size());
DCHECK_EQ(categories.size(), is_category_visible.size());
int suggestions_total = 0;
int visible_categories_count = 0;
for (size_t i = 0; i < categories.size(); ++i) {
+ DCHECK_GE(suggestions_per_category[i],
+ prefetched_suggestions_per_category[i]);
if (is_category_visible[i]) {
LogCategoryHistogramPosition(kHistogramCountOnNtpOpenedIfVisible,
categories[i], suggestions_per_category[i],
kMaxSuggestionsPerCategory);
suggestions_total += suggestions_per_category[i];
++visible_categories_count;
+ if (categories[i].IsKnownCategory(KnownCategories::ARTICLES) &&
+ is_offline) {
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ kHistogramPrefetchedArticlesCountOnNtpOpenedIfVisibleAndOffline,
+ prefetched_suggestions_per_category[i], kMaxSuggestionsPerCategory);
+ }
}
}
UMA_HISTOGRAM_EXACT_LINEAR(kHistogramCountOnNtpOpenedIfVisible,
@@ -245,7 +265,9 @@ void OnSuggestionShown(int global_position,
int position_in_category,
base::Time publish_date,
float score,
- base::Time fetch_date) {
+ base::Time fetch_date,
+ bool is_prefetched,
+ bool is_offline) {
UMA_HISTOGRAM_EXACT_LINEAR(kHistogramShown, global_position,
kMaxSuggestionsTotal);
LogCategoryHistogramPosition(kHistogramShown, category, position_in_category,
@@ -262,9 +284,14 @@ void OnSuggestionShown(int global_position,
kHistogramTimeSinceSuggestionFetched, base::Time::Now() - fetch_date,
base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7),
/*bucket_count=*/100);
+ if (is_offline && is_prefetched) {
+ UMA_HISTOGRAM_EXACT_LINEAR(kHistogramPrefetchedArticleShownWhenOffline,
+ position_in_category,
+ kMaxSuggestionsPerCategory);
+ }
}
- // TODO(markusheintz): Discuss whether the code below should be move into a
+ // TODO(markusheintz): Discuss whether the code below should be moved into a
// separate method called OnSuggestionsListShown.
// When the first of the articles suggestions is shown, then we count this as
// a single usage of content suggestions.
@@ -280,7 +307,9 @@ void OnSuggestionOpened(int global_position,
int position_in_category,
base::Time publish_date,
float score,
- WindowOpenDisposition disposition) {
+ WindowOpenDisposition disposition,
+ bool is_prefetched,
+ bool is_offline) {
UMA_HISTOGRAM_EXACT_LINEAR(kHistogramOpenedCategoryIndex, category_index,
kMaxCategories);
LogCategoryHistogramPosition(kHistogramOpenedCategoryIndex, category,
@@ -308,6 +337,11 @@ void OnSuggestionOpened(int global_position,
if (category.IsKnownCategory(KnownCategories::ARTICLES)) {
RecordContentSuggestionsUsage();
+ if (is_offline && is_prefetched) {
+ UMA_HISTOGRAM_EXACT_LINEAR(kHistogramPrefetchedArticleOpenedWhenOffline,
+ position_in_category,
+ kMaxSuggestionsPerCategory);
+ }
}
base::RecordAction(base::UserMetricsAction("Suggestions.Content.Opened"));
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.h b/chromium/components/ntp_snippets/content_suggestions_metrics.h
index 160242aec10..2f6acd1b245 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.h
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.h
@@ -20,7 +20,9 @@ namespace metrics {
// whether the user actually saw the category.
void OnPageShown(const std::vector<Category>& categories,
const std::vector<int>& suggestions_per_category,
- const std::vector<bool>& is_category_visible);
+ const std::vector<int>& prefetched_suggestions_per_category,
+ const std::vector<bool>& is_category_visible,
+ bool is_offline);
// Should only be called once per NTP for each suggestion.
void OnSuggestionShown(int global_position,
@@ -28,7 +30,9 @@ void OnSuggestionShown(int global_position,
int position_in_category,
base::Time publish_date,
float score,
- base::Time fetch_date);
+ base::Time fetch_date,
+ bool is_prefetched,
+ bool is_offline);
// TODO(crbug.com/682160): Take struct, so that one could not mix up the
// order of arguments.
@@ -38,7 +42,9 @@ void OnSuggestionOpened(int global_position,
int position_in_category,
base::Time publish_date,
float score,
- WindowOpenDisposition disposition);
+ WindowOpenDisposition disposition,
+ bool is_prefetched,
+ bool is_offline);
void OnSuggestionMenuOpened(int global_position,
Category category,
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics_unittest.cc b/chromium/components/ntp_snippets/content_suggestions_metrics_unittest.cc
index fd636e4b967..a13e2fc8cdf 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics_unittest.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics_unittest.cc
@@ -21,21 +21,29 @@ TEST(ContentSuggestionsMetricsTest, ShouldLogOnSuggestionsShown) {
base::HistogramTester histogram_tester;
OnSuggestionShown(/*global_position=*/1,
Category::FromKnownCategory(KnownCategories::ARTICLES),
- /*category_position=*/3, base::Time::Now(), 0.01f,
- base::Time::Now() - base::TimeDelta::FromHours(2));
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/0.01f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/false);
// Test corner cases for score.
OnSuggestionShown(/*global_position=*/1,
Category::FromKnownCategory(KnownCategories::ARTICLES),
- /*category_position=*/3, base::Time::Now(), 0.0f,
- base::Time::Now() - base::TimeDelta::FromHours(2));
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/0.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/false);
OnSuggestionShown(/*global_position=*/1,
Category::FromKnownCategory(KnownCategories::ARTICLES),
- /*category_position=*/3, base::Time::Now(), 1.0f,
- base::Time::Now() - base::TimeDelta::FromHours(2));
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/1.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/false);
OnSuggestionShown(/*global_position=*/1,
Category::FromKnownCategory(KnownCategories::ARTICLES),
- /*category_position=*/3, base::Time::Now(), 8.0f,
- base::Time::Now() - base::TimeDelta::FromHours(2));
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/8.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/false);
EXPECT_THAT(
histogram_tester.GetAllSamples(
@@ -52,7 +60,8 @@ TEST(ContentSuggestionsMetricsTest,
OnPageShown(std::vector<Category>(
{Category::FromKnownCategory(KnownCategories::ARTICLES)}),
/*suggestions_per_category=*/{0},
- /*is_category_visible=*/{false});
+ /*prefetched_suggestions_per_category=*/{0},
+ /*is_category_visible=*/{false}, /*is_offline=*/false);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles"),
@@ -71,7 +80,8 @@ TEST(ContentSuggestionsMetricsTest,
OnPageShown(std::vector<Category>(
{Category::FromKnownCategory(KnownCategories::ARTICLES)}),
/*suggestions_per_category=*/{0},
- /*is_category_visible=*/{true});
+ /*prefetched_suggestions_per_category=*/{0},
+ /*is_category_visible=*/{true}, /*is_offline=*/false);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles"),
@@ -90,7 +100,8 @@ TEST(ContentSuggestionsMetricsTest,
OnPageShown(std::vector<Category>(
{Category::FromKnownCategory(KnownCategories::ARTICLES)}),
/*suggestions_per_category=*/{10},
- /*is_category_visible=*/{true});
+ /*prefetched_suggestions_per_category=*/{0},
+ /*is_category_visible=*/{true}, /*is_offline=*/false);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles"),
@@ -110,7 +121,9 @@ TEST(ContentSuggestionsMetricsTest,
{Category::FromKnownCategory(KnownCategories::ARTICLES),
Category::FromKnownCategory(KnownCategories::BOOKMARKS)}),
/*suggestions_per_category=*/{10, 5},
- /*is_category_visible=*/{true, true});
+ /*prefetched_suggestions_per_category=*/{0, 0},
+ /*is_category_visible=*/{true, true},
+ /*is_offline=*/false);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles"),
@@ -127,6 +140,108 @@ TEST(ContentSuggestionsMetricsTest,
ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
}
+TEST(ContentSuggestionsMetricsTest, ShouldLogPrefetchedSuggestionsWhenShown) {
+ base::HistogramTester histogram_tester;
+ OnSuggestionShown(/*global_position=*/11,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*position_in_category=*/1, base::Time::Now(),
+ /*score=*/1.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/false);
+ OnSuggestionShown(/*global_position=*/13,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/1.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/true, /*is_offline=*/false);
+ OnSuggestionShown(/*global_position=*/15,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*position_in_category=*/5, base::Time::Now(),
+ /*score=*/1.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/false, /*is_offline=*/true);
+ OnSuggestionShown(/*global_position=*/23,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*position_in_category=*/13, base::Time::Now(),
+ /*score=*/1.0f,
+ base::Time::Now() - base::TimeDelta::FromHours(2),
+ /*is_prefetched=*/true, /*is_offline=*/true);
+
+ // Only the last call should be reported, because only there the user is
+ // offline and the suggestion was prefetched at the same time.
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.Shown.Articles.Prefetched.Offline"),
+ ElementsAre(base::Bucket(/*min=*/13, /*count=*/1)));
+}
+
+TEST(ContentSuggestionsMetricsTest, ShouldLogPrefetchedSuggestionsWhenOpened) {
+ base::HistogramTester histogram_tester;
+ OnSuggestionOpened(/*global_position=*/11,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*category_index=*/2,
+ /*position_in_category=*/1, base::Time::Now(),
+ /*score=*/1.0f, WindowOpenDisposition::NEW_BACKGROUND_TAB,
+ /*is_prefetched=*/false, /*is_offline=*/false);
+ OnSuggestionOpened(/*global_position=*/13,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*category_index=*/2,
+ /*position_in_category=*/3, base::Time::Now(),
+ /*score=*/1.0f, WindowOpenDisposition::NEW_BACKGROUND_TAB,
+ /*is_prefetched=*/true, /*is_offline=*/false);
+ OnSuggestionOpened(/*global_position=*/15,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*category_index=*/2,
+ /*position_in_category=*/5, base::Time::Now(),
+ /*score=*/1.0f, WindowOpenDisposition::NEW_BACKGROUND_TAB,
+ /*is_prefetched=*/false, /*is_offline=*/true);
+ OnSuggestionOpened(/*global_position=*/23,
+ Category::FromKnownCategory(KnownCategories::ARTICLES),
+ /*category_index=*/2,
+ /*position_in_category=*/13, base::Time::Now(),
+ /*score=*/1.0f, WindowOpenDisposition::NEW_BACKGROUND_TAB,
+ /*is_prefetched=*/true, /*is_offline=*/true);
+
+ // Only the last call should be reported, because only there the user is
+ // offline and the suggestion was prefetched at the same time.
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "NewTabPage.ContentSuggestions.Opened.Articles.Prefetched.Offline"),
+ ElementsAre(base::Bucket(/*min=*/13, /*count=*/1)));
+}
+
+TEST(ContentSuggestionsMetricsTest,
+ ShouldLogPrefetchedSuggestionsCountWhenPageShown) {
+ base::HistogramTester histogram_tester;
+ OnPageShown(std::vector<Category>(
+ {Category::FromKnownCategory(KnownCategories::ARTICLES)}),
+ /*suggestions_per_category=*/{10},
+ /*prefetched_suggestions_per_category=*/{1},
+ /*is_category_visible=*/{false}, /*is_offline=*/false);
+ OnPageShown(std::vector<Category>(
+ {Category::FromKnownCategory(KnownCategories::ARTICLES)}),
+ /*suggestions_per_category=*/{10},
+ /*prefetched_suggestions_per_category=*/{2},
+ /*is_category_visible=*/{true}, /*is_offline=*/false);
+ OnPageShown(std::vector<Category>(
+ {Category::FromKnownCategory(KnownCategories::ARTICLES)}),
+ /*suggestions_per_category=*/{10},
+ /*prefetched_suggestions_per_category=*/{3},
+ /*is_category_visible=*/{false}, /*is_offline=*/true);
+ OnPageShown(std::vector<Category>(
+ {Category::FromKnownCategory(KnownCategories::ARTICLES)}),
+ /*suggestions_per_category=*/{10},
+ /*prefetched_suggestions_per_category=*/{4},
+ /*is_category_visible=*/{true}, /*is_offline=*/true);
+
+ // Only the last call should be reported, because only there the user is
+ // offline and the section is visible at the same time.
+ EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions."
+ "CountOnNtpOpenedIfVisible."
+ "Articles.Prefetched.Offline"),
+ ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
+}
+
} // namespace
} // namespace metrics
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider.h b/chromium/components/ntp_snippets/content_suggestions_provider.h
index 3fc37b01525..966155a028c 100644
--- a/chromium/components/ntp_snippets/content_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/content_suggestions_provider.h
@@ -93,7 +93,7 @@ class ContentSuggestionsProvider {
// fails, the callback gets a null image. The callback will not be called
// synchronously.
virtual void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) = 0;
+ ImageFetchedCallback callback) = 0;
// Fetches more suggestions for the given category. The new suggestions
// will not include any suggestion of the |known_suggestion_ids| sets.
@@ -104,7 +104,7 @@ class ContentSuggestionsProvider {
// additional suggestions.
virtual void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) = 0;
+ FetchDoneCallback callback) = 0;
// Reloads suggestions from all categories. If the suggestions change, the
// observer must be notified via OnNewSuggestions();
@@ -140,7 +140,7 @@ class ContentSuggestionsProvider {
// may be called synchronously.
virtual void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) = 0;
+ DismissedSuggestionsCallback callback) = 0;
// Used only for debugging purposes. Clears the cache of dismissed
// suggestions for the given |category|, if present, so that no suggestions
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index d06e2170c45..281451461a4 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -145,16 +145,16 @@ ContentSuggestionsService::GetSuggestionsForCategory(Category category) const {
void ContentSuggestionsService::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
if (!providers_by_category_.count(suggestion_id.category())) {
LOG(WARNING) << "Requested image for suggestion " << suggestion_id
<< " for unavailable category " << suggestion_id.category();
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
return;
}
providers_by_category_[suggestion_id.category()]->FetchSuggestionImage(
- suggestion_id, callback);
+ suggestion_id, std::move(callback));
}
// TODO(jkrcal): Split the favicon fetching into a separate class.
@@ -162,17 +162,17 @@ void ContentSuggestionsService::FetchSuggestionFavicon(
const ContentSuggestion::ID& suggestion_id,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
const GURL& domain_with_favicon = GetFaviconDomain(suggestion_id);
if (!domain_with_favicon.is_valid() || !large_icon_service_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
return;
}
GetFaviconFromCache(domain_with_favicon, minimum_size_in_pixel,
- desired_size_in_pixel, callback,
+ desired_size_in_pixel, std::move(callback),
/*continue_to_google_server=*/true);
}
@@ -203,7 +203,7 @@ void ContentSuggestionsService::GetFaviconFromCache(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
bool continue_to_google_server) {
// TODO(jkrcal): Create a general wrapper function in LargeIconService that
// does handle the get-from-cache-and-fallback-to-google-server functionality
@@ -215,7 +215,8 @@ void ContentSuggestionsService::GetFaviconFromCache(
publisher_url, minimum_size_in_pixel, /*desired_size_in_pixel=*/0,
base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
base::Unretained(this), publisher_url, minimum_size_in_pixel,
- desired_size_in_pixel, callback, continue_to_google_server),
+ desired_size_in_pixel, base::Passed(std::move(callback)),
+ continue_to_google_server),
&favicons_task_tracker_);
}
@@ -223,11 +224,11 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
bool continue_to_google_server,
const favicon_base::LargeIconImageResult& result) {
if (!result.image.IsEmpty()) {
- callback.Run(result.image);
+ std::move(callback).Run(result.image);
// The icon is from cache if we haven't gone to Google server yet. The icon
// is freshly fetched, otherwise.
RecordFaviconFetchResult(continue_to_google_server
@@ -245,7 +246,7 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
// We cannot download from the server if there is some small icon in the
// cache (resulting in non-default background color) or if we already did
// so.
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
return;
}
@@ -269,7 +270,7 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled by settings."
policy_exception_justification: "Not implemented."
})");
@@ -280,23 +281,23 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
base::Bind(
&ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished,
base::Unretained(this), publisher_url, minimum_size_in_pixel,
- desired_size_in_pixel, callback));
+ desired_size_in_pixel, base::Passed(std::move(callback))));
}
void ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
favicon_base::GoogleFaviconServerRequestStatus status) {
if (status != favicon_base::GoogleFaviconServerRequestStatus::SUCCESS) {
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
RecordFaviconFetchResult(FaviconFetchResult::FAILURE);
return;
}
GetFaviconFromCache(publisher_url, minimum_size_in_pixel,
- desired_size_in_pixel, callback,
+ desired_size_in_pixel, std::move(callback),
/*continue_to_google_server=*/false);
}
@@ -336,12 +337,13 @@ void ContentSuggestionsService::ClearCachedSuggestions(Category category) {
void ContentSuggestionsService::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
auto iterator = providers_by_category_.find(category);
if (iterator != providers_by_category_.end()) {
- iterator->second->GetDismissedSuggestionsForDebugging(category, callback);
+ iterator->second->GetDismissedSuggestionsForDebugging(category,
+ std::move(callback));
} else {
- callback.Run(std::vector<ContentSuggestion>());
+ std::move(callback).Run(std::vector<ContentSuggestion>());
}
}
@@ -417,7 +419,7 @@ void ContentSuggestionsService::RegisterProvider(
void ContentSuggestionsService::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
auto providers_it = providers_by_category_.find(category);
if (providers_it == providers_by_category_.end()) {
return;
@@ -425,7 +427,8 @@ void ContentSuggestionsService::Fetch(
metrics::RecordFetchAction();
- providers_it->second->Fetch(category, known_suggestion_ids, callback);
+ providers_it->second->Fetch(category, known_suggestion_ids,
+ std::move(callback));
}
void ContentSuggestionsService::ReloadSuggestions() {
@@ -434,31 +437,11 @@ void ContentSuggestionsService::ReloadSuggestions() {
}
}
-void ContentSuggestionsService::SetRemoteSuggestionsEnabled(bool enabled) {
- // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
- // remove by M62.
- NOTREACHED();
-}
-
bool ContentSuggestionsService::AreRemoteSuggestionsEnabled() const {
return remote_suggestions_provider_ &&
!remote_suggestions_provider_->IsDisabled();
}
-bool ContentSuggestionsService::AreRemoteSuggestionsManaged() const {
- // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
- // remove by M62.
- NOTREACHED();
- return false;
-}
-
-bool ContentSuggestionsService::AreRemoteSuggestionsManagedByCustodian() const {
- // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
- // remove by M62.
- NOTREACHED();
- return false;
-}
-
////////////////////////////////////////////////////////////////////////////////
// Private methods
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
index de03d6b5cb0..e9d4991833a 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -20,6 +20,7 @@
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
#include "components/ntp_snippets/callbacks.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
@@ -138,7 +139,7 @@ class ContentSuggestionsService : public KeyedService,
// the callback gets an empty image. The callback will not be called
// synchronously.
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback);
+ ImageFetchedCallback callback);
// Fetches the favicon from local cache (if larger than or equal to
// |minimum_size_in_pixel|) or from Google server (if there is no icon in the
@@ -148,7 +149,7 @@ class ContentSuggestionsService : public KeyedService,
void FetchSuggestionFavicon(const ContentSuggestion::ID& suggestion_id,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback);
+ ImageFetchedCallback callback);
// Dismisses the suggestion with the given |suggestion_id|, if it exists.
// This will not trigger an update through the observers (i.e. providers must
@@ -173,7 +174,7 @@ class ContentSuggestionsService : public KeyedService,
// to get suggestions to just this async Fetch() API.
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback);
+ FetchDoneCallback callback);
// Reloads suggestions from all categories, from all providers. If a provider
// naturally has some ability to generate fresh suggestions, it may provide a
@@ -222,7 +223,7 @@ class ContentSuggestionsService : public KeyedService,
// empty vector. The callback may be called synchronously.
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback);
+ DismissedSuggestionsCallback callback);
// Only for debugging use through the internals page. Some providers
// internally store a list of dismissed suggestions to prevent them from
@@ -231,19 +232,9 @@ class ContentSuggestionsService : public KeyedService,
// supports it).
void ClearDismissedSuggestionsForDebugging(Category category);
- // Enables or disables the remote suggestions provider.
- void SetRemoteSuggestionsEnabled(bool enabled);
-
// Returns true if the remote suggestions provider is enabled.
bool AreRemoteSuggestionsEnabled() const;
- // Returns true if the remote provider is managed by an adminstrator's policy.
- bool AreRemoteSuggestionsManaged() const;
-
- // Returns true if the remote provider is managed by the guardian/parent of a
- // child account.
- bool AreRemoteSuggestionsManagedByCustodian() const;
-
// The reference to the RemoteSuggestionsProvider provider should
// only be set by the factory and only used for debugging.
// TODO(jkrcal) The way we deal with the circular dependency feels wrong.
@@ -334,7 +325,7 @@ class ContentSuggestionsService : public KeyedService,
void GetFaviconFromCache(const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
bool continue_to_google_server);
// Callbacks for fetching favicons.
@@ -342,14 +333,14 @@ class ContentSuggestionsService : public KeyedService,
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
bool continue_to_google_server,
const favicon_base::LargeIconImageResult& result);
void OnGetFaviconFromGoogleServerFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
favicon_base::GoogleFaviconServerRequestStatus status);
// Whether the content suggestions feature is enabled.
diff --git a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
index 9bd9fe94a85..aa5f66a055c 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -279,8 +279,8 @@ TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) {
CreateSuggestions(articles_category, {1}));
ContentSuggestion::ID suggestion_id(articles_category, "1");
- EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _));
- EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0);
+ EXPECT_CALL(*provider1, FetchSuggestionImageMock(suggestion_id, _));
+ EXPECT_CALL(*provider2, FetchSuggestionImageMock(_, _)).Times(0);
service()->FetchSuggestionImage(
suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched,
base::Unretained(this)));
@@ -649,7 +649,7 @@ TEST_F(ContentSuggestionsServiceTest, ShouldForwardFetch) {
MockContentSuggestionsProvider* provider =
MakeRegisteredMockProvider(category);
provider->FireCategoryStatusChangedWithCurrentStatus(category);
- EXPECT_CALL(*provider, Fetch(category, known_suggestions, _));
+ EXPECT_CALL(*provider, FetchMock(category, known_suggestions, _));
service()->Fetch(category, known_suggestions, FetchDoneCallback());
}
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
new file mode 100644
index 00000000000..4094976702f
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
@@ -0,0 +1,81 @@
+// 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/ntp_snippets/contextual/contextual_content_suggestions_service.h"
+
+#include <iterator>
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "components/ntp_snippets/remote/cached_image_fetcher.h"
+#include "components/ntp_snippets/remote/remote_suggestions_database.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
+#include "ui/gfx/image/image.h"
+
+namespace ntp_snippets {
+
+ContextualContentSuggestionsService::ContextualContentSuggestionsService(
+ std::unique_ptr<ContextualSuggestionsFetcher>
+ contextual_suggestions_fetcher,
+ std::unique_ptr<CachedImageFetcher> image_fetcher,
+ std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database)
+ : contextual_suggestions_database_(
+ std::move(contextual_suggestions_database)),
+ contextual_suggestions_fetcher_(
+ std::move(contextual_suggestions_fetcher)),
+ image_fetcher_(std::move(image_fetcher)) {}
+
+ContextualContentSuggestionsService::~ContextualContentSuggestionsService() =
+ default;
+
+void ContextualContentSuggestionsService::FetchContextualSuggestions(
+ const GURL& url,
+ FetchContextualSuggestionsCallback callback) {
+ contextual_suggestions_fetcher_->FetchContextualSuggestions(
+ url,
+ base::BindOnce(
+ &ContextualContentSuggestionsService::DidFetchContextualSuggestions,
+ base::Unretained(this), url, std::move(callback)));
+}
+
+void ContextualContentSuggestionsService::FetchContextualSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ ImageFetchedCallback callback) {
+ const std::string& id_within_category = suggestion_id.id_within_category();
+ auto image_url_iterator = image_url_by_id_.find(id_within_category);
+ if (image_url_iterator != image_url_by_id_.end()) {
+ GURL image_url = image_url_iterator->second;
+ image_fetcher_->FetchSuggestionImage(suggestion_id, image_url,
+ std::move(callback));
+ } else {
+ DVLOG(1) << "FetchContextualSuggestionImage unknown image"
+ << " id_within_category: " << id_within_category;
+ std::move(callback).Run(gfx::Image());
+ }
+}
+
+// TODO(gaschler): Cache contextual suggestions at run-time.
+void ContextualContentSuggestionsService::DidFetchContextualSuggestions(
+ const GURL& url,
+ FetchContextualSuggestionsCallback callback,
+ Status status,
+ ContextualSuggestionsFetcher::OptionalSuggestions fetched_suggestions) {
+ std::vector<ContentSuggestion> suggestions;
+ if (fetched_suggestions.has_value()) {
+ for (const std::unique_ptr<RemoteSuggestion>& suggestion :
+ fetched_suggestions.value()) {
+ suggestions.emplace_back(suggestion->ToContentSuggestion(
+ Category::FromKnownCategory(KnownCategories::CONTEXTUAL)));
+ ContentSuggestion::ID id = suggestions.back().id();
+ GURL image_url = suggestion->salient_image_url();
+ image_url_by_id_[id.id_within_category()] = image_url;
+ }
+ }
+ std::move(callback).Run(status, url, std::move(suggestions));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
new file mode 100644
index 00000000000..e24fa661c24
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
@@ -0,0 +1,76 @@
+// 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_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_CONTENT_SUGGESTIONS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_CONTENT_SUGGESTIONS_SERVICE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/ntp_snippets/callbacks.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
+
+namespace ntp_snippets {
+
+class CachedImageFetcher;
+class RemoteSuggestionsDatabase;
+
+// Retrieves contextual suggestions for a given URL and fetches images
+// for contextual suggestion, using caching.
+class ContextualContentSuggestionsService : public KeyedService {
+ public:
+ ContextualContentSuggestionsService(
+ std::unique_ptr<ContextualSuggestionsFetcher>
+ contextual_suggestions_fetcher,
+ std::unique_ptr<CachedImageFetcher> image_fetcher,
+ std::unique_ptr<RemoteSuggestionsDatabase>
+ contextual_suggestions_database);
+ ~ContextualContentSuggestionsService() override;
+
+ using FetchContextualSuggestionsCallback =
+ base::OnceCallback<void(Status status_code,
+ const GURL& url,
+ std::vector<ContentSuggestion> suggestions)>;
+
+ // Asynchronously fetches contextual suggestions for the given URL.
+ void FetchContextualSuggestions(const GURL& url,
+ FetchContextualSuggestionsCallback callback);
+
+ // Fetches an image for a given contextual suggestion ID.
+ // Asynchronous if cache or network is queried.
+ void FetchContextualSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ ImageFetchedCallback callback);
+
+ private:
+ void DidFetchContextualSuggestions(
+ const GURL& url,
+ FetchContextualSuggestionsCallback callback,
+ Status status,
+ ContextualSuggestionsFetcher::OptionalSuggestions fetched_suggestions);
+
+ // Cache for images of contextual suggestions, needed by CachedImageFetcher.
+ std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database_;
+
+ // Performs actual network request to fetch contextual suggestions.
+ std::unique_ptr<ContextualSuggestionsFetcher> contextual_suggestions_fetcher_;
+
+ std::unique_ptr<CachedImageFetcher> image_fetcher_;
+
+ // Look up by ContentSuggestion::ID::id_within_category() aka std::string to
+ // get image URL.
+ std::map<std::string, GURL> image_url_by_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualContentSuggestionsService);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_CONTENT_SUGGESTIONS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
new file mode 100644
index 00000000000..40e34c252a8
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
@@ -0,0 +1,244 @@
+// 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/ntp_snippets/contextual/contextual_content_suggestions_service.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/mock_callback.h"
+#include "components/image_fetcher/core/image_fetcher_impl.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
+#include "components/ntp_snippets/remote/cached_image_fetcher.h"
+#include "components/ntp_snippets/remote/json_to_categories.h"
+#include "components/ntp_snippets/remote/remote_suggestion.h"
+#include "components/ntp_snippets/remote/remote_suggestion_builder.h"
+#include "components/ntp_snippets/remote/remote_suggestions_database.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"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_unittest_util.h"
+
+using testing::_;
+using testing::AllOf;
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::Pointee;
+using testing::Property;
+
+namespace ntp_snippets {
+
+namespace {
+
+ACTION_TEMPLATE(MoveArg,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(out)) {
+ *out = std::move(*::testing::get<k>(args));
+};
+
+// Always fetches the result that was set by SetFakeResponse.
+class FakeContextualSuggestionsFetcher : public ContextualSuggestionsFetcher {
+ public:
+ void FetchContextualSuggestions(
+ const GURL& url,
+ SuggestionsAvailableCallback callback) override {
+ std::move(callback).Run(fake_status_, std::move(fake_suggestions_));
+ fake_suggestions_ = base::nullopt;
+ }
+
+ void SetFakeResponse(Status fake_status,
+ OptionalSuggestions fake_suggestions) {
+ fake_status_ = fake_status;
+ fake_suggestions_ = std::move(fake_suggestions);
+ }
+
+ const std::string& GetLastStatusForTesting() const override { return empty_; }
+ const std::string& GetLastJsonForTesting() const override { return empty_; }
+ const GURL& GetFetchUrlForTesting() const override { return empty_url_; }
+
+ private:
+ std::string empty_;
+ GURL empty_url_;
+ Status fake_status_ = Status::Success();
+ OptionalSuggestions fake_suggestions_;
+};
+
+// Always fetches a fake image if the given URL is valid.
+class FakeCachedImageFetcher : public CachedImageFetcher {
+ public:
+ FakeCachedImageFetcher(PrefService* pref_service)
+ : CachedImageFetcher(std::unique_ptr<image_fetcher::ImageFetcher>(),
+ pref_service,
+ nullptr){};
+
+ void FetchSuggestionImage(const ContentSuggestion::ID&,
+ const GURL& image_url,
+ ImageFetchedCallback callback) override {
+ gfx::Image image;
+ if (image_url.is_valid()) {
+ image = gfx::test::CreateImage();
+ }
+ std::move(callback).Run(image);
+ }
+};
+
+// GMock does not support movable-only types (ContentSuggestion).
+// Instead WrappedRun is used as callback and it redirects the call to a
+// method without movable-only types, which is then mocked.
+class MockFetchContextualSuggestionsCallback {
+ public:
+ void WrappedRun(Status status,
+ const GURL& url,
+ std::vector<ContentSuggestion> suggestions) {
+ Run(status, url, &suggestions);
+ }
+
+ ContextualContentSuggestionsService::FetchContextualSuggestionsCallback
+ ToOnceCallback() {
+ return base::BindOnce(&MockFetchContextualSuggestionsCallback::WrappedRun,
+ base::Unretained(this));
+ }
+
+ MOCK_METHOD3(Run,
+ void(Status status_code,
+ const GURL& url,
+ std::vector<ContentSuggestion>* suggestions));
+};
+
+} // namespace
+
+class ContextualContentSuggestionsServiceTest : public testing::Test {
+ public:
+ ContextualContentSuggestionsServiceTest() {
+ RequestThrottler::RegisterProfilePrefs(pref_service_.registry());
+ std::unique_ptr<FakeContextualSuggestionsFetcher> fetcher =
+ base::MakeUnique<FakeContextualSuggestionsFetcher>();
+ fetcher_ = fetcher.get();
+ source_ = base::MakeUnique<ContextualContentSuggestionsService>(
+ std::move(fetcher),
+ base::MakeUnique<FakeCachedImageFetcher>(&pref_service_),
+ std::unique_ptr<RemoteSuggestionsDatabase>());
+ }
+
+ FakeContextualSuggestionsFetcher* fetcher() { return fetcher_; }
+ ContextualContentSuggestionsService* source() { return source_.get(); }
+
+ private:
+ FakeContextualSuggestionsFetcher* fetcher_;
+ base::MessageLoop message_loop_;
+ TestingPrefServiceSimple pref_service_;
+ std::unique_ptr<ContextualContentSuggestionsService> source_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualContentSuggestionsServiceTest);
+};
+
+TEST_F(ContextualContentSuggestionsServiceTest,
+ ShouldFetchContextualSuggestion) {
+ MockFetchContextualSuggestionsCallback mock_suggestions_callback;
+ const std::string kValidFromUrl = "http://some.url";
+ const std::string kToUrl = "http://another.url";
+ ContextualSuggestionsFetcher::OptionalSuggestions remote_suggestions =
+ RemoteSuggestion::PtrVector();
+ remote_suggestions->push_back(test::RemoteSuggestionBuilder()
+ .AddId(kToUrl)
+ .SetUrl(kToUrl)
+ .SetAmpUrl(kToUrl)
+ .Build());
+ fetcher()->SetFakeResponse(Status::Success(), std::move(remote_suggestions));
+ EXPECT_CALL(mock_suggestions_callback,
+ Run(Property(&Status::IsSuccess, true), GURL(kValidFromUrl),
+ Pointee(ElementsAre(AllOf(
+ Property(&ContentSuggestion::id,
+ Property(&ContentSuggestion::ID::category,
+ Category::FromKnownCategory(
+ KnownCategories::CONTEXTUAL))),
+ Property(&ContentSuggestion::url, GURL(kToUrl)))))));
+ source()->FetchContextualSuggestions(
+ GURL(kValidFromUrl), mock_suggestions_callback.ToOnceCallback());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ContextualContentSuggestionsServiceTest,
+ ShouldRunCallbackOnEmptyResults) {
+ MockFetchContextualSuggestionsCallback mock_suggestions_callback;
+ const std::string kEmpty;
+ fetcher()->SetFakeResponse(Status::Success(), RemoteSuggestion::PtrVector());
+ EXPECT_CALL(mock_suggestions_callback, Run(Property(&Status::IsSuccess, true),
+ GURL(kEmpty), Pointee(IsEmpty())));
+ source()->FetchContextualSuggestions(
+ GURL(kEmpty), mock_suggestions_callback.ToOnceCallback());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ContextualContentSuggestionsServiceTest, ShouldRunCallbackOnError) {
+ MockFetchContextualSuggestionsCallback mock_suggestions_callback;
+ const std::string kEmpty;
+ fetcher()->SetFakeResponse(Status(StatusCode::TEMPORARY_ERROR, ""),
+ RemoteSuggestion::PtrVector());
+ EXPECT_CALL(mock_suggestions_callback,
+ Run(Property(&Status::IsSuccess, false), GURL(kEmpty),
+ Pointee(IsEmpty())));
+ source()->FetchContextualSuggestions(
+ GURL(kEmpty), mock_suggestions_callback.ToOnceCallback());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ContextualContentSuggestionsServiceTest,
+ ShouldFetchEmptyImageIfNotFound) {
+ base::MockCallback<ImageFetchedCallback> mock_image_fetched_callback;
+ const std::string kEmpty;
+ ContentSuggestion::ID id(
+ Category::FromKnownCategory(KnownCategories::CONTEXTUAL), kEmpty);
+ EXPECT_CALL(mock_image_fetched_callback,
+ Run(Property(&gfx::Image::IsEmpty, true)));
+ source()->FetchContextualSuggestionImage(id,
+ mock_image_fetched_callback.Get());
+ // TODO(gaschler): Verify with a mock that the image fetcher is not called if
+ // the id is unknown.
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ContextualContentSuggestionsServiceTest,
+ ShouldFetchImageForPreviouslyFetchedSuggestion) {
+ const std::string kValidFromUrl = "http://some.url";
+ const std::string kToUrl = "http://another.url";
+ const std::string kValidImageUrl = "http://some.url/image.png";
+ ContextualSuggestionsFetcher::OptionalSuggestions remote_suggestions =
+ RemoteSuggestion::PtrVector();
+ remote_suggestions->push_back(test::RemoteSuggestionBuilder()
+ .AddId(kToUrl)
+ .SetUrl(kToUrl)
+ .SetAmpUrl(kToUrl)
+ .SetImageUrl(kValidImageUrl)
+ .Build());
+ fetcher()->SetFakeResponse(Status::Success(), std::move(remote_suggestions));
+ MockFetchContextualSuggestionsCallback mock_suggestions_callback;
+ std::vector<ContentSuggestion> suggestions;
+ EXPECT_CALL(mock_suggestions_callback, Run(_, _, _))
+ .WillOnce(MoveArg<2>(&suggestions));
+ source()->FetchContextualSuggestions(
+ GURL(kValidFromUrl), mock_suggestions_callback.ToOnceCallback());
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_THAT(suggestions, Not(IsEmpty()));
+ base::MockCallback<ImageFetchedCallback> mock_image_fetched_callback;
+ EXPECT_CALL(mock_image_fetched_callback,
+ Run(Property(&gfx::Image::IsEmpty, false)));
+ source()->FetchContextualSuggestionImage(suggestions[0].id(),
+ mock_image_fetched_callback.Get());
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/contextual_json_request.cc b/chromium/components/ntp_snippets/contextual/contextual_json_request.cc
index fa1d6a66e44..2aba9e5f150 100644
--- a/chromium/components/ntp_snippets/remote/contextual_json_request.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_json_request.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/ntp_snippets/remote/contextual_json_request.h"
+#include "components/ntp_snippets/contextual/contextual_json_request.h"
#include <algorithm>
#include <utility>
@@ -208,7 +208,8 @@ ContextualJsonRequest::Builder::BuildURLFetcher(
const std::string& headers,
const std::string& body) const {
net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("ntp_snippets_fetch", R"(
+ net::DefineNetworkTrafficAnnotation("ntp_contextual_suggestions_fetch",
+ R"(
semantics {
sender: "New Tab Page Contextual Suggestions Fetch"
description:
@@ -217,16 +218,20 @@ ContextualJsonRequest::Builder::BuildURLFetcher(
trigger:
"Triggered when Home sheet is pulled up."
data:
- "The Chromium UI language, as well as a second language the user "
- "understands, based on translate::LanguageModel. For signed-in "
- "users, the requests is authenticated."
+ "Only for a white-listed signed-in test user, the URL of the "
+ "current tab."
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"This feature can be disabled by the flag "
"contextual-suggestions-carousel."
+ chrome_policy {
+ NTPContentSuggestionsEnabled {
+ NTPContentSuggestionsEnabled: False
+ }
+ }
})");
std::unique_ptr<net::URLFetcher> url_fetcher = net::URLFetcher::Create(
url_, net::URLFetcher::POST, delegate, traffic_annotation);
diff --git a/chromium/components/ntp_snippets/remote/contextual_json_request.h b/chromium/components/ntp_snippets/contextual/contextual_json_request.h
index cf379da180c..989880511da 100644
--- a/chromium/components/ntp_snippets/remote/contextual_json_request.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_json_request.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_NTP_SNIPPETS_REMOTE_CONTEXTUAL_JSON_REQUEST_H_
-#define COMPONENTS_NTP_SNIPPETS_REMOTE_CONTEXTUAL_JSON_REQUEST_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_JSON_REQUEST_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_JSON_REQUEST_H_
#include <memory>
#include <string>
@@ -112,4 +112,4 @@ class ContextualJsonRequest : public net::URLFetcherDelegate {
} // namespace ntp_snippets
-#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_CONTEXTUAL_JSON_REQUEST_H_
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_JSON_REQUEST_H_
diff --git a/chromium/components/ntp_snippets/remote/contextual_json_request_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_json_request_unittest.cc
index 9e8f1ddf11c..d501dd15656 100644
--- a/chromium/components/ntp_snippets/remote/contextual_json_request_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_json_request_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/ntp_snippets/remote/contextual_json_request.h"
+#include "components/ntp_snippets/contextual/contextual_json_request.h"
#include <utility>
@@ -42,7 +42,7 @@ MATCHER_P(EqualsJSON, json, "equals JSON") {
<< "parse error: " << err_msg;
return false;
}
- return base::Value::Equals(actual.get(), expected.get());
+ return *expected == *actual;
}
} // namespace
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h
new file mode 100644
index 00000000000..fb5794f18ac
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h
@@ -0,0 +1,44 @@
+// 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_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/remote/remote_suggestion.h"
+#include "components/ntp_snippets/status.h"
+
+namespace ntp_snippets {
+
+// Fetches contextual suggestions from the server.
+class ContextualSuggestionsFetcher {
+ public:
+ using OptionalSuggestions = base::Optional<RemoteSuggestion::PtrVector>;
+
+ // If fetching fails, the optional will be empty.
+ using SuggestionsAvailableCallback =
+ base::OnceCallback<void(Status status,
+ OptionalSuggestions fetched_suggestions)>;
+
+ virtual ~ContextualSuggestionsFetcher() = default;
+
+ virtual void FetchContextualSuggestions(
+ const GURL& url,
+ SuggestionsAvailableCallback callback) = 0;
+
+ virtual const std::string& GetLastStatusForTesting() const = 0;
+ virtual const std::string& GetLastJsonForTesting() const = 0;
+ virtual const GURL& GetFetchUrlForTesting() const = 0;
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
new file mode 100644
index 00000000000..dcf9d84eca7
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
@@ -0,0 +1,305 @@
+// 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/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/ntp_snippets/category.h"
+#include "components/signin/core/browser/access_token_fetcher.h"
+#include "components/strings/grit/components_strings.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using net::HttpRequestHeaders;
+using net::URLFetcher;
+using net::URLRequestContextGetter;
+
+namespace ntp_snippets {
+
+using internal::ContextualJsonRequest;
+using internal::FetchResult;
+
+namespace {
+
+const char kContentSuggestionsApiScope[] =
+ "https://www.googleapis.com/auth/chrome-content-suggestions";
+const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
+
+std::string FetchResultToString(FetchResult result) {
+ switch (result) {
+ case FetchResult::SUCCESS:
+ return "OK";
+ case FetchResult::URL_REQUEST_STATUS_ERROR:
+ return "URLRequestStatus error";
+ case FetchResult::HTTP_ERROR:
+ return "HTTP error";
+ case FetchResult::JSON_PARSE_ERROR:
+ return "Received invalid JSON";
+ case FetchResult::INVALID_SNIPPET_CONTENT_ERROR:
+ return "Invalid / empty list.";
+ case FetchResult::OAUTH_TOKEN_ERROR:
+ return "Error in obtaining an OAuth2 access token.";
+ case FetchResult::MISSING_API_KEY:
+ return "No API key available.";
+ case FetchResult::RESULT_MAX:
+ break;
+ }
+ NOTREACHED();
+ return "Unknown error";
+}
+
+Status FetchResultToStatus(FetchResult result) {
+ switch (result) {
+ case FetchResult::SUCCESS:
+ return Status::Success();
+ // Permanent errors occur if it is more likely that the error originated
+ // from the client.
+ case FetchResult::OAUTH_TOKEN_ERROR:
+ case FetchResult::MISSING_API_KEY:
+ return Status(StatusCode::PERMANENT_ERROR, FetchResultToString(result));
+ // Temporary errors occur if it's more likely that the client behaved
+ // correctly but the server failed to respond as expected.
+ // TODO(fhorschig): Revisit HTTP_ERROR once the rescheduling was reworked.
+ case FetchResult::HTTP_ERROR:
+ case FetchResult::URL_REQUEST_STATUS_ERROR:
+ case FetchResult::INVALID_SNIPPET_CONTENT_ERROR:
+ case FetchResult::JSON_PARSE_ERROR:
+ return Status(StatusCode::TEMPORARY_ERROR, FetchResultToString(result));
+ case FetchResult::RESULT_MAX:
+ break;
+ }
+ NOTREACHED();
+ return Status(StatusCode::PERMANENT_ERROR, std::string());
+}
+
+std::string GetFetchEndpoint() {
+ return "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com/v1"
+ "/publicdebate"
+ "/getsuggestions";
+}
+
+// Creates suggestions from dictionary values in |list| and adds them to
+// |suggestions|. Returns true on success, false if anything went wrong.
+bool AddSuggestionsFromListValue(bool content_suggestions_api,
+ const base::ListValue& list,
+ RemoteSuggestion::PtrVector* suggestions) {
+ for (const auto& value : list) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!value.GetAsDictionary(&dict)) {
+ return false;
+ }
+
+ std::string s;
+ dict->GetAsString(&s);
+ DVLOG(1) << "AddSuggestionsFromListValue " << s;
+ std::unique_ptr<RemoteSuggestion> suggestion =
+ RemoteSuggestion::CreateFromContextualSuggestionsDictionary(*dict);
+ suggestions->push_back(std::move(suggestion));
+ }
+ return true;
+}
+
+} // namespace
+
+ContextualSuggestionsFetcherImpl::ContextualSuggestionsFetcherImpl(
+ SigninManagerBase* signin_manager,
+ OAuth2TokenService* token_service,
+ scoped_refptr<URLRequestContextGetter> url_request_context_getter,
+ PrefService* pref_service,
+ const ParseJSONCallback& parse_json_callback)
+ : signin_manager_(signin_manager),
+ token_service_(token_service),
+ url_request_context_getter_(std::move(url_request_context_getter)),
+ parse_json_callback_(parse_json_callback),
+ fetch_url_(GetFetchEndpoint()) {}
+
+ContextualSuggestionsFetcherImpl::~ContextualSuggestionsFetcherImpl() = default;
+
+const std::string& ContextualSuggestionsFetcherImpl::GetLastStatusForTesting()
+ const {
+ return last_status_;
+}
+const std::string& ContextualSuggestionsFetcherImpl::GetLastJsonForTesting()
+ const {
+ return last_fetch_json_;
+}
+const GURL& ContextualSuggestionsFetcherImpl::GetFetchUrlForTesting() const {
+ return fetch_url_;
+}
+
+void ContextualSuggestionsFetcherImpl::FetchContextualSuggestions(
+ const GURL& url,
+ SuggestionsAvailableCallback callback) {
+ ContextualJsonRequest::Builder builder;
+ builder.SetParseJsonCallback(parse_json_callback_)
+ .SetUrlRequestContextGetter(url_request_context_getter_)
+ .SetContentUrl(url);
+
+ pending_requests_.emplace(std::move(builder), std::move(callback));
+ StartTokenRequest();
+}
+
+void ContextualSuggestionsFetcherImpl::StartRequest(
+ ContextualJsonRequest::Builder builder,
+ SuggestionsAvailableCallback callback,
+ const std::string& oauth_access_token) {
+ builder.SetUrl(fetch_url_)
+ .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
+ base::StringPrintf(kAuthorizationRequestHeaderFormat,
+ oauth_access_token.c_str()));
+ DVLOG(1) << "ContextualSuggestionsFetcherImpl::StartRequest";
+ std::unique_ptr<ContextualJsonRequest> request = builder.Build();
+ ContextualJsonRequest* raw_request = request.get();
+ raw_request->Start(base::BindOnce(
+ &ContextualSuggestionsFetcherImpl::JsonRequestDone,
+ base::Unretained(this), std::move(request), std::move(callback)));
+}
+
+void ContextualSuggestionsFetcherImpl::StartTokenRequest() {
+ // If there is already an ongoing token request, just wait for that.
+ if (token_fetcher_) {
+ return;
+ }
+
+ OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
+ token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
+ "ntp_snippets", signin_manager_, token_service_, scopes,
+ base::BindOnce(
+ &ContextualSuggestionsFetcherImpl::AccessTokenFetchFinished,
+ base::Unretained(this)));
+}
+
+void ContextualSuggestionsFetcherImpl::AccessTokenFetchFinished(
+ const GoogleServiceAuthError& error,
+ const std::string& access_token) {
+ // Delete the fetcher only after we leave this method (which is called from
+ // the fetcher itself).
+ DCHECK(token_fetcher_);
+ std::unique_ptr<AccessTokenFetcher> token_fetcher_deleter(
+ std::move(token_fetcher_));
+
+ if (error.state() != GoogleServiceAuthError::NONE) {
+ AccessTokenError(error);
+ return;
+ }
+
+ DCHECK(!access_token.empty());
+
+ while (!pending_requests_.empty()) {
+ std::pair<ContextualJsonRequest::Builder, SuggestionsAvailableCallback>
+ builder_and_callback = std::move(pending_requests_.front());
+ pending_requests_.pop();
+ StartRequest(std::move(builder_and_callback.first),
+ std::move(builder_and_callback.second), access_token);
+ }
+}
+
+void ContextualSuggestionsFetcherImpl::AccessTokenError(
+ const GoogleServiceAuthError& error) {
+ DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
+
+ LOG(WARNING) << "ContextualSuggestionsFetcherImpl::AccessTokenError "
+ "Unable to get token: "
+ << error.ToString();
+
+ while (!pending_requests_.empty()) {
+ std::pair<ContextualJsonRequest::Builder, SuggestionsAvailableCallback>
+ builder_and_callback = std::move(pending_requests_.front());
+
+ FetchFinished(OptionalSuggestions(), std::move(builder_and_callback.second),
+ FetchResult::OAUTH_TOKEN_ERROR,
+ /*error_details=*/
+ base::StringPrintf(" (%s)", error.ToString().c_str()));
+ pending_requests_.pop();
+ }
+}
+
+void ContextualSuggestionsFetcherImpl::JsonRequestDone(
+ std::unique_ptr<ContextualJsonRequest> request,
+ SuggestionsAvailableCallback callback,
+ std::unique_ptr<base::Value> result,
+ FetchResult status_code,
+ const std::string& error_details) {
+ DCHECK(request);
+
+ DVLOG(1) << "ContextualSuggestionsFetcherImpl::JsonRequestDone status_code="
+ << static_cast<int>(status_code)
+ << " error_details=" << error_details;
+ last_fetch_json_ = request->GetResponseString();
+
+ // TODO(gaschler): Add UMA metrics for fetch duration of the request
+
+ if (!result) {
+ FetchFinished(OptionalSuggestions(), std::move(callback), status_code,
+ error_details);
+ return;
+ }
+
+ OptionalSuggestions optional_suggestions = RemoteSuggestion::PtrVector();
+ if (!JsonToSuggestions(*result, &optional_suggestions.value())) {
+ DLOG(WARNING) << "Received invalid suggestions: " << last_fetch_json_;
+ FetchFinished(OptionalSuggestions(), std::move(callback),
+ FetchResult::INVALID_SNIPPET_CONTENT_ERROR, std::string());
+ return;
+ }
+
+ FetchFinished(std::move(optional_suggestions), std::move(callback),
+ FetchResult::SUCCESS, std::string());
+}
+
+void ContextualSuggestionsFetcherImpl::FetchFinished(
+ OptionalSuggestions optional_suggestions,
+ SuggestionsAvailableCallback callback,
+ FetchResult fetch_result,
+ const std::string& error_details) {
+ DCHECK(fetch_result == FetchResult::SUCCESS ||
+ !optional_suggestions.has_value());
+
+ last_status_ = FetchResultToString(fetch_result) + error_details;
+
+ DVLOG(1) << "Fetch finished: " << last_status_;
+
+ std::move(callback).Run(FetchResultToStatus(fetch_result),
+ std::move(optional_suggestions));
+}
+
+bool ContextualSuggestionsFetcherImpl::JsonToSuggestions(
+ const base::Value& parsed,
+ RemoteSuggestion::PtrVector* suggestions) {
+ const base::DictionaryValue* top_dict = nullptr;
+ if (!parsed.GetAsDictionary(&top_dict)) {
+ return false;
+ }
+
+ const base::ListValue* categories_value = nullptr;
+ if (!top_dict->GetList("categories", &categories_value)) {
+ return false;
+ }
+
+ for (const auto& v : *categories_value) {
+ const base::DictionaryValue* category_value = nullptr;
+ if (!(v.GetAsDictionary(&category_value))) {
+ return false;
+ }
+
+ const base::ListValue* suggestions_list = nullptr;
+ // Absence of a list of suggestions is treated as an empty list, which
+ // is permissible.
+ if (category_value->GetList("suggestions", &suggestions_list)) {
+ if (!AddSuggestionsFromListValue(true, *suggestions_list, suggestions)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
new file mode 100644
index 00000000000..d0c9f1d9f9f
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
@@ -0,0 +1,104 @@
+// 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_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_IMPL_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_IMPL_H_
+
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/time/clock.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/contextual/contextual_json_request.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
+#include "components/ntp_snippets/remote/remote_suggestion.h"
+#include "components/ntp_snippets/status.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class AccessTokenFetcher;
+class OAuth2TokenService;
+class PrefService;
+class SigninManagerBase;
+
+namespace ntp_snippets {
+
+// TODO(gaschler): Move authentication that is in common with
+// RemoteSuggestionsFetcher to a helper class.
+class ContextualSuggestionsFetcherImpl : public ContextualSuggestionsFetcher {
+ public:
+ ContextualSuggestionsFetcherImpl(
+ SigninManagerBase* signin_manager,
+ OAuth2TokenService* token_service,
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+ PrefService* pref_service,
+ const ParseJSONCallback& parse_json_callback);
+ ~ContextualSuggestionsFetcherImpl() override;
+
+ // ContextualSuggestionsFetcher implementation.
+ void FetchContextualSuggestions(
+ const GURL& url,
+ SuggestionsAvailableCallback callback) override;
+
+ const std::string& GetLastStatusForTesting() const override;
+ const std::string& GetLastJsonForTesting() const override;
+ const GURL& GetFetchUrlForTesting() const override;
+
+ private:
+ void StartRequest(internal::ContextualJsonRequest::Builder builder,
+ SuggestionsAvailableCallback callback,
+ const std::string& oauth_access_token);
+
+ void StartTokenRequest();
+
+ void AccessTokenFetchFinished(const GoogleServiceAuthError& error,
+ const std::string& access_token);
+ void AccessTokenError(const GoogleServiceAuthError& error);
+
+ void JsonRequestDone(std::unique_ptr<internal::ContextualJsonRequest> request,
+ SuggestionsAvailableCallback callback,
+ std::unique_ptr<base::Value> result,
+ internal::FetchResult status_code,
+ const std::string& error_details);
+ void FetchFinished(OptionalSuggestions optional_suggestions,
+ SuggestionsAvailableCallback callback,
+ internal::FetchResult status_code,
+ const std::string& error_details);
+
+ bool JsonToSuggestions(const base::Value& parsed,
+ RemoteSuggestion::PtrVector* suggestions);
+
+ // Authentication for signed-in users.
+ SigninManagerBase* signin_manager_;
+ OAuth2TokenService* token_service_;
+
+ std::unique_ptr<AccessTokenFetcher> token_fetcher_;
+
+ // Holds the URL request context.
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
+ // Stores requests that wait for an access token.
+ std::queue<std::pair<internal::ContextualJsonRequest::Builder,
+ SuggestionsAvailableCallback>>
+ pending_requests_;
+
+ const ParseJSONCallback parse_json_callback_;
+
+ // API endpoint for fetching contextual suggestions.
+ const GURL fetch_url_;
+
+ // Info on the last finished fetch.
+ std::string last_status_;
+ std::string last_fetch_json_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsFetcherImpl);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_IMPL_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
new file mode 100644
index 00000000000..0fed25d641b
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
@@ -0,0 +1,267 @@
+// 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/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/remote/test_utils.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+using testing::_;
+using testing::AllOf;
+using testing::Eq;
+using testing::Field;
+using testing::IsEmpty;
+using testing::Property;
+using testing::StartsWith;
+
+const char kTestEmail[] = "foo@bar.com";
+const char kValidURL[] = "http://valid-url.test";
+
+MATCHER(IsEmptySuggestionsList, "is an empty list of suggestions") {
+ ContextualSuggestionsFetcher::OptionalSuggestions& optional_suggestions =
+ *arg;
+ if (!optional_suggestions) {
+ *result_listener << "expected a suggestion list.";
+ return false;
+ }
+ if (optional_suggestions->size() != 0) {
+ *result_listener << "expected empty suggestions, got: "
+ << optional_suggestions->size();
+ return false;
+ }
+ return true;
+}
+
+MATCHER_P(IsSingleSuggestion,
+ url,
+ "is a list with the single suggestion %(url)s") {
+ ContextualSuggestionsFetcher::OptionalSuggestions& optional_suggestions =
+ *arg;
+ if (!optional_suggestions) {
+ *result_listener << "expected a suggestion list.";
+ return false;
+ }
+ if (optional_suggestions->size() != 1) {
+ *result_listener << "expected single suggestion, got: "
+ << optional_suggestions->size();
+ return false;
+ }
+ if (optional_suggestions.value()[0]->url().spec() != url) {
+ *result_listener << "unexpected url, got: "
+ << optional_suggestions.value()[0]->url().spec();
+ return false;
+ }
+ return true;
+}
+
+class MockSuggestionsAvailableCallback {
+ public:
+ // Workaround for gMock's lack of support for movable arguments.
+ void WrappedRun(
+ Status status,
+ ContextualSuggestionsFetcher::OptionalSuggestions optional_suggestions) {
+ Run(status, &optional_suggestions);
+ }
+
+ MOCK_METHOD2(Run,
+ void(Status status,
+ ContextualSuggestionsFetcher::OptionalSuggestions*
+ optional_suggestions));
+};
+
+void ParseJson(const std::string& json,
+ const SuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ base::JSONReader json_reader;
+ std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
+ if (value) {
+ success_callback.Run(std::move(value));
+ } else {
+ error_callback.Run(json_reader.GetErrorMessage());
+ }
+}
+
+} // namespace
+
+class ContextualSuggestionsFetcherTest : public testing::Test {
+ public:
+ ContextualSuggestionsFetcherTest()
+ : fake_url_fetcher_factory_(new net::FakeURLFetcherFactory(nullptr)),
+ mock_task_runner_(new base::TestMockTimeTaskRunner()),
+ mock_task_runner_handle_(mock_task_runner_) {
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
+ new net::TestURLRequestContextGetter(mock_task_runner_.get());
+ fake_token_service_ = base::MakeUnique<FakeProfileOAuth2TokenService>(
+ base::MakeUnique<FakeOAuth2TokenServiceDelegate>(
+ request_context_getter.get()));
+ fetcher_ = base::MakeUnique<ContextualSuggestionsFetcherImpl>(
+ test_utils_.fake_signin_manager(), fake_token_service_.get(),
+ std::move(request_context_getter), test_utils_.pref_service(),
+ base::Bind(&ParseJson));
+ }
+
+ void FastForwardUntilNoTasksRemain() {
+ mock_task_runner_->FastForwardUntilNoTasksRemain();
+ }
+
+ void InitializeFakeCredentials() {
+#if defined(OS_CHROMEOS)
+ test_utils_.fake_signin_manager()->SignIn(kTestEmail);
+#else
+ test_utils_.fake_signin_manager()->SignIn(kTestEmail, "user", "password");
+#endif
+ fake_token_service_->GetDelegate()->UpdateCredentials(kTestEmail, "token");
+ }
+
+ void IssueOAuth2Token() {
+ fake_token_service_->IssueAllTokensForAccount(kTestEmail, "access_token",
+ base::Time::Max());
+ }
+
+ void SetFakeResponse(const std::string& response_data,
+ net::HttpStatusCode response_code,
+ net::URLRequestStatus::Status status) {
+ fake_url_fetcher_factory_->SetFakeResponse(
+ fetcher_->GetFetchUrlForTesting(), response_data, response_code,
+ status);
+ }
+
+ ContextualSuggestionsFetcher::SuggestionsAvailableCallback
+ ToSuggestionsAvailableCallback(MockSuggestionsAvailableCallback* callback) {
+ return base::BindOnce(&MockSuggestionsAvailableCallback::WrappedRun,
+ base::Unretained(callback));
+ }
+
+ ContextualSuggestionsFetcher& fetcher() { return *fetcher_; }
+ MockSuggestionsAvailableCallback& mock_suggestions_available_callback() {
+ return mock_suggestions_available_callback_;
+ }
+
+ private:
+ std::unique_ptr<FakeProfileOAuth2TokenService> fake_token_service_;
+ std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
+ std::unique_ptr<ContextualSuggestionsFetcherImpl> fetcher_;
+ MockSuggestionsAvailableCallback mock_suggestions_available_callback_;
+ scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
+ base::ThreadTaskRunnerHandle mock_task_runner_handle_;
+ test::RemoteSuggestionsTestUtils test_utils_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsFetcherTest);
+};
+
+TEST_F(ContextualSuggestionsFetcherTest, ShouldCreateFetcher) {
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(fetcher().GetLastStatusForTesting(), IsEmpty());
+}
+
+TEST_F(ContextualSuggestionsFetcherTest, ShouldFetchSuggestion) {
+ InitializeFakeCredentials();
+ const std::string kValidResponseData =
+ "{\"categories\" : [{"
+ " \"id\": 0,"
+ " \"suggestions\" : [{"
+ " \"title\" : \"Title\","
+ " \"summary\" : \"...\","
+ " \"url\" : \"http://localhost/foobar\","
+ " \"imageUrl\" : \"http://localhost/foobar.jpg\""
+ " }]"
+ "}]}";
+ SetFakeResponse(/*response_data=*/kValidResponseData, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_suggestions_available_callback(),
+ Run(Property(&Status::IsSuccess, true),
+ IsSingleSuggestion("http://localhost/foobar")));
+
+ fetcher().FetchContextualSuggestions(
+ GURL(kValidURL),
+ ToSuggestionsAvailableCallback(&mock_suggestions_available_callback()));
+ IssueOAuth2Token();
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(fetcher().GetLastStatusForTesting(), Eq("OK"));
+ EXPECT_THAT(fetcher().GetLastJsonForTesting(), Eq(kValidResponseData));
+}
+
+TEST_F(ContextualSuggestionsFetcherTest, ShouldFetchEmptySuggestionsList) {
+ InitializeFakeCredentials();
+ const std::string kValidEmptyCategoryResponseData =
+ "{\"categories\" : [{"
+ " \"id\": 0,"
+ " \"suggestions\": []"
+ "}]}";
+ SetFakeResponse(/*response_data=*/kValidEmptyCategoryResponseData,
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_suggestions_available_callback(),
+ Run(Property(&Status::IsSuccess, true),
+ /*fetched_categories=*/IsEmptySuggestionsList()));
+
+ fetcher().FetchContextualSuggestions(
+ GURL(kValidURL),
+ ToSuggestionsAvailableCallback(&mock_suggestions_available_callback()));
+ IssueOAuth2Token();
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(fetcher().GetLastStatusForTesting(), Eq("OK"));
+ EXPECT_THAT(fetcher().GetLastJsonForTesting(),
+ Eq(kValidEmptyCategoryResponseData));
+}
+
+TEST_F(ContextualSuggestionsFetcherTest,
+ ShouldReportErrorForEmptyResponseData) {
+ InitializeFakeCredentials();
+ SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_suggestions_available_callback(),
+ Run(Property(&Status::IsSuccess, false), _));
+
+ fetcher().FetchContextualSuggestions(
+ GURL(kValidURL),
+ ToSuggestionsAvailableCallback(&mock_suggestions_available_callback()));
+ IssueOAuth2Token();
+ FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(ContextualSuggestionsFetcherTest,
+ ShouldReportErrorForInvalidResponseData) {
+ InitializeFakeCredentials();
+ const std::string kInvalidResponseData = "{ \"recos\": []";
+ SetFakeResponse(/*response_data=*/kInvalidResponseData, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(
+ mock_suggestions_available_callback(),
+ Run(Field(&Status::code, StatusCode::TEMPORARY_ERROR),
+ /*fetched_categories=*/Property(
+ &ContextualSuggestionsFetcher::OptionalSuggestions::has_value,
+ false)));
+
+ fetcher().FetchContextualSuggestions(
+ GURL(kValidURL),
+ ToSuggestionsAvailableCallback(&mock_suggestions_available_callback()));
+ IssueOAuth2Token();
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(fetcher().GetLastStatusForTesting(),
+ StartsWith("Received invalid JSON (error "));
+ EXPECT_THAT(fetcher().GetLastJsonForTesting(), Eq(kInvalidResponseData));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/fake_content_suggestions_provider_observer.h b/chromium/components/ntp_snippets/fake_content_suggestions_provider_observer.h
index 60ff2bf48a6..5617664b72d 100644
--- a/chromium/components/ntp_snippets/fake_content_suggestions_provider_observer.h
+++ b/chromium/components/ntp_snippets/fake_content_suggestions_provider_observer.h
@@ -15,7 +15,7 @@
namespace ntp_snippets {
-class FakeContentSuggestionsProviderObserver
+class FakeContentSuggestionsProviderObserver final
: public ContentSuggestionsProvider::Observer {
public:
FakeContentSuggestionsProviderObserver();
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
index f32adff9f4b..4470c5967ef 100644
--- a/chromium/components/ntp_snippets/features.cc
+++ b/chromium/components/ntp_snippets/features.cc
@@ -13,20 +13,28 @@
namespace ntp_snippets {
+// Holds an experiment ID. So long as the feature is set through a server-side
+// variations config, this feature should exist on the client. This ensures that
+// the experiment ID is visible in chrome://snippets-internals.
+const base::Feature kRemoteSuggestionsBackendFeature{
+ "NTPRemoteSuggestionsBackend", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Keep sorted, and keep nullptr at the end.
-const base::Feature*(kAllFeatures[]) = {&kArticleSuggestionsFeature,
- &kBookmarkSuggestionsFeature,
- &kCategoryOrder,
- &kCategoryRanker,
- &kBreakingNewsPushFeature,
- &kForeignSessionsSuggestionsFeature,
- &kIncreasedVisibility,
- &kKeepPrefetchedContentSuggestions,
- &kNotificationsFeature,
- &kPhysicalWebPageSuggestionsFeature,
- &kPublisherFaviconsFromNewServerFeature,
- &kRecentOfflineTabSuggestionsFeature,
- nullptr};
+const base::Feature* const kAllFeatures[] = {
+ &kArticleSuggestionsFeature,
+ &kBookmarkSuggestionsFeature,
+ &kBreakingNewsPushFeature,
+ &kCategoryOrder,
+ &kCategoryRanker,
+ &kForeignSessionsSuggestionsFeature,
+ &kIncreasedVisibility,
+ &kKeepPrefetchedContentSuggestions,
+ &kNotificationsFeature,
+ &kPhysicalWebPageSuggestionsFeature,
+ &kPublisherFaviconsFromNewServerFeature,
+ &kRecentOfflineTabSuggestionsFeature,
+ &kRemoteSuggestionsBackendFeature,
+ nullptr};
const base::Feature kArticleSuggestionsFeature{
"NTPArticleSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chromium/components/ntp_snippets/features.h b/chromium/components/ntp_snippets/features.h
index 83800fa157c..e092a09a2bb 100644
--- a/chromium/components/ntp_snippets/features.h
+++ b/chromium/components/ntp_snippets/features.h
@@ -24,7 +24,7 @@ namespace ntp_snippets {
// If you add a base::Feature below, you must add it to this list. It is used in
// internal pages to list relevant parameters and settings.
//
-extern const base::Feature*(kAllFeatures[]);
+extern const base::Feature* const kAllFeatures[];
// Features to turn individual providers/categories on/off.
// TODO(jkrcal): Rename to kRemoteSuggestionsFeature.
@@ -123,6 +123,11 @@ constexpr int kNotificationsIgnoredDefaultLimit = 3;
// have been fetched.
extern const base::Feature kKeepPrefetchedContentSuggestions;
+// Whether remote categories (except articles) which are not present in the last
+// fetch response should be deleted. This feature implicitly depends on
+// kArticleSuggestionsFeature.
+extern const base::Feature kDeleteRemoteCategoriesNotPresentInLastFetch;
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc b/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
index 5e0bbfad778..0fad1ad88f4 100644
--- a/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider.cc
@@ -43,6 +43,18 @@ CategoryInfo MockContentSuggestionsProvider::GetCategoryInfo(
base::ASCIIToUTF16("No suggestions message"));
}
+void MockContentSuggestionsProvider::Fetch(const Category& category,
+ const std::set<std::string>& set,
+ FetchDoneCallback callback) {
+ FetchMock(category, set, callback);
+}
+
+void MockContentSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& id,
+ ImageFetchedCallback callback) {
+ FetchSuggestionImageMock(id, callback);
+}
+
void MockContentSuggestionsProvider::FireSuggestionsChanged(
Category category,
std::vector<ContentSuggestion> suggestions) {
@@ -66,4 +78,10 @@ void MockContentSuggestionsProvider::FireSuggestionInvalidated(
observer()->OnSuggestionInvalidated(this, suggestion_id);
}
+void MockContentSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ DismissedSuggestionsCallback callback) {
+ GetDismissedSuggestionsForDebuggingMock(category, callback);
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider.h b/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
index 17cfeadfb81..1e9a0728af8 100644
--- a/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
@@ -47,20 +47,31 @@ class MockContentSuggestionsProvider : public ContentSuggestionsProvider {
void(base::Time begin,
base::Time end,
const base::Callback<bool(const GURL& url)>& filter));
- MOCK_METHOD3(Fetch,
+ // Gmock cannot mock methods that have movable-only type callbacks as
+ // parameters such as FetchDoneCallback, DismissedSuggestionsCallback,
+ // ImageFetchedCallback. As a work-around, Fetch calls the mock method
+ // FetchMock, which may then be checked with EXPECT_CALL.
+ void Fetch(const Category&,
+ const std::set<std::string>&,
+ FetchDoneCallback) override;
+ MOCK_METHOD3(FetchMock,
void(const Category&,
const std::set<std::string>&,
const FetchDoneCallback&));
MOCK_METHOD1(ClearCachedSuggestions, void(Category category));
- MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ DismissedSuggestionsCallback callback) override;
+ MOCK_METHOD2(GetDismissedSuggestionsForDebuggingMock,
void(Category category,
const DismissedSuggestionsCallback& callback));
MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category));
MOCK_METHOD1(DismissSuggestion,
void(const ContentSuggestion::ID& suggestion_id));
- MOCK_METHOD2(FetchSuggestionImage,
- void(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback));
+ void FetchSuggestionImage(const ContentSuggestion::ID& id,
+ ImageFetchedCallback callback) override;
+ MOCK_METHOD2(FetchSuggestionImageMock,
+ void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
private:
std::vector<Category> provided_categories_;
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.cc b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
index 52abe08ab69..9580ea472c9 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.cc
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
@@ -9,9 +9,6 @@ namespace ntp_snippets {
const base::FilePath::CharType kDatabaseFolder[] =
FILE_PATH_LITERAL("NTPSnippets");
-const base::FilePath::CharType kBreakingNewsDatabaseFolder[] =
- FILE_PATH_LITERAL("NTPBreakingNews");
-
const char kContentSuggestionsApiScope[] =
"https://www.googleapis.com/auth/chrome-content-suggestions";
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.h b/chromium/components/ntp_snippets/ntp_snippets_constants.h
index f7ddd58acb3..558b9eeccc7 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.h
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.h
@@ -13,8 +13,6 @@ namespace ntp_snippets {
// the name of the folder, not a full path - it must be appended to e.g. the
// profile path.
extern const base::FilePath::CharType kDatabaseFolder[];
-// TODO(mamir): Check if the same DB can be used.
-extern const base::FilePath::CharType kBreakingNewsDatabaseFolder[];
// OAuth access token scope.
extern const char kContentSuggestionsApiScope[];
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
index 43be2a4daa6..ee5680f2538 100644
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
@@ -109,25 +109,25 @@ void RecentTabSuggestionsProvider::DismissSuggestion(
void RecentTabSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
// TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
// available there.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
}
void RecentTabSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
LOG(DFATAL) << "RecentTabSuggestionsProvider has no |Fetch| functionality!";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
- callback,
+ base::BindOnce(
+ std::move(callback),
Status(StatusCode::PERMANENT_ERROR,
"RecentTabSuggestionsProvider has no |Fetch| functionality!"),
- base::Passed(std::vector<ContentSuggestion>())));
+ std::vector<ContentSuggestion>()));
}
void RecentTabSuggestionsProvider::ClearHistory(
@@ -144,7 +144,7 @@ void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) {
void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
DCHECK_EQ(provided_category_, category);
std::vector<const DownloadUIItem*> items =
@@ -161,7 +161,7 @@ void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
suggestions.push_back(ConvertUIItem(*item));
}
- callback.Run(std::move(suggestions));
+ std::move(callback).Run(std::move(suggestions));
}
void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
index 52da1cc7a47..fce971485bd 100644
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
@@ -41,10 +41,10 @@ class RecentTabSuggestionsProvider
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -52,7 +52,7 @@ class RecentTabSuggestionsProvider
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
index b8382c0caa0..d7ad53737c6 100644
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -132,30 +132,31 @@ void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
base::StringPiece raw_data = resource_bundle.GetRawDataResourceForScale(
IDR_PHYSICAL_WEB_LOGO_WITH_PADDING, resource_bundle.GetMaxScaleFactor());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(callback,
- gfx::Image::CreateFrom1xPNGBytes(
- reinterpret_cast<const unsigned char*>(raw_data.data()),
- raw_data.size())));
+ base::BindOnce(
+ std::move(callback),
+ gfx::Image::CreateFrom1xPNGBytes(
+ reinterpret_cast<const unsigned char*>(raw_data.data()),
+ raw_data.size())));
}
void PhysicalWebPageSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
DCHECK_EQ(category, provided_category_);
std::vector<ContentSuggestion> suggestions =
GetMostRecentPhysicalWebPagesWithFilter(kMaxSuggestionsCount,
known_suggestion_ids);
AppendToShownScannedUrls(suggestions);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, Status::Success(),
- base::Passed(std::move(suggestions))));
+ FROM_HERE, base::BindOnce(std::move(callback), Status::Success(),
+ std::move(suggestions)));
}
void PhysicalWebPageSuggestionsProvider::ClearHistory(
@@ -172,7 +173,7 @@ void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions(
void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
DCHECK_EQ(provided_category_, category);
std::unique_ptr<physical_web::MetadataList> page_metadata_list =
physical_web_data_source_->GetMetadataList();
@@ -184,7 +185,7 @@ void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging(
}
}
- callback.Run(std::move(suggestions));
+ std::move(callback).Run(std::move(suggestions));
}
void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
index befc8ce5e4a..1c356c423d7 100644
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
@@ -43,10 +43,10 @@ class PhysicalWebPageSuggestionsProvider
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -54,7 +54,7 @@ class PhysicalWebPageSuggestionsProvider
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
diff --git a/chromium/components/ntp_snippets/pref_names.cc b/chromium/components/ntp_snippets/pref_names.cc
index 72851b04e21..95c3aeb5d3c 100644
--- a/chromium/components/ntp_snippets/pref_names.cc
+++ b/chromium/components/ntp_snippets/pref_names.cc
@@ -90,5 +90,11 @@ const char kBreakingNewsSubscriptionDataIsAuthenticated[] =
const char kBreakingNewsGCMSubscriptionTokenCache[] =
"ntp_suggestions.breaking_news_gcm_subscription_token_cache";
+const char kBreakingNewsGCMLastTokenValidationTime[] =
+ "ntp_suggestions.breaking_news_gcm_last_token_validation_time";
+
+const char kBreakingNewsGCMLastForcedSubscriptionTime[] =
+ "ntp_suggestions.breaking_news_gcm_last_forced_subscription_time";
+
} // namespace prefs
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/pref_names.h b/chromium/components/ntp_snippets/pref_names.h
index 110aafee4e2..8462d403c05 100644
--- a/chromium/components/ntp_snippets/pref_names.h
+++ b/chromium/components/ntp_snippets/pref_names.h
@@ -110,6 +110,12 @@ extern const char kBreakingNewsSubscriptionDataIsAuthenticated[];
// with the new one and update kBreakingNewsSubscriptionDataToken.
extern const char kBreakingNewsGCMSubscriptionTokenCache[];
+// When the last GCM token validation was.
+extern const char kBreakingNewsGCMLastTokenValidationTime[];
+
+// When the last forced subscription to content suggestions service was.
+extern const char kBreakingNewsGCMLastForcedSubscriptionTime[];
+
} // namespace prefs
} // namespace ntp_snippets
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 9bf791c4857..7690d2ea79b 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
@@ -81,23 +81,23 @@ void ReadingListSuggestionsProvider::DismissSuggestion(
void ReadingListSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
}
void ReadingListSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
LOG(DFATAL) << "ReadingListSuggestionsProvider has no |Fetch| functionality!";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(callback,
- Status(StatusCode::PERMANENT_ERROR,
- "ReadingListSuggestionsProvider has no |Fetch| "
- "functionality!"),
- base::Passed(std::vector<ContentSuggestion>())));
+ base::BindOnce(std::move(callback),
+ Status(StatusCode::PERMANENT_ERROR,
+ "ReadingListSuggestionsProvider has no |Fetch| "
+ "functionality!"),
+ std::vector<ContentSuggestion>()));
}
void ReadingListSuggestionsProvider::ClearHistory(
@@ -114,9 +114,9 @@ void ReadingListSuggestionsProvider::ClearCachedSuggestions(Category category) {
void ReadingListSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
if (!reading_list_model_ || reading_list_model_->IsPerformingBatchUpdates()) {
- callback.Run(std::vector<ContentSuggestion>());
+ std::move(callback).Run(std::vector<ContentSuggestion>());
return;
}
@@ -136,7 +136,7 @@ void ReadingListSuggestionsProvider::GetDismissedSuggestionsForDebugging(
suggestions.emplace_back(ConvertEntry(entry));
}
- callback.Run(std::move(suggestions));
+ std::move(callback).Run(std::move(suggestions));
}
void ReadingListSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
@@ -162,6 +162,8 @@ void ReadingListSuggestionsProvider::ReadingListModelBeingDeleted(
void ReadingListSuggestionsProvider::ReadingListDidApplyChanges(
ReadingListModel* model) {
DCHECK(model == reading_list_model_);
+ if (model->IsPerformingBatchUpdates())
+ return;
FetchReadingListInternal();
}
@@ -227,7 +229,6 @@ ContentSuggestion ReadingListSuggestionsProvider::ConvertEntry(
base::Time::FromDoubleT(entry_time / base::Time::kMicrosecondsPerSecond));
auto extra = base::MakeUnique<ReadingListSuggestionExtra>();
- extra->distilled = entry->DistilledState() == ReadingListEntry::PROCESSED;
extra->favicon_page_url =
entry->DistilledURL().is_valid() ? entry->DistilledURL() : entry->URL();
suggestion.set_reading_list_suggestion_extra(std::move(extra));
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 433d9493b80..4fbfc8ecf82 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
@@ -34,10 +34,10 @@ class ReadingListSuggestionsProvider : public ContentSuggestionsProvider,
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -45,7 +45,7 @@ class ReadingListSuggestionsProvider : public ContentSuggestionsProvider,
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
// ReadingListModelObserver implementation.
diff --git a/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc b/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
index 5faf2830cc1..b9995faa750 100644
--- a/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
+++ b/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
@@ -37,11 +37,12 @@ CachedImageFetcher::~CachedImageFetcher() {}
void CachedImageFetcher::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
database_->LoadImage(
suggestion_id.id_within_category(),
base::Bind(&CachedImageFetcher::OnImageFetchedFromDatabase,
- base::Unretained(this), callback, suggestion_id, url));
+ base::Unretained(this), base::Passed(std::move(callback)),
+ suggestion_id, url));
}
// This function gets only called for caching the image data received from the
@@ -56,15 +57,15 @@ void CachedImageFetcher::OnImageDataFetched(
}
void CachedImageFetcher::OnImageDecodingDone(
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
const std::string& id_within_category,
const gfx::Image& image,
const image_fetcher::RequestMetadata& metadata) {
- callback.Run(image);
+ std::move(callback).Run(image);
}
void CachedImageFetcher::OnImageFetchedFromDatabase(
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
std::string data) { // SnippetImageCallback requires by-value.
@@ -75,37 +76,38 @@ void CachedImageFetcher::OnImageFetchedFromDatabase(
// We're not dealing with multi-frame images.
/*desired_image_frame_size=*/gfx::Size(),
base::Bind(&CachedImageFetcher::OnImageDecodedFromDatabase,
- base::Unretained(this), callback, suggestion_id, url));
+ base::Unretained(this), base::Passed(std::move(callback)),
+ suggestion_id, url));
return;
}
// Fetching from the DB failed; start a network fetch.
- FetchImageFromNetwork(suggestion_id, url, callback);
+ FetchImageFromNetwork(suggestion_id, url, std::move(callback));
}
void CachedImageFetcher::OnImageDecodedFromDatabase(
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
const gfx::Image& image) {
if (!image.IsEmpty()) {
- callback.Run(image);
+ std::move(callback).Run(image);
return;
}
// If decoding the image failed, delete the DB entry.
database_->DeleteImage(suggestion_id.id_within_category());
- FetchImageFromNetwork(suggestion_id, url, callback);
+ FetchImageFromNetwork(suggestion_id, url, std::move(callback));
}
void CachedImageFetcher::FetchImageFromNetwork(
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
if (url.is_empty() || !thumbnail_requests_throttler_.DemandQuotaForRequest(
/*interactive_request=*/true)) {
// Return an empty image. Directly, this is never synchronous with the
// original FetchSuggestionImage() call - an asynchronous database query has
// happened in the meantime.
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
return;
}
@@ -123,7 +125,7 @@ void CachedImageFetcher::FetchImageFromNetwork(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "Currently not available, but in progress: crbug.com/703684"
chrome_policy {
NTPContentSuggestionsEnabled {
@@ -135,7 +137,7 @@ void CachedImageFetcher::FetchImageFromNetwork(
image_fetcher_->StartOrQueueNetworkRequest(
suggestion_id.id_within_category(), url,
base::Bind(&CachedImageFetcher::OnImageDecodingDone,
- base::Unretained(this), callback),
+ base::Unretained(this), base::Passed(std::move(callback))),
traffic_annotation);
}
diff --git a/chromium/components/ntp_snippets/remote/cached_image_fetcher.h b/chromium/components/ntp_snippets/remote/cached_image_fetcher.h
index 1bb290e2758..51eef498ac9 100644
--- a/chromium/components/ntp_snippets/remote/cached_image_fetcher.h
+++ b/chromium/components/ntp_snippets/remote/cached_image_fetcher.h
@@ -46,32 +46,32 @@ class CachedImageFetcher : public image_fetcher::ImageFetcherDelegate {
// Fetches the image for a suggestion. The fetcher will first issue a lookup
// to the underlying cache with a fallback to the network.
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const GURL& image_url,
- const ImageFetchedCallback& callback);
+ virtual void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const GURL& image_url,
+ ImageFetchedCallback callback);
private:
// image_fetcher::ImageFetcherDelegate implementation.
void OnImageDataFetched(const std::string& id_within_category,
const std::string& image_data) override;
- void OnImageDecodingDone(const ImageFetchedCallback& callback,
+ void OnImageDecodingDone(ImageFetchedCallback callback,
const std::string& id_within_category,
const gfx::Image& image,
const image_fetcher::RequestMetadata& metadata);
void OnImageFetchedFromDatabase(
- const ImageFetchedCallback& callback,
+ ImageFetchedCallback callback,
const ContentSuggestion::ID& suggestion_id,
const GURL& image_url,
// SnippetImageCallback requires by-value (not const ref).
std::string data);
- void OnImageDecodedFromDatabase(const ImageFetchedCallback& callback,
+ void OnImageDecodedFromDatabase(ImageFetchedCallback callback,
const ContentSuggestion::ID& suggestion_id,
const GURL& url,
const gfx::Image& image);
void FetchImageFromNetwork(const ContentSuggestion::ID& suggestion_id,
const GURL& url,
- const ImageFetchedCallback& callback);
+ ImageFetchedCallback callback);
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
RemoteSuggestionsDatabase* database_;
diff --git a/chromium/components/ntp_snippets/remote/cached_image_fetcher_unittest.cc b/chromium/components/ntp_snippets/remote/cached_image_fetcher_unittest.cc
index b176acaa8ac..b673c3c3270 100644
--- a/chromium/components/ntp_snippets/remote/cached_image_fetcher_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/cached_image_fetcher_unittest.cc
@@ -12,8 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/test/mock_callback.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/test/scoped_task_environment.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/image_fetcher.h"
#include "components/image_fetcher/core/image_fetcher_impl.h"
@@ -59,17 +58,15 @@ class FakeImageDecoder : public image_fetcher::ImageDecoder {
class CachedImageFetcherTest : public testing::Test {
public:
- CachedImageFetcherTest()
- : fake_url_fetcher_factory_(nullptr),
- mock_task_runner_(new base::TestSimpleTaskRunner()),
- mock_task_runner_handle_(mock_task_runner_) {
+ CachedImageFetcherTest() : fake_url_fetcher_factory_(nullptr) {
EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
RequestThrottler::RegisterProfilePrefs(pref_service_.registry());
- database_ = base::MakeUnique<RemoteSuggestionsDatabase>(
- database_dir_.GetPath(), mock_task_runner_);
+ database_ =
+ base::MakeUnique<RemoteSuggestionsDatabase>(database_dir_.GetPath());
request_context_getter_ = scoped_refptr<net::TestURLRequestContextGetter>(
- new net::TestURLRequestContextGetter(mock_task_runner_.get()));
+ new net::TestURLRequestContextGetter(
+ scoped_task_environment_.GetMainThreadTaskRunner()));
auto decoder = base::MakeUnique<FakeImageDecoder>();
fake_image_decoder_ = decoder.get();
@@ -81,14 +78,22 @@ class CachedImageFetcherTest : public testing::Test {
EXPECT_TRUE(database_->IsInitialized());
}
- void FetchImage(const ImageFetchedCallback& callback) {
+ ~CachedImageFetcherTest() override {
+ cached_image_fetcher_.reset();
+ database_.reset();
+ // We need to run until idle after deleting the database, because
+ // ProtoDatabaseImpl deletes the actual LevelDB asynchronously.
+ RunUntilIdle();
+ }
+
+ void FetchImage(ImageFetchedCallback callback) {
ContentSuggestion::ID content_suggestion_id(
Category::FromKnownCategory(KnownCategories::ARTICLES), kSnippetID);
- cached_image_fetcher_->FetchSuggestionImage(content_suggestion_id,
- GURL(kImageURL), callback);
+ cached_image_fetcher_->FetchSuggestionImage(
+ content_suggestion_id, GURL(kImageURL), std::move(callback));
}
- void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
RemoteSuggestionsDatabase* database() { return database_.get(); }
FakeImageDecoder* fake_image_decoder() { return fake_image_decoder_; }
@@ -102,10 +107,9 @@ class CachedImageFetcherTest : public testing::Test {
base::ScopedTempDir database_dir_;
FakeImageDecoder* fake_image_decoder_;
net::FakeURLFetcherFactory fake_url_fetcher_factory_;
- scoped_refptr<base::TestSimpleTaskRunner> mock_task_runner_;
- base::ThreadTaskRunnerHandle mock_task_runner_handle_;
TestingPrefServiceSimple pref_service_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
DISALLOW_COPY_AND_ASSIGN(CachedImageFetcherTest);
};
diff --git a/chromium/components/ntp_snippets/remote/json_request.cc b/chromium/components/ntp_snippets/remote/json_request.cc
index 2be9a6b5d27..206c846ce1c 100644
--- a/chromium/components/ntp_snippets/remote/json_request.cc
+++ b/chromium/components/ntp_snippets/remote/json_request.cc
@@ -76,7 +76,7 @@ bool IsSendingTopLanguagesEnabled() {
bool IsSendingUserClassEnabled() {
return variations::GetVariationParamByFeatureAsBool(
ntp_snippets::kArticleSuggestionsFeature, kSendUserClassName,
- /*default_value=*/false);
+ /*default_value=*/true);
}
// Translate the BCP 47 |language_code| into a posix locale string.
@@ -371,7 +371,7 @@ std::unique_ptr<net::URLFetcher> JsonRequest::Builder::BuildURLFetcher(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"This feature cannot be disabled by settings now (but is requested "
"to be implemented in crbug.com/695129)."
diff --git a/chromium/components/ntp_snippets/remote/json_request_unittest.cc b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
index 0e52824c3b0..3bbb6a5ffd3 100644
--- a/chromium/components/ntp_snippets/remote/json_request_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
@@ -52,7 +52,7 @@ MATCHER_P(EqualsJSON, json, "equals JSON") {
<< "parse error: " << err_msg;
return false;
}
- return base::Value::Equals(actual.get(), expected.get());
+ return *expected == *actual;
}
} // namespace
diff --git a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
index a595715a321..b05b465d7d3 100644
--- a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
+++ b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
@@ -69,7 +69,11 @@ void PrefetchedPagesTrackerImpl::AddInitializationCompletedCallback(
bool PrefetchedPagesTrackerImpl::PrefetchedOfflinePageExists(
const GURL& url) const {
DCHECK(initialized_);
- return prefetched_urls_.count(url) == 1;
+ DCHECK(prefetched_url_counts_.count(url) == 0 ||
+ prefetched_url_counts_.find(url)->second > 0);
+ // It is enough to check existence of an item (instead of its count), because
+ // the mapping does not contain zero counts.
+ return prefetched_url_counts_.count(url) == 1;
}
void PrefetchedPagesTrackerImpl::OfflinePageModelLoaded(
@@ -87,13 +91,22 @@ void PrefetchedPagesTrackerImpl::OfflinePageAdded(
void PrefetchedPagesTrackerImpl::OfflinePageDeleted(
const offline_pages::OfflinePageModel::DeletedPageInfo& page_info) {
- std::map<int64_t, GURL>::iterator it =
+ std::map<int64_t, GURL>::iterator offline_id_it =
offline_id_to_url_mapping_.find(page_info.offline_id);
- if (it != offline_id_to_url_mapping_.end()) {
- DCHECK(prefetched_urls_.count(it->second));
- prefetched_urls_.erase(it->second);
- offline_id_to_url_mapping_.erase(it);
+
+ if (offline_id_it == offline_id_to_url_mapping_.end()) {
+ // We did not know about this page, thus, nothing to delete.
+ return;
+ }
+
+ std::map<GURL, int>::iterator url_it =
+ prefetched_url_counts_.find(offline_id_it->second);
+ DCHECK(url_it != prefetched_url_counts_.end());
+ --url_it->second;
+ if (url_it->second == 0) {
+ prefetched_url_counts_.erase(url_it);
}
+ offline_id_to_url_mapping_.erase(offline_id_it);
}
void PrefetchedPagesTrackerImpl::Initialize(
@@ -113,8 +126,9 @@ void PrefetchedPagesTrackerImpl::Initialize(
void PrefetchedPagesTrackerImpl::AddOfflinePage(
const OfflinePageItem& offline_page_item) {
const GURL& url = GetOfflinePageUrl(offline_page_item);
- DCHECK(!prefetched_urls_.count(url));
- prefetched_urls_.insert(url);
+ DCHECK(prefetched_url_counts_.count(url) == 0 ||
+ prefetched_url_counts_.find(url)->second > 0);
+ ++prefetched_url_counts_[url];
offline_id_to_url_mapping_[offline_page_item.offline_id] = url;
}
diff --git a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
index 32be1db182e..d314a120343 100644
--- a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
+++ b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
@@ -53,8 +53,12 @@ class PrefetchedPagesTrackerImpl
bool initialized_;
offline_pages::OfflinePageModel* offline_page_model_;
- std::set<GURL> prefetched_urls_;
+ // Mapping from an offline id to a URL for all currently known prefetched
+ // offline pages.
std::map<int64_t, GURL> offline_id_to_url_mapping_;
+ // The mapping above represented as a mapping from a URL to its count. It does
+ // not contain items with zero count.
+ std::map<GURL, int> prefetched_url_counts_;
std::vector<base::OnceCallback<void()>> initialization_completed_callbacks_;
diff --git a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
index ddbb295cb14..440849aef7f 100644
--- a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
@@ -142,7 +142,7 @@ TEST_F(PrefetchedPagesTrackerImplTest, ShouldDeletePrefetchedURLWhenNotified) {
ASSERT_TRUE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
- item.offline_id, item.client_id, "" /* request_origin */));
+ item.offline_id, item.client_id, /*request_origin=*/""));
EXPECT_FALSE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
}
@@ -163,7 +163,7 @@ TEST_F(PrefetchedPagesTrackerImplTest,
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
manually_downloaded_item.offline_id, manually_downloaded_item.client_id,
- "" /* request_origin */));
+ /*request_origin=*/""));
EXPECT_TRUE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
}
@@ -235,4 +235,55 @@ TEST_F(PrefetchedPagesTrackerImplTest,
mock_initialization_completed_callback.Get());
}
+TEST_F(PrefetchedPagesTrackerImplTest,
+ ShouldKeepPrefetchedURLAfterDuplicatePageDeleted) {
+ const OfflinePageItem first_item =
+ CreateOfflinePageItem(GURL("http://prefetched.com"),
+ offline_pages::kSuggestedArticlesNamespace);
+ const OfflinePageItem second_item =
+ CreateOfflinePageItem(GURL("http://prefetched.com"),
+ offline_pages::kSuggestedArticlesNamespace);
+ (*fake_offline_page_model()->mutable_items()) = {first_item, second_item};
+ PrefetchedPagesTrackerImpl tracker(fake_offline_page_model());
+
+ ASSERT_TRUE(
+ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
+
+ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
+ first_item.offline_id, first_item.client_id, /*request_origin=*/""));
+
+ // Only one offline page (out of two) has been removed, the remaining one
+ // should be reported here.
+ EXPECT_TRUE(
+ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
+}
+
+TEST_F(PrefetchedPagesTrackerImplTest,
+ ShouldDeletePrefetchedURLAfterAllItsPagesAreDeleted) {
+ const OfflinePageItem first_item =
+ CreateOfflinePageItem(GURL("http://prefetched.com"),
+ offline_pages::kSuggestedArticlesNamespace);
+ const OfflinePageItem second_item =
+ CreateOfflinePageItem(GURL("http://prefetched.com"),
+ offline_pages::kSuggestedArticlesNamespace);
+ (*fake_offline_page_model()->mutable_items()) = {first_item, second_item};
+ PrefetchedPagesTrackerImpl tracker(fake_offline_page_model());
+
+ ASSERT_TRUE(
+ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
+
+ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
+ first_item.offline_id, first_item.client_id, /*request_origin=*/""));
+
+ ASSERT_TRUE(
+ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
+
+ tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
+ second_item.offline_id, second_item.client_id, /*request_origin=*/""));
+
+ // All offline pages have been removed, their absence should be reported here.
+ EXPECT_FALSE(
+ tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto b/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto
index 45decf8b264..7aa3641a09b 100644
--- a/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto
+++ b/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto
@@ -33,6 +33,11 @@ message SnippetProto {
VIDEO = 1;
}
optional ContentType content_type = 12 [default = UNKNOWN];
+
+ // A rank to preserve the order of suggestions. Lower ranks are shown earlier.
+ // The values may be not consecutive. Must be set on the client. May be absent
+ // in suggestions created before it was introduced.
+ optional int32 rank = 13;
}
message SnippetImageProto {
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion.cc b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
index fc0e4a3bcec..01576462cbe 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
@@ -4,6 +4,8 @@
#include "components/ntp_snippets/remote/remote_suggestion.h"
+#include <limits>
+
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
@@ -87,6 +89,7 @@ RemoteSuggestion::RemoteSuggestion(const std::vector<std::string>& ids,
score_(0),
is_dismissed_(false),
remote_category_id_(remote_category_id),
+ rank_(std::numeric_limits<int>::max()),
should_notify_(false),
content_type_(ContentType::UNKNOWN) {}
@@ -287,6 +290,31 @@ RemoteSuggestion::CreateFromContentSuggestionsDictionary(
}
// static
+std::unique_ptr<RemoteSuggestion>
+RemoteSuggestion::CreateFromContextualSuggestionsDictionary(
+ const base::DictionaryValue& dict) {
+ std::string id;
+ if (!dict.GetString("url", &id) || id.empty()) {
+ return nullptr;
+ }
+ // TODO(gaschler): Remove the unused kArticlesRemoteId argument when moving
+ // away from RemoteSuggestion.
+ auto remote_suggestion = MakeUnique({id}, kArticlesRemoteId);
+ GetURLValue(dict, "url", &remote_suggestion->url_);
+ if (!dict.GetString("title", &remote_suggestion->title_)) {
+ dict.GetString("source", &remote_suggestion->title_);
+ }
+ dict.GetString("snippet", &remote_suggestion->snippet_);
+ GetTimeValue(dict, "creationTime", &remote_suggestion->publish_date_);
+ GetTimeValue(dict, "expirationTime", &remote_suggestion->expiry_date_);
+ GetURLValue(dict, "imageUrl", &remote_suggestion->salient_image_url_);
+ if (!dict.GetString("attribution", &remote_suggestion->publisher_name_)) {
+ dict.GetString("source", &remote_suggestion->publisher_name_);
+ }
+ return remote_suggestion;
+}
+
+// static
std::unique_ptr<RemoteSuggestion> RemoteSuggestion::CreateFromProto(
const SnippetProto& proto) {
// Need at least the id.
@@ -346,6 +374,9 @@ std::unique_ptr<RemoteSuggestion> RemoteSuggestion::CreateFromProto(
snippet->content_type_ = ContentType::VIDEO;
}
+ snippet->rank_ =
+ proto.has_rank() ? proto.rank() : std::numeric_limits<int>::max();
+
return snippet;
}
@@ -389,6 +420,9 @@ SnippetProto RemoteSuggestion::ToProto() const {
if (content_type_ == ContentType::VIDEO) {
result.set_content_type(SnippetProto_ContentType_VIDEO);
}
+
+ result.set_rank(rank_);
+
return result;
}
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion.h b/chromium/components/ntp_snippets/remote/remote_suggestion.h
index 97bda87246d..367cd3ecd6c 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion.h
@@ -51,6 +51,9 @@ class RemoteSuggestion {
int remote_category_id,
const base::Time& fetch_date);
+ static std::unique_ptr<RemoteSuggestion>
+ CreateFromContextualSuggestionsDictionary(const base::DictionaryValue& dict);
+
// Creates an RemoteSuggestion from a protocol buffer. Returns a null pointer
// if the protocol buffer doesn't correspond to a valid suggestion.
static std::unique_ptr<RemoteSuggestion> CreateFromProto(
@@ -107,7 +110,12 @@ class RemoteSuggestion {
float score() const { return score_; }
bool should_notify() const { return should_notify_; }
+ void set_should_notify(bool new_value) { should_notify_ = new_value; }
+
base::Time notification_deadline() const { return notification_deadline_; }
+ void set_notification_deadline(const base::Time& new_value) {
+ notification_deadline_ = new_value;
+ }
ContentType content_type() const { return content_type_; }
@@ -115,9 +123,12 @@ class RemoteSuggestion {
void set_dismissed(bool dismissed) { is_dismissed_ = dismissed; }
// The ID of the remote category this suggestion belongs to, for use with
- // CategoryFactory::FromRemoteCategory.
+ // Category::FromRemoteCategory.
int remote_category_id() const { return remote_category_id_; }
+ int rank() const { return rank_; }
+ void set_rank(int rank) { rank_ = rank; }
+
base::Time fetch_date() const { return fetch_date_; }
// Public for testing.
@@ -148,6 +159,7 @@ class RemoteSuggestion {
float score_;
bool is_dismissed_;
int remote_category_id_;
+ int rank_;
bool should_notify_;
base::Time notification_deadline_;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion_builder.cc b/chromium/components/ntp_snippets/remote/remote_suggestion_builder.cc
new file mode 100644
index 00000000000..95d3d0202c7
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion_builder.cc
@@ -0,0 +1,239 @@
+// 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/ntp_snippets/remote/remote_suggestion_builder.h"
+
+#include <limits>
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
+#include "components/ntp_snippets/time_serialization.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+namespace test {
+
+namespace {
+
+base::Time GetDefaultSuggestionCreationTime() {
+ base::Time out_time;
+ EXPECT_TRUE(base::Time::FromUTCString("2000-01-01T00:00:01Z", &out_time));
+ return out_time;
+}
+
+base::Time GetDefaultSuggestionExpirationTime() {
+ base::Time out_time;
+ EXPECT_TRUE(base::Time::FromUTCString("2100-01-01T00:00:01Z", &out_time));
+ return out_time;
+}
+
+} // namespace
+
+RemoteSuggestionBuilder::RemoteSuggestionBuilder() = default;
+RemoteSuggestionBuilder::RemoteSuggestionBuilder(
+ const RemoteSuggestionBuilder& other) = default;
+RemoteSuggestionBuilder::~RemoteSuggestionBuilder() = default;
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::AddId(const std::string& id) {
+ if (!ids_) {
+ ids_ = std::vector<std::string>();
+ }
+ ids_->push_back(id);
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetTitle(
+ const std::string& title) {
+ title_ = title;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetSnippet(
+ const std::string& snippet) {
+ snippet_ = snippet;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetImageUrl(
+ const std::string& image_url) {
+ salient_image_url_ = image_url;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetPublishDate(
+ const base::Time& publish_date) {
+ publish_date_ = publish_date;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetExpiryDate(
+ const base::Time& expiry_date) {
+ expiry_date_ = expiry_date;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetScore(double score) {
+ score_ = score;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetIsDismissed(
+ bool is_dismissed) {
+ is_dismissed_ = is_dismissed;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetRemoteCategoryId(
+ int remote_category_id) {
+ remote_category_id_ = remote_category_id;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetUrl(
+ const std::string& url) {
+ url_ = url;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetPublisher(
+ const std::string& publisher) {
+ publisher_name_ = publisher;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetAmpUrl(
+ const std::string& amp_url) {
+ amp_url_ = amp_url;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetFetchDate(
+ const base::Time& fetch_date) {
+ fetch_date_ = fetch_date;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetRank(int rank) {
+ rank_ = rank;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetShouldNotify(
+ bool should_notify) {
+ should_notify_ = should_notify;
+ return *this;
+}
+
+RemoteSuggestionBuilder& RemoteSuggestionBuilder::SetNotificationDeadline(
+ const base::Time& notification_deadline) {
+ notification_deadline_ = notification_deadline;
+ return *this;
+}
+
+std::unique_ptr<RemoteSuggestion> RemoteSuggestionBuilder::Build() const {
+ SnippetProto proto;
+ proto.set_title(title_.value_or("Title"));
+ proto.set_snippet(snippet_.value_or("Snippet"));
+ proto.set_salient_image_url(
+ salient_image_url_.value_or("http://image_url.com/"));
+ proto.set_publish_date(SerializeTime(
+ publish_date_.value_or(GetDefaultSuggestionCreationTime())));
+ proto.set_expiry_date(SerializeTime(
+ expiry_date_.value_or(GetDefaultSuggestionExpirationTime())));
+ proto.set_score(score_.value_or(1));
+ proto.set_dismissed(is_dismissed_.value_or(false));
+ proto.set_remote_category_id(remote_category_id_.value_or(1));
+ auto* source = proto.add_sources();
+ source->set_url(url_.value_or("http://url.com/"));
+ source->set_publisher_name(publisher_name_.value_or("Publisher"));
+ source->set_amp_url(amp_url_.value_or("http://amp_url.com/"));
+ proto.set_fetch_date(SerializeTime(fetch_date_.value_or(base::Time::Now())));
+ for (const auto& id :
+ ids_.value_or(std::vector<std::string>{source->url()})) {
+ proto.add_ids(id);
+ }
+ proto.set_rank(rank_.value_or(std::numeric_limits<int>::max()));
+ std::unique_ptr<RemoteSuggestion> suggestion =
+ RemoteSuggestion::CreateFromProto(proto);
+ suggestion->set_should_notify(should_notify_.value_or(false));
+ suggestion->set_notification_deadline(
+ notification_deadline_.value_or(base::Time()));
+ return suggestion;
+}
+
+FetchedCategoryBuilder::FetchedCategoryBuilder() = default;
+FetchedCategoryBuilder::FetchedCategoryBuilder(
+ const FetchedCategoryBuilder& other) = default;
+FetchedCategoryBuilder::~FetchedCategoryBuilder() = default;
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetCategory(Category category) {
+ category_ = category;
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetTitle(
+ const std::string& title) {
+ title_ = base::UTF8ToUTF16(title);
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetCardLayout(
+ ContentSuggestionsCardLayout card_layout) {
+ card_layout_ = card_layout;
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetAdditionalAction(
+ ContentSuggestionsAdditionalAction additional_action) {
+ additional_action_ = additional_action;
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetShowIfEmpty(
+ bool show_if_empty) {
+ show_if_empty_ = show_if_empty;
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::SetNoSuggestionsMessage(
+ const std::string& no_suggestions_message) {
+ no_suggestions_message_ = base::UTF8ToUTF16(no_suggestions_message);
+ return *this;
+}
+
+FetchedCategoryBuilder& FetchedCategoryBuilder::AddSuggestionViaBuilder(
+ const RemoteSuggestionBuilder& builder) {
+ if (!suggestion_builders_) {
+ suggestion_builders_ = std::vector<RemoteSuggestionBuilder>();
+ }
+ suggestion_builders_->push_back(builder);
+ return *this;
+}
+
+FetchedCategory FetchedCategoryBuilder::Build() const {
+ FetchedCategory result = FetchedCategory(
+ category_.value_or(Category::FromRemoteCategory(1)),
+ CategoryInfo(
+ title_.value_or(base::UTF8ToUTF16("Category title")),
+ card_layout_.value_or(ContentSuggestionsCardLayout::FULL_CARD),
+ additional_action_.value_or(
+ ContentSuggestionsAdditionalAction::FETCH),
+ show_if_empty_.value_or(false),
+ no_suggestions_message_.value_or(
+ base::UTF8ToUTF16("No suggestions message"))));
+
+ if (suggestion_builders_) {
+ for (const auto& suggestion_builder : *suggestion_builders_)
+ result.suggestions.push_back(suggestion_builder.Build());
+ }
+ return result;
+}
+
+} // namespace test
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion_builder.h b/chromium/components/ntp_snippets/remote/remote_suggestion_builder.h
new file mode 100644
index 00000000000..7de91bd1289
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion_builder.h
@@ -0,0 +1,98 @@
+// 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_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTION_BUILDER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTION_BUILDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "components/ntp_snippets/remote/json_to_categories.h"
+#include "components/ntp_snippets/remote/remote_suggestion.h"
+
+namespace ntp_snippets {
+
+namespace test {
+
+class RemoteSuggestionBuilder {
+ public:
+ RemoteSuggestionBuilder();
+ RemoteSuggestionBuilder(const RemoteSuggestionBuilder& other);
+ ~RemoteSuggestionBuilder();
+
+ RemoteSuggestionBuilder& AddId(const std::string& id);
+ RemoteSuggestionBuilder& SetTitle(const std::string& title);
+ RemoteSuggestionBuilder& SetSnippet(const std::string& snippet);
+ RemoteSuggestionBuilder& SetImageUrl(const std::string& image_url);
+ RemoteSuggestionBuilder& SetPublishDate(const base::Time& publish_date);
+ RemoteSuggestionBuilder& SetExpiryDate(const base::Time& expiry_date);
+ RemoteSuggestionBuilder& SetScore(double score);
+ RemoteSuggestionBuilder& SetIsDismissed(bool is_dismissed);
+ RemoteSuggestionBuilder& SetRemoteCategoryId(int remote_category_id);
+ RemoteSuggestionBuilder& SetUrl(const std::string& url);
+ RemoteSuggestionBuilder& SetPublisher(const std::string& publisher);
+ RemoteSuggestionBuilder& SetAmpUrl(const std::string& amp_url);
+ RemoteSuggestionBuilder& SetFetchDate(const base::Time& fetch_date);
+ RemoteSuggestionBuilder& SetRank(int rank);
+ RemoteSuggestionBuilder& SetShouldNotify(bool should_notify);
+ RemoteSuggestionBuilder& SetNotificationDeadline(
+ const base::Time& notification_deadline);
+
+ std::unique_ptr<RemoteSuggestion> Build() const;
+
+ private:
+ base::Optional<std::vector<std::string>> ids_;
+ base::Optional<std::string> title_;
+ base::Optional<std::string> snippet_;
+ base::Optional<std::string> salient_image_url_;
+ base::Optional<base::Time> publish_date_;
+ base::Optional<base::Time> expiry_date_;
+ base::Optional<double> score_;
+ base::Optional<bool> is_dismissed_;
+ base::Optional<int> remote_category_id_;
+ base::Optional<std::string> url_;
+ base::Optional<std::string> publisher_name_;
+ base::Optional<std::string> amp_url_;
+ base::Optional<base::Time> fetch_date_;
+ base::Optional<int> rank_;
+ base::Optional<bool> should_notify_;
+ base::Optional<base::Time> notification_deadline_;
+};
+
+class FetchedCategoryBuilder {
+ public:
+ FetchedCategoryBuilder();
+ FetchedCategoryBuilder(const FetchedCategoryBuilder& other);
+ ~FetchedCategoryBuilder();
+
+ FetchedCategoryBuilder& SetCategory(Category category);
+ FetchedCategoryBuilder& SetTitle(const std::string& title);
+ FetchedCategoryBuilder& SetCardLayout(
+ ContentSuggestionsCardLayout card_layout);
+ FetchedCategoryBuilder& SetAdditionalAction(
+ ContentSuggestionsAdditionalAction additional_action);
+ FetchedCategoryBuilder& SetShowIfEmpty(bool show_if_empty);
+ FetchedCategoryBuilder& SetNoSuggestionsMessage(
+ const std::string& no_suggestions_message);
+ FetchedCategoryBuilder& AddSuggestionViaBuilder(
+ const RemoteSuggestionBuilder& builder);
+
+ FetchedCategory Build() const;
+
+ private:
+ base::Optional<Category> category_;
+ base::Optional<base::string16> title_;
+ base::Optional<ContentSuggestionsCardLayout> card_layout_;
+ base::Optional<ContentSuggestionsAdditionalAction> additional_action_;
+ base::Optional<bool> show_if_empty_;
+ base::Optional<base::string16> no_suggestions_message_;
+ base::Optional<std::vector<RemoteSuggestionBuilder>> suggestion_builders_;
+};
+
+} // namespace test
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTION_BUILDER_H_
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index bc79f14dddd..6c8d78763bf 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -405,6 +405,7 @@ TEST(RemoteSuggestionTest, CreateFromProtoToProtoRoundtrip) {
source->set_url("http://cool-suggestions.com/");
source->set_publisher_name("Great Suggestions Inc.");
source->set_amp_url("http://cdn.ampproject.org/c/foo/");
+ proto.set_rank(7);
std::unique_ptr<RemoteSuggestion> snippet =
RemoteSuggestion::CreateFromProto(proto);
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_database.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_database.cc
index 82b42d60b8b..25b3c06b423 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_database.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_database.cc
@@ -8,9 +8,11 @@
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
+#include "base/task_scheduler/post_task.h"
#include "components/leveldb_proto/proto_database_impl.h"
#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
+using leveldb_env::SharedReadCache;
using leveldb_proto::ProtoDatabaseImpl;
namespace {
@@ -24,36 +26,37 @@ const char kImageDatabaseUMAClientName[] = "NTPSnippetImages";
const char kSnippetDatabaseFolder[] = "snippets";
const char kImageDatabaseFolder[] = "images";
-const size_t kSuggestionDatabaseReadCacheSizeBytes = 512 << 10;
-const size_t kImageDatabaseReadCacheSizeBytes = 2 << 20;
-
const size_t kDatabaseWriteBufferSizeBytes = 512 << 10;
} // namespace
namespace ntp_snippets {
RemoteSuggestionsDatabase::RemoteSuggestionsDatabase(
- const base::FilePath& database_dir,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner)
- : database_(new ProtoDatabaseImpl<SnippetProto>(file_task_runner)),
- database_initialized_(false),
- image_database_(
- new ProtoDatabaseImpl<SnippetImageProto>(file_task_runner)),
+ const base::FilePath& database_dir)
+ : database_initialized_(false),
image_database_initialized_(false),
weak_ptr_factory_(this) {
+ auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+ database_ =
+ base::MakeUnique<ProtoDatabaseImpl<SnippetProto>>(file_task_runner);
+ image_database_ =
+ base::MakeUnique<ProtoDatabaseImpl<SnippetImageProto>>(file_task_runner);
+
base::FilePath snippet_dir = database_dir.AppendASCII(kSnippetDatabaseFolder);
database_->InitWithOptions(
kDatabaseUMAClientName,
- leveldb_proto::Options(snippet_dir, kDatabaseWriteBufferSizeBytes,
- kSuggestionDatabaseReadCacheSizeBytes),
+ leveldb_proto::Options(snippet_dir, SharedReadCache::Default,
+ kDatabaseWriteBufferSizeBytes),
base::Bind(&RemoteSuggestionsDatabase::OnDatabaseInited,
weak_ptr_factory_.GetWeakPtr()));
base::FilePath image_dir = database_dir.AppendASCII(kImageDatabaseFolder);
image_database_->InitWithOptions(
kImageDatabaseUMAClientName,
- leveldb_proto::Options(image_dir, kDatabaseWriteBufferSizeBytes,
- kImageDatabaseReadCacheSizeBytes),
+ leveldb_proto::Options(image_dir, SharedReadCache::Default,
+ kDatabaseWriteBufferSizeBytes),
base::Bind(&RemoteSuggestionsDatabase::OnImageDatabaseInited,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_database.h b/chromium/components/ntp_snippets/remote/remote_suggestions_database.h
index 34896ee5f73..91900998084 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_database.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_database.h
@@ -34,9 +34,7 @@ class RemoteSuggestionsDatabase {
using SnippetsCallback = base::Callback<void(RemoteSuggestion::PtrVector)>;
using SnippetImageCallback = base::Callback<void(std::string)>;
- RemoteSuggestionsDatabase(
- const base::FilePath& database_dir,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner);
+ RemoteSuggestionsDatabase(const base::FilePath& database_dir);
~RemoteSuggestionsDatabase();
// Returns whether the database has finished initialization. While this is
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
index df46935a19b..b951f4d6e2b 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
@@ -12,8 +12,8 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -66,11 +66,11 @@ class RemoteSuggestionsDatabaseTest : public testing::Test {
}
~RemoteSuggestionsDatabaseTest() override {
- // We need to run the message loop after deleting the database, because
+ // We need to run until idle after deleting the database, because
// ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
// runner. Without this, we'd get reports of memory leaks.
db_.reset();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
void CreateDatabase() {
@@ -78,10 +78,11 @@ class RemoteSuggestionsDatabaseTest : public testing::Test {
// on the file.
db_.reset();
- db_.reset(new RemoteSuggestionsDatabase(
- database_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get()));
+ db_.reset(new RemoteSuggestionsDatabase(database_dir_.GetPath()));
}
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
RemoteSuggestionsDatabase* db() { return db_.get(); }
// TODO(tschumann): MOCK_METHODS on non mock objects are an anti-pattern.
@@ -95,9 +96,9 @@ class RemoteSuggestionsDatabaseTest : public testing::Test {
MOCK_METHOD1(OnImageLoaded, void(std::string));
private:
- base::MessageLoop message_loop_;
base::ScopedTempDir database_dir_;
std::unique_ptr<RemoteSuggestionsDatabase> db_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsDatabaseTest);
};
@@ -108,7 +109,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, Init) {
CreateDatabase();
EXPECT_FALSE(db()->IsInitialized());
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
EXPECT_TRUE(db()->IsInitialized());
}
@@ -127,7 +128,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, LoadBeforeInit) {
// They should be serviced once initialization finishes.
EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
EXPECT_CALL(*this, OnImageLoaded(_));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
EXPECT_TRUE(db()->IsInitialized());
}
@@ -136,7 +137,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, LoadAfterInit) {
EXPECT_FALSE(db()->IsInitialized());
EXPECT_CALL(*this, OnSnippetsLoadedImpl(_)).Times(0);
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
EXPECT_TRUE(db()->IsInitialized());
Mock::VerifyAndClearExpectations(this);
@@ -149,12 +150,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, LoadAfterInit) {
db()->LoadImage("id",
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsDatabaseTest, Save) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -170,7 +171,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, Save) {
db()->LoadSnippets(
base::Bind(&RemoteSuggestionsDatabaseTest::OnSnippetsLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
@@ -178,12 +179,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, Save) {
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
-TEST_F(RemoteSuggestionsDatabaseTest, SavePersist) {
+TEST_F(RemoteSuggestionsDatabaseTest, DISABLED_SavePersist) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -192,7 +193,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, SavePersist) {
// Store a snippet and an image.
db()->SaveSnippet(*snippet);
db()->SaveImage(snippet->id(), image_data);
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// They should still exist after recreating the database.
CreateDatabase();
@@ -206,12 +207,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, SavePersist) {
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsDatabaseTest, Update) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -229,12 +230,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, Update) {
db()->LoadSnippets(
base::Bind(&RemoteSuggestionsDatabaseTest::OnSnippetsLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsDatabaseTest, Delete) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -248,7 +249,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, Delete) {
db()->LoadSnippets(
base::Bind(&RemoteSuggestionsDatabaseTest::OnSnippetsLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
@@ -260,12 +261,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, Delete) {
db()->LoadSnippets(
base::Bind(&RemoteSuggestionsDatabaseTest::OnSnippetsLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsDatabaseTest, DeleteSnippetDoesNotDeleteImage) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -274,7 +275,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, DeleteSnippetDoesNotDeleteImage) {
// Store a snippet and image.
db()->SaveSnippet(*snippet);
db()->SaveImage(snippet->id(), image_data);
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// Make sure they're there.
EXPECT_CALL(*this,
@@ -286,7 +287,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, DeleteSnippetDoesNotDeleteImage) {
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
@@ -298,12 +299,12 @@ TEST_F(RemoteSuggestionsDatabaseTest, DeleteSnippetDoesNotDeleteImage) {
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsDatabaseTest, DeleteImage) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
@@ -311,14 +312,14 @@ TEST_F(RemoteSuggestionsDatabaseTest, DeleteImage) {
// Store the image.
db()->SaveImage(snippet->id(), image_data);
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// Make sure the image is there.
EXPECT_CALL(*this, OnImageLoaded(image_data));
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
Mock::VerifyAndClearExpectations(this);
@@ -330,7 +331,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, DeleteImage) {
db()->LoadImage(snippet->id(),
base::Bind(&RemoteSuggestionsDatabaseTest::OnImageLoaded,
base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
namespace {
@@ -353,14 +354,14 @@ void LoadExpectedImage(RemoteSuggestionsDatabase* db,
TEST_F(RemoteSuggestionsDatabaseTest, ShouldGarbageCollectImages) {
CreateDatabase();
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_TRUE(db()->IsInitialized());
// Store images.
db()->SaveImage("snippet-id-1", "pretty-image-1");
db()->SaveImage("snippet-id-2", "pretty-image-2");
db()->SaveImage("snippet-id-3", "pretty-image-3");
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// Make sure the to-be-garbage collected images are there.
LoadExpectedImage(db(), "snippet-id-1", "pretty-image-1");
@@ -369,7 +370,7 @@ TEST_F(RemoteSuggestionsDatabaseTest, ShouldGarbageCollectImages) {
// Garbage collect all except the second.
db()->GarbageCollectImages(base::MakeUnique<std::set<std::string>>(
std::set<std::string>({"snippet-id-2"})));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// Make sure the images are gone.
LoadExpectedImage(db(), "snippet-id-1", "");
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index e4c2e2eb894..da04ecefcc7 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -4,11 +4,11 @@
#include "components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h"
-#include <deque>
#include <map>
#include <utility>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
@@ -218,7 +218,7 @@ class DelegateCallingTestURLFetcherFactory
DropAndCallDelegate(fetcher_id);
}
- std::deque<int> fetchers_; // std::queue doesn't support std::find.
+ base::circular_deque<int> fetchers_;
};
// Factory for FakeURLFetcher objects that always generate errors.
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h b/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
index a2b76f5fa33..6f240090e4e 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider.h
@@ -20,9 +20,7 @@ class RemoteSuggestionsFetcher;
class RemoteSuggestionsProvider : public ContentSuggestionsProvider {
public:
// Callback to notify with the result of a fetch.
- // TODO(jkrcal): Change to OnceCallback? A OnceCallback does only have a
- // move-constructor which seems problematic for google mock.
- using FetchStatusCallback = base::Callback<void(Status status_code)>;
+ using FetchStatusCallback = base::OnceCallback<void(Status status_code)>;
~RemoteSuggestionsProvider() override;
@@ -32,7 +30,7 @@ class RemoteSuggestionsProvider : public ContentSuggestionsProvider {
// triggered by the user and have lower priority on the server. After the
// fetch finished, the provided |callback| will be triggered with the status
// of the fetch (unless nullptr).
- virtual void RefetchInTheBackground(const FetchStatusCallback& callback) = 0;
+ virtual void RefetchInTheBackground(FetchStatusCallback callback) = 0;
virtual const RemoteSuggestionsFetcher* suggestions_fetcher_for_debugging()
const = 0;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index c13ee94413e..5291ffa6a1d 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -23,11 +23,13 @@
#include "base/values.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/image_fetcher/core/image_fetcher.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service_impl.h"
#include "components/ntp_snippets/switches.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -133,6 +135,72 @@ base::TimeDelta GetMaxAgeForAdditionalPrefetchedSuggestion() {
kDefaultMaxAgeForAdditionalPrefetchedSuggestion.InMinutes()));
}
+// Whether notifications for fetched suggestions are enabled. Note that this
+// param does not overwrite other switches which could disable these
+// notifications.
+const bool kEnableFetchedSuggestionsNotificationsDefault = true;
+const char kEnableFetchedSuggestionsNotificationsParamName[] =
+ "enable_fetched_suggestions_notifications";
+
+bool IsFetchedSuggestionsNotificationsEnabled() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ ntp_snippets::kNotificationsFeature,
+ kEnableFetchedSuggestionsNotificationsParamName,
+ kEnableFetchedSuggestionsNotificationsDefault);
+}
+
+// Whether notifications for pushed (prepended) suggestions are enabled. Note
+// that this param does not overwrite other switches which could disable these
+// notifications.
+const bool kEnablePushedSuggestionsNotificationsDefault = false;
+const char kEnablePushedSuggestionsNotificationsParamName[] =
+ "enable_pushed_suggestions_notifications";
+
+bool IsPushedSuggestionsNotificationsEnabled() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ ntp_snippets::kNotificationsFeature,
+ kEnablePushedSuggestionsNotificationsParamName,
+ kEnablePushedSuggestionsNotificationsDefault);
+}
+
+// Whether signed-in users should be subscribed for pushed suggestions.
+const bool kEnableSignedInUsersSubscriptionForPushedSuggestionsDefault = true;
+const char kEnableSignedInUsersSubscriptionForPushedSuggestionsParamName[] =
+ "enable_signed_in_users_subscription_for_pushed_suggestions";
+
+bool IsSignedInUsersSubscriptionForPushedSuggestionsEnabled() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ ntp_snippets::kBreakingNewsPushFeature,
+ kEnableSignedInUsersSubscriptionForPushedSuggestionsParamName,
+ kEnableSignedInUsersSubscriptionForPushedSuggestionsDefault);
+}
+
+// Whether signed-out users should be subscribed for pushed suggestions.
+const bool kEnableSignedOutUsersSubscriptionForPushedSuggestionsDefault = false;
+const char kEnableSignedOutUsersSubscriptionForPushedSuggestionsParamName[] =
+ "enable_signed_out_users_subscription_for_pushed_suggestions";
+
+bool IsSignedOutUsersSubscriptionForPushedSuggestionsEnabled() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ ntp_snippets::kBreakingNewsPushFeature,
+ kEnableSignedOutUsersSubscriptionForPushedSuggestionsParamName,
+ kEnableSignedOutUsersSubscriptionForPushedSuggestionsDefault);
+}
+
+// Whether notification info is overriden for fetched suggestions. Note that
+// this param does not overwrite other switches which could disable these
+// notifications.
+const bool kForceFetchedSuggestionsNotificationsDefault = false;
+const char kForceFetchedSuggestionsNotificationsParamName[] =
+ "force_fetched_suggestions_notifications";
+
+bool ShouldForceFetchedSuggestionsNotifications() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ ntp_snippets::kNotificationsFeature,
+ kForceFetchedSuggestionsNotificationsParamName,
+ kForceFetchedSuggestionsNotificationsDefault);
+}
+
template <typename SuggestionPtrContainer>
std::unique_ptr<std::vector<std::string>> GetSuggestionIDVector(
const SuggestionPtrContainer& suggestions) {
@@ -223,12 +291,11 @@ std::vector<ContentSuggestion> ConvertToContentSuggestions(
return result;
}
-void CallWithEmptyResults(const FetchDoneCallback& callback,
- const Status& status) {
+void CallWithEmptyResults(FetchDoneCallback callback, const Status& status) {
if (callback.is_null()) {
return;
}
- callback.Run(status, std::vector<ContentSuggestion>());
+ std::move(callback).Run(status, std::vector<ContentSuggestion>());
}
void AddDismissedIdsToRequest(const RemoteSuggestion::PtrVector& dismissed,
@@ -242,6 +309,21 @@ void AddDismissedIdsToRequest(const RemoteSuggestion::PtrVector& dismissed,
}
}
+void AddDismissedArchivedIdsToRequest(
+ const base::circular_deque<std::unique_ptr<RemoteSuggestion>>& archived,
+ RequestParams* request_params) {
+ // We add all archived, dismissed IDs to the request (the archive is limited
+ // to kMaxArchivedSuggestionCount suggestions). They don't get persisted,
+ // which means that the user very recently dismissed them and that they are
+ // usually not many.
+ for (auto it = archived.begin(); it != archived.end(); ++it) {
+ const RemoteSuggestion& suggestion = **it;
+ if (suggestion.is_dismissed()) {
+ request_params->excluded_ids.insert(suggestion.id());
+ }
+ }
+}
+
} // namespace
RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
@@ -254,7 +336,8 @@ RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
std::unique_ptr<RemoteSuggestionsDatabase> database,
std::unique_ptr<RemoteSuggestionsStatusService> status_service,
- std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker)
+ std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker,
+ std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider)
: RemoteSuggestionsProvider(observer),
state_(State::NOT_INITED),
pref_service_(pref_service),
@@ -271,7 +354,9 @@ RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
fetch_when_ready_interactive_(false),
clear_history_dependent_state_when_initialized_(false),
clock_(base::MakeUnique<base::DefaultClock>()),
- prefetched_pages_tracker_(std::move(prefetched_pages_tracker)) {
+ prefetched_pages_tracker_(std::move(prefetched_pages_tracker)),
+ breaking_news_raw_data_provider_(
+ std::move(breaking_news_raw_data_provider)) {
RestoreCategoriesFromPrefs();
// The articles category always exists. Add it if we didn't get it from prefs.
// TODO(treib): Rethink this.
@@ -300,7 +385,12 @@ RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
base::Unretained(this)));
}
-RemoteSuggestionsProviderImpl::~RemoteSuggestionsProviderImpl() = default;
+RemoteSuggestionsProviderImpl::~RemoteSuggestionsProviderImpl() {
+ if (breaking_news_raw_data_provider_ &&
+ breaking_news_raw_data_provider_->IsListening()) {
+ breaking_news_raw_data_provider_->StopListening();
+ }
+}
// static
void RemoteSuggestionsProviderImpl::RegisterProfilePrefs(
@@ -308,7 +398,7 @@ void RemoteSuggestionsProviderImpl::RegisterProfilePrefs(
registry->RegisterListPref(prefs::kRemoteSuggestionCategories);
registry->RegisterInt64Pref(prefs::kLastSuccessfulBackgroundFetchTime, 0);
- RemoteSuggestionsStatusService::RegisterProfilePrefs(registry);
+ RemoteSuggestionsStatusServiceImpl::RegisterProfilePrefs(registry);
}
void RemoteSuggestionsProviderImpl::ReloadSuggestions() {
@@ -325,8 +415,8 @@ void RemoteSuggestionsProviderImpl::ReloadSuggestions() {
}
void RemoteSuggestionsProviderImpl::RefetchInTheBackground(
- const FetchStatusCallback& callback) {
- FetchSuggestions(/*interactive_request=*/false, callback);
+ FetchStatusCallback callback) {
+ FetchSuggestions(/*interactive_request=*/false, std::move(callback));
}
const RemoteSuggestionsFetcher*
@@ -354,11 +444,11 @@ bool RemoteSuggestionsProviderImpl::IsDisabled() const {
void RemoteSuggestionsProviderImpl::FetchSuggestions(
bool interactive_request,
- const FetchStatusCallback& callback) {
+ FetchStatusCallback callback) {
if (!ready()) {
fetch_when_ready_ = true;
fetch_when_ready_interactive_ = interactive_request;
- fetch_when_ready_callback_ = callback;
+ fetch_when_ready_callback_ = std::move(callback);
return;
}
@@ -367,35 +457,35 @@ void RemoteSuggestionsProviderImpl::FetchSuggestions(
RequestParams params = BuildFetchParams(/*fetched_category=*/base::nullopt);
params.interactive_request = interactive_request;
suggestions_fetcher_->FetchSnippets(
- params,
- base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchFinished,
- base::Unretained(this), callback, interactive_request));
+ params, base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchFinished,
+ base::Unretained(this), std::move(callback),
+ interactive_request));
}
void RemoteSuggestionsProviderImpl::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
if (!ready()) {
- CallWithEmptyResults(callback,
+ CallWithEmptyResults(std::move(callback),
Status(StatusCode::TEMPORARY_ERROR,
"RemoteSuggestionsProvider is not ready!"));
return;
}
if (!remote_suggestions_scheduler_->AcquireQuotaForInteractiveFetch()) {
- CallWithEmptyResults(callback, Status(StatusCode::TEMPORARY_ERROR,
- "Interactive quota exceeded!"));
+ CallWithEmptyResults(
+ std::move(callback),
+ Status(StatusCode::TEMPORARY_ERROR, "Interactive quota exceeded!"));
return;
}
// Make sure after the fetch, the scheduler is informed about the status.
- FetchDoneCallback callback_wrapper = base::Bind(
- [](RemoteSuggestionsScheduler* scheduler,
- const FetchDoneCallback& callback, Status status_code,
- std::vector<ContentSuggestion> suggestions) {
+ FetchDoneCallback callback_wrapper = base::BindOnce(
+ [](RemoteSuggestionsScheduler* scheduler, FetchDoneCallback callback,
+ Status status_code, std::vector<ContentSuggestion> suggestions) {
scheduler->OnInteractiveFetchFinished(status_code);
- callback.Run(status_code, std::move(suggestions));
+ std::move(callback).Run(status_code, std::move(suggestions));
},
- base::Unretained(remote_suggestions_scheduler_), callback);
+ base::Unretained(remote_suggestions_scheduler_), std::move(callback));
RequestParams params = BuildFetchParams(category);
params.excluded_ids.insert(known_suggestion_ids.begin(),
@@ -406,7 +496,7 @@ void RemoteSuggestionsProviderImpl::Fetch(
suggestions_fetcher_->FetchSnippets(
params,
base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchMoreFinished,
- base::Unretained(this), callback_wrapper));
+ base::Unretained(this), std::move(callback_wrapper)));
}
// Builds default fetcher params.
@@ -419,14 +509,17 @@ RequestParams RemoteSuggestionsProviderImpl::BuildFetchParams(
// added first to truncate them less.
if (fetched_category.has_value()) {
DCHECK(category_contents_.count(*fetched_category));
- AddDismissedIdsToRequest(
- category_contents_.find(*fetched_category)->second.dismissed, &result);
+ const CategoryContent& content =
+ category_contents_.find(*fetched_category)->second;
+ AddDismissedIdsToRequest(content.dismissed, &result);
+ AddDismissedArchivedIdsToRequest(content.archived, &result);
}
for (const auto& map_entry : category_contents_) {
if (fetched_category.has_value() && map_entry.first == *fetched_category) {
continue;
}
AddDismissedIdsToRequest(map_entry.second.dismissed, &result);
+ AddDismissedArchivedIdsToRequest(map_entry.second.archived, &result);
}
return result;
}
@@ -514,10 +607,10 @@ void RemoteSuggestionsProviderImpl::OnSignInStateChanged() {
void RemoteSuggestionsProviderImpl::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
auto content_it = category_contents_.find(category);
DCHECK(content_it != category_contents_.end());
- callback.Run(
+ std::move(callback).Run(
ConvertToContentSuggestions(category, content_it->second.dismissed));
}
@@ -531,14 +624,16 @@ void RemoteSuggestionsProviderImpl::ClearDismissedSuggestionsForDebugging(
return;
}
- if (content->dismissed.empty()) {
- return;
+ if (!content->dismissed.empty()) {
+ database_->DeleteSnippets(GetSuggestionIDVector(content->dismissed));
+ // The image got already deleted when the suggestion was dismissed.
+ content->dismissed.clear();
}
- database_->DeleteSnippets(GetSuggestionIDVector(content->dismissed));
- // The image got already deleted when the suggestion was dismissed.
-
- content->dismissed.clear();
+ // Update the archive.
+ for (const auto& suggestion : content->archived) {
+ suggestion->set_dismissed(false);
+ }
}
// static
@@ -601,12 +696,17 @@ void RemoteSuggestionsProviderImpl::OnDatabaseLoaded(
}
// Sort the suggestions in each category.
- // TODO(treib): Persist the actual order in the DB somehow? crbug.com/654409
for (auto& entry : category_contents_) {
CategoryContent* content = &entry.second;
std::sort(content->suggestions.begin(), content->suggestions.end(),
[](const std::unique_ptr<RemoteSuggestion>& lhs,
const std::unique_ptr<RemoteSuggestion>& rhs) {
+ if (lhs->rank() != rhs->rank()) {
+ return lhs->rank() < rhs->rank();
+ }
+ // Suggestion created before the rank was introduced have rank
+ // equal to INT_MAX by default. Sort them by score.
+ // TODO(vitaliii): Remove this fallback (and its test) in M64.
return lhs->score() > rhs->score();
});
}
@@ -625,18 +725,18 @@ void RemoteSuggestionsProviderImpl::OnDatabaseError() {
}
void RemoteSuggestionsProviderImpl::OnFetchMoreFinished(
- const FetchDoneCallback& fetching_callback,
+ FetchDoneCallback fetching_callback,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories) {
if (!fetched_categories) {
DCHECK(!status.IsSuccess());
- CallWithEmptyResults(fetching_callback, status);
+ CallWithEmptyResults(std::move(fetching_callback), status);
return;
}
if (fetched_categories->size() != 1u) {
LOG(DFATAL) << "Requested one exclusive category but received "
<< fetched_categories->size() << " categories.";
- CallWithEmptyResults(fetching_callback,
+ CallWithEmptyResults(std::move(fetching_callback),
Status(StatusCode::PERMANENT_ERROR,
"RemoteSuggestionsProvider received more "
"categories than requested."));
@@ -655,11 +755,11 @@ void RemoteSuggestionsProviderImpl::OnFetchMoreFinished(
// |fetched_category.suggestions|.
ArchiveSuggestions(existing_content, &fetched_category.suggestions);
- fetching_callback.Run(Status::Success(), std::move(result));
+ std::move(fetching_callback).Run(Status::Success(), std::move(result));
}
void RemoteSuggestionsProviderImpl::OnFetchFinished(
- const FetchStatusCallback& callback,
+ FetchStatusCallback callback,
bool interactive_request,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories) {
@@ -669,18 +769,43 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
return;
}
+ if (!status.IsSuccess()) {
+ if (callback) {
+ std::move(callback).Run(status);
+ }
+ return;
+ }
+
if (IsKeepingPrefetchedSuggestionsEnabled() && prefetched_pages_tracker_ &&
!prefetched_pages_tracker_->IsInitialized()) {
// Wait until the tracker is initialized.
prefetched_pages_tracker_->AddInitializationCompletedCallback(
base::BindOnce(&RemoteSuggestionsProviderImpl::OnFetchFinished,
- base::Unretained(this), callback, interactive_request,
- status, std::move(fetched_categories)));
+ base::Unretained(this), std::move(callback),
+ interactive_request, status,
+ std::move(fetched_categories)));
return;
}
+ if (fetched_categories) {
+ for (FetchedCategory& fetched_category : *fetched_categories) {
+ for (std::unique_ptr<RemoteSuggestion>& suggestion :
+ fetched_category.suggestions) {
+ if (ShouldForceFetchedSuggestionsNotifications() &&
+ IsFetchedSuggestionsNotificationsEnabled()) {
+ suggestion->set_should_notify(true);
+ suggestion->set_notification_deadline(clock_->Now() +
+ base::TimeDelta::FromDays(7));
+ }
+ if (!IsFetchedSuggestionsNotificationsEnabled()) {
+ suggestion->set_should_notify(false);
+ }
+ }
+ }
+ }
+
// Record the fetch time of a successfull background fetch.
- if (!interactive_request && status.IsSuccess()) {
+ if (!interactive_request) {
pref_service_->SetInt64(prefs::kLastSuccessfulBackgroundFetchTime,
clock_->Now().ToInternalValue());
}
@@ -697,8 +822,7 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
ClearExpiredDismissedSuggestions();
// If suggestions were fetched successfully, update our |category_contents_|
- // from
- // each category provided by the server.
+ // from each category provided by the server.
if (fetched_categories) {
// TODO(treib): Reorder |category_contents_| to match the order we received
// from the server. crbug.com/653816
@@ -733,6 +857,18 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
category_ranker_->AppendCategoryIfNecessary(fetched_category.category);
}
}
+
+ // Delete categories not present in this fetch.
+ std::vector<Category> categories_to_delete;
+ for (auto& item : category_contents_) {
+ Category category = item.first;
+ CategoryContent* content = &item.second;
+ if (!content->included_in_last_server_response &&
+ category != articles_category_) {
+ categories_to_delete.push_back(category);
+ }
+ }
+ DeleteCategories(categories_to_delete);
}
// TODO(tschumann): The suggestions fetcher needs to signal errors so that we
@@ -743,11 +879,18 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
// ones), so update the pref.
StoreCategoriesToPrefs();
- for (const auto& item : category_contents_) {
+ for (auto& item : category_contents_) {
Category category = item.first;
UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
// TODO(sfiera): notify only when a category changed above.
NotifyNewSuggestions(category, item.second);
+
+ // The suggestions may be reused (e.g. when prepending an article), avoid
+ // trigering notifications for the second time.
+ for (std::unique_ptr<RemoteSuggestion>& suggestion :
+ item.second.suggestions) {
+ suggestion->set_should_notify(false);
+ }
}
// TODO(sfiera): equivalent metrics for non-articles.
@@ -762,7 +905,7 @@ void RemoteSuggestionsProviderImpl::OnFetchFinished(
}
if (callback) {
- callback.Run(status);
+ std::move(callback).Run(status);
}
}
@@ -801,15 +944,6 @@ void RemoteSuggestionsProviderImpl::IntegrateSuggestions(
RemoteSuggestion::PtrVector new_suggestions) {
DCHECK(ready());
- // Do not touch the current set of suggestions if the newly fetched one is
- // empty.
- // TODO(tschumann): This should go. If we get empty results we should update
- // accordingly and remove the old one (only of course if this was not received
- // through a fetch-more).
- if (new_suggestions.empty()) {
- return;
- }
-
// It's entirely possible that the newly fetched suggestions contain articles
// that have been present before.
// We need to make sure to only delete and archive suggestions that don't
@@ -867,34 +1001,110 @@ void RemoteSuggestionsProviderImpl::IntegrateSuggestions(
// Note, that ArchiveSuggestions will clear |content->suggestions|.
ArchiveSuggestions(content, &content->suggestions);
+ // TODO(vitaliii): Move rank logic into the database. It will set ranks and
+ // return already sorted suggestions.
+ for (size_t i = 0; i < new_suggestions.size(); ++i) {
+ new_suggestions[i]->set_rank(i);
+ }
database_->SaveSnippets(new_suggestions);
content->suggestions = std::move(new_suggestions);
}
+void RemoteSuggestionsProviderImpl::PrependArticleSuggestion(
+ std::unique_ptr<RemoteSuggestion> remote_suggestion) {
+ if (!ready()) {
+ return;
+ }
+
+ if (!IsPushedSuggestionsNotificationsEnabled()) {
+ remote_suggestion->set_should_notify(false);
+ }
+
+ ClearExpiredDismissedSuggestions();
+
+ DCHECK_EQ(articles_category_, Category::FromRemoteCategory(
+ remote_suggestion->remote_category_id()));
+
+ auto content_it = category_contents_.find(articles_category_);
+ if (content_it == category_contents_.end()) {
+ return;
+ }
+ CategoryContent* content = &content_it->second;
+
+ std::vector<std::unique_ptr<RemoteSuggestion>> suggestions;
+ suggestions.push_back(std::move(remote_suggestion));
+
+ SanitizeReceivedSuggestions(content->dismissed, &suggestions);
+
+ if (!suggestions.empty()) {
+ content->suggestions.insert(content->suggestions.begin(),
+ std::move(suggestions[0]));
+
+ for (size_t i = 0; i < content->suggestions.size(); ++i) {
+ content->suggestions[i]->set_rank(i);
+ }
+
+ NotifyNewSuggestions(articles_category_, *content);
+
+ // Avoid triggering the pushed suggestion notification for the second time
+ // (e.g. when another suggestions is pushed).
+ content->suggestions[0]->set_should_notify(false);
+
+ database_->SaveSnippets(content->suggestions);
+ }
+}
+
void RemoteSuggestionsProviderImpl::DismissSuggestionFromCategoryContent(
CategoryContent* content,
const std::string& id_within_category) {
- auto it =
- std::find_if(content->suggestions.begin(), content->suggestions.end(),
- [&id_within_category](
- const std::unique_ptr<RemoteSuggestion>& suggestion) {
- return suggestion->id() == id_within_category;
- });
- if (it == content->suggestions.end()) {
- return;
+ auto id_predicate = [&id_within_category](
+ const std::unique_ptr<RemoteSuggestion>& suggestion) {
+ return suggestion->id() == id_within_category;
+ };
+
+ auto it = std::find_if(content->suggestions.begin(),
+ content->suggestions.end(), id_predicate);
+ if (it != content->suggestions.end()) {
+ (*it)->set_dismissed(true);
+ database_->SaveSnippet(**it);
+ content->dismissed.push_back(std::move(*it));
+ content->suggestions.erase(it);
+ } else {
+ // Check the archive.
+ auto archive_it = std::find_if(content->archived.begin(),
+ content->archived.end(), id_predicate);
+ if (archive_it != content->archived.end()) {
+ (*archive_it)->set_dismissed(true);
+ }
}
+}
- (*it)->set_dismissed(true);
+void RemoteSuggestionsProviderImpl::DeleteCategories(
+ const std::vector<Category>& categories) {
+ for (Category category : categories) {
+ auto it = category_contents_.find(category);
+ if (it == category_contents_.end()) {
+ continue;
+ }
+ const CategoryContent& content = it->second;
- database_->SaveSnippet(**it);
+ UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
- content->dismissed.push_back(std::move(*it));
- content->suggestions.erase(it);
+ if (!content.suggestions.empty()) {
+ database_->DeleteImages(GetSuggestionIDVector(content.suggestions));
+ database_->DeleteSnippets(GetSuggestionIDVector(content.suggestions));
+ }
+ if (!content.dismissed.empty()) {
+ database_->DeleteImages(GetSuggestionIDVector(content.dismissed));
+ database_->DeleteSnippets(GetSuggestionIDVector(content.dismissed));
+ }
+ category_contents_.erase(it);
+ }
}
void RemoteSuggestionsProviderImpl::ClearExpiredDismissedSuggestions() {
- std::vector<Category> categories_to_erase;
+ std::vector<Category> categories_to_delete;
const base::Time now = base::Time::Now();
@@ -919,15 +1129,11 @@ void RemoteSuggestionsProviderImpl::ClearExpiredDismissedSuggestions() {
if (content->suggestions.empty() && content->dismissed.empty() &&
category != articles_category_ &&
!content->included_in_last_server_response) {
- categories_to_erase.push_back(category);
+ categories_to_delete.push_back(category);
}
}
- for (Category category : categories_to_erase) {
- UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
- category_contents_.erase(category);
- }
-
+ DeleteCategories(categories_to_delete);
StoreCategoriesToPrefs();
}
@@ -983,10 +1189,10 @@ void RemoteSuggestionsProviderImpl::NukeAllSuggestions() {
void RemoteSuggestionsProviderImpl::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
if (!base::ContainsKey(category_contents_, suggestion_id.category())) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
return;
}
GURL image_url = FindSuggestionImageUrl(suggestion_id);
@@ -995,10 +1201,11 @@ void RemoteSuggestionsProviderImpl::FetchSuggestionImage(
// find it in the database (and also can't fetch it remotely). Cut the
// lookup short and return directly.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
return;
}
- image_fetcher_.FetchSuggestionImage(suggestion_id, image_url, callback);
+ image_fetcher_.FetchSuggestionImage(suggestion_id, image_url,
+ std::move(callback));
}
void RemoteSuggestionsProviderImpl::EnterStateReady() {
@@ -1010,7 +1217,8 @@ void RemoteSuggestionsProviderImpl::EnterStateReady() {
auto article_category_it = category_contents_.find(articles_category_);
DCHECK(article_category_it != category_contents_.end());
if (fetch_when_ready_) {
- FetchSuggestions(fetch_when_ready_interactive_, fetch_when_ready_callback_);
+ FetchSuggestions(fetch_when_ready_interactive_,
+ std::move(fetch_when_ready_callback_));
fetch_when_ready_ = false;
}
@@ -1027,12 +1235,53 @@ void RemoteSuggestionsProviderImpl::EnterStateReady() {
void RemoteSuggestionsProviderImpl::EnterStateDisabled() {
ClearSuggestions();
+ if (breaking_news_raw_data_provider_ &&
+ breaking_news_raw_data_provider_->IsListening()) {
+ breaking_news_raw_data_provider_->StopListening();
+ }
}
void RemoteSuggestionsProviderImpl::EnterStateError() {
status_service_.reset();
}
+void RemoteSuggestionsProviderImpl::
+ UpdatePushedSuggestionsSubscriptionDueToStatusChange(
+ RemoteSuggestionsStatus new_status) {
+ if (!breaking_news_raw_data_provider_) {
+ return;
+ }
+
+ bool should_be_subscribed = false;
+ switch (new_status) {
+ case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN:
+ should_be_subscribed =
+ IsSignedInUsersSubscriptionForPushedSuggestionsEnabled();
+ break;
+
+ case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT:
+ should_be_subscribed =
+ IsSignedOutUsersSubscriptionForPushedSuggestionsEnabled();
+ break;
+
+ case RemoteSuggestionsStatus::EXPLICITLY_DISABLED:
+ should_be_subscribed = false;
+ break;
+ }
+
+ if (should_be_subscribed) {
+ if (!breaking_news_raw_data_provider_->IsListening()) {
+ breaking_news_raw_data_provider_->StartListening(
+ base::Bind(&RemoteSuggestionsProviderImpl::PrependArticleSuggestion,
+ base::Unretained(this)));
+ }
+ } else {
+ if (breaking_news_raw_data_provider_->IsListening()) {
+ breaking_news_raw_data_provider_->StopListening();
+ }
+ }
+}
+
void RemoteSuggestionsProviderImpl::FinishInitialization() {
if (clear_history_dependent_state_when_initialized_) {
// We clear here in addition to EnterStateReady, so that it happens even if
@@ -1092,6 +1341,8 @@ void RemoteSuggestionsProviderImpl::OnStatusChanged(
UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED);
break;
}
+
+ UpdatePushedSuggestionsSubscriptionDueToStatusChange(new_status);
}
void RemoteSuggestionsProviderImpl::EnterState(State state) {
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index ef70fc46b17..f450c3c140e 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -6,7 +6,6 @@
#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_PROVIDER_IMPL_H_
#include <cstddef>
-#include <deque>
#include <map>
#include <memory>
#include <set>
@@ -15,6 +14,7 @@
#include <vector>
#include "base/callback_forward.h"
+#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/optional.h"
@@ -43,6 +43,7 @@ class ImageFetcher;
namespace ntp_snippets {
+class BreakingNewsListener;
class CategoryRanker;
class RemoteSuggestionsDatabase;
class RemoteSuggestionsScheduler;
@@ -68,7 +69,8 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
std::unique_ptr<RemoteSuggestionsDatabase> database,
std::unique_ptr<RemoteSuggestionsStatusService> status_service,
- std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker);
+ std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker,
+ std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider);
~RemoteSuggestionsProviderImpl() override;
@@ -84,7 +86,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
bool initialized() const { return ready() || state_ == State::DISABLED; }
// RemoteSuggestionsProvider implementation.
- void RefetchInTheBackground(const FetchStatusCallback& callback) override;
+ void RefetchInTheBackground(FetchStatusCallback callback) override;
// TODO(fhorschig): Remove this getter when there is an interface for the
// fetcher that allows better mocks.
@@ -101,10 +103,10 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ReloadSuggestions() override;
void ClearHistory(
base::Time begin,
@@ -114,7 +116,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
void OnSignInStateChanged() override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
// Returns the maximum number of suggestions that will be shown at once.
@@ -142,6 +144,10 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// the constructor.
CachedImageFetcher& GetImageFetcherForTesting() { return image_fetcher_; }
+ BreakingNewsListener* breaking_news_listener_for_debugging() {
+ return breaking_news_raw_data_provider_.get();
+ }
+
private:
friend class RemoteSuggestionsProviderImplTest;
@@ -207,10 +213,10 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// The additional information about a category.
CategoryInfo info;
+ // TODO(vitaliii): Remove this field. It is always true, because we now
+ // remove categories not included in the last fetch.
// True iff the server returned results in this category in the last fetch.
- // We never remove categories that the server still provides, but if the
- // server stops providing a category, we won't yet report it as NOT_PROVIDED
- // while we still have non-expired suggestions in it.
+ // We never remove categories that the server still provides.
bool included_in_last_server_response = true;
// All currently active suggestions (excl. the dismissed ones).
@@ -220,7 +226,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// be on some open NTP. We do not persist this list so that on a new start
// of Chrome, this is empty.
// |archived| is a FIFO buffer with a maximum length.
- std::deque<std::unique_ptr<RemoteSuggestion>> archived;
+ base::circular_deque<std::unique_ptr<RemoteSuggestion>> archived;
// Suggestions that the user dismissed. We keep these around until they
// expire so we won't re-add them to |suggestions| on the next fetch.
@@ -243,8 +249,7 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// quota for requests, etc.), useful for requests triggered by the user. After
// the fetch finished, the provided |callback| will be triggered with the
// status of the fetch.
- void FetchSuggestions(bool interactive_request,
- const FetchStatusCallback& callback);
+ void FetchSuggestions(bool interactive_request, FetchStatusCallback callback);
// Returns the URL of the image of a suggestion if it is among the current or
// among the archived suggestions in the matching category. Returns an empty
@@ -257,13 +262,13 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// Callback for fetch-more requests with the RemoteSuggestionsFetcher.
void OnFetchMoreFinished(
- const FetchDoneCallback& fetching_callback,
+ FetchDoneCallback fetching_callback,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories);
// Callback for regular fetch requests with the RemoteSuggestionsFetcher.
void OnFetchFinished(
- const FetchStatusCallback& callback,
+ FetchStatusCallback callback,
bool interactive_request,
Status status,
RemoteSuggestionsFetcher::OptionalFetchedCategories fetched_categories);
@@ -286,6 +291,10 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
CategoryContent* content,
RemoteSuggestion::PtrVector new_suggestions);
+ // Adds newly available suggestion at the top of Articles category.
+ void PrependArticleSuggestion(
+ std::unique_ptr<RemoteSuggestion> remote_suggestion);
+
// Dismisses a suggestion within a given category content.
// Note that this modifies the suggestion datastructures of |content|
// invalidating iterators.
@@ -293,6 +302,10 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
CategoryContent* content,
const std::string& id_within_category);
+ // Sets categories status to NOT_PROVIDED and deletes them (including their
+ // suggestions from the database).
+ void DeleteCategories(const std::vector<Category>& categories);
+
// Removes expired dismissed suggestions from the service and the database.
void ClearExpiredDismissedSuggestions();
@@ -340,6 +353,11 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// Do not call directly, use |EnterState| instead.
void EnterStateError();
+ // Subscribes or unsubcribes from pushed suggestions depending on the new
+ // status.
+ void UpdatePushedSuggestionsSubscriptionDueToStatusChange(
+ RemoteSuggestionsStatus new_status);
+
// Converts the cached suggestions in the given |category| to content
// suggestions and notifies the observer.
void NotifyNewSuggestions(Category category, const CategoryContent& content);
@@ -395,6 +413,11 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
// The service that provides events and data about the signin and sync state.
std::unique_ptr<RemoteSuggestionsStatusService> status_service_;
+ // TODO(tschumann): All "fetch-when-available" logic should live in the
+ // RemoteSuggestionsScheduler. Remove this here. Instead, the scheduler should
+ // also call ready() before forwarding requests. If the provider becomes
+ // ready, it calls OnProviderActivated() which will process triggers queued in
+ // the scheduler.
// Set to true if FetchSuggestions is called while the service isn't ready.
// The fetch will be executed once the service enters the READY state.
// TODO(jkrcal): create a struct and have here just one base::Optional<>?
@@ -413,8 +436,13 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
std::unique_ptr<base::Clock> clock_;
// Prefetched pages tracker to query which urls have been prefetched.
+ // |nullptr| is handled gracefully and just disables the functionality.
std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker_;
+ // Listens for BreakingNews updates (e.g. through GCM) and notifies the
+ // provider.
+ std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider_;
+
DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProviderImpl);
};
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index 116dbad428b..ae50314ca57 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
+#include <limits>
#include <map>
#include <memory>
#include <string>
@@ -16,22 +17,21 @@
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/simple_test_clock.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/image_fetcher.h"
#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "components/image_fetcher/core/request_metadata.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_info.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
@@ -45,10 +45,14 @@
#include "components/ntp_snippets/remote/persistent_scheduler.h"
#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
#include "components/ntp_snippets/remote/remote_suggestion.h"
+#include "components/ntp_snippets/remote/remote_suggestion_builder.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h"
#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service_impl.h"
#include "components/ntp_snippets/remote/test_utils.h"
+#include "components/ntp_snippets/time_serialization.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
@@ -64,15 +68,21 @@
using image_fetcher::ImageFetcher;
using image_fetcher::ImageFetcherDelegate;
+using ntp_snippets::test::FetchedCategoryBuilder;
+using ntp_snippets::test::RemoteSuggestionBuilder;
using testing::_;
+using testing::AnyNumber;
+using testing::AtMost;
using testing::Contains;
using testing::CreateFunctor;
using testing::ElementsAre;
+using testing::ElementsAreArray;
using testing::Eq;
using testing::Field;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
+using testing::Matcher;
using testing::Mock;
using testing::MockFunction;
using testing::NiceMock;
@@ -138,8 +148,8 @@ std::unique_ptr<RemoteSuggestion> CreateTestRemoteSuggestion(
snippet_proto.set_title("title");
snippet_proto.set_snippet("snippet");
snippet_proto.set_salient_image_url(url + "p.jpg");
- snippet_proto.set_publish_date(GetDefaultCreationTime().ToTimeT());
- snippet_proto.set_expiry_date(GetDefaultExpirationTime().ToTimeT());
+ snippet_proto.set_publish_date(SerializeTime(GetDefaultCreationTime()));
+ snippet_proto.set_expiry_date(SerializeTime(GetDefaultExpirationTime()));
snippet_proto.set_remote_category_id(1);
auto* source = snippet_proto.add_sources();
source->set_url(url);
@@ -148,177 +158,6 @@ std::unique_ptr<RemoteSuggestion> CreateTestRemoteSuggestion(
return RemoteSuggestion::CreateFromProto(snippet_proto);
}
-class RemoteSuggestionBuilder {
- public:
- RemoteSuggestionBuilder() = default;
-
- RemoteSuggestionBuilder& AddId(const std::string& id) {
- if (!ids_) {
- ids_ = std::vector<std::string>();
- }
- ids_->push_back(id);
- return *this;
- }
- RemoteSuggestionBuilder& SetTitle(const std::string& title) {
- title_ = title;
- return *this;
- }
- RemoteSuggestionBuilder& SetSnippet(const std::string& snippet) {
- snippet_ = snippet;
- return *this;
- }
- RemoteSuggestionBuilder& SetImageUrl(const std::string& image_url) {
- salient_image_url_ = image_url;
- return *this;
- }
- RemoteSuggestionBuilder& SetPublishDate(const base::Time& publish_date) {
- publish_date_ = publish_date;
- return *this;
- }
- RemoteSuggestionBuilder& SetExpiryDate(const base::Time& expiry_date) {
- expiry_date_ = expiry_date;
- return *this;
- }
- RemoteSuggestionBuilder& SetScore(double score) {
- score_ = score;
- return *this;
- }
- RemoteSuggestionBuilder& SetIsDismissed(bool is_dismissed) {
- is_dismissed_ = is_dismissed;
- return *this;
- }
- RemoteSuggestionBuilder& SetRemoteCategoryId(int remote_category_id) {
- remote_category_id_ = remote_category_id;
- return *this;
- }
- RemoteSuggestionBuilder& SetUrl(const std::string& url) {
- url_ = url;
- return *this;
- }
- RemoteSuggestionBuilder& SetPublisher(const std::string& publisher) {
- publisher_name_ = publisher;
- return *this;
- }
- RemoteSuggestionBuilder& SetAmpUrl(const std::string& amp_url) {
- amp_url_ = amp_url;
- return *this;
- }
- RemoteSuggestionBuilder& SetFetchDate(const base::Time& fetch_date) {
- fetch_date_ = fetch_date;
- return *this;
- }
-
- std::unique_ptr<RemoteSuggestion> Build() const {
- SnippetProto proto;
- proto.set_title(title_.value_or("Title"));
- proto.set_snippet(snippet_.value_or("Snippet"));
- proto.set_salient_image_url(
- salient_image_url_.value_or("http://image_url.com/"));
- proto.set_publish_date(
- publish_date_.value_or(GetDefaultCreationTime()).ToInternalValue());
- proto.set_expiry_date(
- expiry_date_.value_or(GetDefaultExpirationTime()).ToInternalValue());
- proto.set_score(score_.value_or(1));
- proto.set_dismissed(is_dismissed_.value_or(false));
- proto.set_remote_category_id(remote_category_id_.value_or(1));
- auto* source = proto.add_sources();
- source->set_url(url_.value_or("http://url.com/"));
- source->set_publisher_name(publisher_name_.value_or("Publisher"));
- source->set_amp_url(amp_url_.value_or("http://amp_url.com/"));
- proto.set_fetch_date(
- fetch_date_.value_or(base::Time::Now()).ToInternalValue());
- for (const auto& id :
- ids_.value_or(std::vector<std::string>{source->url()})) {
- proto.add_ids(id);
- }
- return RemoteSuggestion::CreateFromProto(proto);
- }
-
- private:
- base::Optional<std::vector<std::string>> ids_;
- base::Optional<std::string> title_;
- base::Optional<std::string> snippet_;
- base::Optional<std::string> salient_image_url_;
- base::Optional<base::Time> publish_date_;
- base::Optional<base::Time> expiry_date_;
- base::Optional<double> score_;
- base::Optional<bool> is_dismissed_;
- base::Optional<int> remote_category_id_;
- base::Optional<std::string> url_;
- base::Optional<std::string> publisher_name_;
- base::Optional<std::string> amp_url_;
- base::Optional<base::Time> fetch_date_;
-};
-
-class FetchedCategoryBuilder {
- public:
- FetchedCategoryBuilder() = default;
-
- FetchedCategoryBuilder& SetCategory(Category category) {
- category_ = category;
- return *this;
- }
- FetchedCategoryBuilder& SetTitle(const std::string& title) {
- title_ = base::UTF8ToUTF16(title);
- return *this;
- }
- FetchedCategoryBuilder& SetCardLayout(
- ContentSuggestionsCardLayout card_layout) {
- card_layout_ = card_layout;
- return *this;
- }
- FetchedCategoryBuilder& SetAdditionalAction(
- ContentSuggestionsAdditionalAction additional_action) {
- additional_action_ = additional_action;
- return *this;
- }
- FetchedCategoryBuilder& SetShowIfEmpty(bool show_if_empty) {
- show_if_empty_ = show_if_empty;
- return *this;
- }
- FetchedCategoryBuilder& SetNoSuggestionsMessage(
- const std::string& no_suggestions_message) {
- no_suggestions_message_ = base::UTF8ToUTF16(no_suggestions_message);
- return *this;
- }
- FetchedCategoryBuilder& AddSuggestionViaBuilder(
- const RemoteSuggestionBuilder& builder) {
- if (!suggestion_builders_) {
- suggestion_builders_ = std::vector<RemoteSuggestionBuilder>();
- }
- suggestion_builders_->push_back(builder);
- return *this;
- }
-
- FetchedCategory Build() const {
- FetchedCategory result = FetchedCategory(
- category_.value_or(Category::FromRemoteCategory(1)),
- CategoryInfo(
- title_.value_or(base::UTF8ToUTF16("Category title")),
- card_layout_.value_or(ContentSuggestionsCardLayout::FULL_CARD),
- additional_action_.value_or(
- ContentSuggestionsAdditionalAction::FETCH),
- show_if_empty_.value_or(false),
- no_suggestions_message_.value_or(
- base::UTF8ToUTF16("No suggestions message"))));
-
- if (suggestion_builders_) {
- for (const auto& suggestion_builder : *suggestion_builders_)
- result.suggestions.push_back(suggestion_builder.Build());
- }
- return result;
- }
-
- private:
- base::Optional<Category> category_;
- base::Optional<base::string16> title_;
- base::Optional<ContentSuggestionsCardLayout> card_layout_;
- base::Optional<ContentSuggestionsAdditionalAction> additional_action_;
- base::Optional<bool> show_if_empty_;
- base::Optional<base::string16> no_suggestions_message_;
- base::Optional<std::vector<RemoteSuggestionBuilder>> suggestion_builders_;
-};
-
using ServeImageCallback = base::Callback<void(
const std::string&,
base::Callback<void(const std::string&,
@@ -434,6 +273,45 @@ class MockPrefetchedPagesTracker : public PrefetchedPagesTracker {
MOCK_CONST_METHOD1(PrefetchedOfflinePageExists, bool(const GURL& url));
};
+class FakeBreakingNewsListener : public BreakingNewsListener {
+ public:
+ ~FakeBreakingNewsListener() override = default;
+
+ // BreakingNewsListener implementation.
+ void StartListening(OnNewRemoteSuggestionCallback callback) override {
+ on_new_remote_suggestion_callback_ = callback;
+ }
+
+ void StopListening() override {
+ on_new_remote_suggestion_callback_ = OnNewRemoteSuggestionCallback();
+ }
+
+ bool IsListening() const override {
+ return !on_new_remote_suggestion_callback_.is_null();
+ }
+
+ void PushSuggestion(std::unique_ptr<RemoteSuggestion> suggestion) {
+ EXPECT_TRUE(IsListening());
+ on_new_remote_suggestion_callback_.Run(std::move(suggestion));
+ }
+
+ private:
+ OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback_;
+};
+
+class MockRemoteSuggestionsStatusService
+ : public RemoteSuggestionsStatusService {
+ public:
+ ~MockRemoteSuggestionsStatusService() override = default;
+
+ MOCK_METHOD1(Init, void(const StatusChangeCallback& callback));
+ MOCK_METHOD0(OnSignInStateChanged, void());
+};
+
+std::string BoolToString(bool value) {
+ return value ? "true" : "false";
+}
+
} // namespace
class RemoteSuggestionsProviderImplTest : public ::testing::Test {
@@ -454,38 +332,67 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
}
~RemoteSuggestionsProviderImplTest() override {
- // We need to run the message loop after deleting the database, because
+ // We need to run until idle after deleting the database, because
// ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
// runner. Without this, we'd get reports of memory leaks.
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
// TODO(vitaliii): Rewrite this function to initialize a test class member
// instead of creating a new provider.
- std::unique_ptr<RemoteSuggestionsProviderImpl> MakeSuggestionsProvider() {
+ std::unique_ptr<RemoteSuggestionsProviderImpl> MakeSuggestionsProvider(
+ bool use_mock_prefetched_pages_tracker,
+ bool use_fake_breaking_news_listener,
+ bool use_mock_remote_suggestions_status_service) {
auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
+ use_mock_prefetched_pages_tracker, use_fake_breaking_news_listener,
+ use_mock_remote_suggestions_status_service);
WaitForSuggestionsProviderInitialization(provider.get());
return provider;
}
std::unique_ptr<RemoteSuggestionsProviderImpl>
MakeSuggestionsProviderWithoutInitialization(
- bool use_mock_prefetched_pages_tracker) {
- scoped_refptr<base::SingleThreadTaskRunner> task_runner(
- base::ThreadTaskRunnerHandle::Get());
-
+ bool use_mock_prefetched_pages_tracker,
+ bool use_fake_breaking_news_listener,
+ bool use_mock_remote_suggestions_status_service) {
utils_.ResetSigninManager();
auto mock_suggestions_fetcher =
base::MakeUnique<StrictMock<MockRemoteSuggestionsFetcher>>();
mock_suggestions_fetcher_ = mock_suggestions_fetcher.get();
- std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker;
+ std::unique_ptr<StrictMock<MockPrefetchedPagesTracker>>
+ mock_prefetched_pages_tracker;
if (use_mock_prefetched_pages_tracker) {
- prefetched_pages_tracker =
+ mock_prefetched_pages_tracker =
base::MakeUnique<StrictMock<MockPrefetchedPagesTracker>>();
}
- prefetched_pages_tracker_ = prefetched_pages_tracker.get();
+ mock_prefetched_pages_tracker_ = mock_prefetched_pages_tracker.get();
+
+ std::unique_ptr<FakeBreakingNewsListener> fake_breaking_news_listener;
+ if (use_fake_breaking_news_listener) {
+ fake_breaking_news_listener =
+ base::MakeUnique<FakeBreakingNewsListener>();
+ }
+ fake_breaking_news_listener_ = fake_breaking_news_listener.get();
+
+ std::unique_ptr<RemoteSuggestionsStatusService>
+ remote_suggestions_status_service;
+ if (use_mock_remote_suggestions_status_service) {
+ auto mock_remote_suggestions_status_service =
+ base::MakeUnique<StrictMock<MockRemoteSuggestionsStatusService>>();
+ EXPECT_CALL(*mock_remote_suggestions_status_service, Init(_))
+ .WillOnce(SaveArg<0>(&status_change_callback_));
+ remote_suggestions_status_service =
+ std::move(mock_remote_suggestions_status_service);
+ } else {
+ remote_suggestions_status_service =
+ base::MakeUnique<RemoteSuggestionsStatusServiceImpl>(
+ utils_.fake_signin_manager(), utils_.pref_service(),
+ std::string());
+ }
+ remote_suggestions_status_service_ =
+ remote_suggestions_status_service.get();
auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>();
@@ -495,23 +402,25 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
.WillByDefault(Return(&image_decoder_));
EXPECT_FALSE(observer_);
observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>();
- auto database = base::MakeUnique<RemoteSuggestionsDatabase>(
- database_dir_.GetPath(), task_runner);
+ auto database =
+ base::MakeUnique<RemoteSuggestionsDatabase>(database_dir_.GetPath());
database_ = database.get();
return base::MakeUnique<RemoteSuggestionsProviderImpl>(
observer_.get(), utils_.pref_service(), "fr", category_ranker_.get(),
scheduler_.get(), std::move(mock_suggestions_fetcher),
std::move(image_fetcher), std::move(database),
- base::MakeUnique<RemoteSuggestionsStatusService>(
- utils_.fake_signin_manager(), utils_.pref_service(), std::string()),
- std::move(prefetched_pages_tracker));
+ std::move(remote_suggestions_status_service),
+ std::move(mock_prefetched_pages_tracker),
+ std::move(fake_breaking_news_listener));
}
std::unique_ptr<RemoteSuggestionsProviderImpl>
MakeSuggestionsProviderWithoutInitializationWithStrictScheduler() {
scheduler_ = base::MakeUnique<StrictMock<MockScheduler>>();
return MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
}
void WaitForSuggestionsProviderInitialization(
@@ -520,18 +429,25 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
provider->state_);
// TODO(treib): Find a better way to wait for initialization to finish.
- base::RunLoop().RunUntilIdle();
- EXPECT_NE(RemoteSuggestionsProviderImpl::State::NOT_INITED,
- provider->state_);
+ RunUntilIdle();
}
void ResetSuggestionsProvider(
- std::unique_ptr<RemoteSuggestionsProviderImpl>* provider) {
+ std::unique_ptr<RemoteSuggestionsProviderImpl>* provider,
+ bool use_mock_prefetched_pages_tracker,
+ bool use_fake_breaking_news_listener,
+ bool use_mock_remote_suggestions_status_service) {
provider->reset();
+ // We need to run until idle after deleting the RemoteSuggestionsDatabase.
+ RunUntilIdle();
observer_.reset();
- *provider = MakeSuggestionsProvider();
+ *provider = MakeSuggestionsProvider(
+ use_mock_prefetched_pages_tracker, use_fake_breaking_news_listener,
+ use_mock_remote_suggestions_status_service);
}
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
void SetCategoryRanker(std::unique_ptr<CategoryRanker> category_ranker) {
category_ranker_ = std::move(category_ranker);
}
@@ -561,8 +477,8 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
StrictMock<MockRemoteSuggestionsFetcher>* mock_suggestions_fetcher() {
return mock_suggestions_fetcher_;
}
- PrefetchedPagesTracker* prefetched_pages_tracker() {
- return prefetched_pages_tracker_;
+ StrictMock<MockPrefetchedPagesTracker>* mock_prefetched_pages_tracker() {
+ return mock_prefetched_pages_tracker_;
}
// TODO(tschumann): Make this a strict-mock. We want to avoid unneccesary
// network requests.
@@ -571,6 +487,9 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
PrefService* pref_service() { return utils_.pref_service(); }
RemoteSuggestionsDatabase* database() { return database_; }
MockScheduler* scheduler() { return scheduler_.get(); }
+ FakeBreakingNewsListener* fake_breaking_news_listener() {
+ return fake_breaking_news_listener_;
+ }
void FetchTheseSuggestions(
RemoteSuggestionsProviderImpl* provider,
@@ -583,9 +502,7 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
.RetiresOnSaturation();
provider->FetchSuggestions(
interactive_request, RemoteSuggestionsProvider::FetchStatusCallback());
- std::move(snippets_callback)
- .Run(Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ std::move(snippets_callback).Run(status, std::move(fetched_categories));
}
void FetchMoreTheseSuggestions(
@@ -602,14 +519,25 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
.WillOnce(Return(true))
.RetiresOnSaturation();
- provider->Fetch(category, known_suggestion_ids, fetch_done_callback);
- std::move(snippets_callback)
- .Run(Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ provider->Fetch(category, known_suggestion_ids,
+ std::move(fetch_done_callback));
+ std::move(snippets_callback).Run(status, std::move(fetched_categories));
+ }
+
+ void PushArticleSuggestionToTheFront(
+ std::unique_ptr<RemoteSuggestion> suggestion) {
+ ASSERT_TRUE(fake_breaking_news_listener_);
+ fake_breaking_news_listener_->PushSuggestion(std::move(suggestion));
+ }
+
+ void ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus old_status,
+ RemoteSuggestionsStatus new_status) {
+ EXPECT_FALSE(status_change_callback_.is_null());
+ status_change_callback_.Run(old_status, new_status);
}
void SetOrderNewRemoteCategoriesBasedOnArticlesCategoryParam(bool value) {
- // params_manager supports only one
+ // VariationParamsManager supports only one
// |SetVariationParamsWithFeatureAssociations| at a time, so we clear
// previous settings first to make this explicit.
params_manager_.ClearAllVariationParams();
@@ -623,7 +551,7 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
void EnableKeepingPrefetchedContentSuggestions(
int max_additional_prefetched_suggestions,
const base::TimeDelta& max_age_for_additional_prefetched_suggestion) {
- // params_manager supports only one
+ // VariationParamsManager supports only one
// |SetVariationParamsWithFeatureAssociations| at a time, so we clear
// previous settings first to make this explicit.
params_manager_.ClearAllVariationParams();
@@ -639,18 +567,60 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
{kKeepPrefetchedContentSuggestions.name});
}
+ void SetTriggeringNotificationsAndSubscriptionParams(
+ bool fetched_notifications_enabled,
+ bool pushed_notifications_enabled,
+ bool subscribe_signed_in,
+ bool subscribe_signed_out) {
+ // VariationParamsManager supports only one
+ // |SetVariationParamsWithFeatureAssociations| at a time, so we clear
+ // previous settings first to make this explicit.
+ params_manager_.ClearAllVariationParams();
+ params_manager_.SetVariationParamsWithFeatureAssociations(
+ /*trial_name=*/kNotificationsFeature.name,
+ {
+ {"enable_fetched_suggestions_notifications",
+ BoolToString(fetched_notifications_enabled)},
+ {"enable_pushed_suggestions_notifications",
+ BoolToString(pushed_notifications_enabled)},
+ {"enable_signed_in_users_subscription_for_pushed_suggestions",
+ BoolToString(subscribe_signed_in)},
+ {"enable_signed_out_users_subscription_for_pushed_suggestions",
+ BoolToString(subscribe_signed_out)},
+ },
+ {kNotificationsFeature.name, kBreakingNewsPushFeature.name});
+ }
+
+ void SetFetchedNotificationsParams(bool enable, bool force) {
+ // VariationParamsManager supports only one
+ // |SetVariationParamsWithFeatureAssociations| at a time, so we clear
+ // previous settings first to make this explicit.
+ params_manager_.ClearAllVariationParams();
+ params_manager_.SetVariationParamsWithFeatureAssociations(
+ /*trial_name=*/kNotificationsFeature.name,
+ {
+ {"enable_fetched_suggestions_notifications", BoolToString(enable)},
+ {"force_fetched_suggestions_notifications", BoolToString(force)},
+ },
+ {kNotificationsFeature.name});
+ }
+
private:
variations::testing::VariationParamsManager params_manager_;
test::RemoteSuggestionsTestUtils utils_;
- base::MessageLoop message_loop_;
std::unique_ptr<CategoryRanker> category_ranker_;
UserClassifier user_classifier_;
std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_;
StrictMock<MockRemoteSuggestionsFetcher>* mock_suggestions_fetcher_;
- PrefetchedPagesTracker* prefetched_pages_tracker_;
+ StrictMock<MockPrefetchedPagesTracker>* mock_prefetched_pages_tracker_;
NiceMock<MockImageFetcher>* image_fetcher_;
FakeImageDecoder image_decoder_;
std::unique_ptr<MockScheduler> scheduler_;
+ FakeBreakingNewsListener* fake_breaking_news_listener_;
+ RemoteSuggestionsStatusService* remote_suggestions_status_service_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ RemoteSuggestionsStatusService::StatusChangeCallback status_change_callback_;
base::ScopedTempDir database_dir_;
RemoteSuggestionsDatabase* database_;
@@ -659,9 +629,11 @@ class RemoteSuggestionsProviderImplTest : public ::testing::Test {
};
TEST_F(RemoteSuggestionsProviderImplTest, Full) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
- // TODO(vitaliii): Inline the vector creation in FetchTheseSuggestions.
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -674,8 +646,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, Full) {
.SetPublisher(kSuggestionPublisherName))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -699,7 +670,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, CategoryTitle) {
// Don't send an initial response -- we want to test what happens without any
// server status.
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// The articles category should be there by default, and have a title.
CategoryInfo info_before = provider->GetCategoryInfo(articles_category());
@@ -717,8 +691,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, CategoryTitle) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder())
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -736,7 +709,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, CategoryTitle) {
}
TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -761,8 +737,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) {
.SetPublisher(kSuggestionPublisherName))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().statuses(),
Eq(std::map<Category, CategoryStatus, Category::CompareByID>{
@@ -804,7 +779,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) {
}
TEST_F(RemoteSuggestionsProviderImplTest, ArticleCategoryInfo) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
CategoryInfo article_info = provider->GetCategoryInfo(articles_category());
EXPECT_THAT(article_info.additional_action(),
Eq(ContentSuggestionsAdditionalAction::FETCH));
@@ -812,7 +790,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, ArticleCategoryInfo) {
}
TEST_F(RemoteSuggestionsProviderImplTest, ExperimentalCategoryInfo) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -828,8 +809,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ExperimentalCategoryInfo) {
// Load data with multiple categories so that a new experimental category gets
// registered.
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
CategoryInfo info = provider->GetCategoryInfo(unknown_category());
EXPECT_THAT(info.additional_action(),
@@ -868,10 +848,12 @@ TEST_F(RemoteSuggestionsProviderImplTest, AddRemoteCategoriesToCategoryRanker) {
EXPECT_CALL(*raw_mock_ranker,
AppendCategoryIfNecessary(Category::FromRemoteCategory(12)));
}
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
}
TEST_F(RemoteSuggestionsProviderImplTest,
@@ -921,10 +903,12 @@ TEST_F(RemoteSuggestionsProviderImplTest,
InsertCategoryAfterIfNecessary(Category::FromRemoteCategory(12),
articles_category()));
}
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
}
TEST_F(
@@ -944,14 +928,19 @@ TEST_F(
EXPECT_CALL(*raw_mock_ranker, InsertCategoryBeforeIfNecessary(_, _)).Times(0);
EXPECT_CALL(*raw_mock_ranker,
AppendCategoryIfNecessary(Category::FromRemoteCategory(11)));
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
}
TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -964,8 +953,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("2"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_EQ(observer().StatusForCategory(articles_category()),
CategoryStatus::AVAILABLE);
@@ -979,7 +967,11 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
Category::FromRemoteCategory(kUnknownRemoteCategoryId));
// Recreate the provider to simulate a Chrome restart.
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// The categories should have been restored.
ASSERT_NE(observer().StatusForCategory(articles_category()),
@@ -1005,7 +997,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) {
TEST_F(RemoteSuggestionsProviderImplTest, PersistRemoteCategoryOrder) {
// We create a provider with a normal ranker to store the order.
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -1023,8 +1018,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistRemoteCategoryOrder) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("12"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// We manually recreate the provider to simulate Chrome restart and enforce a
// mock ranker.
@@ -1048,11 +1042,18 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistRemoteCategoryOrder) {
EXPECT_CALL(*raw_mock_ranker,
AppendCategoryIfNecessary(Category::FromRemoteCategory(12)));
}
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
}
TEST_F(RemoteSuggestionsProviderImplTest, PersistSuggestions) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -1067,15 +1068,18 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistSuggestions) {
RemoteSuggestionBuilder().AddId("2").SetRemoteCategoryId(2))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1));
// Recreate the provider to simulate a Chrome restart.
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// The suggestions in both categories should have been restored.
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
@@ -1085,7 +1089,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistSuggestions) {
TEST_F(RemoteSuggestionsProviderImplTest, DontNotifyIfNotAvailable) {
// Get some suggestions into the database.
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -1098,8 +1105,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, DontNotifyIfNotAvailable) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("2"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -1111,7 +1117,11 @@ TEST_F(RemoteSuggestionsProviderImplTest, DontNotifyIfNotAvailable) {
pref_service()->SetBoolean(prefs::kEnableSnippets, false);
// Recreate the provider to simulate a Chrome start.
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
ASSERT_THAT(RemoteSuggestionsProviderImpl::State::DISABLED,
Eq(provider->state_));
@@ -1123,7 +1133,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, DontNotifyIfNotAvailable) {
}
TEST_F(RemoteSuggestionsProviderImplTest, Clear) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1132,8 +1145,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, Clear) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("1"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
@@ -1144,7 +1156,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, Clear) {
}
TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::string first("http://first");
std::vector<FetchedCategory> fetched_categories;
@@ -1154,8 +1169,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(first))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
ElementsAre(Pointee(Property(&RemoteSuggestion::id, first))));
@@ -1167,8 +1181,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(second))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// The suggestions loaded last replace all that was loaded previously.
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
ElementsAre(Pointee(Property(&RemoteSuggestion::id, second))));
@@ -1176,7 +1189,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) {
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldResolveFetchedSuggestionThumbnail) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1185,8 +1201,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("id"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
ElementsAre(Pointee(Property(&RemoteSuggestion::id, "id"))));
@@ -1203,7 +1218,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
}
TEST_F(RemoteSuggestionsProviderImplTest, ShouldFetchMore) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1212,8 +1230,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldFetchMore) {
.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId("first"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
ElementsAre(Pointee(Property(&RemoteSuggestion::id, "first"))));
@@ -1232,12 +1249,15 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldFetchMore) {
provider.get(), articles_category(),
/*known_suggestion_ids=*/std::set<std::string>(),
/*fetch_done_callback=*/expect_only_second_suggestion_received,
- Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
}
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldResolveFetchedMoreSuggestionThumbnail) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1255,7 +1275,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
provider.get(), articles_category(),
/*known_suggestion_ids=*/std::set<std::string>(),
/*fetch_done_callback=*/assert_only_first_suggestion_received,
- Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
ServeImageCallback serve_one_by_one_image_callback =
@@ -1273,9 +1293,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// should not add any suggestions to B.
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldNotChangeSuggestionsInOtherSurfacesWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// Fetch a suggestion.
std::vector<FetchedCategory> fetched_categories;
@@ -1286,8 +1307,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
RemoteSuggestionBuilder().AddId("http://old.com/"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
ElementsAre(Property(&ContentSuggestion::id,
@@ -1313,7 +1333,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
provider.get(), articles_category(),
/*known_suggestion_ids=*/{"http://old.com/"},
/*fetch_done_callback=*/assert_receiving_one_new_suggestion,
- Status(StatusCode::SUCCESS, "message"), std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Other surfaces should remain the same.
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
@@ -1327,9 +1347,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// there as well.
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldNotAffectFetchMoreInOtherSurfacesWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// Fetch more on the surface A.
std::vector<FetchedCategory> fetched_categories;
@@ -1357,8 +1378,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
/*known_suggestion_ids=*/std::set<std::string>(),
assert_receiving_one_new_suggestion);
std::move(snippets_callback)
- .Run(Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ .Run(Status::Success(), std::move(fetched_categories));
// Now fetch more on the surface B. The response is the same as before.
fetched_categories.clear();
@@ -1391,13 +1411,15 @@ TEST_F(RemoteSuggestionsProviderImplTest,
/*known_suggestion_ids=*/std::set<std::string>(),
expect_receiving_same_suggestion);
std::move(snippets_callback)
- .Run(Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ .Run(Status::Success(), std::move(fetched_categories));
}
TEST_F(RemoteSuggestionsProviderImplTest,
ClearHistoryShouldDeleteArchivedSuggestions) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// First get suggestions into the archived state which happens through
// subsequent fetches. Then we verify the entries are gone from the 'archived'
// state by trying to load their images (and we shouldn't even know the URLs
@@ -1412,8 +1434,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
RemoteSuggestionBuilder().AddId("http://id-2"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
fetched_categories.clear();
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -1424,8 +1445,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
RemoteSuggestionBuilder().AddId("http://new-id-2"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Make sure images of both batches are available. This is to sanity check our
// assumptions for the test are right.
ServeImageCallback cb =
@@ -1467,7 +1487,9 @@ void SuggestionsLoaded(
TEST_F(RemoteSuggestionsProviderImplTest, ReturnFetchRequestEmptyBeforeInit) {
auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
EXPECT_CALL(*mock_suggestions_fetcher(), FetchSnippets(_, _)).Times(0);
MockFunction<void(Status, const std::vector<ContentSuggestion>&)> loaded;
@@ -1475,12 +1497,15 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReturnFetchRequestEmptyBeforeInit) {
IsEmpty()));
provider->Fetch(articles_category(), std::set<std::string>(),
base::Bind(&SuggestionsLoaded, &loaded));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldForwardTemporaryErrorFromFetcher) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback;
MockFunction<void(Status, const std::vector<ContentSuggestion>&)> loaded;
@@ -1503,7 +1528,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldNotAddNewSuggestionsAfterFetchError) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
FetchTheseSuggestions(
provider.get(), /*interactive_request=*/false,
@@ -1515,7 +1543,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldNotClearOldSuggestionsAfterFetchError) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(FetchedCategory(
@@ -1525,8 +1556,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
fetched_categories[0].suggestions.push_back(
CreateTestRemoteSuggestion(base::StringPrintf("http://abc.com/")));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/false,
- Status(StatusCode::SUCCESS, "success message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(
provider->GetSuggestionsForTesting(articles_category()),
@@ -1543,7 +1573,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
}
TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
const FetchedCategoryBuilder category_builder =
@@ -1553,8 +1586,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
RemoteSuggestionBuilder().AddId("http://site.com"));
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
@@ -1591,18 +1623,20 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
IsEmpty());
// The suggestion should stay dismissed even after re-creating the provider.
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
IsEmpty());
@@ -1613,14 +1647,16 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
}
TEST_F(RemoteSuggestionsProviderImplTest, GetDismissed) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1630,8 +1666,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, GetDismissed) {
RemoteSuggestionBuilder().AddId("http://site.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
provider->DismissSuggestion(MakeArticleID("http://site.com"));
@@ -1648,7 +1683,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, GetDismissed) {
}
},
provider.get(), this));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// There should be no dismissed suggestion after clearing the list.
provider->ClearDismissedSuggestionsForDebugging(articles_category());
@@ -1661,11 +1696,14 @@ TEST_F(RemoteSuggestionsProviderImplTest, GetDismissed) {
EXPECT_EQ(0u, dismissed_suggestions.size());
},
provider.get(), this));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
}
TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1676,8 +1714,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
.SetExpiryDate(base::Time::Now()))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Load the image to store it in the database.
// TODO(tschumann): Introduce some abstraction to nicely work with image
// fetching expectations.
@@ -1703,8 +1740,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
RemoteSuggestionBuilder().AddId("http://second/"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetDismissedSuggestionsForTesting(articles_category()),
IsEmpty());
@@ -1715,7 +1751,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
}
TEST_F(RemoteSuggestionsProviderImplTest, ExpiredContentNotRemoved) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1725,15 +1764,17 @@ TEST_F(RemoteSuggestionsProviderImplTest, ExpiredContentNotRemoved) {
RemoteSuggestionBuilder().SetExpiryDate(base::Time::Now()))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
}
TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSource) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1746,8 +1787,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSource) {
.SetAmpUrl("http://source1.amp.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
@@ -1760,7 +1800,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSource) {
}
TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSourceWithMissingData) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1770,33 +1813,40 @@ TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSourceWithMissingData) {
RemoteSuggestionBuilder().SetPublisher("").SetAmpUrl(""))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
IsEmpty());
}
TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
base::HistogramTester tester;
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
Status(StatusCode::TEMPORARY_ERROR, "message"),
base::nullopt);
+ // Error responses don't update the list of suggestions and shouldn't
+ // influence these metrics.
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
+ IsEmpty());
// Fetch error shouldn't contribute to NumArticlesFetched.
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
IsEmpty());
- // Emptry categories list.
+ // TODO(tschumann): The expectations in these tests have high dependencies on
+ // the sequence of unrelated events. This test should be split up into
+ // multiple tests.
+
+ // Empty categories list.
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::vector<FetchedCategory>());
+ Status::Success(), std::vector<FetchedCategory>());
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/2)));
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
IsEmpty());
@@ -1805,10 +1855,9 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
fetched_categories.push_back(
FetchedCategoryBuilder().SetCategory(articles_category()).Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3)));
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2)));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
@@ -1821,10 +1870,9 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
base::Bucket(/*min=*/1, /*count=*/1)));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -1834,10 +1882,9 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
base::Bucket(/*min=*/1, /*count=*/2)));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -1852,10 +1899,9 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
fetched_categories.clear();
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/4),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
base::Bucket(/*min=*/1, /*count=*/2)));
// Dismissed suggestions shouldn't influence NumArticlesFetched.
EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
@@ -1867,7 +1913,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) {
}
TEST_F(RemoteSuggestionsProviderImplTest, DismissShouldRespectAllKnownUrls) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
const std::vector<std::string> source_urls = {
"http://mashable.com/2016/05/11/stolen",
@@ -1890,8 +1939,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, DismissShouldRespectAllKnownUrls) {
.SetPublisher(publishers[0]))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(1));
// Dismiss the suggestion via the mashable source corpus ID.
@@ -1912,14 +1960,16 @@ TEST_F(RemoteSuggestionsProviderImplTest, DismissShouldRespectAllKnownUrls) {
.SetPublisher(publishers[1]))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
IsEmpty());
}
TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -1929,8 +1979,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) {
RemoteSuggestionBuilder().AddId(kSuggestionUrl))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
gfx::Image image;
MockFunction<void(const gfx::Image&)> image_fetched;
@@ -1947,13 +1996,16 @@ TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) {
MakeArticleID(kSuggestionUrl),
base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
base::Unretained(&image_fetched)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
// Check that the image by ServeOneByOneImage is really served.
EXPECT_EQ(1, image.Width());
}
TEST_F(RemoteSuggestionsProviderImplTest, EmptyImageReturnedForNonExistentId) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// Create a non-empty image so that we can test the image gets updated.
gfx::Image image = gfx::test::CreateImage(1, 1);
@@ -1965,7 +2017,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, EmptyImageReturnedForNonExistentId) {
base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
base::Unretained(&image_fetched)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
EXPECT_TRUE(image.IsEmpty());
}
@@ -1974,7 +2026,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// Testing that the provider is not accessing the database is tricky.
// Therefore, we simply put in some data making sure that if the provider asks
// the database, it will get a wrong answer.
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
ContentSuggestion::ID unknown_id = MakeArticleID(kSuggestionUrl2);
database()->SaveImage(unknown_id.id_within_category(), "some image blob");
@@ -1991,12 +2046,15 @@ TEST_F(RemoteSuggestionsProviderImplTest,
base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
base::Unretained(&image_fetched)));
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
EXPECT_TRUE(image.IsEmpty()) << "got image with width: " << image.Width();
}
TEST_F(RemoteSuggestionsProviderImplTest, ClearHistoryRemovesAllSuggestions) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2008,8 +2066,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ClearHistoryRemovesAllSuggestions) {
RemoteSuggestionBuilder().AddId("http://second/"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
SizeIs(2));
@@ -2035,7 +2092,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
ShouldKeepArticlesCategoryAvailableAfterClearHistory) {
// If the provider marks that category as NOT_PROVIDED, then it won't be shown
// at all in the UI and the user cannot load new data :-/.
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
ASSERT_THAT(observer().StatusForCategory(articles_category()),
Eq(CategoryStatus::AVAILABLE));
@@ -2047,7 +2107,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
}
TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2057,8 +2120,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
RemoteSuggestionBuilder().AddId(kSuggestionUrl))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &provider->GetImageFetcherForTesting());
@@ -2080,12 +2142,15 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
"http://something.com/pletely/unrelated"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// The image should still be available until a restart happens.
EXPECT_FALSE(
FetchImage(provider.get(), MakeArticleID(kSuggestionUrl)).IsEmpty());
- ResetSuggestionsProvider(&provider);
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// After the restart, the image should be garbage collected.
EXPECT_TRUE(
FetchImage(provider.get(), MakeArticleID(kSuggestionUrl)).IsEmpty());
@@ -2093,7 +2158,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldHandleMoreThanMaxSuggestionsInResponse) {
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
FetchedCategoryBuilder category_builder;
@@ -2104,8 +2172,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
}
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// TODO(tschumann): We should probably trim out any additional results and
// only serve the MaxSuggestionCount items.
EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
@@ -2118,7 +2185,9 @@ TEST_F(RemoteSuggestionsProviderImplTest,
// is triggered since the suggestions DB is empty. Therefore the provider must
// not be initialized until the test clock is set.
auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
auto simple_test_clock = base::MakeUnique<base::SimpleTestClock>();
base::SimpleTestClock* simple_test_clock_ptr = simple_test_clock.get();
@@ -2143,9 +2212,8 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.RetiresOnSaturation();
provider->RefetchInTheBackground(
RemoteSuggestionsProvider::FetchStatusCallback());
- base::RunLoop().RunUntilIdle();
- std::move(snippets_callback)
- .Run(Status(StatusCode::SUCCESS, "message"), base::nullopt);
+ RunUntilIdle();
+ std::move(snippets_callback).Run(Status::Success(), base::nullopt);
// TODO(jkrcal): Move together with the pref storage into the scheduler.
EXPECT_EQ(
simple_test_clock_ptr->Now().ToInternalValue(),
@@ -2228,9 +2296,10 @@ TEST_F(RemoteSuggestionsProviderImplTest, CallsSchedulerWhenSignedOut) {
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldExcludeKnownSuggestionsWithoutTruncatingWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::set<std::string> known_ids;
for (int i = 0; i < 200; ++i) {
@@ -2250,9 +2319,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldExcludeDismissedSuggestionsWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2264,8 +2334,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
ASSERT_TRUE(fetched_categories[0].suggestions[0]->is_complete());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
provider->DismissSuggestion(MakeArticleID("http://abc.com/"));
std::set<std::string> expected_excluded_ids({"http://abc.com/"});
@@ -2284,9 +2353,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldTruncateExcludedDismissedSuggestionsWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
FetchedCategoryBuilder category_builder;
@@ -2299,8 +2369,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Dismiss them.
for (int i = 0; i < kSuggestionsCount; ++i) {
provider->DismissSuggestion(
@@ -2322,9 +2391,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldPreferLatestExcludedDismissedSuggestionsWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
FetchedCategoryBuilder category_builder;
@@ -2337,8 +2407,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
fetched_categories.push_back(category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Dismiss them in reverse order.
std::string first_dismissed_suggestion_id;
@@ -2366,10 +2435,110 @@ TEST_F(RemoteSuggestionsProviderImplTest,
}
TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldExcludeDismissedFetchedMoreSuggestions) {
+ // This tests verifies that dismissing an article seen in the fetch-more state
+ // (i.e., an article that has been fetched via fetch-more) will be excluded in
+ // future fetches.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ FetchedCategoryBuilder category_builder;
+ category_builder.SetCategory(articles_category());
+ const int kSuggestionsCount = 5;
+ for (int i = 0; i < kSuggestionsCount; ++i) {
+ category_builder.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(
+ base::StringPrintf("http://abc.com/%d", i)));
+ }
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(category_builder.Build());
+
+ FetchMoreTheseSuggestions(
+ provider.get(), articles_category(),
+ /*known_suggestion_ids=*/std::set<std::string>(),
+ /*fetch_done_callback=*/
+ base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
+ ASSERT_THAT(suggestions, SizeIs(5));
+ }),
+ Status::Success(), std::move(fetched_categories));
+
+ // Dismiss them.
+ for (int i = 0; i < kSuggestionsCount; ++i) {
+ provider->DismissSuggestion(
+ MakeArticleID(base::StringPrintf("http://abc.com/%d", i)));
+ }
+
+ EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+ .WillOnce(Return(true))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *mock_suggestions_fetcher(),
+ FetchSnippets(Field(&RequestParams::excluded_ids,
+ ElementsAre("http://abc.com/0", "http://abc.com/1",
+ "http://abc.com/2", "http://abc.com/3",
+ "http://abc.com/4")),
+ _));
+ provider->Fetch(
+ articles_category(), std::set<std::string>(),
+ base::Bind([](Status status_code,
+ std::vector<ContentSuggestion> suggestions) {}));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest, ClearDismissedAfterFetchMore) {
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ FetchedCategoryBuilder category_builder;
+ category_builder.SetCategory(articles_category());
+ category_builder.AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().AddId(base::StringPrintf("http://abc.com")));
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(category_builder.Build());
+
+ FetchMoreTheseSuggestions(
+ provider.get(), articles_category(),
+ /*known_suggestion_ids=*/std::set<std::string>(),
+ /*fetch_done_callback=*/
+ base::Bind(
+ [](Status status, std::vector<ContentSuggestion> suggestions) {}),
+ Status::Success(), std::move(fetched_categories));
+
+ provider->DismissSuggestion(MakeArticleID("http://abc.com"));
+
+ EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+ .WillRepeatedly(Return(true));
+
+ // Make sure the article got marked as dismissed.
+ InSequence s;
+ EXPECT_CALL(*mock_suggestions_fetcher(),
+ FetchSnippets(Field(&RequestParams::excluded_ids,
+ ElementsAre("http://abc.com")),
+ _));
+ provider->Fetch(
+ articles_category(), std::set<std::string>(),
+ base::Bind([](Status status_code,
+ std::vector<ContentSuggestion> suggestions) {}));
+
+ // Clear dismissals.
+ provider->ClearDismissedSuggestionsForDebugging(articles_category());
+
+ // Fetch and verify the article is not marked as dismissed anymore.
+ EXPECT_CALL(*mock_suggestions_fetcher(),
+ FetchSnippets(Field(&RequestParams::excluded_ids, IsEmpty()), _));
+ provider->Fetch(
+ articles_category(), std::set<std::string>(),
+ base::Bind([](Status status_code,
+ std::vector<ContentSuggestion> suggestions) {}));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
ShouldExcludeDismissedSuggestionsFromAllCategoriesWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// Add article suggestions.
std::vector<FetchedCategory> fetched_categories;
@@ -2393,8 +2562,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
fetched_categories.push_back(second_category_builder.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Dismiss all suggestions.
std::set<std::string> expected_excluded_ids;
@@ -2424,9 +2592,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
TEST_F(RemoteSuggestionsProviderImplTest,
ShouldPreferTargetCategoryExcludedDismissedSuggestionsWhenFetchingMore) {
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/false);
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
// Add article suggestions.
std::vector<FetchedCategory> fetched_categories;
@@ -2448,8 +2617,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
CreateTestRemoteSuggestion("http://other.com/"));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
// Dismiss article suggestions first.
for (int i = 0; i < kMaxExcludedDismissedIds; ++i) {
@@ -2482,7 +2650,10 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProvider();
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
FetchedCategoryBuilder()
@@ -2490,8 +2661,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.AddSuggestionViaBuilder(RemoteSuggestionBuilder())
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
}
@@ -2502,11 +2672,12 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2518,8 +2689,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.prefetched.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -2538,8 +2708,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.other.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(
observer().SuggestionsForCategory(articles_category()),
@@ -2555,11 +2724,12 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2572,8 +2742,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.not_prefetched.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -2592,8 +2761,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.other.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
UnorderedElementsAre(Property(
@@ -2607,9 +2775,11 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAgeForAdditionalPrefetchedSuggestion);
auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
WaitForSuggestionsProviderInitialization(provider.get());
const int prefetched_suggestions_count =
@@ -2627,8 +2797,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(prefetched_suggestions_count));
@@ -2650,8 +2819,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.not_prefetched.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(kMaxAdditionalPrefetchedSuggestions + 1));
@@ -2663,11 +2831,12 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
std::vector<FetchedCategory> fetched_categories;
fetched_categories.push_back(
@@ -2686,8 +2855,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.Build());
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(2));
@@ -2715,8 +2883,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.WillOnce(Return(true));
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(
observer().SuggestionsForCategory(articles_category()),
@@ -2729,18 +2896,18 @@ TEST_F(RemoteSuggestionsProviderImplTest,
MakeArticleID("http://prefetched.com/1"))));
}
-TEST_F(
- RemoteSuggestionsProviderImplTest,
- ShouldKeepMostRecentlyFetchedPrefetchedSuggestionsFirstAfterFetchWhenEnabled) {
+TEST_F(RemoteSuggestionsProviderImplTest,
+ KeepMostRecentlyFetchedPrefetchedSuggestionsFirstAfterFetchWhenEnabled) {
EnableKeepingPrefetchedContentSuggestions(
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
std::vector<FetchedCategory> fetched_categories;
const int prefetched_suggestions_count =
@@ -2763,8 +2930,7 @@ TEST_F(
}
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
}
const std::vector<ContentSuggestion>& actual_suggestions =
@@ -2793,9 +2959,11 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAgeForAdditionalPrefetchedSuggestion);
auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
auto wrapped_provider_clock = base::MakeUnique<base::SimpleTestClock>();
base::SimpleTestClock* provider_clock = wrapped_provider_clock.get();
@@ -2819,8 +2987,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.Build());
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(1));
@@ -2844,8 +3011,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
PrefetchedOfflinePageExists(GURL("http://amp.prefetched.com")))
.WillOnce(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(2));
@@ -2869,8 +3035,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
PrefetchedOfflinePageExists(GURL("http://amp.prefetched.com")))
.WillOnce(Return(true));
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
ElementsAre(Property(&ContentSuggestion::id,
MakeArticleID("http://other.com"))));
@@ -2882,11 +3047,12 @@ TEST_F(RemoteSuggestionsProviderImplTest,
kMaxAdditionalPrefetchedSuggestions,
kMaxAgeForAdditionalPrefetchedSuggestion);
- auto provider = MakeSuggestionsProviderWithoutInitialization(
- /*use_mock_prefetched_pages_tracker=*/true);
- auto* mock_tracker = static_cast<StrictMock<MockPrefetchedPagesTracker>*>(
- prefetched_pages_tracker());
- WaitForSuggestionsProviderInitialization(provider.get());
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/true,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ StrictMock<MockPrefetchedPagesTracker>* mock_tracker =
+ mock_prefetched_pages_tracker();
base::OnceCallback<void()> initialization_completed_callback;
EXPECT_CALL(*mock_tracker, IsInitialized()).WillRepeatedly(Return(false));
@@ -2902,8 +3068,7 @@ TEST_F(RemoteSuggestionsProviderImplTest,
.SetAmpUrl("http://amp.prefetched.com"))
.Build());
FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
- Status(StatusCode::SUCCESS, "message"),
- std::move(fetched_categories));
+ Status::Success(), std::move(fetched_categories));
EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
SizeIs(0));
@@ -2913,4 +3078,972 @@ TEST_F(RemoteSuggestionsProviderImplTest,
SizeIs(1));
}
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldRestoreSuggestionsFromDatabaseInSameOrderAsFetched) {
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .AddId("http://1.com")
+ .SetUrl("http://1.com")
+ .SetScore(1))
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .AddId("http://3.com")
+ .SetUrl("http://3.com")
+ .SetScore(3))
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .AddId("http://2.com")
+ .SetUrl("http://2.com")
+ .SetScore(2))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ ASSERT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::id, MakeArticleID("http://1.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://3.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://2.com"))));
+
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::id, MakeArticleID("http://1.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://3.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://2.com"))));
+}
+
+// TODO(vitaliii): Remove this test (as well as the score fallback) in M64.
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldSortSuggestionsWithoutRanksByScore) {
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Write suggestions without ranks (i.e. with default values) directly to
+ // database to simulate behaviour of M61.
+ std::vector<std::unique_ptr<RemoteSuggestion>> suggestions;
+ suggestions.push_back(RemoteSuggestionBuilder()
+ .AddId("http://1.com")
+ .SetUrl("http://1.com")
+ .SetScore(1)
+ .SetRank(std::numeric_limits<int>::max())
+ .Build());
+ suggestions.push_back(RemoteSuggestionBuilder()
+ .AddId("http://3.com")
+ .SetUrl("http://3.com")
+ .SetScore(3)
+ .SetRank(std::numeric_limits<int>::max())
+ .Build());
+ suggestions.push_back(RemoteSuggestionBuilder()
+ .AddId("http://2.com")
+ .SetUrl("http://2.com")
+ .SetScore(2)
+ .SetRank(std::numeric_limits<int>::max())
+ .Build());
+
+ database()->SaveSnippets(suggestions);
+
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::id, MakeArticleID("http://3.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://2.com")),
+ Property(&ContentSuggestion::id, MakeArticleID("http://1.com"))));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ PrependingShouldNotAffectOtherSuggestions) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ // Set up the provider with some article suggestions.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ FetchedCategoryBuilder category_builder =
+ FetchedCategoryBuilder().SetCategory(articles_category());
+ for (int i = 0; i < 10; ++i) {
+ const std::string url = "http://other.com/" + base::IntToString(i);
+ category_builder.AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().AddId(url).SetUrl(url));
+ }
+ fetched_categories.push_back(category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // Prepend an article suggestion.
+ const std::string prepended_url = "http://prepended.com/";
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId(prepended_url)
+ .SetUrl(prepended_url)
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+
+ // Check that the prepended suggestion is in the front, and all the others are
+ // still there in the same order.
+ std::vector<Matcher<const ContentSuggestion&>> expected;
+ expected.push_back(
+ Property(&ContentSuggestion::id, MakeArticleID(prepended_url)));
+ for (int i = 0; i < 10; ++i) {
+ expected.push_back(
+ Property(&ContentSuggestion::id,
+ MakeArticleID("http://other.com/" + base::IntToString(i))));
+ }
+
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAreArray(expected));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest, ShouldNotPrependDismissedSuggestion) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Prepend an article suggestion.
+ const RemoteSuggestionBuilder suggestion_builder =
+ RemoteSuggestionBuilder()
+ .AddId("http://prepended.com")
+ .SetUrl("http://prepended.com");
+
+ PushArticleSuggestionToTheFront(suggestion_builder.Build());
+ ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+ SizeIs(1));
+
+ // Dismiss it.
+ provider->DismissSuggestion(MakeArticleID("http://prepended.com"));
+ ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+ IsEmpty());
+
+ // Prepend it again and verify that it is ignored.
+ PushArticleSuggestionToTheFront(suggestion_builder.Build());
+ EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+ IsEmpty());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldRestorePrependedSuggestionOnTopAfterRestart) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ // Set up the provider with some article suggestions.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ FetchedCategoryBuilder category_builder =
+ FetchedCategoryBuilder().SetCategory(articles_category());
+ for (int i = 0; i < 10; ++i) {
+ const std::string url = "http://other.com/" + base::IntToString(i);
+ category_builder.AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().AddId(url).SetUrl(url));
+ }
+ fetched_categories.push_back(category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // Prepend an article suggestion.
+ const std::string prepended_url = "http://prepended.com";
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId(prepended_url)
+ .SetUrl(prepended_url)
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+
+ // Reset the provider to imitate browser restart.
+ ResetSuggestionsProvider(
+ &provider,
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Check that prepended suggestion is in the front of the restored list and
+ // all other suggestions are present in the same order.
+ std::vector<Matcher<const ContentSuggestion&>> expected;
+ expected.push_back(
+ Property(&ContentSuggestion::id, MakeArticleID(prepended_url)));
+ for (int i = 0; i < 10; ++i) {
+ expected.push_back(
+ Property(&ContentSuggestion::id,
+ MakeArticleID("http://other.com/" + base::IntToString(i))));
+ }
+
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAreArray(expected));
+}
+
+TEST_F(
+ RemoteSuggestionsProviderImplTest,
+ PrependingShouldNotTriggerFetchedSuggestionNotificationForTheSecondTime) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/true,
+ /*pushed_notifications_enabled=*/true,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ // Set up the provider with an article suggestion triggering a notification.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .AddId("http://fetched.com/")
+ .SetUrl("http://fetched.com/")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime()))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra,
+ Not(nullptr))));
+
+ // Prepend an article suggestion.
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId("http://prepended.com")
+ .SetUrl("http://prepended.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime())
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+
+ // Previously fetched suggestion should not trigger a notification.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::notification_extra, Not(nullptr)),
+ Property(&ContentSuggestion::notification_extra, nullptr)));
+}
+
+TEST_F(
+ RemoteSuggestionsProviderImplTest,
+ PrependingShouldNotTriggerPrependedSuggestionNotificationForTheSecondTime) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/true,
+ /*pushed_notifications_enabled=*/true,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Prepend an article suggestion.
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId("http://prepended.com")
+ .SetUrl("http://prepended.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime())
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra,
+ Not(nullptr))));
+
+ // Prepend another article suggestion.
+ std::unique_ptr<RemoteSuggestion> another_prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId("http://another_prepended.com")
+ .SetUrl("http://another_prepended.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime())
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(another_prepended_suggestion));
+
+ // Previously prepended suggestion should not trigger a notification.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::notification_extra, Not(nullptr)),
+ Property(&ContentSuggestion::notification_extra, nullptr)));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ PrependingShouldNotTriggerNotificationWhenDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/true,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Prepend an article suggestion triggering a notification.
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId("http://prepended.com")
+ .SetUrl("http://prepended.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime())
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+
+ // The prepended suggestion should not trigger a notification because such
+ // notifications are disabled.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra, nullptr)));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ FetchingShouldNotTriggerNotificationWhenDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/true,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Fetch a suggestion triggering a notification.
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .AddId("http://fetched.com/")
+ .SetUrl("http://fetched.com/")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime()))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // The fetched suggestion should not trigger a notification because such
+ // notifications are disabled.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra, nullptr)));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ PrependingShouldTriggerNotificationEvenIfFetchedNotificationsDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/true,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Prepend an article suggestion triggering a notification.
+ std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+ RemoteSuggestionBuilder()
+ .AddId("http://prepended.com")
+ .SetUrl("http://prepended.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime())
+ .Build();
+
+ PushArticleSuggestionToTheFront(std::move(prepended_suggestion));
+
+ // The prepended suggestion should trigger a notification even though fetched
+ // notifications are disabled.
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra,
+ Not(nullptr))));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ FetchingShouldTriggerNotificationEvenIfPrependedNotificationsDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/true,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Fetch a suggestion triggering a notification.
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .AddId("http://fetched.com/")
+ .SetUrl("http://fetched.com/")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime()))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // The fetched suggestion should trigger a notification even though prepended
+ // notifications are disabled.
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra,
+ Not(nullptr))));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldNotStartListeningForBreakingNewsIfSuggestionsDisabledAtStartup) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProviderWithoutInitialization(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+ EXPECT_FALSE(fake_listener->IsListening());
+
+ WaitForSuggestionsProviderInitialization(provider.get());
+ EXPECT_FALSE(fake_listener->IsListening());
+
+ // Notify the provider about status change (simulating startup). The provider
+ // should not start listening, because the suggestions are disabled.
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED);
+ EXPECT_FALSE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldNotStartListeningForBreakingNewsIfSignedOutAndDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/false);
+
+ auto provider = MakeSuggestionsProviderWithoutInitialization(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+ EXPECT_FALSE(fake_listener->IsListening());
+
+ WaitForSuggestionsProviderInitialization(provider.get());
+ EXPECT_FALSE(fake_listener->IsListening());
+
+ // Notify the provider about status change (simulating startup). The provider
+ // should not start listening, because the user is signed out and such
+ // subscription is disabled via feature params.
+ ChangeRemoteSuggestionsStatus(
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
+ EXPECT_FALSE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldStartListeningForBreakingNewsIfSuggestionsEnabledAtStartup) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/false,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+ ASSERT_FALSE(fake_listener->IsListening());
+
+ // Notify the provider about status change (simulating startup). The provider
+ // should start listening, because the suggestions are enabled.
+ ChangeRemoteSuggestionsStatus(
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
+ EXPECT_TRUE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldStartListeningForBreakingNewsIfSuggestionsEnabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/false);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+
+ // Notify the provider about status change (simulating startup).
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED);
+ ASSERT_FALSE(fake_listener->IsListening());
+
+ // Simulate the user enabling suggestions by notifying the status change. The
+ // provider should start listening.
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN);
+ EXPECT_TRUE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldStopListeningForBreakingNewsIfSuggestionsDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+
+ // Notify the provider about status change (simulating startup).
+ ChangeRemoteSuggestionsStatus(
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
+ ASSERT_TRUE(fake_listener->IsListening());
+
+ // Simulate the user disabling suggestions by notifying the status change. The
+ // provider should stop listening.
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT,
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED);
+ EXPECT_FALSE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldStopListeningForBreakingNewsAfterSignOutIfDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/true,
+ /*subscribe_signed_out=*/false);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+
+ // Notify the provider about status change (simulating startup).
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN);
+ ASSERT_TRUE(fake_listener->IsListening());
+
+ // Simulate the user signing out by notifying the status change. The provider
+ // should stop listening, because signed out subscription is disabled via
+ // feature params.
+ ChangeRemoteSuggestionsStatus(
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
+ EXPECT_FALSE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldStopListeningForBreakingNewsAfterSignInIfDisabled) {
+ SetTriggeringNotificationsAndSubscriptionParams(
+ /*fetched_notifications_enabled=*/false,
+ /*pushed_notifications_enabled=*/false,
+ /*subscribe_signed_in=*/false,
+ /*subscribe_signed_out=*/true);
+
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/true,
+ /*use_mock_remote_suggestions_status_service=*/true);
+
+ FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener();
+
+ // Notify the provider about status change (simulating startup).
+ ChangeRemoteSuggestionsStatus(
+ RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT);
+ ASSERT_TRUE(fake_listener->IsListening());
+
+ // Simulate the user signing in by notifying the status change. The provider
+ // should stop listening, because signed in subscription is disabled via
+ // feature params.
+ ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT,
+ RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN);
+ EXPECT_FALSE(fake_listener->IsListening());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldForceFetchedSuggestionsNotificationsWhenEnabled) {
+ SetFetchedNotificationsParams(
+ /*enabled=*/true, /*force=*/true);
+
+ // Initialize the provider with two article suggestions - one with a
+ // notification and one - without.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .SetUrl("http://article_with_notification.com")
+ .SetShouldNotify(true)
+ .SetNotificationDeadline(GetDefaultExpirationTime()))
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .SetUrl("http://article_without_notification.com")
+ .SetShouldNotify(false))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // For the observer, both suggestions must have notifications, because they
+ // are forced via a feature param.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ Property(&ContentSuggestion::notification_extra, Not(nullptr)),
+ Property(&ContentSuggestion::notification_extra, Not(nullptr))));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldNotForceFetchedSuggestionsNotificationsWhenExplicitlyDisabled) {
+ SetFetchedNotificationsParams(
+ /*enabled=*/false, /*force=*/true);
+
+ // Initialize the provider with an article suggestions without a notification.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder()
+ .SetUrl("http://article_without_notification.com")
+ .SetShouldNotify(false))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // For the observer, the suggestion still must not have a notification (even
+ // though they are forced via a feature param), because the fetched
+ // notifications are explicitly disabled via another feature param.
+ EXPECT_THAT(
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(Property(&ContentSuggestion::notification_extra, nullptr)));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldDeleteNotFetchedCategoryWhenDeletionEnabled) {
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ const FetchedCategoryBuilder articles_category_builder =
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://articles.com"));
+ fetched_categories.push_back(articles_category_builder.Build());
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(other_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://not_articles.com"))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(other_category()));
+
+ // Fetch only one category - articles.
+ fetched_categories.push_back(articles_category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ // The other category must be gone, because it was not included in the last
+ // fetch and the deletion is enabled via feature params.
+ EXPECT_EQ(CategoryStatus::NOT_PROVIDED,
+ observer().StatusForCategory(other_category()));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldKeepFetchedCategoryWhenDeletionEnabled) {
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ const FetchedCategoryBuilder articles_category_builder =
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://articles.com"));
+ fetched_categories.push_back(articles_category_builder.Build());
+ const FetchedCategoryBuilder other_category_builder =
+ FetchedCategoryBuilder()
+ .SetCategory(other_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://not_articles.com"));
+ fetched_categories.push_back(other_category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(other_category()));
+
+ // Fetch the same two categories again.
+ fetched_categories.push_back(articles_category_builder.Build());
+ fetched_categories.push_back(other_category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ // The other category must remain, because it was included in the last fetch.
+ EXPECT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(other_category()));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ShouldKeepArticleCategoryEvenWhenNotFetchedAndDeletionEnabled) {
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://articles.com"))
+ .Build());
+ const FetchedCategoryBuilder other_category_builder =
+ FetchedCategoryBuilder()
+ .SetCategory(other_category())
+ .AddSuggestionViaBuilder(
+ RemoteSuggestionBuilder().SetUrl("http://not_articles.com"));
+ fetched_categories.push_back(other_category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+
+ // Fetch only one other category.
+ fetched_categories.push_back(other_category_builder.Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+ fetched_categories.clear();
+
+ // Articles category still must be provided (it is an exception) even though
+ // it was not included in the last fetch and the deletion is enabled via
+ // feature params.
+ EXPECT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ EmptySectionResponseShouldClearSection) {
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Set up state with present suggestions.
+ // Unfortunately, we cannot create the fetched_categories inline, as some part
+ // requires a copy of FetchedCategory which is not supported :-/.
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .SetUrl("http://articles.com")
+ .SetAmpUrl(""))
+ .Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+
+ // Next fetch returns an empty article section.
+ fetched_categories.clear();
+ fetched_categories.push_back(
+ FetchedCategoryBuilder().SetCategory(articles_category()).Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ // Articles category still must be provided, but empty.
+ EXPECT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ IsEmpty());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ FetchErrorShouldLeaveSuggestionsUnchangedEmptySection) {
+ // Tests that we don't interpret the response value in error cases.
+ // Note, that the contract of the callback guarantees that we always send
+ // a null value in error cases. However, such a contract is brittle and the
+ // code is not too clear on the receiving side.
+ // TODO(tschumann): Establish and enforce a clear and robust error handling
+ // contract.
+
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Set up state with present suggestions.
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .SetUrl("http://articles.com")
+ .SetAmpUrl(""))
+ .Build());
+
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+
+ // Next fetch returns an error (with an empty section).
+ fetched_categories.clear();
+ fetched_categories.push_back(
+ FetchedCategoryBuilder().SetCategory(articles_category()).Build());
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status(StatusCode::TEMPORARY_ERROR, "some error"),
+ std::move(fetched_categories));
+
+ // Articles category should stay unchanged.
+ EXPECT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category())[0].url(),
+ GURL("http://articles.com"));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ FetchErrorShouldLeaveSuggestionsUnchangedNullResponse) {
+ // Initialize the provider with two categories.
+ auto provider = MakeSuggestionsProvider(
+ /*use_mock_prefetched_pages_tracker=*/false,
+ /*use_fake_breaking_news_listener=*/false,
+ /*use_mock_remote_suggestions_status_service=*/false);
+
+ // Set up state with present suggestions.
+ std::vector<FetchedCategory> fetched_categories;
+ fetched_categories.push_back(
+ FetchedCategoryBuilder()
+ .SetCategory(articles_category())
+ .AddSuggestionViaBuilder(RemoteSuggestionBuilder()
+ .SetUrl("http://articles.com")
+ .SetAmpUrl(""))
+ .Build());
+
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status::Success(), std::move(fetched_categories));
+
+ ASSERT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+
+ // Next fetch returns an error (with an empty section).
+ FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+ Status(StatusCode::TEMPORARY_ERROR, "some error"),
+ base::nullopt);
+
+ // Articles category should stay unchanged.
+ EXPECT_EQ(CategoryStatus::AVAILABLE,
+ observer().StatusForCategory(articles_category()));
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category())[0].url(),
+ GURL("http://articles.com"));
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
index 78d34176168..d4fad75d315 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler.h
@@ -19,6 +19,8 @@ struct Status;
// their events.
class RemoteSuggestionsScheduler {
public:
+ virtual ~RemoteSuggestionsScheduler() = default;
+
// Set the provider that performs background fetching. Should be only called
// by the factory.
virtual void SetProvider(RemoteSuggestionsProvider* provider) = 0;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
index 064a30d3f46..543ccb0d75c 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
@@ -131,12 +131,12 @@ static_assert(
// For backward compatibility "ntp_opened" value is kept and denotes the
// SURFACE_OPENED trigger type.
-const char* kTriggerTypeNames[] = {"persistent_scheduler_wake_up", "ntp_opened",
- "browser_foregrounded",
- "browser_cold_start"};
+const char* const kTriggerTypeNames[] = {"persistent_scheduler_wake_up",
+ "ntp_opened", "browser_foregrounded",
+ "browser_cold_start"};
-const char* kTriggerTypesParamName = "scheduler_trigger_types";
-const char* kTriggerTypesParamValueForEmptyList = "-";
+const char* const kTriggerTypesParamName = "scheduler_trigger_types";
+const char* const kTriggerTypesParamValueForEmptyList = "-";
const int kBlockBackgroundFetchesMinutesAfterClearingHistory = 30;
@@ -343,13 +343,12 @@ void ReportTimeUntilPersistentFetch(
} // namespace
-class EulaState : public web_resource::EulaAcceptedNotifier::Observer {
+class EulaState final : public web_resource::EulaAcceptedNotifier::Observer {
public:
- EulaState(PrefService* local_state_prefs,
- RemoteSuggestionsScheduler* scheduler)
+ EulaState(PrefService* local_state_prefs, base::Closure eula_accepted)
: eula_notifier_(
web_resource::EulaAcceptedNotifier::Create(local_state_prefs)),
- scheduler_(scheduler) {
+ eula_accepted_(eula_accepted) {
// EulaNotifier is not constructed on some platforms (such as desktop).
if (!eula_notifier_) {
return;
@@ -370,15 +369,17 @@ class EulaState : public web_resource::EulaAcceptedNotifier::Observer {
// EulaAcceptedNotifier::Observer implementation.
void OnEulaAccepted() override {
- // Emulate a persistent fetch - we really want to fetch, initially!
- // TODO(jkrcal): Find a cleaner solution. This is somewhat hacky and can
- // mess up with metrics.
- scheduler_->OnPersistentSchedulerWakeUp();
+ // Note that this code is only run if a previous call to IsEulaAccepted()
+ // returned false. In that case, the prefs are watched and this method gets
+ // executed once the setting flips to accepted. Hence, we can assume that
+ // at the time this code runs, a background-fetch trigger is queued in the
+ // scheduler.
+ eula_accepted_.Run();
}
private:
std::unique_ptr<web_resource::EulaAcceptedNotifier> eula_notifier_;
- RemoteSuggestionsScheduler* scheduler_;
+ base::Callback<void()> eula_accepted_;
DISALLOW_COPY_AND_ASSIGN(EulaState);
};
@@ -450,7 +451,10 @@ RemoteSuggestionsSchedulerImpl::RemoteSuggestionsSchedulerImpl(
CONTENT_SUGGESTION_FETCHER_ACTIVE_SUGGESTIONS_CONSUMER),
time_until_first_shown_trigger_reported_(false),
time_until_first_startup_trigger_reported_(false),
- eula_state_(base::MakeUnique<EulaState>(local_state_prefs, this)),
+ eula_state_(base::MakeUnique<EulaState>(
+ local_state_prefs,
+ base::Bind(&RemoteSuggestionsSchedulerImpl::RunQueuedTriggersIfReady,
+ base::Unretained(this)))),
profile_prefs_(profile_prefs),
clock_(std::move(clock)),
enabled_triggers_(GetEnabledTriggerTypes()) {
@@ -494,6 +498,18 @@ void RemoteSuggestionsSchedulerImpl::SetProvider(
void RemoteSuggestionsSchedulerImpl::OnProviderActivated() {
StartScheduling();
+ RunQueuedTriggersIfReady();
+}
+
+void RemoteSuggestionsSchedulerImpl::RunQueuedTriggersIfReady() {
+ // Process any queued triggers if we're now ready for background fetches.
+ if (IsReadyForBackgroundFetches()) {
+ std::set<TriggerType> queued_triggers_copy;
+ queued_triggers_copy.swap(queued_triggers_);
+ for (const TriggerType trigger : queued_triggers_copy) {
+ RefetchInTheBackgroundIfAppropriate(trigger);
+ }
+ }
}
void RemoteSuggestionsSchedulerImpl::OnProviderDeactivated() {
@@ -655,6 +671,10 @@ void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
return;
}
+ if (enabled_triggers_.count(trigger) == 0) {
+ return;
+ }
+
if (net::NetworkChangeNotifier::IsOffline()) {
// Do not let a request fail due to lack of internet connection. Then, such
// a failure would get logged and further requests would be blocked for a
@@ -662,7 +682,8 @@ void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
return;
}
- if (BackgroundFetchesDisabled(trigger)) {
+ if (!IsReadyForBackgroundFetches()) {
+ queued_triggers_.insert(trigger);
return;
}
@@ -742,25 +763,20 @@ bool RemoteSuggestionsSchedulerImpl::ShouldRefetchInTheBackgroundNow(
first_allowed_fetch_time <= now;
}
-bool RemoteSuggestionsSchedulerImpl::BackgroundFetchesDisabled(
- TriggerType trigger) const {
+bool RemoteSuggestionsSchedulerImpl::IsReadyForBackgroundFetches() const {
if (!provider_) {
- return true; // Cannot fetch as remote suggestions provider does not exist.
+ return false; // Cannot fetch as remote suggestions provider does not
+ // exist.
}
if (schedule_.is_empty()) {
- return true; // Background fetches are disabled in general.
- }
-
- if (enabled_triggers_.count(trigger) == 0) {
- return true; // Background fetches for |trigger| are not enabled.
+ return false; // Background fetches are disabled in general.
}
-
if (!eula_state_->IsEulaAccepted()) {
- return true; // No background fetches are allowed before EULA is accepted.
+ return false; // No background fetches are allowed before EULA is accepted.
}
- return false;
+ return true;
}
bool RemoteSuggestionsSchedulerImpl::AcquireQuota(bool interactive_request) {
@@ -825,8 +841,8 @@ RemoteSuggestionsSchedulerImpl::GetEnabledTriggerTypes() {
std::set<TriggerType> enabled_types;
for (const auto& token : tokens) {
- auto** it = std::find(std::begin(kTriggerTypeNames),
- std::end(kTriggerTypeNames), token);
+ auto* const* it = std::find(std::begin(kTriggerTypeNames),
+ std::end(kTriggerTypeNames), token);
if (it == std::end(kTriggerTypeNames)) {
DLOG(WARNING) << "Failed to parse variation param "
<< kTriggerTypesParamName << " with string value "
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
index 6c6e63df23b..99bc7a2c599 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
@@ -42,7 +42,7 @@ class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
PrefService* local_state_prefs,
std::unique_ptr<base::Clock> clock);
- ~RemoteSuggestionsSchedulerImpl();
+ ~RemoteSuggestionsSchedulerImpl() override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
@@ -98,8 +98,10 @@ class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
bool ShouldRefetchInTheBackgroundNow(base::Time last_fetch_attempt_time,
TriggerType trigger);
- // Returns whether background fetching (for the given |trigger|) is disabled.
- bool BackgroundFetchesDisabled(TriggerType trigger) const;
+ // Returns whether all components are ready for background fetches.
+ bool IsReadyForBackgroundFetches() const;
+ // Runs any queued triggers if the system is ready for background fetches.
+ void RunQueuedTriggersIfReady();
// Returns true if quota is available for another request.
bool AcquireQuota(bool interactive_request);
@@ -158,6 +160,7 @@ class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
PrefService* profile_prefs_;
std::unique_ptr<base::Clock> clock_;
std::set<TriggerType> enabled_triggers_;
+ std::set<TriggerType> queued_triggers_;
base::Time background_fetches_allowed_after_;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
index 8567849469f..07a9c3cbbce 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -37,11 +37,13 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::AnyNumber;
using testing::ElementsAre;
using testing::Eq;
using testing::Field;
using testing::InSequence;
using testing::Invoke;
+using testing::InvokeArgument;
using testing::IsEmpty;
using testing::Mock;
using testing::MockFunction;
@@ -61,6 +63,12 @@ class RemoteSuggestionsFetcher;
namespace {
+ACTION_TEMPLATE(SaveArgByMove,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = std::move(*::testing::get<k>(args));
+}
+
class MockPersistentScheduler : public PersistentScheduler {
public:
MOCK_METHOD2(Schedule,
@@ -75,8 +83,17 @@ class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
public:
MockRemoteSuggestionsProvider(Observer* observer)
: RemoteSuggestionsProvider(observer) {}
- MOCK_METHOD1(RefetchInTheBackground,
- void(const RemoteSuggestionsProvider::FetchStatusCallback&));
+ // Gmock cannot mock methods that have movable-only type callbacks as
+ // parameters such as FetchDoneCallback, DismissedSuggestionsCallback,
+ // ImageFetchedCallback, FetchStatusCallback. As a work-around,
+ // RefetchInTheBackground calls the mock method RefetchInTheBackgroundMock,
+ // which may then be checked with EXPECT_CALL.
+ void RefetchInTheBackground(
+ RemoteSuggestionsProvider::FetchStatusCallback callback) override {
+ RefetchInTheBackgroundMock(&callback);
+ }
+ MOCK_METHOD1(RefetchInTheBackgroundMock,
+ void(RemoteSuggestionsProvider::FetchStatusCallback*));
MOCK_CONST_METHOD0(suggestions_fetcher_for_debugging,
const RemoteSuggestionsFetcher*());
MOCK_CONST_METHOD1(GetUrlWithFavicon,
@@ -88,7 +105,12 @@ class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
void(base::Time begin,
base::Time end,
const base::Callback<bool(const GURL& url)>& filter));
- MOCK_METHOD3(Fetch,
+ void Fetch(const Category& category,
+ const std::set<std::string>& set,
+ FetchDoneCallback callback) override {
+ FetchMock(category, set, callback);
+ }
+ MOCK_METHOD3(FetchMock,
void(const Category&,
const std::set<std::string>&,
const FetchDoneCallback&));
@@ -96,10 +118,20 @@ class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
MOCK_METHOD1(ClearCachedSuggestions, void(Category));
MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category));
MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&));
- MOCK_METHOD2(FetchSuggestionImage,
+ void FetchSuggestionImage(const ContentSuggestion::ID& id,
+ ImageFetchedCallback callback) override {
+ FetchSuggestionImageMock(id, callback);
+ }
+ MOCK_METHOD2(FetchSuggestionImageMock,
void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
- MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
- void(Category, const DismissedSuggestionsCallback&));
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ DismissedSuggestionsCallback callback) override {
+ GetDismissedSuggestionsForDebuggingMock(category, callback);
+ }
+ MOCK_METHOD2(GetDismissedSuggestionsForDebuggingMock,
+ void(Category category,
+ const DismissedSuggestionsCallback& callback));
MOCK_METHOD0(OnSignInStateChanged, void());
};
@@ -186,16 +218,29 @@ class RemoteSuggestionsSchedulerImplTest : public ::testing::Test {
std::map<std::string, std::string> default_variation_params_;
variations::testing::VariationParamsManager params_manager_;
- void ActivateProvider() {
+ void ActivateProviderAndEula() {
SetEulaAcceptedPref();
scheduler_->OnProviderActivated();
}
void DeactivateProvider() { scheduler_->OnProviderDeactivated(); }
+ void ExpectOneRetiringRefetchInTheBackground() {
+ // After a successful fetch, the client updates it's schedule, so we expect
+ // another call here.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).RetiresOnSaturation();
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(Invoke(
+ [](RemoteSuggestionsProvider::FetchStatusCallback* callback) {
+ std::move(*callback).Run(Status::Success());
+ }))
+ .RetiresOnSaturation();
+ }
+
MockPersistentScheduler* persistent_scheduler() {
return &persistent_scheduler_;
}
+
base::SimpleTestClock* test_clock() { return test_clock_; }
MockRemoteSuggestionsProvider* provider() { return provider_.get(); }
RemoteSuggestionsSchedulerImpl* scheduler() { return scheduler_.get(); }
@@ -231,7 +276,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
scheduler()->OnProviderActivated();
// Verify fetches get triggered.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnPersistentSchedulerWakeUp();
}
@@ -265,7 +310,25 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldFetchWhenEulaGetsAccepted) {
scheduler()->OnPersistentSchedulerWakeUp();
// Accepting Eula afterwards results in a background fetch.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
+ SetEulaAcceptedPref();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueBackgroundRequestIfEulaIsMissing) {
+ // Only run this tests on platforms supporting Eula.
+ if (!IsEulaNotifierAvailable()) {
+ return;
+ }
+ // Eula is not ready -- no fetch. But request should get queued.
+ scheduler()->OnPersistentSchedulerWakeUp();
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ // Activate provider -- this should set up the schedule but cannot trigger a
+ // fetch due to Eula missing.
+ scheduler()->OnProviderActivated();
+
+ // Accepting Eula picks up the queued fetch.
+ ExpectOneRetiringRefetchInTheBackground();
SetEulaAcceptedPref();
}
@@ -277,7 +340,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
scheduler()->OnPersistentSchedulerWakeUp();
scheduler()->OnSuggestionsSurfaceOpened();
@@ -294,10 +357,10 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// For instance, persistent scheduler wake up should be enabled by default.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnPersistentSchedulerWakeUp();
}
@@ -309,10 +372,10 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// For instance, persistent scheduler wake up should be enabled by default.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnPersistentSchedulerWakeUp();
}
@@ -325,9 +388,9 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnPersistentSchedulerWakeUp();
}
@@ -337,16 +400,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
{
InSequence s;
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
}
// First enable the scheduler -- calling Schedule() for the first time.
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first persistent fetch successful -- calling Schedule() again.
scheduler()->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Make the second fetch.
scheduler()->OnPersistentSchedulerWakeUp();
}
@@ -356,11 +419,12 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
{
InSequence s;
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ // We do not capture and execute the callback to keep the fetch in-flight.
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
// RefetchInTheBackground is not called after the second trigger.
}
// First enable the scheduler -- calling Schedule() for the first time.
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first persistent fetch never finish.
scheduler()->OnPersistentSchedulerWakeUp();
// Make the second fetch.
@@ -375,9 +439,9 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -389,24 +453,119 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ ExpectOneRetiringRefetchInTheBackground();
scheduler()->OnBrowserForegrounded();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldFetchOnBrowserColdStartForTheFirstTime) {
- // First set only this type to be allowed.
- SetVariationParameter("scheduler_trigger_types", "browser_cold_start");
- ResetProvider();
-
// Then enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
+
+ ExpectOneRetiringRefetchInTheBackground();
+ scheduler()->OnBrowserColdStart();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueBackgroundFetchSignalsOnPersistentSchedulerWakeUp) {
+ // Enable EULA to make this test not depend on that setting (or it being
+ // flipped)
+ SetEulaAcceptedPref();
+
+ // On activation, the Schedule should get updated and the queued background
+ // fetch should get propagated.
+ scheduler()->OnPersistentSchedulerWakeUp();
+
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ExpectOneRetiringRefetchInTheBackground();
+ ActivateProviderAndEula();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueBackgroundFetchSignalsOnSurfaceOpened) {
+ // Enable EULA to make this test not depend on that setting (or it being
+ // flipped)
+ SetEulaAcceptedPref();
+
+ // On activation, the Schedule should get updated and the queued background
+ // fetch should get propagated.
+ scheduler()->OnSuggestionsSurfaceOpened();
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ExpectOneRetiringRefetchInTheBackground();
+ ActivateProviderAndEula();
+}
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueBackgroundFetchSignalsOnBrowserForegrounded) {
+ // Enable EULA to make this test not depend on that setting (or it being
+ // flipped)
+ SetEulaAcceptedPref();
+
+ // On activation, the Schedule should get updated and the queued background
+ // fetch should get propagated.
+ scheduler()->OnBrowserForegrounded();
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ExpectOneRetiringRefetchInTheBackground();
+ ActivateProviderAndEula();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueBackgroundFetchSignalsOnBrowserColdStart) {
+ // Enable EULA to make this test not depend on that setting (or it being
+ // flipped)
+ SetEulaAcceptedPref();
+
+ // On activation, the Schedule should get updated and the queued background
+ // fetch should get propagated.
+ scheduler()->OnBrowserColdStart();
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
+ ExpectOneRetiringRefetchInTheBackground();
+ ActivateProviderAndEula();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ShouldQueueMultipleBackgroundFetchSignals) {
+ // Enable EULA to make this test not depend on that setting (or it being
+ // flipped)
+ SetEulaAcceptedPref();
+
+ // We want to store multiple events to respect lower thresholds for specific
+ // events properly. To test this, we do the following setup:
+ // (1) Force a fetch.
+ // (2) Simulate a stop of the browser, wait until surface-opened would trigger
+ // a fetch but start-up would not trigger a fetch yet.
+ // (3) simulate a very slow initialization, where the scheduler sees both
+ // events (cold start and surface opened) before being activated.
+ // (4) make sure that activation triggers a background fetch.
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(AnyNumber());
+ ActivateProviderAndEula();
+ ExpectOneRetiringRefetchInTheBackground();
+ scheduler()->OnBrowserColdStart();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER - we work with the
+ // default interval for this class here. This time would allow for a fetch on
+ // NTP open but not on cold start.
+ test_clock()->Advance(base::TimeDelta::FromHours(13));
+ // This should *not* trigger a fetch.
+ scheduler()->OnBrowserColdStart();
+
+ // Simulate a restart.
+ EXPECT_CALL(*persistent_scheduler(), Unschedule());
+ scheduler()->OnProviderDeactivated();
+ ResetProvider(); // Also resets the scheduler and test clock.
+
+ test_clock()->Advance(base::TimeDelta::FromHours(13));
+ scheduler()->OnSuggestionsSurfaceOpened();
scheduler()->OnBrowserColdStart();
+ ExpectOneRetiringRefetchInTheBackground();
+
+ // Signal the provider is ready (EULA check should still pass from the first
+ // start). We don't want to trigger EULA again as it will simulate a
+ // persistent fetch.
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
@@ -414,14 +573,14 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// First enable the scheduler; the second Schedule is called after the
// successful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first soft fetch successful.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// The second call is ignored if it happens right after the first one.
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -431,14 +590,14 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// First enable the scheduler; the second Schedule is called after the
// successful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first persistent fetch successful.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// The second call is ignored if it happens right after the first one.
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -447,14 +606,14 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldNotFetchOnSuggestionsSurfaceOpenedAfterFailedSoftFetch) {
// First enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first soft fetch failed.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+ std::move(signal_fetch_done).Run(Status(StatusCode::PERMANENT_ERROR, ""));
// The second call is ignored if it happens right after the first one.
scheduler()->OnSuggestionsSurfaceOpened();
@@ -464,14 +623,14 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldNotFetchOnSuggestionsSurfaceOpenedAfterFailedPersistentFetch) {
// First enable the scheduler.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first persistent fetch failed.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+ std::move(signal_fetch_done).Run(Status(StatusCode::PERMANENT_ERROR, ""));
// The second call is ignored if it happens right after the first one.
scheduler()->OnSuggestionsSurfaceOpened();
@@ -485,19 +644,19 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
// The first call to NTPOpened results in a fetch.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
// Rescheduling after a succesful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
// The second call to NTPOpened 4hrs later again results in a fetch.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
}
// First enable the scheduler.
- ActivateProvider();
+ ActivateProviderAndEula();
// Make the first soft fetch successful.
scheduler()->OnBrowserForegrounded();
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Open NTP again after 9hrs.
test_clock()->Advance(base::TimeDelta::FromHours(24));
scheduler()->OnBrowserForegrounded();
@@ -510,7 +669,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldRescheduleOnBrowserUpgraded) {
TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnActivation) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
@@ -520,7 +679,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
EXPECT_CALL(*persistent_scheduler(), Unschedule());
}
- ActivateProvider();
+ ActivateProviderAndEula();
DeactivateProvider();
}
@@ -528,46 +687,46 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnLaterActivation) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
// There is no schedule yet, so inactivation does not trigger unschedule.
DeactivateProvider();
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldRescheduleAfterSuccessfulFetch) {
// First reschedule on becoming active.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
// Trigger a fetch.
scheduler()->OnPersistentSchedulerWakeUp();
// Second reschedule after a successful fetch.
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldNotRescheduleAfterFailedFetch) {
// Only reschedule on becoming active.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
// Trigger a fetch.
scheduler()->OnPersistentSchedulerWakeUp();
// No furter reschedule after a failure.
- signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
+ std::move(signal_fetch_done).Run(Status(StatusCode::PERMANENT_ERROR, ""));
}
TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldScheduleOnlyOnce) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// No further call to Schedule on a second status callback.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldUnscheduleOnlyOnce) {
@@ -577,7 +736,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldUnscheduleOnlyOnce) {
EXPECT_CALL(*persistent_scheduler(), Unschedule());
}
// First schedule so that later we really unschedule.
- ActivateProvider();
+ ActivateProviderAndEula();
DeactivateProvider();
// No further call to Unschedule on second status callback.
DeactivateProvider();
@@ -586,20 +745,20 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldUnscheduleOnlyOnce) {
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenPersistentWifiParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the wifi interval for this class.
SetVariationParameter("fetching_interval_hours-wifi-active_ntp_user", "1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenPersistentFallbackParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the fallback interval for this class.
@@ -607,13 +766,13 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
"1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenShownWifiParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the on usage interval for this class.
@@ -621,13 +780,13 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
"1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenShownFallbackParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the fallback interval for this class.
@@ -635,13 +794,13 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
"1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenStartupWifiParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the on usage interval for this class.
@@ -649,13 +808,13 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
"1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
ReschedulesWhenStartupFallbackParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
- ActivateProvider();
+ ActivateProviderAndEula();
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
// null. Change the fallback interval for this class.
@@ -663,7 +822,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
"startup_fetching_interval_hours-fallback-active_ntp_user", "1.5");
// Schedule() should get called for the second time after params have changed.
- ActivateProvider();
+ ActivateProviderAndEula();
}
TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForShownTriggerOnWifi) {
@@ -673,16 +832,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForShownTriggerOnWifi) {
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The first call to NTPOpened results in a fetch.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
// Rescheduling after a succesful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Open NTP again after too short delay (one minute missing). UserClassifier
// defaults to UserClass::ACTIVE_NTP_USER - we work with the default interval
@@ -693,7 +852,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForShownTriggerOnWifi) {
// Open NTP after another delay, now together long enough to issue a fetch.
test_clock()->Advance(base::TimeDelta::FromMinutes(2));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -709,16 +868,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The first call to NTPOpened results in a fetch.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
// Rescheduling after a succesful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Open NTP again after too short delay. This time no fetch is executed.
test_clock()->Advance(base::TimeDelta::FromMinutes(20));
@@ -726,7 +885,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Open NTP after another delay, now together long enough to issue a fetch.
test_clock()->Advance(base::TimeDelta::FromMinutes(10));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -740,16 +899,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The first call to NTPOpened results in a fetch.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
// Rescheduling after a succesful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Open NTP again after too short delay. This time no fetch is executed.
test_clock()->Advance(base::TimeDelta::FromHours(5));
@@ -757,7 +916,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Open NTP after another delay, now together long enough to issue a fetch.
test_clock()->Advance(base::TimeDelta::FromHours(7));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -773,16 +932,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The first call to NTPOpened results in a fetch.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnSuggestionsSurfaceOpened();
// Rescheduling after a succesful fetch.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Open NTP again after too short delay. This time no fetch is executed.
test_clock()->Advance(base::TimeDelta::FromMinutes(20));
@@ -790,7 +949,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Open NTP after another delay, now together long enough to issue a fetch.
test_clock()->Advance(base::TimeDelta::FromMinutes(10));
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
scheduler()->OnSuggestionsSurfaceOpened();
}
@@ -798,7 +957,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
ShouldBlockFetchingForSomeTimeAfterHistoryCleared) {
// First enable the scheduler -- this will trigger the persistent scheduling.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// Clear the history.
scheduler()->OnHistoryCleared();
@@ -808,7 +967,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// A trigger after another 16 minutes is performed (more than 30m after
// clearing the history).
- EXPECT_CALL(*provider(), RefetchInTheBackground(_));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_));
test_clock()->Advance(base::TimeDelta::FromMinutes(16));
scheduler()->OnBrowserForegrounded();
}
@@ -819,15 +978,15 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// First enable the scheduler -- this will trigger the persistent scheduling.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The first trigger results in a fetch.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
- .WillOnce(SaveArg<0>(&signal_fetch_done));
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
+ .WillOnce(SaveArgByMove<0>(&signal_fetch_done));
scheduler()->OnBrowserForegrounded();
// Make the fetch successful -- this results in rescheduling.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
// Clear the suggestions - results in an immediate fetch.
EXPECT_CALL(*provider(), ReloadSuggestions());
@@ -860,16 +1019,16 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(6);
// First enable the scheduler -- this will trigger the persistent scheduling.
- ActivateProvider();
+ ActivateProviderAndEula();
// As long as the quota suffices, the call gets through.
RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
- EXPECT_CALL(*provider(), RefetchInTheBackground(_))
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_))
.Times(5)
- .WillRepeatedly(SaveArg<0>(&signal_fetch_done));
+ .WillRepeatedly(SaveArgByMove<0>(&signal_fetch_done));
for (int x = 0; x < 5; ++x) {
scheduler()->OnPersistentSchedulerWakeUp();
- signal_fetch_done.Run(Status::Success());
+ std::move(signal_fetch_done).Run(Status::Success());
}
// For the 6th time, it is blocked by the scheduling provider.
@@ -885,10 +1044,10 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// First enable the scheduler -- this will trigger the persistent scheduling.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
- ActivateProvider();
+ ActivateProviderAndEula();
// The startup triggers are ignored.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_)).Times(0);
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_)).Times(0);
scheduler()->OnBrowserForegrounded();
scheduler()->OnBrowserColdStart();
@@ -910,7 +1069,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, ShouldIgnoreSignalsWhenOffline) {
scheduler()->OnProviderActivated();
// All signals are ignored because of being offline.
- EXPECT_CALL(*provider(), RefetchInTheBackground(_)).Times(0);
+ EXPECT_CALL(*provider(), RefetchInTheBackgroundMock(_)).Times(0);
scheduler()->OnPersistentSchedulerWakeUp();
scheduler()->OnSuggestionsSurfaceOpened();
scheduler()->OnBrowserForegrounded();
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 f37187ee0fe..a3b6e8eb0ab 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
@@ -6,14 +6,9 @@
#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_H_
#include "base/callback.h"
-#include "base/gtest_prod_util.h"
#include "base/scoped_observer.h"
#include "components/prefs/pref_change_registrar.h"
-class PrefRegistrySimple;
-class PrefService;
-class SigninManagerBase;
-
namespace ntp_snippets {
enum class RemoteSuggestionsStatus : int {
@@ -32,58 +27,16 @@ class RemoteSuggestionsStatusService {
using StatusChangeCallback =
base::Callback<void(RemoteSuggestionsStatus old_status,
RemoteSuggestionsStatus new_status)>;
-
- RemoteSuggestionsStatusService(SigninManagerBase* signin_manager,
- PrefService* pref_service,
- const std::string& additional_toggle_pref);
-
- virtual ~RemoteSuggestionsStatusService();
-
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+ virtual ~RemoteSuggestionsStatusService() = default;
// Starts listening for changes from the dependencies. |callback| will be
// called when a significant change in state is detected.
- void Init(const StatusChangeCallback& callback);
+ virtual void Init(const StatusChangeCallback& callback) = 0;
// To be called when the signin state changed. Will compute the new
// state considering the initialisation configuration and the preferences,
// and notify via the registered callback if appropriate.
- void OnSignInStateChanged();
-
- private:
- // TODO(jkrcal): Rewrite the tests using the public API - observing status
- // changes instead of calling private GetStatusFromDeps() directly.
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceTest,
- SigninNeededIfSpecifiedByParam);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceTest, NoSigninNeeded);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceTest, DisabledViaPref);
-
- // Callback for the PrefChangeRegistrar.
- void OnSnippetsEnabledChanged();
-
- void OnStateChanged(RemoteSuggestionsStatus new_status);
-
- bool IsSignedIn() const;
-
- // Returns whether the service is explicitly disabled, by the user or by a
- // policy for example.
- bool IsExplicitlyDisabled() const;
-
- RemoteSuggestionsStatus GetStatusFromDeps() const;
-
- RemoteSuggestionsStatus status_;
- StatusChangeCallback status_change_callback_;
-
- // Name of a preference to be used as an additional toggle to guard the
- // remote suggestions provider.
- std::string additional_toggle_pref_;
-
- SigninManagerBase* signin_manager_;
- PrefService* pref_service_;
-
- PrefChangeRegistrar pref_change_registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsStatusService);
+ virtual void OnSignInStateChanged() = 0;
};
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc
index f035bba4f57..e4d6576d761 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc
@@ -1,8 +1,8 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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/ntp_snippets/remote/remote_suggestions_status_service.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service_impl.h"
#include <string>
@@ -16,7 +16,7 @@
namespace ntp_snippets {
-RemoteSuggestionsStatusService::RemoteSuggestionsStatusService(
+RemoteSuggestionsStatusServiceImpl::RemoteSuggestionsStatusServiceImpl(
SigninManagerBase* signin_manager,
PrefService* pref_service,
const std::string& additional_toggle_pref)
@@ -28,15 +28,16 @@ RemoteSuggestionsStatusService::RemoteSuggestionsStatusService(
!IsExplicitlyDisabled());
}
-RemoteSuggestionsStatusService::~RemoteSuggestionsStatusService() = default;
+RemoteSuggestionsStatusServiceImpl::~RemoteSuggestionsStatusServiceImpl() =
+ default;
// static
-void RemoteSuggestionsStatusService::RegisterProfilePrefs(
+void RemoteSuggestionsStatusServiceImpl::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kEnableSnippets, true);
}
-void RemoteSuggestionsStatusService::Init(
+void RemoteSuggestionsStatusServiceImpl::Init(
const StatusChangeCallback& callback) {
DCHECK(status_change_callback_.is_null());
@@ -51,22 +52,23 @@ void RemoteSuggestionsStatusService::Init(
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
prefs::kEnableSnippets,
- base::Bind(&RemoteSuggestionsStatusService::OnSnippetsEnabledChanged,
+ base::Bind(&RemoteSuggestionsStatusServiceImpl::OnSnippetsEnabledChanged,
base::Unretained(this)));
if (!additional_toggle_pref_.empty()) {
pref_change_registrar_.Add(
additional_toggle_pref_,
- base::Bind(&RemoteSuggestionsStatusService::OnSnippetsEnabledChanged,
- base::Unretained(this)));
+ base::Bind(
+ &RemoteSuggestionsStatusServiceImpl::OnSnippetsEnabledChanged,
+ base::Unretained(this)));
}
}
-void RemoteSuggestionsStatusService::OnSnippetsEnabledChanged() {
+void RemoteSuggestionsStatusServiceImpl::OnSnippetsEnabledChanged() {
OnStateChanged(GetStatusFromDeps());
}
-void RemoteSuggestionsStatusService::OnStateChanged(
+void RemoteSuggestionsStatusServiceImpl::OnStateChanged(
RemoteSuggestionsStatus new_status) {
if (new_status == status_) {
return;
@@ -76,17 +78,17 @@ void RemoteSuggestionsStatusService::OnStateChanged(
status_ = new_status;
}
-bool RemoteSuggestionsStatusService::IsSignedIn() const {
+bool RemoteSuggestionsStatusServiceImpl::IsSignedIn() const {
// TODO(dgn): remove the SigninManager dependency. It should be possible to
// replace it by passing the new state via OnSignInStateChanged().
return signin_manager_ && signin_manager_->IsAuthenticated();
}
-void RemoteSuggestionsStatusService::OnSignInStateChanged() {
+void RemoteSuggestionsStatusServiceImpl::OnSignInStateChanged() {
OnStateChanged(GetStatusFromDeps());
}
-bool RemoteSuggestionsStatusService::IsExplicitlyDisabled() const {
+bool RemoteSuggestionsStatusServiceImpl::IsExplicitlyDisabled() const {
if (!pref_service_->GetBoolean(prefs::kEnableSnippets)) {
DVLOG(1) << "[GetStatusFromDeps] Disabled via pref";
return true;
@@ -102,7 +104,7 @@ bool RemoteSuggestionsStatusService::IsExplicitlyDisabled() const {
return false;
}
-RemoteSuggestionsStatus RemoteSuggestionsStatusService::GetStatusFromDeps()
+RemoteSuggestionsStatus RemoteSuggestionsStatusServiceImpl::GetStatusFromDeps()
const {
if (IsExplicitlyDisabled()) {
return RemoteSuggestionsStatus::EXPLICITLY_DISABLED;
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
new file mode 100644
index 00000000000..dd74af7bffa
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h
@@ -0,0 +1,75 @@
+// 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_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_IMPL_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_IMPL_H_
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/scoped_observer.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service.h"
+#include "components/prefs/pref_change_registrar.h"
+
+class PrefRegistrySimple;
+class PrefService;
+class SigninManagerBase;
+
+namespace ntp_snippets {
+
+class RemoteSuggestionsStatusServiceImpl
+ : public RemoteSuggestionsStatusService {
+ public:
+ RemoteSuggestionsStatusServiceImpl(SigninManagerBase* signin_manager,
+ PrefService* pref_service,
+ const std::string& additional_toggle_pref);
+
+ ~RemoteSuggestionsStatusServiceImpl() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // RemoteSuggestionsStatusService implementation.
+ void Init(const StatusChangeCallback& callback) override;
+ void OnSignInStateChanged() override;
+
+ private:
+ // TODO(jkrcal): Rewrite the tests using the public API - observing status
+ // changes instead of calling private GetStatusFromDeps() directly.
+ FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceImplTest,
+ SigninNeededIfSpecifiedByParam);
+ FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceImplTest,
+ NoSigninNeeded);
+ FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsStatusServiceImplTest,
+ DisabledViaPref);
+
+ // Callback for the PrefChangeRegistrar.
+ void OnSnippetsEnabledChanged();
+
+ void OnStateChanged(RemoteSuggestionsStatus new_status);
+
+ bool IsSignedIn() const;
+
+ // Returns whether the service is explicitly disabled, by the user or by a
+ // policy for example.
+ bool IsExplicitlyDisabled() const;
+
+ RemoteSuggestionsStatus GetStatusFromDeps() const;
+
+ RemoteSuggestionsStatus status_;
+ StatusChangeCallback status_change_callback_;
+
+ // Name of a preference to be used as an additional toggle to guard the
+ // remote suggestions provider.
+ std::string additional_toggle_pref_;
+
+ SigninManagerBase* signin_manager_;
+ PrefService* pref_service_;
+
+ PrefChangeRegistrar pref_change_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsStatusServiceImpl);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_IMPL_H_
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc
index 65ca301f231..7fa670b89e9 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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/ntp_snippets/remote/remote_suggestions_status_service.h"
+#include "components/ntp_snippets/remote/remote_suggestions_status_service_impl.h"
#include <memory>
@@ -24,15 +24,15 @@
namespace ntp_snippets {
-class RemoteSuggestionsStatusServiceTest : public ::testing::Test {
+class RemoteSuggestionsStatusServiceImplTest : public ::testing::Test {
public:
- RemoteSuggestionsStatusServiceTest() {
- RemoteSuggestionsStatusService::RegisterProfilePrefs(
+ RemoteSuggestionsStatusServiceImplTest() {
+ RemoteSuggestionsStatusServiceImpl::RegisterProfilePrefs(
utils_.pref_service()->registry());
}
- std::unique_ptr<RemoteSuggestionsStatusService> MakeService() {
- return base::MakeUnique<RemoteSuggestionsStatusService>(
+ std::unique_ptr<RemoteSuggestionsStatusServiceImpl> MakeService() {
+ return base::MakeUnique<RemoteSuggestionsStatusServiceImpl>(
utils_.fake_signin_manager(), utils_.pref_service(), std::string());
}
@@ -41,14 +41,14 @@ class RemoteSuggestionsStatusServiceTest : public ::testing::Test {
variations::testing::VariationParamsManager params_manager_;
};
-TEST_F(RemoteSuggestionsStatusServiceTest, NoSigninNeeded) {
+TEST_F(RemoteSuggestionsStatusServiceImplTest, NoSigninNeeded) {
auto service = MakeService();
// By default, no signin is required.
EXPECT_EQ(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT,
service->GetStatusFromDeps());
- // One can still sign in.
+// One can still sign in.
#if defined(OS_CHROMEOS)
utils_.fake_signin_manager()->SignIn("foo@bar.com");
#else
@@ -58,7 +58,7 @@ TEST_F(RemoteSuggestionsStatusServiceTest, NoSigninNeeded) {
service->GetStatusFromDeps());
}
-TEST_F(RemoteSuggestionsStatusServiceTest, DisabledViaPref) {
+TEST_F(RemoteSuggestionsStatusServiceImplTest, DisabledViaPref) {
auto service = MakeService();
// The default test setup is signed out. The service is enabled.
@@ -70,7 +70,7 @@ TEST_F(RemoteSuggestionsStatusServiceTest, DisabledViaPref) {
EXPECT_EQ(RemoteSuggestionsStatus::EXPLICITLY_DISABLED,
service->GetStatusFromDeps());
- // The other dependencies shouldn't matter anymore.
+// The other dependencies shouldn't matter anymore.
#if defined(OS_CHROMEOS)
utils_.fake_signin_manager()->SignIn("foo@bar.com");
#else
diff --git a/chromium/components/ntp_snippets/remote/test_utils.cc b/chromium/components/ntp_snippets/remote/test_utils.cc
index 18809331a60..3c5687474f3 100644
--- a/chromium/components/ntp_snippets/remote/test_utils.cc
+++ b/chromium/components/ntp_snippets/remote/test_utils.cc
@@ -15,6 +15,7 @@
#include "components/sync/driver/fake_sync_service.h"
namespace ntp_snippets {
+
namespace test {
FakeSyncService::FakeSyncService()
@@ -81,4 +82,5 @@ void RemoteSuggestionsTestUtils::ResetSigninManager() {
}
} // namespace test
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/test_utils.h b/chromium/components/ntp_snippets/remote/test_utils.h
index ed825a6196f..d956011596a 100644
--- a/chromium/components/ntp_snippets/remote/test_utils.h
+++ b/chromium/components/ntp_snippets/remote/test_utils.h
@@ -6,12 +6,13 @@
#define COMPONENTS_NTP_SNIPPETS_REMOTE_TEST_UTILS_H_
#include <memory>
+#include <string>
+#include <vector>
#include "build/build_config.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/sync/driver/fake_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "testing/gtest/include/gtest/gtest.h"
class AccountTrackerService;
class FakeProfileOAuth2TokenService;
@@ -27,6 +28,7 @@ using SigninManagerForTest = FakeSigninManager;
#endif // OS_CHROMEOS
namespace ntp_snippets {
+
namespace test {
class FakeSyncService : public syncer::FakeSyncService {
@@ -75,6 +77,7 @@ class RemoteSuggestionsTestUtils {
};
} // namespace test
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_TEST_UTILS_H_
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
index eae4fc2cb30..e59f1071093 100644
--- a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -220,23 +220,23 @@ void ForeignSessionsSuggestionsProvider::DismissSuggestion(
void ForeignSessionsSuggestionsProvider::FetchSuggestionImage(
const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) {
+ ImageFetchedCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, gfx::Image()));
+ FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
}
void ForeignSessionsSuggestionsProvider::Fetch(
const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) {
+ FetchDoneCallback callback) {
LOG(DFATAL)
<< "ForeignSessionsSuggestionsProvider has no |Fetch| functionality!";
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback,
- Status(StatusCode::PERMANENT_ERROR,
- "ForeignSessionsSuggestionsProvider "
- "has no |Fetch| functionality!"),
- base::Passed(std::vector<ContentSuggestion>())));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ Status(StatusCode::PERMANENT_ERROR,
+ "ForeignSessionsSuggestionsProvider "
+ "has no |Fetch| functionality!"),
+ std::vector<ContentSuggestion>()));
}
void ForeignSessionsSuggestionsProvider::ClearHistory(
@@ -265,7 +265,7 @@ void ForeignSessionsSuggestionsProvider::ClearCachedSuggestions(
void ForeignSessionsSuggestionsProvider::GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) {
+ DismissedSuggestionsCallback callback) {
DCHECK_EQ(category, provided_category_);
InverseDismissedItemFilter filter(pref_service_);
// Use GetSuggestionCandidates instead of BuildSuggestions(), to avoid the
@@ -275,7 +275,7 @@ void ForeignSessionsSuggestionsProvider::GetDismissedSuggestionsForDebugging(
for (auto data : GetSuggestionCandidates(filter.ToCallback())) {
suggestions.push_back(BuildSuggestion(data));
}
- callback.Run(std::move(suggestions));
+ std::move(callback).Run(std::move(suggestions));
}
void ForeignSessionsSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
index 0fa52849ac6..3450c80b312 100644
--- a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
@@ -55,10 +55,10 @@ class ForeignSessionsSuggestionsProvider : public ContentSuggestionsProvider {
CategoryInfo GetCategoryInfo(Category category) override;
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
+ ImageFetchedCallback callback) override;
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
+ FetchDoneCallback callback) override;
void ClearHistory(
base::Time begin,
base::Time end,
@@ -66,7 +66,7 @@ class ForeignSessionsSuggestionsProvider : public ContentSuggestionsProvider {
void ClearCachedSuggestions(Category category) override;
void GetDismissedSuggestionsForDebugging(
Category category,
- const DismissedSuggestionsCallback& callback) override;
+ DismissedSuggestionsCallback callback) override;
void ClearDismissedSuggestionsForDebugging(Category category) override;
void OnForeignTabChange();
diff --git a/chromium/components/ntp_snippets/status.h b/chromium/components/ntp_snippets/status.h
index 83710451c7e..4b62053f309 100644
--- a/chromium/components/ntp_snippets/status.h
+++ b/chromium/components/ntp_snippets/status.h
@@ -9,11 +9,18 @@
namespace ntp_snippets {
-// This enum indicates how an operation was completed.
+// This enum indicates how an operation was completed. These values are written
+// to logs. New enum values can be added, but existing enums must never be
+// renumbered or deleted and reused.
enum class StatusCode {
- SUCCESS, // The operation has been completed successfully.
- TEMPORARY_ERROR, // The operation failed but retrying might solve the error.
- PERMANENT_ERROR, // The operation failed and would fail again if retried.
+ // The operation has been completed successfully.
+ SUCCESS = 0,
+ // The operation failed but retrying might solve the error.
+ TEMPORARY_ERROR = 1,
+ // The operation failed and would fail again if retried.
+ PERMANENT_ERROR = 2,
+
+ STATUS_CODE_COUNT
};
// This struct provides the status code of a request and an optional message
diff --git a/chromium/components/ntp_snippets/time_serialization.cc b/chromium/components/ntp_snippets/time_serialization.cc
new file mode 100644
index 00000000000..ba86b69f3d5
--- /dev/null
+++ b/chromium/components/ntp_snippets/time_serialization.cc
@@ -0,0 +1,18 @@
+// 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/ntp_snippets/time_serialization.h"
+
+namespace ntp_snippets {
+
+int64_t SerializeTime(const base::Time& time) {
+ base::TimeDelta delta = time - base::Time();
+ return delta.InMicroseconds();
+}
+
+base::Time DeserializeTime(int64_t serialized_time) {
+ return base::Time() + base::TimeDelta::FromMicroseconds(serialized_time);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/time_serialization.h b/chromium/components/ntp_snippets/time_serialization.h
new file mode 100644
index 00000000000..46d927cff4d
--- /dev/null
+++ b/chromium/components/ntp_snippets/time_serialization.h
@@ -0,0 +1,22 @@
+// 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_NTP_SNIPPETS_TIME_SERIALIZATION_H_
+#define COMPONENTS_NTP_SNIPPETS_TIME_SERIALIZATION_H_
+
+#include "base/time/time.h"
+
+namespace ntp_snippets {
+
+// Backward compatible replacements for deprecated
+// base::Time::To/FromInternalValue. Only for serialization. Do not change them,
+// because the values based on them are persisted in multiple places (e.g.
+// prefs, on-disk database). The value repesents number of microseconds since
+// 1st of January 1601 (aka Windows epoch).
+int64_t SerializeTime(const base::Time& time);
+base::Time DeserializeTime(int64_t serialized_time);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_TIME_SERIALIZATION_H_
diff --git a/chromium/components/ntp_snippets_strings.grdp b/chromium/components/ntp_snippets_strings.grdp
index 5f047253d27..672811ecb1f 100644
--- a/chromium/components/ntp_snippets_strings.grdp
+++ b/chromium/components/ntp_snippets_strings.grdp
@@ -15,10 +15,22 @@
</message>
</if>
- <message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER" desc="Header of the articles section, which is a list of news articles displayed as cards on the New Tab Page.">
- Articles for you
+ <message name="IDS_NTP_ARTICLE_SUGGESTIONS_NOT_AVAILABLE" desc="On the New Tab Page, text of a toast transiently shown to the user to indicate that no article could be fetched.">
+ Articles aren't available right now
</message>
+ <if expr="use_titlecase">
+ <message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER" desc="Header of the articles section, which is a list of news articles displayed as cards on the New Tab Page.">
+ Articles for You
+ </message>
+ </if>
+
+ <if expr="not use_titlecase">
+ <message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER" desc="Header of the articles section, which is a list of news articles displayed as cards on the New Tab Page.">
+ Articles for you
+ </message>
+ </if>
+
<message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_EMPTY" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see suggested articles in this area in the future.">
Your suggested articles appear here
</message>
@@ -48,9 +60,17 @@
Your nearby suggestions appear here
</message>
- <message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_HEADER" desc="Header of the Reading List section. The Reading List section shows a list of unread pages from the Reading List.">
- Reading list
- </message>
+ <if expr="use_titlecase">
+ <message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_HEADER" desc="Header of the Reading List section. The Reading List section shows a list of unread pages from the Reading List.">
+ Reading List
+ </message>
+ </if>
+
+ <if expr="not use_titlecase">
+ <message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_HEADER" desc="Header of the Reading List section. The Reading List section shows a list of unread pages from the Reading List.">
+ Reading list
+ </message>
+ </if>
<message name="IDS_NTP_READING_LIST_SUGGESTIONS_SECTION_EMPTY" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see Reading List articles in this area in the future.">
Pages from your reading list appear here
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index d9704187e88..300d4758576 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -28,6 +28,7 @@ static_library("ntp_tiles") {
"popular_sites_impl.h",
"pref_names.cc",
"pref_names.h",
+ "section_type.h",
"switches.cc",
"switches.h",
"tile_source.h",
@@ -111,6 +112,7 @@ source_set("unit_tests") {
if (is_android) {
java_cpp_enum("ntp_tiles_enums_java") {
sources = [
+ "section_type.h",
"tile_source.h",
"tile_visual_type.h",
]
diff --git a/chromium/components/ntp_tiles/constants.cc b/chromium/components/ntp_tiles/constants.cc
index 6af7a1727cd..048cf796baa 100644
--- a/chromium/components/ntp_tiles/constants.cc
+++ b/chromium/components/ntp_tiles/constants.cc
@@ -18,6 +18,12 @@ extern const base::Feature kPopularSitesBakedInContentFeature{
extern const base::Feature kNtpMostLikelyFaviconsFromServerFeature{
"NTPMostLikelyFaviconsFromServer", base::FEATURE_DISABLED_BY_DEFAULT};
+extern const base::Feature kLowerResolutionFaviconsFeature{
+ "NTPTilesLowerResolutionFavicons", base::FEATURE_DISABLED_BY_DEFAULT};
+
+extern const base::Feature kSiteExplorationUiFeature{
+ "SiteExplorationUi", base::FEATURE_DISABLED_BY_DEFAULT};
+
bool AreNtpMostLikelyFaviconsFromServerEnabled() {
// Check if the experimental flag is forced on or off.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chromium/components/ntp_tiles/constants.h b/chromium/components/ntp_tiles/constants.h
index 4af8d54413b..03a2be48a1e 100644
--- a/chromium/components/ntp_tiles/constants.h
+++ b/chromium/components/ntp_tiles/constants.h
@@ -23,6 +23,13 @@ extern const base::Feature kPopularSitesBakedInContentFeature;
// Likely tiles on the New Tab Page.
extern const base::Feature kNtpMostLikelyFaviconsFromServerFeature;
+// Feature to allow displaying lower resolution favicons for Tiles on the New
+// Tab Page.
+extern const base::Feature kLowerResolutionFaviconsFeature;
+
+// Feature to provide site exploration tiles in addition to personal tiles.
+extern const base::Feature kSiteExplorationUiFeature;
+
// Use this to find out whether the kNtpMostLikelyFaviconsFromServerFeature is
// enabled. This helper function abstracts iOS special way to override the
// feature (via command-line params).
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl.cc b/chromium/components/ntp_tiles/icon_cacher_impl.cc
index 7b9e06ff2d4..c1518fd5e8c 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl.cc
@@ -133,7 +133,7 @@ void IconCacherImpl::OnGetFaviconImageForPageURLFinished(
destination: WEBSITE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification: "Not implemented."
})");
@@ -252,7 +252,7 @@ void IconCacherImpl::OnGetLargeIconOrFallbackStyleFinished(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can disable this feature via 'History' setting under "
"'Advanced sync settings'."
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index 2ce20e89b7d..94ffc498e72 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -437,9 +437,7 @@ TEST_F(IconCacherTestPopularSites, LargeNotCachedAndFetchPerformedOnlyOnce) {
class IconCacherTestMostLikely : public IconCacherTestBase {
protected:
IconCacherTestMostLikely()
- : large_icon_service_background_task_runner_(
- new base::TestSimpleTaskRunner()),
- fetcher_for_large_icon_service_(
+ : fetcher_for_large_icon_service_(
base::MakeUnique<::testing::StrictMock<MockImageFetcher>>()),
fetcher_for_icon_cacher_(
base::MakeUnique<::testing::StrictMock<MockImageFetcher>>()) {
@@ -453,8 +451,6 @@ class IconCacherTestMostLikely : public IconCacherTestBase {
SetDesiredImageFrameSize(gfx::Size(128, 128)));
}
- scoped_refptr<base::TestSimpleTaskRunner>
- large_icon_service_background_task_runner_;
std::unique_ptr<MockImageFetcher> fetcher_for_large_icon_service_;
std::unique_ptr<MockImageFetcher> fetcher_for_icon_cacher_;
};
@@ -467,8 +463,7 @@ TEST_F(IconCacherTestMostLikely, Cached) {
PreloadIcon(page_url, icon_url, favicon_base::TOUCH_ICON, 128, 128);
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -502,8 +497,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchSucceeded) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -511,7 +505,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchSucceeded) {
// Both these task runners need to be flushed in order to get |done| called by
// running the main loop.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
loop.Run();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
@@ -541,8 +535,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchFailed) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -550,7 +543,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchFailed) {
// Both these task runners need to be flushed before flushing the main thread
// queue in order to finish the work.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
WaitForMainThreadTasksToFinish();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
@@ -573,8 +566,7 @@ TEST_F(IconCacherTestMostLikely, HandlesEmptyCallbacksNicely) {
.WillOnce(PassFetch(128, 128));
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -582,7 +574,7 @@ TEST_F(IconCacherTestMostLikely, HandlesEmptyCallbacksNicely) {
// Both these task runners need to be flushed before flushing the main thread
// queue in order to finish the work.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
WaitForMainThreadTasksToFinish();
// Even though the callbacks are not called, the icon gets written out.
@@ -609,8 +601,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchPerformedOnlyOnce) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -619,7 +610,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchPerformedOnlyOnce) {
// Both these task runners need to be flushed in order to get |done| called by
// running the main loop.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
loop.Run();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
diff --git a/chromium/components/ntp_tiles/metrics.cc b/chromium/components/ntp_tiles/metrics.cc
index 4064c1594f3..bcd9f4a6a6d 100644
--- a/chromium/components/ntp_tiles/metrics.cc
+++ b/chromium/components/ntp_tiles/metrics.cc
@@ -23,7 +23,8 @@ const int kMaxNumTiles = 12;
// Identifiers for the various tile sources.
const char kHistogramClientName[] = "client";
const char kHistogramServerName[] = "server";
-const char kHistogramPopularName[] = "popular";
+const char kHistogramPopularName[] = "popular_fetched";
+const char kHistogramBakedInName[] = "popular_baked_in";
const char kHistogramWhitelistName[] = "whitelist";
const char kHistogramHomepageName[] = "homepage";
@@ -51,6 +52,8 @@ std::string GetSourceHistogramName(TileSource source) {
switch (source) {
case TileSource::TOP_SITES:
return kHistogramClientName;
+ case TileSource::POPULAR_BAKED_IN:
+ return kHistogramBakedInName;
case TileSource::POPULAR:
return kHistogramPopularName;
case TileSource::WHITELIST:
diff --git a/chromium/components/ntp_tiles/metrics_unittest.cc b/chromium/components/ntp_tiles/metrics_unittest.cc
index dbbe4c1e8e3..cba9de50eeb 100644
--- a/chromium/components/ntp_tiles/metrics_unittest.cc
+++ b/chromium/components/ntp_tiles/metrics_unittest.cc
@@ -71,7 +71,7 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForIcons) {
base::Bucket(/*min=*/3, /*count=*/1),
base::Bucket(/*min=*/4, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
- "NewTabPage.SuggestionsImpression.popular"),
+ "NewTabPage.SuggestionsImpression.popular_fetched"),
ElementsAre(base::Bucket(/*min=*/7, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
ElementsAre(base::Bucket(/*min=*/ICON_REAL, /*count=*/4),
@@ -83,9 +83,10 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForIcons) {
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
ElementsAre(base::Bucket(/*min=*/ICON_REAL, /*count=*/3),
base::Bucket(/*min=*/ICON_COLOR, /*count=*/2)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- ElementsAre(base::Bucket(/*min=*/ICON_COLOR,
- /*count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+ ElementsAre(base::Bucket(/*min=*/ICON_COLOR,
+ /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -124,7 +125,7 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForThumbnails) {
histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.client"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
- "NewTabPage.SuggestionsImpression.popular"),
+ "NewTabPage.SuggestionsImpression.popular_fetched"),
ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/2),
@@ -133,8 +134,9 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForThumbnails) {
ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
ElementsAre(base::Bucket(/*min=*/THUMBNAIL_FAILED, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
IsEmpty());
@@ -155,8 +157,9 @@ TEST(RecordTileClickTest, ShouldRecordUmaForIcon) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
@@ -183,8 +186,9 @@ TEST(RecordTileClickTest, ShouldRecordUmaForThumbnail) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
IsEmpty());
@@ -212,8 +216,9 @@ TEST(RecordTileClickTest, ShouldNotRecordUnknownTileType) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
// But all of the tile type histograms should be empty.
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index 45a4bcddbb8..7327615bab2 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -5,12 +5,14 @@
#include "components/ntp_tiles/most_visited_sites.h"
#include <algorithm>
+#include <iterator>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/metrics/user_metrics.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/history/core/browser/top_sites.h"
#include "components/ntp_tiles/constants.h"
@@ -33,13 +35,27 @@ namespace {
const base::Feature kDisplaySuggestionsServiceTiles{
"DisplaySuggestionsServiceTiles", base::FEATURE_ENABLED_BY_DEFAULT};
-// The maximum index of the home page tile.
-const size_t kMaxHomeTileIndex = 3;
+// URL host prefixes. Hosts with these prefixes often redirect to each other, or
+// have the same content.
+// Popular sites are excluded if the user has visited a page whose host only
+// differs by one of these prefixes. Even if the URL does not point to the exact
+// same page, the user will have a personalized suggestion that is more likely
+// to be of use for them.
+// A cleaner way could be checking the history for redirects but this requires
+// the page to be visited on the device.
+const char* kKnownGenericPagePrefixes[] = {
+ "m.", "mobile.", // Common prefixes among popular sites.
+ "edition.", // Used among news papers (CNN, Independent, ...)
+ "www.", // Usually no-www domains redirect to www or vice-versa.
+ // The following entry MUST REMAIN LAST as it is prefix of every string!
+ ""}; // The no-www domain matches domains on same level .
// Determine whether we need any tiles from PopularSites to fill up a grid of
-// |num_tiles| tiles.
+// |num_tiles| tiles. If exploration sections are used, we need popular sites
+// regardless of how many tiles we already have.
bool NeedPopularSites(const PrefService* prefs, int num_tiles) {
- return prefs->GetInteger(prefs::kNumPersonalTiles) < num_tiles;
+ return base::FeatureList::IsEnabled(kSiteExplorationUiFeature) ||
+ prefs->GetInteger(prefs::kNumPersonalTiles) < num_tiles;
}
bool AreURLsEquivalent(const GURL& url1, const GURL& url2) {
@@ -56,6 +72,16 @@ bool HasHomeTile(const NTPTilesVector& tiles) {
return false;
}
+std::string StripFirstGenericPrefix(const std::string& host) {
+ for (const char* prefix : kKnownGenericPagePrefixes) {
+ if (base::StartsWith(host, prefix, base::CompareCase::INSENSITIVE_ASCII)) {
+ return std::string(
+ base::TrimString(host, prefix, base::TrimPositions::TRIM_LEADING));
+ }
+ }
+ return host;
+}
+
} // namespace
MostVisitedSites::MostVisitedSites(
@@ -89,12 +115,27 @@ MostVisitedSites::~MostVisitedSites() {
supervisor_->SetObserver(nullptr);
}
+// static
+bool MostVisitedSites::IsHostOrMobilePageKnown(
+ const std::set<std::string>& hosts_to_skip,
+ const std::string& host) {
+ std::string no_prefix_host = StripFirstGenericPrefix(host);
+ for (const char* prefix : kKnownGenericPagePrefixes) {
+ if (hosts_to_skip.count(prefix + no_prefix_host) ||
+ hosts_to_skip.count(prefix + host)) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool MostVisitedSites::DoesSourceExist(TileSource source) const {
switch (source) {
case TileSource::TOP_SITES:
return top_sites_ != nullptr;
case TileSource::SUGGESTIONS_SERVICE:
return suggestions_service_ != nullptr;
+ case TileSource::POPULAR_BAKED_IN:
case TileSource::POPULAR:
return popular_sites_ != nullptr;
case TileSource::WHITELIST:
@@ -128,10 +169,6 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
}
if (top_sites_) {
- // TopSites updates itself after a delay. To ensure up-to-date results,
- // force an update now.
- top_sites_->SyncWithHistory();
-
// Register as TopSitesObserver so that we can update ourselves when the
// TopSites changes.
top_sites_observer_.Add(top_sites_.get());
@@ -148,6 +185,14 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
}
void MostVisitedSites::Refresh() {
+ if (top_sites_) {
+ // TopSites updates itself after a delay. To ensure up-to-date results,
+ // force an update now.
+ // TODO(mastiz): Is seems unnecessary to refresh TopSites if we will end up
+ // using server-side suggestions.
+ top_sites_->SyncWithHistory();
+ }
+
suggestions_service_->FetchSuggestionsData();
}
@@ -345,38 +390,66 @@ NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
return whitelist_tiles;
}
-NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
+std::map<SectionType, NTPTilesVector>
+MostVisitedSites::CreatePopularSitesSections(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles) {
+ std::map<SectionType, NTPTilesVector> sections = {
+ std::make_pair(SectionType::PERSONALIZED, NTPTilesVector())};
// For child accounts popular sites tiles will not be added.
if (supervisor_ && supervisor_->IsChildProfile()) {
- return NTPTilesVector();
+ return sections;
}
if (!popular_sites_ || !ShouldShowPopularSites()) {
- return NTPTilesVector();
+ return sections;
+ }
+
+ const std::set<std::string> no_hosts;
+ for (const auto& section_type_and_sites : popular_sites()->sections()) {
+ 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 = num_sites_ - num_actual_tiles;
+ sections[type] =
+ CreatePopularSitesTiles(/*popular_sites=*/sites,
+ /*hosts_to_skip=*/used_hosts,
+ /*num_max_tiles=*/num_required_tiles);
+ } else {
+ sections[type] = CreatePopularSitesTiles(/*popular_sites=*/sites,
+ /*hosts_to_skip=*/no_hosts,
+ /*num_max_tiles=*/num_sites_);
+ }
}
+ return sections;
+}
+NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
+ const PopularSites::SitesVector& sites_vector,
+ const std::set<std::string>& hosts_to_skip,
+ size_t num_max_tiles) {
// Collect non-blacklisted popular suggestions, skipping those already present
// in the personal suggestions.
NTPTilesVector popular_sites_tiles;
- for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
- if (popular_sites_tiles.size() + num_actual_tiles >= num_sites_)
+ for (const PopularSites::Site& popular_site : sites_vector) {
+ if (popular_sites_tiles.size() >= num_max_tiles) {
break;
+ }
// Skip blacklisted sites.
if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url))
continue;
const std::string& host = popular_site.url.host();
- // Skip tiles already present in personal or whitelists.
- if (used_hosts.find(host) != used_hosts.end())
+ if (IsHostOrMobilePageKnown(hosts_to_skip, host)) {
continue;
+ }
NTPTile tile;
tile.title = popular_site.title;
tile.url = GURL(popular_site.url);
- tile.source = TileSource::POPULAR;
+ tile.source = popular_site.baked_in ? TileSource::POPULAR_BAKED_IN
+ : TileSource::POPULAR;
popular_sites_tiles.push_back(std::move(tile));
base::Closure icon_available =
base::Bind(&MostVisitedSites::OnIconMadeAvailable,
@@ -404,38 +477,34 @@ NTPTilesVector MostVisitedSites::InsertHomeTile(
const GURL& home_page_url = home_page_client_->GetHomePageUrl();
NTPTilesVector new_tiles;
- // Add the home tile to the first four tiles.
- NTPTile home_tile;
- home_tile.url = home_page_url;
- home_tile.title = title;
- home_tile.source = TileSource::HOMEPAGE;
-
bool home_tile_added = false;
- size_t index = 0;
- while (index < tiles.size() && new_tiles.size() < num_sites_) {
- bool hosts_are_equal = tiles[index].url.host() == home_page_url.host();
+ for (auto& tile : tiles) {
+ if (new_tiles.size() >= num_sites_) {
+ break;
+ }
- // Add the home tile to the first four tiles
- // or at the position of a tile that has the same host
- // and is ranked higher.
// TODO(fhorschig): Introduce a more sophisticated deduplication.
- if (!home_tile_added && (index >= kMaxHomeTileIndex || hosts_are_equal)) {
- new_tiles.push_back(std::move(home_tile));
+ if (tile.url.host() == home_page_url.host()) {
+ tile.source = TileSource::HOMEPAGE;
home_tile_added = true;
- continue; // Do not advance the current tile index.
- }
-
- // Add non-home page tiles.
- if (!hosts_are_equal) {
- new_tiles.push_back(std::move(tiles[index]));
}
- ++index;
+ new_tiles.push_back(std::move(tile));
}
// Add the home page tile if there are less than 4 tiles
// and none of them is the home page (and there is space left).
- if (!home_tile_added && new_tiles.size() < num_sites_) {
+ if (!home_tile_added) {
+ // Make room for the home page tile.
+ if (new_tiles.size() >= num_sites_) {
+ new_tiles.pop_back();
+ }
+
+ NTPTile home_tile;
+ home_tile.url = home_page_url;
+ home_tile.title = title;
+ home_tile.source = TileSource::HOMEPAGE;
+
new_tiles.push_back(std::move(home_tile));
}
return new_tiles;
@@ -463,13 +532,14 @@ void MostVisitedSites::SaveTilesAndNotify(NTPTilesVector personal_tiles) {
CreateWhitelistEntryPointTiles(used_hosts, num_actual_tiles);
AddToHostsAndTotalCount(whitelist_tiles, &used_hosts, &num_actual_tiles);
- NTPTilesVector popular_sites_tiles =
- CreatePopularSitesTiles(used_hosts, num_actual_tiles);
- AddToHostsAndTotalCount(popular_sites_tiles, &used_hosts, &num_actual_tiles);
+ std::map<SectionType, NTPTilesVector> sections =
+ CreatePopularSitesSections(used_hosts, num_actual_tiles);
+ AddToHostsAndTotalCount(sections[SectionType::PERSONALIZED], &used_hosts,
+ &num_actual_tiles);
NTPTilesVector new_tiles =
MergeTiles(std::move(personal_tiles), std::move(whitelist_tiles),
- std::move(popular_sites_tiles));
+ std::move(sections[SectionType::PERSONALIZED]));
if (current_tiles_.has_value() && (*current_tiles_ == new_tiles)) {
return;
}
@@ -483,10 +553,10 @@ void MostVisitedSites::SaveTilesAndNotify(NTPTilesVector personal_tiles) {
num_personal_tiles++;
}
prefs_->SetInteger(prefs::kNumPersonalTiles, num_personal_tiles);
-
if (!observer_)
return;
- observer_->OnMostVisitedURLsAvailable(*current_tiles_);
+ sections[SectionType::PERSONALIZED] = *current_tiles_;
+ observer_->OnURLsAvailable(sections);
}
// static
@@ -509,10 +579,12 @@ void MostVisitedSites::OnPopularSitesDownloaded(bool success) {
return;
}
- for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
- // Ignore callback; these icons will be seen on the *next* NTP.
- icon_cacher_->StartFetchPopularSites(popular_site, base::Closure(),
- base::Closure());
+ for (const auto& section : popular_sites_->sections()) {
+ for (const PopularSites::Site& site : section.second) {
+ // Ignore callback; these icons will be seen on the *next* NTP.
+ icon_cacher_->StartFetchPopularSites(site, base::Closure(),
+ base::Closure());
+ }
}
}
diff --git a/chromium/components/ntp_tiles/most_visited_sites.h b/chromium/components/ntp_tiles/most_visited_sites.h
index 661623d30d4..2331c58f3ca 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.h
+++ b/chromium/components/ntp_tiles/most_visited_sites.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -15,6 +16,7 @@
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
@@ -24,6 +26,7 @@
#include "components/history/core/browser/top_sites_observer.h"
#include "components/ntp_tiles/ntp_tile.h"
#include "components/ntp_tiles/popular_sites.h"
+#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/tile_source.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
@@ -85,7 +88,9 @@ class MostVisitedSites : public history::TopSitesObserver,
// The observer to be notified when the list of most visited sites changes.
class Observer {
public:
- virtual void OnMostVisitedURLsAvailable(const NTPTilesVector& tiles) = 0;
+ // |sections| must at least contain the PERSONALIZED section.
+ virtual void OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) = 0;
virtual void OnIconMadeAvailable(const GURL& site_url) = 0;
protected:
@@ -165,6 +170,22 @@ class MostVisitedSites : public history::TopSitesObserver,
NTPTilesVector popular_tiles);
private:
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainWithNoWwwDomain);
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainByRemovingMobilePrefixes);
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainByReplacingMobilePrefixes);
+
+ // This function tries to match the given |host| to a close fit in
+ // |hosts_to_skip| by removing a prefix that is commonly used to redirect from
+ // or to mobile pages (m.xyz.com --> xyz.com).
+ // If this approach fails, the prefix is replaced by another prefix.
+ // That way, true is returned for m.x.com if www.x.com is in |hosts_to_skip|.
+ static bool IsHostOrMobilePageKnown(
+ const std::set<std::string>& hosts_to_skip,
+ const std::string& host);
+
// Initialize the query to Top Sites. Called if the SuggestionsService
// returned no data.
void InitiateTopSitesQuery();
@@ -193,11 +214,19 @@ class MostVisitedSites : public history::TopSitesObserver,
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
- // Creates popular tiles whose hosts weren't used yet.
- NTPTilesVector CreatePopularSitesTiles(
+ // Creates tiles for all popular site sections. Uses |num_actual_tiles| and
+ // |used_hosts| to restrict results for the PERSONALIZED section.
+ std::map<SectionType, NTPTilesVector> CreatePopularSitesSections(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
+ // Creates tiles for |sites_vector|. The returned vector will neither contain
+ // more than |num_max_tiles| nor include sites in |hosts_to_skip|.
+ NTPTilesVector CreatePopularSitesTiles(
+ const PopularSites::SitesVector& sites_vector,
+ const std::set<std::string>& hosts_to_skip,
+ size_t num_max_tiles);
+
// Initiates a query for the home page tile if needed and calls
// |SaveTilesAndNotify| in the end.
void InitiateNotificationForNewTiles(NTPTilesVector new_tiles);
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index 43bdea7dc97..0eb30120ee7 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <ostream>
#include <string>
@@ -29,6 +30,7 @@
#include "components/ntp_tiles/json_unsafe_parser.h"
#include "components/ntp_tiles/popular_sites_impl.h"
#include "components/ntp_tiles/pref_names.h"
+#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/switches.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "net/url_request/test_url_fetcher_factory.h"
@@ -59,11 +61,14 @@ using testing::ByMove;
using testing::Contains;
using testing::ElementsAre;
using testing::Eq;
+using testing::Ge;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
+using testing::Key;
using testing::Mock;
using testing::Not;
+using testing::Pair;
using testing::Return;
using testing::ReturnRef;
using testing::SaveArg;
@@ -87,13 +92,17 @@ MATCHER_P3(MatchesTile, title, url, source, PrintTile(title, url, source)) {
arg.source == source;
}
-MATCHER_P3(FirstTileIs,
+MATCHER_P3(FirstPersonalizedTileIs,
title,
url,
source,
std::string("first tile ") + PrintTile(title, url, source)) {
- return !arg.empty() && arg[0].title == base::ASCIIToUTF16(title) &&
- arg[0].url == GURL(url) && arg[0].source == source;
+ if (arg.count(SectionType::PERSONALIZED) == 0) {
+ return false;
+ }
+ const NTPTilesVector& tiles = arg.at(SectionType::PERSONALIZED);
+ return !tiles.empty() && tiles[0].title == base::ASCIIToUTF16(title) &&
+ tiles[0].url == GURL(url) && tiles[0].source == source;
}
// testing::InvokeArgument<N> does not work with base::Callback, fortunately
@@ -208,7 +217,8 @@ class MockSuggestionsService : public SuggestionsService {
class MockMostVisitedSitesObserver : public MostVisitedSites::Observer {
public:
- MOCK_METHOD1(OnMostVisitedURLsAvailable, void(const NTPTilesVector& tiles));
+ MOCK_METHOD1(OnURLsAvailable,
+ void(const std::map<SectionType, NTPTilesVector>& sections));
MOCK_METHOD1(OnIconMadeAvailable, void(const GURL& site_url));
};
@@ -273,10 +283,10 @@ class PopularSitesFactoryForTest {
PopularSitesImpl::RegisterProfilePrefs(pref_service->registry());
if (enabled) {
prefs_->SetString(prefs::kPopularSitesOverrideCountry, "IN");
- prefs_->SetString(prefs::kPopularSitesOverrideVersion, "7");
+ prefs_->SetString(prefs::kPopularSitesOverrideVersion, "5");
url_fetcher_factory_.SetFakeResponse(
- GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_7.json"),
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_5.json"),
R"([{
"title": "PopularSite1",
"url": "http://popularsite1/",
@@ -289,6 +299,70 @@ class PopularSitesFactoryForTest {
},
])",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ url_fetcher_factory_.SetFakeResponse(
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_US_5.json"),
+ R"([{
+ "title": "ESPN",
+ "url": "http://www.espn.com",
+ "favicon_url": "http://www.espn.com/favicon.ico"
+ }, {
+ "title": "Mobile",
+ "url": "http://www.mobile.de",
+ "favicon_url": "http://www.mobile.de/favicon.ico"
+ }, {
+ "title": "Google News",
+ "url": "http://news.google.com",
+ "favicon_url": "http://news.google.com/favicon.ico"
+ },
+ ])",
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ url_fetcher_factory_.SetFakeResponse(
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_6.json"),
+ R"([{
+ "section": 1, // PERSONALIZED
+ "sites": [{
+ "title": "PopularSite1",
+ "url": "http://popularsite1/",
+ "favicon_url": "http://popularsite1/favicon.ico"
+ },
+ {
+ "title": "PopularSite2",
+ "url": "http://popularsite2/",
+ "favicon_url": "http://popularsite2/favicon.ico"
+ },
+ ]
+ },
+ {
+ "section": 4, // NEWS
+ "sites": [{
+ "large_icon_url": "https://news.google.com/icon.ico",
+ "title": "Google News",
+ "url": "https://news.google.com/"
+ },
+ {
+ "favicon_url": "https://news.google.com/icon.ico",
+ "title": "Google News Germany",
+ "url": "https://news.google.de/"
+ }]
+ },
+ {
+ "section": 2, // SOCIAL
+ "sites": [{
+ "large_icon_url": "https://ssl.gstatic.com/icon.png",
+ "title": "Google+",
+ "url": "https://plus.google.com/"
+ }]
+ },
+ {
+ "section": 3, // ENTERTAINMENT
+ "sites": [
+ // Intentionally empty site list.
+ ]
+ }
+ ])",
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
}
}
@@ -330,6 +404,8 @@ class TopSitesCallbackList {
std::vector<TopSites::GetMostVisitedURLsCallback> callbacks_;
};
+} // namespace
+
// Param specifies whether Popular Sites is enabled via variations.
class MostVisitedSitesTest : public ::testing::TestWithParam<bool> {
protected:
@@ -350,6 +426,10 @@ class MostVisitedSitesTest : public ::testing::TestWithParam<bool> {
feature_list_.InitAndDisableFeature(
kNtpMostLikelyFaviconsFromServerFeature);
+ RecreateMostVisitedSites();
+ }
+
+ void RecreateMostVisitedSites() {
// We use StrictMock to make sure the object is not used unless Popular
// Sites is enabled.
auto icon_cacher = base::MakeUnique<StrictMock<MockIconCacher>>();
@@ -444,6 +524,12 @@ TEST_P(MostVisitedSitesTest, ShouldStartNoCallInConstructor) {
base::RunLoop().RunUntilIdle();
}
+TEST_P(MostVisitedSitesTest, ShouldRefreshBothBackends) {
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData());
+ most_visited_sites_->Refresh();
+}
+
TEST_P(MostVisitedSitesTest, ShouldIncludeTileForHomePage) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
@@ -454,7 +540,7 @@ TEST_P(MostVisitedSitesTest, ShouldIncludeTileForHomePage) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE)));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -467,8 +553,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageWithoutClient) {
.WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{}));
EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -491,11 +579,15 @@ TEST_P(MostVisitedSitesTest, ShouldIncludeHomeTileWithUrlBeforeQueryingName) {
{
testing::Sequence seq;
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(MatchesTile(
- kHomePageTitle, kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile(kHomePageTitle, kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
}
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -514,7 +606,7 @@ TEST_P(MostVisitedSitesTest, ShouldUpdateHomePageTileOnHomePageStateChanged) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE)));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -527,7 +619,7 @@ TEST_P(MostVisitedSitesTest, ShouldUpdateHomePageTileOnHomePageStateChanged) {
EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
.WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{}));
EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(0);
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(Not(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(Not(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE))));
most_visited_sites_->OnHomePageStateChanged();
base::RunLoop().RunUntilIdle();
@@ -543,13 +635,15 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfNoTileRequested) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(IsEmpty()));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, IsEmpty()))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/0);
base::RunLoop().RunUntilIdle();
}
-TEST_P(MostVisitedSitesTest, ShouldReturnMostPopularPageIfOneTileRequested) {
+TEST_P(MostVisitedSitesTest, ShouldReturnHomePageIfOneTileRequested) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
DisableRemoteSuggestions();
@@ -560,15 +654,17 @@ TEST_P(MostVisitedSitesTest, ShouldReturnMostPopularPageIfOneTileRequested) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 1", "http://site1/", TileSource::TOP_SITES))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
}
-TEST_P(MostVisitedSitesTest, ShouldContainHomePageInFirstFourTiles) {
+TEST_P(MostVisitedSitesTest, ShouldReplaceLastTileWithHomePageWhenFull) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
DisableRemoteSuggestions();
@@ -584,16 +680,48 @@ TEST_P(MostVisitedSitesTest, ShouldContainHomePageInFirstFourTiles) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- std::vector<NTPTile> tiles;
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_))
- .WillOnce(SaveArg<0>(&tiles));
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
- /*num_sites=*/8);
+ /*num_sites=*/4);
base::RunLoop().RunUntilIdle();
- // Assert that the home page tile is in the first four tiles.
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(4ul));
+ // Assert that the home page is appended as the final tile.
EXPECT_THAT(tiles[3], MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE));
}
+TEST_P(MostVisitedSitesTest, ShouldAppendHomePageWhenNotFull) {
+ FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
+ home_page_client->SetHomePageEnabled(true);
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>((MostVisitedURLList{
+ MakeMostVisitedURL("Site 1", "http://site1/"),
+ MakeMostVisitedURL("Site 2", "http://site2/"),
+ MakeMostVisitedURL("Site 3", "http://site3/"),
+ MakeMostVisitedURL("Site 4", "http://site4/"),
+ MakeMostVisitedURL("Site 5", "http://site5/"),
+ })));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(false));
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/8);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(6ul));
+ // Assert that the home page is appended as the final tile.
+ EXPECT_THAT(tiles[5], MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE));
+}
+
TEST_P(MostVisitedSitesTest, ShouldDeduplicateHomePageWithTopSites) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
@@ -606,11 +734,13 @@ TEST_P(MostVisitedSitesTest, ShouldDeduplicateHomePageWithTopSites) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(AllOf(
- Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)),
- Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::TOP_SITES))))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ AllOf(Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)),
+ Not(Contains(
+ MatchesTile("", kHomePageUrl, TileSource::TOP_SITES))))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -628,8 +758,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfItIsNewTabPage) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -646,8 +778,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfThereIsNone) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -666,8 +800,8 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfEmptyUrl) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(
- FirstTileIs("", kEmptyHomePageUrl, TileSource::HOMEPAGE))));
+ OnURLsAvailable(Not(FirstPersonalizedTileIs(
+ "", kEmptyHomePageUrl, TileSource::HOMEPAGE))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -689,8 +823,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfBlacklisted) {
.Times(AtLeast(1))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -710,8 +846,10 @@ TEST_P(MostVisitedSitesTest, ShouldPinHomePageAgainIfBlacklistingUndone) {
.Times(AtLeast(1))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -724,8 +862,11 @@ TEST_P(MostVisitedSitesTest, ShouldPinHomePageAgainIfBlacklistingUndone) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AtLeast(1))
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(Contains(MatchesTile(
- "", kHomePageUrl, TileSource::HOMEPAGE))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE))))));
most_visited_sites_->OnBlockedSitesChanged();
base::RunLoop().RunUntilIdle();
@@ -747,6 +888,89 @@ TEST_P(MostVisitedSitesTest, ShouldInformSuggestionSourcesWhenBlacklisting) {
/*add_url=*/false);
}
+TEST_P(MostVisitedSitesTest, ShouldContainSiteExplorationsWhenFeatureEnabled) {
+ base::test::ScopedFeatureList feature_list;
+ std::map<SectionType, NTPTilesVector> sections;
+ feature_list.InitAndEnableFeature(kSiteExplorationUiFeature);
+ pref_service_.SetString(prefs::kPopularSitesOverrideVersion, "6");
+ RecreateMostVisitedSites(); // Refills cache with version 6 popular sites.
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>(
+ MostVisitedURLList{MakeMostVisitedURL("Site 1", "http://site1/")}));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/3);
+ base::RunLoop().RunUntilIdle();
+
+ if (!IsPopularSitesEnabledViaVariations()) {
+ EXPECT_THAT(
+ sections,
+ Contains(Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES)))));
+ return;
+ }
+ const auto& expected_sections =
+ most_visited_sites_->popular_sites()->sections();
+ ASSERT_THAT(expected_sections.size(), Ge(2ul));
+ EXPECT_THAT(sections.size(), Eq(expected_sections.size()));
+ EXPECT_THAT(
+ sections,
+ AllOf(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR)))),
+ Contains(Pair(SectionType::NEWS, SizeIs(2ul))),
+ Contains(Pair(SectionType::SOCIAL, SizeIs(1ul))),
+ Contains(Pair(_, IsEmpty()))));
+}
+
+TEST_P(MostVisitedSitesTest,
+ ShouldDeduplicatePopularSitesWithMostVisitedIffHostAndTitleMatches) {
+ pref_service_.SetString(prefs::kPopularSitesOverrideCountry, "US");
+ RecreateMostVisitedSites(); // Refills cache with ESPN and Google News.
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{
+ MakeMostVisitedURL("ESPN", "http://espn.com/"),
+ MakeMostVisitedURL("Mobile", "http://m.mobile.de/"),
+ MakeMostVisitedURL("Google", "http://www.google.com/")}));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/6);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ Contains(MatchesTile("Google", "http://www.google.com/",
+ TileSource::TOP_SITES)));
+ if (IsPopularSitesEnabledViaVariations()) {
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ Contains(MatchesTile("Google News", "http://news.google.com/",
+ TileSource::POPULAR)));
+ }
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ AllOf(Contains(MatchesTile("ESPN", "http://espn.com/",
+ TileSource::TOP_SITES)),
+ Contains(MatchesTile("Mobile", "http://m.mobile.de/",
+ TileSource::TOP_SITES)),
+ Not(Contains(MatchesTile("ESPN", "http://www.espn.com/",
+ TileSource::POPULAR))),
+ Not(Contains(MatchesTile("Mobile", "http://www.mobile.de/",
+ TileSource::POPULAR)))));
+}
+
TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
// If cached, TopSites returns the tiles synchronously, running the callback
// even before the function returns.
@@ -755,7 +979,6 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
MostVisitedURLList{MakeMostVisitedURL("Site 1", "http://site1/")}));
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -764,17 +987,22 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
if (IsPopularSitesEnabledViaVariations()) {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 1", "http://site1/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES))))));
}
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -792,7 +1020,7 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(_))
.WillRepeatedly(Return(false));
}
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
mock_top_sites_->NotifyTopSitesChanged(
history::TopSitesObserver::ChangeReason::MOST_VISITED);
base::RunLoop().RunUntilIdle();
@@ -802,13 +1030,47 @@ INSTANTIATE_TEST_CASE_P(MostVisitedSitesTest,
MostVisitedSitesTest,
::testing::Bool());
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainWithNoWwwDomain) {
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.mobile.de"},
+ "mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.de"},
+ "www.mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.co.uk"},
+ "www.mobile.co.uk"));
+}
+
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByRemovingMobilePrefixes) {
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"bbc.co.uk"}, "m.bbc.co.uk"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"m.bbc.co.uk"}, "bbc.co.uk"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"},
+ "edition.cnn.com"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"edition.cnn.com"},
+ "cnn.com"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"}, "mobile.cnn.com"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"}, "cnn.com"));
+}
+
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByReplacingMobilePrefixes) {
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.bbc.co.uk"},
+ "m.bbc.co.uk"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"m.mobile.de"},
+ "www.mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.cnn.com"},
+ "edition.cnn.com"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"},
+ "www.cnn.com"));
+}
+
class MostVisitedSitesWithCacheHitTest : public MostVisitedSitesTest {
public:
// Constructor sets the common expectations for the case where suggestions
// service has cached results when the observer is registered.
MostVisitedSitesWithCacheHitTest() {
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -818,27 +1080,33 @@ class MostVisitedSitesWithCacheHitTest : public MostVisitedSitesTest {
MakeSuggestion("Site 2", "http://site2/"),
MakeSuggestion("Site 3", "http://site3/"),
})));
+
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 2", "http://site2/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 2", "http://site2/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR))))));
} else {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 2", "http://site2/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 2", "http://site2/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -858,7 +1126,8 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldFavorSuggestionsServiceCache) {
TEST_P(MostVisitedSitesWithCacheHitTest,
ShouldPropagateUpdateBySuggestionsService) {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 4", "http://site4/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 5", "http://site5/",
@@ -866,7 +1135,7 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
MatchesTile("Site 6", "http://site6/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 7", "http://site7/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -876,7 +1145,9 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
}
TEST_P(MostVisitedSitesWithCacheHitTest, ShouldTruncateList) {
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(SizeIs(4)));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, SizeIs(4)))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -889,19 +1160,23 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldTruncateList) {
TEST_P(MostVisitedSitesWithCacheHitTest,
ShouldCompleteWithPopularSitesIffEnabled) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -917,11 +1192,14 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES),
- MatchesTile("Site 7", "http://site7/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES),
+ MatchesTile("Site 7", "http://site7/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 4", "http://site4/"),
MakeMostVisitedURL("Site 5", "http://site5/"),
@@ -934,7 +1212,7 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldFetchFaviconsIfEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kNtpMostLikelyFaviconsFromServerFeature);
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
EXPECT_CALL(*icon_cacher_, StartFetchMostLikely(GURL("http://site4/"), _));
suggestions_service_callbacks_.Notify(
@@ -952,7 +1230,6 @@ class MostVisitedSitesWithEmptyCacheTest : public MostVisitedSitesTest {
// service doesn't have cached results when the observer is registered.
MostVisitedSitesWithEmptyCacheTest() {
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -960,6 +1237,7 @@ class MostVisitedSitesWithEmptyCacheTest : public MostVisitedSitesTest {
.WillOnce(Return(SuggestionsProfile())); // Empty cache.
EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
.WillOnce(Invoke(&top_sites_callbacks_, &TopSitesCallbackList::Add));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -980,19 +1258,23 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldCompleteWithPopularSitesIffEnabled) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -1003,13 +1285,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldIgnoreTopSitesIfSuggestionsServiceFaster) {
// Reply from suggestions service triggers and update to our observer.
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 1", "http://site1/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 1", "http://site1/"),
MakeSuggestion("Site 2", "http://site2/"),
@@ -1036,10 +1319,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1052,10 +1338,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1065,13 +1354,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from suggestions service overrides top sites.
InSequence seq;
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 4", "http://site4/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 5", "http://site5/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 6", "http://site6/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -1084,10 +1374,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1103,10 +1396,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1126,10 +1422,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
MakeMostVisitedURL("Site 6", "http://site6/")}));
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/",
+ TileSource::TOP_SITES))))));
mock_top_sites_->NotifyTopSitesChanged(
history::TopSitesObserver::ChangeReason::MOST_VISITED);
base::RunLoop().RunUntilIdle();
@@ -1138,16 +1437,19 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldSendEmptyListIfBothTopSitesAndSuggestionsServiceEmpty) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
// The Android NTP doesn't finish initialization until it gets tiles, so a
// 0-tile notification is always needed.
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(IsEmpty()));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(ElementsAre(Pair(
+ SectionType::PERSONALIZED, IsEmpty()))));
}
suggestions_service_callbacks_.Notify(SuggestionsProfile());
top_sites_callbacks_.ClearAndNotify(MostVisitedURLList{});
@@ -1159,10 +1461,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldNotifyOnceIfTopSitesUnchanged) {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
suggestions_service_callbacks_.Notify(SuggestionsProfile());
@@ -1189,13 +1494,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldNotifyOnceIfSuggestionsUnchanged) {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 1", "http://site1/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
for (int i = 0; i < 5; ++i) {
suggestions_service_callbacks_.Notify(
@@ -1282,5 +1588,4 @@ TEST(MostVisitedSitesMergeTest, ShouldMergeTilesFavoringPersonalOverPopular) {
TileSource::POPULAR)));
}
-} // namespace
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/popular_sites.h b/chromium/components/ntp_tiles/popular_sites.h
index f1e207fcac1..7e6b21db219 100644
--- a/chromium/components/ntp_tiles/popular_sites.h
+++ b/chromium/components/ntp_tiles/popular_sites.h
@@ -5,12 +5,14 @@
#ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_H_
#define COMPONENTS_NTP_TILES_POPULAR_SITES_H_
+#include <map>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/ntp_tiles/section_type.h"
#include "url/gurl.h"
namespace base {
@@ -37,6 +39,7 @@ class PopularSites {
GURL favicon_url;
GURL large_icon_url;
GURL thumbnail_url;
+ bool baked_in;
int default_icon_resource; // < 0 if there is none. Used for popular sites.
};
@@ -60,8 +63,8 @@ class PopularSites {
virtual bool MaybeStartFetch(bool force_download,
const FinishedCallback& callback) = 0;
- // Returns the list of available sites.
- virtual const SitesVector& sites() const = 0;
+ // Returns the cached list of available sections and their sites.
+ virtual const std::map<SectionType, SitesVector>& sections() const = 0;
// Various internals exposed publicly for diagnostic pages only.
virtual GURL GetLastURLFetched() const = 0;
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.cc b/chromium/components/ntp_tiles/popular_sites_impl.cc
index 38fc464509b..c238ab8867a 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl.cc
@@ -5,13 +5,16 @@
#include "components/ntp_tiles/popular_sites_impl.h"
#include <stddef.h>
+#include <map>
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -53,12 +56,9 @@ const char kPopularSitesURLFormat[] =
const char kPopularSitesDefaultDirectory[] = "chrome/ntp/";
const char kPopularSitesDefaultCountryCode[] = "DEFAULT";
const char kPopularSitesDefaultVersion[] = "5";
+const int kSitesExplorationStartVersion = 6;
const int kPopularSitesRedownloadIntervalHours = 24;
-const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
-const char kPopularSitesURLPref[] = "popular_sites_url";
-const char kPopularSitesJsonPref[] = "suggested_sites_json";
-
GURL GetPopularSitesURL(const std::string& directory,
const std::string& country,
const std::string& version) {
@@ -128,10 +128,65 @@ PopularSites::SitesVector ParseSiteList(const base::ListValue& list) {
GURL(large_icon_url), GURL(thumbnail_url));
item->GetInteger("default_icon_resource",
&sites.back().default_icon_resource);
+ item->GetBoolean("baked_in", &sites.back().baked_in);
}
return sites;
}
+std::map<SectionType, PopularSites::SitesVector> ParseVersion5(
+ const base::ListValue& list) {
+ return {{SectionType::PERSONALIZED, ParseSiteList(list)}};
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove(
+ const base::ListValue& list) {
+ // Valid lists would have contained at least the PERSONALIZED section.
+ std::map<SectionType, PopularSites::SitesVector> sections = {
+ std::make_pair(SectionType::PERSONALIZED, PopularSites::SitesVector{})};
+ for (size_t i = 0; i < list.GetSize(); i++) {
+ const base::DictionaryValue* item;
+ if (!list.GetDictionary(i, &item)) {
+ LOG(WARNING) << "Parsed SitesExploration list contained an invalid "
+ << "section at position " << i << ".";
+ continue;
+ }
+ int section;
+ if (!item->GetInteger("section", &section) || section < 0 ||
+ section > static_cast<int>(SectionType::LAST)) {
+ LOG(WARNING) << "Parsed SitesExploration list contained a section with "
+ << "invalid ID (" << section << ")";
+ continue;
+ }
+ SectionType section_type = static_cast<SectionType>(section);
+ if (section_type == SectionType::UNKNOWN) {
+ LOG(WARNING) << "Dropped an unknown section in SitesExploration list.";
+ continue;
+ }
+ const base::ListValue* sites_list;
+ if (!item->GetList("sites", &sites_list)) {
+ continue;
+ }
+ sections[section_type] = ParseSiteList(*sites_list);
+ }
+ if (!base::FeatureList::IsEnabled(kSiteExplorationUiFeature)) {
+ // New versions of popular sites that should act like old versions will
+ // mimic having only the personalized list.
+ return {std::make_pair(SectionType::PERSONALIZED,
+ std::move(sections[SectionType::PERSONALIZED]))};
+ }
+ return sections;
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseSites(
+ const base::ListValue& list,
+ int version) {
+ if (version >= kSitesExplorationStartVersion) {
+ return ParseVersion6OrAbove(list);
+ } else {
+ return ParseVersion5(list);
+ }
+}
+
#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
void SetDefaultResourceForSite(int index,
int resource_id,
@@ -157,6 +212,10 @@ std::unique_ptr<base::ListValue> DefaultPopularSites() {
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_DEFAULT_POPULAR_SITES_JSON)));
DCHECK(sites);
+ for (base::Value& site : *sites) {
+ base::DictionaryValue& dict = static_cast<base::DictionaryValue&>(site);
+ dict.SetBoolean("baked_in", true);
+ }
#if defined(GOOGLE_CHROME_BUILD)
int index = 0;
for (int icon_resource :
@@ -183,6 +242,7 @@ PopularSites::Site::Site(const base::string16& title,
favicon_url(favicon_url),
large_icon_url(large_icon_url),
thumbnail_url(thumbnail_url),
+ baked_in(false),
default_icon_resource(-1) {}
PopularSites::Site::Site(const Site& other) = default;
@@ -201,7 +261,9 @@ PopularSitesImpl::PopularSitesImpl(
download_context_(download_context),
parse_json_(std::move(parse_json)),
is_fallback_(false),
- sites_(ParseSiteList(*prefs->GetList(kPopularSitesJsonPref))),
+ sections_(
+ ParseSites(*prefs->GetList(prefs::kPopularSitesJsonPref),
+ prefs_->GetInteger(prefs::kPopularSitesVersionPref))),
weak_ptr_factory_(this) {}
PopularSitesImpl::~PopularSitesImpl() {}
@@ -212,7 +274,7 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
callback_ = callback;
const base::Time last_download_time = base::Time::FromInternalValue(
- prefs_->GetInt64(kPopularSitesLastDownloadPref));
+ prefs_->GetInt64(prefs::kPopularSitesLastDownloadPref));
const base::TimeDelta time_since_last_download =
base::Time::Now() - last_download_time;
const base::TimeDelta redownload_interval =
@@ -221,7 +283,7 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
pending_url_ = GetURLToFetch();
const bool url_changed =
- pending_url_.spec() != prefs_->GetString(kPopularSitesURLPref);
+ pending_url_.spec() != prefs_->GetString(prefs::kPopularSitesURLPref);
// Download forced, or we need to download a new file.
if (force_download || download_time_is_future ||
@@ -232,18 +294,20 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
return false;
}
-const PopularSites::SitesVector& PopularSitesImpl::sites() const {
- return sites_;
+const std::map<SectionType, PopularSitesImpl::SitesVector>&
+PopularSitesImpl::sections() const {
+ return sections_;
}
GURL PopularSitesImpl::GetLastURLFetched() const {
- return GURL(prefs_->GetString(kPopularSitesURLPref));
+ return GURL(prefs_->GetString(prefs::kPopularSitesURLPref));
}
GURL PopularSitesImpl::GetURLToFetch() {
const std::string directory = GetDirectoryToFetch();
const std::string country = GetCountryToFetch();
const std::string version = GetVersionToFetch();
+ base::StringToInt(version, &version_in_pending_url_);
const GURL override_url =
GURL(prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
@@ -311,7 +375,7 @@ std::string PopularSitesImpl::GetVersionToFetch() {
}
const base::ListValue* PopularSitesImpl::GetCachedJson() {
- return prefs_->GetList(kPopularSitesJsonPref);
+ return prefs_->GetList(prefs::kPopularSitesJsonPref);
}
// static
@@ -326,9 +390,13 @@ void PopularSitesImpl::RegisterProfilePrefs(
user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideVersion,
std::string());
- user_prefs->RegisterInt64Pref(kPopularSitesLastDownloadPref, 0);
- user_prefs->RegisterStringPref(kPopularSitesURLPref, std::string());
- user_prefs->RegisterListPref(kPopularSitesJsonPref, DefaultPopularSites());
+ user_prefs->RegisterInt64Pref(prefs::kPopularSitesLastDownloadPref, 0);
+ user_prefs->RegisterStringPref(prefs::kPopularSitesURLPref, std::string());
+ user_prefs->RegisterListPref(prefs::kPopularSitesJsonPref,
+ DefaultPopularSites());
+ int version;
+ base::StringToInt(kPopularSitesDefaultVersion, &version);
+ user_prefs->RegisterIntegerPref(prefs::kPopularSitesVersionPref, version);
}
void PopularSitesImpl::FetchPopularSites() {
@@ -347,7 +415,7 @@ void PopularSitesImpl::FetchPopularSites() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification:
"Not implemented, considered not useful."
@@ -390,13 +458,13 @@ void PopularSitesImpl::OnJsonParsed(std::unique_ptr<base::Value> json) {
OnDownloadFailed();
return;
}
-
- prefs_->Set(kPopularSitesJsonPref, *list);
- prefs_->SetInt64(kPopularSitesLastDownloadPref,
+ prefs_->Set(prefs::kPopularSitesJsonPref, *list);
+ prefs_->SetInt64(prefs::kPopularSitesLastDownloadPref,
base::Time::Now().ToInternalValue());
- prefs_->SetString(kPopularSitesURLPref, pending_url_.spec());
+ prefs_->SetInteger(prefs::kPopularSitesVersionPref, version_in_pending_url_);
+ prefs_->SetString(prefs::kPopularSitesURLPref, pending_url_.spec());
- sites_ = ParseSiteList(*list);
+ sections_ = ParseSites(*list, version_in_pending_url_);
callback_.Run(true);
}
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.h b/chromium/components/ntp_tiles/popular_sites_impl.h
index 116297342df..c58dbf3538d 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.h
+++ b/chromium/components/ntp_tiles/popular_sites_impl.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
#define COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
+#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -59,7 +60,7 @@ class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
// PopularSites implementation.
bool MaybeStartFetch(bool force_download,
const FinishedCallback& callback) override;
- const SitesVector& sites() const override;
+ const std::map<SectionType, SitesVector>& sections() const override;
GURL GetLastURLFetched() const override;
GURL GetURLToFetch() override;
std::string GetDirectoryToFetch() override;
@@ -95,8 +96,9 @@ class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
std::unique_ptr<net::URLFetcher> fetcher_;
bool is_fallback_;
- SitesVector sites_;
+ std::map<SectionType, SitesVector> sections_;
GURL pending_url_;
+ int version_in_pending_url_;
base::WeakPtrFactory<PopularSitesImpl> weak_ptr_factory_;
diff --git a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
index d29217f2045..17fc409c3f3 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -16,6 +16,7 @@
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
@@ -24,6 +25,7 @@
#include "components/ntp_tiles/json_unsafe_parser.h"
#include "components/ntp_tiles/pref_names.h"
#include "components/ntp_tiles/switches.h"
+#include "components/ntp_tiles/tile_source.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "net/http/http_status_code.h"
@@ -33,9 +35,15 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+using testing::Contains;
+using testing::ElementsAre;
using testing::Eq;
using testing::Gt;
using testing::IsEmpty;
+using testing::Not;
+using testing::Pair;
+using testing::SizeIs;
namespace ntp_tiles {
namespace {
@@ -44,9 +52,13 @@ const char kTitle[] = "title";
const char kUrl[] = "url";
const char kLargeIconUrl[] = "large_icon_url";
const char kFaviconUrl[] = "favicon_url";
+const char kSection[] = "section";
+const char kSites[] = "sites";
using TestPopularSite = std::map<std::string, std::string>;
using TestPopularSiteVector = std::vector<TestPopularSite>;
+using TestPopularSection = std::pair<SectionType, TestPopularSiteVector>;
+using TestPopularSectionVector = std::vector<TestPopularSection>;
::testing::Matcher<const base::string16&> Str16Eq(const std::string& s) {
return ::testing::Eq(base::UTF8ToUTF16(s));
@@ -95,18 +107,38 @@ class PopularSitesTest : public ::testing::Test {
prefs_->SetString(prefs::kPopularSitesOverrideVersion, version);
}
- void RespondWithJSON(const std::string& url,
- const TestPopularSiteVector& sites) {
- base::ListValue sites_value;
+ std::unique_ptr<base::ListValue> CreateListFromTestSites(
+ const TestPopularSiteVector& sites) {
+ auto sites_value = base::MakeUnique<base::ListValue>();
for (const TestPopularSite& site : sites) {
auto site_value = base::MakeUnique<base::DictionaryValue>();
for (const std::pair<std::string, std::string>& kv : site) {
site_value->SetString(kv.first, kv.second);
}
- sites_value.Append(std::move(site_value));
+ sites_value->Append(std::move(site_value));
}
+ return sites_value;
+ }
+
+ void RespondWithV5JSON(const std::string& url,
+ const TestPopularSiteVector& sites) {
std::string sites_string;
- base::JSONWriter::Write(sites_value, &sites_string);
+ base::JSONWriter::Write(*CreateListFromTestSites(sites), &sites_string);
+ url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+
+ void RespondWithV6JSON(const std::string& url,
+ const TestPopularSectionVector& sections) {
+ base::ListValue sections_value;
+ for (const TestPopularSection& section : sections) {
+ auto section_value = base::MakeUnique<base::DictionaryValue>();
+ section_value->SetInteger(kSection, static_cast<int>(section.first));
+ section_value->SetList(kSites, CreateListFromTestSites(section.second));
+ sections_value.Append(std::move(section_value));
+ }
+ std::string sites_string;
+ base::JSONWriter::Write(sections_value, &sites_string);
url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
}
@@ -130,6 +162,18 @@ class PopularSitesTest : public ::testing::Test {
// called at all, and if yes which was the returned bool value.
base::Optional<bool> FetchPopularSites(bool force_download,
PopularSites::SitesVector* sites) {
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ base::Optional<bool> save_success =
+ FetchAllSections(force_download, &sections);
+ *sites = sections.at(SectionType::PERSONALIZED);
+ return save_success;
+ }
+
+ // Returns an optional bool representing whether the completion callback was
+ // called at all, and if yes which was the returned bool value.
+ base::Optional<bool> FetchAllSections(
+ bool force_download,
+ std::map<SectionType, PopularSites::SitesVector>* sections) {
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get()));
@@ -148,7 +192,7 @@ class PopularSitesTest : public ::testing::Test {
&save_success, &loop))) {
loop.Run();
}
- *sites = popular_sites->sites();
+ *sections = popular_sites->sections();
return save_success;
}
@@ -176,8 +220,10 @@ TEST_F(PopularSitesTest, ContainsDefaultTilesRightAfterConstruction) {
base::ThreadTaskRunnerHandle::Get()));
auto popular_sites = CreatePopularSites(url_request_context.get());
- EXPECT_THAT(popular_sites->sites().size(),
- Eq(GetNumberOfDefaultPopularSitesForPlatform()));
+ EXPECT_THAT(
+ popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED,
+ SizeIs(GetNumberOfDefaultPopularSitesForPlatform()))));
}
TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
@@ -190,17 +236,18 @@ TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
base::ThreadTaskRunnerHandle::Get()));
auto popular_sites = CreatePopularSites(url_request_context.get());
- EXPECT_THAT(popular_sites->sites().size(), Eq(0ul));
+ EXPECT_THAT(popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED, IsEmpty())));
}
TEST_F(PopularSitesTest, ShouldSucceedFetching) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
PopularSites::SitesVector sites;
- EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Eq(base::Optional<bool>(true)));
ASSERT_THAT(sites.size(), Eq(1u));
@@ -212,10 +259,10 @@ TEST_F(PopularSitesTest, ShouldSucceedFetching) {
}
TEST_F(PopularSitesTest, Fallback) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kYouTube, kChromium});
@@ -237,9 +284,9 @@ TEST_F(PopularSitesTest, Fallback) {
}
TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
RespondWith404(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
@@ -249,6 +296,7 @@ TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
EXPECT_THAT(sites.size(), Eq(GetNumberOfDefaultPopularSitesForPlatform()));
}
+#if defined(OS_ANDROID) || defined(OS_IOS)
TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
@@ -256,18 +304,22 @@ TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
std::unique_ptr<PopularSites> popular_sites =
CreatePopularSites(url_request_context.get());
-#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
- ASSERT_FALSE(popular_sites->sites().empty());
- for (const auto& site : popular_sites->sites()) {
+ const PopularSites::SitesVector& sites =
+ popular_sites->sections().at(SectionType::PERSONALIZED);
+ ASSERT_FALSE(sites.empty());
+ for (const auto& site : sites) {
+ EXPECT_TRUE(site.baked_in);
+#if defined(GOOGLE_CHROME_BUILD)
EXPECT_THAT(site.default_icon_resource, Gt(0));
- }
#endif
+ }
}
+#endif
TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
@@ -290,20 +342,21 @@ TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
// Assert that callback was scheduled so we can wait for its completion.
ASSERT_TRUE(callback_was_scheduled);
// There should be 8 default sites as nothing was fetched yet.
- EXPECT_THAT(popular_sites->sites().size(),
+ EXPECT_THAT(popular_sites->sections().at(SectionType::PERSONALIZED).size(),
Eq(GetNumberOfDefaultPopularSitesForPlatform()));
loop.Run(); // Wait for the fetch to finish and the callback to return.
EXPECT_TRUE(save_success.value());
// The 1 fetched site should replace the default sites.
- EXPECT_THAT(popular_sites->sites().size(), Eq(1ul));
+ EXPECT_THAT(popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1ul))));
}
TEST_F(PopularSitesTest, UsesCachedJson) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
// First request succeeds and gets cached.
@@ -313,17 +366,17 @@ TEST_F(PopularSitesTest, UsesCachedJson) {
// File disappears from server, but we don't need it because it's cached.
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::nullopt));
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
}
TEST_F(PopularSitesTest, CachesEmptyFile) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWithData(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json", "[]");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json", "[]");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kWikipedia});
@@ -334,8 +387,8 @@ TEST_F(PopularSitesTest, CachesEmptyFile) {
EXPECT_THAT(sites, IsEmpty());
// File appears on server, but we continue to use our cached empty file.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::nullopt));
@@ -343,9 +396,9 @@ TEST_F(PopularSitesTest, CachesEmptyFile) {
}
TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
// First request succeeds and gets cached.
@@ -355,41 +408,65 @@ TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// File disappears from server. Download is forced, so we get the new file.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Eq(base::Optional<bool>(true)));
EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
}
+TEST_F(PopularSitesTest, DoesntUseCacheWithDeprecatedVersion) {
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
+ {kWikipedia});
+
+ // First request succeeds and gets cached.
+ PopularSites::SitesVector sites;
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ Eq(base::Optional<bool>(true)));
+ EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
+ EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(5));
+
+ // The client is updated to use V6. Drop old data and refetch.
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}}});
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ Eq(base::Optional<bool>(true)));
+ EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
+ EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(6));
+}
+
TEST_F(PopularSitesTest, RefetchesAfterCountryMoved) {
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_5.json",
{kChromium});
PopularSites::SitesVector sites;
// First request (in ZZ) saves Wikipedia.
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// Second request (now in ZX) saves Chromium.
- SetCountryAndVersion("ZX", "9");
+ SetCountryAndVersion("ZX", "5");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
base::Optional<bool>(true));
EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
}
TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWithData(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
"ceci n'est pas un json");
RespondWith404(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
@@ -400,8 +477,8 @@ TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
Eq(base::Optional<bool>(false)));
// Second request refetches ZZ_9, which now has data.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
@@ -410,10 +487,10 @@ TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
}
TEST_F(PopularSitesTest, RefetchesAfterFallback) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kWikipedia});
@@ -425,8 +502,8 @@ TEST_F(PopularSitesTest, RefetchesAfterFallback) {
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// Second request refetches ZZ_9, which now has data.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
@@ -435,10 +512,10 @@ TEST_F(PopularSitesTest, RefetchesAfterFallback) {
}
TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
prefs_->SetString(prefs::kPopularSitesOverrideDirectory, "foo/bar/");
- RespondWithJSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_9.json",
- {kWikipedia});
+ RespondWithV5JSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_5.json",
+ {kWikipedia});
PopularSites::SitesVector sites;
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
@@ -447,5 +524,64 @@ TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
EXPECT_THAT(sites.size(), Eq(1u));
}
+TEST_F(PopularSitesTest, DoesNotFetchExplorationSitesWithoutFeature) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(kSiteExplorationUiFeature);
+
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}},
+ {SectionType::NEWS, {kYouTube}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ // The fetched news section should not be propagated without enabled feature.
+ EXPECT_THAT(sections, Not(Contains(Pair(SectionType::NEWS, _))));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesWithFeature) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndEnableFeature(kSiteExplorationUiFeature);
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}},
+ {SectionType::ENTERTAINMENT, {kWikipedia, kYouTube}},
+ {SectionType::NEWS, {kYouTube}},
+ {SectionType::TOOLS, TestPopularSiteVector{}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1)),
+ Pair(SectionType::ENTERTAINMENT, SizeIs(2)),
+ Pair(SectionType::NEWS, SizeIs(1)),
+ Pair(SectionType::TOOLS, IsEmpty())));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesIgnoreUnknownSections) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndEnableFeature(kSiteExplorationUiFeature);
+
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::UNKNOWN, {kChromium}},
+ {SectionType::NEWS, {kYouTube}},
+ {SectionType::UNKNOWN, {kWikipedia, kYouTube}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ // Expect that there are four sections, none of which is empty.
+ EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(0)),
+ Pair(SectionType::NEWS, SizeIs(1))));
+}
+
} // namespace
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/pref_names.cc b/chromium/components/ntp_tiles/pref_names.cc
index c8839987362..409de49b546 100644
--- a/chromium/components/ntp_tiles/pref_names.cc
+++ b/chromium/components/ntp_tiles/pref_names.cc
@@ -25,5 +25,11 @@ const char kPopularSitesOverrideCountry[] = "popular_sites.override_country";
// If set, this will override the default file version for popular sites.
const char kPopularSitesOverrideVersion[] = "popular_sites.override_version";
+// Prefs used to cache suggested sites and store caching meta data.
+const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
+const char kPopularSitesURLPref[] = "popular_sites_url";
+const char kPopularSitesJsonPref[] = "suggested_sites_json";
+const char kPopularSitesVersionPref[] = "suggested_sites_version";
+
} // namespace prefs
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/pref_names.h b/chromium/components/ntp_tiles/pref_names.h
index 9c4de063cf9..687f5577b29 100644
--- a/chromium/components/ntp_tiles/pref_names.h
+++ b/chromium/components/ntp_tiles/pref_names.h
@@ -15,6 +15,11 @@ extern const char kPopularSitesOverrideDirectory[];
extern const char kPopularSitesOverrideCountry[];
extern const char kPopularSitesOverrideVersion[];
+extern const char kPopularSitesLastDownloadPref[];
+extern const char kPopularSitesURLPref[];
+extern const char kPopularSitesJsonPref[];
+extern const char kPopularSitesVersionPref[];
+
} // namespace prefs
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/section_type.h b/chromium/components/ntp_tiles/section_type.h
new file mode 100644
index 00000000000..f1f9f5ca801
--- /dev/null
+++ b/chromium/components/ntp_tiles/section_type.h
@@ -0,0 +1,30 @@
+// 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_NTP_TILES_SECTION_TYPE_H_
+#define COMPONENTS_NTP_TILES_SECTION_TYPE_H_
+
+namespace ntp_tiles {
+
+// The type of a section means all its tiles originate here. Ranked descendingly
+// from most important section to least important.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: TileSectionType
+enum class SectionType {
+ UNKNOWN,
+ PERSONALIZED,
+ SOCIAL,
+ ENTERTAINMENT,
+ NEWS,
+ ECOMMERCE,
+ TOOLS,
+ TRAVEL,
+
+ LAST = TRAVEL
+};
+
+} // namespace ntp_tiles
+
+#endif // COMPONENTS_NTP_TILES_SECTION_TYPE_H_
diff --git a/chromium/components/ntp_tiles/tile_source.h b/chromium/components/ntp_tiles/tile_source.h
index 53ca5eab207..551e1f92557 100644
--- a/chromium/components/ntp_tiles/tile_source.h
+++ b/chromium/components/ntp_tiles/tile_source.h
@@ -17,6 +17,8 @@ enum class TileSource {
SUGGESTIONS_SERVICE,
// Tile is regionally popular.
POPULAR,
+ // Tile is a popular site baked into the binary.
+ POPULAR_BAKED_IN,
// Tile is on a custodian-managed whitelist.
WHITELIST,
// Tile containing the user-set home page is replacing the home page button.
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index 098e7156ae7..64fbb6d2264 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -5,6 +5,8 @@
#include "components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h"
#include <array>
+#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/callback.h"
@@ -276,10 +278,12 @@ void NTPTilesInternalsMessageHandler::SendTiles(
result);
}
-void NTPTilesInternalsMessageHandler::OnMostVisitedURLsAvailable(
- const NTPTilesVector& tiles) {
+void NTPTilesInternalsMessageHandler::OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) {
cancelable_task_tracker_.TryCancelAll();
+ // TODO(fhorschig): Handle non-personalized tiles - https://crbug.com/753852.
+ const NTPTilesVector& tiles = sections.at(SectionType::PERSONALIZED);
if (tiles.empty()) {
SendTiles(tiles, FaviconResultMap());
return;
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
index 4306f832692..7f42af2b571 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
@@ -60,7 +60,8 @@ class NTPTilesInternalsMessageHandler : public MostVisitedSites::Observer {
const FaviconResultMap& result_map);
// MostVisitedSites::Observer.
- void OnMostVisitedURLsAvailable(const NTPTilesVector& tiles) override;
+ void OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) override;
void OnIconMadeAvailable(const GURL& site_url) override;
void OnFaviconLookupDone(const NTPTilesVector& 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 c407b726676..8e922ea74db 100644
--- a/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
+++ b/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -46,7 +46,7 @@ found in the LICENSE file.
<tbody jsselect="suggestionsService">
<tr jsdisplay="$this">
<td class="detail">
- <input id="suggestions-fetch" type="submit" value="Fetch"></input>
+ <input id="suggestions-fetch" type="submit" value="Fetch">
</td>
<td class="value" jscontent="status"></td>
</tr>
@@ -77,7 +77,7 @@ found in the LICENSE file.
</tr>
<tr jsdisplay="$this">
<td class="detail">
- <input id="popular-view-json" type="submit", value="View JSON"></input>
+ <input id="popular-view-json" type="submit", value="View JSON">
</td>
<td class="value"><pre id="popular-json-value" jscontent="json"></pre></td>
</tr>
@@ -96,7 +96,7 @@ found in the LICENSE file.
<td class="value" jsdisplay="!$this">no</td>
</tr>
<tr jsskip="true">
- <th colspan="2"><input id="submit-update" type="submit" value="Update"></input></th>
+ <th colspan="2"><input id="submit-update" type="submit" value="Update"></th>
</tr>
</tbody>
</table>
@@ -115,9 +115,10 @@ found in the LICENSE file.
<td class="value" jsdisplay="source == 0">TOP_SITES</td>
<td class="value" jsdisplay="source == 1">SUGGESTIONS_SERVICE</td>
<td class="value" jsdisplay="source == 2">POPULAR</td>
- <td class="value" jsdisplay="source == 3">WHITELIST</td>
- <td class="value" jsdisplay="source == 4">HOMEPAGE</td>
- <td class="value" jsdisplay="source &gt; 4">???</td>
+ <td class="value" jsdisplay="source == 3">POPULAR_BAKED_IN</td>
+ <td class="value" jsdisplay="source == 4">WHITELIST</td>
+ <td class="value" jsdisplay="source == 5">HOMEPAGE</td>
+ <td class="value" jsdisplay="source &gt; 5">???</td>
</tr>
<tr>
<td class="detail">URL</td>
diff --git a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
index feb37418940..41140354310 100644
--- a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
+++ b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
@@ -38,7 +38,7 @@ void GetVisualsForItemHelperCallback(ScopedJavaGlobalRef<jobject> j_callback,
const OfflineItemVisuals* visuals) {
JNIEnv* env = AttachCurrentThread();
Java_OfflineContentAggregatorBridge_onVisualsAvailable(
- env, j_callback.obj(), ConvertUTF8ToJavaString(env, id.name_space),
+ env, j_callback, ConvertUTF8ToJavaString(env, id.name_space),
ConvertUTF8ToJavaString(env, id.id),
OfflineItemVisualsBridge::CreateOfflineItemVisuals(env, visuals));
}
@@ -77,7 +77,7 @@ OfflineContentAggregatorBridge::~OfflineContentAggregatorBridge() {
provider_->RemoveObserver(this);
Java_OfflineContentAggregatorBridge_onNativeDestroyed(AttachCurrentThread(),
- java_ref_.obj());
+ java_ref_);
}
jboolean OfflineContentAggregatorBridge::AreItemsAvailable(
@@ -122,8 +122,10 @@ void OfflineContentAggregatorBridge::ResumeDownload(
JNIEnv* env,
const JavaParamRef<jobject>& jobj,
const JavaParamRef<jstring>& j_namespace,
- const JavaParamRef<jstring>& j_id) {
- provider_->ResumeDownload(CreateContentId(env, j_namespace, j_id));
+ const JavaParamRef<jstring>& j_id,
+ jboolean j_has_user_gesture) {
+ provider_->ResumeDownload(CreateContentId(env, j_namespace, j_id),
+ j_has_user_gesture);
}
ScopedJavaLocalRef<jobject> OfflineContentAggregatorBridge::GetItemById(
@@ -162,7 +164,7 @@ void OfflineContentAggregatorBridge::OnItemsAvailable(
return;
JNIEnv* env = AttachCurrentThread();
- Java_OfflineContentAggregatorBridge_onItemsAvailable(env, java_ref_.obj());
+ Java_OfflineContentAggregatorBridge_onItemsAvailable(env, java_ref_);
}
void OfflineContentAggregatorBridge::OnItemsAdded(
@@ -172,8 +174,7 @@ void OfflineContentAggregatorBridge::OnItemsAdded(
JNIEnv* env = AttachCurrentThread();
Java_OfflineContentAggregatorBridge_onItemsAdded(
- env, java_ref_.obj(),
- OfflineItemBridge::CreateOfflineItemList(env, items));
+ env, java_ref_, OfflineItemBridge::CreateOfflineItemList(env, items));
}
void OfflineContentAggregatorBridge::OnItemRemoved(const ContentId& id) {
@@ -182,7 +183,7 @@ void OfflineContentAggregatorBridge::OnItemRemoved(const ContentId& id) {
JNIEnv* env = AttachCurrentThread();
Java_OfflineContentAggregatorBridge_onItemRemoved(
- env, java_ref_.obj(), ConvertUTF8ToJavaString(env, id.name_space),
+ env, java_ref_, ConvertUTF8ToJavaString(env, id.name_space),
ConvertUTF8ToJavaString(env, id.id));
}
@@ -192,7 +193,7 @@ void OfflineContentAggregatorBridge::OnItemUpdated(const OfflineItem& item) {
JNIEnv* env = AttachCurrentThread();
Java_OfflineContentAggregatorBridge_onItemUpdated(
- env, java_ref_.obj(), OfflineItemBridge::CreateOfflineItem(env, &item));
+ env, java_ref_, OfflineItemBridge::CreateOfflineItem(env, &item));
}
} // namespace android
diff --git a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
index 0c4dfc1f7a0..5444009dfc5 100644
--- a/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
+++ b/chromium/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
@@ -58,7 +58,8 @@ class OfflineContentAggregatorBridge : public OfflineContentProvider::Observer,
void ResumeDownload(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& j_namespace,
- const base::android::JavaParamRef<jstring>& j_id);
+ const base::android::JavaParamRef<jstring>& j_id,
+ jboolean j_has_user_gesture);
base::android::ScopedJavaLocalRef<jobject> GetItemById(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj,
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
index 64ba2e23004..d3bc2923ebb 100644
--- a/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -107,14 +107,16 @@ void OfflineContentAggregator::PauseDownload(const ContentId& id) {
base::Unretained(it->second), id));
}
-void OfflineContentAggregator::ResumeDownload(const ContentId& id) {
+void OfflineContentAggregator::ResumeDownload(const ContentId& id,
+ bool has_user_gesture) {
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
- RunIfReady(it->second, base::Bind(&OfflineContentProvider::ResumeDownload,
- base::Unretained(it->second), id));
+ RunIfReady(it->second,
+ base::Bind(&OfflineContentProvider::ResumeDownload,
+ base::Unretained(it->second), id, has_user_gesture));
}
const OfflineItem* OfflineContentAggregator::GetItemById(const ContentId& id) {
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator.h b/chromium/components/offline_items_collection/core/offline_content_aggregator.h
index 68df56858a9..b66ae041ef4 100644
--- a/chromium/components/offline_items_collection/core/offline_content_aggregator.h
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator.h
@@ -81,7 +81,7 @@ class OfflineContentAggregator : public OfflineContentProvider,
void RemoveItem(const ContentId& id) override;
void CancelDownload(const ContentId& id) override;
void PauseDownload(const ContentId& id) override;
- void ResumeDownload(const ContentId& id) override;
+ void ResumeDownload(const ContentId& id, bool has_user_gesture) override;
const OfflineItem* GetItemById(const ContentId& id) override;
OfflineItemList GetAllItems() override;
void GetVisualsForItem(const ContentId& id,
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 45d77fd42e2..e259bb4ed7f 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
@@ -295,8 +295,8 @@ TEST_F(OfflineContentAggregatorTest, ActionPropagatesToRightProvider) {
EXPECT_CALL(provider2, RemoveItem(id2)).Times(1);
EXPECT_CALL(provider1, CancelDownload(id1)).Times(1);
EXPECT_CALL(provider2, CancelDownload(id2)).Times(1);
- EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1);
- EXPECT_CALL(provider2, ResumeDownload(id2)).Times(1);
+ EXPECT_CALL(provider1, ResumeDownload(id1, false)).Times(1);
+ EXPECT_CALL(provider2, ResumeDownload(id2, true)).Times(1);
EXPECT_CALL(provider1, PauseDownload(id1)).Times(1);
EXPECT_CALL(provider2, PauseDownload(id2)).Times(1);
EXPECT_CALL(provider1, GetVisualsForItem(id1, _)).Times(1);
@@ -307,8 +307,8 @@ TEST_F(OfflineContentAggregatorTest, ActionPropagatesToRightProvider) {
aggregator_.RemoveItem(id2);
aggregator_.CancelDownload(id1);
aggregator_.CancelDownload(id2);
- aggregator_.ResumeDownload(id1);
- aggregator_.ResumeDownload(id2);
+ aggregator_.ResumeDownload(id1, false);
+ aggregator_.ResumeDownload(id2, true);
aggregator_.PauseDownload(id1);
aggregator_.PauseDownload(id2);
aggregator_.GetVisualsForItem(id1, OfflineContentProvider::VisualsCallback());
@@ -331,11 +331,11 @@ TEST_F(OfflineContentAggregatorTest, ActionPropagatesAfterInitialize) {
{
testing::InSequence sequence;
EXPECT_CALL(provider1, PauseDownload(id1)).Times(1);
- EXPECT_CALL(provider1, ResumeDownload(id1)).Times(1);
+ EXPECT_CALL(provider1, ResumeDownload(id1, true)).Times(1);
EXPECT_CALL(provider1, OpenItem(id1)).Times(1);
EXPECT_CALL(provider2, OpenItem(id2)).Times(0);
- aggregator_.ResumeDownload(id1);
+ aggregator_.ResumeDownload(id1, true);
aggregator_.OpenItem(id1);
provider1.NotifyOnItemsAvailable();
aggregator_.OpenItem(id2);
diff --git a/chromium/components/offline_items_collection/core/offline_content_provider.h b/chromium/components/offline_items_collection/core/offline_content_provider.h
index 82af9958674..fbaba9f9df0 100644
--- a/chromium/components/offline_items_collection/core/offline_content_provider.h
+++ b/chromium/components/offline_items_collection/core/offline_content_provider.h
@@ -74,7 +74,8 @@ class OfflineContentProvider {
virtual void PauseDownload(const ContentId& id) = 0;
// Called to resume a paused download of an OfflineItem represented by |id|.
- virtual void ResumeDownload(const ContentId& id) = 0;
+ // TODO(shaktisahu): Remove |has_user_gesture| if we end up not needing it.
+ virtual void ResumeDownload(const ContentId& id, bool has_user_gesture) = 0;
// Returns an OfflineItem represented by |id| or |nullptr| if none exists.
// The caller should not hold ownership of the returned item beyond the scope
diff --git a/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
index c0c49a4cedb..922cc5a8684 100644
--- a/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
+++ b/chromium/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
@@ -42,7 +42,7 @@ class MockOfflineContentProvider : public OfflineContentProvider {
MOCK_METHOD1(RemoveItem, void(const ContentId&));
MOCK_METHOD1(CancelDownload, void(const ContentId&));
MOCK_METHOD1(PauseDownload, void(const ContentId&));
- MOCK_METHOD1(ResumeDownload, void(const ContentId&));
+ MOCK_METHOD2(ResumeDownload, void(const ContentId&, bool));
MOCK_METHOD1(GetItemById, const OfflineItem*(const ContentId&));
MOCK_METHOD2(GetVisualsForItem,
void(const ContentId&, const VisualsCallback&));
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc
index b1a01640043..0c356826fad 100644
--- a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.cc
@@ -62,8 +62,9 @@ void ThrottledOfflineContentProvider::PauseDownload(const ContentId& id) {
FlushUpdates();
}
-void ThrottledOfflineContentProvider::ResumeDownload(const ContentId& id) {
- wrapped_provider_->ResumeDownload(id);
+void ThrottledOfflineContentProvider::ResumeDownload(const ContentId& id,
+ bool has_user_gesture) {
+ wrapped_provider_->ResumeDownload(id, has_user_gesture);
FlushUpdates();
}
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h
index 86845f92666..3df43f9db52 100644
--- a/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider.h
@@ -40,7 +40,7 @@ class ThrottledOfflineContentProvider
void RemoveItem(const ContentId& id) override;
void CancelDownload(const ContentId& id) override;
void PauseDownload(const ContentId& id) override;
- void ResumeDownload(const ContentId& id) override;
+ void ResumeDownload(const ContentId& id, bool has_user_gesture) override;
// Because this class queues updates, a call to Observer::OnItemUpdated might
// get triggered with the same contents as returned by these getter methods in
diff --git a/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc b/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc
index 7191fb253df..e70b2e5284b 100644
--- a/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc
+++ b/chromium/components/offline_items_collection/core/throttled_offline_content_provider_unittest.cc
@@ -114,7 +114,7 @@ TEST_F(ThrottledOfflineContentProviderTest, TestBasicPassthrough) {
EXPECT_CALL(wrapped_provider_, RemoveItem(id));
EXPECT_CALL(wrapped_provider_, CancelDownload(id));
EXPECT_CALL(wrapped_provider_, PauseDownload(id));
- EXPECT_CALL(wrapped_provider_, ResumeDownload(id));
+ EXPECT_CALL(wrapped_provider_, ResumeDownload(id, true));
EXPECT_CALL(wrapped_provider_, GetVisualsForItem(id, _));
EXPECT_CALL(wrapped_provider_, GetItemById(id)).WillRepeatedly(Return(&item));
EXPECT_CALL(wrapped_provider_, GetAllItems()).WillRepeatedly(Return(items));
@@ -123,7 +123,7 @@ TEST_F(ThrottledOfflineContentProviderTest, TestBasicPassthrough) {
provider_.RemoveItem(id);
provider_.CancelDownload(id);
provider_.PauseDownload(id);
- provider_.ResumeDownload(id);
+ provider_.ResumeDownload(id, true);
provider_.GetVisualsForItem(id, OfflineContentProvider::VisualsCallback());
EXPECT_EQ(&item, provider_.GetItemById(id));
EXPECT_EQ(items, provider_.GetAllItems());
@@ -361,7 +361,7 @@ TEST_F(ThrottledOfflineContentProviderTest, TestPokingProviderFlushesQueue) {
EXPECT_CALL(wrapped_provider_, PauseDownload(_))
.WillRepeatedly(
InvokeWithoutArgs(CallbackToFunctor(base::Bind(updater, item5))));
- EXPECT_CALL(wrapped_provider_, ResumeDownload(_))
+ EXPECT_CALL(wrapped_provider_, ResumeDownload(_, _))
.WillRepeatedly(
InvokeWithoutArgs(CallbackToFunctor(base::Bind(updater, item6))));
@@ -402,7 +402,7 @@ TEST_F(ThrottledOfflineContentProviderTest, TestPokingProviderFlushesQueue) {
EXPECT_CALL(observer, OnItemUpdated(item6)).Times(1);
provider_.set_last_update_time(base::TimeTicks::Now());
wrapped_provider_.NotifyOnItemUpdated(item1);
- provider_.ResumeDownload(id1);
+ provider_.ResumeDownload(id1, false);
}
}
diff --git a/chromium/components/offline_pages/content/renovations/BUILD.gn b/chromium/components/offline_pages/content/renovations/BUILD.gn
new file mode 100644
index 00000000000..955803e16eb
--- /dev/null
+++ b/chromium/components/offline_pages/content/renovations/BUILD.gn
@@ -0,0 +1,19 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+source_set("renovations") {
+ sources = [
+ "render_frame_script_injector.cc",
+ "render_frame_script_injector.h",
+ ]
+
+ deps = [
+ "//components/offline_pages/core/renovations",
+ "//content/public/browser",
+ ]
+}
diff --git a/chromium/components/offline_pages/content/renovations/DEPS b/chromium/components/offline_pages/content/renovations/DEPS
new file mode 100644
index 00000000000..c24130ef510
--- /dev/null
+++ b/chromium/components/offline_pages/content/renovations/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+content/public/browser",
+ "+content/public/common",
+]
diff --git a/chromium/components/offline_pages/content/renovations/render_frame_script_injector.cc b/chromium/components/offline_pages/content/renovations/render_frame_script_injector.cc
new file mode 100644
index 00000000000..78111112b11
--- /dev/null
+++ b/chromium/components/offline_pages/content/renovations/render_frame_script_injector.cc
@@ -0,0 +1,48 @@
+// 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/offline_pages/content/renovations/render_frame_script_injector.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/common/isolated_world_ids.h"
+
+namespace offline_pages {
+
+RenderFrameScriptInjector::RenderFrameScriptInjector(
+ content::RenderFrameHost* render_frame_host,
+ int isolated_world_id)
+ : render_frame_host_(render_frame_host),
+ isolated_world_id_(isolated_world_id) {
+ DCHECK(render_frame_host_);
+ DCHECK(isolated_world_id_ > content::ISOLATED_WORLD_ID_GLOBAL &&
+ isolated_world_id_ < content::ISOLATED_WORLD_ID_MAX);
+}
+
+void RenderFrameScriptInjector::Inject(base::string16 script,
+ ResultCallback callback) {
+ // Must create proxy callback since ExecuteJavaScriptInIsolatedWorld
+ // takes a |const base::Value*| argument instead of a |const
+ // base::Value&|.
+ base::RepeatingCallback<void(const base::Value*)> proxy_callback =
+ base::BindRepeating(
+ [](ResultCallback user_callback, const base::Value* result) {
+ base::Value new_result = result ? result->Clone() : base::Value();
+ if (user_callback)
+ user_callback.Run(new_result);
+ },
+ callback);
+
+ // |render_frame_host_| should still be alive if the
+ // caller is using this class correctly.
+ DCHECK(render_frame_host_);
+ render_frame_host_->ExecuteJavaScriptInIsolatedWorld(
+ script, std::move(proxy_callback), isolated_world_id_);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/content/renovations/render_frame_script_injector.h b/chromium/components/offline_pages/content/renovations/render_frame_script_injector.h
new file mode 100644
index 00000000000..4417ae309ae
--- /dev/null
+++ b/chromium/components/offline_pages/content/renovations/render_frame_script_injector.h
@@ -0,0 +1,37 @@
+// 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_OFFLINE_PAGES_CONTENT_RENOVATIONS_RENDER_FRAME_SCRIPT_INJECTOR_H_
+#define COMPONENTS_OFFLINE_PAGES_CONTENT_RENOVATIONS_RENDER_FRAME_SCRIPT_INJECTOR_H_
+
+#include "components/offline_pages/core/renovations/script_injector.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace offline_pages {
+
+// ScriptInjector for running scripts in a RenderFrame within a given isolated
+// world.
+class RenderFrameScriptInjector : public ScriptInjector {
+ public:
+ ~RenderFrameScriptInjector() override = default;
+
+ // The |render_frame_host| is expected to outlive this
+ // RenderFrameScriptInjector instance.
+ RenderFrameScriptInjector(content::RenderFrameHost* render_frame_host,
+ int isolated_world_id);
+
+ // ScriptInjector implementation.
+ void Inject(base::string16 script, ResultCallback callback) override;
+
+ private:
+ content::RenderFrameHost* render_frame_host_;
+ int isolated_world_id_;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CONTENT_RENOVATIONS_RENDER_FRAME_SCRIPT_INJECTOR_H_
diff --git a/chromium/components/offline_pages/core/BUILD.gn b/chromium/components/offline_pages/core/BUILD.gn
index 90eb73a6000..eb23f53416b 100644
--- a/chromium/components/offline_pages/core/BUILD.gn
+++ b/chromium/components/offline_pages/core/BUILD.gn
@@ -36,7 +36,13 @@ static_library("core") {
"offline_page_storage_manager.cc",
"offline_page_storage_manager.h",
"offline_page_types.h",
+ "offline_pages_ukm_reporter.cc",
+ "offline_pages_ukm_reporter.h",
+ "offline_pages_ukm_reporter_stub.cc",
+ "offline_pages_ukm_reporter_stub.h",
"offline_store_types.h",
+ "offline_time_utils.cc",
+ "offline_time_utils.h",
"snapshot_controller.cc",
"snapshot_controller.h",
"task.cc",
@@ -50,6 +56,8 @@ static_library("core") {
"//base",
"//components/keyed_service/core",
"//net",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql:sql",
"//url",
]
@@ -101,6 +109,7 @@ source_set("unit_tests") {
"offline_page_model_impl_unittest.cc",
"offline_page_model_query_unittest.cc",
"offline_page_storage_manager_unittest.cc",
+ "offline_pages_ukm_reporter_unittest.cc",
"snapshot_controller_unittest.cc",
"task_queue_unittest.cc",
"task_unittest.cc",
@@ -112,8 +121,11 @@ source_set("unit_tests") {
":test_support",
"prefetch:unit_tests",
"recent_tabs:unit_tests",
+ "renovations:unit_tests",
"//base",
"//base/test:test_support",
+ "//components/ukm:test_support",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql:sql",
"//testing/gtest",
"//url",
diff --git a/chromium/components/offline_pages/core/DEPS b/chromium/components/offline_pages/core/DEPS
index 5d8bc16f120..852e57ee9a4 100644
--- a/chromium/components/offline_pages/core/DEPS
+++ b/chromium/components/offline_pages/core/DEPS
@@ -1,4 +1,6 @@
include_rules = [
"+components/keyed_service",
+ "+components/ukm",
+ "+services/metrics/public/cpp",
"+sql",
]
diff --git a/chromium/components/offline_pages/core/archive_manager.cc b/chromium/components/offline_pages/core/archive_manager.cc
index 400a059f26c..f73293e4eda 100644
--- a/chromium/components/offline_pages/core/archive_manager.cc
+++ b/chromium/components/offline_pages/core/archive_manager.cc
@@ -132,4 +132,8 @@ void ArchiveManager::GetStorageStats(
base::ThreadTaskRunnerHandle::Get(), callback));
}
+const base::FilePath& ArchiveManager::GetArchivesDir() const {
+ return archives_dir_;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/archive_manager.h b/chromium/components/offline_pages/core/archive_manager.h
index dc92e7de79b..e4e24562bab 100644
--- a/chromium/components/offline_pages/core/archive_manager.h
+++ b/chromium/components/offline_pages/core/archive_manager.h
@@ -63,6 +63,9 @@ class ArchiveManager {
const base::Callback<void(const StorageStats& storage_sizes)>& callback)
const;
+ // Gets the archive directory.
+ const base::FilePath& GetArchivesDir() const;
+
protected:
ArchiveManager();
@@ -71,6 +74,8 @@ class ArchiveManager {
base::FilePath archives_dir_;
// Task runner for running file operations.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArchiveManager);
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/BUILD.gn b/chromium/components/offline_pages/core/background/BUILD.gn
index 083e7a9e898..17f84ebe5cd 100644
--- a/chromium/components/offline_pages/core/background/BUILD.gn
+++ b/chromium/components/offline_pages/core/background/BUILD.gn
@@ -87,6 +87,7 @@ static_library("test_support") {
deps = [
":background_offliner",
"//base",
+ "//components/offline_pages/core",
"//net",
]
}
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.cc b/chromium/components/offline_pages/core/background/pick_request_task.cc
index d2faeac9cb1..59f338a21c4 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task.cc
@@ -31,14 +31,15 @@ bool kNonUserRequestsFound = true;
namespace offline_pages {
-PickRequestTask::PickRequestTask(RequestQueueStore* store,
- OfflinerPolicy* policy,
- RequestPickedCallback picked_callback,
- RequestNotPickedCallback not_picked_callback,
- RequestCountCallback request_count_callback,
- DeviceConditions& device_conditions,
- const std::set<int64_t>& disabled_requests,
- std::deque<int64_t>& prioritized_requests)
+PickRequestTask::PickRequestTask(
+ RequestQueueStore* store,
+ OfflinerPolicy* policy,
+ RequestPickedCallback picked_callback,
+ RequestNotPickedCallback not_picked_callback,
+ RequestCountCallback request_count_callback,
+ DeviceConditions& device_conditions,
+ const std::set<int64_t>& disabled_requests,
+ base::circular_deque<int64_t>& prioritized_requests)
: store_(store),
policy_(policy),
picked_callback_(picked_callback),
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.h b/chromium/components/offline_pages/core/background/pick_request_task.h
index b6cad2cce18..3c25615d708 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.h
+++ b/chromium/components/offline_pages/core/background/pick_request_task.h
@@ -5,9 +5,9 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
-#include <deque>
#include <set>
+#include "base/containers/circular_deque.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/background/request_queue_results.h"
#include "components/offline_pages/core/background/save_page_request.h"
@@ -45,7 +45,7 @@ class PickRequestTask : public Task {
RequestCountCallback request_count_callback,
DeviceConditions& device_conditions,
const std::set<int64_t>& disabled_requests,
- std::deque<int64_t>& prioritized_requests);
+ base::circular_deque<int64_t>& prioritized_requests);
~PickRequestTask() override;
@@ -96,7 +96,7 @@ class PickRequestTask : public Task {
RequestCountCallback request_count_callback_;
std::unique_ptr<DeviceConditions> device_conditions_;
const std::set<int64_t>& disabled_requests_;
- std::deque<int64_t>& prioritized_requests_;
+ base::circular_deque<int64_t>& prioritized_requests_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<PickRequestTask> weak_ptr_factory_;
};
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 7f686246551..c43a3637d08 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
@@ -4,11 +4,11 @@
#include "components/offline_pages/core/background/pick_request_task.h"
-#include <deque>
#include <memory>
#include <set>
#include "base/bind.h"
+#include "base/containers/circular_deque.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -128,7 +128,7 @@ class PickRequestTaskTest : public testing::Test {
std::unique_ptr<OfflinerPolicy> policy_;
RequestCoordinatorEventLogger event_logger_;
std::set<int64_t> disabled_requests_;
- std::deque<int64_t> prioritized_requests_;
+ base::circular_deque<int64_t> prioritized_requests_;
std::unique_ptr<PickRequestTask> task_;
bool request_queue_not_picked_called_;
bool cleanup_needed_;
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.cc b/chromium/components/offline_pages/core/background/request_coordinator.cc
index 099a91fd2a4..1772877588c 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator.cc
@@ -21,6 +21,7 @@
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
namespace offline_pages {
@@ -216,7 +217,8 @@ RequestCoordinator::RequestCoordinator(
std::unique_ptr<RequestQueue> queue,
std::unique_ptr<Scheduler> scheduler,
net::NetworkQualityEstimator::NetworkQualityProvider*
- network_quality_estimator)
+ network_quality_estimator,
+ std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter)
: is_low_end_device_(base::SysInfo::IsLowEndDevice()),
state_(RequestCoordinatorState::IDLE),
processing_state_(ProcessingWindowState::STOPPED),
@@ -227,6 +229,7 @@ RequestCoordinator::RequestCoordinator(
scheduler_(std::move(scheduler)),
policy_controller_(new ClientPolicyController()),
network_quality_estimator_(network_quality_estimator),
+ ukm_reporter_(std::move(ukm_reporter)),
network_quality_at_request_start_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
active_request_id_(0),
last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
@@ -288,6 +291,14 @@ int64_t RequestCoordinator::SavePageLater(
network_quality_estimator_->GetEffectiveConnectionType());
}
+ // Record UKM for this page offlining attempt.
+ if (ukm_reporter_) {
+ ukm_reporter_->ReportUrlOfflineRequest(
+ save_page_later_params.url,
+ save_page_later_params.availability ==
+ RequestAvailability::DISABLED_FOR_OFFLINER);
+ }
+
return id;
}
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.h b/chromium/components/offline_pages/core/background/request_coordinator.h
index 9f27623f134..a1131564cdc 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.h
+++ b/chromium/components/offline_pages/core/background/request_coordinator.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
@@ -34,6 +35,7 @@ class OfflinerPolicy;
class Offliner;
class SavePageRequest;
class ClientPolicyController;
+class OfflinePagesUkmReporter;
// Coordinates queueing and processing save page later requests.
class RequestCoordinator : public KeyedService,
@@ -110,7 +112,8 @@ class RequestCoordinator : public KeyedService,
std::unique_ptr<RequestQueue> queue,
std::unique_ptr<Scheduler> scheduler,
net::NetworkQualityEstimator::NetworkQualityProvider*
- network_quality_estimator);
+ network_quality_estimator,
+ std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter);
~RequestCoordinator() override;
@@ -447,6 +450,8 @@ class RequestCoordinator : public KeyedService,
// Unowned pointer to the Network Quality Estimator.
net::NetworkQualityEstimator::NetworkQualityProvider*
network_quality_estimator_;
+ // Object that can record Url Keyed Metrics (UKM).
+ std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_;
net::EffectiveConnectionType network_quality_at_request_start_;
// Holds an ID of the currently active request.
int64_t active_request_id_;
@@ -479,7 +484,7 @@ class RequestCoordinator : public KeyedService,
// it was completed or cancelled), the task will remove it.
// Currently it's used as LIFO.
// TODO(romax): see if LIFO is a good idea or change to FIFO. crbug.com/705106
- std::deque<int64_t> prioritized_requests_;
+ base::circular_deque<int64_t> prioritized_requests_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<RequestCoordinator> weak_ptr_factory_;
diff --git a/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.cc b/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.cc
index 3aa3236fb99..acc4453a66a 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.cc
@@ -12,6 +12,7 @@
#include "components/offline_pages/core/background/save_page_request.h"
#include "components/offline_pages/core/background/scheduler.h"
#include "components/offline_pages/core/background/scheduler_stub.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter_stub.h"
namespace offline_pages {
@@ -22,6 +23,7 @@ RequestCoordinatorStubTaco::RequestCoordinatorStubTaco() {
offliner_ = base::MakeUnique<OfflinerStub>();
scheduler_ = base::MakeUnique<SchedulerStub>();
network_quality_provider_ = base::MakeUnique<NetworkQualityProviderStub>();
+ ukm_reporter_ = base::MakeUnique<OfflinePagesUkmReporterStub>();
}
RequestCoordinatorStubTaco::~RequestCoordinatorStubTaco() {
@@ -66,10 +68,16 @@ void RequestCoordinatorStubTaco::SetNetworkQualityProvider(
network_quality_provider_ = std::move(network_quality_provider);
}
+void RequestCoordinatorStubTaco::SetOfflinePagesUkmReporter(
+ std::unique_ptr<offline_pages::OfflinePagesUkmReporter> ukm_reporter) {
+ ukm_reporter_ = std::move(ukm_reporter);
+}
+
void RequestCoordinatorStubTaco::CreateRequestCoordinator() {
request_coordinator_ = base::MakeUnique<RequestCoordinator>(
std::move(policy_), std::move(offliner_), std::move(queue_),
- std::move(scheduler_), network_quality_provider_.get());
+ std::move(scheduler_), network_quality_provider_.get(),
+ std::move(ukm_reporter_));
}
RequestCoordinator* RequestCoordinatorStubTaco::request_coordinator() {
diff --git a/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.h b/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.h
index 58879d12214..14f23d519f1 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.h
+++ b/chromium/components/offline_pages/core/background/request_coordinator_stub_taco.h
@@ -40,6 +40,8 @@ class RequestCoordinatorStubTaco {
void SetNetworkQualityProvider(
std::unique_ptr<net::NetworkQualityEstimator::NetworkQualityProvider>
network_quality_provider);
+ void SetOfflinePagesUkmReporter(
+ std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter);
// Creates and caches an instance of RequestCoordinator, using default or
// overridden stub dependencies.
@@ -61,6 +63,7 @@ class RequestCoordinatorStubTaco {
std::unique_ptr<Scheduler> scheduler_;
std::unique_ptr<net::NetworkQualityEstimator::NetworkQualityProvider>
network_quality_provider_;
+ std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_;
std::unique_ptr<RequestCoordinator> request_coordinator_;
};
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 d16f9d5c8f9..cc1003e7483 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -10,6 +10,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/circular_deque.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
@@ -313,7 +314,7 @@ class RequestCoordinatorTest : public testing::Test {
return coordinator()->disabled_requests_;
}
- const std::deque<int64_t>& prioritized_requests() {
+ const base::circular_deque<int64_t>& prioritized_requests() {
return coordinator()->prioritized_requests_;
}
diff --git a/chromium/components/offline_pages/core/background/request_queue.cc b/chromium/components/offline_pages/core/background/request_queue.cc
index bac52ae5abb..45ae3d0216b 100644
--- a/chromium/components/offline_pages/core/background/request_queue.cc
+++ b/chromium/components/offline_pages/core/background/request_queue.cc
@@ -60,12 +60,14 @@ void AddRequestDone(const RequestQueue::AddRequestCallback& callback,
} // namespace
RequestQueue::RequestQueue(std::unique_ptr<RequestQueueStore> store)
- : store_(std::move(store)), weak_ptr_factory_(this) {
+ : store_(std::move(store)), task_queue_(this), weak_ptr_factory_(this) {
Initialize();
}
RequestQueue::~RequestQueue() {}
+void RequestQueue::OnTaskQueueIsIdle() {}
+
void RequestQueue::GetRequests(const GetRequestsCallback& callback) {
std::unique_ptr<Task> task(new GetRequestsTask(
store_.get(), base::Bind(&GetRequestsDone, callback)));
@@ -123,7 +125,7 @@ void RequestQueue::PickNextRequest(
PickRequestTask::RequestCountCallback request_count_callback,
DeviceConditions& conditions,
std::set<int64_t>& disabled_requests,
- std::deque<int64_t>& prioritized_requests) {
+ base::circular_deque<int64_t>& prioritized_requests) {
// Using the PickerContext, create a picker task.
std::unique_ptr<Task> task(
new PickRequestTask(store_.get(), policy, picked_callback,
diff --git a/chromium/components/offline_pages/core/background/request_queue.h b/chromium/components/offline_pages/core/background/request_queue.h
index d0c66a7ad48..a8156b32b4b 100644
--- a/chromium/components/offline_pages/core/background/request_queue.h
+++ b/chromium/components/offline_pages/core/background/request_queue.h
@@ -7,13 +7,13 @@
#include <stdint.h>
-#include <deque>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/background/cleanup_task_factory.h"
@@ -31,7 +31,7 @@ class CleanupTaskFactory;
class RequestQueueStore;
// Class responsible for managing save page requests.
-class RequestQueue {
+class RequestQueue : public TaskQueue::Delegate {
public:
// Callback used for |GetRequests|.
typedef base::Callback<void(GetRequestsResult,
@@ -50,7 +50,10 @@ class RequestQueue {
typedef base::Callback<void(UpdateRequestResult)> UpdateRequestCallback;
explicit RequestQueue(std::unique_ptr<RequestQueueStore> store);
- ~RequestQueue();
+ ~RequestQueue() override;
+
+ // TaskQueue::Delegate
+ void OnTaskQueueIsIdle() override;
// Gets all of the active requests from the store. Calling this method may
// schedule purging of the request queue.
@@ -97,7 +100,7 @@ class RequestQueue {
PickRequestTask::RequestCountCallback request_count_callback,
DeviceConditions& conditions,
std::set<int64_t>& disabled_requests,
- std::deque<int64_t>& prioritized_requests);
+ base::circular_deque<int64_t>& prioritized_requests);
// Reconcile any requests that were active the last time chrome exited.
void ReconcileRequests(const UpdateCallback& callback);
diff --git a/chromium/components/offline_pages/core/client_id.cc b/chromium/components/offline_pages/core/client_id.cc
index df60634116b..e4f988cf1c1 100644
--- a/chromium/components/offline_pages/core/client_id.cc
+++ b/chromium/components/offline_pages/core/client_id.cc
@@ -4,6 +4,8 @@
#include "components/offline_pages/core/client_id.h"
+#include <ostream>
+
namespace offline_pages {
ClientId::ClientId() {}
@@ -22,4 +24,16 @@ bool ClientId::operator<(const ClientId& client_id) const {
return name_space < client_id.name_space;
}
+std::string ClientId::ToString() const {
+ return std::string("ClientId(")
+ .append(name_space)
+ .append(", ")
+ .append(id)
+ .append(")");
+}
+
+std::ostream& operator<<(std::ostream& out, const ClientId& cid) {
+ return out << cid.ToString();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/client_id.h b/chromium/components/offline_pages/core/client_id.h
index 8c749828344..3493375d2e2 100644
--- a/chromium/components/offline_pages/core/client_id.h
+++ b/chromium/components/offline_pages/core/client_id.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_CLIENT_ID_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_CLIENT_ID_H_
+#include <iosfwd>
#include <string>
namespace offline_pages {
@@ -21,6 +22,8 @@ struct ClientId {
bool operator<(const ClientId& client_id) const;
+ std::string ToString() const;
+
// The namespace that identifies the client (of course 'namespace' is a
// reserved word, so...).
std::string name_space;
@@ -31,6 +34,8 @@ struct ClientId {
std::string id;
};
+std::ostream& operator<<(std::ostream& out, const ClientId& cid);
+
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_CLIENT_ID_H_ \ No newline at end of file
diff --git a/chromium/components/offline_pages/core/client_namespace_constants.cc b/chromium/components/offline_pages/core/client_namespace_constants.cc
index 66a4321fb36..1384597b13c 100644
--- a/chromium/components/offline_pages/core/client_namespace_constants.cc
+++ b/chromium/components/offline_pages/core/client_namespace_constants.cc
@@ -6,6 +6,8 @@
namespace offline_pages {
+// NOTE: When adding a namespace constant, you MUST add this as a suffix in
+// //tools/metrics/histograms/histograms.xml or risk crashes due to DCHECKs.
const char kBookmarkNamespace[] = "bookmark";
const char kLastNNamespace[] = "last_n";
const char kAsyncNamespace[] = "async_loading";
diff --git a/chromium/components/offline_pages/core/offline_event_logger.cc b/chromium/components/offline_pages/core/offline_event_logger.cc
index 09d2b7f90f5..62f89309ee4 100644
--- a/chromium/components/offline_pages/core/offline_event_logger.cc
+++ b/chromium/components/offline_pages/core/offline_event_logger.cc
@@ -33,6 +33,7 @@ void OfflineEventLogger::GetLogs(std::vector<std::string>* records) {
}
void OfflineEventLogger::RecordActivity(const std::string& activity) {
+ DVLOG(1) << activity;
if (!is_logging_ || activity.empty())
return;
diff --git a/chromium/components/offline_pages/core/offline_event_logger.h b/chromium/components/offline_pages/core/offline_event_logger.h
index 40bb9c45a3a..4eafff150d6 100644
--- a/chromium/components/offline_pages/core/offline_event_logger.h
+++ b/chromium/components/offline_pages/core/offline_event_logger.h
@@ -5,10 +5,10 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_EVENT_LOGGER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_EVENT_LOGGER_H_
-#include <deque>
#include <string>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
namespace offline_pages {
@@ -62,7 +62,7 @@ class OfflineEventLogger {
private:
// Recorded offline page activities.
- std::deque<std::string> activities_;
+ base::circular_deque<std::string> activities_;
// Whether we are currently recording logs or not.
bool is_logging_;
diff --git a/chromium/components/offline_pages/core/offline_page_feature.cc b/chromium/components/offline_pages/core/offline_page_feature.cc
index cbc572e8749..457f1be4bbe 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature.cc
@@ -51,9 +51,8 @@ const base::Feature kOfflinePagesAsyncDownloadFeature{
const base::Feature kPrefetchingOfflinePagesFeature{
"OfflinePagesPrefetching", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kNewBackgroundLoaderFeature {
- "BackgroundLoader", base::FEATURE_DISABLED_BY_DEFAULT
-};
+const base::Feature kNewBackgroundLoaderFeature{
+ "BackgroundLoader", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kOfflinePagesCTV2Feature{"OfflinePagesCTV2",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/offline_pages/core/offline_page_item.cc b/chromium/components/offline_pages/core/offline_page_item.cc
index 5b13c80d4ed..77f5d712351 100644
--- a/chromium/components/offline_pages/core/offline_page_item.cc
+++ b/chromium/components/offline_pages/core/offline_page_item.cc
@@ -7,7 +7,11 @@
namespace offline_pages {
OfflinePageItem::OfflinePageItem()
- : file_size(0), access_count(0), flags(NO_FLAG) {}
+ : file_size(0),
+ access_count(0),
+ flags(NO_FLAG),
+ system_download_id(0),
+ upgrade_attempt(0) {}
OfflinePageItem::OfflinePageItem(const GURL& url,
int64_t offline_id,
@@ -20,7 +24,9 @@ OfflinePageItem::OfflinePageItem(const GURL& url,
file_path(file_path),
file_size(file_size),
access_count(0),
- flags(NO_FLAG) {}
+ flags(NO_FLAG),
+ system_download_id(0),
+ upgrade_attempt(0) {}
OfflinePageItem::OfflinePageItem(const GURL& url,
int64_t offline_id,
@@ -36,7 +42,9 @@ OfflinePageItem::OfflinePageItem(const GURL& url,
creation_time(creation_time),
last_access_time(creation_time),
access_count(0),
- flags(NO_FLAG) {}
+ flags(NO_FLAG),
+ system_download_id(0),
+ upgrade_attempt(0) {}
OfflinePageItem::OfflinePageItem(const GURL& url,
int64_t offline_id,
@@ -54,7 +62,9 @@ OfflinePageItem::OfflinePageItem(const GURL& url,
last_access_time(creation_time),
access_count(0),
flags(NO_FLAG),
- request_origin(request_origin) {}
+ request_origin(request_origin),
+ system_download_id(0),
+ upgrade_attempt(0) {}
OfflinePageItem::OfflinePageItem(const OfflinePageItem& other) = default;
@@ -67,7 +77,10 @@ bool OfflinePageItem::operator==(const OfflinePageItem& other) const {
last_access_time == other.last_access_time &&
access_count == other.access_count && title == other.title &&
flags == other.flags && original_url == other.original_url &&
- request_origin == other.request_origin;
+ request_origin == other.request_origin &&
+ system_download_id == other.system_download_id &&
+ file_missing_time == other.file_missing_time &&
+ upgrade_attempt == other.upgrade_attempt && digest == digest;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_item.h b/chromium/components/offline_pages/core/offline_page_item.h
index f952e6f6918..b65e1cd5d70 100644
--- a/chromium/components/offline_pages/core/offline_page_item.h
+++ b/chromium/components/offline_pages/core/offline_page_item.h
@@ -79,6 +79,17 @@ struct OfflinePageItem {
// The app, if any, that the item was saved on behalf of.
// Empty string implies Chrome.
std::string request_origin;
+ // System download id.
+ int64_t system_download_id;
+ // The most recent time when the file was discovered missing.
+ // NULL time implies the file is not missing.
+ base::Time file_missing_time;
+ // Number of attemps for upgrading the MHTML page into new format.
+ int upgrade_attempt;
+ // Digest of the page calculated when page is saved, in order to tell if the
+ // page can be trusted. This field will always be an empty string for
+ // temporary and shared pages.
+ std::string digest;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
index de6ef9e77fb..8daeeaf2980 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/offline_page_item.h"
+#include "components/offline_pages/core/offline_time_utils.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/transaction.h"
@@ -34,13 +35,17 @@ bool CreateOfflinePagesTable(sql::Connection* db) {
" file_size INTEGER NOT NULL,"
" last_access_time INTEGER NOT NULL,"
" access_count INTEGER NOT NULL,"
+ " system_download_id INTEGER NOT NULL DEFAULT 0,"
+ " file_missing_time INTEGER NOT NULL DEFAULT 0,"
+ " upgrade_attempt INTEGER NOT NULL DEFAULT 0,"
" client_namespace VARCHAR NOT NULL,"
" client_id VARCHAR NOT NULL,"
" online_url VARCHAR NOT NULL,"
" file_path VARCHAR NOT NULL,"
" title VARCHAR NOT NULL DEFAULT '',"
" original_url VARCHAR NOT NULL DEFAULT '',"
- " request_origin VARCHAR NOT NULL DEFAULT ''"
+ " request_origin VARCHAR NOT NULL DEFAULT '',"
+ " digest VARCHAR NOT NULL DEFAULT ''"
")";
return db->Execute(kSql);
}
@@ -143,6 +148,20 @@ bool UpgradeFrom57(sql::Connection* db) {
return UpgradeWithQuery(db, kSql);
}
+bool UpgradeFrom61(sql::Connection* db) {
+ const char kSql[] =
+ "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
+ " (offline_id, creation_time, file_size, last_access_time, "
+ "access_count, client_namespace, client_id, online_url, "
+ "file_path, title, original_url, request_origin) "
+ "SELECT "
+ "offline_id, creation_time, file_size, last_access_time, "
+ "access_count, client_namespace, client_id, online_url, "
+ "file_path, title, original_url, request_origin "
+ "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
+ return UpgradeWithQuery(db, kSql);
+}
+
bool CreateSchema(sql::Connection* db) {
// If you create a transaction but don't Commit() it is automatically
// rolled back by its destructor when it falls out of scope.
@@ -175,6 +194,9 @@ bool CreateSchema(sql::Connection* db) {
} else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "request_origin")) {
if (!UpgradeFrom57(db))
return false;
+ } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "digest")) {
+ if (!UpgradeFrom61(db))
+ return false;
}
// This would be a great place to add indices when we need them.
@@ -213,18 +235,20 @@ std::string GetUTF8StringFromPath(const base::FilePath& path) {
// all columns present.
OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
int64_t id = statement->ColumnInt64(0);
- base::Time creation_time =
- base::Time::FromInternalValue(statement->ColumnInt64(1));
+ base::Time creation_time = FromDatabaseTime(statement->ColumnInt64(1));
int64_t file_size = statement->ColumnInt64(2);
- base::Time last_access_time =
- base::Time::FromInternalValue(statement->ColumnInt64(3));
+ base::Time last_access_time = FromDatabaseTime(statement->ColumnInt64(3));
int access_count = statement->ColumnInt(4);
- ClientId client_id(statement->ColumnString(5), statement->ColumnString(6));
- GURL url(statement->ColumnString(7));
- base::FilePath path(GetPathFromUTF8String(statement->ColumnString(8)));
- base::string16 title = statement->ColumnString16(9);
- GURL original_url(statement->ColumnString(10));
- std::string request_origin = statement->ColumnString(11);
+ int64_t system_download_id = statement->ColumnInt64(5);
+ base::Time file_missing_time = FromDatabaseTime(statement->ColumnInt64(6));
+ int upgrade_attempt = statement->ColumnInt(7);
+ ClientId client_id(statement->ColumnString(8), statement->ColumnString(9));
+ GURL url(statement->ColumnString(10));
+ base::FilePath path(GetPathFromUTF8String(statement->ColumnString(11)));
+ base::string16 title = statement->ColumnString16(12);
+ GURL original_url(statement->ColumnString(13));
+ std::string request_origin = statement->ColumnString(14);
+ std::string digest = statement->ColumnString(15);
OfflinePageItem item(url, id, client_id, path, file_size, creation_time);
item.last_access_time = last_access_time;
@@ -232,6 +256,10 @@ OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
item.title = title;
item.original_url = original_url;
item.request_origin = request_origin;
+ item.system_download_id = system_download_id;
+ item.file_missing_time = file_missing_time;
+ item.upgrade_attempt = upgrade_attempt;
+ item.digest = digest;
return item;
}
@@ -242,9 +270,10 @@ ItemActionStatus Insert(sql::Connection* db, const OfflinePageItem& item) {
"INSERT OR IGNORE INTO " OFFLINE_PAGES_TABLE_NAME
" (offline_id, online_url, client_namespace, client_id, file_path, "
"file_size, creation_time, last_access_time, access_count, "
- "title, original_url, request_origin)"
+ "title, original_url, request_origin, system_download_id, "
+ "file_missing_time, upgrade_attempt, digest)"
" VALUES "
- " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, item.offline_id);
@@ -253,12 +282,17 @@ ItemActionStatus Insert(sql::Connection* db, const OfflinePageItem& item) {
statement.BindString(3, item.client_id.id);
statement.BindString(4, GetUTF8StringFromPath(item.file_path));
statement.BindInt64(5, item.file_size);
- statement.BindInt64(6, item.creation_time.ToInternalValue());
- statement.BindInt64(7, item.last_access_time.ToInternalValue());
+ statement.BindInt64(6, ToDatabaseTime(item.creation_time));
+ statement.BindInt64(7, ToDatabaseTime(item.last_access_time));
statement.BindInt(8, item.access_count);
statement.BindString16(9, item.title);
statement.BindString(10, item.original_url.spec());
statement.BindString(11, item.request_origin);
+ statement.BindInt64(12, item.system_download_id);
+ statement.BindInt64(13, ToDatabaseTime(item.file_missing_time));
+ statement.BindInt(14, item.upgrade_attempt);
+ statement.BindString(15, item.digest);
+
if (!statement.Run())
return ItemActionStatus::STORE_ERROR;
if (db->GetLastChangeCount() == 0)
@@ -271,7 +305,9 @@ bool Update(sql::Connection* db, const OfflinePageItem& item) {
"UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
" SET online_url = ?, client_namespace = ?, client_id = ?, file_path = ?,"
" file_size = ?, creation_time = ?, last_access_time = ?,"
- " access_count = ?, title = ?, original_url = ?, request_origin = ?"
+ " access_count = ?, title = ?, original_url = ?, request_origin = ?,"
+ " system_download_id = ?, file_missing_time = ?, upgrade_attempt = ?,"
+ " digest = ?"
" WHERE offline_id = ?";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -280,13 +316,17 @@ bool Update(sql::Connection* db, const OfflinePageItem& item) {
statement.BindString(2, item.client_id.id);
statement.BindString(3, GetUTF8StringFromPath(item.file_path));
statement.BindInt64(4, item.file_size);
- statement.BindInt64(5, item.creation_time.ToInternalValue());
- statement.BindInt64(6, item.last_access_time.ToInternalValue());
+ statement.BindInt64(5, ToDatabaseTime(item.creation_time));
+ statement.BindInt64(6, ToDatabaseTime(item.last_access_time));
statement.BindInt(7, item.access_count);
statement.BindString16(8, item.title);
statement.BindString(9, item.original_url.spec());
statement.BindString(10, item.request_origin);
- statement.BindInt64(11, item.offline_id);
+ statement.BindInt64(11, item.system_download_id);
+ statement.BindInt64(12, ToDatabaseTime(item.file_missing_time));
+ statement.BindInt(13, item.upgrade_attempt);
+ statement.BindString(14, item.digest);
+ statement.BindInt64(15, item.offline_id);
return statement.Run() && db->GetLastChangeCount() > 0;
}
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.h b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.h
index e9c44ec6400..0d4e16567b5 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_sql.h
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_sql.h
@@ -39,6 +39,8 @@ namespace offline_pages {
// removed when metadata consistency check happens.
// * In M58-M60 there were no changes.
// * In M61 request_origin was added.
+// * In M62 system_download_id, file_missing_time, upgrade_attempt and digest
+// were added to support P2P sharing feature.
//
// Here is a procedure to update the schema for this store:
// * Decide how to detect that the store is on a particular version, which
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 171d969fcb6..44f415c3115 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
@@ -37,6 +37,9 @@ const base::FilePath::CharType kFilePath[] =
FILE_PATH_LITERAL("/offline_pages/example_com.mhtml");
int64_t kFileSize = 234567LL;
int64_t kOfflineId = 12345LL;
+const char kTestRequestOrigin[] = "request.origin";
+int64_t kTestSystemDownloadId = 42LL;
+const char kTestDigest[] = "test-digest";
// Build a store with outdated schema to simulate the upgrading process.
void BuildTestStoreWithSchemaFromM52(const base::FilePath& file) {
@@ -312,6 +315,51 @@ void BuildTestStoreWithSchemaFromM57(const base::FilePath& file) {
connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "request_origin"));
}
+void BuildTestStoreWithSchemaFromM61(const base::FilePath& file) {
+ sql::Connection connection;
+ ASSERT_TRUE(
+ connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db"))));
+ ASSERT_TRUE(connection.is_open());
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1
+ "(offline_id INTEGER PRIMARY KEY NOT NULL,"
+ " creation_time INTEGER NOT NULL,"
+ " file_size INTEGER NOT NULL,"
+ " last_access_time INTEGER NOT NULL,"
+ " access_count INTEGER NOT NULL,"
+ " client_namespace VARCHAR NOT NULL,"
+ " client_id VARCHAR NOT NULL,"
+ " online_url VARCHAR NOT NULL,"
+ " file_path VARCHAR NOT NULL,"
+ " title VARCHAR NOT NULL DEFAULT '',"
+ " original_url VARCHAR NOT NULL DEFAULT '',"
+ " request_origin VARCHAR NOT NULL DEFAULT ''"
+ ")"));
+ ASSERT_TRUE(connection.CommitTransaction());
+ sql::Statement statement(connection.GetUniqueStatement(
+ "INSERT INTO " OFFLINE_PAGES_TABLE_V1
+ "(offline_id, creation_time, file_size, "
+ "last_access_time, access_count, client_namespace, "
+ "client_id, online_url, file_path, title, original_url, "
+ "request_origin) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ statement.BindInt64(0, kOfflineId);
+ statement.BindInt(1, 0);
+ statement.BindInt64(2, kFileSize);
+ statement.BindInt(3, 0);
+ statement.BindInt(4, 1);
+ statement.BindCString(5, kTestClientNamespace);
+ statement.BindString(6, kTestClientId2.id);
+ statement.BindCString(7, kTestURL);
+ statement.BindString(8, base::FilePath(kFilePath).MaybeAsASCII());
+ statement.BindString16(9, base::UTF8ToUTF16("Test title"));
+ statement.BindCString(10, kOriginalTestURL);
+ statement.BindString(11, kTestRequestOrigin);
+ ASSERT_TRUE(statement.Run());
+ ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
+ ASSERT_FALSE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "digest"));
+}
+
class OfflinePageMetadataStoreFactory {
public:
OfflinePageMetadataStore* BuildStore(const base::FilePath& file_path) {
@@ -361,6 +409,13 @@ class OfflinePageMetadataStoreFactory {
base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
+
+ OfflinePageMetadataStore* BuildStoreM61(const base::FilePath& file_path) {
+ BuildTestStoreWithSchemaFromM61(file_path);
+ OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
+ base::ThreadTaskRunnerHandle::Get(), file_path);
+ return store;
+ }
};
enum CalledCallback { NONE, LOAD, ADD, UPDATE, REMOVE, RESET };
@@ -383,6 +438,7 @@ class OfflinePageMetadataStoreTest : public testing::Test {
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM55();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM56();
std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM57();
+ std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM61();
void PumpLoop();
@@ -481,6 +537,8 @@ void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved(
base::FilePath(kFilePath), kFileSize);
offline_page.title = base::UTF8ToUTF16("a title");
offline_page.original_url = GURL(kOriginalTestURL);
+ offline_page.system_download_id = kTestSystemDownloadId;
+ offline_page.digest = kTestDigest;
store->AddOfflinePage(offline_page,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
@@ -617,6 +675,22 @@ OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM57() {
return store;
}
+std::unique_ptr<OfflinePageMetadataStore>
+OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM61() {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ factory_.BuildStoreM61(temp_directory_.GetPath()));
+ PumpLoop();
+ store->Initialize(
+ base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ return store;
+}
+
// Loads empty store and makes sure that there are no offline pages stored in
// it.
TEST_F(OfflinePageMetadataStoreTest, LoadEmptyStore) {
@@ -763,6 +837,17 @@ TEST_F(OfflinePageMetadataStoreTest, LoadVersion57Store) {
CheckThatOfflinePageCanBeSaved(std::move(store));
}
+// Loads a string with schema from M61.
+// This test case would crash if it's not handling correctly when we're loading
+// old version stores.
+TEST_F(OfflinePageMetadataStoreTest, LoadVersion61Store) {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ BuildStoreWithSchemaFromM61());
+
+ OfflinePageItem item = CheckThatStoreHasOneItem();
+ CheckThatOfflinePageCanBeSaved(std::move(store));
+}
+
// Adds metadata of an offline page into a store and then opens the store
// again to make sure that stored metadata survives store restarts.
TEST_F(OfflinePageMetadataStoreTest, AddOfflinePage) {
@@ -874,8 +959,10 @@ TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
base::FilePath(FILE_PATH_LITERAL("//other.page.com.mhtml"));
OfflinePageItem offline_page_2(GURL("https://other.page.com"), 5678LL,
kTestClientId2, file_path_2, 12345,
- base::Time::Now(), "abc.xyz");
+ base::Time::Now(), kTestRequestOrigin);
offline_page_2.original_url = GURL("https://example.com/bar");
+ offline_page_2.system_download_id = kTestSystemDownloadId;
+ offline_page_2.digest = kTestDigest;
store->AddOfflinePage(offline_page_2,
base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
base::Unretained(this)));
@@ -923,16 +1010,7 @@ TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
EXPECT_EQ(LOAD, last_called_callback_);
EXPECT_EQ(STATUS_TRUE, last_status_);
ASSERT_EQ(1U, offline_pages_.size());
- EXPECT_EQ(offline_page_2.url, offline_pages_[0].url);
- EXPECT_EQ(offline_page_2.offline_id, offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page_2.file_path, offline_pages_[0].file_path);
- EXPECT_EQ(offline_page_2.file_size, offline_pages_[0].file_size);
- EXPECT_EQ(offline_page_2.creation_time, offline_pages_[0].creation_time);
- EXPECT_EQ(offline_page_2.last_access_time,
- offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page_2.access_count, offline_pages_[0].access_count);
- EXPECT_EQ(offline_page_2.client_id, offline_pages_[0].client_id);
- EXPECT_EQ(offline_page_2.request_origin, offline_pages_[0].request_origin);
+ EXPECT_EQ(offline_page_2, offline_pages_[0]);
}
// Tests updating offline page metadata from the store.
@@ -963,7 +1041,9 @@ TEST_F(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
offline_page.file_size = kFileSize + 1;
offline_page.access_count++;
offline_page.original_url = GURL("https://example.com/bar");
- offline_page.request_origin = "abc.xyz";
+ offline_page.request_origin = kTestRequestOrigin;
+ offline_page.upgrade_attempt = 1;
+ offline_page.digest = kTestDigest;
std::vector<OfflinePageItem> items_to_update;
items_to_update.push_back(offline_page);
store->UpdateOfflinePages(
diff --git a/chromium/components/offline_pages/core/offline_page_model.h b/chromium/components/offline_pages/core/offline_page_model.h
index ee5fba6f6e4..dd5a2b5f03c 100644
--- a/chromium/components/offline_pages/core/offline_page_model.h
+++ b/chromium/components/offline_pages/core/offline_page_model.h
@@ -44,15 +44,6 @@ struct ClientId;
// * how to cancel requests and what to expect
class OfflinePageModel : public base::SupportsUserData {
public:
- // Controls how to search on differnt URLs for pages.
- enum class URLSearchMode {
- // Match against the last committed URL only.
- SEARCH_BY_FINAL_URL_ONLY,
- // Match against all stored URLs, including the last committed URL and
- // the original request URL.
- SEARCH_BY_ALL_URLS
- };
-
// Describes the parameters to control how to save a page.
struct SavePageParams {
SavePageParams();
@@ -163,6 +154,11 @@ class OfflinePageModel : public base::SupportsUserData {
const std::vector<ClientId>& client_ids,
const MultipleOfflinePageItemCallback& callback) = 0;
+ // Retrieves all pages associated with the |request_origin|.
+ virtual void GetPagesByRequestOrigin(
+ const std::string& request_origin,
+ const MultipleOfflinePageItemCallback& callback) = 0;
+
// Deletes cached offline pages matching the URL predicate.
virtual void DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl.cc b/chromium/components/offline_pages/core/offline_page_model_impl.cc
index c6ee5cabb92..14525a26394 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_impl.cc
@@ -331,13 +331,12 @@ OfflinePageModelImpl::OfflinePageModelImpl()
OfflinePageModelImpl::OfflinePageModelImpl(
std::unique_ptr<OfflinePageMetadataStore> store,
- const base::FilePath& archives_dir,
+ std::unique_ptr<ArchiveManager> archive_manager,
const scoped_refptr<base::SequencedTaskRunner>& task_runner)
: store_(std::move(store)),
- archives_dir_(archives_dir),
is_loaded_(false),
policy_controller_(new ClientPolicyController()),
- archive_manager_(new ArchiveManager(archives_dir, task_runner)),
+ archive_manager_(std::move(archive_manager)),
testing_clock_(nullptr),
skip_clearing_original_url_for_testing_(false),
weak_ptr_factory_(this) {
@@ -389,7 +388,7 @@ void OfflinePageModelImpl::SavePage(
create_archive_params.use_page_problem_detectors =
save_page_params.use_page_problem_detectors;
archiver->CreateArchive(
- archives_dir_, create_archive_params,
+ archive_manager_->GetArchivesDir(), create_archive_params,
base::Bind(&OfflinePageModelImpl::OnCreateArchiveDone,
weak_ptr_factory_.GetWeakPtr(), save_page_params, offline_id,
GetCurrentTime(), callback));
@@ -532,6 +531,18 @@ void OfflinePageModelImpl::GetPagesByClientIds(
base::Passed(builder.Build(GetPolicyController())), callback));
}
+void OfflinePageModelImpl::GetPagesByRequestOrigin(
+ const std::string& request_origin,
+ const MultipleOfflinePageItemCallback& callback) {
+ OfflinePageModelQueryBuilder builder;
+ builder.SetRequestOrigin(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
+ request_origin);
+ RunWhenLoaded(
+ base::Bind(&OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(builder.Build(GetPolicyController())), callback));
+}
+
void OfflinePageModelImpl::DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) {
@@ -561,7 +572,9 @@ void OfflinePageModelImpl::CheckPagesExistOffline(
OfflinePageModelQueryBuilder builder;
builder
.SetUrls(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
- std::vector<GURL>(urls.begin(), urls.end()))
+ std::vector<GURL>(urls.begin(), urls.end()),
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+ false /* strip_fragment */)
.RequireRestrictedToOriginalTab(
OfflinePageModelQueryBuilder::Requirement::EXCLUDE_MATCHING);
auto pages_to_urls = base::Bind(
@@ -648,43 +661,14 @@ void OfflinePageModelImpl::GetPagesByURL(
const GURL& url,
URLSearchMode url_search_mode,
const MultipleOfflinePageItemCallback& callback) {
+ OfflinePageModelQueryBuilder builder;
+ builder.SetUrls(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING,
+ std::vector<GURL>({url}), url_search_mode,
+ true /* strip_fragment */);
RunWhenLoaded(
- base::Bind(&OfflinePageModelImpl::GetPagesByURLWhenLoadDone,
- weak_ptr_factory_.GetWeakPtr(), url,
- url_search_mode, callback));
-}
-
-void OfflinePageModelImpl::GetPagesByURLWhenLoadDone(
- const GURL& url,
- URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) const {
- DCHECK(is_loaded_);
- std::vector<OfflinePageItem> result;
-
- GURL::Replacements remove_params;
- remove_params.ClearRef();
-
- GURL url_without_fragment =
- url.ReplaceComponents(remove_params);
-
- for (const auto& id_page_pair : offline_pages_) {
- // First, search by last committed URL with fragment stripped.
- if (url_without_fragment ==
- id_page_pair.second.url.ReplaceComponents(remove_params)) {
- result.push_back(id_page_pair.second);
- continue;
- }
- // Then, search by original request URL if |url_search_mode| wants it.
- // Note that we want to do the exact match with fragment included. This is
- // because original URL is used for redirect purpose and it is always safer
- // to support the exact redirect.
- if (url_search_mode == URLSearchMode::SEARCH_BY_ALL_URLS &&
- url == id_page_pair.second.original_url) {
- result.push_back(id_page_pair.second);
- }
- }
-
- callback.Run(result);
+ base::Bind(&OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(builder.Build(GetPolicyController())), callback));
}
void OfflinePageModelImpl::CheckMetadataConsistency() {
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl.h b/chromium/components/offline_pages/core/offline_page_model_impl.h
index 8e4a7683252..11a38820693 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl.h
+++ b/chromium/components/offline_pages/core/offline_page_model_impl.h
@@ -57,7 +57,7 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// All blocking calls/disk access will happen on the provided |task_runner|.
OfflinePageModelImpl(
std::unique_ptr<OfflinePageMetadataStore> store,
- const base::FilePath& archives_dir,
+ std::unique_ptr<ArchiveManager> archive_manager,
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
~OfflinePageModelImpl() override;
@@ -83,6 +83,10 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
const std::vector<ClientId>& client_ids,
const MultipleOfflinePageItemCallback& callback) override;
+ void GetPagesByRequestOrigin(
+ const std::string& request_origin,
+ const MultipleOfflinePageItemCallback& callback) override;
+
void DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) override;
@@ -263,9 +267,6 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// Persistent store for offline page metadata.
std::unique_ptr<OfflinePageMetadataStore> store_;
- // Location where all of the archive files will be stored.
- base::FilePath archives_dir_;
-
// The observers.
base::ObserverList<Observer> observers_;
diff --git a/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc b/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
index 89b7432c2af..c5d11207922 100644
--- a/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_impl_unittest.cc
@@ -131,6 +131,8 @@ class OfflinePageModelImplTest
MultipleOfflinePageItemResult GetAllPages();
MultipleOfflinePageItemResult GetPagesByClientIds(
const std::vector<ClientId>& client_ids);
+ MultipleOfflinePageItemResult GetPagesByRequestOrigin(
+ const std::string& origin);
void DeletePagesByClientIds(const std::vector<ClientId>& client_ids);
// Saves the page without waiting for it to finish.
@@ -333,8 +335,10 @@ OfflinePageModelImplTest::BuildStore() {
std::unique_ptr<OfflinePageModelImpl> OfflinePageModelImplTest::BuildModel(
std::unique_ptr<OfflinePageMetadataStore> store) {
+ std::unique_ptr<ArchiveManager> archive_manager(new ArchiveManager(
+ temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get()));
return std::unique_ptr<OfflinePageModelImpl>(
- new OfflinePageModelImpl(std::move(store), temp_dir_.GetPath(),
+ new OfflinePageModelImpl(std::move(store), std::move(archive_manager),
base::ThreadTaskRunnerHandle::Get()));
}
@@ -457,6 +461,17 @@ MultipleOfflinePageItemResult OfflinePageModelImplTest::GetPagesByClientIds(
return result;
}
+MultipleOfflinePageItemResult OfflinePageModelImplTest::GetPagesByRequestOrigin(
+ const std::string& origin) {
+ MultipleOfflinePageItemResult result;
+ model()->GetPagesByRequestOrigin(
+ origin,
+ base::Bind(&OfflinePageModelImplTest::OnGetMultipleOfflinePageItemsResult,
+ AsWeakPtr(), base::Unretained(&result)));
+ PumpLoop();
+ return result;
+}
+
void OfflinePageModelImplTest::DeletePagesByClientIds(
const std::vector<ClientId>& client_ids) {
model()->DeletePagesByClientIds(
@@ -527,8 +542,7 @@ MultipleOfflinePageItemResult OfflinePageModelImplTest::GetPagesByFinalURL(
const GURL& url) {
MultipleOfflinePageItemResult result;
model()->GetPagesByURL(
- url,
- OfflinePageModel::URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+ url, URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
base::Bind(&OfflinePageModelImplTest::OnGetMultipleOfflinePageItemsResult,
AsWeakPtr(), base::Unretained(&result)));
PumpLoop();
@@ -539,8 +553,7 @@ MultipleOfflinePageItemResult OfflinePageModelImplTest::GetPagesByAllURLS(
const GURL& url) {
MultipleOfflinePageItemResult result;
model()->GetPagesByURL(
- url,
- OfflinePageModel::URLSearchMode::SEARCH_BY_ALL_URLS,
+ url, URLSearchMode::SEARCH_BY_ALL_URLS,
base::Bind(&OfflinePageModelImplTest::OnGetMultipleOfflinePageItemsResult,
AsWeakPtr(), base::Unretained(&result)));
PumpLoop();
@@ -698,8 +711,8 @@ TEST_F(OfflinePageModelImplTest, SavePageOfflineCreationStoreWriteFailure) {
TEST_F(OfflinePageModelImplTest, SavePageLocalFileFailed) {
// Don't create archiver since it will not be needed for pages that are not
// going to be saved.
- SavePageWithArchiver(
- kFileUrl, kTestClientId1, std::unique_ptr<OfflinePageTestArchiver>());
+ SavePageWithArchiver(kFileUrl, kTestClientId1,
+ std::unique_ptr<OfflinePageTestArchiver>());
EXPECT_EQ(SavePageResult::SKIPPED, last_save_result());
}
@@ -1069,8 +1082,8 @@ TEST_F(OfflinePageModelImplTest, DetectThatHeadlessPageIsDeleted) {
EXPECT_TRUE(base::PathExists(path));
// Since we've manually changed the store, we have to reload the model to
- // actually refresh the in-memory copy in model. Otherwise GetAllPages() would
- // still have the page we saved above.
+ // actually refresh the in-memory copy in model. Otherwise GetAllPages()
+ // would still have the page we saved above.
ResetModel();
PumpLoop();
@@ -1336,6 +1349,30 @@ TEST_F(OfflinePageModelImplTest, GetPagesByClientIds) {
EXPECT_EQ(kTestUrl2, item.url);
}
+TEST_F(OfflinePageModelImplTest, GetPagesByRequestOrigin) {
+ // We will save 3 pages.
+ std::string origin1("abc.xyz");
+ std::string origin2("abc");
+ std::pair<SavePageResult, int64_t> save_pages[3];
+ save_pages[0] = SavePage(kTestUrl, kTestClientId1, origin1);
+ save_pages[1] = SavePage(kTestUrl2, kTestClientId2, origin2);
+ save_pages[2] = SavePage(kTestUrl3, kTestClientId3, origin1);
+
+ for (const auto& save_result : save_pages) {
+ ASSERT_EQ(OfflinePageModel::SavePageResult::SUCCESS,
+ std::get<0>(save_result));
+ }
+
+ std::vector<OfflinePageItem> offline_pages = GetPagesByRequestOrigin(origin2);
+ EXPECT_EQ(1U, offline_pages.size());
+
+ const OfflinePageItem& item = offline_pages[0];
+ EXPECT_EQ(kTestUrl2, item.url);
+ EXPECT_EQ(origin2, item.request_origin);
+ EXPECT_EQ(kTestClientId2.name_space, item.client_id.name_space);
+ EXPECT_EQ(kTestClientId2.id, item.client_id.id);
+}
+
TEST_F(OfflinePageModelImplTest, DeletePagesByClientIds) {
// We will save 3 pages.
std::pair<SavePageResult, int64_t> saved_pages[3];
@@ -1404,8 +1441,8 @@ TEST_F(OfflinePageModelImplTest, StoreLoadFailurePersists) {
// Should record failure to load.
histograms().ExpectBucketCount("OfflinePages.Model.FinalLoadSuccessful",
false, 1);
- // Should show the previous count since no attempts are recorded for failure.
- // In case of failure, all attempts are assumed spent.
+ // Should show the previous count since no attempts are recorded for
+ // failure. In case of failure, all attempts are assumed spent.
histograms().ExpectUniqueSample("OfflinePages.Model.InitAttemptsSpent", 1, 1);
const std::vector<OfflinePageItem>& offline_pages = GetAllPages();
diff --git a/chromium/components/offline_pages/core/offline_page_model_query.cc b/chromium/components/offline_pages/core/offline_page_model_query.cc
index 382e20b7273..dd737adbe09 100644
--- a/chromium/components/offline_pages/core/offline_page_model_query.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_query.cc
@@ -11,8 +11,45 @@
namespace offline_pages {
+namespace {
+
+int CountMatchingUrls(const GURL& url_pattern,
+ const std::set<GURL>& urls,
+ bool strip_fragment) {
+ int count = 0;
+
+ // If |strip_fragment| is true, all urls will be compared after fragments
+ // stripped. Otherwise just do exact matching.
+ if (strip_fragment) {
+ for (const auto& url : urls) {
+ GURL::Replacements remove_params;
+ remove_params.ClearRef();
+ GURL url_without_fragment = url.ReplaceComponents(remove_params);
+ if (url_without_fragment == url_pattern.ReplaceComponents(remove_params))
+ count++;
+ }
+ } else {
+ count = urls.count(url_pattern);
+ }
+ return count;
+}
+
+} // namespace
+
using Requirement = OfflinePageModelQuery::Requirement;
+OfflinePageModelQuery::URLSearchParams::URLSearchParams() = default;
+
+OfflinePageModelQuery::URLSearchParams::URLSearchParams(
+ std::set<GURL> url_set,
+ URLSearchMode search_mode,
+ bool strip_frag)
+ : urls(url_set), mode(search_mode), strip_fragment(strip_frag) {}
+
+OfflinePageModelQuery::URLSearchParams::URLSearchParams(
+ const URLSearchParams& params) = default;
+OfflinePageModelQuery::URLSearchParams::~URLSearchParams() = default;
+
OfflinePageModelQueryBuilder::OfflinePageModelQueryBuilder()
: offline_ids_(std::make_pair(Requirement::UNSET, std::vector<int64_t>())) {
}
@@ -33,10 +70,22 @@ OfflinePageModelQueryBuilder& OfflinePageModelQueryBuilder::SetClientIds(
return *this;
}
+OfflinePageModelQueryBuilder& OfflinePageModelQueryBuilder::SetRequestOrigin(
+ Requirement requirement,
+ const std::string& request_origin) {
+ request_origin_ = std::make_pair(requirement, request_origin);
+ return *this;
+}
+
OfflinePageModelQueryBuilder& OfflinePageModelQueryBuilder::SetUrls(
Requirement requirement,
- const std::vector<GURL>& urls) {
- urls_ = std::make_pair(requirement, urls);
+ const std::vector<GURL>& urls,
+ URLSearchMode search_mode,
+ bool defrag) {
+ urls_ = std::make_pair(
+ requirement,
+ OfflinePageModelQuery::URLSearchParams(
+ std::set<GURL>(urls.begin(), urls.end()), search_mode, defrag));
return *this;
}
@@ -80,9 +129,11 @@ std::unique_ptr<OfflinePageModelQuery> OfflinePageModelQueryBuilder::Build(
auto query = base::MakeUnique<OfflinePageModelQuery>();
- query->urls_ = std::make_pair(
- urls_.first, std::set<GURL>(urls_.second.begin(), urls_.second.end()));
- urls_ = std::make_pair(Requirement::UNSET, std::vector<GURL>());
+ query->urls_ = urls_;
+ urls_ = std::make_pair(
+ Requirement::UNSET,
+ OfflinePageModelQuery::URLSearchParams(
+ std::set<GURL>(), URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, false));
query->offline_ids_ = std::make_pair(
offline_ids_.first, std::set<int64_t>(offline_ids_.second.begin(),
offline_ids_.second.end()));
@@ -92,6 +143,10 @@ std::unique_ptr<OfflinePageModelQuery> OfflinePageModelQueryBuilder::Build(
std::set<ClientId>(client_ids_.second.begin(), client_ids_.second.end()));
client_ids_ = std::make_pair(Requirement::UNSET, std::vector<ClientId>());
+ query->request_origin_ =
+ std::make_pair(request_origin_.first, request_origin_.second);
+ request_origin_ = std::make_pair(Requirement::UNSET, std::string());
+
std::vector<std::string> allowed_namespaces;
bool uses_namespace_restrictions = false;
@@ -176,14 +231,25 @@ OfflinePageModelQuery::GetRestrictedToClientIds() const {
return client_ids_;
}
-std::pair<Requirement, std::set<GURL>>
+std::pair<Requirement, OfflinePageModelQuery::URLSearchParams>
OfflinePageModelQuery::GetRestrictedToUrls() const {
- if (urls_.first == Requirement::UNSET)
- return std::make_pair(Requirement::UNSET, std::set<GURL>());
-
+ if (std::get<0>(urls_) == Requirement::UNSET) {
+ URLSearchParams unset_params;
+ unset_params.urls = std::set<GURL>();
+ unset_params.mode = URLSearchMode::SEARCH_BY_FINAL_URL_ONLY;
+ unset_params.strip_fragment = false;
+ return std::make_pair(Requirement::UNSET, unset_params);
+ }
return urls_;
}
+std::pair<Requirement, std::string> OfflinePageModelQuery::GetRequestOrigin()
+ const {
+ if (request_origin_.first == Requirement::UNSET)
+ return std::make_pair(Requirement::UNSET, std::string());
+ return request_origin_;
+}
+
bool OfflinePageModelQuery::Matches(const OfflinePageItem& item) const {
switch (offline_ids_.first) {
case Requirement::UNSET:
@@ -198,17 +264,17 @@ bool OfflinePageModelQuery::Matches(const OfflinePageItem& item) const {
break;
}
- switch (urls_.first) {
- case Requirement::UNSET:
- break;
- case Requirement::INCLUDE_MATCHING:
- if (urls_.second.count(item.url) == 0)
- return false;
- break;
- case Requirement::EXCLUDE_MATCHING:
- if (urls_.second.count(item.url) > 0)
- return false;
- break;
+ Requirement url_requirement = urls_.first;
+ URLSearchParams params = urls_.second;
+ if (url_requirement != Requirement::UNSET) {
+ int count = CountMatchingUrls(item.url, params.urls, params.strip_fragment);
+ if (params.mode == URLSearchMode::SEARCH_BY_ALL_URLS)
+ count += CountMatchingUrls(item.original_url, params.urls,
+ false /* strip_fragment */);
+ if ((url_requirement == Requirement::INCLUDE_MATCHING && count == 0) ||
+ (url_requirement == Requirement::EXCLUDE_MATCHING && count > 0)) {
+ return false;
+ }
}
const ClientId& client_id = item.client_id;
@@ -230,6 +296,19 @@ bool OfflinePageModelQuery::Matches(const OfflinePageItem& item) const {
break;
}
+ switch (request_origin_.first) {
+ case Requirement::UNSET:
+ break;
+ case Requirement::INCLUDE_MATCHING:
+ if (request_origin_.second != item.request_origin)
+ return false;
+ break;
+ case Requirement::EXCLUDE_MATCHING:
+ if (request_origin_.second == item.request_origin)
+ return false;
+ break;
+ }
+
return true;
}
diff --git a/chromium/components/offline_pages/core/offline_page_model_query.h b/chromium/components/offline_pages/core/offline_page_model_query.h
index 4107b39063e..b20ebb297d0 100644
--- a/chromium/components/offline_pages/core/offline_page_model_query.h
+++ b/chromium/components/offline_pages/core/offline_page_model_query.h
@@ -32,13 +32,34 @@ class OfflinePageModelQuery {
EXCLUDE_MATCHING,
};
+ struct URLSearchParams {
+ URLSearchParams();
+ URLSearchParams(const URLSearchParams& params);
+ URLSearchParams(std::set<GURL> url_set,
+ URLSearchMode search_mode,
+ bool strip_frag);
+ ~URLSearchParams();
+
+ // The set of urls for matching.
+ std::set<GURL> urls;
+ // The mode for searching. By final url only or both final and original
+ // urls.
+ URLSearchMode mode;
+ // Whether fragments should be stripped. It will *not* work on
+ // *|original_url|*.
+ // TODO(crbug.com/753609): Try to make this also available when matching for
+ // |original_url|.
+ bool strip_fragment;
+ };
+
OfflinePageModelQuery();
virtual ~OfflinePageModelQuery();
std::pair<bool, std::set<std::string>> GetRestrictedToNamespaces() const;
std::pair<Requirement, std::set<int64_t>> GetRestrictedToOfflineIds() const;
std::pair<Requirement, std::set<ClientId>> GetRestrictedToClientIds() const;
- std::pair<Requirement, std::set<GURL>> GetRestrictedToUrls() const;
+ std::pair<Requirement, URLSearchParams> GetRestrictedToUrls() const;
+ std::pair<Requirement, std::string> GetRequestOrigin() const;
// This is the workhorse function that is used by the in-memory offline page
// model, given a page it will find out whether that page matches the query.
@@ -51,7 +72,8 @@ class OfflinePageModelQuery {
std::pair<Requirement, std::set<int64_t>> offline_ids_;
std::pair<Requirement, std::set<ClientId>> client_ids_;
- std::pair<Requirement, std::set<GURL>> urls_;
+ std::pair<Requirement, URLSearchParams> urls_;
+ std::pair<Requirement, std::string> request_origin_;
DISALLOW_COPY_AND_ASSIGN(OfflinePageModelQuery);
};
@@ -80,10 +102,24 @@ class OfflinePageModelQueryBuilder {
OfflinePageModelQueryBuilder& SetClientIds(Requirement requirement,
const std::vector<ClientId>& ids);
+ // Sets the request origin that are valid for this request. If called
+ // multiple times, overwrites the previous request origin restrictions.
+ OfflinePageModelQueryBuilder& SetRequestOrigin(
+ Requirement requirement,
+ const std::string& request_origin);
+
// Sets the URLs that are valid for this request. If called multiple times,
// overwrites previous URL restrictions.
+ // |search_mode| is used to control if the URL will be matched with final
+ // URL only or both final URL and original URL.
+ // If |strip_fragment| is true, *only final* urls will be matched without
+ // fragment.
+ // TODO(crbug.com/753609): Try to unify fragment handling for original and
+ // final urls.
OfflinePageModelQueryBuilder& SetUrls(Requirement requirement,
- const std::vector<GURL>& urls);
+ const std::vector<GURL>& urls,
+ URLSearchMode search_mode,
+ bool strip_fragment);
// Only include pages whose namespaces satisfy
// ClientPolicyController::IsRemovedOnCacheReset(|namespace|) ==
@@ -131,7 +167,8 @@ class OfflinePageModelQueryBuilder {
std::pair<Requirement, std::vector<int64_t>> offline_ids_;
std::pair<Requirement, std::vector<ClientId>> client_ids_;
- std::pair<Requirement, std::vector<GURL>> urls_;
+ std::pair<Requirement, OfflinePageModelQuery::URLSearchParams> urls_;
+ std::pair<Requirement, std::string> request_origin_;
Requirement removed_on_cache_reset_ = Requirement::UNSET;
Requirement supported_by_download_ = Requirement::UNSET;
diff --git a/chromium/components/offline_pages/core/offline_page_model_query_unittest.cc b/chromium/components/offline_pages/core/offline_page_model_query_unittest.cc
index 01eb27b6a69..2e0145a6d8b 100644
--- a/chromium/components/offline_pages/core/offline_page_model_query_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_query_unittest.cc
@@ -14,6 +14,7 @@
namespace offline_pages {
using Requirement = OfflinePageModelQueryBuilder::Requirement;
+using URLSearchParams = OfflinePageModelQuery::URLSearchParams;
namespace {
@@ -26,6 +27,9 @@ const GURL kUrl2 = GURL("https://ktestitem2.com");
const OfflinePageItem kTestItem2(kUrl2, 2, kClientId2, base::FilePath(), 2);
const char kTestNamespace[] = "test_namespace";
+const GURL kTempUrl = GURL("https://temp.temp");
+const GURL kTempFragUrl = GURL("https://temp.temp#frag1");
+const GURL kFragUrl1 = GURL("https://ktestitem1.com#frag");
} // namespace
class OfflinePageModelQueryTest : public testing::Test {
@@ -60,6 +64,19 @@ class OfflinePageModelQueryTest : public testing::Test {
return OfflinePageItem(GURL("https://download.com"), 7,
{kLastNNamespace, "id1"}, base::FilePath(), 7);
}
+
+ const OfflinePageItem cct_page() {
+ OfflinePageItem page = kTestItem1;
+ page.request_origin = "[\"abc.xyz\",[\"12345\"]]";
+ return page;
+ }
+ const OfflinePageItem CreatePageWithUrls(const GURL& url,
+ const GURL& original_url) {
+ OfflinePageItem page = kTestItem1;
+ page.url = url;
+ page.original_url = original_url;
+ return page;
+ }
};
OfflinePageModelQueryTest::OfflinePageModelQueryTest() {
@@ -215,67 +232,85 @@ TEST_F(OfflinePageModelQueryTest, ClientIdsReplace) {
TEST_F(OfflinePageModelQueryTest, UrlsSet) {
std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
- builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls);
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, false);
std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
auto restriction = query->GetRestrictedToUrls();
const Requirement& requirement = restriction.first;
- const std::set<GURL>& urls_out = restriction.second;
+ const URLSearchParams& params = restriction.second;
EXPECT_EQ(Requirement::INCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, params.mode);
+ EXPECT_FALSE(params.strip_fragment);
- ASSERT_EQ(urls.size(), urls_out.size());
+ ASSERT_EQ(urls.size(), params.urls.size());
for (auto url : urls) {
- EXPECT_EQ(1U, urls_out.count(url)) << "Did not find " << url
- << "in query restrictions.";
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
}
EXPECT_TRUE(query->Matches(kTestItem1));
EXPECT_FALSE(query->Matches(kTestItem2));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kUrl1, kTempUrl)));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(GURL(""), GURL("https://abc.def"))));
}
TEST_F(OfflinePageModelQueryTest, UrlsSet_Exclude) {
std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
- builder_.SetUrls(Requirement::EXCLUDE_MATCHING, urls);
+ builder_.SetUrls(Requirement::EXCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, false);
std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
auto restriction = query->GetRestrictedToUrls();
const Requirement& requirement = restriction.first;
- const std::set<GURL>& urls_out = restriction.second;
+ const URLSearchParams& params = restriction.second;
EXPECT_EQ(Requirement::EXCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, params.mode);
+ EXPECT_FALSE(params.strip_fragment);
- ASSERT_EQ(urls.size(), urls_out.size());
+ ASSERT_EQ(urls.size(), params.urls.size());
for (auto url : urls) {
- EXPECT_EQ(1U, urls_out.count(url)) << "Did not find " << url
- << "in query restrictions.";
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
}
EXPECT_FALSE(query->Matches(kTestItem1));
EXPECT_TRUE(query->Matches(kTestItem2));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kUrl1, kTempUrl)));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(GURL(""), GURL("https://abc.def"))));
}
TEST_F(OfflinePageModelQueryTest, UrlsReplace) {
std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
std::vector<GURL> urls2 = {kUrl2, GURL("https://abc.def")};
- builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls);
- builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls2);
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, false);
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls2,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, false);
std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
auto restriction = query->GetRestrictedToUrls();
const Requirement& requirement = restriction.first;
- const std::set<GURL>& urls_out = restriction.second;
+ const URLSearchParams& params = restriction.second;
EXPECT_EQ(Requirement::INCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, params.mode);
+ EXPECT_FALSE(params.strip_fragment);
- ASSERT_EQ(urls2.size(), urls_out.size());
+ ASSERT_EQ(urls2.size(), params.urls.size());
for (auto url : urls2) {
- EXPECT_EQ(1U, urls_out.count(url)) << "Did not find " << url
- << "in query restrictions.";
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
}
EXPECT_FALSE(query->Matches(kTestItem1));
@@ -452,4 +487,256 @@ TEST_F(OfflinePageModelQueryTest, RequireNamespace) {
EXPECT_FALSE(query->Matches(test_namespace_page()));
}
+TEST_F(OfflinePageModelQueryTest, UrlsSet_SearchByAll) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_ALL_URLS, false);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::INCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_ALL_URLS, params.mode);
+ EXPECT_FALSE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_TRUE(query->Matches(kTestItem1));
+ EXPECT_FALSE(query->Matches(kTestItem2));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kUrl1, kTempUrl)));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(kUrl1, GURL("https://abc.def"))));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(kTempUrl, GURL("https://abc.def"))));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempUrl, GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, UrlsSet_Exclude_SearchByAll) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::EXCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_ALL_URLS, false);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::EXCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_ALL_URLS, params.mode);
+ EXPECT_FALSE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_FALSE(query->Matches(kTestItem1));
+ EXPECT_TRUE(query->Matches(kTestItem2));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kUrl1, kTempUrl)));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(kUrl1, GURL("https://abc.def"))));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(kTempUrl, GURL("https://abc.def"))));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempUrl, GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, UrlsSet_Defrag) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, true);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::INCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, params.mode);
+ EXPECT_TRUE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_TRUE(query->Matches(kTestItem1));
+ EXPECT_FALSE(query->Matches(kTestItem2));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kFragUrl1, kTempUrl)));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(kFragUrl1, GURL("https://abc.def"))));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(kTempUrl, GURL("https://abc.def"))));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_TRUE(query->Matches(
+ CreatePageWithUrls(GURL("https://abc.def#frag2"), GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, UrlsSet_Exclude_Defrag) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::EXCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, true);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::EXCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, params.mode);
+ EXPECT_TRUE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_FALSE(query->Matches(kTestItem1));
+ EXPECT_TRUE(query->Matches(kTestItem2));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kFragUrl1, kTempUrl)));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempUrl, kUrl1)));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(kFragUrl1, GURL("https://abc.def"))));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(kTempUrl, GURL("https://abc.def"))));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_FALSE(query->Matches(
+ CreatePageWithUrls(GURL("https://abc.def#frag2"), GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, UrlsSet_SearchByAll_Defrag) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::INCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_ALL_URLS, true);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::INCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_ALL_URLS, params.mode);
+ EXPECT_TRUE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_TRUE(query->Matches(kTestItem1));
+ EXPECT_FALSE(query->Matches(kTestItem2));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kFragUrl1, kTempUrl)));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempUrl, kFragUrl1)));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(kFragUrl1, GURL("https://abc.def"))));
+ EXPECT_FALSE(query->Matches(
+ CreatePageWithUrls(kTempUrl, GURL("https://abc.def#frag2"))));
+ EXPECT_TRUE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kTempFragUrl, GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, UrlsSet_Exclude_SearchByAll_Defrag) {
+ std::vector<GURL> urls = {kUrl1, GURL("https://abc.def")};
+ builder_.SetUrls(Requirement::EXCLUDE_MATCHING, urls,
+ URLSearchMode::SEARCH_BY_ALL_URLS, true);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+
+ auto restriction = query->GetRestrictedToUrls();
+ const Requirement& requirement = restriction.first;
+ const URLSearchParams& params = restriction.second;
+
+ EXPECT_EQ(Requirement::EXCLUDE_MATCHING, requirement);
+ EXPECT_EQ(URLSearchMode::SEARCH_BY_ALL_URLS, params.mode);
+ EXPECT_TRUE(params.strip_fragment);
+
+ ASSERT_EQ(urls.size(), params.urls.size());
+ for (auto url : urls) {
+ EXPECT_EQ(1U, params.urls.count(url))
+ << "Did not find " << url << "in query restrictions.";
+ }
+
+ EXPECT_FALSE(query->Matches(kTestItem1));
+ EXPECT_TRUE(query->Matches(kTestItem2));
+ EXPECT_FALSE(query->Matches(CreatePageWithUrls(kFragUrl1, kTempFragUrl)));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempUrl, kFragUrl1)));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(kUrl1, GURL("https://abc.def#frag2"))));
+ EXPECT_TRUE(query->Matches(
+ CreatePageWithUrls(kTempUrl, GURL("https://abc.def#frag2"))));
+ EXPECT_FALSE(
+ query->Matches(CreatePageWithUrls(GURL("https://abc.def"), GURL(""))));
+ EXPECT_TRUE(query->Matches(CreatePageWithUrls(kTempFragUrl, GURL(""))));
+}
+
+TEST_F(OfflinePageModelQueryTest, RequestOrigin_Exclude) {
+ builder_.SetRequestOrigin(Requirement::EXCLUDE_MATCHING, "");
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+ std::pair<Requirement, std::string> offline_origin_restriction =
+ query->GetRequestOrigin();
+ EXPECT_EQ(Requirement::EXCLUDE_MATCHING, offline_origin_restriction.first);
+
+ ASSERT_EQ("", offline_origin_restriction.second);
+
+ EXPECT_FALSE(query->Matches(kTestItem1));
+ EXPECT_TRUE(query->Matches(cct_page()));
+}
+
+TEST_F(OfflinePageModelQueryTest, RequestOrigin_Include) {
+ builder_.SetRequestOrigin(Requirement::INCLUDE_MATCHING, "");
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+ std::pair<Requirement, std::string> offline_origin_restriction =
+ query->GetRequestOrigin();
+ EXPECT_EQ(Requirement::INCLUDE_MATCHING, offline_origin_restriction.first);
+
+ ASSERT_EQ("", offline_origin_restriction.second);
+
+ EXPECT_TRUE(query->Matches(kTestItem1));
+ EXPECT_FALSE(query->Matches(cct_page()));
+}
+
+TEST_F(OfflinePageModelQueryTest, RequestOrigin_Replace) {
+ std::string origin1 = "";
+ std::string origin2 = "[\"abc.xyz\",[\"12345\"]]";
+
+ builder_.SetRequestOrigin(Requirement::INCLUDE_MATCHING, origin1);
+ builder_.SetRequestOrigin(Requirement::INCLUDE_MATCHING, origin2);
+
+ std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_);
+ std::pair<Requirement, std::string> offline_origin_restriction =
+ query->GetRequestOrigin();
+ EXPECT_EQ(Requirement::INCLUDE_MATCHING, offline_origin_restriction.first);
+
+ ASSERT_EQ(origin2, offline_origin_restriction.second);
+
+ EXPECT_FALSE(query->Matches(kTestItem1));
+ EXPECT_TRUE(query->Matches(cct_page()));
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_types.h b/chromium/components/offline_pages/core/offline_page_types.h
index 552b32a92d8..34dfc844f6d 100644
--- a/chromium/components/offline_pages/core/offline_page_types.h
+++ b/chromium/components/offline_pages/core/offline_page_types.h
@@ -72,6 +72,15 @@ enum class DeletePageResult {
RESULT_COUNT,
};
+// Controls how to search on differnt URLs for pages.
+enum class URLSearchMode {
+ // Match against the last committed URL only.
+ SEARCH_BY_FINAL_URL_ONLY,
+ // Match against all stored URLs, including the last committed URL and
+ // the original request URL.
+ SEARCH_BY_ALL_URLS,
+};
+
typedef std::set<GURL> CheckPagesExistOfflineResult;
typedef std::vector<int64_t> MultipleOfflineIdResult;
typedef std::vector<OfflinePageItem> MultipleOfflinePageItemResult;
diff --git a/chromium/components/offline_pages/core/offline_pages_ukm_reporter.cc b/chromium/components/offline_pages/core/offline_pages_ukm_reporter.cc
new file mode 100644
index 00000000000..e6e01bb86a5
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_pages_ukm_reporter.cc
@@ -0,0 +1,47 @@
+// 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/offline_pages/core/offline_pages_ukm_reporter.h"
+
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+const char OfflinePagesUkmReporter::kRequestUkmEventName[] =
+ "OfflinePages.SavePageRequested";
+const char OfflinePagesUkmReporter::kForegroundUkmMetricName[] =
+ "RequestedFromForeground";
+
+void OfflinePagesUkmReporter::ReportUrlOfflineRequest(const GURL& gurl,
+ bool foreground) {
+ ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+ if (ukm_recorder == nullptr)
+ return;
+
+ // This unique ID represents this whole navigation.
+ int32_t source_id = ukm::UkmRecorder::GetNewSourceID();
+
+ // Associate the URL with this navigation.
+ ukm_recorder->UpdateSourceURL(source_id, gurl);
+
+ // Tag this metric as an offline page request for the URL. This is a private
+ // member of UkmRecorder, so we need to be friends to use it.
+ // std::unique_ptr<ukm::UkmEntryBuilder> builder =
+ // ukm_recorder->GetEntryBuilder(
+ // source_id, OfflinePagesUkmReporter::kRequestUkmEventName);
+ // int metric_value = 0;
+ // if (foreground)
+ // metric_value = 1;
+ // builder->AddMetric(OfflinePagesUkmReporter::kForegroundUkmMetricName,
+ // metric_value);
+
+ // TODO: Change to the new way:
+ ukm::builders::OfflinePages_SavePageRequested(source_id)
+ .SetRequestedFromForeground(foreground ? 1 : 0)
+ .Record(ukm_recorder);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_pages_ukm_reporter.h b/chromium/components/offline_pages/core/offline_pages_ukm_reporter.h
new file mode 100644
index 00000000000..c644ebf947e
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_pages_ukm_reporter.h
@@ -0,0 +1,27 @@
+// 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_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
+
+class GURL;
+
+namespace offline_pages {
+
+// Interface for reporting that a URL has been offlined. The implementation
+// needs to be in BROWSER code, but the interface is used from COMPONENTS code.
+class OfflinePagesUkmReporter {
+ public:
+ static const char kRequestUkmEventName[];
+ static const char kForegroundUkmMetricName[];
+
+ virtual ~OfflinePagesUkmReporter() = default;
+
+ // Report that an offline copy has been made of this URL.
+ virtual void ReportUrlOfflineRequest(const GURL& gurl, bool foreground);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
diff --git a/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc
new file mode 100644
index 00000000000..deaadd3322a
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc
@@ -0,0 +1,18 @@
+// 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/offline_pages/core/offline_pages_ukm_reporter_stub.h"
+
+namespace offline_pages {
+
+OfflinePagesUkmReporterStub::OfflinePagesUkmReporterStub()
+ : foreground_(false) {}
+
+void OfflinePagesUkmReporterStub::ReportUrlOfflineRequest(const GURL& gurl,
+ bool foreground) {
+ gurl_ = gurl;
+ foreground_ = foreground;
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.h b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.h
new file mode 100644
index 00000000000..4debf09a12f
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_stub.h
@@ -0,0 +1,29 @@
+// 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_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
+
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+class OfflinePagesUkmReporterStub : public OfflinePagesUkmReporter {
+ public:
+ OfflinePagesUkmReporterStub();
+ ~OfflinePagesUkmReporterStub() override = default;
+ void ReportUrlOfflineRequest(const GURL& gurl, bool foreground) override;
+
+ const GURL& GetLastOfflinedUrl() const { return gurl_; }
+ bool GetForeground() const { return foreground_; }
+
+ private:
+ GURL gurl_;
+ bool foreground_;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
diff --git a/chromium/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc
new file mode 100644
index 00000000000..c494d3543cd
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc
@@ -0,0 +1,42 @@
+// 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/offline_pages/core/offline_pages_ukm_reporter.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kVisitedUrl[] = "http://m.en.wikipedia.org/wiki/Glider_(sailplane)";
+} // namespace
+
+namespace offline_pages {
+
+class OfflinePagesUkmReporterTest : public testing::Test {
+ public:
+ ukm::TestUkmRecorder* test_recorder() { return &test_recorder_; }
+
+ private:
+ ukm::TestAutoSetUkmRecorder test_recorder_;
+};
+
+TEST_F(OfflinePagesUkmReporterTest, RecordOfflinePageVisit) {
+ OfflinePagesUkmReporter reporter;
+ GURL gurl(kVisitedUrl);
+
+ reporter.ReportUrlOfflineRequest(gurl, false);
+
+ EXPECT_EQ(1U, test_recorder()->sources_count());
+ const ukm::UkmSource* found_source =
+ test_recorder()->GetSourceForUrl(kVisitedUrl);
+ EXPECT_NE(nullptr, found_source);
+
+ test_recorder()->ExpectMetric(
+ *found_source, ukm::builders::OfflinePages_SavePageRequested::kEntryName,
+ ukm::builders::OfflinePages_SavePageRequested::
+ kRequestedFromForegroundName,
+ 0);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_time_utils.cc b/chromium/components/offline_pages/core/offline_time_utils.cc
new file mode 100644
index 00000000000..71094b6156d
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_time_utils.cc
@@ -0,0 +1,19 @@
+// 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/offline_pages/core/offline_time_utils.h"
+
+#include "base/time/time.h"
+
+namespace offline_pages {
+
+int64_t ToDatabaseTime(base::Time time) {
+ return time.since_origin().InMicroseconds();
+}
+
+base::Time FromDatabaseTime(int64_t serialized_time) {
+ return base::Time() + base::TimeDelta::FromMicroseconds(serialized_time);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_time_utils.h b/chromium/components/offline_pages/core/offline_time_utils.h
new file mode 100644
index 00000000000..b2c94f0f2f0
--- /dev/null
+++ b/chromium/components/offline_pages/core/offline_time_utils.h
@@ -0,0 +1,25 @@
+// 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_OFFLINE_PAGES_CORE_OFFLINE_TIME_UTILS_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_TIME_UTILS_H_
+
+#include <stdint.h>
+
+namespace base {
+class Time;
+}
+
+namespace offline_pages {
+
+// Time conversion methods for the time format recommended for offline pages
+// projects for database storage: elapsed time in microseconds since the Windows
+// epoch. Not all offline pages projects adhere to this format for legacy
+// reasons.
+int64_t ToDatabaseTime(base::Time time);
+base::Time FromDatabaseTime(int64_t serialized_time);
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_TIME_UTILS_H_
diff --git a/chromium/components/offline_pages/core/prefetch/BUILD.gn b/chromium/components/offline_pages/core/prefetch/BUILD.gn
index 63ec7359b3f..d231fb456c5 100644
--- a/chromium/components/offline_pages/core/prefetch/BUILD.gn
+++ b/chromium/components/offline_pages/core/prefetch/BUILD.gn
@@ -11,6 +11,14 @@ static_library("prefetch") {
sources = [
"add_unique_urls_task.cc",
"add_unique_urls_task.h",
+ "download_archives_task.cc",
+ "download_archives_task.h",
+ "download_cleanup_task.cc",
+ "download_cleanup_task.h",
+ "download_completed_task.cc",
+ "download_completed_task.h",
+ "generate_page_bundle_reconcile_task.cc",
+ "generate_page_bundle_reconcile_task.h",
"generate_page_bundle_request.cc",
"generate_page_bundle_request.h",
"generate_page_bundle_task.cc",
@@ -19,18 +27,31 @@ static_library("prefetch") {
"get_operation_request.h",
"get_operation_task.cc",
"get_operation_task.h",
+ "import_archives_task.cc",
+ "import_archives_task.h",
+ "import_completed_task.cc",
+ "import_completed_task.h",
+ "mark_operation_done_task.cc",
+ "mark_operation_done_task.h",
+ "metrics_finalization_task.cc",
+ "metrics_finalization_task.h",
"offline_metrics_collector.h",
+ "page_bundle_update_task.cc",
+ "page_bundle_update_task.h",
+ "prefetch_background_task_handler.h",
+ "prefetch_configuration.cc",
+ "prefetch_configuration.h",
"prefetch_dispatcher.h",
"prefetch_dispatcher_impl.cc",
"prefetch_dispatcher_impl.h",
- "prefetch_downloader.cc",
"prefetch_downloader.h",
+ "prefetch_downloader_impl.cc",
+ "prefetch_downloader_impl.h",
"prefetch_gcm_app_handler.cc",
"prefetch_gcm_app_handler.h",
"prefetch_gcm_handler.h",
+ "prefetch_importer.cc",
"prefetch_importer.h",
- "prefetch_item.cc",
- "prefetch_item.h",
"prefetch_network_request_factory.h",
"prefetch_network_request_factory_impl.cc",
"prefetch_network_request_factory_impl.h",
@@ -45,6 +66,12 @@ static_library("prefetch") {
"prefetch_service_impl.h",
"prefetch_types.cc",
"prefetch_types.h",
+ "sent_get_operation_cleanup_task.cc",
+ "sent_get_operation_cleanup_task.h",
+ "stale_entry_finalizer_task.cc",
+ "stale_entry_finalizer_task.h",
+ "store/prefetch_downloader_quota.cc",
+ "store/prefetch_downloader_quota.h",
"store/prefetch_store.cc",
"store/prefetch_store.h",
"store/prefetch_store_utils.cc",
@@ -78,6 +105,10 @@ static_library("prefetch") {
static_library("test_support") {
testonly = true
sources = [
+ "mock_prefetch_item_generator.cc",
+ "mock_prefetch_item_generator.h",
+ "prefetch_item.cc",
+ "prefetch_item.h",
"prefetch_request_test_base.cc",
"prefetch_request_test_base.h",
"prefetch_service_test_taco.cc",
@@ -89,6 +120,8 @@ static_library("test_support") {
"test_offline_metrics_collector.h",
"test_prefetch_dispatcher.cc",
"test_prefetch_dispatcher.h",
+ "test_prefetch_downloader.cc",
+ "test_prefetch_downloader.h",
"test_prefetch_gcm_handler.cc",
"test_prefetch_gcm_handler.h",
"test_prefetch_importer.h",
@@ -99,6 +132,7 @@ static_library("test_support") {
deps = [
":prefetch",
"//base",
+ "//components/download/public",
"//components/gcm_driver/instance_id",
"//components/keyed_service/core",
"//components/offline_pages/core",
@@ -123,18 +157,30 @@ source_set("unit_tests") {
testonly = true
sources = [
"add_unique_urls_task_unittest.cc",
+ "download_archives_task_unittest.cc",
+ "download_cleanup_task_unittest.cc",
+ "download_completed_task_unittest.cc",
+ "generate_page_bundle_reconcile_task_unittest.cc",
"generate_page_bundle_request_unittest.cc",
"generate_page_bundle_task_unittest.cc",
"get_operation_request_unittest.cc",
"get_operation_task_unittest.cc",
+ "import_archives_task_unittest.cc",
+ "import_completed_task_unittest.cc",
+ "mark_operation_done_task_unittest.cc",
+ "metrics_finalization_task_unittest.cc",
+ "page_bundle_update_task_unittest.cc",
"prefetch_dispatcher_impl_unittest.cc",
- "prefetch_downloader_unittest.cc",
+ "prefetch_downloader_impl_unittest.cc",
"prefetch_gcm_app_handler_unittest.cc",
"prefetch_item_unittest.cc",
"prefetch_network_request_factory_impl_unittest.cc",
"prefetch_request_fetcher_unittest.cc",
"prefetch_request_operation_response_unittest.cc",
"prefetch_server_urls_unittest.cc",
+ "sent_get_operation_cleanup_task_unittest.cc",
+ "stale_entry_finalizer_task_unittest.cc",
+ "store/prefetch_downloader_quota_unittest.cc",
"store/prefetch_store_unittest.cc",
"suggested_articles_observer_unittest.cc",
]
@@ -143,6 +189,7 @@ source_set("unit_tests") {
":prefetch",
":test_support",
"//base",
+ "//components/download/internal/test:test_support",
"//components/download/public",
"//components/gcm_driver/instance_id",
"//components/offline_pages/core",
diff --git a/chromium/components/offline_pages/core/prefetch/DEPS b/chromium/components/offline_pages/core/prefetch/DEPS
index 98d9dd2c4b6..0232f6a3749 100644
--- a/chromium/components/offline_pages/core/prefetch/DEPS
+++ b/chromium/components/offline_pages/core/prefetch/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/download/internal/test",
"+components/download/public",
"+google_apis",
"+components/variations",
diff --git a/chromium/components/offline_pages/core/prefetch/README.md b/chromium/components/offline_pages/core/prefetch/README.md
index 1d6e9ca11c8..4279a3b8831 100644
--- a/chromium/components/offline_pages/core/prefetch/README.md
+++ b/chromium/components/offline_pages/core/prefetch/README.md
@@ -32,6 +32,9 @@ They implement TaskQueue's Task API so that they can be exclusively executed.
commands they require to do their work.
* Tasks receive a pointer to the store to be able to execute their SQL commands.
+More detailed instructions of how to use Prefetch store can be found [here](
+store/README.md)
+
## Development guidelines
* Implementations that are injected dependencies during service creation should
diff --git a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.cc b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.cc
index 732941c67a9..604471aee83 100644
--- a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.cc
+++ b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.cc
@@ -13,6 +13,8 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/time/time.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
@@ -51,18 +53,19 @@ bool CreatePrefetchItemSync(sql::Connection* db,
static const char kSql[] =
"INSERT INTO prefetch_items"
" (offline_id, requested_url, client_namespace, client_id, creation_time,"
- " freshness_time)"
+ " freshness_time, title)"
" VALUES"
- " (?, ?, ?, ?, ?, ?)";
+ " (?, ?, ?, ?, ?, ?, ?)";
- int64_t now_internal = base::Time::Now().ToInternalValue();
+ int64_t now_db_time = ToDatabaseTime(base::Time::Now());
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
- statement.BindInt64(0, GenerateOfflineId());
+ statement.BindInt64(0, PrefetchStoreUtils::GenerateOfflineId());
statement.BindString(1, prefetch_url.url.spec());
statement.BindString(2, name_space);
statement.BindString(3, prefetch_url.id);
- statement.BindInt64(4, now_internal);
- statement.BindInt64(5, now_internal);
+ statement.BindInt64(4, now_db_time);
+ statement.BindInt64(5, now_db_time);
+ statement.BindString16(6, prefetch_url.title);
return statement.Run();
}
@@ -104,8 +107,10 @@ AddUniqueUrlsTask::Result AddUrlsAndCleanupZombiesSync(
for (const auto& existing_item : existing_items) {
if (existing_item.second.second != PrefetchItemState::ZOMBIE)
continue;
- if (!DeletePrefetchItemByOfflineIdSync(db, existing_item.second.first))
+ if (!PrefetchStoreUtils::DeletePrefetchItemByOfflineIdSync(
+ db, existing_item.second.first)) {
return AddUniqueUrlsTask::Result::STORE_ERROR; // Transaction rollback.
+ }
}
if (!transaction.Commit())
@@ -116,13 +121,18 @@ AddUniqueUrlsTask::Result AddUrlsAndCleanupZombiesSync(
}
AddUniqueUrlsTask::AddUniqueUrlsTask(
+ PrefetchDispatcher* prefetch_dispatcher,
PrefetchStore* prefetch_store,
const std::string& name_space,
const std::vector<PrefetchURL>& prefetch_urls)
- : prefetch_store_(prefetch_store),
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
name_space_(name_space),
prefetch_urls_(prefetch_urls),
- weak_ptr_factory_(this) {}
+ weak_ptr_factory_(this) {
+ DCHECK(prefetch_dispatcher_);
+ DCHECK(prefetch_store_);
+}
AddUniqueUrlsTask::~AddUniqueUrlsTask() {}
@@ -134,11 +144,8 @@ void AddUniqueUrlsTask::Run() {
}
void AddUniqueUrlsTask::OnUrlsAdded(Result result) {
- if (result == Result::URLS_ADDED) {
- // TODO(carlosk): schedule NWake here if at least one new entry was added to
- // the store.
- NOTIMPLEMENTED();
- }
+ if (result == Result::URLS_ADDED)
+ prefetch_dispatcher_->EnsureTaskScheduled();
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.h b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.h
index b4009158236..39be78be37f 100644
--- a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.h
+++ b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task.h
@@ -13,6 +13,7 @@
#include "components/offline_pages/core/task.h"
namespace offline_pages {
+class PrefetchDispatcher;
class PrefetchStore;
struct PrefetchURL;
@@ -34,7 +35,8 @@ class AddUniqueUrlsTask : public Task {
STORE_ERROR,
};
- AddUniqueUrlsTask(PrefetchStore* prefetch_store,
+ AddUniqueUrlsTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
const std::string& name_space,
const std::vector<PrefetchURL>& prefetch_urls);
~AddUniqueUrlsTask() override;
@@ -44,9 +46,11 @@ class AddUniqueUrlsTask : public Task {
private:
void OnUrlsAdded(Result result);
+ // Dispatcher to call back to with results. Not owned.
+ PrefetchDispatcher* prefetch_dispatcher_;
// Prefetch store to execute against. Not owned.
PrefetchStore* prefetch_store_;
- const std::string& name_space_;
+ std::string name_space_;
std::vector<PrefetchURL> prefetch_urls_;
base::WeakPtrFactory<AddUniqueUrlsTask> weak_ptr_factory_;
diff --git a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
index 4a9c0437519..343ab5fe13e 100644
--- a/chromium/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
@@ -4,21 +4,36 @@
#include "components/offline_pages/core/prefetch/add_unique_urls_task.h"
+#include <map>
+#include <set>
#include <string>
#include <vector>
+#include "base/strings/utf_string_conversions.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace offline_pages {
namespace {
-void VerifyItemCount(int expected_count, int actual_count) {
- EXPECT_EQ(expected_count, actual_count);
-}
+const char kTestNamespace[] = "test";
+const char kClientId1[] = "ID-1";
+const char kClientId2[] = "ID-2";
+const char kClientId3[] = "ID-3";
+const char kClientId4[] = "ID-5";
+const GURL kTestURL1("https://www.google.com/");
+const GURL kTestURL2("http://www.example.com/");
+const GURL kTestURL3("https://news.google.com/");
+const GURL kTestURL4("https://chrome.google.com/");
+const base::string16 kTestTitle1 = base::ASCIIToUTF16("Title 1");
+const base::string16 kTestTitle2 = base::ASCIIToUTF16("Title 2");
+const base::string16 kTestTitle3 = base::ASCIIToUTF16("Title 3");
+const base::string16 kTestTitle4 = base::ASCIIToUTF16("Title 4");
} // namespace
class AddUniqueUrlsTaskTest : public testing::Test {
@@ -35,15 +50,22 @@ class AddUniqueUrlsTaskTest : public testing::Test {
void PumpLoop();
+ // Returns all items stored in a map keyed with client id.
+ std::map<std::string, PrefetchItem> GetAllItems();
+
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+
private:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
PrefetchStoreTestUtil store_test_util_;
+ TestPrefetchDispatcher dispatcher_;
};
AddUniqueUrlsTaskTest::AddUniqueUrlsTaskTest()
: task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_) {}
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
void AddUniqueUrlsTaskTest::SetUp() {
store_test_util_.BuildStoreInMemory();
@@ -58,72 +80,136 @@ void AddUniqueUrlsTaskTest::PumpLoop() {
task_runner_->RunUntilIdle();
}
+std::map<std::string, PrefetchItem> AddUniqueUrlsTaskTest::GetAllItems() {
+ std::set<PrefetchItem> set;
+ store_util()->GetAllItems(&set);
+
+ std::map<std::string, PrefetchItem> map;
+ for (const auto& item : set)
+ map[item.client_id.id] = item;
+ return map;
+}
+
TEST_F(AddUniqueUrlsTaskTest, AddTaskInEmptyStore) {
- std::string name_space("test");
std::vector<PrefetchURL> urls;
- urls.push_back(PrefetchURL{"ID-1", GURL("https://www.google.com/")});
- urls.push_back(PrefetchURL{"ID-2", GURL("http://www.example.com/")});
- AddUniqueUrlsTask task(store(), name_space, urls);
+ urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
+ urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
+ AddUniqueUrlsTask task(dispatcher(), store(), kTestNamespace, urls);
task.Run();
PumpLoop();
- store_util()->CountPrefetchItems(base::BindOnce(&VerifyItemCount, 2));
- PumpLoop();
+ std::map<std::string, PrefetchItem> items = GetAllItems();
+ ASSERT_EQ(2u, items.size());
+ ASSERT_TRUE(items.count(kClientId1) > 0);
+ EXPECT_EQ(kTestURL1, items[kClientId1].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId1].client_id.name_space);
+ EXPECT_EQ(kTestTitle1, items[kClientId1].title);
+ ASSERT_TRUE(items.count(kClientId2) > 0);
+ EXPECT_EQ(kTestURL2, items[kClientId2].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId2].client_id.name_space);
+ EXPECT_EQ(kTestTitle2, items[kClientId2].title);
+
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
}
-TEST_F(AddUniqueUrlsTaskTest, DontAddURLIfItExists) {
- std::string name_space("test");
+TEST_F(AddUniqueUrlsTaskTest, SingleDuplicateUrlNotAdded) {
std::vector<PrefetchURL> urls;
- urls.push_back(PrefetchURL{"ID-1", GURL("https://www.google.com/")});
- urls.push_back(PrefetchURL{"ID-2", GURL("http://www.example.com/")});
- AddUniqueUrlsTask task1(store(), name_space, urls);
+ urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
+ AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
task1.Run();
PumpLoop();
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
- urls.clear();
- urls.push_back(PrefetchURL{"ID-1", GURL("https://www.google.com/")});
- urls.push_back(PrefetchURL{"ID-3", GURL("https://news.google.com/")});
- AddUniqueUrlsTask task2(store(), name_space, urls);
+ // AddUniqueUrlsTask with no URLs should not increment task schedule count.
+ AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, {});
task2.Run();
PumpLoop();
+ // The task schedule count should not have changed with no new URLs.
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
- // Do the count here.
- store_util()->CountPrefetchItems(base::BindOnce(&VerifyItemCount, 3));
+ AddUniqueUrlsTask task3(dispatcher(), store(), kTestNamespace, urls);
+ task3.Run();
PumpLoop();
+ // The task schedule count should not have changed with no new URLs.
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
}
-TEST_F(AddUniqueUrlsTaskTest, HandleZombiePrefetchItems) {
- std::string name_space("test");
+TEST_F(AddUniqueUrlsTaskTest, DontAddURLIfItExists) {
std::vector<PrefetchURL> urls;
- urls.push_back(PrefetchURL{"ID-1", GURL("https://www.google.com/")});
- urls.push_back(PrefetchURL{"ID-2", GURL("http://www.example.com/")});
- urls.push_back(PrefetchURL{"ID-3", GURL("https://news.google.com/")});
- AddUniqueUrlsTask task1(store(), name_space, urls);
+ urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
+ urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
+ AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
task1.Run();
PumpLoop();
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
- store_util()->ZombifyPrefetchItem(name_space, urls[0].url,
- base::BindOnce(&VerifyItemCount, 1));
+ urls.clear();
+ // This PrefetchURL has a duplicate URL, should not be added.
+ urls.push_back(PrefetchURL{kClientId4, kTestURL1, kTestTitle4});
+ urls.push_back(PrefetchURL{kClientId3, kTestURL3, kTestTitle3});
+
+ AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, urls);
+ task2.Run();
PumpLoop();
- store_util()->ZombifyPrefetchItem(name_space, urls[1].url,
- base::BindOnce(&VerifyItemCount, 1));
+ EXPECT_EQ(2, dispatcher()->task_schedule_count);
+
+ std::map<std::string, PrefetchItem> items = GetAllItems();
+ ASSERT_EQ(3u, items.size());
+ ASSERT_TRUE(items.count(kClientId1) > 0);
+ EXPECT_EQ(kTestURL1, items[kClientId1].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId1].client_id.name_space);
+ EXPECT_EQ(kTestTitle1, items[kClientId1].title);
+ ASSERT_TRUE(items.count(kClientId2) > 0);
+ EXPECT_EQ(kTestURL2, items[kClientId2].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId2].client_id.name_space);
+ EXPECT_EQ(kTestTitle2, items[kClientId2].title);
+ ASSERT_TRUE(items.count(kClientId3) > 0);
+ EXPECT_EQ(kTestURL3, items[kClientId3].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId3].client_id.name_space);
+ EXPECT_EQ(kTestTitle3, items[kClientId3].title);
+}
+
+TEST_F(AddUniqueUrlsTaskTest, HandleZombiePrefetchItems) {
+ std::vector<PrefetchURL> urls;
+ urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
+ urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
+ urls.push_back(PrefetchURL{kClientId3, kTestURL3, kTestTitle3});
+ AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
+ task1.Run();
PumpLoop();
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
+
+ // ZombifyPrefetchItem returns the number of affected items.
+ EXPECT_EQ(1, store_util()->ZombifyPrefetchItems(kTestNamespace, urls[0].url));
+ EXPECT_EQ(1, store_util()->ZombifyPrefetchItems(kTestNamespace, urls[1].url));
urls.clear();
- urls.push_back(PrefetchURL{"ID-1", GURL("https://www.google.com/")});
- urls.push_back(PrefetchURL{"ID-3", GURL("https://news.google.com/")});
- urls.push_back(PrefetchURL{"ID-4", GURL("https://chrome.google.com/")});
+ urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
+ urls.push_back(PrefetchURL{kClientId3, kTestURL3, kTestTitle3});
+ urls.push_back(PrefetchURL{kClientId4, kTestURL4, kTestTitle4});
// ID-1 is expected to stay in zombie state.
// ID-2 is expected to be removed, because it is in zombie state.
// ID-3 is still requested, so it is ignored.
// ID-4 is added.
- AddUniqueUrlsTask task2(store(), name_space, urls);
+ AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, urls);
task2.Run();
PumpLoop();
-
- // Do the count here.
- store_util()->CountPrefetchItems(base::BindOnce(&VerifyItemCount, 3));
- PumpLoop();
+ EXPECT_EQ(2, dispatcher()->task_schedule_count);
+
+ std::map<std::string, PrefetchItem> items = GetAllItems();
+ ASSERT_EQ(3u, items.size());
+ ASSERT_TRUE(items.count(kClientId1) > 0);
+ EXPECT_EQ(kTestURL1, items[kClientId1].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId1].client_id.name_space);
+ EXPECT_EQ(kTestTitle1, items[kClientId1].title);
+ ASSERT_TRUE(items.count(kClientId3) > 0);
+ EXPECT_EQ(kTestURL3, items[kClientId3].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId3].client_id.name_space);
+ EXPECT_EQ(kTestTitle3, items[kClientId3].title);
+ ASSERT_TRUE(items.count(kClientId4) > 0);
+ EXPECT_EQ(kTestURL4, items[kClientId4].url);
+ EXPECT_EQ(kTestNamespace, items[kClientId4].client_id.name_space);
+ EXPECT_EQ(kTestTitle4, items[kClientId4].title);
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_archives_task.cc b/chromium/components/offline_pages/core/prefetch/download_archives_task.cc
new file mode 100644
index 00000000000..ec27ad85a69
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_archives_task.cc
@@ -0,0 +1,186 @@
+// 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/offline_pages/core/prefetch/download_archives_task.h"
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+namespace {
+
+struct ItemReadyForDownload {
+ int64_t offline_id;
+ std::string archive_body_name;
+ int64_t archive_body_length;
+};
+
+using ItemsReadyForDownload = std::vector<ItemReadyForDownload>;
+
+ItemsReadyForDownload FindItemsReadyForDownload(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT offline_id, archive_body_name, archive_body_length"
+ " FROM prefetch_items"
+ " WHERE state = ?"
+ " ORDER BY creation_time DESC";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::RECEIVED_BUNDLE));
+
+ ItemsReadyForDownload items_to_download;
+ while (statement.Step()) {
+ items_to_download.push_back({statement.ColumnInt64(0),
+ statement.ColumnString(1),
+ statement.ColumnInt64(2)});
+ }
+
+ return items_to_download;
+}
+
+std::unique_ptr<int> CountDownloadsInProgress(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT COUNT(offline_id) FROM prefetch_items WHERE state = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADING));
+ if (!statement.Step())
+ return nullptr;
+ return base::MakeUnique<int>(statement.ColumnInt(0));
+}
+
+bool MarkItemAsDownloading(sql::Connection* db,
+ int64_t offline_id,
+ const std::string& guid) {
+ // Code below only changes freshness time once, when the archive download is
+ // attempted for the first time. We don't want to perpetuate the lifetime of
+ // the item longer than that, if we keep on retrying it.
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?,"
+ " guid = ?,"
+ " freshness_time = CASE WHEN download_initiation_attempts = 0 THEN ?"
+ " ELSE freshness_time END,"
+ " download_initiation_attempts = download_initiation_attempts + 1"
+ " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADING));
+ statement.BindString(1, guid);
+ statement.BindInt64(2, ToDatabaseTime(base::Time::Now()));
+ statement.BindInt64(3, offline_id);
+ return statement.Run();
+}
+
+std::unique_ptr<DownloadArchivesTask::ItemsToDownload>
+SelectAndMarkItemsForDownloadSync(sql::Connection* db) {
+ if (!db)
+ return nullptr;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return nullptr;
+
+ // Get current count of concurrent downloads and bail early if we are already
+ // downloading more than we can.
+ std::unique_ptr<int> concurrent_downloads(CountDownloadsInProgress(db));
+ if (!concurrent_downloads ||
+ *concurrent_downloads >= DownloadArchivesTask::kMaxConcurrentDownloads) {
+ return nullptr;
+ }
+
+ // TODO(fgorski): Move the ownership of the clock up to prefetch dispatcher or
+ // a similar object.
+ // Code below is fine for now, because both objects are destroyed at the end
+ // of the method. Clock inside of |PrefetchDownloaderQuota| has to be
+ // controlled from the outside, therefore is passed by a pointer.
+ base::DefaultClock clock;
+ PrefetchDownloaderQuota downloader_quota(db, &clock);
+ int64_t available_quota = downloader_quota.GetAvailableQuotaBytes();
+ if (available_quota <= 0)
+ return nullptr;
+
+ ItemsReadyForDownload ready_items = FindItemsReadyForDownload(db);
+ if (ready_items.empty())
+ return nullptr;
+
+ // Below implementation is a greedy algorithm that selects the next item we
+ // can download without quota violation and maximum concurrent downloads
+ // violation, as ordered by the |FindItemsReadyForDownload| function.
+ auto items_to_download =
+ base::MakeUnique<DownloadArchivesTask::ItemsToDownload>();
+ for (const auto& ready_item : ready_items) {
+ // Concurrent downloads check.
+ if (*concurrent_downloads >= DownloadArchivesTask::kMaxConcurrentDownloads)
+ break;
+
+ // Quota check. Skips all items that violate quota.
+ if (ready_item.archive_body_length > available_quota)
+ continue;
+ available_quota -= ready_item.archive_body_length;
+
+ // Explicitly not reusing the GUID from the last archive download attempt
+ // here.
+ std::string guid = base::GenerateGUID();
+ if (!MarkItemAsDownloading(db, ready_item.offline_id, guid))
+ return nullptr;
+ items_to_download->push_back({guid, ready_item.archive_body_name});
+ ++(*concurrent_downloads);
+ }
+
+ // Write new remaining quota with date here.
+ if (!downloader_quota.SetAvailableQuotaBytes(available_quota))
+ return nullptr;
+
+ if (!transaction.Commit())
+ return nullptr;
+
+ return items_to_download;
+}
+
+} // namespace
+
+// static
+const int DownloadArchivesTask::kMaxConcurrentDownloads = 2;
+
+DownloadArchivesTask::DownloadArchivesTask(
+ PrefetchStore* prefetch_store,
+ PrefetchDownloader* prefetch_downloader)
+ : prefetch_store_(prefetch_store),
+ prefetch_downloader_(prefetch_downloader),
+ weak_ptr_factory_(this) {
+ DCHECK(prefetch_store_);
+ DCHECK(prefetch_downloader_);
+}
+
+DownloadArchivesTask::~DownloadArchivesTask() = default;
+
+void DownloadArchivesTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(SelectAndMarkItemsForDownloadSync),
+ base::BindOnce(&DownloadArchivesTask::SendItemsToPrefetchDownloader,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DownloadArchivesTask::SendItemsToPrefetchDownloader(
+ std::unique_ptr<ItemsToDownload> items_to_download) {
+ if (items_to_download) {
+ for (const auto& download_item : *items_to_download) {
+ prefetch_downloader_->StartDownload(download_item.guid,
+ download_item.archive_body_name);
+ }
+ }
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_archives_task.h b/chromium/components/offline_pages/core/prefetch/download_archives_task.h
new file mode 100644
index 00000000000..4f15535e4fc
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_archives_task.h
@@ -0,0 +1,59 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_ARCHIVES_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_ARCHIVES_TASK_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDownloader;
+class PrefetchStore;
+
+// Task that starts a download of archives for tasks that already received the
+// bundle information.
+class DownloadArchivesTask : public Task {
+ public:
+ // Maximum number of parallel downloads.
+ static const int kMaxConcurrentDownloads;
+
+ // Represents item to be downloaded as a result of running the task.
+ struct DownloadItem {
+ std::string guid;
+ std::string archive_body_name;
+ };
+
+ // Result of lookup of items ready to be downloaded. First element of the pair
+ // is offline ID, second is archive body name.
+ using ItemsToDownload = std::vector<DownloadItem>;
+
+ DownloadArchivesTask(PrefetchStore* prefetch_store,
+ PrefetchDownloader* prefetch_downloader);
+ ~DownloadArchivesTask() override;
+
+ void Run() override;
+
+ private:
+ void SendItemsToPrefetchDownloader(
+ std::unique_ptr<ItemsToDownload> items_to_download);
+
+ // Prefetch store to execute against. Not owned.
+ PrefetchStore* prefetch_store_;
+ // Prefetch downloader to request downloads from. Not owned.
+ PrefetchDownloader* prefetch_downloader_;
+
+ base::WeakPtrFactory<DownloadArchivesTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadArchivesTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_ARCHIVES_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/download_archives_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/download_archives_task_unittest.cc
new file mode 100644
index 00000000000..5a039d26459
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_archives_task_unittest.cc
@@ -0,0 +1,323 @@
+// 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/offline_pages/core/prefetch/download_archives_task.h"
+
+#include <algorithm>
+#include <set>
+
+#include "base/guid.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_downloader.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+
+const int64_t kSmallArchiveSize = 1LL * 1024 * 1024;
+const int64_t kLargeArchiveSize =
+ 2 * PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 3;
+
+const PrefetchItem* FindPrefetchItemByOfflineId(
+ const std::set<PrefetchItem>& items,
+ int64_t offline_id) {
+ auto found_it = std::find_if(items.begin(), items.end(),
+ [&offline_id](const PrefetchItem& i) -> bool {
+ return i.offline_id == offline_id;
+ });
+ if (found_it != items.end())
+ return &(*found_it);
+ return nullptr;
+}
+
+class DownloadArchivesTaskTest : public TaskTestBase {
+ public:
+ TestPrefetchDownloader* prefetch_downloader() {
+ return &test_prefetch_downloader_;
+ }
+
+ int64_t InsertDummyItem();
+ void InsertDummyItemInState(PrefetchItemState state);
+ int64_t InsertItemToDownload(int64_t archive_size);
+
+ private:
+ TestPrefetchDownloader test_prefetch_downloader_;
+};
+
+int64_t DownloadArchivesTaskTest::InsertDummyItem() {
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ store_util()->InsertPrefetchItem(item);
+ return item.offline_id;
+}
+
+void DownloadArchivesTaskTest::InsertDummyItemInState(PrefetchItemState state) {
+ store_util()->InsertPrefetchItem(item_generator()->CreateItem(state));
+}
+
+int64_t DownloadArchivesTaskTest::InsertItemToDownload(int64_t archive_size) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+ item.archive_body_length = archive_size;
+ store_util()->InsertPrefetchItem(item);
+ return item.offline_id;
+}
+
+TEST_F(DownloadArchivesTaskTest, NoArchivesToDownload) {
+ InsertDummyItemInState(PrefetchItemState::NEW_REQUEST);
+ InsertDummyItemInState(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ InsertDummyItemInState(PrefetchItemState::AWAITING_GCM);
+ InsertDummyItemInState(PrefetchItemState::RECEIVED_GCM);
+ InsertDummyItemInState(PrefetchItemState::SENT_GET_OPERATION);
+ InsertDummyItemInState(PrefetchItemState::DOWNLOADING);
+ InsertDummyItemInState(PrefetchItemState::DOWNLOADED);
+ InsertDummyItemInState(PrefetchItemState::IMPORTING);
+ InsertDummyItemInState(PrefetchItemState::FINISHED);
+ InsertDummyItemInState(PrefetchItemState::ZOMBIE);
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&items_after_run));
+
+ EXPECT_EQ(items_before_run, items_after_run);
+}
+
+TEST_F(DownloadArchivesTaskTest, SingleArchiveToDownload) {
+ int64_t dummy_item_id = InsertDummyItem();
+ int64_t download_item_id = InsertItemToDownload(kLargeArchiveSize);
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(2U, store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(2U, store_util()->GetAllItems(&items_after_run));
+
+ const PrefetchItem* dummy_item_before =
+ FindPrefetchItemByOfflineId(items_before_run, dummy_item_id);
+ const PrefetchItem* dummy_item_after =
+ FindPrefetchItemByOfflineId(items_after_run, dummy_item_id);
+ ASSERT_TRUE(dummy_item_before);
+ ASSERT_TRUE(dummy_item_after);
+ EXPECT_EQ(*dummy_item_before, *dummy_item_after);
+
+ const PrefetchItem* download_item_before =
+ FindPrefetchItemByOfflineId(items_before_run, download_item_id);
+ EXPECT_EQ(0, download_item_before->download_initiation_attempts);
+
+ const PrefetchItem* download_item =
+ FindPrefetchItemByOfflineId(items_after_run, download_item_id);
+ ASSERT_TRUE(download_item);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item->state);
+ EXPECT_EQ(1, download_item->download_initiation_attempts);
+ // These times are created using base::Time::Now() in short distance from each
+ // other, therefore putting *_LE was considered too.
+ EXPECT_LT(download_item_before->freshness_time,
+ download_item->freshness_time);
+
+ std::map<std::string, std::string> requested_downloads =
+ prefetch_downloader()->requested_downloads();
+ auto it = requested_downloads.find(download_item->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item->archive_body_name);
+}
+
+TEST_F(DownloadArchivesTaskTest, MultipleArchivesToDownload) {
+ int64_t dummy_item_id = InsertDummyItem();
+ int64_t download_item_id_1 = InsertItemToDownload(kSmallArchiveSize);
+ int64_t download_item_id_2 = InsertItemToDownload(kSmallArchiveSize);
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(3U, store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(3U, store_util()->GetAllItems(&items_after_run));
+
+ const PrefetchItem* dummy_item_before =
+ FindPrefetchItemByOfflineId(items_before_run, dummy_item_id);
+ const PrefetchItem* dummy_item_after =
+ FindPrefetchItemByOfflineId(items_after_run, dummy_item_id);
+ ASSERT_TRUE(dummy_item_before);
+ ASSERT_TRUE(dummy_item_after);
+ EXPECT_EQ(*dummy_item_before, *dummy_item_after);
+
+ const PrefetchItem* download_item_1 =
+ FindPrefetchItemByOfflineId(items_after_run, download_item_id_1);
+ ASSERT_TRUE(download_item_1);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item_1->state);
+
+ const PrefetchItem* download_item_2 =
+ FindPrefetchItemByOfflineId(items_after_run, download_item_id_2);
+ ASSERT_TRUE(download_item_2);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item_2->state);
+
+ std::map<std::string, std::string> requested_downloads =
+ prefetch_downloader()->requested_downloads();
+ EXPECT_EQ(2U, requested_downloads.size());
+
+ auto it = requested_downloads.find(download_item_1->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item_1->archive_body_name);
+
+ it = requested_downloads.find(download_item_2->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item_2->archive_body_name);
+}
+
+TEST_F(DownloadArchivesTaskTest, MultipleLargeArchivesToDownload) {
+ int64_t dummy_item_id = InsertDummyItem();
+ // download_item_1 is expected to be fresher, therefore we create it second.
+ int64_t download_item_id_2 = InsertItemToDownload(kLargeArchiveSize);
+ int64_t download_item_id_1 = InsertItemToDownload(kLargeArchiveSize);
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(3U, store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(3U, store_util()->GetAllItems(&items_after_run));
+
+ const PrefetchItem* dummy_item_before =
+ FindPrefetchItemByOfflineId(items_before_run, dummy_item_id);
+ const PrefetchItem* dummy_item_after =
+ FindPrefetchItemByOfflineId(items_after_run, dummy_item_id);
+ ASSERT_TRUE(dummy_item_before);
+ ASSERT_TRUE(dummy_item_after);
+ EXPECT_EQ(*dummy_item_before, *dummy_item_after);
+
+ const PrefetchItem* download_item_1 =
+ FindPrefetchItemByOfflineId(items_after_run, download_item_id_1);
+ ASSERT_TRUE(download_item_1);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item_1->state);
+
+ const PrefetchItem* download_item_2 =
+ FindPrefetchItemByOfflineId(items_after_run, download_item_id_2);
+ ASSERT_TRUE(download_item_2);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE, download_item_2->state);
+
+ std::map<std::string, std::string> requested_downloads =
+ prefetch_downloader()->requested_downloads();
+ EXPECT_EQ(1U, requested_downloads.size());
+
+ auto it = requested_downloads.find(download_item_1->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item_1->archive_body_name);
+}
+
+TEST_F(DownloadArchivesTaskTest, TooManyArchivesToDownload) {
+ // Create multiple archives.
+ std::vector<int64_t> item_ids;
+ const int total_items = DownloadArchivesTask::kMaxConcurrentDownloads + 2;
+ // Create more than we allow to download in parallel and put then in the
+ // |item_ids| in front.
+ for (int i = 0; i < total_items; ++i)
+ item_ids.insert(item_ids.begin(), InsertItemToDownload(kSmallArchiveSize));
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(static_cast<size_t>(total_items),
+ store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(static_cast<size_t>(total_items),
+ store_util()->GetAllItems(&items_after_run));
+
+ std::map<std::string, std::string> requested_downloads =
+ prefetch_downloader()->requested_downloads();
+ EXPECT_EQ(static_cast<size_t>(DownloadArchivesTask::kMaxConcurrentDownloads),
+ requested_downloads.size());
+
+ // First |kMaxConcurrentDownloads| should be started.
+ for (int i = 0; i < DownloadArchivesTask::kMaxConcurrentDownloads; ++i) {
+ const PrefetchItem* download_item =
+ FindPrefetchItemByOfflineId(items_after_run, item_ids[i]);
+ ASSERT_TRUE(download_item);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item->state);
+
+ auto it = requested_downloads.find(download_item->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item->archive_body_name);
+ }
+
+ // Remaining items shouldn't have been started.
+ for (int i = DownloadArchivesTask::kMaxConcurrentDownloads; i < total_items;
+ ++i) {
+ const PrefetchItem* download_item_before =
+ FindPrefetchItemByOfflineId(items_before_run, item_ids[i]);
+ const PrefetchItem* download_item_after =
+ FindPrefetchItemByOfflineId(items_before_run, item_ids[i]);
+ ASSERT_TRUE(download_item_before);
+ ASSERT_TRUE(download_item_after);
+ EXPECT_EQ(*download_item_before, *download_item_before);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE, download_item_after->state);
+ }
+}
+
+TEST_F(DownloadArchivesTaskTest, SingleArchiveSecondAttempt) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+ item.download_initiation_attempts = 1;
+ item.freshness_time = base::Time::Now();
+ item.guid = base::GenerateGUID();
+ store_util()->InsertPrefetchItem(item);
+
+ std::set<PrefetchItem> items_before_run;
+ EXPECT_EQ(1U, store_util()->GetAllItems(&items_before_run));
+
+ DownloadArchivesTask task(store(), prefetch_downloader());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> items_after_run;
+ EXPECT_EQ(1U, store_util()->GetAllItems(&items_after_run));
+
+ const PrefetchItem* download_item =
+ FindPrefetchItemByOfflineId(items_after_run, item.offline_id);
+ ASSERT_TRUE(download_item);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, download_item->state);
+ EXPECT_EQ(2, download_item->download_initiation_attempts);
+ EXPECT_EQ(item.archive_body_name, download_item->archive_body_name);
+ // GUID expected to change between download attempts.
+ EXPECT_NE(item.guid, download_item->guid);
+ // Freshness time not expected to change after first attempt.
+ EXPECT_EQ(item.freshness_time, download_item->freshness_time);
+
+ std::map<std::string, std::string> requested_downloads =
+ prefetch_downloader()->requested_downloads();
+ auto it = requested_downloads.find(download_item->guid);
+ ASSERT_TRUE(it != requested_downloads.end());
+ EXPECT_EQ(it->second, download_item->archive_body_name);
+}
+
+} // namespace
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_cleanup_task.cc b/chromium/components/offline_pages/core/prefetch/download_cleanup_task.cc
new file mode 100644
index 00000000000..55a7656a8e8
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_cleanup_task.cc
@@ -0,0 +1,176 @@
+// 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/offline_pages/core/prefetch/download_cleanup_task.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+namespace {
+
+struct DownloadInfo {
+ int64_t offline_id;
+ std::string guid;
+};
+
+std::vector<DownloadInfo> GetAllOutstandingDownloadsSync(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT offline_id, guid"
+ " FROM prefetch_items"
+ " WHERE state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADING));
+
+ std::vector<DownloadInfo> downloads;
+ while (statement.Step())
+ downloads.push_back({statement.ColumnInt64(0), statement.ColumnString(1)});
+ return downloads;
+}
+
+bool RetryOrExpireDownloadSync(int64_t offline_id,
+ int max_attempts,
+ sql::Connection* db) {
+ // For all items in DOWNLOADING state:
+ // * transit to RECEIVED_BUNDLE state if not exceeding maximum attempts
+ // * transit to FINISHED state with error_code set otherwise.
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = CASE WHEN download_initiation_attempts < ? THEN ?"
+ " ELSE ? END,"
+ " error_code = CASE WHEN download_initiation_attempts < ? "
+ " THEN error_code ELSE ? END"
+ " WHERE offline_id = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, max_attempts);
+ statement.BindInt(1, static_cast<int>(PrefetchItemState::RECEIVED_BUNDLE));
+ statement.BindInt(2, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(3, max_attempts);
+ statement.BindInt(
+ 4,
+ static_cast<int>(PrefetchItemErrorCode::DOWNLOAD_MAX_ATTEMPTS_REACHED));
+ statement.BindInt64(5, offline_id);
+
+ return statement.Run();
+}
+
+bool MarkDownloadAsCompletedSync(int64_t offline_id,
+ const base::FilePath& file_path,
+ int64_t file_size,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?, file_path = ?, file_size = ?"
+ " WHERE offline_id = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADED));
+ statement.BindString(1, file_path.AsUTF8Unsafe());
+ statement.BindInt64(2, file_size);
+ statement.BindInt64(3, offline_id);
+
+ return statement.Run();
+}
+
+bool CleanupDownloadsSync(
+ int max_attempts,
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads,
+ sql::Connection* db) {
+ if (!db)
+ return false;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+
+ std::vector<DownloadInfo> outstanding_prefetch_downloads =
+ GetAllOutstandingDownloadsSync(db);
+ if (outstanding_prefetch_downloads.empty())
+ return true;
+
+ for (const auto& outstanding_prefetch_download :
+ outstanding_prefetch_downloads) {
+ std::string outstanding_prefetch_download_id =
+ outstanding_prefetch_download.guid;
+
+ // If the outstanding prefetch download has already completed successfully
+ // per the download system, mark it as download completed.
+ const auto& success_download_iter =
+ success_downloads.find(outstanding_prefetch_download_id);
+ if (success_download_iter != success_downloads.end()) {
+ if (!MarkDownloadAsCompletedSync(
+ outstanding_prefetch_download.offline_id,
+ success_download_iter->second.first, // file path
+ success_download_iter->second.second, // file size
+ db)) {
+ return false;
+ }
+ continue;
+ }
+
+ // If the download is in progress, no change.
+ if (outstanding_download_ids.find(outstanding_prefetch_download_id) !=
+ outstanding_download_ids.end()) {
+ continue;
+ }
+
+ // Otherwise, update the state to either retry the opeation or error out.
+ if (!RetryOrExpireDownloadSync(outstanding_prefetch_download.offline_id,
+ max_attempts, db)) {
+ return false;
+ }
+ }
+
+ return transaction.Commit();
+}
+
+} // namespace
+
+// static
+const int DownloadCleanupTask::kMaxDownloadAttempts = 3;
+
+DownloadCleanupTask::DownloadCleanupTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads)
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
+ outstanding_download_ids_(outstanding_download_ids),
+ success_downloads_(success_downloads),
+ weak_ptr_factory_(this) {}
+
+DownloadCleanupTask::~DownloadCleanupTask() {}
+
+void DownloadCleanupTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&CleanupDownloadsSync, kMaxDownloadAttempts,
+ outstanding_download_ids_, success_downloads_),
+ base::BindOnce(&DownloadCleanupTask::OnFinished,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DownloadCleanupTask::OnFinished(bool success) {
+ if (success)
+ prefetch_dispatcher_->SchedulePipelineProcessing();
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_cleanup_task.h b/chromium/components/offline_pages/core/prefetch/download_cleanup_task.h
new file mode 100644
index 00000000000..9e178d514e5
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_cleanup_task.h
@@ -0,0 +1,55 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_CLEANUP_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_CLEANUP_TASK_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Reconciliation task for cleaning up database entries that are in DOWNLOADING
+// state. This is indeed triggered only when the download service is ready and
+// notifies us about the ongoing and completed downloads.
+class DownloadCleanupTask : public Task {
+ public:
+ // Maximum number of attempts to retry a download.
+ static const int kMaxDownloadAttempts;
+
+ DownloadCleanupTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads);
+ ~DownloadCleanupTask() override;
+
+ void Run() override;
+
+ private:
+ void OnFinished(bool success);
+
+ PrefetchDispatcher* prefetch_dispatcher_; // Outlives this class.
+ PrefetchStore* prefetch_store_; // Outlives this class.
+ std::set<std::string> outstanding_download_ids_;
+ std::map<std::string, std::pair<base::FilePath, int64_t>> success_downloads_;
+
+ base::WeakPtrFactory<DownloadCleanupTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadCleanupTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_CLEANUP_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc
new file mode 100644
index 00000000000..bfb22d2b360
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc
@@ -0,0 +1,154 @@
+// 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/offline_pages/core/prefetch/download_cleanup_task.h"
+
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
+const int64_t kTestFileSize = 88888;
+} // namespace
+
+class DownloadCleanupTaskTest : public TaskTestBase {
+ public:
+ DownloadCleanupTaskTest() = default;
+ ~DownloadCleanupTaskTest() override = default;
+
+ void CreateAndRunDownloadCleanupTask(
+ const std::string& outstanding_download_id,
+ const std::string& success_download_id) {
+ std::set<std::string> outstanding_download_ids;
+ if (!outstanding_download_id.empty())
+ outstanding_download_ids.emplace(outstanding_download_id);
+
+ std::map<std::string, std::pair<base::FilePath, int64_t>> success_downloads;
+ if (!success_download_id.empty()) {
+ success_downloads.emplace(success_download_id,
+ std::make_pair(kTestFilePath, kTestFileSize));
+ }
+
+ DownloadCleanupTask task(&dispatcher_, store(), outstanding_download_ids,
+ success_downloads);
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ }
+
+ private:
+ TestPrefetchDispatcher dispatcher_;
+};
+
+TEST_F(DownloadCleanupTaskTest, Retry) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+ item.download_initiation_attempts =
+ DownloadCleanupTask::kMaxDownloadAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ CreateAndRunDownloadCleanupTask(std::string(), std::string());
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE, store_item->state);
+ EXPECT_EQ(item.download_initiation_attempts,
+ store_item->download_initiation_attempts);
+ EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, store_item->error_code);
+}
+
+TEST_F(DownloadCleanupTaskTest, NoRetryForOngoingDownload) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+ item.download_initiation_attempts =
+ DownloadCleanupTask::kMaxDownloadAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ CreateAndRunDownloadCleanupTask(item.guid, std::string());
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(DownloadCleanupTaskTest, ErrorOnMaxAttempts) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+ item.download_initiation_attempts = DownloadCleanupTask::kMaxDownloadAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ CreateAndRunDownloadCleanupTask(std::string(), std::string());
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::FINISHED, store_item->state);
+ EXPECT_EQ(PrefetchItemErrorCode::DOWNLOAD_MAX_ATTEMPTS_REACHED,
+ store_item->error_code);
+ EXPECT_EQ(item.download_initiation_attempts,
+ store_item->download_initiation_attempts);
+}
+
+TEST_F(DownloadCleanupTaskTest, SkipForOngoingDownloadWithMaxAttempts) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+ item.download_initiation_attempts = DownloadCleanupTask::kMaxDownloadAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ CreateAndRunDownloadCleanupTask(item.guid, std::string());
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(DownloadCleanupTaskTest, NoUpdateForOtherStates) {
+ std::set<PrefetchItem> items;
+ std::vector<PrefetchItemState> all_other_states =
+ TaskTestBase::GetAllStatesExcept(PrefetchItemState::DOWNLOADING);
+ for (const auto& state : all_other_states) {
+ PrefetchItem item = item_generator()->CreateItem(state);
+ item.download_initiation_attempts =
+ DownloadCleanupTask::kMaxDownloadAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+ items.insert(item);
+ }
+
+ CreateAndRunDownloadCleanupTask(std::string(), std::string());
+
+ std::set<PrefetchItem> store_items;
+ store_util()->GetAllItems(&store_items);
+ EXPECT_EQ(items, store_items);
+}
+
+TEST_F(DownloadCleanupTaskTest, MarkDownloadCompleted) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+ item.download_initiation_attempts =
+ DownloadCleanupTask::kMaxDownloadAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ CreateAndRunDownloadCleanupTask(std::string(), item.guid);
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADED, store_item->state);
+ EXPECT_EQ(kTestFilePath, store_item->file_path);
+ EXPECT_EQ(kTestFileSize, store_item->file_size);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_completed_task.cc b/chromium/components/offline_pages/core/prefetch/download_completed_task.cc
new file mode 100644
index 00000000000..1c578e57416
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_completed_task.cc
@@ -0,0 +1,97 @@
+// 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/offline_pages/core/prefetch/download_completed_task.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+namespace {
+
+bool UpdatePrefetchItemOnDownloadSuccessSync(const std::string& guid,
+ const base::FilePath& file_path,
+ int64_t file_size,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?, file_path = ?, file_size = ?"
+ " WHERE guid = ? AND state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADED));
+ statement.BindString(1, file_path.AsUTF8Unsafe());
+ statement.BindInt64(2, file_size);
+ statement.BindString(3, guid);
+ statement.BindInt(4, static_cast<int>(PrefetchItemState::DOWNLOADING));
+
+ return statement.Run();
+}
+
+bool UpdatePrefetchItemOnDownloadErrorSync(const std::string& guid,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?, error_code = ?"
+ " WHERE guid = ? AND state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(1, static_cast<int>(PrefetchItemErrorCode::DOWNLOAD_ERROR));
+ statement.BindString(2, guid);
+ statement.BindInt(3, static_cast<int>(PrefetchItemState::DOWNLOADING));
+
+ return statement.Run();
+}
+
+} // namespace
+
+DownloadCompletedTask::DownloadCompletedTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const PrefetchDownloadResult& download_result)
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
+ download_result_(download_result),
+ weak_ptr_factory_(this) {
+ DCHECK(!download_result_.download_id.empty());
+}
+
+DownloadCompletedTask::~DownloadCompletedTask() {}
+
+void DownloadCompletedTask::Run() {
+ if (download_result_.success) {
+ prefetch_store_->Execute(
+ base::BindOnce(&UpdatePrefetchItemOnDownloadSuccessSync,
+ download_result_.download_id, download_result_.file_path,
+ download_result_.file_size),
+ base::BindOnce(&DownloadCompletedTask::OnPrefetchItemUpdated,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ prefetch_store_->Execute(
+ base::BindOnce(&UpdatePrefetchItemOnDownloadErrorSync,
+ download_result_.download_id),
+ base::BindOnce(&DownloadCompletedTask::OnPrefetchItemUpdated,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void DownloadCompletedTask::OnPrefetchItemUpdated(bool success) {
+ // No further action can be done if the database fails to be updated. The
+ // cleanup task should eventually kick in to clean this up.
+ if (success)
+ prefetch_dispatcher_->SchedulePipelineProcessing();
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/download_completed_task.h b/chromium/components/offline_pages/core/prefetch/download_completed_task.h
new file mode 100644
index 00000000000..118713ce419
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_completed_task.h
@@ -0,0 +1,41 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_COMPLETED_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_COMPLETED_TASK_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Task that responses to the completed download.
+class DownloadCompletedTask : public Task {
+ public:
+ DownloadCompletedTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const PrefetchDownloadResult& download_result);
+ ~DownloadCompletedTask() override;
+
+ void Run() override;
+
+ private:
+ void OnPrefetchItemUpdated(bool success);
+
+ PrefetchDispatcher* prefetch_dispatcher_; // Outlives this class.
+ PrefetchStore* prefetch_store_; // Outlives this class.
+ PrefetchDownloadResult download_result_;
+
+ base::WeakPtrFactory<DownloadCompletedTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadCompletedTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_DOWNLOAD_COMPLETED_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/download_completed_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
new file mode 100644
index 00000000000..06a943192f1
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
@@ -0,0 +1,156 @@
+// 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/offline_pages/core/prefetch/download_completed_task.h"
+
+#include <string>
+#include <vector>
+
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+const int64_t kTestOfflineID = 1111;
+const int64_t kTestOfflineID2 = 223344;
+const char kTestGUID[] = "1a150628-1b56-44da-a85a-c575120af180";
+const char kTestGUID2[] = "736edb12-98f6-41c2-8e50-a667694511a5";
+const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
+const int64_t kTestFileSize = 88888;
+} // namespace
+
+class DownloadCompletedTaskTest : public testing::Test {
+ public:
+ DownloadCompletedTaskTest();
+ ~DownloadCompletedTaskTest() override = default;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ void PumpLoop();
+
+ PrefetchStore* store() { return store_test_util_.store(); }
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+
+ private:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+ TestPrefetchDispatcher dispatcher_;
+ PrefetchStoreTestUtil store_test_util_;
+};
+
+DownloadCompletedTaskTest::DownloadCompletedTaskTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
+
+void DownloadCompletedTaskTest::SetUp() {
+ store_test_util_.BuildStoreInMemory();
+
+ PrefetchItem item;
+ item.offline_id = kTestOfflineID;
+ item.guid = kTestGUID;
+ item.state = PrefetchItemState::DOWNLOADING;
+ item.creation_time = base::Time::Now();
+ item.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item));
+
+ PrefetchItem item2;
+ item2.offline_id = kTestOfflineID2;
+ item2.guid = kTestGUID2;
+ item2.state = PrefetchItemState::NEW_REQUEST;
+ item2.creation_time = base::Time::Now();
+ item2.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item2));
+}
+
+void DownloadCompletedTaskTest::TearDown() {
+ store_test_util_.DeleteStore();
+ PumpLoop();
+}
+
+void DownloadCompletedTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+TEST_F(DownloadCompletedTaskTest, UpdateItemOnDownloadSuccess) {
+ PrefetchDownloadResult download_result(kTestGUID, kTestFilePath,
+ kTestFileSize);
+ DownloadCompletedTask task(dispatcher(), store(), download_result);
+ task.Run();
+ PumpLoop();
+
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADED, item->state);
+ EXPECT_EQ(kTestGUID, item->guid);
+ EXPECT_EQ(kTestFilePath, item->file_path);
+ EXPECT_EQ(kTestFileSize, item->file_size);
+}
+
+TEST_F(DownloadCompletedTaskTest, UpdateItemOnDownloadError) {
+ PrefetchDownloadResult download_result;
+ download_result.download_id = kTestGUID;
+ download_result.success = false;
+ DownloadCompletedTask task(dispatcher(), store(), download_result);
+ task.Run();
+ PumpLoop();
+
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::FINISHED, item->state);
+ EXPECT_EQ(PrefetchItemErrorCode::DOWNLOAD_ERROR, item->error_code);
+ EXPECT_EQ(kTestGUID, item->guid);
+ EXPECT_TRUE(item->file_path.empty());
+ EXPECT_EQ(-1, item->file_size);
+}
+
+TEST_F(DownloadCompletedTaskTest, NoUpdateOnMismatchedDownloadSuccess) {
+ PrefetchDownloadResult download_result(kTestGUID2, kTestFilePath,
+ kTestFileSize);
+ DownloadCompletedTask task(dispatcher(), store(), download_result);
+ task.Run();
+ PumpLoop();
+
+ // Item will only be updated when both offline_id and state match.
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, item->state);
+
+ std::unique_ptr<PrefetchItem> item2 =
+ store_util()->GetPrefetchItem(kTestOfflineID2);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+}
+
+TEST_F(DownloadCompletedTaskTest, NoUpdateOnMismatchedDownloadError) {
+ PrefetchDownloadResult download_result;
+ download_result.download_id = kTestGUID2;
+ download_result.success = false;
+ DownloadCompletedTask task(dispatcher(), store(), download_result);
+ task.Run();
+ PumpLoop();
+
+ // Item will only be updated when both offline_id and state match.
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::DOWNLOADING, item->state);
+
+ std::unique_ptr<PrefetchItem> item2 =
+ store_util()->GetPrefetchItem(kTestOfflineID2);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.cc
new file mode 100644
index 00000000000..e7c9a7ea2c0
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.cc
@@ -0,0 +1,139 @@
+// 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/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+namespace {
+
+struct FetchedUrl {
+ FetchedUrl() = default;
+ FetchedUrl(int64_t offline_id,
+ const std::string& requested_url,
+ int generate_bundle_attempts)
+ : offline_id_(offline_id),
+ requested_url_(requested_url),
+ generate_bundle_attempts_(generate_bundle_attempts) {}
+
+ int64_t offline_id_;
+ std::string requested_url_;
+ int generate_bundle_attempts_;
+};
+
+std::vector<FetchedUrl> GetAllUrlsMarkedRequestedSync(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT offline_id, requested_url, generate_bundle_attempts"
+ " FROM prefetch_items"
+ " WHERE state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(
+ 0, static_cast<int>(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE));
+
+ std::vector<FetchedUrl> urls;
+ while (statement.Step()) {
+ urls.emplace_back(statement.ColumnInt64(0), statement.ColumnString(1),
+ statement.ColumnInt(2));
+ }
+ return urls;
+}
+
+bool MarkUrlFinishedSync(const int64_t offline_id, sql::Connection* db) {
+ PrefetchItemErrorCode error_code =
+ PrefetchItemErrorCode::GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED;
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?, error_code = ?"
+ " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(1, static_cast<int>(error_code));
+ statement.BindInt64(2, offline_id);
+ return statement.Run();
+}
+
+bool MarkUrlForRetrySync(const int64_t offline_id, sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?"
+ " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::NEW_REQUEST));
+ statement.BindInt64(1, offline_id);
+ return statement.Run();
+}
+
+bool ReconcileGenerateBundleRequests(
+ std::unique_ptr<std::set<std::string>> requested_urls,
+ int max_attempts,
+ sql::Connection* db) {
+ if (!db)
+ return false;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+
+ std::vector<FetchedUrl> urls = GetAllUrlsMarkedRequestedSync(db);
+ if (urls.empty())
+ return false;
+
+ for (const auto& url : urls) {
+ // If the url is a part of active request, do nothing.
+ if (requested_urls->count(url.requested_url_) > 0)
+ continue;
+
+ // Otherwise, update the state to either retry request or error out.
+ bool updated = url.generate_bundle_attempts_ >= max_attempts
+ ? MarkUrlFinishedSync(url.offline_id_, db)
+ : MarkUrlForRetrySync(url.offline_id_, db);
+ if (!updated)
+ return false;
+ }
+
+ return transaction.Commit();
+}
+} // namespace
+
+// static
+const int GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts = 3;
+
+GeneratePageBundleReconcileTask::GeneratePageBundleReconcileTask(
+ PrefetchStore* prefetch_store,
+ PrefetchNetworkRequestFactory* request_factory)
+ : prefetch_store_(prefetch_store),
+ request_factory_(request_factory),
+ weak_factory_(this) {}
+
+GeneratePageBundleReconcileTask::~GeneratePageBundleReconcileTask() = default;
+
+void GeneratePageBundleReconcileTask::Run() {
+ std::unique_ptr<std::set<std::string>> requested_urls =
+ request_factory_->GetAllUrlsRequested();
+ DCHECK(requested_urls);
+
+ prefetch_store_->Execute(
+ base::BindOnce(&ReconcileGenerateBundleRequests,
+ std::move(requested_urls), kMaxGenerateBundleAttempts),
+ base::BindOnce(&GeneratePageBundleReconcileTask::FinishedUpdate,
+ weak_factory_.GetWeakPtr()));
+}
+
+void GeneratePageBundleReconcileTask::FinishedUpdate(bool success) {
+ // TODO(dimich): report failure/success to UMA.
+ TaskComplete();
+}
+
+} // namespace offline_pages \ No newline at end of file
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h
new file mode 100644
index 00000000000..89d6927434c
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h
@@ -0,0 +1,43 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_RECONCILE_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_RECONCILE_TASK_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchNetworkRequestFactory;
+class PrefetchStore;
+
+// Reconciling task that finds URL entries that claim they are being requested
+// but for which there is no active network request and moves them either into
+// state where network request can be retried or finishes them with error code
+// if the number of retries is over the limit.
+class GeneratePageBundleReconcileTask : public Task {
+ public:
+ static const int kMaxGenerateBundleAttempts;
+
+ GeneratePageBundleReconcileTask(
+ PrefetchStore* prefetch_store,
+ PrefetchNetworkRequestFactory* request_factory);
+ ~GeneratePageBundleReconcileTask() override;
+
+ // Task implementation.
+ void Run() override;
+
+ private:
+ void FinishedUpdate(bool success);
+
+ PrefetchStore* prefetch_store_;
+ PrefetchNetworkRequestFactory* request_factory_;
+
+ base::WeakPtrFactory<GeneratePageBundleReconcileTask> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(GeneratePageBundleReconcileTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_RECONCILE_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc
new file mode 100644
index 00000000000..2673302435b
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc
@@ -0,0 +1,188 @@
+// 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/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h"
+
+#include <string>
+
+#include "base/time/time.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+namespace {
+class FakePrefetchNetworkRequestFactory : public PrefetchNetworkRequestFactory {
+ public:
+ FakePrefetchNetworkRequestFactory() {
+ requested_urls_ = base::MakeUnique<std::set<std::string>>();
+ }
+ ~FakePrefetchNetworkRequestFactory() override = default;
+
+ // Implementation of PrefetchNetworkRequestFactory
+ bool HasOutstandingRequests() const override { return false; }
+ void MakeGeneratePageBundleRequest(
+ const std::vector<std::string>& prefetch_urls,
+ const std::string& gcm_registration_id,
+ const PrefetchRequestFinishedCallback& callback) override {}
+ std::unique_ptr<std::set<std::string>> GetAllUrlsRequested() const override {
+ return base::MakeUnique<std::set<std::string>>(*requested_urls_);
+ }
+ void MakeGetOperationRequest(
+ const std::string& operation_name,
+ const PrefetchRequestFinishedCallback& callback) override {}
+ GetOperationRequest* FindGetOperationRequestByName(
+ const std::string& operation_name) const override {
+ return nullptr;
+ }
+ std::unique_ptr<std::set<std::string>> GetAllOperationNamesRequested()
+ const override {
+ return nullptr;
+ }
+
+ void AddRequestedUrl(const std::string& url) { requested_urls_->insert(url); }
+
+ private:
+ std::unique_ptr<std::set<std::string>> requested_urls_;
+};
+} // namespace
+
+class GeneratePageBundleReconcileTaskTest : public TaskTestBase {
+ public:
+ GeneratePageBundleReconcileTaskTest();
+ ~GeneratePageBundleReconcileTaskTest() override = default;
+
+ FakePrefetchNetworkRequestFactory* request_factory() {
+ return request_factory_.get();
+ }
+
+ // Inserts the item with specified fields set into database, returns the
+ // same item.
+ PrefetchItem InsertItem(PrefetchItemState state, int attempts_count);
+
+ private:
+ std::unique_ptr<FakePrefetchNetworkRequestFactory> request_factory_;
+};
+
+GeneratePageBundleReconcileTaskTest::GeneratePageBundleReconcileTaskTest()
+ : request_factory_(base::MakeUnique<FakePrefetchNetworkRequestFactory>()) {}
+
+PrefetchItem GeneratePageBundleReconcileTaskTest::InsertItem(
+ PrefetchItemState state,
+ int attempts_count) {
+ PrefetchItem item = item_generator()->CreateItem(state);
+ item.generate_bundle_attempts = attempts_count;
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item));
+ return item;
+}
+
+TEST_F(GeneratePageBundleReconcileTaskTest, Retry) {
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ item.generate_bundle_attempts =
+ GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ GeneratePageBundleReconcileTask task(store(), request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, store_item->state);
+ EXPECT_EQ(item.generate_bundle_attempts,
+ store_item->generate_bundle_attempts);
+}
+
+TEST_F(GeneratePageBundleReconcileTaskTest, NoRetryForOngoingRequest) {
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ item.generate_bundle_attempts =
+ GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ request_factory()->AddRequestedUrl(item.url.spec());
+
+ GeneratePageBundleReconcileTask task(store(), request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(GeneratePageBundleReconcileTaskTest, ErrorOnMaxAttempts) {
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ item.generate_bundle_attempts =
+ GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ GeneratePageBundleReconcileTask task(store(), request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::FINISHED, store_item->state);
+ EXPECT_EQ(
+ PrefetchItemErrorCode::GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED,
+ store_item->error_code);
+ EXPECT_EQ(item.generate_bundle_attempts,
+ store_item->generate_bundle_attempts);
+}
+
+TEST_F(GeneratePageBundleReconcileTaskTest,
+ SkipForOngoingRequestWithMaxAttempts) {
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ item.generate_bundle_attempts =
+ GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ request_factory()->AddRequestedUrl(item.url.spec());
+
+ GeneratePageBundleReconcileTask task(store(), request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(GeneratePageBundleReconcileTaskTest, NoUpdateForOtherStates) {
+ std::set<PrefetchItem> items;
+ const int attempts_count =
+ GeneratePageBundleReconcileTask::kMaxGenerateBundleAttempts;
+ std::vector<PrefetchItemState> all_other_states =
+ TaskTestBase::GetAllStatesExcept(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ for (const auto& state : all_other_states)
+ items.insert(InsertItem(state, attempts_count));
+
+ GeneratePageBundleReconcileTask task(store(), request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> store_items;
+ store_util()->GetAllItems(&store_items);
+ EXPECT_EQ(items, store_items);
+}
+
+} // namespace offline_pages \ No newline at end of file
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
index 3cb6b2b674b..07d6ee626f4 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
@@ -24,16 +24,16 @@ GeneratePageBundleRequest::GeneratePageBundleRequest(
version_info::Channel channel,
net::URLRequestContextGetter* request_context_getter,
const PrefetchRequestFinishedCallback& callback)
- : callback_(callback) {
+ : callback_(callback), requested_urls_(page_urls) {
proto::GeneratePageBundleRequest request;
request.set_user_agent(user_agent);
request.set_max_bundle_size_bytes(max_bundle_size_bytes);
request.set_output_format(proto::FORMAT_MHTML);
request.set_gcm_registration_id(gcm_registration_id);
- for (const auto& page_url : page_urls) {
+ for (const auto& url : requested_urls_) {
proto::PageParameters* page = request.add_pages();
- page->set_url(page_url);
+ page->set_url(url);
page->set_transformation(proto::NO_TRANSFORMATION);
}
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.h b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.h
index 6e13334ca37..2bc1a98f5d7 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.h
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_REQUEST_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_REQUEST_H_
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -32,10 +33,13 @@ class GeneratePageBundleRequest {
const PrefetchRequestFinishedCallback& callback);
~GeneratePageBundleRequest();
+ const std::vector<std::string>& requested_urls() { return requested_urls_; }
+
private:
void OnCompleted(PrefetchRequestStatus status, const std::string& data);
PrefetchRequestFinishedCallback callback_;
+ std::vector<std::string> requested_urls_;
std::unique_ptr<PrefetchRequestFetcher> fetcher_;
DISALLOW_COPY_AND_ASSIGN(GeneratePageBundleRequest);
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
index 17e478a46f8..40fdf2b645a 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
@@ -15,8 +15,10 @@
#include "url/url_constants.h"
using testing::_;
+using testing::Contains;
using testing::DoAll;
using testing::Eq;
+using testing::Not;
using testing::SaveArg;
namespace offline_pages {
@@ -50,6 +52,10 @@ TEST_F(GeneratePageBundleRequestTest, RequestData) {
std::unique_ptr<GeneratePageBundleRequest> request(
CreateRequest(callback.Get()));
+ EXPECT_EQ(2UL, request->requested_urls().size());
+ EXPECT_THAT(request->requested_urls(), Contains(kTestURL));
+ EXPECT_THAT(request->requested_urls(), Contains(kTestURL2));
+
net::TestURLFetcher* fetcher = GetRunningFetcher();
EXPECT_TRUE(fetcher->GetOriginalURL().SchemeIs(url::kHttpsScheme));
EXPECT_TRUE(base::StartsWith(fetcher->GetOriginalURL().query(), "key",
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
index b5ded96f23d..9641a3ef2f6 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
@@ -4,39 +4,126 @@
#include "components/offline_pages/core/prefetch/generate_page_bundle_task.h"
-#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
namespace offline_pages {
-
namespace {
-// TODO(dewittj): Use the SQL store.
-// Once that TODO is done, this will choose from the list of available Prefetch
-// URLs stored in the prefetch model. Until then, this does nothing.
-static int SelectURLsToPrefetch() {
- NOTIMPLEMENTED();
- return 1;
+// Temporary storage for Urls metadata fetched from the storage.
+struct FetchedUrl {
+ FetchedUrl() = default;
+ FetchedUrl(int64_t offline_id,
+ const std::string& requested_url,
+ int generate_bundle_attempts)
+ : offline_id(offline_id),
+ requested_url(requested_url),
+ generate_bundle_attempts(generate_bundle_attempts) {}
+
+ int64_t offline_id;
+ std::string requested_url;
+ int generate_bundle_attempts;
+};
+
+// This is maximum URLs that Offline Page Service can take in one request.
+const int kMaxUrlsToSend = 100;
+
+bool UpdateStateSync(sql::Connection* db, const FetchedUrl& url) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, generate_bundle_attempts = ?"
+ " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(
+ 0, static_cast<int>(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE));
+ statement.BindInt(1, url.generate_bundle_attempts + 1);
+ statement.BindInt64(2, url.offline_id);
+ return statement.Run();
}
-// TODO(fgorski): replace this with the SQL executor.
-static void Execute(base::RepeatingCallback<int()> command_callback,
- base::OnceCallback<void(int)> result_callback) {
- std::move(result_callback).Run(command_callback.Run());
+std::unique_ptr<std::vector<FetchedUrl>> FetchUrlsSync(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT offline_id, requested_url, generate_bundle_attempts"
+ " FROM prefetch_items"
+ " WHERE state = ?"
+ " ORDER BY creation_time DESC";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::NEW_REQUEST));
+
+ auto urls = base::MakeUnique<std::vector<FetchedUrl>>();
+ while (statement.Step()) {
+ urls->push_back(
+ FetchedUrl(statement.ColumnInt64(0), // offline_id
+ statement.ColumnString(1), // requested_url
+ statement.ColumnInt(2))); // generate_bundle_attempts
+ }
+
+ return urls;
+}
+
+bool MarkUrlFinishedWithError(sql::Connection* db, const FetchedUrl& url) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, error_code = ?"
+ " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(1,
+ static_cast<int>(PrefetchItemErrorCode::TOO_MANY_NEW_URLS));
+ statement.BindInt64(2, url.offline_id);
+ return statement.Run();
+}
+
+std::unique_ptr<std::vector<std::string>> SelectUrlsToPrefetchSync(
+ sql::Connection* db) {
+ if (!db)
+ return nullptr;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return nullptr;
+
+ auto urls = FetchUrlsSync(db);
+ if (!urls || urls->empty())
+ return nullptr;
+
+ // If we've got more than kMaxUrlsToSend URLs, mark the extra ones FINISHED
+ // and remove them from the list.
+ if (urls->size() > kMaxUrlsToSend) {
+ for (size_t index = kMaxUrlsToSend; index < urls->size(); ++index) {
+ if (!MarkUrlFinishedWithError(db, urls->at(index)))
+ return nullptr;
+ }
+ urls->resize(kMaxUrlsToSend);
+ }
+
+ auto url_specs = base::MakeUnique<std::vector<std::string>>();
+ for (const auto& url : *urls) {
+ if (!UpdateStateSync(db, url))
+ return nullptr;
+ url_specs->push_back(std::move(url.requested_url));
+ }
+
+ if (!transaction.Commit())
+ return nullptr;
+
+ return url_specs;
}
} // namespace
GeneratePageBundleTask::GeneratePageBundleTask(
- const std::vector<PrefetchURL>& prefetch_urls,
+ PrefetchStore* prefetch_store,
PrefetchGCMHandler* gcm_handler,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback)
- : prefetch_urls_(prefetch_urls),
+ : prefetch_store_(prefetch_store),
gcm_handler_(gcm_handler),
request_factory_(request_factory),
callback_(callback),
@@ -45,30 +132,30 @@ GeneratePageBundleTask::GeneratePageBundleTask(
GeneratePageBundleTask::~GeneratePageBundleTask() {}
void GeneratePageBundleTask::Run() {
- Execute(base::BindRepeating(&SelectURLsToPrefetch),
- base::BindOnce(&GeneratePageBundleTask::StartGeneratePageBundle,
- weak_factory_.GetWeakPtr()));
+ prefetch_store_->Execute(
+ base::BindOnce(&SelectUrlsToPrefetchSync),
+ base::BindOnce(&GeneratePageBundleTask::StartGeneratePageBundle,
+ weak_factory_.GetWeakPtr()));
}
-void GeneratePageBundleTask::StartGeneratePageBundle(int updated_entry_count) {
- if (prefetch_urls_.empty()) {
+void GeneratePageBundleTask::StartGeneratePageBundle(
+ std::unique_ptr<std::vector<std::string>> urls) {
+ if (!urls || urls->empty()) {
TaskComplete();
return;
}
- gcm_handler_->GetGCMToken(base::Bind(
- &GeneratePageBundleTask::GotRegistrationId, weak_factory_.GetWeakPtr()));
+ gcm_handler_->GetGCMToken(
+ base::Bind(&GeneratePageBundleTask::GotRegistrationId,
+ weak_factory_.GetWeakPtr(), base::Passed(std::move(urls))));
}
void GeneratePageBundleTask::GotRegistrationId(
+ std::unique_ptr<std::vector<std::string>> urls,
const std::string& id,
instance_id::InstanceID::Result result) {
- std::vector<std::string> url_strings;
- for (auto& prefetch_url : prefetch_urls_) {
- url_strings.push_back(prefetch_url.url.spec());
- }
-
- request_factory_->MakeGeneratePageBundleRequest(url_strings, id, callback_);
+ // TODO(dimich): Add UMA reporting on instance_id::InstanceID::Result.
+ request_factory_->MakeGeneratePageBundleRequest(*urls, id, callback_);
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
index 4f990055fcb..6f0f6d2f706 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_TASK_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GENERATE_PAGE_BUNDLE_TASK_H_
+#include <memory>
#include <string>
#include <vector>
@@ -16,14 +17,13 @@
namespace offline_pages {
class PrefetchGCMHandler;
class PrefetchNetworkRequestFactory;
+class PrefetchStore;
// Task that attempts to start archiving the URLs the prefetch service has
// determined are viable to prefetch.
class GeneratePageBundleTask : public Task {
public:
- // TODO(dewittj): remove the list of prefetch URLs when the DB operation can
- // supply the current set of URLs.
- GeneratePageBundleTask(const std::vector<PrefetchURL>& prefetch_urls,
+ GeneratePageBundleTask(PrefetchStore* prefetch_store,
PrefetchGCMHandler* gcm_handler,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback);
@@ -33,17 +33,17 @@ class GeneratePageBundleTask : public Task {
void Run() override;
private:
- void StartGeneratePageBundle(int updated_entry_count);
- void GotRegistrationId(const std::string& id,
+ void StartGeneratePageBundle(std::unique_ptr<std::vector<std::string>> urls);
+ void GotRegistrationId(std::unique_ptr<std::vector<std::string>> urls,
+ const std::string& id,
instance_id::InstanceID::Result result);
- std::vector<PrefetchURL> prefetch_urls_;
+ PrefetchStore* prefetch_store_;
PrefetchGCMHandler* gcm_handler_;
PrefetchNetworkRequestFactory* request_factory_;
PrefetchRequestFinishedCallback callback_;
base::WeakPtrFactory<GeneratePageBundleTask> weak_factory_;
-
DISALLOW_COPY_AND_ASSIGN(GeneratePageBundleTask);
};
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
index f57f8817837..f2b87144c4b 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
@@ -4,18 +4,22 @@
#include "components/offline_pages/core/prefetch/generate_page_bundle_task.h"
+#include "base/logging.h"
#include "base/test/mock_callback.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
#include "components/offline_pages/core/prefetch/task_test_base.h"
#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
#include "components/offline_pages/core/task.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::_;
+using testing::Contains;
using testing::HasSubstr;
-using testing::DoAll;
-using testing::SaveArg;
+using testing::Not;
namespace offline_pages {
@@ -35,35 +39,61 @@ class GeneratePageBundleTaskTest : public TaskTestBase {
TEST_F(GeneratePageBundleTaskTest, EmptyTask) {
base::MockCallback<PrefetchRequestFinishedCallback> callback;
- GeneratePageBundleTask task(std::vector<PrefetchURL>(), gcm_handler(),
+ GeneratePageBundleTask task(store(), gcm_handler(),
prefetch_request_factory(), callback.Get());
ExpectTaskCompletes(&task);
task.Run();
- task_runner->RunUntilIdle();
+ RunUntilIdle();
- EXPECT_EQ(nullptr,
- prefetch_request_factory()->CurrentGeneratePageBundleRequest());
+ EXPECT_FALSE(prefetch_request_factory()->HasOutstandingRequests());
+ auto requested_urls = prefetch_request_factory()->GetAllUrlsRequested();
+ EXPECT_TRUE(requested_urls->empty());
}
TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
- base::MockCallback<PrefetchRequestFinishedCallback> callback;
- std::vector<PrefetchURL> urls = {
- {"id1", GURL("https://example.com/1.html")},
- {"id2", GURL("https://example.com/2.html")},
- };
- GeneratePageBundleTask task(urls, gcm_handler(), prefetch_request_factory(),
- callback.Get());
- ExpectTaskCompletes(&task);
+ base::MockCallback<PrefetchRequestFinishedCallback> request_callback;
+
+ PrefetchItem item1 =
+ item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item1));
+ PrefetchItem item2 =
+ item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item2));
+ EXPECT_NE(item1.offline_id, item2.offline_id);
+
+ // This item should be unaffected by the task.
+ PrefetchItem item3 =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item3));
+
+ EXPECT_EQ(3, store_util()->CountPrefetchItems());
+ GeneratePageBundleTask task(store(), gcm_handler(),
+ prefetch_request_factory(),
+ request_callback.Get());
+ ExpectTaskCompletes(&task);
task.Run();
- task_runner->RunUntilIdle();
+ RunUntilIdle();
+
+ auto requested_urls = prefetch_request_factory()->GetAllUrlsRequested();
+ EXPECT_THAT(*requested_urls, Contains(item1.url.spec()));
+ EXPECT_THAT(*requested_urls, Contains(item2.url.spec()));
+ EXPECT_THAT(*requested_urls, Not(Contains(item3.url.spec())));
- EXPECT_NE(nullptr,
- prefetch_request_factory()->CurrentGeneratePageBundleRequest());
std::string upload_data =
url_fetcher_factory()->GetFetcherByID(0)->upload_data();
- EXPECT_THAT(upload_data, HasSubstr("example.com"));
+ EXPECT_THAT(upload_data, HasSubstr(MockPrefetchItemGenerator::kUrlPrefix));
+
+ EXPECT_EQ(3, store_util()->CountPrefetchItems());
+
+ ASSERT_TRUE(store_util()->GetPrefetchItem(item1.offline_id));
+ ASSERT_TRUE(store_util()->GetPrefetchItem(item2.offline_id));
+
+ EXPECT_EQ(store_util()->GetPrefetchItem(item1.offline_id)->state,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ EXPECT_EQ(store_util()->GetPrefetchItem(item2.offline_id)->state,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/get_operation_task.cc b/chromium/components/offline_pages/core/prefetch/get_operation_task.cc
index ec1f65d3595..e8befc9346d 100644
--- a/chromium/components/offline_pages/core/prefetch/get_operation_task.cc
+++ b/chromium/components/offline_pages/core/prefetch/get_operation_task.cc
@@ -9,31 +9,84 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
namespace offline_pages {
namespace {
-// Will hold the actual SQL implementation for marking a GetOperation attempt in
-// the database.
-static int MarkOperationAttemptStarted(const std::string& operation_name) {
- NOTIMPLEMENTED();
- return 1;
+GetOperationTask::OperationResultList MakeError() {
+ return nullptr;
}
-// TODO(fgorski): replace this with the SQL executor.
-static void Execute(base::RepeatingCallback<int()> command_callback,
- base::OnceCallback<void(int)> result_callback) {
- std::move(result_callback).Run(command_callback.Run());
+bool UpdatePrefetchItemsForOperationSync(sql::Connection* db,
+ const std::string& operation_name) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET"
+ " state = ?,"
+ " get_operation_attempts = get_operation_attempts + 1"
+ " WHERE state = ? AND operation_name = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::SENT_GET_OPERATION));
+ statement.BindInt(1, static_cast<int>(PrefetchItemState::RECEIVED_GCM));
+ statement.BindString(2, operation_name);
+
+ return statement.Run();
+}
+
+std::unique_ptr<std::vector<std::string>> AvailableOperationsSync(
+ sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT DISTINCT operation_name FROM prefetch_items WHERE state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::RECEIVED_GCM));
+
+ auto operations = base::MakeUnique<std::vector<std::string>>();
+ while (statement.Step()) {
+ operations->push_back(statement.ColumnString(0)); // operation_name
+ }
+ return operations;
}
+
+GetOperationTask::OperationResultList SelectOperationsToFetch(
+ sql::Connection* db) {
+ if (!db)
+ return MakeError();
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return MakeError();
+
+ auto operations = AvailableOperationsSync(db);
+ if (!operations)
+ return MakeError();
+
+ for (std::string operation : *operations) {
+ if (!UpdatePrefetchItemsForOperationSync(db, operation))
+ return MakeError(); // Rollback.
+ }
+
+ if (!transaction.Commit())
+ return MakeError();
+
+ return operations;
+}
+
} // namespace
GetOperationTask::GetOperationTask(
- const std::string& operation_name,
+ PrefetchStore* store,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback)
- : operation_name_(operation_name),
+ : prefetch_store_(store),
request_factory_(request_factory),
callback_(callback),
weak_factory_(this) {}
@@ -41,13 +94,20 @@ GetOperationTask::GetOperationTask(
GetOperationTask::~GetOperationTask() {}
void GetOperationTask::Run() {
- Execute(base::BindRepeating(&MarkOperationAttemptStarted, operation_name_),
- base::BindOnce(&GetOperationTask::StartGetOperation,
- weak_factory_.GetWeakPtr()));
+ prefetch_store_->Execute(
+ base::BindOnce(&SelectOperationsToFetch),
+ base::BindOnce(&GetOperationTask::StartGetOperationRequests,
+ weak_factory_.GetWeakPtr()));
}
-void GetOperationTask::StartGetOperation(int updated_entry_count) {
- request_factory_->MakeGetOperationRequest(operation_name_, callback_);
+void GetOperationTask::StartGetOperationRequests(
+ OperationResultList operation_names) {
+ if (operation_names) {
+ for (std::string& operation : *operation_names) {
+ request_factory_->MakeGetOperationRequest(operation, callback_);
+ }
+ }
+
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/prefetch/get_operation_task.h b/chromium/components/offline_pages/core/prefetch/get_operation_task.h
index bedcebec00b..8b67e61b70a 100644
--- a/chromium/components/offline_pages/core/prefetch/get_operation_task.h
+++ b/chromium/components/offline_pages/core/prefetch/get_operation_task.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GET_OPERATION_TASK_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_GET_OPERATION_TASK_H_
+#include <memory>
#include <string>
#include <vector>
@@ -14,11 +15,16 @@
namespace offline_pages {
class PrefetchNetworkRequestFactory;
+class PrefetchStore;
-// Task that attempts to fetch results for a completed operation.
+// Task that attempts to fetch results for a completed operation. Searches the
+// URLs table for operations with rows in the appropriate state and fires off
+// concurrent GetOperation requests.
class GetOperationTask : public Task {
public:
- GetOperationTask(const std::string& operation_name,
+ using OperationResultList = std::unique_ptr<std::vector<std::string>>;
+
+ GetOperationTask(PrefetchStore* store,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback);
~GetOperationTask() override;
@@ -27,9 +33,9 @@ class GetOperationTask : public Task {
void Run() override;
private:
- void StartGetOperation(int updated_entry_count);
+ void StartGetOperationRequests(OperationResultList list);
- const std::string& operation_name_;
+ PrefetchStore* prefetch_store_;
PrefetchNetworkRequestFactory* request_factory_;
PrefetchRequestFinishedCallback callback_;
diff --git a/chromium/components/offline_pages/core/prefetch/get_operation_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
index 59917a066d2..0e340a89c20 100644
--- a/chromium/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
@@ -5,6 +5,7 @@
#include "components/offline_pages/core/prefetch/get_operation_task.h"
#include "base/test/mock_callback.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/prefetch/task_test_base.h"
#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
@@ -12,12 +13,17 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::_;
-using testing::HasSubstr;
using testing::DoAll;
+using testing::HasSubstr;
using testing::SaveArg;
+using testing::_;
namespace offline_pages {
+namespace {
+const char kOperationName[] = "an_operation";
+const char kOtherOperationName[] = "an_operation";
+const char kOperationShouldNotBeRequested[] = "Operation Not Found";
+} // namespace
// All tests cases here only validate the request data and check for general
// http response. The tests for the Operation proto data returned in the http
@@ -26,28 +32,90 @@ class GetOperationTaskTest : public TaskTestBase {
public:
GetOperationTaskTest() = default;
~GetOperationTaskTest() override = default;
-
- TestPrefetchGCMHandler* gcm_handler() { return &gcm_handler_; }
-
- private:
- TestPrefetchGCMHandler gcm_handler_;
};
TEST_F(GetOperationTaskTest, NormalOperationTask) {
base::MockCallback<PrefetchRequestFinishedCallback> callback;
- std::string operation_name = "anoperation";
- GetOperationTask task(operation_name, prefetch_request_factory(),
- callback.Get());
- ExpectTaskCompletes(&task);
+ int64_t id = InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::RECEIVED_GCM);
+ ASSERT_NE(nullptr, store_util()->GetPrefetchItem(id));
+ GetOperationTask task(store(), prefetch_request_factory(), callback.Get());
+ ExpectTaskCompletes(&task);
task.Run();
- task_runner->RunUntilIdle();
+ RunUntilIdle();
EXPECT_NE(nullptr, prefetch_request_factory()->FindGetOperationRequestByName(
- operation_name));
+ kOperationName));
std::string path =
url_fetcher_factory()->GetFetcherByID(0)->GetOriginalURL().path();
- EXPECT_THAT(path, HasSubstr(operation_name));
+ EXPECT_THAT(path, HasSubstr(kOperationName));
+ EXPECT_EQ(1, store_util()->LastCommandChangeCount());
+ ASSERT_NE(nullptr, store_util()->GetPrefetchItem(id));
+ EXPECT_EQ(1, store_util()->GetPrefetchItem(id)->get_operation_attempts);
+}
+
+TEST_F(GetOperationTaskTest, NotMatchingEntries) {
+ base::MockCallback<PrefetchRequestFinishedCallback> callback;
+ std::vector<PrefetchItemState> states = {
+ PrefetchItemState::NEW_REQUEST,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE,
+ PrefetchItemState::AWAITING_GCM,
+ PrefetchItemState::RECEIVED_BUNDLE,
+ PrefetchItemState::DOWNLOADING,
+ PrefetchItemState::FINISHED,
+ PrefetchItemState::ZOMBIE};
+ std::vector<int64_t> entries;
+ for (auto& state : states) {
+ entries.push_back(
+ InsertPrefetchItemInStateWithOperation(kOperationName, state));
+ }
+
+ GetOperationTask task(store(), prefetch_request_factory(), callback.Get());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ EXPECT_EQ(nullptr, prefetch_request_factory()->FindGetOperationRequestByName(
+ kOperationName));
+ for (int64_t id : entries) {
+ EXPECT_NE(PrefetchItemState::SENT_GET_OPERATION,
+ store_util()->GetPrefetchItem(id)->state);
+ // No attempts should be recorded.
+ EXPECT_GT(1, store_util()->GetPrefetchItem(id)->get_operation_attempts);
+ }
+}
+
+TEST_F(GetOperationTaskTest, TwoOperations) {
+ base::MockCallback<PrefetchRequestFinishedCallback> callback;
+ int64_t item1 = InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::RECEIVED_GCM);
+
+ int64_t item2 = InsertPrefetchItemInStateWithOperation(
+ kOtherOperationName, PrefetchItemState::RECEIVED_GCM);
+
+ // One should not be fetched.
+ int64_t unused_item = InsertPrefetchItemInStateWithOperation(
+ kOperationShouldNotBeRequested, PrefetchItemState::SENT_GET_OPERATION);
+
+ GetOperationTask task(store(), prefetch_request_factory(), callback.Get());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ EXPECT_NE(nullptr, prefetch_request_factory()->FindGetOperationRequestByName(
+ kOperationName));
+ EXPECT_NE(nullptr, prefetch_request_factory()->FindGetOperationRequestByName(
+ kOtherOperationName));
+ EXPECT_EQ(1, store_util()->GetPrefetchItem(item1)->get_operation_attempts);
+ EXPECT_EQ(1, store_util()->GetPrefetchItem(item2)->get_operation_attempts);
+
+ // The one with no entries in RECEIVED_GCM state should not be requested.
+ EXPECT_EQ(nullptr, prefetch_request_factory()->FindGetOperationRequestByName(
+ kOperationShouldNotBeRequested));
+ // No attempts should be recorded.
+ EXPECT_GT(1,
+ store_util()->GetPrefetchItem(unused_item)->get_operation_attempts);
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/import_archives_task.cc b/chromium/components/offline_pages/core/prefetch/import_archives_task.cc
new file mode 100644
index 00000000000..253c80e892e
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_archives_task.cc
@@ -0,0 +1,114 @@
+// 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/offline_pages/core/prefetch/import_archives_task.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+namespace {
+
+std::unique_ptr<std::vector<PrefetchArchiveInfo>> GetArchivesSync(
+ sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT offline_id, client_namespace, client_id, requested_url,"
+ " final_archived_url, title, file_path, file_size"
+ " FROM prefetch_items"
+ " WHERE state = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADED));
+
+ std::unique_ptr<std::vector<PrefetchArchiveInfo>> archives;
+ while (statement.Step()) {
+ PrefetchArchiveInfo archive;
+ archive.offline_id = statement.ColumnInt64(0);
+ archive.client_id.name_space = statement.ColumnString(1);
+ archive.client_id.id = statement.ColumnString(2);
+ archive.url = GURL(statement.ColumnString(3));
+ archive.final_archived_url = GURL(statement.ColumnString(4));
+ archive.title = statement.ColumnString16(5);
+ archive.file_path =
+ base::FilePath::FromUTF8Unsafe(statement.ColumnString(6));
+ archive.file_size = statement.ColumnInt64(7);
+ if (!archives)
+ archives = base::MakeUnique<std::vector<PrefetchArchiveInfo>>();
+ archives->push_back(archive);
+ }
+
+ return archives;
+}
+
+bool UpdateToImportingStateSync(int64_t offline_id, sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?"
+ " WHERE offline_id = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::IMPORTING));
+ statement.BindInt64(1, offline_id);
+
+ return statement.Run();
+}
+
+std::unique_ptr<std::vector<PrefetchArchiveInfo>>
+GetArchivesAndUpdateToImportingStateSync(sql::Connection* db) {
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return nullptr;
+
+ std::unique_ptr<std::vector<PrefetchArchiveInfo>> archives =
+ GetArchivesSync(db);
+ if (!archives)
+ return nullptr;
+
+ for (const auto& archive : *archives) {
+ if (!UpdateToImportingStateSync(archive.offline_id, db))
+ return nullptr;
+ }
+
+ if (!transaction.Commit())
+ return nullptr;
+
+ return archives;
+}
+
+} // namespace
+
+ImportArchivesTask::ImportArchivesTask(PrefetchStore* prefetch_store,
+ PrefetchImporter* prefetch_importer)
+ : prefetch_store_(prefetch_store),
+ prefetch_importer_(prefetch_importer),
+ weak_ptr_factory_(this) {}
+
+ImportArchivesTask::~ImportArchivesTask() {}
+
+void ImportArchivesTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&GetArchivesAndUpdateToImportingStateSync),
+ base::BindOnce(&ImportArchivesTask::OnArchivesRetrieved,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ImportArchivesTask::OnArchivesRetrieved(
+ std::unique_ptr<std::vector<PrefetchArchiveInfo>> archives) {
+ if (archives) {
+ for (const auto& archive : *archives)
+ prefetch_importer_->ImportArchive(archive);
+ }
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/import_archives_task.h b/chromium/components/offline_pages/core/prefetch/import_archives_task.h
new file mode 100644
index 00000000000..96496219e63
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_archives_task.h
@@ -0,0 +1,43 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_ARCHIVES_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_ARCHIVES_TASK_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_importer.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchStore;
+
+// Task that attempts to import a downloaded archive to offline page model.
+class ImportArchivesTask : public Task {
+ public:
+ ImportArchivesTask(PrefetchStore* prefetch_store,
+ PrefetchImporter* prefetch_importer);
+ ~ImportArchivesTask() override;
+
+ void Run() override;
+
+ private:
+ void OnArchivesRetrieved(
+ std::unique_ptr<std::vector<PrefetchArchiveInfo>> archive);
+
+ PrefetchStore* prefetch_store_; // Outlives this class.
+ PrefetchImporter* prefetch_importer_; // Outlives this class.
+ PrefetchArchiveInfo archive_;
+
+ base::WeakPtrFactory<ImportArchivesTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImportArchivesTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_ARCHIVES_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/import_archives_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
new file mode 100644
index 00000000000..960975aebd4
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
@@ -0,0 +1,182 @@
+// 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/offline_pages/core/prefetch/import_archives_task.h"
+
+#include <string>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/prefetch/prefetch_importer.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+
+const int64_t kTestOfflineID = 1111;
+const int64_t kTestOfflineID2 = 223344;
+const int64_t kTestOfflineID3 = 987;
+const GURL kTestURL("http://sample.org");
+const GURL kTestURL2("http://sample.org");
+const GURL kTestFinalURL("https://sample.org/foo");
+const GURL kTestFinalURL2("https://sample.org/foo");
+const ClientId kTestClientID("Foo", "Bar");
+const ClientId kTestClientID2("Foo2", "Bar2");
+const base::string16 kTestTitle = base::ASCIIToUTF16("Hello");
+const base::string16 kTestTitle2 = base::ASCIIToUTF16("Hello2");
+const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
+const base::FilePath kTestFilePath2(FILE_PATH_LITERAL("foo2"));
+const int64_t kTestFileSize = 88888;
+const int64_t kTestFileSize2 = 999;
+
+class TestPrefetchImporter : public PrefetchImporter {
+ public:
+ TestPrefetchImporter() : PrefetchImporter(nullptr) {}
+ ~TestPrefetchImporter() override = default;
+
+ void ImportArchive(const PrefetchArchiveInfo& archive) override {
+ archives_.push_back(archive);
+ }
+
+ const std::vector<PrefetchArchiveInfo>& archives() const { return archives_; }
+
+ private:
+ std::vector<PrefetchArchiveInfo> archives_;
+};
+
+} // namespace
+
+// TODO(carlosk, jianli): Update this test to extend and use the functionality
+// provided by TaskTestBase.
+class ImportArchivesTaskTest : public testing::Test {
+ public:
+ ImportArchivesTaskTest();
+ ~ImportArchivesTaskTest() override = default;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ void PumpLoop();
+
+ PrefetchStore* store() { return store_test_util_.store(); }
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+ TestPrefetchImporter* importer() { return &test_importer_; }
+
+ private:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+ PrefetchStoreTestUtil store_test_util_;
+ TestPrefetchImporter test_importer_;
+};
+
+ImportArchivesTaskTest::ImportArchivesTaskTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
+
+void ImportArchivesTaskTest::SetUp() {
+ store_test_util_.BuildStoreInMemory();
+
+ PrefetchItem item;
+ item.offline_id = kTestOfflineID;
+ item.state = PrefetchItemState::DOWNLOADED;
+ item.url = kTestURL;
+ item.final_archived_url = kTestFinalURL;
+ item.client_id = kTestClientID;
+ item.title = kTestTitle;
+ item.file_path = kTestFilePath;
+ item.file_size = kTestFileSize;
+ item.creation_time = base::Time::Now();
+ item.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item));
+
+ PrefetchItem item2;
+ item2.offline_id = kTestOfflineID2;
+ item2.state = PrefetchItemState::DOWNLOADED;
+ item2.url = kTestURL2;
+ item2.final_archived_url = kTestFinalURL2;
+ item2.client_id = kTestClientID2;
+ item2.title = kTestTitle2;
+ item2.file_path = kTestFilePath2;
+ item2.file_size = kTestFileSize2;
+ item2.creation_time = base::Time::Now();
+ item2.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item2));
+
+ PrefetchItem item3;
+ item3.offline_id = kTestOfflineID3;
+ item3.state = PrefetchItemState::NEW_REQUEST;
+ item3.creation_time = base::Time::Now();
+ item3.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item3));
+}
+
+void ImportArchivesTaskTest::TearDown() {
+ store_test_util_.DeleteStore();
+ PumpLoop();
+}
+
+void ImportArchivesTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+TEST_F(ImportArchivesTaskTest, Importing) {
+ ImportArchivesTask task(store(), importer());
+ task.Run();
+ PumpLoop();
+
+ // Two items are updated.
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::IMPORTING, item->state);
+
+ item = store_util()->GetPrefetchItem(kTestOfflineID2);
+ EXPECT_EQ(PrefetchItemState::IMPORTING, item->state);
+
+ // One item is not updated.
+ item = store_util()->GetPrefetchItem(kTestOfflineID3);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item->state);
+
+ // Validate the info passed to PrefetchImporter.
+ ASSERT_EQ(2u, importer()->archives().size());
+
+ PrefetchArchiveInfo archive1;
+ PrefetchArchiveInfo archive2;
+ if (importer()->archives()[0].offline_id == kTestOfflineID) {
+ archive1 = importer()->archives()[0];
+ archive2 = importer()->archives()[1];
+ }
+ if (importer()->archives()[1].offline_id == kTestOfflineID) {
+ archive1 = importer()->archives()[1];
+ archive2 = importer()->archives()[0];
+ }
+ EXPECT_EQ(kTestOfflineID, archive1.offline_id);
+ EXPECT_EQ(kTestClientID, archive1.client_id);
+ EXPECT_EQ(kTestURL, archive1.url);
+ EXPECT_EQ(kTestFinalURL, archive1.final_archived_url);
+ EXPECT_EQ(kTestTitle, archive1.title);
+ EXPECT_EQ(kTestFilePath, archive1.file_path);
+ EXPECT_EQ(kTestFileSize, archive1.file_size);
+
+ EXPECT_EQ(kTestOfflineID2, archive2.offline_id);
+ EXPECT_EQ(kTestClientID2, archive2.client_id);
+ EXPECT_EQ(kTestURL2, archive2.url);
+ EXPECT_EQ(kTestFinalURL2, archive2.final_archived_url);
+ EXPECT_EQ(kTestTitle2, archive2.title);
+ EXPECT_EQ(kTestFilePath2, archive2.file_path);
+ EXPECT_EQ(kTestFileSize2, archive2.file_size);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/import_completed_task.cc b/chromium/components/offline_pages/core/prefetch/import_completed_task.cc
new file mode 100644
index 00000000000..1622b675dc0
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_completed_task.cc
@@ -0,0 +1,70 @@
+// 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/offline_pages/core/prefetch/import_completed_task.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+namespace {
+
+bool UpdateToFinishedStateSync(int64_t offline_id,
+ bool success,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = ?, error_code = ?"
+ " WHERE offline_id = ? AND state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(
+ 1, static_cast<int>(success ? PrefetchItemErrorCode::SUCCESS
+ : PrefetchItemErrorCode::IMPORT_ERROR));
+ statement.BindInt64(2, offline_id);
+ statement.BindInt(3, static_cast<int>(PrefetchItemState::IMPORTING));
+
+ return statement.Run();
+}
+
+} // namespace
+
+ImportCompletedTask::ImportCompletedTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ int64_t offline_id,
+ bool success)
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
+ offline_id_(offline_id),
+ success_(success),
+ weak_ptr_factory_(this) {}
+
+ImportCompletedTask::~ImportCompletedTask() {}
+
+void ImportCompletedTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&UpdateToFinishedStateSync, offline_id_, success_),
+ base::BindOnce(&ImportCompletedTask::OnStateUpdatedToFinished,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ImportCompletedTask::OnStateUpdatedToFinished(bool success) {
+ // No further action can be done if the database fails to be updated. The
+ // cleanup task should eventually kick in to clean this up.
+ if (success)
+ prefetch_dispatcher_->SchedulePipelineProcessing();
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/import_completed_task.h b/chromium/components/offline_pages/core/prefetch/import_completed_task.h
new file mode 100644
index 00000000000..a2ff66f7ea4
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_completed_task.h
@@ -0,0 +1,43 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_COMPLETED_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_COMPLETED_TASK_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Task that responses to the completed import.
+class ImportCompletedTask : public Task {
+ public:
+ ImportCompletedTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ int64_t offline_id,
+ bool success);
+ ~ImportCompletedTask() override;
+
+ void Run() override;
+
+ private:
+ void OnStateUpdatedToFinished(bool success);
+
+ PrefetchDispatcher* prefetch_dispatcher_; // Outlives this class.
+ PrefetchStore* prefetch_store_; // Outlives this class.
+ int64_t offline_id_;
+ bool success_;
+
+ base::WeakPtrFactory<ImportCompletedTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImportCompletedTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_IMPORT_COMPLETED_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/import_completed_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/import_completed_task_unittest.cc
new file mode 100644
index 00000000000..ee77855625d
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/import_completed_task_unittest.cc
@@ -0,0 +1,137 @@
+// 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/offline_pages/core/prefetch/import_completed_task.h"
+
+#include <string>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/prefetch/prefetch_importer.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+const int64_t kTestOfflineID = 1111;
+const int64_t kTestOfflineID2 = 223344;
+} // namespace
+
+class ImportCompletedTaskTest : public testing::Test {
+ public:
+ ImportCompletedTaskTest();
+ ~ImportCompletedTaskTest() override = default;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ void PumpLoop();
+
+ PrefetchStore* store() { return store_test_util_.store(); }
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+
+ private:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+ TestPrefetchDispatcher dispatcher_;
+ PrefetchStoreTestUtil store_test_util_;
+};
+
+ImportCompletedTaskTest::ImportCompletedTaskTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
+
+void ImportCompletedTaskTest::SetUp() {
+ store_test_util_.BuildStoreInMemory();
+
+ PrefetchItem item;
+ item.offline_id = kTestOfflineID;
+ item.state = PrefetchItemState::IMPORTING;
+ item.creation_time = base::Time::Now();
+ item.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item));
+
+ PrefetchItem item2;
+ item2.offline_id = kTestOfflineID2;
+ item2.state = PrefetchItemState::NEW_REQUEST;
+ item2.creation_time = base::Time::Now();
+ item2.freshness_time = item.creation_time;
+ EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item2));
+}
+
+void ImportCompletedTaskTest::TearDown() {
+ store_test_util_.DeleteStore();
+ PumpLoop();
+}
+
+void ImportCompletedTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+TEST_F(ImportCompletedTaskTest, ImportSuccess) {
+ ImportCompletedTask task(dispatcher(), store(), kTestOfflineID, true);
+ task.Run();
+ PumpLoop();
+
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::FINISHED, item->state);
+ EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, item->error_code);
+}
+
+TEST_F(ImportCompletedTaskTest, ImportError) {
+ ImportCompletedTask task(dispatcher(), store(), kTestOfflineID, false);
+ task.Run();
+ PumpLoop();
+
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::FINISHED, item->state);
+ EXPECT_EQ(PrefetchItemErrorCode::IMPORT_ERROR, item->error_code);
+}
+
+TEST_F(ImportCompletedTaskTest, NoUpdateOnMismatchedImportSuccess) {
+ ImportCompletedTask task(dispatcher(), store(), kTestOfflineID2, true);
+ task.Run();
+ PumpLoop();
+
+ // Item will only be updated when both guid and state match.
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::IMPORTING, item->state);
+
+ std::unique_ptr<PrefetchItem> item2 =
+ store_util()->GetPrefetchItem(kTestOfflineID2);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+}
+
+TEST_F(ImportCompletedTaskTest, NoUpdateOnMismatchedImportError) {
+ ImportCompletedTask task(dispatcher(), store(), kTestOfflineID2, false);
+ task.Run();
+ PumpLoop();
+
+ // Item will only be updated when both guid and state match.
+ std::unique_ptr<PrefetchItem> item =
+ store_util()->GetPrefetchItem(kTestOfflineID);
+ EXPECT_EQ(PrefetchItemState::IMPORTING, item->state);
+
+ std::unique_ptr<PrefetchItem> item2 =
+ store_util()->GetPrefetchItem(kTestOfflineID2);
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.cc b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.cc
new file mode 100644
index 00000000000..9d68ab9b8ab
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.cc
@@ -0,0 +1,89 @@
+// 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/offline_pages/core/prefetch/mark_operation_done_task.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+namespace {
+
+bool UpdatePrefetchItemsSync(sql::Connection* db,
+ const std::string& operation_name) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, freshness_time = ?"
+ " WHERE state = ? AND operation_name = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::RECEIVED_GCM));
+ statement.BindInt64(1, base::Time::Now().ToInternalValue());
+ statement.BindInt(2, static_cast<int>(PrefetchItemState::AWAITING_GCM));
+ statement.BindString(3, operation_name);
+
+ return statement.Run();
+}
+
+MarkOperationDoneTask::TaskResult MakeStoreError() {
+ return std::make_pair(MarkOperationDoneTask::StoreResult::STORE_ERROR, -1);
+}
+
+// Will hold the actual SQL implementation for marking a MarkOperationDone
+// attempt in the database.
+MarkOperationDoneTask::TaskResult MarkOperationCompletedOnServerSync(
+ const std::string& operation_name,
+ sql::Connection* db) {
+ if (!db)
+ return MakeStoreError();
+
+ sql::Transaction transaction(db);
+ if (transaction.Begin() && UpdatePrefetchItemsSync(db, operation_name) &&
+ transaction.Commit()) {
+ return std::make_pair(MarkOperationDoneTask::StoreResult::UPDATED,
+ db->GetLastChangeCount());
+ }
+ return MakeStoreError();
+}
+
+} // namespace
+
+MarkOperationDoneTask::MarkOperationDoneTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const std::string& operation_name)
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
+ operation_name_(operation_name),
+ weak_factory_(this) {}
+
+MarkOperationDoneTask::~MarkOperationDoneTask() {}
+
+void MarkOperationDoneTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&MarkOperationCompletedOnServerSync, operation_name_),
+ base::BindOnce(&MarkOperationDoneTask::Done, weak_factory_.GetWeakPtr()));
+}
+
+void MarkOperationDoneTask::Done(TaskResult result) {
+ result_ = result;
+
+ // We need to make sure we can process any work that was created by this event
+ // so we will ensure the task is scheudled.
+ if (change_count() > 0)
+ prefetch_dispatcher_->EnsureTaskScheduled();
+
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.h b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.h
new file mode 100644
index 00000000000..5ad22203652
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task.h
@@ -0,0 +1,68 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_MARK_OPERATION_DONE_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MARK_OPERATION_DONE_TASK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Event Handler Task that responds to GCM messages and marks the corresponding
+// operation as finished in the DB. This task then requests action tasks if any
+// urls were affected.
+class MarkOperationDoneTask : public Task {
+ public:
+ // StoreResult represents the overall status of executing the command in the
+ // SQL store.
+ enum class StoreResult {
+ UNFINISHED = 0,
+ UPDATED,
+ STORE_ERROR,
+ };
+
+ // TaskResult includes both a StoreResult and the number of rows that were
+ // affected by a successful SQL command.
+ using TaskResult = std::pair<StoreResult, int64_t>;
+
+ // TODO(dewittj): Schedule action tasks via "SchedulePipelineProcessing" if we
+ // are in a background task.
+ MarkOperationDoneTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
+ const std::string& operation_name);
+ ~MarkOperationDoneTask() override;
+
+ // Task implementation.
+ void Run() override;
+
+ StoreResult store_result() const { return std::get<0>(result_); }
+
+ // Number of rows changed, or -1 if there was a store error (or not yet
+ // finished).
+ int64_t change_count() const { return std::get<1>(result_); }
+
+ private:
+ void MarkOperationDone(int updated_entry_count);
+ void Done(TaskResult result);
+
+ PrefetchDispatcher* prefetch_dispatcher_;
+ PrefetchStore* prefetch_store_;
+ std::string operation_name_;
+ TaskResult result_ = std::make_pair(StoreResult::UNFINISHED, -1);
+
+ base::WeakPtrFactory<MarkOperationDoneTask> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MarkOperationDoneTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MARK_OPERATION_DONE_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc
new file mode 100644
index 00000000000..b32e524ec96
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc
@@ -0,0 +1,163 @@
+// 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/offline_pages/core/prefetch/mark_operation_done_task.h"
+
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
+#include "components/offline_pages/core/task.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+const char kOperationName[] = "an_operation";
+const char kOtherOperationName[] = "other_operation";
+
+// All tests cases here only validate the request data and check for general
+// http response. The tests for the Operation proto data returned in the http
+// response are covered in PrefetchRequestOperationResponseTest.
+class MarkOperationDoneTaskTest : public TaskTestBase {
+ public:
+ MarkOperationDoneTaskTest() = default;
+ ~MarkOperationDoneTaskTest() override = default;
+
+ void SetUp() override { TaskTestBase::SetUp(); }
+
+ int64_t InsertAwaitingGCMOperation(std::string name) {
+ return InsertPrefetchItemInStateWithOperation(
+ name, PrefetchItemState::AWAITING_GCM);
+ }
+
+ int64_t InsertPrefetchItemInStateWithOperation(std::string operation_name,
+ PrefetchItemState state) {
+ PrefetchItem item = item_generator()->CreateItem(state);
+ item.operation_name = operation_name;
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item));
+ return item.offline_id;
+ }
+
+ void ExpectStoreChangeCount(MarkOperationDoneTask* task,
+ int64_t change_count) {
+ EXPECT_EQ(MarkOperationDoneTask::StoreResult::UPDATED,
+ task->store_result());
+ EXPECT_EQ(change_count, task->change_count());
+ EXPECT_EQ(change_count > 0 ? 1 : 0, dispatcher()->task_schedule_count);
+ }
+
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+
+ private:
+ TestPrefetchDispatcher dispatcher_;
+};
+
+TEST_F(MarkOperationDoneTaskTest, NoOpTask) {
+ MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
+ ExpectTaskCompletes(&task);
+
+ task.Run();
+ RunUntilIdle();
+ ExpectStoreChangeCount(&task, 0);
+}
+
+TEST_F(MarkOperationDoneTaskTest, SingleMatchingURL) {
+ int64_t id = InsertAwaitingGCMOperation(kOperationName);
+ MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
+
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ ExpectStoreChangeCount(&task, 1);
+
+ EXPECT_EQ(1, store_util()->CountPrefetchItems());
+ ASSERT_TRUE(store_util()->GetPrefetchItem(id));
+ EXPECT_EQ(PrefetchItemState::RECEIVED_GCM,
+ store_util()->GetPrefetchItem(id)->state);
+}
+
+TEST_F(MarkOperationDoneTaskTest, NoSuchURLs) {
+ // Insert a record with an operation name.
+ int64_t id1 = InsertAwaitingGCMOperation(kOperationName);
+
+ // Start a task for an unrelated operation name.
+ MarkOperationDoneTask task(dispatcher(), store(), kOtherOperationName);
+
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ ExpectStoreChangeCount(&task, 0);
+
+ ASSERT_TRUE(store_util()->GetPrefetchItem(id1));
+ EXPECT_EQ(PrefetchItemState::AWAITING_GCM,
+ store_util()->GetPrefetchItem(id1)->state);
+}
+
+TEST_F(MarkOperationDoneTaskTest, ManyURLs) {
+ // Create 5 records with an operation name.
+ std::vector<int64_t> ids;
+ for (int i = 0; i < 5; i++) {
+ ids.push_back(InsertAwaitingGCMOperation(kOperationName));
+ }
+
+ // Insert a record with a different operation name.
+ int64_t id_other = InsertAwaitingGCMOperation(kOtherOperationName);
+
+ ASSERT_EQ(6, store_util()->CountPrefetchItems());
+
+ // Start a task for the first operation name.
+ MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
+
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ ExpectStoreChangeCount(&task, ids.size());
+
+ // The items should be in the new state.
+ for (int64_t id : ids) {
+ auto item = store_util()->GetPrefetchItem(id);
+ ASSERT_TRUE(item);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_GCM, item->state);
+ }
+
+ // The other item should not be changed.
+ ASSERT_TRUE(store_util()->GetPrefetchItem(id_other));
+ EXPECT_EQ(PrefetchItemState::AWAITING_GCM,
+ store_util()->GetPrefetchItem(id_other)->state);
+}
+
+TEST_F(MarkOperationDoneTaskTest, URLsInWrongState) {
+ std::vector<int64_t> ids;
+ ids.push_back(InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::SENT_GET_OPERATION));
+ ids.push_back(InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::RECEIVED_BUNDLE));
+ ids.push_back(InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::DOWNLOADING));
+ ids.push_back(InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::FINISHED));
+ ids.push_back(InsertPrefetchItemInStateWithOperation(
+ kOperationName, PrefetchItemState::ZOMBIE));
+
+ // Start a task for the first operation name.
+ MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
+
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ ExpectStoreChangeCount(&task, 0);
+
+ for (int64_t id : ids) {
+ ASSERT_TRUE(store_util()->GetPrefetchItem(id));
+ EXPECT_NE(PrefetchItemState::RECEIVED_GCM,
+ store_util()->GetPrefetchItem(id)->state);
+ }
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.cc b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.cc
new file mode 100644
index 00000000000..449d2915e6b
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.cc
@@ -0,0 +1,231 @@
+// 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/offline_pages/core/prefetch/metrics_finalization_task.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+namespace {
+
+// In-memory representation of URL metadata fetched from SQLite storage.
+struct PrefetchItemStats {
+ PrefetchItemStats(int64_t offline_id,
+ int generate_bundle_attempts,
+ int get_operation_attempts,
+ int download_initiation_attempts,
+ int64_t archive_body_length,
+ base::Time creation_time,
+ PrefetchItemErrorCode error_code,
+ int64_t file_size)
+ : offline_id(offline_id),
+ generate_bundle_attempts(generate_bundle_attempts),
+ get_operation_attempts(get_operation_attempts),
+ download_initiation_attempts(download_initiation_attempts),
+ archive_body_length(archive_body_length),
+ creation_time(creation_time),
+ error_code(error_code),
+ file_size(file_size) {}
+
+ int64_t offline_id;
+ int generate_bundle_attempts;
+ int get_operation_attempts;
+ int download_initiation_attempts;
+ int64_t archive_body_length;
+ base::Time creation_time;
+ PrefetchItemErrorCode error_code;
+ int64_t file_size;
+};
+
+std::vector<PrefetchItemStats> FetchUrlsSync(sql::Connection* db) {
+ static const char kSql[] = R"(
+ SELECT offline_id, generate_bundle_attempts, get_operation_attempts,
+ download_initiation_attempts, archive_body_length, creation_time,
+ error_code, file_size
+ FROM prefetch_items
+ WHERE state = ?
+)";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+
+ std::vector<PrefetchItemStats> urls;
+ while (statement.Step()) {
+ urls.emplace_back(
+ statement.ColumnInt64(0), // offline_id
+ statement.ColumnInt(1), // generate_bundle_attempts
+ statement.ColumnInt(2), // get_operation_attempts
+ statement.ColumnInt(3), // download_initiation_attempts
+ statement.ColumnInt64(4), // archive_body_length
+ FromDatabaseTime(statement.ColumnInt64(5)), // creation_time
+ static_cast<PrefetchItemErrorCode>(
+ statement.ColumnInt(6)), // error_code
+ statement.ColumnInt64(7) // file_size
+ );
+ }
+
+ return urls;
+}
+
+bool MarkUrlAsZombie(sql::Connection* db,
+ base::Time freshness_time,
+ int64_t offline_id) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, freshness_time = ? WHERE "
+ "offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::ZOMBIE));
+ statement.BindInt(1, ToDatabaseTime(freshness_time));
+ statement.BindInt64(2, offline_id);
+ return statement.Run();
+}
+
+// These constants represent important indexes in the
+// OfflinePrefetchArchiveActualSizeVsExpected histogram enum.
+const int kEnumZeroArchiveBodyLength = 0;
+const int kEnumRange0To100Min = 1;
+const int kEnumRange0To100Max = 10;
+const int kEnumSizeMatches100 = 11;
+const int kEnumRange100To200OrMoreMin = 12;
+const int kEnumRange100To200OrMoreMax = 22;
+
+// Value meaning the file size should not be reported (not a valid index in the
+// OfflinePrefetchArchiveActualSizeVsExpected enum).
+const int kShouldNotReportFileSize = -1;
+
+// Returned values conform to the definition of the
+// OfflinePrefetchArchiveActualSizeVsExpected histogram enum. Except for -1
+// which means "do not report".
+int GetFileSizeEnumValueFor(int64_t archive_body_length, int64_t file_size) {
+ // Archiving service reported body length as zero.
+ if (archive_body_length == 0)
+ return kEnumZeroArchiveBodyLength;
+
+ // For other cases, reporting should only happen if both size values were set
+ // meaning the item reached at least the successfully downloaded state.
+ if (archive_body_length < 0 || file_size < 0)
+ return kShouldNotReportFileSize;
+
+ if (archive_body_length == file_size)
+ return kEnumSizeMatches100;
+
+ // For smaller sizes than expected, return an index in the 0% <= ratio < 100%
+ // range.
+ double ratio = static_cast<double>(file_size) / archive_body_length;
+ if (archive_body_length > file_size) {
+ return std::max(
+ kEnumRange0To100Min,
+ std::min(kEnumRange0To100Max, static_cast<int>(ratio * 10) + 1));
+ }
+
+ // Otherwise return an index in the 100% < ratio range.
+ return std::max(
+ kEnumRange100To200OrMoreMin,
+ std::min(kEnumRange100To200OrMoreMax, static_cast<int>(ratio * 10) + 2));
+}
+
+void ReportMetricsFor(const PrefetchItemStats& url, const base::Time now) {
+ // Lifetime reporting.
+ static const int kFourWeeksInSeconds =
+ base::TimeDelta::FromDays(28).InSeconds();
+ const bool successful = url.error_code == PrefetchItemErrorCode::SUCCESS;
+ int64_t lifetime_seconds = (now - url.creation_time).InSeconds();
+ if (successful) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "OfflinePages.Prefetching.ItemLifetime.Successful", lifetime_seconds, 1,
+ kFourWeeksInSeconds, 50);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.Prefetching.ItemLifetime.Failed",
+ lifetime_seconds, 1, kFourWeeksInSeconds, 50);
+ }
+
+ // Error code reporting.
+ UMA_HISTOGRAM_SPARSE_SLOWLY("OfflinePages.Prefetching.FinishedItemErrorCode",
+ static_cast<int>(url.error_code));
+
+ // Unexpected file size reporting.
+ int file_size_enum_value =
+ GetFileSizeEnumValueFor(url.archive_body_length, url.file_size);
+ if (file_size_enum_value != kShouldNotReportFileSize) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected",
+ file_size_enum_value, kEnumRange100To200OrMoreMax);
+ }
+
+ // Attempt counts reporting.
+ static const int kMaxPossibleRetries = 20;
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GeneratePageBundle",
+ url.generate_bundle_attempts, kMaxPossibleRetries);
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GetOperation",
+ url.get_operation_attempts, kMaxPossibleRetries);
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ "OfflinePages.Prefetching.ActionRetryAttempts.DownloadInitiation",
+ url.download_initiation_attempts, kMaxPossibleRetries);
+}
+
+bool ReportMetricsAndFinalizeSync(sql::Connection* db) {
+ if (!db)
+ return false;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+
+ const std::vector<PrefetchItemStats> urls = FetchUrlsSync(db);
+
+ base::Time now = base::Time::Now();
+ for (const auto& url : urls) {
+ MarkUrlAsZombie(db, now, url.offline_id);
+ }
+
+ if (transaction.Commit()) {
+ for (const auto& url : urls) {
+ DVLOG(1) << "Finalized prefetch item: (" << url.offline_id << ", "
+ << url.generate_bundle_attempts << ", "
+ << url.get_operation_attempts << ", "
+ << url.download_initiation_attempts << ", "
+ << url.archive_body_length << ", " << url.creation_time << ", "
+ << static_cast<int>(url.error_code) << ", " << url.file_size
+ << ")";
+ ReportMetricsFor(url, now);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+MetricsFinalizationTask::MetricsFinalizationTask(PrefetchStore* prefetch_store)
+ : prefetch_store_(prefetch_store), weak_factory_(this) {}
+
+MetricsFinalizationTask::~MetricsFinalizationTask() {}
+
+void MetricsFinalizationTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&ReportMetricsAndFinalizeSync),
+ base::BindOnce(&MetricsFinalizationTask::MetricsFinalized,
+ weak_factory_.GetWeakPtr()));
+}
+
+void MetricsFinalizationTask::MetricsFinalized(bool result) {
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.h b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.h
new file mode 100644
index 00000000000..f8a2e8a04b2
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task.h
@@ -0,0 +1,38 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_METRICS_FINALIZATION_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_METRICS_FINALIZATION_TASK_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchStore;
+
+// Prefetching task that takes finished PrefetchItems, records interesting
+// metrics about the final status, and marks them as zombies. Zombies are
+// cleaned up when suggestions are updated and there are no more
+// suggestions at the |requested_url|.
+class MetricsFinalizationTask : public Task {
+ public:
+ explicit MetricsFinalizationTask(PrefetchStore* prefetch_store);
+ ~MetricsFinalizationTask() override;
+
+ // Task implementation.
+ void Run() override;
+
+ private:
+ void MetricsFinalized(bool result);
+
+ PrefetchStore* prefetch_store_;
+
+ base::WeakPtrFactory<MetricsFinalizationTask> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(MetricsFinalizationTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_METRICS_FINALIZATION_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc
new file mode 100644
index 00000000000..ecdf30f1e24
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc
@@ -0,0 +1,253 @@
+// 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/offline_pages/core/prefetch/metrics_finalization_task.h"
+
+#include <set>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/histogram_tester.h"
+#include "components/offline_pages/core/prefetch/mock_prefetch_item_generator.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+class MetricsFinalizationTaskTest : public TaskTestBase {
+ public:
+ MetricsFinalizationTaskTest() = default;
+ ~MetricsFinalizationTaskTest() override = default;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ std::unique_ptr<MetricsFinalizationTask> metrics_finalization_task_;
+};
+
+void MetricsFinalizationTaskTest::SetUp() {
+ TaskTestBase::SetUp();
+ metrics_finalization_task_ =
+ base::MakeUnique<MetricsFinalizationTask>(store());
+}
+
+void MetricsFinalizationTaskTest::TearDown() {
+ metrics_finalization_task_.reset();
+ TaskTestBase::TearDown();
+}
+
+// Tests that the task works correctly with an empty database.
+TEST_F(MetricsFinalizationTaskTest, EmptyRun) {
+ EXPECT_EQ(0, store_util()->CountPrefetchItems());
+
+ // Execute the metrics task.
+ ExpectTaskCompletes(metrics_finalization_task_.get());
+ metrics_finalization_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(0, store_util()->CountPrefetchItems());
+}
+
+// Verifies that expired and non-expired items from all expirable states are
+// properly handled.
+TEST_F(MetricsFinalizationTaskTest, LeavesOtherStatesAlone) {
+ // Insert fresh and stale items for all expirable states from all buckets.
+ std::vector<PrefetchItemState> all_states_but_finished = {
+ PrefetchItemState::NEW_REQUEST,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE,
+ PrefetchItemState::AWAITING_GCM,
+ PrefetchItemState::RECEIVED_GCM,
+ PrefetchItemState::SENT_GET_OPERATION,
+ PrefetchItemState::RECEIVED_BUNDLE,
+ PrefetchItemState::DOWNLOADING,
+ PrefetchItemState::DOWNLOADED,
+ PrefetchItemState::IMPORTING,
+ PrefetchItemState::ZOMBIE,
+ };
+
+ for (auto& state : all_states_but_finished) {
+ PrefetchItem item = item_generator()->CreateItem(state);
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item))
+ << "Failed inserting item with state " << static_cast<int>(state);
+ }
+
+ std::set<PrefetchItem> all_inserted_items;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&all_inserted_items));
+
+ // Execute the task.
+ ExpectTaskCompletes(metrics_finalization_task_.get());
+ metrics_finalization_task_->Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> all_items_after_task;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&all_items_after_task));
+ EXPECT_EQ(all_inserted_items, all_items_after_task);
+}
+
+TEST_F(MetricsFinalizationTaskTest, FinalizesMultipleItems) {
+ std::set<PrefetchItem> finished_items = {
+ item_generator()->CreateItem(PrefetchItemState::FINISHED),
+ item_generator()->CreateItem(PrefetchItemState::FINISHED),
+ item_generator()->CreateItem(PrefetchItemState::FINISHED)};
+
+ PrefetchItem unfinished_item =
+ item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
+
+ for (auto& item : finished_items) {
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+ }
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(unfinished_item));
+
+ // Execute the metrics task.
+ ExpectTaskCompletes(metrics_finalization_task_.get());
+ metrics_finalization_task_->Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> all_items;
+ // The finished ones should be zombies and the new request should be
+ // untouched.
+ EXPECT_EQ(4U, store_util()->GetAllItems(&all_items));
+ EXPECT_EQ(0U, FilterByState(all_items, PrefetchItemState::FINISHED).size());
+ EXPECT_EQ(3U, FilterByState(all_items, PrefetchItemState::ZOMBIE).size());
+
+ std::set<PrefetchItem> items_in_new_request_state =
+ FilterByState(all_items, PrefetchItemState::NEW_REQUEST);
+ EXPECT_EQ(1U, items_in_new_request_state.count(unfinished_item));
+}
+
+TEST_F(MetricsFinalizationTaskTest, MetricsAreReported) {
+ PrefetchItem successful_item =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ successful_item.generate_bundle_attempts = 1;
+ successful_item.get_operation_attempts = 1;
+ successful_item.download_initiation_attempts = 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(successful_item));
+
+ PrefetchItem failed_item =
+ item_generator()->CreateItem(PrefetchItemState::RECEIVED_GCM);
+ failed_item.state = PrefetchItemState::FINISHED;
+ failed_item.error_code = PrefetchItemErrorCode::ARCHIVING_FAILED;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(failed_item));
+
+ PrefetchItem unfinished_item =
+ item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(unfinished_item));
+
+ // Execute the metrics task.
+ base::HistogramTester histogram_tester;
+ ExpectTaskCompletes(metrics_finalization_task_.get());
+ metrics_finalization_task_->Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> all_items;
+ EXPECT_EQ(3U, store_util()->GetAllItems(&all_items));
+ EXPECT_EQ(2U, FilterByState(all_items, PrefetchItemState::ZOMBIE).size());
+ EXPECT_EQ(1U,
+ FilterByState(all_items, PrefetchItemState::NEW_REQUEST).size());
+
+ // One successful and one failed samples.
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.Prefetching.ItemLifetime.Successful", 0, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.Prefetching.ItemLifetime.Failed", 0, 1);
+
+ // One sample for each_error code value.
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.Prefetching.FinishedItemErrorCode", 2);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.FinishedItemErrorCode",
+ static_cast<int>(PrefetchItemErrorCode::SUCCESS), 1);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.FinishedItemErrorCode",
+ static_cast<int>(PrefetchItemErrorCode::ARCHIVING_FAILED), 1);
+
+ // One sample at the "size matches (100%)" bucket.
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 11, 1);
+
+ // Attempt values match what was set above (non set values default to 0).
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GeneratePageBundle", 2);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GeneratePageBundle", 0, 1);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GeneratePageBundle", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GetOperation", 2);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GetOperation", 0, 1);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.GetOperation", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.DownloadInitiation", 2);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.DownloadInitiation", 0, 1);
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.ActionRetryAttempts.DownloadInitiation", 1, 1);
+}
+
+TEST_F(MetricsFinalizationTaskTest, FileSizeMetricsAreReportedCorrectly) {
+ PrefetchItem zero_body_length =
+ item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+ zero_body_length.state = PrefetchItemState::FINISHED;
+ zero_body_length.archive_body_length = 0;
+ zero_body_length.file_size = -1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(zero_body_length));
+
+ PrefetchItem smaller_than_expected =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ smaller_than_expected.archive_body_length = 1000;
+ smaller_than_expected.file_size = 999;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(smaller_than_expected));
+
+ PrefetchItem sizes_match =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ sizes_match.archive_body_length = 1000;
+ sizes_match.file_size = 1000;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(sizes_match));
+
+ PrefetchItem larger_than_expected =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ larger_than_expected.archive_body_length = 1000;
+ larger_than_expected.file_size = 1001;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(larger_than_expected));
+
+ PrefetchItem much_larger_than_expected =
+ item_generator()->CreateItem(PrefetchItemState::FINISHED);
+ much_larger_than_expected.archive_body_length = 1000;
+ much_larger_than_expected.file_size = 10000;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(much_larger_than_expected));
+
+ // Execute the metrics task.
+ base::HistogramTester histogram_tester;
+ ExpectTaskCompletes(metrics_finalization_task_.get());
+ metrics_finalization_task_->Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> all_items;
+ EXPECT_EQ(5U, store_util()->GetAllItems(&all_items));
+ EXPECT_EQ(5U, FilterByState(all_items, PrefetchItemState::ZOMBIE).size());
+
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 5);
+ // One sample at the "archive_body_length = 0" bucket.
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 0, 1);
+ // One sample at the "90% to 100%" bucket.
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 10, 1);
+ // One sample at the "size matches (100%)" bucket.
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 11, 1);
+ // One sample at the "100% to 110%" bucket.
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 12, 1);
+ // One sample at the "above 200%" bucket.
+ histogram_tester.ExpectBucketCount(
+ "OfflinePages.Prefetching.DownloadedArchiveSizeVsExpected", 22, 1);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.cc b/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.cc
new file mode 100644
index 00000000000..130f123bbfa
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.cc
@@ -0,0 +1,118 @@
+// 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/offline_pages/core/prefetch/mock_prefetch_item_generator.h"
+
+#include "base/files/file_path.h"
+#include "base/guid.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/offline_pages/core/client_id.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+// All static.
+const std::string MockPrefetchItemGenerator::kClientNamespace(
+ "test_prefetch_namespace");
+const std::string MockPrefetchItemGenerator::kClientIdPrefix("test_client_id_");
+const std::string MockPrefetchItemGenerator::kUrlPrefix(
+ "http://www.requested.com/");
+const std::string MockPrefetchItemGenerator::kFinalUrlPrefix(
+ "http://www.final.com/");
+const std::string MockPrefetchItemGenerator::kOperationNamePrefix(
+ "test_operation_name_");
+const std::string MockPrefetchItemGenerator::kArchiveBodyNamePrefix(
+ "test_archive_body_name_");
+const std::string MockPrefetchItemGenerator::kTitlePrefix("test_title_");
+const std::string MockPrefetchItemGenerator::kFilePathPrefix("test_file_path_");
+
+MockPrefetchItemGenerator::MockPrefetchItemGenerator() = default;
+
+MockPrefetchItemGenerator::~MockPrefetchItemGenerator() = default;
+
+PrefetchItem MockPrefetchItemGenerator::CreateItem(PrefetchItemState state) {
+ static int item_counter = 0;
+ ++item_counter;
+ PrefetchItem new_item;
+
+ // Values set with non prefix based values.
+ new_item.state = state;
+ new_item.offline_id = GenerateTestOfflineId();
+ new_item.creation_time = base::Time::Now();
+ new_item.freshness_time = new_item.creation_time;
+
+ // Values always set using prefixes.
+ CHECK(client_namespace_.length());
+ new_item.client_id = ClientId(
+ client_namespace_, client_id_prefix_ + base::IntToString(item_counter));
+ new_item.url = GURL(url_prefix_ + base::IntToString(item_counter));
+
+ if (title_prefix_.length()) {
+ new_item.title =
+ base::UTF8ToUTF16(title_prefix_ + base::IntToString(item_counter));
+ }
+
+ if (state == PrefetchItemState::NEW_REQUEST ||
+ state == PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE) {
+ return new_item;
+ }
+
+ if (operation_name_prefix_.length()) {
+ new_item.operation_name =
+ operation_name_prefix_ + base::IntToString(item_counter);
+ }
+
+ if (state == PrefetchItemState::AWAITING_GCM ||
+ state == PrefetchItemState::RECEIVED_GCM ||
+ state == PrefetchItemState::SENT_GET_OPERATION) {
+ return new_item;
+ }
+
+ if (archive_body_name_prefix_.length()) {
+ new_item.archive_body_name =
+ archive_body_name_prefix_ + base::IntToString(item_counter);
+ new_item.archive_body_length = item_counter * 100;
+ }
+ if (final_url_prefix_.length()) {
+ new_item.final_archived_url =
+ GURL(final_url_prefix_ + base::IntToString(item_counter));
+ }
+
+ if (state == PrefetchItemState::RECEIVED_BUNDLE)
+ return new_item;
+
+ new_item.guid = base::GenerateGUID();
+ if (file_path_prefix_.length()) {
+ new_item.file_path = base::FilePath::FromUTF8Unsafe(
+ file_path_prefix_ + base::IntToString(item_counter));
+ }
+
+ if (state == PrefetchItemState::DOWNLOADING) {
+ return new_item;
+ }
+
+ new_item.file_size = new_item.archive_body_length;
+
+ if (state == PrefetchItemState::DOWNLOADED ||
+ state == PrefetchItemState::IMPORTING ||
+ state == PrefetchItemState::FINISHED ||
+ state == PrefetchItemState::ZOMBIE) {
+ return new_item;
+ }
+
+ // This code should explicitly account for all states so adding a new one will
+ // cause this to crash in debug mode.
+ NOTREACHED();
+
+ return new_item;
+}
+
+int64_t MockPrefetchItemGenerator::GenerateTestOfflineId() {
+ return ++offline_id_counter_;
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.h b/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.h
new file mode 100644
index 00000000000..fef45c673e6
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/mock_prefetch_item_generator.h
@@ -0,0 +1,90 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_MOCK_PREFETCH_ITEM_GENERATOR_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MOCK_PREFETCH_ITEM_GENERATOR_H_
+
+#include <string>
+
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+
+namespace offline_pages {
+
+// Generator of PrefetchItem instances with all fields automatically
+// pre-populated with values that are reasonable and unique (within the
+// instance). To further customize returned items one can set custom prefixes or
+// just change the actual values of returned instances. When creating an item
+// with a particular state, only the fields applicable to that state will be
+// populated, and the rest will remain in their default state, even if prefixes
+// are set for that data member.
+class MockPrefetchItemGenerator {
+ public:
+ static const std::string kClientNamespace;
+ static const std::string kClientIdPrefix;
+ static const std::string kUrlPrefix;
+ static const std::string kFinalUrlPrefix;
+ static const std::string kOperationNamePrefix;
+ static const std::string kArchiveBodyNamePrefix;
+ static const std::string kTitlePrefix;
+ static const std::string kFilePathPrefix;
+
+ MockPrefetchItemGenerator();
+ ~MockPrefetchItemGenerator();
+
+ // Creates a new item using all set prefixes and an internal counter to set
+ // reasonable and unique values to all fields including the instance-unique
+ // offline ID.
+ PrefetchItem CreateItem(PrefetchItemState state);
+
+ // Generates a unique offline ID within the context of this generator
+ // instance. Values will not be unique among different instances.
+ int64_t GenerateTestOfflineId();
+
+ // Setters for all prefixes.
+ void set_client_namespace(std::string client_namespace) {
+ client_namespace_ = client_namespace;
+ }
+ void set_client_id_prefix(std::string client_id_prefix) {
+ client_id_prefix_ = client_id_prefix;
+ }
+ void set_url_prefix(std::string url_prefix) { url_prefix_ = url_prefix; }
+ void set_final_url_prefix(std::string final_url_prefix) {
+ final_url_prefix_ = final_url_prefix;
+ }
+ void set_operation_name_prefix(std::string operation_name_prefix) {
+ operation_name_prefix_ = operation_name_prefix;
+ }
+ void set_archive_body_name_prefix(std::string archive_body_name_prefix) {
+ archive_body_name_prefix_ = archive_body_name_prefix;
+ }
+ void set_title_prefix(std::string title_prefix) {
+ title_prefix_ = title_prefix;
+ }
+ void set_file_path_prefix(std::string file_path_prefix) {
+ file_path_prefix_ = file_path_prefix;
+ }
+
+ private:
+ // These namespace name and prefixes must always be set.
+ std::string client_namespace_ = kClientNamespace;
+ std::string client_id_prefix_ = kClientIdPrefix;
+ std::string url_prefix_ = kUrlPrefix;
+
+ // These prefixes, if custom set to the empty string, will cause related
+ // values not to be set.
+ std::string final_url_prefix_ = kFinalUrlPrefix;
+ std::string operation_name_prefix_ = kOperationNamePrefix;
+ std::string archive_body_name_prefix_ = kArchiveBodyNamePrefix;
+ std::string title_prefix_ = kTitlePrefix;
+ std::string file_path_prefix_ = kFilePathPrefix;
+
+ // Test offline IDs start at an arbitrary, non-zero value to ease recognizing
+ // generated ID values among other integer values while debugging.
+ int64_t offline_id_counter_ = 1000;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MOCK_PREFETCH_ITEM_GENERATOR_H_
diff --git a/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.cc b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.cc
new file mode 100644
index 00000000000..e80240adc41
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.cc
@@ -0,0 +1,200 @@
+// 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/offline_pages/core/prefetch/page_bundle_update_task.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+using PageBundleUpdateResult = PageBundleUpdateTask::PageBundleUpdateResult;
+
+namespace {
+
+// Marks a successfully rendered URL as having received the bundle, and returns
+// whether any records matched the given RenderPageInfo.
+bool MarkUrlRenderedSync(sql::Connection* db,
+ const RenderPageInfo& page,
+ const std::string& operation_name) {
+ DCHECK_EQ(page.status, RenderStatus::RENDERED);
+
+ // If the operation name is empty, then we assume this is from a
+ // GeneratePageBundle request, so we don't need to match because the incoming
+ // operation name is the new operation name for unfinished entries in the
+ // newest batch.
+ static const char kSql[] = R"(UPDATE prefetch_items
+ SET state = ?,
+ final_archived_url = ?,
+ archive_body_name = ?,
+ archive_body_length = ?
+ WHERE requested_url = ? AND (
+ (state = ? AND operation_name = "") OR
+ (state = ? AND operation_name = ?)
+ )
+ )";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ DCHECK(statement.is_valid());
+
+ std::string final_url = page.redirect_url;
+ if (final_url == page.url)
+ final_url = "";
+
+ // SET
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::RECEIVED_BUNDLE));
+ statement.BindString(1, final_url);
+ statement.BindString(2, page.body_name);
+ statement.BindInt64(3, page.body_length);
+
+ // WHERE
+ statement.BindString(4, page.url);
+ statement.BindInt(
+ 5, static_cast<int>(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE));
+ statement.BindInt(6, static_cast<int>(PrefetchItemState::SENT_GET_OPERATION));
+ statement.BindString(7, operation_name);
+
+ if (!statement.Run())
+ return false;
+
+ return db->GetLastChangeCount() > 0;
+}
+
+// Marks a URL that failed to render as finished.
+void MarkUrlFailedSync(sql::Connection* db,
+ const RenderPageInfo& page,
+ const std::string& operation_name,
+ PrefetchItemErrorCode final_status) {
+ DCHECK_NE(page.status, RenderStatus::RENDERED);
+
+ static const char kSql[] = R"(UPDATE prefetch_items
+ SET state = ?,
+ error_code = ?
+ WHERE requested_url = ? AND (
+ (state = ? AND operation_name = "") OR
+ (state = ? AND operation_name = ?)
+ )
+ )";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ DCHECK(statement.is_valid());
+
+ std::string final_url = page.redirect_url;
+ if (final_url.empty())
+ final_url = page.url;
+
+ // SET
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(1, static_cast<int>(final_status));
+
+ // WHERE
+ statement.BindString(2, page.url);
+ statement.BindInt(
+ 3, static_cast<int>(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE));
+ statement.BindInt(4, static_cast<int>(PrefetchItemState::SENT_GET_OPERATION));
+ statement.BindString(5, operation_name);
+
+ statement.Run();
+}
+
+// Marks URLs known to be PENDING as awaiting GCM.
+void MarkAwaitingGCMSync(sql::Connection* db,
+ const RenderPageInfo& page,
+ const std::string& operation_name) {
+ static const char kSql[] = R"(UPDATE prefetch_items
+ SET state = ?,
+ operation_name = ?
+ WHERE state = ? AND requested_url = ?
+ )";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ DCHECK(statement.is_valid());
+
+ // SET
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::AWAITING_GCM));
+ statement.BindString(1, operation_name);
+
+ // WHERE
+ statement.BindInt(
+ 2, static_cast<int>(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE));
+ statement.BindString(3, page.url);
+
+ statement.Run();
+}
+
+// Individually updates all pages for the given operation
+PageBundleUpdateResult UpdateWithOperationResultsSync(
+ const std::string operation_name,
+ const std::vector<RenderPageInfo>& pages,
+ sql::Connection* db) {
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+
+ bool schedule_pipeline_processing = false;
+
+ for (auto& page : pages) {
+ switch (page.status) {
+ case RenderStatus::RENDERED:
+ if (MarkUrlRenderedSync(db, page, operation_name))
+ schedule_pipeline_processing = true;
+ break;
+ case RenderStatus::FAILED:
+ MarkUrlFailedSync(db, page, operation_name,
+ PrefetchItemErrorCode::ARCHIVING_FAILED);
+ break;
+ case RenderStatus::EXCEEDED_LIMIT:
+ MarkUrlFailedSync(db, page, operation_name,
+ PrefetchItemErrorCode::ARCHIVING_LIMIT_EXCEEDED);
+ break;
+ case RenderStatus::PENDING:
+ MarkAwaitingGCMSync(db, page, operation_name);
+ break;
+ }
+ }
+
+ return transaction.Commit() && schedule_pipeline_processing;
+}
+
+} // namespace
+
+PageBundleUpdateTask::PageBundleUpdateTask(
+ PrefetchStore* store,
+ PrefetchDispatcher* dispatcher,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages)
+ : store_(store),
+ dispatcher_(dispatcher),
+ operation_name_(operation_name),
+ pages_(pages),
+ weak_factory_(this) {
+ DCHECK(store_);
+}
+
+PageBundleUpdateTask::~PageBundleUpdateTask() = default;
+
+void PageBundleUpdateTask::Run() {
+ store_->Execute(
+ base::BindOnce(&UpdateWithOperationResultsSync, operation_name_, pages_),
+ base::BindOnce(&PageBundleUpdateTask::FinishedWork,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PageBundleUpdateTask::FinishedWork(
+ PageBundleUpdateResult needs_pipeline_processing) {
+ if (needs_pipeline_processing)
+ dispatcher_->SchedulePipelineProcessing();
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.h b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.h
new file mode 100644
index 00000000000..88ca890b861
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task.h
@@ -0,0 +1,68 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_PAGE_BUNDLE_UPDATE_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PAGE_BUNDLE_UPDATE_TASK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Task that writes down the result of a prefetch networking operation and
+// optionally schedules action tasks. Results in the form of |operation_name|
+// and vector of |RenderPageInfo| are provided in both GetOperation and
+// GeneratePageBundle responses.
+//
+// This task does 3 things:
+// - Any pages in the |pages| list that have succeeded are updated to
+// RECEIVED_BUNDLE and body name / length are updated.
+// - Any pages in the |pages| list that failed are updated to FINISHED
+// with the ARCHIVING_FAILED error code.
+// - Any pages in the result that are "Pending" and match rows with an
+// empty operation name will update to AWAITING_GCM and save the
+// operation name.
+// - Pages in the SENT_GENERATE_PAGE_BUNDLE or SENT_GET_OPERATION state but that
+// are not reflected in the |pages| list are ignored, and will be cleaned up
+// by reconcilers if necessary.
+class PageBundleUpdateTask : public Task {
+ public:
+ // The result is whether we need more action tasks to run right now.
+ using PageBundleUpdateResult = bool;
+
+ PageBundleUpdateTask(PrefetchStore* store,
+ PrefetchDispatcher* dispatcher,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages);
+ ~PageBundleUpdateTask() override;
+
+ // Task implementation.
+ void Run() override;
+
+ private:
+ void FinishedWork(PageBundleUpdateResult result);
+
+ // Owned by PrefetchService which also transitively owns |this|, so raw
+ // pointer is OK.
+ PrefetchStore* store_;
+ // PrefetchDispatcher owns the task queue which owns |this|, so raw pointer is
+ // OK.
+ PrefetchDispatcher* dispatcher_;
+ std::string operation_name_;
+ std::vector<RenderPageInfo> pages_;
+
+ base::WeakPtrFactory<PageBundleUpdateTask> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageBundleUpdateTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PAGE_BUNDLE_UPDATE_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc
new file mode 100644
index 00000000000..608ed57dd8f
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc
@@ -0,0 +1,250 @@
+// 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/offline_pages/core/prefetch/page_bundle_update_task.h"
+
+#include "base/logging.h"
+#include "base/test/mock_callback.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "components/offline_pages/core/task.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::HasSubstr;
+
+namespace offline_pages {
+
+class PageBundleUpdateTaskTest : public TaskTestBase {
+ public:
+ PageBundleUpdateTaskTest() = default;
+ ~PageBundleUpdateTaskTest() override = default;
+
+ TestPrefetchDispatcher dispatcher;
+
+ RenderPageInfo FailedPageInfoForPrefetchItem(const PrefetchItem& item) {
+ RenderPageInfo rv;
+
+ rv.url = item.url.spec();
+ rv.status = RenderStatus::FAILED;
+ return rv;
+ }
+
+ RenderPageInfo PendingPageInfoForPrefetchItem(const PrefetchItem& item) {
+ RenderPageInfo rv;
+
+ rv.url = item.url.spec();
+ rv.status = RenderStatus::PENDING;
+ return rv;
+ }
+
+ RenderPageInfo RenderedPageInfoForPrefetchItem(const PrefetchItem& item) {
+ RenderPageInfo rv;
+
+ rv.url = item.url.spec();
+ rv.status = RenderStatus::RENDERED;
+ rv.body_name = std::to_string(++body_name_count_);
+ rv.body_length = 1024 + body_name_count_; // a realistic number of bytes
+
+ rv.render_time = base::Time::Now();
+ return rv;
+ }
+
+ private:
+ int body_name_count_ = 0;
+};
+
+TEST_F(PageBundleUpdateTaskTest, EmptyTask) {
+ PageBundleUpdateTask task(store(), &dispatcher, "operation", {});
+ ExpectTaskCompletes(&task);
+
+ task.Run();
+ RunUntilIdle();
+ EXPECT_EQ(0, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, UpdatesItemsFromSentGeneratePageBundle) {
+ // Tests that SENT_GENERATE_PAGE_BUNDLE can correctly transition pages to
+ // RECEIVED_BUNDLE.
+ PrefetchItem item1 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_EQ("", item1.operation_name);
+ PrefetchItem item2 =
+ item_generator()->CreateItem(PrefetchItemState::AWAITING_GCM);
+ ASSERT_NE("", item2.operation_name);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item1));
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item2));
+ ASSERT_EQ(2, store_util()->CountPrefetchItems());
+
+ // We assume that the bundle contains items for two entries, but one of those
+ // entries is not in the correct state to be updated (different operation
+ // name).
+ PageBundleUpdateTask task(store(), &dispatcher, "operation",
+ {
+ RenderedPageInfoForPrefetchItem(item1),
+ RenderedPageInfoForPrefetchItem(item2),
+ });
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ // The matching entry has been updated.
+ EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE,
+ store_util()->GetPrefetchItem(item1.offline_id)->state);
+ EXPECT_NE("",
+ store_util()->GetPrefetchItem(item1.offline_id)->archive_body_name);
+ EXPECT_LT(
+ 0, store_util()->GetPrefetchItem(item1.offline_id)->archive_body_length);
+ // The non-matching entry has not changed.
+ EXPECT_EQ(item2, *(store_util()->GetPrefetchItem(item2.offline_id)));
+ // The dispatcher knows to reschedule the action tasks.
+ EXPECT_LE(1, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, SentGetOperationToReceivedBundle) {
+ PrefetchItem item1 =
+ item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
+ ASSERT_EQ("", item1.archive_body_name);
+ ASSERT_EQ(-1, item1.archive_body_length);
+
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item1));
+
+ PageBundleUpdateTask task(store(), &dispatcher, item1.operation_name,
+ {
+ RenderedPageInfoForPrefetchItem(item1),
+ });
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ // The matching entry has been updated.
+ EXPECT_EQ(store_util()->GetPrefetchItem(item1.offline_id)->state,
+ PrefetchItemState::RECEIVED_BUNDLE);
+ EXPECT_NE("",
+ store_util()->GetPrefetchItem(item1.offline_id)->archive_body_name);
+ EXPECT_LT(
+ 0, store_util()->GetPrefetchItem(item1.offline_id)->archive_body_length);
+ EXPECT_LE(1, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, UrlDoesNotMatch) {
+ // Tests that no change happens if the URLs passed into the task don't match
+ // the ones in the store.
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ // Dummy item not inserted into store.
+ PrefetchItem item2 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+
+ ASSERT_NE(item.url, item2.url);
+
+ PageBundleUpdateTask task(store(), &dispatcher, "operation",
+ {
+ RenderedPageInfoForPrefetchItem(item2),
+ });
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ EXPECT_EQ(item, *(store_util()->GetPrefetchItem(item.offline_id)));
+ EXPECT_EQ(0, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, PendingRenderAwaitsGCM) {
+ // Tests that the transition to AWAITING_GCM happens correctly from
+ // SENT_GENERATE_PAGE_BUNDLE.
+ PrefetchItem item = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_EQ("", item.operation_name);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ PageBundleUpdateTask task(store(), &dispatcher, "operation",
+ {
+ PendingPageInfoForPrefetchItem(item),
+ });
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ EXPECT_EQ(PrefetchItemState::AWAITING_GCM,
+ store_util()->GetPrefetchItem(item.offline_id)->state);
+ EXPECT_EQ("operation",
+ store_util()->GetPrefetchItem(item.offline_id)->operation_name);
+ EXPECT_EQ(0, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, FailedRenderToFinished) {
+ // Tests one item with a archiving failed result, and one with a limit
+ // exceeded result.
+ PrefetchItem item1 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_EQ(PrefetchItemErrorCode::SUCCESS, item1.error_code);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item1));
+ RenderPageInfo item1_render_info = FailedPageInfoForPrefetchItem(item1);
+
+ PrefetchItem item2 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_EQ(PrefetchItemErrorCode::SUCCESS, item2.error_code);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item2));
+ RenderPageInfo item2_render_info = FailedPageInfoForPrefetchItem(item2);
+ item2_render_info.status = RenderStatus::EXCEEDED_LIMIT;
+ PageBundleUpdateTask task(store(), &dispatcher, "operation",
+ {item2_render_info, item1_render_info});
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ EXPECT_EQ(PrefetchItemState::FINISHED,
+ store_util()->GetPrefetchItem(item1.offline_id)->state);
+ EXPECT_EQ(PrefetchItemErrorCode::ARCHIVING_FAILED,
+ store_util()->GetPrefetchItem(item1.offline_id)->error_code);
+
+ EXPECT_EQ(PrefetchItemState::FINISHED,
+ store_util()->GetPrefetchItem(item2.offline_id)->state);
+ EXPECT_EQ(PrefetchItemErrorCode::ARCHIVING_LIMIT_EXCEEDED,
+ store_util()->GetPrefetchItem(item2.offline_id)->error_code);
+ EXPECT_EQ(0, dispatcher.processing_schedule_count);
+}
+
+TEST_F(PageBundleUpdateTaskTest, MixOfResults) {
+ // Tests that 3 items all with different render results get updated
+ // independently and properly.
+ PrefetchItem item1 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item1));
+ RenderPageInfo item1_render_info = PendingPageInfoForPrefetchItem(item1);
+
+ PrefetchItem item2 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item2));
+ RenderPageInfo item2_render_info = FailedPageInfoForPrefetchItem(item2);
+
+ PrefetchItem item3 = item_generator()->CreateItem(
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item3));
+ RenderPageInfo item3_render_info = RenderedPageInfoForPrefetchItem(item3);
+
+ PageBundleUpdateTask task(
+ store(), &dispatcher, "operation",
+ {item3_render_info, item2_render_info, item1_render_info});
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ EXPECT_EQ(PrefetchItemState::AWAITING_GCM,
+ store_util()->GetPrefetchItem(item1.offline_id)->state);
+ EXPECT_EQ(PrefetchItemState::FINISHED,
+ store_util()->GetPrefetchItem(item2.offline_id)->state);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE,
+ store_util()->GetPrefetchItem(item3.offline_id)->state);
+ EXPECT_LE(1, dispatcher.processing_schedule_count);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_background_task_handler.h b/chromium/components/offline_pages/core/prefetch/prefetch_background_task_handler.h
new file mode 100644
index 00000000000..6ef3e3f0aa6
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_background_task_handler.h
@@ -0,0 +1,37 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_BACKGROUND_TASK_HANDLER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_BACKGROUND_TASK_HANDLER_H_
+
+#include <memory>
+
+namespace offline_pages {
+
+// Interface for system-specific integrations with background task scheduling.
+class PrefetchBackgroundTaskHandler {
+ public:
+ virtual ~PrefetchBackgroundTaskHandler() = default;
+
+ // Stops any pending scheduled work.
+ virtual void CancelBackgroundTask() = 0;
+
+ // Ensures that Chrome will be started using a background task at an
+ // appropriate time in the future.
+ virtual void EnsureTaskScheduled() = 0;
+
+ // Requests that the network backoff be increased due to a server response.
+ virtual void Backoff() = 0;
+
+ // Resets the backoff in case of a successful network attempt.
+ virtual void ResetBackoff() = 0;
+
+ // Returns the number of seconds beyond the normal scheduling interval that
+ // the backoff should wait.
+ virtual int GetAdditionalBackoffSeconds() const = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_BACKGROUND_TASK_HANDLER_H_
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_configuration.cc b/chromium/components/offline_pages/core/prefetch/prefetch_configuration.cc
new file mode 100644
index 00000000000..6ed27b1abb5
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_configuration.cc
@@ -0,0 +1,15 @@
+// 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/offline_pages/core/prefetch/prefetch_configuration.h"
+
+#include "components/offline_pages/core/offline_page_feature.h"
+
+namespace offline_pages {
+
+bool PrefetchConfiguration::IsPrefetchingEnabled() {
+ return IsPrefetchingOfflinePagesEnabled() && IsPrefetchingEnabledBySettings();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_configuration.h b/chromium/components/offline_pages/core/prefetch/prefetch_configuration.h
new file mode 100644
index 00000000000..93064949738
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_configuration.h
@@ -0,0 +1,29 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_CONFIGURATION_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_CONFIGURATION_H_
+
+namespace offline_pages {
+
+// Class that interfaces with configuration systems to provide prefetching
+// specific configuration information.
+class PrefetchConfiguration {
+ public:
+ virtual ~PrefetchConfiguration() = default;
+
+ // Returns true if all needed flags and settings allows the prefetching of
+ // offline pages to run. Note that this result can change in the course of the
+ // application lifetime. Should not be overridden by subclasses.
+ bool IsPrefetchingEnabled();
+
+ protected:
+ // Returns true if user settings allow the prefetching of offline pages to
+ // run. Should not be called by users of this class.
+ virtual bool IsPrefetchingEnabledBySettings() = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_CONFIGURATION_H_
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
index 033cd545194..461bb41300d 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DISPATCHER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DISPATCHER_H_
+#include <map>
#include <memory>
+#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/memory/weak_ptr.h"
@@ -20,6 +23,24 @@ class PrefetchService;
// Serves as the entry point for external signals into the prefetching system.
// It listens to these events, converts them to the appropriate internal tasks
// and manage their execution and inter-dependencies.
+// Tasks are generally categorized as one of the follwoing types:
+// 1. Event handlers. These react to incoming events, such as new URLs coming
+// from suggestion service or network request finished and response is
+// available. Typical task of this type would capture the incoming data into
+// pipeline and indicate that more processing of pipeline is needed by
+// calling PrefetchDispatcher::SchedulePipelineProcessing().
+// 2. Reconcilers. These are tasks that are invoked on periodic wakeup
+// (BackgroundTask) and are responsible for checking status of ongoing
+// operations, such as network request or a download. If the failure
+// condition found (as a result of Chrome being killed in the middle of
+// network request for example), they make necessary adjustments and
+// optionally call PrefetchDispatcher::SchedulePipelineProcessing()
+// 3. Actions. These are expecting the prefetch items database looking for
+// items that are ready for some applied actions - for example, to start
+// a network request or download, or to be expired etc. These tasks are
+// scheduled as a bundle when TaskQueue becomes empty in response to
+// PrefetchDispatcher::SchedulePipelineProcessing(), and also once after
+// Reconcilers during BackgroundTask processing.
class PrefetchDispatcher {
public:
// A |ScopedBackgroundTask| is created when we are running in a background
@@ -41,6 +62,19 @@ class PrefetchDispatcher {
// be done before any other methods are called.
virtual void SetService(PrefetchService* service) = 0;
+ // Called by an Event Handler or Reconciler Task in case it modified state
+ // of one or more prefetch items and needs Actions tasks to examine/process
+ // pipeline again.
+ virtual void SchedulePipelineProcessing() = 0;
+
+ // Called by Event Handler tasks to ensure that we will wake up in the
+ // background to process data produced by the event handler. For example, if
+ // new URLs are added to the system, this is called to process them later in
+ // the background. If we are in a background task, requests rescheduling at
+ // the end of the task. Otherwise, updates the task in the OS scheduler.
+ // Does not update any existing task, so will not affect backoff.
+ virtual void EnsureTaskScheduled() = 0;
+
// Called when a client has candidate URLs for the system to prefetch, along
// with the client's unique namespace. URLs that are currently in the system
// for this client are acceptable but ignored.
@@ -74,6 +108,23 @@ class PrefetchDispatcher {
virtual void GCMOperationCompletedMessageReceived(
const std::string& operation_name) = 0;
+ // Called when a download service is up and notifies us about the ongoing and
+ // success downloads. The prefetch system should clean up the database to
+ // be consistent with those reported from the download system.
+ // Note that the failed downloads are not reported. The cleanup task can
+ // easily figure this out from both sides and take care of them.
+ virtual void CleanupDownloads(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) = 0;
+
+ // Called when a download is completed successfully or fails.
+ virtual void DownloadCompleted(
+ const PrefetchDownloadResult& download_result) = 0;
+
+ // Called when an archive import is completed successfully or fails.
+ virtual void ImportCompleted(int64_t offline_id, bool success) = 0;
+
// Used by the test to signal the completion of the background task.
virtual void RequestFinishBackgroundTaskForTest() = 0;
};
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 04b825495b8..59654f1551d 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -13,14 +13,27 @@
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/offline_event_logger.h"
-#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/prefetch/add_unique_urls_task.h"
+#include "components/offline_pages/core/prefetch/download_archives_task.h"
+#include "components/offline_pages/core/prefetch/download_cleanup_task.h"
+#include "components/offline_pages/core/prefetch/download_completed_task.h"
+#include "components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task.h"
#include "components/offline_pages/core/prefetch/generate_page_bundle_task.h"
#include "components/offline_pages/core/prefetch/get_operation_task.h"
+#include "components/offline_pages/core/prefetch/import_archives_task.h"
+#include "components/offline_pages/core/prefetch/import_completed_task.h"
+#include "components/offline_pages/core/prefetch/mark_operation_done_task.h"
+#include "components/offline_pages/core/prefetch/metrics_finalization_task.h"
+#include "components/offline_pages/core/prefetch/page_bundle_update_task.h"
+#include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
+#include "components/offline_pages/core/prefetch/prefetch_configuration.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
+#include "components/offline_pages/core/prefetch/prefetch_importer.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h"
+#include "components/offline_pages/core/prefetch/stale_entry_finalizer_task.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
#include "components/offline_pages/core/task.h"
#include "url/gurl.h"
@@ -34,7 +47,8 @@ void DeleteBackgroundTaskHelper(
}
} // namespace
-PrefetchDispatcherImpl::PrefetchDispatcherImpl() : weak_factory_(this) {}
+PrefetchDispatcherImpl::PrefetchDispatcherImpl()
+ : task_queue_(this), weak_factory_(this) {}
PrefetchDispatcherImpl::~PrefetchDispatcherImpl() = default;
@@ -43,24 +57,43 @@ void PrefetchDispatcherImpl::SetService(PrefetchService* service) {
service_ = service;
}
+void PrefetchDispatcherImpl::SchedulePipelineProcessing() {
+ needs_pipeline_processing_ = true;
+ service_->GetLogger()->RecordActivity(
+ "Dispatcher: Scheduled more pipeline processing.");
+}
+
+void PrefetchDispatcherImpl::EnsureTaskScheduled() {
+ if (background_task_) {
+ background_task_->SetNeedsReschedule(true /* reschedule */,
+ false /* backoff */);
+ } else {
+ service_->GetPrefetchBackgroundTaskHandler()->EnsureTaskScheduled();
+ }
+}
+
void PrefetchDispatcherImpl::AddCandidatePrefetchURLs(
const std::string& name_space,
const std::vector<PrefetchURL>& prefetch_urls) {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
+ service_->GetLogger()->RecordActivity("Dispatcher: Received " +
+ std::to_string(prefetch_urls.size()) +
+ " suggested URLs.");
+
PrefetchStore* prefetch_store = service_->GetPrefetchStore();
std::unique_ptr<Task> add_task = base::MakeUnique<AddUniqueUrlsTask>(
- prefetch_store, name_space, prefetch_urls);
+ this, prefetch_store, name_space, prefetch_urls);
task_queue_.AddTask(std::move(add_task));
// TODO(dewittj): Remove when we have proper scheduling.
- BeginBackgroundTask(nullptr);
+ EnsureTaskScheduled();
}
void PrefetchDispatcherImpl::RemoveAllUnprocessedPrefetchURLs(
const std::string& name_space) {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
NOTIMPLEMENTED();
@@ -68,7 +101,7 @@ void PrefetchDispatcherImpl::RemoveAllUnprocessedPrefetchURLs(
void PrefetchDispatcherImpl::RemovePrefetchURLsByClientId(
const ClientId& client_id) {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
NOTIMPLEMENTED();
@@ -76,42 +109,104 @@ void PrefetchDispatcherImpl::RemovePrefetchURLsByClientId(
void PrefetchDispatcherImpl::BeginBackgroundTask(
std::unique_ptr<ScopedBackgroundTask> background_task) {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
+ service_->GetLogger()->RecordActivity(
+ "Dispatcher: Beginning background task.");
background_task_ = std::move(background_task);
- // TODO(dewittj): Remove this when the task can get the suggestions from the
- // SQL store directly.
- std::vector<PrefetchURL> prefetch_urls;
- service_->GetSuggestedArticlesObserver()->GetCurrentSuggestions(
- &prefetch_urls);
+ QueueReconcileTasks();
+ QueueActionTasks();
+}
+
+void PrefetchDispatcherImpl::QueueReconcileTasks() {
+ service_->GetLogger()->RecordActivity("Dispatcher: Adding reconcile tasks.");
+ // Note: For optimal results StaleEntryFinalizerTask should be executed before
+ // other reconciler tasks that deal with external systems so that entries
+ // finalized by it will promptly effect any external processing they relate
+ // to.
+ task_queue_.AddTask(base::MakeUnique<StaleEntryFinalizerTask>(
+ this, service_->GetPrefetchStore()));
+
+ task_queue_.AddTask(base::MakeUnique<GeneratePageBundleReconcileTask>(
+ service_->GetPrefetchStore(),
+ service_->GetPrefetchNetworkRequestFactory()));
+
+ task_queue_.AddTask(base::MakeUnique<SentGetOperationCleanupTask>(
+ service_->GetPrefetchStore(),
+ service_->GetPrefetchNetworkRequestFactory()));
+
+ // This task should be last, because it is least important for correct
+ // operation of the system, and because any reconciliation tasks might
+ // generate more entries in the FINISHED state that the finalization task
+ // could pick up.
+ task_queue_.AddTask(
+ base::MakeUnique<MetricsFinalizationTask>(service_->GetPrefetchStore()));
+}
+
+void PrefetchDispatcherImpl::QueueActionTasks() {
+ service_->GetLogger()->RecordActivity("Dispatcher: Adding action tasks.");
+
+ std::unique_ptr<Task> download_archives_task =
+ base::MakeUnique<DownloadArchivesTask>(service_->GetPrefetchStore(),
+ service_->GetPrefetchDownloader());
+ task_queue_.AddTask(std::move(download_archives_task));
+
+ std::unique_ptr<Task> get_operation_task = base::MakeUnique<GetOperationTask>(
+ service_->GetPrefetchStore(),
+ service_->GetPrefetchNetworkRequestFactory(),
+ base::Bind(&PrefetchDispatcherImpl::DidGetOperationRequest,
+ weak_factory_.GetWeakPtr()));
+ task_queue_.AddTask(std::move(get_operation_task));
std::unique_ptr<Task> generate_page_bundle_task =
base::MakeUnique<GeneratePageBundleTask>(
- prefetch_urls, service_->GetPrefetchGCMHandler(),
+ service_->GetPrefetchStore(), service_->GetPrefetchGCMHandler(),
service_->GetPrefetchNetworkRequestFactory(),
- base::Bind(&PrefetchDispatcherImpl::DidPrefetchRequest,
- weak_factory_.GetWeakPtr(), "GeneratePageBundleRequest"));
+ base::Bind(&PrefetchDispatcherImpl::DidGenerateBundleRequest,
+ weak_factory_.GetWeakPtr()));
task_queue_.AddTask(std::move(generate_page_bundle_task));
+
+ std::unique_ptr<Task> import_archives_task =
+ base::MakeUnique<ImportArchivesTask>(service_->GetPrefetchStore(),
+ service_->GetPrefetchImporter());
+ task_queue_.AddTask(std::move(import_archives_task));
}
void PrefetchDispatcherImpl::StopBackgroundTask() {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
+ service_->GetLogger()->RecordActivity(
+ "Dispatcher: Stopping background task.");
+
DisposeTask();
}
void PrefetchDispatcherImpl::RequestFinishBackgroundTaskForTest() {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
DisposeTask();
}
+void PrefetchDispatcherImpl::OnTaskQueueIsIdle() {
+ if (needs_pipeline_processing_) {
+ needs_pipeline_processing_ = false;
+ QueueActionTasks();
+ } else {
+ PrefetchNetworkRequestFactory* request_factory =
+ service_->GetPrefetchNetworkRequestFactory();
+ if (!request_factory->HasOutstandingRequests())
+ DisposeTask();
+ }
+}
+
void PrefetchDispatcherImpl::DisposeTask() {
- DCHECK(background_task_);
+ if (!background_task_)
+ return;
+
// Delay the deletion till the caller finishes.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&DeleteBackgroundTaskHelper,
@@ -120,16 +215,77 @@ void PrefetchDispatcherImpl::DisposeTask() {
void PrefetchDispatcherImpl::GCMOperationCompletedMessageReceived(
const std::string& operation_name) {
- if (!IsPrefetchingOfflinePagesEnabled())
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
+ return;
+
+ service_->GetLogger()->RecordActivity("Dispatcher: Received GCM message.");
+
+ PrefetchStore* prefetch_store = service_->GetPrefetchStore();
+ task_queue_.AddTask(base::MakeUnique<MarkOperationDoneTask>(
+ this, prefetch_store, operation_name));
+}
+
+void PrefetchDispatcherImpl::DidGenerateBundleRequest(
+ PrefetchRequestStatus status,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages) {
+ PrefetchStore* prefetch_store = service_->GetPrefetchStore();
+ task_queue_.AddTask(base::MakeUnique<PageBundleUpdateTask>(
+ prefetch_store, this, operation_name, pages));
+ LogRequestResult("GeneratePageBundleRequest", status, operation_name, pages);
+}
+
+void PrefetchDispatcherImpl::DidGetOperationRequest(
+ PrefetchRequestStatus status,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages) {
+ PrefetchStore* prefetch_store = service_->GetPrefetchStore();
+ task_queue_.AddTask(base::MakeUnique<PageBundleUpdateTask>(
+ prefetch_store, this, operation_name, pages));
+ LogRequestResult("GetOperationRequest", status, operation_name, pages);
+}
+
+void PrefetchDispatcherImpl::CleanupDownloads(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) {
+ task_queue_.AddTask(base::MakeUnique<DownloadCleanupTask>(
+ service_->GetPrefetchDispatcher(), service_->GetPrefetchStore(),
+ outstanding_download_ids, success_downloads));
+}
+
+void PrefetchDispatcherImpl::DownloadCompleted(
+ const PrefetchDownloadResult& download_result) {
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
return;
- task_queue_.AddTask(base::MakeUnique<GetOperationTask>(
- operation_name, service_->GetPrefetchNetworkRequestFactory(),
- base::Bind(&PrefetchDispatcherImpl::DidPrefetchRequest,
- weak_factory_.GetWeakPtr(), "GetOperation")));
+ service_->GetLogger()->RecordActivity(
+ "Download " + download_result.download_id +
+ (download_result.success ? "succeeded" : "failed"));
+ if (download_result.success) {
+ service_->GetLogger()->RecordActivity(
+ "Download size: " + std::to_string(download_result.file_size));
+ }
+
+ task_queue_.AddTask(base::MakeUnique<DownloadCompletedTask>(
+ service_->GetPrefetchDispatcher(), service_->GetPrefetchStore(),
+ download_result));
+}
+
+void PrefetchDispatcherImpl::ImportCompleted(int64_t offline_id, bool success) {
+ if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
+ return;
+
+ service_->GetLogger()->RecordActivity("Importing archive " +
+ std::to_string(offline_id) +
+ (success ? "succeeded" : "failed"));
+
+ task_queue_.AddTask(base::MakeUnique<ImportCompletedTask>(
+ service_->GetPrefetchDispatcher(), service_->GetPrefetchStore(),
+ offline_id, success));
}
-void PrefetchDispatcherImpl::DidPrefetchRequest(
+void PrefetchDispatcherImpl::LogRequestResult(
const std::string& request_name_for_logging,
PrefetchRequestStatus status,
const std::string& operation_name,
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 4559abd1a86..9c4424b7c49 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -19,13 +19,16 @@
namespace offline_pages {
class PrefetchService;
-class PrefetchDispatcherImpl : public PrefetchDispatcher {
+class PrefetchDispatcherImpl : public PrefetchDispatcher,
+ public TaskQueue::Delegate {
public:
PrefetchDispatcherImpl();
~PrefetchDispatcherImpl() override;
// PrefetchDispatcher implementation:
void SetService(PrefetchService* service) override;
+ void EnsureTaskScheduled() override;
+ void SchedulePipelineProcessing() override;
void AddCandidatePrefetchURLs(
const std::string& name_space,
const std::vector<PrefetchURL>& prefetch_urls) override;
@@ -36,19 +39,51 @@ class PrefetchDispatcherImpl : public PrefetchDispatcher {
void StopBackgroundTask() override;
void GCMOperationCompletedMessageReceived(
const std::string& operation_name) override;
+ void CleanupDownloads(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) override;
+ void DownloadCompleted(
+ const PrefetchDownloadResult& download_result) override;
+ void ImportCompleted(int64_t offline_id, bool success) override;
void RequestFinishBackgroundTaskForTest() override;
+ // TaskQueue::Delegate implementation:
+ void OnTaskQueueIsIdle() override;
+
private:
friend class PrefetchDispatcherTest;
void DisposeTask();
- void DidPrefetchRequest(const std::string& request_name_for_logging,
- PrefetchRequestStatus status,
- const std::string& operation_name,
- const std::vector<RenderPageInfo>& pages);
+
+ // Callbacks for network requests.
+ void DidGenerateBundleRequest(PrefetchRequestStatus status,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages);
+ void DidGetOperationRequest(PrefetchRequestStatus status,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages);
+ void LogRequestResult(const std::string& request_name_for_logging,
+ PrefetchRequestStatus status,
+ const std::string& operation_name,
+ const std::vector<RenderPageInfo>& pages);
+
+ // Adds the Reconcile tasks to the TaskQueue. These look for error/stuck
+ // processing conditions that happen as result of Chrome being evicted
+ // or network failures of certain kind. They are run on periodic wakeup
+ // (BeginBackgroundTask()). See PrefetchDispatcher interface
+ // declaration for Reconcile tasks definition.
+ void QueueReconcileTasks();
+ // Adds the Action tasks to the queue. See PrefetchDispatcher interface
+ // declaration for Action tasks definition.
+ // Action tasks can be added to the queue either in response to periodic
+ // wakeup (when BeginBackgroundTask() is called) or any time TaskQueue is
+ // becomes idle and any task called SchedulePipelineProcessing() before.
+ void QueueActionTasks();
PrefetchService* service_;
TaskQueue task_queue_;
+ bool needs_pipeline_processing_ = false;
std::unique_ptr<ScopedBackgroundTask> background_task_;
base::WeakPtrFactory<PrefetchDispatcherImpl> weak_factory_;
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 7944ff133d0..71f5dba7a76 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
@@ -7,14 +7,14 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_feature_list.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "components/offline_pages/core/offline_event_logger.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/prefetch/generate_page_bundle_request.h"
#include "components/offline_pages/core/prefetch/get_operation_request.h"
+#include "components/offline_pages/core/prefetch/prefetch_configuration.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/prefetch_request_test_base.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/prefetch_service_test_taco.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
@@ -23,9 +23,12 @@
#include "components/offline_pages/core/prefetch/test_prefetch_network_request_factory.h"
#include "components/version_info/channel.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using testing::Contains;
+
namespace offline_pages {
namespace {
@@ -46,7 +49,7 @@ class TestScopedBackgroundTask
} // namespace
-class PrefetchDispatcherTest : public testing::Test {
+class PrefetchDispatcherTest : public PrefetchRequestTestBase {
public:
PrefetchDispatcherTest();
@@ -54,46 +57,51 @@ class PrefetchDispatcherTest : public testing::Test {
void SetUp() override;
void TearDown() override;
- void PumpLoop();
-
PrefetchDispatcher::ScopedBackgroundTask* GetBackgroundTask() {
return dispatcher_->background_task_.get();
}
+ TaskQueue& GetTaskQueueFrom(PrefetchDispatcherImpl* prefetch_dispatcher) {
+ return prefetch_dispatcher->task_queue_;
+ }
+
TaskQueue* dispatcher_task_queue() { return &dispatcher_->task_queue_; }
PrefetchDispatcher* prefetch_dispatcher() { return dispatcher_; }
-
- base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
+ TestPrefetchNetworkRequestFactory* network_request_factory() {
+ return network_request_factory_;
+ }
protected:
std::vector<PrefetchURL> test_urls_;
private:
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
std::unique_ptr<PrefetchServiceTestTaco> taco_;
base::test::ScopedFeatureList feature_list_;
// Owned by |taco_|.
PrefetchDispatcherImpl* dispatcher_;
+ // Owned by |taco_|.
+ TestPrefetchNetworkRequestFactory* network_request_factory_;
};
-PrefetchDispatcherTest::PrefetchDispatcherTest()
- : task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_) {
+PrefetchDispatcherTest::PrefetchDispatcherTest() {
feature_list_.InitAndEnableFeature(kPrefetchingOfflinePagesFeature);
}
void PrefetchDispatcherTest::SetUp() {
dispatcher_ = new PrefetchDispatcherImpl();
+ network_request_factory_ = new TestPrefetchNetworkRequestFactory();
taco_.reset(new PrefetchServiceTestTaco);
taco_->SetPrefetchDispatcher(base::WrapUnique(dispatcher_));
+ taco_->SetPrefetchNetworkRequestFactory(
+ base::WrapUnique(network_request_factory_));
taco_->CreatePrefetchService();
ASSERT_TRUE(test_urls_.empty());
- test_urls_.push_back({"1", GURL("http://testurl.com/foo")});
- test_urls_.push_back({"2", GURL("https://testurl.com/bar")});
+ test_urls_.push_back({"1", GURL("http://testurl.com/foo"), base::string16()});
+ test_urls_.push_back(
+ {"2", GURL("https://testurl.com/bar"), base::string16()});
}
void PrefetchDispatcherTest::TearDown() {
@@ -102,10 +110,6 @@ void PrefetchDispatcherTest::TearDown() {
PumpLoop();
}
-void PrefetchDispatcherTest::PumpLoop() {
- task_runner()->RunUntilIdle();
-}
-
TEST_F(PrefetchDispatcherTest, DispatcherDoesNotCrash) {
// TODO(https://crbug.com/735254): Ensure that Dispatcher unit test keep up
// with the state of adding tasks, and that the end state is we have tests
@@ -131,9 +135,7 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfFeatureNotEnabled) {
disabled_feature_list.InitAndDisableFeature(kPrefetchingOfflinePagesFeature);
// Don't add a task for new prefetch URLs.
- PrefetchURL prefetch_url("id", GURL("https://www.chromium.org"));
- prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
EXPECT_FALSE(dispatcher_task_queue()->HasRunningTask());
// Do nothing with a new background task.
@@ -141,7 +143,66 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfFeatureNotEnabled) {
base::MakeUnique<TestScopedBackgroundTask>());
EXPECT_EQ(nullptr, GetBackgroundTask());
- // Everything else is unimplemented.
+ // TODO(carlosk): add more checks here.
+}
+
+class DisablingPrefetchConfiguration : public PrefetchConfiguration {
+ public:
+ bool IsPrefetchingEnabledBySettings() override { return false; };
+};
+
+TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfSettingsDoNotAllowIt) {
+ PrefetchDispatcherImpl* dispatcher = new PrefetchDispatcherImpl();
+ PrefetchServiceTestTaco taco;
+ taco.SetPrefetchDispatcher(base::WrapUnique(dispatcher));
+ taco.SetPrefetchNetworkRequestFactory(
+ base::MakeUnique<TestPrefetchNetworkRequestFactory>());
+ taco.SetPrefetchConfiguration(
+ base::MakeUnique<DisablingPrefetchConfiguration>());
+ taco.CreatePrefetchService();
+
+ // Don't add a task for new prefetch URLs.
+ dispatcher->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ EXPECT_FALSE(GetTaskQueueFrom(dispatcher).HasRunningTask());
+
+ // Do nothing with a new background task.
+ dispatcher->BeginBackgroundTask(base::MakeUnique<TestScopedBackgroundTask>());
+ EXPECT_EQ(nullptr, GetBackgroundTask());
+
+ // TODO(carlosk): add more checks here.
+}
+
+TEST_F(PrefetchDispatcherTest, DispatcherReleasesBackgroundTask) {
+ PrefetchURL prefetch_url("id", GURL("https://www.chromium.org"),
+ base::string16());
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(
+ kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ PumpLoop();
+
+ // We start the background task, causing reconcilers and action tasks to be
+ // run. We should hold onto the background task until there is no more work to
+ // do, after the network request ends.
+ ASSERT_EQ(nullptr, GetBackgroundTask());
+ prefetch_dispatcher()->BeginBackgroundTask(
+ base::MakeUnique<TestScopedBackgroundTask>());
+ EXPECT_TRUE(dispatcher_task_queue()->HasRunningTask());
+ PumpLoop();
+
+ // Still holding onto the background task.
+ EXPECT_NE(nullptr, GetBackgroundTask());
+ EXPECT_FALSE(dispatcher_task_queue()->HasRunningTask());
+ EXPECT_THAT(*network_request_factory()->GetAllUrlsRequested(),
+ Contains(prefetch_url.url.spec()));
+
+ // When the network request finishes, the dispatcher should still hold the
+ // ScopedBackgroundTask because it needs to process the results of the
+ // request.
+ RespondWithHttpError(500);
+ EXPECT_NE(nullptr, GetBackgroundTask());
+ PumpLoop();
+
+ // Because there is no work remaining, the background task should be released.
+ EXPECT_EQ(nullptr, GetBackgroundTask());
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader.cc b/chromium/components/offline_pages/core/prefetch/prefetch_downloader.cc
deleted file mode 100644
index 8f03b678637..00000000000
--- a/chromium/components/offline_pages/core/prefetch/prefetch_downloader.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "components/download/public/download_service.h"
-#include "components/offline_pages/core/prefetch/prefetch_server_urls.h"
-#include "url/gurl.h"
-
-namespace offline_pages {
-
-PrefetchDownloader::PrefetchDownloader(
- download::DownloadService* download_service,
- version_info::Channel channel)
- : download_service_(download_service),
- channel_(channel),
- weak_ptr_factory_(this) {
- DCHECK(download_service);
- service_started_ = download_service->GetStatus() ==
- download::DownloadService::ServiceStatus::READY;
-}
-
-PrefetchDownloader::PrefetchDownloader(version_info::Channel channel)
- : channel_(channel), weak_ptr_factory_(this) {}
-
-PrefetchDownloader::~PrefetchDownloader() = default;
-
-void PrefetchDownloader::SetCompletedCallback(
- const PrefetchDownloadCompletedCallback& callback) {
- callback_ = callback;
-}
-
-void PrefetchDownloader::StartDownload(const std::string& download_id,
- const std::string& download_location) {
- if (!service_started_) {
- pending_downloads_.push_back(
- std::make_pair(download_id, download_location));
- return;
- }
-
- // TODO(jianli): Specify scheduling parameters, i.e. battery, network and etc.
- // http://crbug.com/736156
- download::DownloadParams params;
- params.client = download::DownloadClient::OFFLINE_PAGE_PREFETCH;
- // TODO(jianli): Remove the uppercase after the download service fixes
- // this issue.
- params.guid = base::ToUpperASCII(download_id);
- params.callback = base::Bind(&PrefetchDownloader::OnStartDownload,
- weak_ptr_factory_.GetWeakPtr());
- params.request_params.url = PrefetchDownloadURL(download_location, channel_);
- download_service_->StartDownload(params);
-}
-
-void PrefetchDownloader::CancelDownload(const std::string& download_id) {
- if (service_started_) {
- download_service_->CancelDownload(download_id);
- return;
- }
- for (auto iter = pending_downloads_.begin(); iter != pending_downloads_.end();
- ++iter) {
- if (iter->first == download_id) {
- pending_downloads_.erase(iter);
- return;
- }
- }
- pending_cancellations_.push_back(download_id);
-}
-
-void PrefetchDownloader::OnDownloadServiceReady() {
- DCHECK_EQ(download::DownloadService::ServiceStatus::READY,
- download_service_->GetStatus());
- service_started_ = true;
-
- for (const auto& entry : pending_downloads_)
- StartDownload(entry.first, entry.second);
- pending_downloads_.clear();
-
- for (const auto& entry : pending_cancellations_)
- download_service_->CancelDownload(entry);
- pending_cancellations_.clear();
-}
-
-void PrefetchDownloader::OnDownloadServiceShutdown() {
- service_started_ = false;
-}
-
-void PrefetchDownloader::OnDownloadSucceeded(const std::string& download_id,
- const base::FilePath& file_path,
- uint64_t file_size) {
- if (callback_)
- callback_.Run(PrefetchDownloadResult(download_id, file_path, file_size));
-}
-
-void PrefetchDownloader::OnDownloadFailed(const std::string& download_id) {
- if (callback_) {
- PrefetchDownloadResult result;
- result.download_id = download_id;
- callback_.Run(result);
- }
-}
-
-void PrefetchDownloader::OnStartDownload(
- const std::string& download_id,
- download::DownloadParams::StartResult result) {
- if (result != download::DownloadParams::StartResult::ACCEPTED)
- OnDownloadFailed(download_id);
-}
-
-} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader.h b/chromium/components/offline_pages/core/prefetch/prefetch_downloader.h
index 4dd0f2496dd..76381a3314a 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_downloader.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader.h
@@ -5,90 +5,55 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DOWNLOADER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DOWNLOADER_H_
+#include <map>
+#include <set>
#include <string>
#include <utility>
-#include <vector>
#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/download/public/download_params.h"
-#include "components/offline_pages/core/prefetch/prefetch_types.h"
-#include "components/version_info/channel.h"
-
-namespace download {
-class DownloadService;
-} // namespace download
+#include "base/files/file_path.h"
namespace offline_pages {
-
-class PrefetchServiceTestTaco;
+class PrefetchService;
// Asynchronously downloads the archive.
class PrefetchDownloader {
public:
- PrefetchDownloader(download::DownloadService* download_service,
- version_info::Channel channel);
- ~PrefetchDownloader();
+ virtual ~PrefetchDownloader() = default;
- void SetCompletedCallback(const PrefetchDownloadCompletedCallback& callback);
+ virtual void SetPrefetchService(PrefetchService* service) = 0;
// Starts to download an archive from |download_location|.
- void StartDownload(const std::string& download_id,
- const std::string& download_location);
+ virtual void StartDownload(const std::string& download_id,
+ const std::string& download_location) = 0;
// Cancels a previous scheduled download.
- void CancelDownload(const std::string& download_id);
-
- // Responding to download client event.
+ virtual void CancelDownload(const std::string& download_id) = 0;
// Called when the download service is initialized and can accept the
// downloads.
- void OnDownloadServiceReady();
+ // |success_downloads| is a map with download_id as key and pair of file path
+ // and file size as value.
+ virtual void OnDownloadServiceReady(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) = 0;
+
+ // Called when the download service fails to initialize and should not be
+ // used.
+ virtual void OnDownloadServiceUnavailable() = 0;
// Called when the download service is tearing down.
- void OnDownloadServiceShutdown();
+ virtual void OnDownloadServiceShutdown() = 0;
// Called when a download is completed successfully. Note that the download
- // can be scheduled in preious sessions.
- void OnDownloadSucceeded(const std::string& download_id,
- const base::FilePath& file_path,
- uint64_t file_size);
+ // can be scheduled in previous sessions.
+ virtual void OnDownloadSucceeded(const std::string& download_id,
+ const base::FilePath& file_path,
+ int64_t file_size) = 0;
// Called when a download fails.
- void OnDownloadFailed(const std::string& download_id);
-
- private:
- friend class PrefetchServiceTestTaco;
-
- // For test only.
- explicit PrefetchDownloader(version_info::Channel channel);
-
- // Callback for StartDownload.
- void OnStartDownload(const std::string& download_id,
- download::DownloadParams::StartResult result);
-
- // Unowned. It is valid until |this| instance is disposed.
- download::DownloadService* download_service_;
-
- version_info::Channel channel_;
- PrefetchDownloadCompletedCallback callback_;
-
- // Flag to indicate if the download service is ready to take downloads.
- bool service_started_ = false;
-
- // TODO(jianli): Investigate making PrefetchService waits for DownloadService
- // ready in order to avoid queueing.
- // List of downloads pending to start after the download service starts. Each
- // item is a pair of download id and download location.
- std::vector<std::pair<std::string, std::string>> pending_downloads_;
- // List of ids of downloads waiting to be cancelled after the download service
- // starts.
- std::vector<std::string> pending_cancellations_;
-
- base::WeakPtrFactory<PrefetchDownloader> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefetchDownloader);
+ virtual void OnDownloadFailed(const std::string& download_id) = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
new file mode 100644
index 00000000000..e1495c13a8f
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
@@ -0,0 +1,184 @@
+// 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/offline_pages/core/prefetch/prefetch_downloader_impl.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "components/download/public/download_params.h"
+#include "components/download/public/download_service.h"
+#include "components/offline_pages/core/offline_event_logger.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_server_urls.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+namespace {
+
+void NotifyDispatcher(PrefetchService* service, PrefetchDownloadResult result) {
+ if (service) {
+ PrefetchDispatcher* dispatcher = service->GetPrefetchDispatcher();
+ if (dispatcher)
+ dispatcher->DownloadCompleted(result);
+ }
+}
+
+} // namespace
+
+PrefetchDownloaderImpl::PrefetchDownloaderImpl(
+ download::DownloadService* download_service,
+ version_info::Channel channel)
+ : download_service_(download_service),
+ channel_(channel),
+ weak_ptr_factory_(this) {
+ DCHECK(download_service);
+ service_started_ = download_service->GetStatus() ==
+ download::DownloadService::ServiceStatus::READY;
+}
+
+PrefetchDownloaderImpl::PrefetchDownloaderImpl(version_info::Channel channel)
+ : download_service_(nullptr), channel_(channel), weak_ptr_factory_(this) {}
+
+PrefetchDownloaderImpl::~PrefetchDownloaderImpl() = default;
+
+void PrefetchDownloaderImpl::SetPrefetchService(PrefetchService* service) {
+ prefetch_service_ = service;
+}
+
+void PrefetchDownloaderImpl::StartDownload(
+ const std::string& download_id,
+ const std::string& download_location) {
+ if (!service_started_) {
+ pending_downloads_.push_back(
+ std::make_pair(download_id, download_location));
+ return;
+ }
+
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Start download of '" + download_location +
+ "', download_id=" + download_id);
+
+ download::DownloadParams params;
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("prefetch_download", R"(
+ semantics {
+ sender: "Prefetch Downloader"
+ description:
+ "Chromium interacts with Offline Page Service to prefetch "
+ "suggested website resources."
+ trigger:
+ "When there are suggested website resources to fetch."
+ data:
+ "The link to the contents of the suggested website resources to "
+ "fetch."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "Users can enable or disable the offline prefetch on desktop by "
+ "toggling 'Use a prediction service to load pages more quickly' in "
+ "settings under Privacy and security, or on Android by toggling "
+ "chrome://flags#offline-prefetch."
+ chrome_policy {
+ NetworkPredictionOptions {
+ NetworkPredictionOptions: 2
+ }
+ }
+ })");
+ params.traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
+ params.client = download::DownloadClient::OFFLINE_PAGE_PREFETCH;
+ params.guid = download_id;
+ params.callback = base::Bind(&PrefetchDownloaderImpl::OnStartDownload,
+ weak_ptr_factory_.GetWeakPtr());
+ params.scheduling_params.network_requirements =
+ download::SchedulingParams::NetworkRequirements::UNMETERED;
+ params.scheduling_params.battery_requirements =
+ download::SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE;
+ params.request_params.url = PrefetchDownloadURL(download_location, channel_);
+ download_service_->StartDownload(params);
+}
+
+void PrefetchDownloaderImpl::CancelDownload(const std::string& download_id) {
+ if (service_started_) {
+ download_service_->CancelDownload(download_id);
+ return;
+ }
+ for (auto iter = pending_downloads_.begin(); iter != pending_downloads_.end();
+ ++iter) {
+ if (iter->first == download_id) {
+ pending_downloads_.erase(iter);
+ return;
+ }
+ }
+ pending_cancellations_.push_back(download_id);
+}
+
+void PrefetchDownloaderImpl::OnDownloadServiceReady(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) {
+ prefetch_service_->GetLogger()->RecordActivity("Downloader: Service ready.");
+ DCHECK_EQ(download::DownloadService::ServiceStatus::READY,
+ download_service_->GetStatus());
+ service_started_ = true;
+
+ PrefetchDispatcher* dispatcher = prefetch_service_->GetPrefetchDispatcher();
+ if (dispatcher)
+ dispatcher->CleanupDownloads(outstanding_download_ids, success_downloads);
+
+ for (const auto& entry : pending_downloads_)
+ StartDownload(entry.first, entry.second);
+ pending_downloads_.clear();
+
+ for (const auto& entry : pending_cancellations_)
+ download_service_->CancelDownload(entry);
+ pending_cancellations_.clear();
+}
+
+void PrefetchDownloaderImpl::OnDownloadServiceUnavailable() {
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Service unavailable.");
+ // TODO(jianli): Report UMA.
+}
+
+void PrefetchDownloaderImpl::OnDownloadServiceShutdown() {
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Service shutdown.");
+ service_started_ = false;
+}
+
+void PrefetchDownloaderImpl::OnDownloadSucceeded(
+ const std::string& download_id,
+ const base::FilePath& file_path,
+ int64_t file_size) {
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Download succeeded, download_id=" + download_id);
+ NotifyDispatcher(prefetch_service_,
+ PrefetchDownloadResult(download_id, file_path, file_size));
+}
+
+void PrefetchDownloaderImpl::OnDownloadFailed(const std::string& download_id) {
+ PrefetchDownloadResult result;
+ result.download_id = download_id;
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Download failed, download_id=" + download_id);
+ NotifyDispatcher(prefetch_service_, result);
+}
+
+void PrefetchDownloaderImpl::OnStartDownload(
+ const std::string& download_id,
+ download::DownloadParams::StartResult result) {
+ prefetch_service_->GetLogger()->RecordActivity(
+ "Downloader: Download started, download_id=" + download_id +
+ ", result=" + std::to_string(static_cast<int>(result)));
+ if (result != download::DownloadParams::StartResult::ACCEPTED)
+ OnDownloadFailed(download_id);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
new file mode 100644
index 00000000000..7c6b5aef4b5
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
@@ -0,0 +1,89 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DOWNLOADER_IMPL_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DOWNLOADER_IMPL_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/download/public/download_params.h"
+#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/version_info/channel.h"
+
+namespace download {
+class DownloadService;
+} // namespace download
+
+namespace offline_pages {
+
+class PrefetchService;
+class PrefetchServiceTestTaco;
+
+// Asynchronously downloads the archive.
+class PrefetchDownloaderImpl : public PrefetchDownloader {
+ public:
+ PrefetchDownloaderImpl(download::DownloadService* download_service,
+ version_info::Channel channel);
+ ~PrefetchDownloaderImpl() override;
+
+ // PrefetchDownloader implementation:
+ void SetPrefetchService(PrefetchService* service) override;
+ void StartDownload(const std::string& download_id,
+ const std::string& download_location) override;
+ void CancelDownload(const std::string& download_id) override;
+ void OnDownloadServiceReady(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) override;
+ void OnDownloadServiceUnavailable() override;
+ void OnDownloadServiceShutdown() override;
+ void OnDownloadSucceeded(const std::string& download_id,
+ const base::FilePath& file_path,
+ int64_t file_size) override;
+ void OnDownloadFailed(const std::string& download_id) override;
+
+ private:
+ friend class PrefetchServiceTestTaco;
+
+ // For test only.
+ explicit PrefetchDownloaderImpl(version_info::Channel channel);
+
+ // Callback for StartDownload.
+ void OnStartDownload(const std::string& download_id,
+ download::DownloadParams::StartResult result);
+
+ // Unowned. It is valid until |this| instance is disposed.
+ download::DownloadService* download_service_;
+
+ // Unowned, owns |this|.
+ PrefetchService* prefetch_service_ = nullptr;
+
+ version_info::Channel channel_;
+
+ // Flag to indicate if the download service is ready to take downloads.
+ bool service_started_ = false;
+
+ // TODO(jianli): Investigate making PrefetchService waits for DownloadService
+ // ready in order to avoid queueing.
+ // List of downloads pending to start after the download service starts. Each
+ // item is a pair of download id and download location.
+ std::vector<std::pair<std::string, std::string>> pending_downloads_;
+ // List of ids of downloads waiting to be cancelled after the download service
+ // starts.
+ std::vector<std::string> pending_cancellations_;
+
+ base::WeakPtrFactory<PrefetchDownloaderImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefetchDownloaderImpl);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DOWNLOADER_IMPL_H_
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
index 1befed2dc73..1eb22284d79 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl_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/offline_pages/core/prefetch/prefetch_downloader.h"
+#include "components/offline_pages/core/prefetch/prefetch_downloader_impl.h"
#include <list>
#include <utility>
@@ -11,128 +11,51 @@
#include "base/bind.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/download/public/download_service.h"
+#include "components/download/internal/test/empty_client.h"
+#include "components/download/internal/test/test_download_service.h"
+#include "components/download/public/download_metadata.h"
#include "components/download/public/service_config.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/prefetch_service_test_taco.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
#include "net/base/url_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const version_info::Channel kTestChannel = version_info::Channel::UNKNOWN;
-const char kDownloadId[] = "1234";
-const char kDownloadId2[] = "ABCD";
-const char kFailedDownloadId[] = "FFFFFF";
+const char kDownloadId[] = "1234Ab";
+const char kDownloadId2[] = "Abcd";
+const char kFailedDownloadId[] = "f1f1FF";
const char kDownloadLocation[] = "page/1";
const char kDownloadLocation2[] = "page/zz";
const char kServerPathForDownload[] = "/v1/media/page/1";
-const uint64_t kTestFileSize = 12345678u;
} // namespace
-namespace download {
-class TestServiceConfig : public ServiceConfig {
- public:
- TestServiceConfig() = default;
- ~TestServiceConfig() override = default;
-
- uint32_t GetMaxScheduledDownloadsPerClient() const override { return 0; }
- const base::TimeDelta& GetFileKeepAliveTime() const override {
- return time_delta_;
- }
-
- private:
- base::TimeDelta time_delta_;
-};
+namespace offline_pages {
-class TestDownloadService : public DownloadService {
+class TestDownloadClient : public download::test::EmptyClient {
public:
- TestDownloadService() = default;
- ~TestDownloadService() override = default;
-
- // DownloadService implementation.
- const ServiceConfig& GetConfig() override { return service_config_; }
- void OnStartScheduledTask(DownloadTaskType task_type,
- const TaskFinishedCallback& callback) override {}
- bool OnStopScheduledTask(DownloadTaskType task_type) override { return true; }
- ServiceStatus GetStatus() override {
- return ready_ ? DownloadService::ServiceStatus::READY
- : DownloadService::ServiceStatus::STARTING_UP;
- }
-
- void StartDownload(const DownloadParams& download_params) override {
- if (!ready_) {
- OnDownloadFailed(download_params.guid);
- return;
- }
- downloads_.push_back(download_params);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&TestDownloadService::ProcessDownload,
- base::Unretained(this)));
- }
+ explicit TestDownloadClient(PrefetchDownloader* downloader)
+ : downloader_(downloader) {}
- void PauseDownload(const std::string& guid) override {}
- void ResumeDownload(const std::string& guid) override {}
+ ~TestDownloadClient() override = default;
- void CancelDownload(const std::string& guid) override {
- for (auto iter = downloads_.begin(); iter != downloads_.end(); ++iter) {
- if (iter->guid == guid) {
- downloads_.erase(iter);
- return;
- }
- }
+ void OnDownloadFailed(const std::string& guid,
+ download::Client::FailureReason reason) override {
+ downloader_->OnDownloadFailed(guid);
}
- void ChangeDownloadCriteria(const std::string& guid,
- const SchedulingParams& params) override {}
-
- DownloadParams GetDownload(const std::string& guid) const {
- for (auto iter = downloads_.begin(); iter != downloads_.end(); ++iter) {
- if (iter->guid == guid)
- return *iter;
- }
- return DownloadParams();
- }
-
- void set_ready(bool ready) { ready_ = ready; }
- void set_prefetch_downloader(
- offline_pages::PrefetchDownloader* prefetch_downloader) {
- prefetch_downloader_ = prefetch_downloader;
+ void OnDownloadSucceeded(
+ const std::string& guid,
+ const download::CompletionInfo& completion_info) override {
+ downloader_->OnDownloadSucceeded(guid, completion_info.path,
+ completion_info.bytes_downloaded);
}
private:
- void ProcessDownload() {
- if (!ready_ || downloads_.empty())
- return;
- DownloadParams params = downloads_.front();
- downloads_.pop_front();
- if (params.guid == kFailedDownloadId)
- OnDownloadFailed(params.guid);
- else
- OnDownloadSucceeded(params.guid, base::FilePath(), kTestFileSize);
- }
-
- void OnDownloadSucceeded(const std::string& guid,
- const base::FilePath& file_path,
- uint64_t file_size) {
- if (prefetch_downloader_)
- prefetch_downloader_->OnDownloadSucceeded(guid, file_path, file_size);
- }
-
- void OnDownloadFailed(const std::string& guid) {
- if (prefetch_downloader_)
- prefetch_downloader_->OnDownloadFailed(guid);
- }
-
- bool ready_ = false;
- offline_pages::PrefetchDownloader* prefetch_downloader_ = nullptr;
- TestServiceConfig service_config_;
- std::list<DownloadParams> downloads_;
-
- DISALLOW_COPY_AND_ASSIGN(TestDownloadService);
+ PrefetchDownloader* downloader_;
};
-} // namespace download
-
-namespace offline_pages {
class PrefetchDownloaderTest : public testing::Test {
public:
@@ -142,15 +65,17 @@ class PrefetchDownloaderTest : public testing::Test {
void SetUp() override {
prefetch_service_taco_.reset(new PrefetchServiceTestTaco);
-
- auto downloader =
- base::MakeUnique<PrefetchDownloader>(&download_service_, kTestChannel);
- download_service_.set_prefetch_downloader(downloader.get());
+ dispatcher_ = new TestPrefetchDispatcher();
+
+ auto downloader = base::MakeUnique<PrefetchDownloaderImpl>(
+ &download_service_, kTestChannel);
+ download_service_.SetFailedDownload(kFailedDownloadId, false);
+ download_client_ = base::MakeUnique<TestDownloadClient>(downloader.get());
+ download_service_.set_client(download_client_.get());
+ prefetch_service_taco_->SetPrefetchDispatcher(
+ base::WrapUnique(dispatcher_));
prefetch_service_taco_->SetPrefetchDownloader(std::move(downloader));
-
prefetch_service_taco_->CreatePrefetchService();
- GetPrefetchDownloader()->SetCompletedCallback(base::Bind(
- &PrefetchDownloaderTest::OnDownloadCompleted, base::Unretained(this)));
}
void TearDown() override {
@@ -159,11 +84,14 @@ class PrefetchDownloaderTest : public testing::Test {
}
void SetDownloadServiceReady(bool ready) {
- download_service_.set_ready(ready);
- if (ready)
- GetPrefetchDownloader()->OnDownloadServiceReady();
- else
+ download_service_.set_is_ready(ready);
+ if (ready) {
+ GetPrefetchDownloader()->OnDownloadServiceReady(
+ std::set<std::string>(),
+ std::map<std::string, std::pair<base::FilePath, int64_t>>());
+ } else {
GetPrefetchDownloader()->OnDownloadServiceShutdown();
+ }
}
void StartDownload(const std::string& download_id,
@@ -175,39 +103,38 @@ class PrefetchDownloaderTest : public testing::Test {
GetPrefetchDownloader()->CancelDownload(download_id);
}
- download::DownloadParams GetDownload(const std::string& guid) const {
+ base::Optional<download::DownloadParams> GetDownload(
+ const std::string& guid) const {
return download_service_.GetDownload(guid);
}
void PumpLoop() { task_runner_->RunUntilIdle(); }
const std::vector<PrefetchDownloadResult>& completed_downloads() const {
- return completed_downloads_;
+ return dispatcher_->download_results;
}
private:
- void OnDownloadCompleted(const PrefetchDownloadResult& result) {
- completed_downloads_.push_back(result);
- }
-
PrefetchDownloader* GetPrefetchDownloader() const {
return prefetch_service_taco_->prefetch_service()->GetPrefetchDownloader();
}
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
- download::TestDownloadService download_service_;
+ download::test::TestDownloadService download_service_;
+ std::unique_ptr<TestDownloadClient> download_client_;
std::unique_ptr<PrefetchServiceTestTaco> prefetch_service_taco_;
- std::vector<PrefetchDownloadResult> completed_downloads_;
+ TestPrefetchDispatcher* dispatcher_;
};
TEST_F(PrefetchDownloaderTest, DownloadParams) {
SetDownloadServiceReady(true);
StartDownload(kDownloadId, kDownloadLocation);
- download::DownloadParams params = GetDownload(kDownloadId);
- EXPECT_EQ(kDownloadId, params.guid);
- EXPECT_EQ(download::DownloadClient::OFFLINE_PAGE_PREFETCH, params.client);
- GURL download_url = params.request_params.url;
+ base::Optional<download::DownloadParams> params = GetDownload(kDownloadId);
+ ASSERT_TRUE(params.has_value());
+ EXPECT_EQ(kDownloadId, params->guid);
+ EXPECT_EQ(download::DownloadClient::OFFLINE_PAGE_PREFETCH, params->client);
+ GURL download_url = params->request_params.url;
EXPECT_TRUE(download_url.SchemeIs(url::kHttpsScheme));
EXPECT_EQ(kServerPathForDownload, download_url.path());
std::string key_value;
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_importer.cc b/chromium/components/offline_pages/core/prefetch/prefetch_importer.cc
new file mode 100644
index 00000000000..b7febd071b6
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_importer.cc
@@ -0,0 +1,18 @@
+// 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/offline_pages/core/prefetch/prefetch_importer.h"
+
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+
+namespace offline_pages {
+
+PrefetchImporter::PrefetchImporter(PrefetchDispatcher* dispatcher)
+ : dispatcher_(dispatcher) {}
+
+void PrefetchImporter::NotifyImportCompleted(int64_t offline_id, bool success) {
+ dispatcher_->ImportCompleted(offline_id, success);
+}
+
+} // namespace offline_pages \ No newline at end of file
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_importer.h b/chromium/components/offline_pages/core/prefetch/prefetch_importer.h
index 1ef3edf6117..c9e84c7c3da 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_importer.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_importer.h
@@ -5,36 +5,30 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_IMPORTER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_IMPORTER_H_
-#include <string>
-
-class GURL;
-namespace base {
-class FilePath;
-} // namespace base
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
namespace offline_pages {
-struct ClientId;
+class PrefetchDispatcher;
// Interface to import the downloaded archive such that it can be rendered as
// offline page.
class PrefetchImporter {
public:
- using CompletedCallback =
- base::Callback<void(bool success, int64_t offline_id)>;
-
+ explicit PrefetchImporter(PrefetchDispatcher* dispatcher);
virtual ~PrefetchImporter() = default;
// Imports the downloaded archive by moving the file into archive directory
// and creating an entry in the offline metadata database.
- virtual void ImportFile(const GURL& url,
- const GURL& original_url,
- const base::string16& title,
- int64_t offline_id,
- const ClientId& client_id,
- const base::FilePath& file_path,
- int64_t file_size,
- const CompletedCallback& callback) = 0;
+ virtual void ImportArchive(const PrefetchArchiveInfo& info) = 0;
+
+ protected:
+ void NotifyImportCompleted(int64_t offline_id, bool success);
+
+ private:
+ PrefetchDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefetchImporter);
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_item.cc b/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
index 375bf091d7d..291409a5cf8 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
@@ -4,29 +4,75 @@
#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include <ostream>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+
namespace offline_pages {
PrefetchItem::PrefetchItem() = default;
PrefetchItem::PrefetchItem(const PrefetchItem& other) = default;
-PrefetchItem::~PrefetchItem(){};
+PrefetchItem::PrefetchItem(PrefetchItem&& other) = default;
+
+PrefetchItem::~PrefetchItem() = default;
+
+PrefetchItem& PrefetchItem::operator=(const PrefetchItem& other) = default;
+
+PrefetchItem& PrefetchItem::operator=(PrefetchItem&& other) = default;
bool PrefetchItem::operator==(const PrefetchItem& other) const {
return offline_id == other.offline_id && guid == other.guid &&
client_id == other.client_id && state == other.state &&
url == other.url && final_archived_url == other.final_archived_url &&
- request_archive_attempt_count == other.request_archive_attempt_count &&
+ generate_bundle_attempts == other.generate_bundle_attempts &&
+ get_operation_attempts == other.get_operation_attempts &&
+ download_initiation_attempts == other.download_initiation_attempts &&
operation_name == other.operation_name &&
archive_body_name == other.archive_body_name &&
archive_body_length == other.archive_body_length &&
creation_time == other.creation_time &&
freshness_time == other.freshness_time &&
- error_code == other.error_code;
+ error_code == other.error_code && title == other.title &&
+ file_path == other.file_path && file_size == other.file_size;
}
bool PrefetchItem::operator!=(const PrefetchItem& other) const {
return !(*this == other);
}
+bool PrefetchItem::operator<(const PrefetchItem& other) const {
+ return offline_id < other.offline_id;
+}
+
+std::string PrefetchItem::ToString() const {
+ std::string s("PrefetchItem(");
+ s.append(base::Int64ToString(offline_id)).append(", ");
+ s.append(guid).append(", ");
+ s.append(client_id.ToString()).append(", ");
+ s.append(base::IntToString(static_cast<int>(state))).append(", ");
+ s.append(url.possibly_invalid_spec()).append(", ");
+ s.append(final_archived_url.possibly_invalid_spec()).append(", ");
+ s.append(base::IntToString(generate_bundle_attempts)).append(", ");
+ s.append(base::IntToString(get_operation_attempts)).append(", ");
+ s.append(base::IntToString(download_initiation_attempts)).append(", ");
+ s.append(operation_name).append(", ");
+ s.append(archive_body_name).append(", ");
+ s.append(base::IntToString(archive_body_length)).append(", ");
+ s.append(base::Int64ToString(ToDatabaseTime(creation_time))).append(", ");
+ s.append(base::Int64ToString(ToDatabaseTime(freshness_time))).append(", ");
+ s.append(base::IntToString(static_cast<int>(error_code))).append(", ");
+ s.append(base::UTF16ToUTF8(title)).append(", ");
+ s.append(file_path.AsUTF8Unsafe()).append(", ");
+ s.append(base::IntToString(static_cast<int>(file_size))).append(")");
+ return s;
+}
+
+std::ostream& operator<<(std::ostream& out, const PrefetchItem& pi) {
+ return out << pi.ToString();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_item.h b/chromium/components/offline_pages/core/prefetch/prefetch_item.h
index ad22a92398c..0baaf7c6a8a 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_item.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_item.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_ITEM_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_ITEM_H_
+#include <stdint.h>
+#include <iosfwd>
#include <string>
+#include "base/files/file_path.h"
#include "base/time/time.h"
#include "components/offline_pages/core/client_id.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
@@ -21,12 +24,19 @@ namespace offline_pages {
// inserted into) the persistent prefetching data store.
struct PrefetchItem {
PrefetchItem();
- explicit PrefetchItem(const PrefetchItem& other);
+ PrefetchItem(const PrefetchItem& other);
+ PrefetchItem(PrefetchItem&& other);
~PrefetchItem();
+ PrefetchItem& operator=(const PrefetchItem& other);
+ PrefetchItem& operator=(PrefetchItem&& other);
+
bool operator==(const PrefetchItem& other) const;
bool operator!=(const PrefetchItem& other) const;
+ bool operator<(const PrefetchItem& other) const;
+
+ std::string ToString() const;
// Primary key that stays consistent between prefetch item, request and
// offline page.
@@ -52,8 +62,16 @@ struct PrefetchItem {
// left empty if they are the same.
GURL final_archived_url;
- // Number of times an attempt was made to generate an archive for this item.
- int request_archive_attempt_count = 0;
+ // Number of attempts to request OPS to generate an archive for this item.
+ int generate_bundle_attempts = 0;
+
+ // Number of attempts to obtain from OPS information about the archive
+ // generation operation for this item.
+ int get_operation_attempts = 0;
+
+ // Number of attempts to request the downloads system to start downloading the
+ // archive for this item.
+ int download_initiation_attempts = 0;
// Name used to identify the archiving operation being executed by the
// prefetching service for processing this item's URL. It is used as the
@@ -87,8 +105,19 @@ struct PrefetchItem {
// The reason why the item was set to the FINISHED state. Should be
// disregarded until reaching that state.
PrefetchItemErrorCode error_code = PrefetchItemErrorCode::SUCCESS;
+
+ // The title of the page.
+ base::string16 title;
+
+ // The file path to the archive of the page.
+ base::FilePath file_path;
+
+ // The size of the archive file.
+ int64_t file_size = -1;
};
+std::ostream& operator<<(std::ostream& out, const PrefetchItem& pi);
+
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_ITEM_H_
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_item_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_item_unittest.cc
index 3778281b23a..8be14345891 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_item_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_item_unittest.cc
@@ -4,81 +4,135 @@
#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace offline_pages {
-TEST(PrefetchItemTest, OperatorEqualsAndCopyConstructor) {
+class PrefetchItemTest : public testing::Test {
+ public:
+ void CheckFieldAndResetItem(PrefetchItem& item, const char* tested_field);
+ void CheckAllFieldsWereTested();
+
+ std::size_t GetTableColumnsCount();
+
+ private:
+ std::size_t checked_fields_counter_ = 0;
+};
+
+// Checks behavior of some PrefetchItem methods for an item with one single
+// member updated to a non-default value. After testing the item is reset and
+// |checked_fields_counter_| is incremented.
+void PrefetchItemTest::CheckFieldAndResetItem(PrefetchItem& item,
+ const char* tested_field) {
+ EXPECT_NE(item, PrefetchItem())
+ << "Item with updated \"" << tested_field
+ << "\" should not equal a default constructed item";
+ EXPECT_EQ(item, PrefetchItem(item))
+ << "Item with updated \"" << tested_field
+ << "\" should equal a copy constructed based off of it";
+ EXPECT_NE(item.ToString(), PrefetchItem().ToString())
+ << "Result of ToString() from an item with updated \"" << tested_field
+ << "\" should not equal the ToString() result from a default constructed"
+ " item";
+ item = PrefetchItem();
+ ++checked_fields_counter_;
+}
+
+// Compares the |checked_fields_counter_| value with the number of columns in
+// the SQLite table to make sure they match. This should be run after all
+// PrefetchItem fields were verified with CheckFieldAndResetItem and it helps in
+// confirming PrefetchItem implementation and tests are coping with changes in
+// the table.
+void PrefetchItemTest::CheckAllFieldsWereTested() {
+ // Note: the off-by-1 difference is due to the single client_id field, of type
+ // ClientID, representing 2 columns in the database table (client_namespace
+ // and client_id).
+ EXPECT_EQ(GetTableColumnsCount() - 1, checked_fields_counter_)
+ << "The number of tested fields mismatches the number of columns in the "
+ "database table.";
+}
+
+// Computes the number of columns the SQL table has.
+std::size_t PrefetchItemTest::GetTableColumnsCount() {
+ std::string tableCreationSql(PrefetchStore::GetTableCreationSqlForTesting());
+ std::vector<std::string> create_statement_split = base::SplitString(
+ tableCreationSql, "()", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+ EXPECT_EQ(3U, create_statement_split.size());
+
+ std::string& columns_list = create_statement_split[1];
+ std::vector<std::string> columns_split = base::SplitString(
+ columns_list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ return columns_split.size();
+}
+
+TEST_F(PrefetchItemTest, OperatorEqualsCopyConstructorAndToString) {
PrefetchItem item1;
EXPECT_EQ(item1, PrefetchItem());
EXPECT_EQ(item1, PrefetchItem(item1));
+ EXPECT_EQ(item1.ToString(), PrefetchItem().ToString());
item1.offline_id = 77L;
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "offline_id");
item1.guid = "A";
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "guid");
item1.client_id = ClientId("B", "C");
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "client_id");
item1.state = PrefetchItemState::AWAITING_GCM;
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "state");
item1.url = GURL("http://test.com");
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "url");
item1.final_archived_url = GURL("http://test.com/final");
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "final_archived_url");
- item1.request_archive_attempt_count = 10;
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ item1.generate_bundle_attempts = 10;
+ CheckFieldAndResetItem(item1, "generate_bundle_attempts");
+
+ item1.get_operation_attempts = 11;
+ CheckFieldAndResetItem(item1, "get_operation_attempts");
+
+ item1.download_initiation_attempts = 12;
+ CheckFieldAndResetItem(item1, "download_initiation_attempts");
item1.operation_name = "D";
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "operation_name");
item1.archive_body_name = "E";
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "archive_body_name");
item1.archive_body_length = 20;
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "archive_body_length");
item1.creation_time = base::Time::FromJavaTime(1000L);
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "creation_time");
item1.freshness_time = base::Time::FromJavaTime(2000L);
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
- item1 = PrefetchItem();
+ CheckFieldAndResetItem(item1, "freshness_time");
- item1.error_code = PrefetchItemErrorCode::EXPIRED;
- EXPECT_NE(item1, PrefetchItem());
- EXPECT_EQ(item1, PrefetchItem(item1));
+ item1.error_code = PrefetchItemErrorCode::TOO_MANY_NEW_URLS;
+ CheckFieldAndResetItem(item1, "error_code");
+
+ item1.title = base::UTF8ToUTF16("F");
+ CheckFieldAndResetItem(item1, "title");
+
+ item1.file_path = base::FilePath(FILE_PATH_LITERAL("G"));
+ CheckFieldAndResetItem(item1, "file_path");
+
+ item1.file_size = 30;
+ CheckFieldAndResetItem(item1, "file_size");
+
+ CheckAllFieldsWereTested();
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory.h b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory.h
index de785448de5..835ce2156fd 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory.h
@@ -6,29 +6,35 @@
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_NETWORK_REQUEST_FACTORY_H_
#include <memory>
+#include <set>
#include <string>
#include <vector>
#include "components/offline_pages/core/prefetch/prefetch_types.h"
namespace offline_pages {
-class GeneratePageBundleRequest;
class GetOperationRequest;
class PrefetchNetworkRequestFactory {
public:
virtual ~PrefetchNetworkRequestFactory() = default;
+ // Returns 'true' if there is at least one outstanding active network
+ // request. Used to determine if the background processing window can be
+ // closed.
+ virtual bool HasOutstandingRequests() const = 0;
+
// Creates and starts a new GeneratePageBundle request, retaining ownership.
- // If a GeneratePageBundle request already exists, this will cancel the
- // existing request and start a new one.
+ // If a GeneratePageBundle request for one or more specified URLs already
+ // exists, this will create another one regardless.
virtual void MakeGeneratePageBundleRequest(
const std::vector<std::string>& prefetch_urls,
const std::string& gcm_registration_id,
const PrefetchRequestFinishedCallback& callback) = 0;
- // Gets the current GeneratePageBundleRequest. After |callback| is executed,
- // this will return |nullptr|.
- virtual GeneratePageBundleRequest* CurrentGeneratePageBundleRequest()
+
+ // Returns a list of URLs included into all currently ongoing
+ // GeneratePageBundle requests.
+ virtual std::unique_ptr<std::set<std::string>> GetAllUrlsRequested()
const = 0;
// Creates and starts a new GetOperationRequest, retaining ownership.
@@ -37,9 +43,15 @@ class PrefetchNetworkRequestFactory {
virtual void MakeGetOperationRequest(
const std::string& operation_name,
const PrefetchRequestFinishedCallback& callback) = 0;
+
// Returns the current GetOperationRequest with the given name, if any.
virtual GetOperationRequest* FindGetOperationRequestByName(
const std::string& operation_name) const = 0;
+
+ // Returns a list of operation names included into all currently ongoing
+ // GetOperation requests.
+ virtual std::unique_ptr<std::set<std::string>> GetAllOperationNamesRequested()
+ const = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
index ddb9e4224f9..f6f1f907cfb 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.cc
@@ -9,8 +9,15 @@
#include "components/offline_pages/core/prefetch/generate_page_bundle_request.h"
#include "components/offline_pages/core/prefetch/get_operation_request.h"
+namespace {
constexpr int kMaxBundleSizeBytes = 20 * 1024 * 1024; // 20 MB
+// Max concurrent outstanding requests. If more requests asked to be created,
+// the requests are silently not created (considered failed). This is used
+// as emergency limit that should rarely be encountered in normal operations.
+const int kMaxConcurrentRequests = 10;
+} // namespace
+
namespace offline_pages {
PrefetchNetworkRequestFactoryImpl::PrefetchNetworkRequestFactoryImpl(
@@ -25,26 +32,42 @@ PrefetchNetworkRequestFactoryImpl::PrefetchNetworkRequestFactoryImpl(
PrefetchNetworkRequestFactoryImpl::~PrefetchNetworkRequestFactoryImpl() =
default;
+bool PrefetchNetworkRequestFactoryImpl::HasOutstandingRequests() const {
+ return !(generate_page_bundle_requests_.empty() &&
+ get_operation_requests_.empty());
+}
+
void PrefetchNetworkRequestFactoryImpl::MakeGeneratePageBundleRequest(
const std::vector<std::string>& url_strings,
const std::string& gcm_registration_id,
const PrefetchRequestFinishedCallback& callback) {
- generate_page_bundle_request_ = base::MakeUnique<GeneratePageBundleRequest>(
- user_agent_, gcm_registration_id, kMaxBundleSizeBytes, url_strings,
- channel_, request_context_.get(),
- base::Bind(
- &PrefetchNetworkRequestFactoryImpl::GeneratePageBundleRequestDone,
- weak_factory_.GetWeakPtr(), callback));
+ if (!AddConcurrentRequest())
+ return;
+ uint64_t request_id = GetNextRequestId();
+ generate_page_bundle_requests_[request_id] =
+ base::MakeUnique<GeneratePageBundleRequest>(
+ user_agent_, gcm_registration_id, kMaxBundleSizeBytes, url_strings,
+ channel_, request_context_.get(),
+ base::Bind(
+ &PrefetchNetworkRequestFactoryImpl::GeneratePageBundleRequestDone,
+ weak_factory_.GetWeakPtr(), callback, request_id));
}
-GeneratePageBundleRequest*
-PrefetchNetworkRequestFactoryImpl::CurrentGeneratePageBundleRequest() const {
- return generate_page_bundle_request_.get();
+std::unique_ptr<std::set<std::string>>
+PrefetchNetworkRequestFactoryImpl::GetAllUrlsRequested() const {
+ auto result = base::MakeUnique<std::set<std::string>>();
+ for (const auto& request_pair : generate_page_bundle_requests_) {
+ for (const auto& url : request_pair.second->requested_urls())
+ result->insert(url);
+ }
+ return result;
}
void PrefetchNetworkRequestFactoryImpl::MakeGetOperationRequest(
const std::string& operation_name,
const PrefetchRequestFinishedCallback& callback) {
+ if (!AddConcurrentRequest())
+ return;
get_operation_requests_[operation_name] =
base::MakeUnique<GetOperationRequest>(
operation_name, channel_, request_context_.get(),
@@ -55,11 +78,13 @@ void PrefetchNetworkRequestFactoryImpl::MakeGetOperationRequest(
void PrefetchNetworkRequestFactoryImpl::GeneratePageBundleRequestDone(
const PrefetchRequestFinishedCallback& callback,
+ uint64_t request_id,
PrefetchRequestStatus status,
const std::string& operation_name,
const std::vector<RenderPageInfo>& pages) {
callback.Run(status, operation_name, pages);
- generate_page_bundle_request_.reset();
+ generate_page_bundle_requests_.erase(request_id);
+ ReleaseConcurrentRequest();
}
void PrefetchNetworkRequestFactoryImpl::GetOperationRequestDone(
@@ -69,6 +94,7 @@ void PrefetchNetworkRequestFactoryImpl::GetOperationRequestDone(
const std::vector<RenderPageInfo>& pages) {
callback.Run(status, operation_name, pages);
get_operation_requests_.erase(operation_name);
+ ReleaseConcurrentRequest();
}
GetOperationRequest*
@@ -81,4 +107,29 @@ PrefetchNetworkRequestFactoryImpl::FindGetOperationRequestByName(
return iter->second.get();
}
+bool PrefetchNetworkRequestFactoryImpl::AddConcurrentRequest() {
+ if (concurrent_request_count_ >= kMaxConcurrentRequests)
+ return false;
+ ++concurrent_request_count_;
+ return true;
+}
+
+std::unique_ptr<std::set<std::string>>
+PrefetchNetworkRequestFactoryImpl::GetAllOperationNamesRequested() const {
+ auto result = base::MakeUnique<std::set<std::string>>();
+ for (const auto& request_pair : get_operation_requests_)
+ result->insert(request_pair.first);
+ return result;
+}
+
+void PrefetchNetworkRequestFactoryImpl::ReleaseConcurrentRequest() {
+ DCHECK(concurrent_request_count_ > 0);
+ --concurrent_request_count_;
+}
+
+// In-memory request id, incremented for each new GeneratePageBundleRequest.
+uint64_t PrefetchNetworkRequestFactoryImpl::GetNextRequestId() {
+ return ++request_id_;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h
index 57f1d149f47..3c481084a0a 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h
@@ -7,6 +7,7 @@
#include <map>
#include <memory>
+#include <set>
#include <string>
#include <vector>
@@ -28,36 +29,63 @@ class PrefetchNetworkRequestFactoryImpl : public PrefetchNetworkRequestFactory {
~PrefetchNetworkRequestFactoryImpl() override;
+ bool HasOutstandingRequests() const override;
+
void MakeGeneratePageBundleRequest(
const std::vector<std::string>& prefetch_urls,
const std::string& gcm_registration_id,
const PrefetchRequestFinishedCallback& callback) override;
- GeneratePageBundleRequest* CurrentGeneratePageBundleRequest() const override;
+
+ std::unique_ptr<std::set<std::string>> GetAllUrlsRequested() const override;
void MakeGetOperationRequest(
const std::string& operation_name,
const PrefetchRequestFinishedCallback& callback) override;
+
GetOperationRequest* FindGetOperationRequestByName(
const std::string& operation_name) const override;
+ std::unique_ptr<std::set<std::string>> GetAllOperationNamesRequested()
+ const override;
+
private:
void GeneratePageBundleRequestDone(
const PrefetchRequestFinishedCallback& callback,
+ uint64_t request_id,
PrefetchRequestStatus status,
const std::string& operation_name,
const std::vector<RenderPageInfo>& pages);
+
void GetOperationRequestDone(const PrefetchRequestFinishedCallback& callback,
PrefetchRequestStatus status,
const std::string& operation_name,
const std::vector<RenderPageInfo>& pages);
+
+ // Returns 'true' if a new network request can be created, 'false' if the
+ // maximum count of concurrent network requests has been reached.
+ bool AddConcurrentRequest();
+
+ // Called when network request finishes, decrementing the counter of
+ // concurrent network requests.
+ void ReleaseConcurrentRequest();
+
+ uint64_t GetNextRequestId();
+
scoped_refptr<net::URLRequestContextGetter> request_context_;
version_info::Channel channel_;
std::string user_agent_;
- std::unique_ptr<GeneratePageBundleRequest> generate_page_bundle_request_;
+ std::map<uint64_t, std::unique_ptr<GeneratePageBundleRequest>>
+ generate_page_bundle_requests_;
std::map<std::string, std::unique_ptr<GetOperationRequest>>
get_operation_requests_;
+ // Count of concurrent network requests of any type. Used as emergency limiter
+ // to prevent generating too many parallel network requests.
+ size_t concurrent_request_count_ = 0;
+ // Used to id GeneratePageBundle requests so they can be removed from the map.
+ uint64_t request_id_ = 0;
+
base::WeakPtrFactory<PrefetchNetworkRequestFactoryImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrefetchNetworkRequestFactoryImpl);
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 8a91b7632e5..09756e87865 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
@@ -12,10 +12,16 @@
#include "components/version_info/channel.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::Contains;
+using testing::Not;
+
namespace offline_pages {
+// TODO(dimich): Add tests that cancel/fail/complete the requests and
+// verify that the tests are removed form maps etc.
class PrefetchNetworkRequestFactoryTest : public testing::Test {
public:
PrefetchNetworkRequestFactoryTest();
@@ -44,19 +50,29 @@ TEST_F(PrefetchNetworkRequestFactoryTest, TestMakeGetOperationRequest) {
// Query whether there is an operation to start with, before we make a
// request.
std::string operation_name = "an operation";
+ EXPECT_FALSE(request_factory()->HasOutstandingRequests());
GetOperationRequest* request =
request_factory()->FindGetOperationRequestByName(operation_name);
EXPECT_EQ(nullptr, request);
+ auto operation_names = request_factory()->GetAllOperationNamesRequested();
+ EXPECT_TRUE(operation_names->empty());
+
// Then, make the request and ensure we can find it by name.
request_factory()->MakeGetOperationRequest(operation_name,
PrefetchRequestFinishedCallback());
+ EXPECT_TRUE(request_factory()->HasOutstandingRequests());
request = request_factory()->FindGetOperationRequestByName(operation_name);
EXPECT_NE(nullptr, request);
+ operation_names = request_factory()->GetAllOperationNamesRequested();
+ EXPECT_EQ(1UL, operation_names->size());
+ EXPECT_THAT(*operation_names, Contains(operation_name));
+
// Then check that a request is not found for another name (which was not
// requested).
std::string operation_name_2 = "another operation";
+ EXPECT_TRUE(request_factory()->HasOutstandingRequests());
GetOperationRequest* request_2 =
request_factory()->FindGetOperationRequestByName(operation_name_2);
EXPECT_EQ(nullptr, request_2);
@@ -86,19 +102,109 @@ TEST_F(PrefetchNetworkRequestFactoryTest, TestMakeGeneratePageBundleRequest) {
std::vector<std::string> urls = {"example.com/1", "example.com/2"};
std::string reg_id = "a registration id";
- GeneratePageBundleRequest* request =
- request_factory()->CurrentGeneratePageBundleRequest();
- EXPECT_EQ(nullptr, request);
+ EXPECT_FALSE(request_factory()->HasOutstandingRequests());
request_factory()->MakeGeneratePageBundleRequest(
urls, reg_id, PrefetchRequestFinishedCallback());
- request = request_factory()->CurrentGeneratePageBundleRequest();
- EXPECT_NE(nullptr, request);
- urls = {"example.com/3"};
+ EXPECT_TRUE(request_factory()->HasOutstandingRequests());
+
+ auto requested_urls = request_factory()->GetAllUrlsRequested();
+ EXPECT_THAT(*requested_urls, Contains(urls[0]));
+ EXPECT_THAT(*requested_urls, Contains(urls[1]));
+
+ std::vector<std::string> urls2 = {"example.com/3"};
request_factory()->MakeGeneratePageBundleRequest(
- urls, reg_id, PrefetchRequestFinishedCallback());
- EXPECT_NE(request, request_factory()->CurrentGeneratePageBundleRequest());
+ urls2, reg_id, PrefetchRequestFinishedCallback());
+ requested_urls = request_factory()->GetAllUrlsRequested();
+ EXPECT_THAT(*requested_urls, Contains(urls[0]));
+ EXPECT_THAT(*requested_urls, Contains(urls[1]));
+ EXPECT_THAT(*requested_urls, Contains(urls2[0]));
+}
+
+TEST_F(PrefetchNetworkRequestFactoryTest, ManyGenerateBundleRequests) {
+ std::vector<std::string> urls1 = {"example.com/1"};
+ std::string reg_id = "a registration id";
+ const int kTooManyRequests = 20;
+
+ for (int i = 0; i < kTooManyRequests; ++i) {
+ request_factory()->MakeGeneratePageBundleRequest(
+ urls1, reg_id, PrefetchRequestFinishedCallback());
+ }
+
+ // Add one more request, over the maximum count of concurrent requests.
+ std::vector<std::string> urls2 = {"example.com/2"};
+ request_factory()->MakeGeneratePageBundleRequest(
+ urls2, reg_id, PrefetchRequestFinishedCallback());
+
+ auto requested_urls = request_factory()->GetAllUrlsRequested();
+ EXPECT_THAT(*requested_urls, Contains(urls1[0]));
+ // Requests over maximum concurrent count of requests should not be made.
+ EXPECT_THAT(*requested_urls, Not(Contains(urls2[0])));
+}
+
+TEST_F(PrefetchNetworkRequestFactoryTest, ManyGetOperationRequests) {
+ std::string operation_name1 = "an operation 1";
+ const int kTooManyRequests = 20;
+
+ for (int i = 0; i < kTooManyRequests; ++i) {
+ request_factory()->MakeGetOperationRequest(
+ operation_name1, PrefetchRequestFinishedCallback());
+ }
+
+ // Add one more request, over the maximum count of concurrent requests.
+ std::string operation_name2 = "an operation 2";
+ request_factory()->MakeGetOperationRequest(operation_name2,
+ PrefetchRequestFinishedCallback());
+
+ auto operation_names = request_factory()->GetAllOperationNamesRequested();
+ EXPECT_THAT(*operation_names, Contains(operation_name1));
+ // Requests over maximum concurrent count of requests should not be made.
+ EXPECT_THAT(*operation_names, Not(Contains(operation_name2)));
+
+ EXPECT_NE(nullptr,
+ request_factory()->FindGetOperationRequestByName(operation_name1));
+ // Requests over maximum concurrent count of requests should not be made.
+ EXPECT_EQ(nullptr,
+ request_factory()->FindGetOperationRequestByName(operation_name2));
+}
+
+TEST_F(PrefetchNetworkRequestFactoryTest, ManyRequestsMixedType) {
+ std::string operation_name1 = "an operation 1";
+ const int kNotTooManyRequests = 6;
+
+ for (int i = 0; i < kNotTooManyRequests; ++i) {
+ request_factory()->MakeGetOperationRequest(
+ operation_name1, PrefetchRequestFinishedCallback());
+ }
+
+ // Still possible to make more requests...
+ std::string operation_name2 = "an operation 2";
+ request_factory()->MakeGetOperationRequest(operation_name2,
+ PrefetchRequestFinishedCallback());
+
+ auto operation_names = request_factory()->GetAllOperationNamesRequested();
+ EXPECT_THAT(*operation_names, Contains(operation_name1));
+ EXPECT_THAT(*operation_names, Contains(operation_name2));
+
+ // This should get the factory over the max number of allowed requests.
+ std::vector<std::string> urls1 = {"example.com/1"};
+ std::string reg_id = "a registration id";
+ for (int i = 0; i < kNotTooManyRequests; ++i) {
+ request_factory()->MakeGeneratePageBundleRequest(
+ urls1, reg_id, PrefetchRequestFinishedCallback());
+ }
+
+ // Add one more request, over the maximum count of concurrent requests.
+ std::string operation_name3 = "an operation 3";
+ request_factory()->MakeGetOperationRequest(operation_name3,
+ PrefetchRequestFinishedCallback());
+
+ operation_names = request_factory()->GetAllOperationNamesRequested();
+ EXPECT_THAT(*operation_names, Contains(operation_name1));
+ EXPECT_THAT(*operation_names, Contains(operation_name2));
+ // Requests over maximum concurrent count of requests should not be made.
+ EXPECT_THAT(*operation_names, Not(Contains(operation_name3)));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc b/chromium/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
index d533ab1b0a7..00a1fa5d68e 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_request_fetcher.cc
@@ -67,7 +67,7 @@ PrefetchRequestFetcher::PrefetchRequestFetcher(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable the offline prefetch by toggling"
"chrome://flags#offline-prefetch in Chromium on Android."
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 1a6305d1450..1cef6704971 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
@@ -48,4 +48,8 @@ net::TestURLFetcher* PrefetchRequestTestBase::GetRunningFetcher() {
return url_fetcher_factory_.GetFetcherByID(0);
}
+void PrefetchRequestTestBase::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.h b/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.h
index a45e94da730..914978a4aa5 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.h
@@ -29,6 +29,8 @@ class PrefetchRequestTestBase : public testing::Test {
return request_context_.get();
}
+ void PumpLoop();
+
private:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service.h b/chromium/components/offline_pages/core/prefetch/prefetch_service.h
index 974a3dcf5c7..26058335ec5 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service.h
@@ -10,6 +10,8 @@
namespace offline_pages {
class OfflineEventLogger;
class OfflineMetricsCollector;
+class PrefetchBackgroundTaskHandler;
+class PrefetchConfiguration;
class PrefetchDispatcher;
class PrefetchDownloader;
class PrefetchGCMHandler;
@@ -37,6 +39,8 @@ class PrefetchService : public KeyedService {
virtual PrefetchDownloader* GetPrefetchDownloader() = 0;
virtual PrefetchStore* GetPrefetchStore() = 0;
virtual PrefetchImporter* GetPrefetchImporter() = 0;
+ virtual PrefetchBackgroundTaskHandler* GetPrefetchBackgroundTaskHandler() = 0;
+ virtual PrefetchConfiguration* GetPrefetchConfiguration() = 0;
// May be |nullptr| in tests. The PrefetchService does not depend on the
// SuggestedArticlesObserver, it merely owns it for lifetime purposes.
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 f8525bee927..679af76b54a 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc
@@ -11,6 +11,8 @@
#include "components/offline_pages/core/client_id.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "components/offline_pages/core/prefetch/offline_metrics_collector.h"
+#include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
+#include "components/offline_pages/core/prefetch/prefetch_configuration.h"
#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
@@ -29,7 +31,10 @@ PrefetchServiceImpl::PrefetchServiceImpl(
std::unique_ptr<PrefetchStore> prefetch_store,
std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer,
std::unique_ptr<PrefetchDownloader> prefetch_downloader,
- std::unique_ptr<PrefetchImporter> prefetch_importer)
+ std::unique_ptr<PrefetchImporter> prefetch_importer,
+ std::unique_ptr<PrefetchBackgroundTaskHandler>
+ prefetch_background_task_handler,
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration)
: offline_metrics_collector_(std::move(offline_metrics_collector)),
prefetch_dispatcher_(std::move(dispatcher)),
prefetch_gcm_handler_(std::move(gcm_handler)),
@@ -37,14 +42,17 @@ PrefetchServiceImpl::PrefetchServiceImpl(
prefetch_store_(std::move(prefetch_store)),
suggested_articles_observer_(std::move(suggested_articles_observer)),
prefetch_downloader_(std::move(prefetch_downloader)),
- prefetch_importer_(std::move(prefetch_importer)) {
+ prefetch_importer_(std::move(prefetch_importer)),
+ prefetch_background_task_handler_(
+ std::move(prefetch_background_task_handler)),
+ prefetch_configuration_(std::move(prefetch_configuration)) {
prefetch_dispatcher_->SetService(this);
+ prefetch_downloader_->SetPrefetchService(this);
prefetch_gcm_handler_->SetService(this);
suggested_articles_observer_->SetPrefetchService(this);
- prefetch_downloader_->SetCompletedCallback(
- base::Bind(&PrefetchServiceImpl::OnDownloadCompleted,
- // Downloader is owned by this instance.
- base::Unretained(this)));
+ // TODO(dimich): OK for experiments, only takes a little memory if experiment
+ // is enabled. Remove before stable launch.
+ logger_.SetIsLogging(true);
}
PrefetchServiceImpl::~PrefetchServiceImpl() = default;
@@ -86,22 +94,18 @@ PrefetchImporter* PrefetchServiceImpl::GetPrefetchImporter() {
return prefetch_importer_.get();
}
-void PrefetchServiceImpl::Shutdown() {
- suggested_articles_observer_.reset();
- prefetch_downloader_.reset();
+PrefetchBackgroundTaskHandler*
+PrefetchServiceImpl::GetPrefetchBackgroundTaskHandler() {
+ return prefetch_background_task_handler_.get();
}
-void PrefetchServiceImpl::OnDownloadCompleted(
- const PrefetchDownloadResult& result) {
- logger_.RecordActivity("Download " + result.download_id +
- (result.success ? " succeeded" : " failed"));
- if (!result.success)
- return;
-
- logger_.RecordActivity("Downloaded as " + result.file_path.MaybeAsASCII() +
- " with size " + std::to_string(result.file_size));
+PrefetchConfiguration* PrefetchServiceImpl::GetPrefetchConfiguration() {
+ return prefetch_configuration_.get();
+}
- // TODO(jianli): To hook up with prefetch importer.
+void PrefetchServiceImpl::Shutdown() {
+ suggested_articles_observer_.reset();
+ prefetch_downloader_.reset();
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.h
index e79935d750e..7f9b17164c4 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "components/offline_pages/core/offline_event_logger.h"
+#include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
@@ -24,7 +25,10 @@ class PrefetchServiceImpl : public PrefetchService {
std::unique_ptr<PrefetchStore> prefetch_store,
std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer,
std::unique_ptr<PrefetchDownloader> prefetch_downloader,
- std::unique_ptr<PrefetchImporter> prefetch_importer);
+ std::unique_ptr<PrefetchImporter> prefetch_importer,
+ std::unique_ptr<PrefetchBackgroundTaskHandler> background_task_handler,
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration);
+
~PrefetchServiceImpl() override;
// PrefetchService implementation:
@@ -37,14 +41,13 @@ class PrefetchServiceImpl : public PrefetchService {
OfflineEventLogger* GetLogger() override;
PrefetchDownloader* GetPrefetchDownloader() override;
PrefetchImporter* GetPrefetchImporter() override;
+ PrefetchBackgroundTaskHandler* GetPrefetchBackgroundTaskHandler() override;
+ PrefetchConfiguration* GetPrefetchConfiguration() override;
// KeyedService implementation:
void Shutdown() override;
private:
- // Called when a download completes.
- void OnDownloadCompleted(const PrefetchDownloadResult& result);
-
OfflineEventLogger logger_;
std::unique_ptr<OfflineMetricsCollector> offline_metrics_collector_;
@@ -55,6 +58,9 @@ class PrefetchServiceImpl : public PrefetchService {
std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_;
std::unique_ptr<PrefetchDownloader> prefetch_downloader_;
std::unique_ptr<PrefetchImporter> prefetch_importer_;
+ std::unique_ptr<PrefetchBackgroundTaskHandler>
+ prefetch_background_task_handler_;
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration_;
DISALLOW_COPY_AND_ASSIGN(PrefetchServiceImpl);
};
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
index 5aaa109e5a5..e57deff0e53 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
@@ -6,11 +6,15 @@
#include <utility>
+#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/prefetch/offline_metrics_collector.h"
+#include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
+#include "components/offline_pages/core/prefetch/prefetch_configuration.h"
#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
+#include "components/offline_pages/core/prefetch/prefetch_downloader_impl.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_importer.h"
#include "components/offline_pages/core/prefetch/prefetch_service_impl.h"
@@ -26,7 +30,34 @@
namespace offline_pages {
namespace {
+
const version_info::Channel kTestChannel = version_info::Channel::UNKNOWN;
+
+class StubPrefetchBackgroundTaskHandler : public PrefetchBackgroundTaskHandler {
+ public:
+ StubPrefetchBackgroundTaskHandler() = default;
+ ~StubPrefetchBackgroundTaskHandler() override = default;
+ void CancelBackgroundTask() override {}
+ void EnsureTaskScheduled() override {}
+ void Backoff() override {}
+ void ResetBackoff() override {}
+ int GetAdditionalBackoffSeconds() const override { return 0; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubPrefetchBackgroundTaskHandler);
+};
+
+class StubPrefetchConfiguration : public PrefetchConfiguration {
+ public:
+ StubPrefetchConfiguration() = default;
+ ~StubPrefetchConfiguration() override = default;
+
+ bool IsPrefetchingEnabledBySettings() override { return true; };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubPrefetchConfiguration);
+};
+
} // namespace
PrefetchServiceTestTaco::PrefetchServiceTestTaco() {
@@ -35,17 +66,18 @@ PrefetchServiceTestTaco::PrefetchServiceTestTaco() {
gcm_handler_ = base::MakeUnique<TestPrefetchGCMHandler>();
network_request_factory_ =
base::MakeUnique<TestPrefetchNetworkRequestFactory>();
-
- PrefetchStoreTestUtil store_test_util;
- store_test_util.BuildStoreInMemory();
- prefetch_store_sql_ = store_test_util.ReleaseStore();
-
+ prefetch_store_sql_ =
+ base::MakeUnique<PrefetchStore>(base::ThreadTaskRunnerHandle::Get());
suggested_articles_observer_ = base::MakeUnique<SuggestedArticlesObserver>();
- prefetch_downloader_ = base::WrapUnique(new PrefetchDownloader(kTestChannel));
+ prefetch_downloader_ =
+ base::WrapUnique(new PrefetchDownloaderImpl(kTestChannel));
prefetch_importer_ = base::MakeUnique<TestPrefetchImporter>();
// This sets up the testing articles as an empty vector, we can ignore the
// result here. This allows us to not create a ContentSuggestionsService.
suggested_articles_observer_->GetTestingArticles();
+ prefetch_background_task_handler_ =
+ base::MakeUnique<StubPrefetchBackgroundTaskHandler>();
+ prefetch_configuration_ = base::MakeUnique<StubPrefetchConfiguration>();
}
PrefetchServiceTestTaco::~PrefetchServiceTestTaco() = default;
@@ -98,6 +130,20 @@ void PrefetchServiceTestTaco::SetPrefetchImporter(
prefetch_importer_ = std::move(prefetch_importer);
}
+void PrefetchServiceTestTaco::SetPrefetchBackgroundTaskHandler(
+ std::unique_ptr<PrefetchBackgroundTaskHandler>
+ prefetch_background_task_handler) {
+ CHECK(!prefetch_service_);
+ prefetch_background_task_handler_ =
+ std::move(prefetch_background_task_handler);
+}
+
+void PrefetchServiceTestTaco::SetPrefetchConfiguration(
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration) {
+ CHECK(!prefetch_service_);
+ prefetch_configuration_ = std::move(prefetch_configuration);
+}
+
void PrefetchServiceTestTaco::CreatePrefetchService() {
CHECK(metrics_collector_ && dispatcher_ && gcm_handler_ &&
network_request_factory_ && prefetch_store_sql_ &&
@@ -107,7 +153,9 @@ void PrefetchServiceTestTaco::CreatePrefetchService() {
std::move(metrics_collector_), std::move(dispatcher_),
std::move(gcm_handler_), std::move(network_request_factory_),
std::move(prefetch_store_sql_), std::move(suggested_articles_observer_),
- std::move(prefetch_downloader_), std::move(prefetch_importer_));
+ std::move(prefetch_downloader_), std::move(prefetch_importer_),
+ std::move(prefetch_background_task_handler_),
+ std::move(prefetch_configuration_));
}
std::unique_ptr<PrefetchService>
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
index 3e15c51cd0a..21798a2d64f 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
@@ -13,6 +13,8 @@
namespace offline_pages {
class OfflineMetricsCollector;
+class PrefetchBackgroundTaskHandler;
+class PrefetchConfiguration;
class PrefetchDispatcher;
class PrefetchDownloader;
class PrefetchGCMHandler;
@@ -53,6 +55,11 @@ class PrefetchServiceTestTaco {
void SetPrefetchDownloader(
std::unique_ptr<PrefetchDownloader> prefetch_downloader);
void SetPrefetchImporter(std::unique_ptr<PrefetchImporter> prefetch_importer);
+ void SetPrefetchBackgroundTaskHandler(
+ std::unique_ptr<PrefetchBackgroundTaskHandler>
+ prefetch_background_task_handler);
+ void SetPrefetchConfiguration(
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration);
// Creates and caches an instance of PrefetchService, using default or
// overridden test dependencies.
@@ -78,6 +85,9 @@ class PrefetchServiceTestTaco {
std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_;
std::unique_ptr<PrefetchDownloader> prefetch_downloader_;
std::unique_ptr<PrefetchImporter> prefetch_importer_;
+ std::unique_ptr<PrefetchBackgroundTaskHandler>
+ prefetch_background_task_handler_;
+ std::unique_ptr<PrefetchConfiguration> prefetch_configuration_;
std::unique_ptr<PrefetchService> prefetch_service_;
};
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_types.cc b/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
index 7f68f576d70..59e0c5b9fe8 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
@@ -14,7 +14,7 @@ PrefetchDownloadResult::PrefetchDownloadResult() = default;
PrefetchDownloadResult::PrefetchDownloadResult(const std::string& download_id,
const base::FilePath& file_path,
- uint64_t file_size)
+ int64_t file_size)
: download_id(download_id),
success(true),
file_path(file_path),
@@ -23,4 +23,21 @@ PrefetchDownloadResult::PrefetchDownloadResult(const std::string& download_id,
PrefetchDownloadResult::PrefetchDownloadResult(
const PrefetchDownloadResult& other) = default;
+bool PrefetchDownloadResult::operator==(
+ const PrefetchDownloadResult& other) const {
+ return download_id == other.download_id && success == other.success &&
+ file_path == other.file_path && file_size == other.file_size;
+}
+
+PrefetchArchiveInfo::PrefetchArchiveInfo() = default;
+
+PrefetchArchiveInfo::PrefetchArchiveInfo(const PrefetchArchiveInfo& other) =
+ default;
+
+PrefetchArchiveInfo::~PrefetchArchiveInfo() = default;
+
+bool PrefetchArchiveInfo::empty() const {
+ return offline_id == 0;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_types.h b/chromium/components/offline_pages/core/prefetch/prefetch_types.h
index 1fdb49a0983..87dc2ec4ff3 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_types.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_types.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/files/file_path.h"
+#include "base/strings/string16.h"
#include "base/time/time.h"
#include "components/offline_pages/core/client_id.h"
#include "url/gurl.h"
@@ -69,39 +70,90 @@ struct RenderPageInfo {
// might be skipped.
enum class PrefetchItemState {
// New request just received from the client.
- NEW_REQUEST,
+ NEW_REQUEST = 0,
// The item has been included in a GeneratePageBundle RPC requesting the
// creation of an archive for its URL.
- SENT_GENERATE_PAGE_BUNDLE,
+ SENT_GENERATE_PAGE_BUNDLE = 10,
// The archive was not immediately available (cached) upon the request and
// is now waiting for a GCM message notifying of its archiving operation
// completion.
- AWAITING_GCM,
+ AWAITING_GCM = 20,
// The GCM message notifying of the archiving operation completion was
// received for this item.
- RECEIVED_GCM,
+ RECEIVED_GCM = 30,
// A GetOperation RPC was sent for this item to query for the final results
// of its archiving request.
- SENT_GET_OPERATION,
+ SENT_GET_OPERATION = 40,
// Information was received about a successfully created archive for this
// item that can now be downloaded.
- RECEIVED_BUNDLE,
+ RECEIVED_BUNDLE = 50,
// This item's archive is currently being downloaded.
- DOWNLOADING,
+ DOWNLOADING = 60,
+ // The archive has been downloaded, waiting to be imported into offline pages
+ // model.
+ DOWNLOADED = 70,
+ // The archive is being imported into offline pages model.
+ IMPORTING = 80,
// Item has finished processing, successfully or otherwise, and is waiting to
// be processed for stats reporting to UMA.
- FINISHED,
+ FINISHED = 90,
// UMA stats have been reported and the item is being kept just long enough
// to confirm that the same URL is not being repeatedly requested by its
// client.
- ZOMBIE,
+ ZOMBIE = 100,
};
-// Error codes used to identify the reason why a prefetch item has finished
-// processing.
+// Error codes used to identify the reason why a prefetch entry has finished
+// processing in the pipeline. This values are only meaningful for entries in
+// the "finished" state.
+//
+// New entries can be added anywhere as long as they are assigned unique values
+// and kept in ascending order. Deprecated entries should be labeled as such but
+// never removed. Assigned values should never be reused. Remember to update the
+// MAX value if adding a new trailing item.
+//
+// Changes to this enum must be reflected in the respective metrics enum named
+// PrefetchItemErrorCode in enums.xml. Use the exact same integer value for each
+// mirrored entry.
enum class PrefetchItemErrorCode {
- SUCCESS,
- EXPIRED,
+ // The entry had gone through the pipeline and successfully completed
+ // prefetching. Explicitly setting to 0 as that is the default value for the
+ // respective SQLite column.
+ SUCCESS = 0,
+ // Got too many URLs from suggestions, canceled this one. See kMaxUrlsToSend
+ // defined in GeneratePageBundleTask.
+ TOO_MANY_NEW_URLS = 100,
+ // An error happened while attempting to download the archive file.
+ DOWNLOAD_ERROR = 200,
+ // An error happened while importing the downloaded archive file int the
+ // Offline Pages system.
+ IMPORT_ERROR = 300,
+ // Got a failure result from GetOperation (or the GeneratePageBundle
+ // metadata).
+ ARCHIVING_FAILED = 400,
+ // Got a failure result from GetOperation or GeneratePageBundle that a
+ // server-side limit on the page was exceeded.
+ ARCHIVING_LIMIT_EXCEEDED = 500,
+ // These next STALE_AT_* values identify entries that stayed for too long in
+ // the same pipeline bucket so that their "freshness date" was considered too
+ // old for what was allowed for that bucket. See StaleEntryFinalizerTask for
+ // more details.
+ STALE_AT_NEW_REQUEST = 600,
+ STALE_AT_AWAITING_GCM = 700,
+ STALE_AT_RECEIVED_GCM = 800,
+ STALE_AT_RECEIVED_BUNDLE = 900,
+ STALE_AT_DOWNLOADING = 1000,
+ STALE_AT_UNKNOWN = 1100,
+ // Exceeded maximum retries for get operation request.
+ GET_OPERATION_MAX_ATTEMPTS_REACHED = 1200,
+ // Exceeded maximum retries limit for generate page bundle request.
+ GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED = 1300,
+ // Exceeded maximum retries for download.
+ DOWNLOAD_MAX_ATTEMPTS_REACHED = 1400,
+ // Clock was set back too far in time.
+ MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED = 1500,
+ // Note: Must always have the same value as the last actual entry.
+ MAX = MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED
};
// Callback invoked upon completion of a prefetch request.
@@ -112,7 +164,10 @@ using PrefetchRequestFinishedCallback =
// Holds information about a suggested URL to be prefetched.
struct PrefetchURL {
- PrefetchURL(const std::string& id, const GURL& url) : id(id), url(url) {}
+ PrefetchURL(const std::string& id,
+ const GURL& url,
+ const base::string16& title)
+ : id(id), url(url), title(title) {}
// Client provided ID to allow the matching of provided URLs to the respective
// work item in the prefetching system within that client's assigned
@@ -122,6 +177,9 @@ struct PrefetchURL {
// This URL will be prefetched by the service.
GURL url;
+
+ // The title of the page.
+ base::string16 title;
};
// Result of a completed download.
@@ -129,19 +187,36 @@ struct PrefetchDownloadResult {
PrefetchDownloadResult();
PrefetchDownloadResult(const std::string& download_id,
const base::FilePath& file_path,
- uint64_t file_size);
+ int64_t file_size);
PrefetchDownloadResult(const PrefetchDownloadResult& other);
+ bool operator==(const PrefetchDownloadResult& other) const;
std::string download_id;
bool success = false;
base::FilePath file_path;
- uint64_t file_size = 0u;
+ int64_t file_size = 0;
};
// Callback invoked upon completion of a download.
using PrefetchDownloadCompletedCallback =
base::Callback<void(const PrefetchDownloadResult& result)>;
+// Describes all the info needed to import an archive.
+struct PrefetchArchiveInfo {
+ PrefetchArchiveInfo();
+ PrefetchArchiveInfo(const PrefetchArchiveInfo& other);
+ ~PrefetchArchiveInfo();
+ bool empty() const;
+
+ int64_t offline_id = 0; // Defaults to invalid id.
+ ClientId client_id;
+ GURL url;
+ GURL final_archived_url;
+ base::string16 title;
+ base::FilePath file_path;
+ int64_t file_size = 0;
+};
+
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_TYPES_H_
diff --git a/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.cc b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.cc
new file mode 100644
index 00000000000..6bd9064a772
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.cc
@@ -0,0 +1,131 @@
+// 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/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h"
+
+#include <set>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+namespace {
+
+std::unique_ptr<std::vector<std::string>> GetAllOperationsSync(
+ sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT DISTINCT operation_name"
+ " FROM prefetch_items"
+ " WHERE state = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::SENT_GET_OPERATION));
+
+ std::unique_ptr<std::vector<std::string>> operation_names;
+ while (statement.Step()) {
+ if (!operation_names)
+ operation_names = base::MakeUnique<std::vector<std::string>>();
+ operation_names->push_back(statement.ColumnString(0));
+ }
+ return operation_names;
+}
+
+bool UpdateOperationSync(const std::string& operation_name,
+ int max_attempts,
+ sql::Connection* db) {
+ // For all items in SENT_GET_OPERATION state and matching |operation_name|:
+ // * transit to RECEIVED_GCM state if not exceeding maximum attempts
+ // * transit to FINISHED state with error_code set otherwise.
+ static const char kSql[] =
+ "UPDATE prefetch_items"
+ " SET state = CASE WHEN get_operation_attempts < ? THEN ?"
+ " ELSE ? END,"
+ " error_code = CASE WHEN get_operation_attempts < ? THEN error_code"
+ " ELSE ? END"
+ " WHERE state = ? AND operation_name = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, max_attempts);
+ statement.BindInt(1, static_cast<int>(PrefetchItemState::RECEIVED_GCM));
+ statement.BindInt(2, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(3, max_attempts);
+ statement.BindInt(
+ 4, static_cast<int>(
+ PrefetchItemErrorCode::GET_OPERATION_MAX_ATTEMPTS_REACHED));
+ statement.BindInt(5, static_cast<int>(PrefetchItemState::SENT_GET_OPERATION));
+ statement.BindString(6, operation_name);
+
+ return statement.Run();
+}
+
+bool CleanupOperationsSync(
+ std::unique_ptr<std::set<std::string>> ongoing_operation_names,
+ int max_attempts,
+ sql::Connection* db) {
+ if (!db)
+ return false;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+
+ std::unique_ptr<std::vector<std::string>> tracked_operation_names =
+ GetAllOperationsSync(db);
+ if (!tracked_operation_names)
+ return false;
+
+ for (const auto& tracked_operation_name : *tracked_operation_names) {
+ // If the operation request is still running, do nothing.
+ if (ongoing_operation_names &&
+ ongoing_operation_names->count(tracked_operation_name) > 0)
+ continue;
+
+ // Otherwise, update the state to either retry the opeation or error out.
+ if (!UpdateOperationSync(tracked_operation_name, max_attempts, db))
+ return false;
+ }
+
+ return transaction.Commit();
+}
+
+} // namespace
+
+// static
+const int SentGetOperationCleanupTask::kMaxGetOperationAttempts = 3;
+
+SentGetOperationCleanupTask::SentGetOperationCleanupTask(
+ PrefetchStore* prefetch_store,
+ PrefetchNetworkRequestFactory* request_factory)
+ : prefetch_store_(prefetch_store),
+ request_factory_(request_factory),
+ weak_ptr_factory_(this) {}
+
+SentGetOperationCleanupTask::~SentGetOperationCleanupTask() {}
+
+void SentGetOperationCleanupTask::Run() {
+ std::unique_ptr<std::set<std::string>> ongoing_operation_names =
+ request_factory_->GetAllOperationNamesRequested();
+
+ prefetch_store_->Execute(
+ base::BindOnce(&CleanupOperationsSync, std::move(ongoing_operation_names),
+ kMaxGetOperationAttempts),
+ base::BindOnce(&SentGetOperationCleanupTask::OnFinished,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SentGetOperationCleanupTask::OnFinished(bool success) {
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h
new file mode 100644
index 00000000000..6a657acd541
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h
@@ -0,0 +1,42 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_SENT_GET_OPERATION_CLEANUP_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SENT_GET_OPERATION_CLEANUP_TASK_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchNetworkRequestFactory;
+class PrefetchStore;
+
+// Reconciliation task responsible for cleaning up database entries that are in
+// SENT_GET_OPERATION state.
+class SentGetOperationCleanupTask : public Task {
+ public:
+ // Maximum number of attempts allowed for get operation request.
+ static const int kMaxGetOperationAttempts;
+
+ SentGetOperationCleanupTask(PrefetchStore* prefetch_store,
+ PrefetchNetworkRequestFactory* request_factory);
+ ~SentGetOperationCleanupTask() override;
+
+ void Run() override;
+
+ private:
+ void OnFinished(bool success);
+
+ PrefetchStore* prefetch_store_; // Outlives this class.
+ PrefetchNetworkRequestFactory* request_factory_; // Outlives this class.
+
+ base::WeakPtrFactory<SentGetOperationCleanupTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SentGetOperationCleanupTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SENT_GET_OPERATION_CLEANUP_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc
new file mode 100644
index 00000000000..31f48fca469
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc
@@ -0,0 +1,173 @@
+// 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/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h"
+
+#include <string>
+
+#include "base/time/time.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+class TestingPrefetchNetworkRequestFactory
+ : public PrefetchNetworkRequestFactory {
+ public:
+ TestingPrefetchNetworkRequestFactory() {
+ ongoing_operation_names_ = base::MakeUnique<std::set<std::string>>();
+ }
+ ~TestingPrefetchNetworkRequestFactory() override = default;
+
+ // PrefetchNetworkRequestFactory implementation.
+ bool HasOutstandingRequests() const override { return false; }
+ void MakeGeneratePageBundleRequest(
+ const std::vector<std::string>& prefetch_urls,
+ const std::string& gcm_registration_id,
+ const PrefetchRequestFinishedCallback& callback) override {}
+ std::unique_ptr<std::set<std::string>> GetAllUrlsRequested() const override {
+ return std::unique_ptr<std::set<std::string>>();
+ }
+ void MakeGetOperationRequest(
+ const std::string& operation_name,
+ const PrefetchRequestFinishedCallback& callback) override {}
+ GetOperationRequest* FindGetOperationRequestByName(
+ const std::string& operation_name) const override {
+ return nullptr;
+ }
+ std::unique_ptr<std::set<std::string>> GetAllOperationNamesRequested()
+ const override {
+ return base::MakeUnique<std::set<std::string>>(*ongoing_operation_names_);
+ }
+
+ void AddOngoingOperation(const std::string& operation_name) {
+ ongoing_operation_names_->insert(operation_name);
+ }
+
+ private:
+ std::unique_ptr<std::set<std::string>> ongoing_operation_names_;
+};
+} // namespace
+
+class SentGetOperationCleanupTaskTest : public TaskTestBase {
+ public:
+ SentGetOperationCleanupTaskTest() = default;
+ ~SentGetOperationCleanupTaskTest() override = default;
+};
+
+TEST_F(SentGetOperationCleanupTaskTest, Retry) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
+ item.get_operation_attempts =
+ SentGetOperationCleanupTask::kMaxGetOperationAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ SentGetOperationCleanupTask task(store(), prefetch_request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::RECEIVED_GCM, store_item->state);
+ EXPECT_EQ(item.get_operation_attempts, store_item->get_operation_attempts);
+}
+
+TEST_F(SentGetOperationCleanupTaskTest, NoRetryForOngoingRequest) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
+ item.get_operation_attempts =
+ SentGetOperationCleanupTask::kMaxGetOperationAttempts - 1;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ std::unique_ptr<TestingPrefetchNetworkRequestFactory> request_factory =
+ base::MakeUnique<TestingPrefetchNetworkRequestFactory>();
+ request_factory->AddOngoingOperation(item.operation_name);
+
+ SentGetOperationCleanupTask task(store(), request_factory.get());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(SentGetOperationCleanupTaskTest, ErrorOnMaxAttempts) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
+ item.get_operation_attempts =
+ SentGetOperationCleanupTask::kMaxGetOperationAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ SentGetOperationCleanupTask task(store(), prefetch_request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(PrefetchItemState::FINISHED, store_item->state);
+ EXPECT_EQ(PrefetchItemErrorCode::GET_OPERATION_MAX_ATTEMPTS_REACHED,
+ store_item->error_code);
+ EXPECT_EQ(item.get_operation_attempts, store_item->get_operation_attempts);
+}
+
+TEST_F(SentGetOperationCleanupTaskTest, SkipForOngoingRequestWithMaxAttempts) {
+ PrefetchItem item =
+ item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
+ item.get_operation_attempts =
+ SentGetOperationCleanupTask::kMaxGetOperationAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+
+ std::unique_ptr<TestingPrefetchNetworkRequestFactory> request_factory =
+ base::MakeUnique<TestingPrefetchNetworkRequestFactory>();
+ request_factory->AddOngoingOperation(item.operation_name);
+
+ SentGetOperationCleanupTask task(store(), request_factory.get());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::unique_ptr<PrefetchItem> store_item =
+ store_util()->GetPrefetchItem(item.offline_id);
+ ASSERT_TRUE(store_item);
+ EXPECT_EQ(item, *store_item);
+}
+
+TEST_F(SentGetOperationCleanupTaskTest, NoUpdateForOtherStates) {
+ std::set<PrefetchItem> items;
+ std::vector<PrefetchItemState> all_other_states =
+ TaskTestBase::GetAllStatesExcept(PrefetchItemState::SENT_GET_OPERATION);
+ for (const auto& state : all_other_states) {
+ PrefetchItem item = item_generator()->CreateItem(state);
+ item.get_operation_attempts =
+ SentGetOperationCleanupTask::kMaxGetOperationAttempts;
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item));
+ items.insert(item);
+ }
+
+ SentGetOperationCleanupTask task(store(), prefetch_request_factory());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+
+ std::set<PrefetchItem> store_items;
+ store_util()->GetAllItems(&store_items);
+ EXPECT_EQ(items, store_items);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc
new file mode 100644
index 00000000000..63c6d8589ea
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc
@@ -0,0 +1,186 @@
+// 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/offline_pages/core/prefetch/stale_entry_finalizer_task.h"
+
+#include <array>
+
+#include "base/bind.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+using Result = StaleEntryFinalizerTask::Result;
+
+namespace {
+
+const base::TimeDelta FreshnessPeriodForState(PrefetchItemState state) {
+ switch (state) {
+ // Bucket 1.
+ case PrefetchItemState::NEW_REQUEST:
+ return base::TimeDelta::FromDays(1);
+ // Bucket 2.
+ case PrefetchItemState::AWAITING_GCM:
+ case PrefetchItemState::RECEIVED_GCM:
+ case PrefetchItemState::RECEIVED_BUNDLE:
+ return base::TimeDelta::FromDays(1);
+ // Bucket 3.
+ case PrefetchItemState::DOWNLOADING:
+ return base::TimeDelta::FromDays(2);
+ default:
+ NOTREACHED();
+ }
+ return base::TimeDelta::FromDays(1);
+}
+
+PrefetchItemErrorCode ErrorCodeForState(PrefetchItemState state) {
+ switch (state) {
+ case PrefetchItemState::NEW_REQUEST:
+ return PrefetchItemErrorCode::STALE_AT_NEW_REQUEST;
+ case PrefetchItemState::AWAITING_GCM:
+ return PrefetchItemErrorCode::STALE_AT_AWAITING_GCM;
+ case PrefetchItemState::RECEIVED_GCM:
+ return PrefetchItemErrorCode::STALE_AT_RECEIVED_GCM;
+ case PrefetchItemState::RECEIVED_BUNDLE:
+ return PrefetchItemErrorCode::STALE_AT_RECEIVED_BUNDLE;
+ case PrefetchItemState::DOWNLOADING:
+ return PrefetchItemErrorCode::STALE_AT_DOWNLOADING;
+ default:
+ NOTREACHED();
+ }
+ return PrefetchItemErrorCode::STALE_AT_UNKNOWN;
+}
+
+bool FinalizeStaleItems(PrefetchItemState state,
+ base::Time now,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, error_code = ?"
+ " WHERE state = ? AND freshness_time < ?";
+ const int64_t earliest_fresh_db_time =
+ ToDatabaseTime(now - FreshnessPeriodForState(state));
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(1, static_cast<int>(ErrorCodeForState(state)));
+ statement.BindInt(2, static_cast<int>(state));
+ statement.BindInt64(3, earliest_fresh_db_time);
+
+ return statement.Run();
+}
+
+bool MoreWorkInQueue(sql::Connection* db) {
+ static const char kSql[] =
+ "SELECT COUNT(*) FROM prefetch_items"
+ " WHERE state NOT IN (?, ?)";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::ZOMBIE));
+ statement.BindInt(1, static_cast<int>(PrefetchItemState::AWAITING_GCM));
+
+ // In event of failure, assume more work exists.
+ if (!statement.Step())
+ return true;
+
+ return statement.ColumnInt(0) > 0;
+}
+
+// If the user shifted the clock backwards too far, our items will stay around
+// for a very long time. Don't allow that so we don't waste resources with
+// potentially outdated content.
+bool FinalizeFutureItems(PrefetchItemState state,
+ base::Time now,
+ sql::Connection* db) {
+ static const char kSql[] =
+ "UPDATE prefetch_items SET state = ?, error_code = ?"
+ " WHERE state = ? AND freshness_time > ?";
+ const int64_t future_fresh_db_time_limit =
+ ToDatabaseTime(now + base::TimeDelta::FromDays(1));
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+ statement.BindInt(
+ 1, static_cast<int>(
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED));
+ statement.BindInt(2, static_cast<int>(state));
+ statement.BindInt64(3, future_fresh_db_time_limit);
+
+ return statement.Run();
+}
+
+Result FinalizeStaleEntriesSync(StaleEntryFinalizerTask::NowGetter now_getter,
+ sql::Connection* db) {
+ if (!db)
+ return Result::NO_MORE_WORK;
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return Result::NO_MORE_WORK;
+
+ const std::array<PrefetchItemState, 5> expirable_states = {{
+ // Bucket 1.
+ PrefetchItemState::NEW_REQUEST,
+ // Bucket 2.
+ PrefetchItemState::AWAITING_GCM, PrefetchItemState::RECEIVED_GCM,
+ PrefetchItemState::RECEIVED_BUNDLE,
+ // Bucket 3.
+ PrefetchItemState::DOWNLOADING,
+ }};
+ base::Time now = now_getter.Run();
+ for (PrefetchItemState state : expirable_states) {
+ if (!FinalizeStaleItems(state, now, db))
+ return Result::NO_MORE_WORK;
+
+ if (!FinalizeFutureItems(state, now, db))
+ return Result::NO_MORE_WORK;
+ }
+
+ Result result = Result::MORE_WORK_NEEDED;
+ if (!MoreWorkInQueue(db))
+ result = Result::NO_MORE_WORK;
+
+ // If all FinalizeStaleItems calls succeeded the transaction is committed.
+ return transaction.Commit() ? result : Result::NO_MORE_WORK;
+}
+
+} // namespace
+
+StaleEntryFinalizerTask::StaleEntryFinalizerTask(
+ PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store)
+ : prefetch_dispatcher_(prefetch_dispatcher),
+ prefetch_store_(prefetch_store),
+ now_getter_(base::BindRepeating(&base::Time::Now)),
+ weak_ptr_factory_(this) {
+ DCHECK(prefetch_dispatcher_);
+ DCHECK(prefetch_store_);
+}
+
+StaleEntryFinalizerTask::~StaleEntryFinalizerTask() {}
+
+void StaleEntryFinalizerTask::Run() {
+ prefetch_store_->Execute(
+ base::BindOnce(&FinalizeStaleEntriesSync, now_getter_),
+ base::BindOnce(&StaleEntryFinalizerTask::OnFinished,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void StaleEntryFinalizerTask::SetNowGetterForTesting(NowGetter now_getter) {
+ now_getter_ = now_getter;
+}
+
+void StaleEntryFinalizerTask::OnFinished(Result result) {
+ final_status_ = result;
+ if (final_status_ == Result::MORE_WORK_NEEDED)
+ prefetch_dispatcher_->EnsureTaskScheduled();
+ DVLOG(1) << "Finalization task "
+ << (result == Result::NO_MORE_WORK ? "not " : "")
+ << "scheduling background processing.";
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.h b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.h
new file mode 100644
index 00000000000..efeb17d6e39
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task.h
@@ -0,0 +1,62 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_STALE_ENTRY_FINALIZER_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STALE_ENTRY_FINALIZER_TASK_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class PrefetchDispatcher;
+class PrefetchStore;
+
+// Reconciliation task responsible for finalizing entries for which their
+// freshness date are past the limits specific to each pipeline bucket. Entries
+// considered stale are moved to the "finished" state and have their error code
+// column set to the PrefetchItemErrorCode value that identifies the bucket they
+// were at.
+class StaleEntryFinalizerTask : public Task {
+ public:
+ enum class Result { NO_MORE_WORK, MORE_WORK_NEEDED };
+ using NowGetter = base::RepeatingCallback<base::Time()>;
+
+ StaleEntryFinalizerTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store);
+ ~StaleEntryFinalizerTask() override;
+
+ void Run() override;
+
+ // Allows tests to control the source of current time values used internally
+ // for freshness checks.
+ void SetNowGetterForTesting(NowGetter now_getter);
+
+ // Will be set to true upon after an error-free run.
+ Result final_status() const { return final_status_; }
+
+ private:
+ void OnFinished(Result result);
+
+ // Not owned.
+ PrefetchDispatcher* prefetch_dispatcher_;
+
+ // Prefetch store to execute against. Not owned.
+ PrefetchStore* prefetch_store_;
+
+ // Defaults to base::Time::Now upon construction.
+ NowGetter now_getter_;
+
+ Result final_status_ = Result::NO_MORE_WORK;
+
+ base::WeakPtrFactory<StaleEntryFinalizerTask> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(StaleEntryFinalizerTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STALE_ENTRY_FINALIZER_TASK_H_
diff --git a/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
new file mode 100644
index 00000000000..762f76b312d
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
@@ -0,0 +1,365 @@
+// 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/offline_pages/core/prefetch/stale_entry_finalizer_task.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/prefetch/mock_prefetch_item_generator.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+using Result = StaleEntryFinalizerTask::Result;
+
+std::set<PrefetchItem> Filter(const std::set<PrefetchItem>& items,
+ PrefetchItemState state) {
+ std::set<PrefetchItem> result;
+ for (const PrefetchItem& item : items) {
+ if (item.state == state)
+ result.insert(item);
+ }
+ return result;
+}
+
+class StaleEntryFinalizerTaskTest : public TaskTestBase {
+ public:
+ StaleEntryFinalizerTaskTest() = default;
+ ~StaleEntryFinalizerTaskTest() override = default;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ PrefetchItem CreateAndInsertItem(PrefetchItemState state,
+ int time_delta_in_hours);
+
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+
+ protected:
+ TestPrefetchDispatcher dispatcher_;
+ std::unique_ptr<StaleEntryFinalizerTask> stale_finalizer_task_;
+ base::Time fake_now_;
+};
+
+void StaleEntryFinalizerTaskTest::SetUp() {
+ TaskTestBase::SetUp();
+ stale_finalizer_task_ =
+ base::MakeUnique<StaleEntryFinalizerTask>(dispatcher(), store());
+ fake_now_ = base::Time() + base::TimeDelta::FromDays(100);
+ stale_finalizer_task_->SetNowGetterForTesting(base::BindRepeating(
+ [](base::Time t) -> base::Time { return t; }, fake_now_));
+}
+
+void StaleEntryFinalizerTaskTest::TearDown() {
+ stale_finalizer_task_.reset();
+ TaskTestBase::TearDown();
+}
+
+PrefetchItem StaleEntryFinalizerTaskTest::CreateAndInsertItem(
+ PrefetchItemState state,
+ int time_delta_in_hours) {
+ PrefetchItem item(item_generator()->CreateItem(state));
+ item.freshness_time =
+ fake_now_ + base::TimeDelta::FromHours(time_delta_in_hours);
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item))
+ << "Failed inserting item with state " << static_cast<int>(state);
+ return item;
+}
+
+// Tests that the task works correctly with an empty database.
+TEST_F(StaleEntryFinalizerTaskTest, EmptyRun) {
+ std::set<PrefetchItem> no_items;
+ EXPECT_EQ(0U, store_util()->GetAllItems(&no_items));
+
+ // Execute the expiration task.
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::NO_MORE_WORK, stale_finalizer_task_->final_status());
+ EXPECT_EQ(0U, store_util()->GetAllItems(&no_items));
+}
+
+// Verifies that expired and non-expired items from all expirable states are
+// properly handled.
+TEST_F(StaleEntryFinalizerTaskTest, HandlesFreshnessTimesCorrectly) {
+ // Insert fresh and stale items for all expirable states from all buckets.
+ PrefetchItem b1_item1_fresh =
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, -23);
+ PrefetchItem b1_item2_stale =
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, -25);
+
+ PrefetchItem b2_item1_fresh =
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, -23);
+ PrefetchItem b2_item2_stale =
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, -25);
+ PrefetchItem b2_item3_fresh =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, -23);
+ PrefetchItem b2_item4_stale =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, -25);
+ PrefetchItem b2_item5_fresh =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, -23);
+ PrefetchItem b2_item6_stale =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, -25);
+
+ PrefetchItem b3_item1_fresh =
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, -47);
+ PrefetchItem b3_item2_stale =
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, -49);
+
+ // Check inserted initial items.
+ std::set<PrefetchItem> initial_items = {
+ b1_item1_fresh, b1_item2_stale, b2_item1_fresh, b2_item2_stale,
+ b2_item3_fresh, b2_item4_stale, b2_item5_fresh, b2_item6_stale,
+ b3_item1_fresh, b3_item2_stale};
+ std::set<PrefetchItem> all_inserted_items;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&all_inserted_items));
+ EXPECT_EQ(initial_items, all_inserted_items);
+
+ // Execute the expiration task.
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+ // Create the expected finished version of each stale item.
+ PrefetchItem b1_item2_finished(b1_item2_stale);
+ b1_item2_finished.state = PrefetchItemState::FINISHED;
+ b1_item2_finished.error_code = PrefetchItemErrorCode::STALE_AT_NEW_REQUEST;
+ PrefetchItem b2_item2_finished(b2_item2_stale);
+ b2_item2_finished.state = PrefetchItemState::FINISHED;
+ b2_item2_finished.error_code = PrefetchItemErrorCode::STALE_AT_AWAITING_GCM;
+ PrefetchItem b2_item4_finished(b2_item4_stale);
+ b2_item4_finished.state = PrefetchItemState::FINISHED;
+ b2_item4_finished.error_code = PrefetchItemErrorCode::STALE_AT_RECEIVED_GCM;
+ PrefetchItem b2_item6_finished(b2_item6_stale);
+ b2_item6_finished.state = PrefetchItemState::FINISHED;
+ b2_item6_finished.error_code =
+ PrefetchItemErrorCode::STALE_AT_RECEIVED_BUNDLE;
+ PrefetchItem b3_item2_finished(b3_item2_stale);
+ b3_item2_finished.state = PrefetchItemState::FINISHED;
+ b3_item2_finished.error_code = PrefetchItemErrorCode::STALE_AT_DOWNLOADING;
+
+ // Creates the expected set of final items and compares with what's in store.
+ std::set<PrefetchItem> expected_final_items = {
+ b1_item1_fresh, b1_item2_finished, b2_item1_fresh, b2_item2_finished,
+ b2_item3_fresh, b2_item4_finished, b2_item5_fresh, b2_item6_finished,
+ b3_item1_fresh, b3_item2_finished};
+ EXPECT_EQ(10U, expected_final_items.size());
+ std::set<PrefetchItem> all_items_post_expiration;
+ EXPECT_EQ(10U, store_util()->GetAllItems(&all_items_post_expiration));
+ EXPECT_EQ(expected_final_items, all_items_post_expiration);
+}
+
+// Checks that items from all states are handled properly by the task when all
+// their freshness dates are really old.
+TEST_F(StaleEntryFinalizerTaskTest, HandlesStalesInAllStatesCorrectly) {
+ // Insert "stale" items for every state.
+ const int many_hours = -7 * 24;
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, many_hours);
+ CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, many_hours);
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, many_hours);
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, many_hours);
+ CreateAndInsertItem(PrefetchItemState::SENT_GET_OPERATION, many_hours);
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, many_hours);
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, many_hours);
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADED, many_hours);
+ CreateAndInsertItem(PrefetchItemState::IMPORTING, many_hours);
+ CreateAndInsertItem(PrefetchItemState::FINISHED, many_hours);
+ CreateAndInsertItem(PrefetchItemState::ZOMBIE, many_hours);
+ EXPECT_EQ(11, store_util()->CountPrefetchItems());
+
+ // Execute the expiration task.
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+ // Checks item counts for states expected to still exist.
+ std::set<PrefetchItem> post_items;
+ EXPECT_EQ(11U, store_util()->GetAllItems(&post_items));
+ EXPECT_EQ(
+ 1U,
+ Filter(post_items, PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE).size());
+ EXPECT_EQ(1U,
+ Filter(post_items, PrefetchItemState::SENT_GET_OPERATION).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::DOWNLOADED).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::IMPORTING).size());
+ EXPECT_EQ(6U, Filter(post_items, PrefetchItemState::FINISHED).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::ZOMBIE).size());
+}
+
+TEST_F(StaleEntryFinalizerTaskTest, NoWorkInQueue) {
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 0);
+ CreateAndInsertItem(PrefetchItemState::ZOMBIE, 0);
+
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::NO_MORE_WORK, stale_finalizer_task_->final_status());
+ EXPECT_EQ(0, dispatcher()->task_schedule_count);
+}
+
+TEST_F(StaleEntryFinalizerTaskTest, WorkInQueue) {
+ std::vector<PrefetchItemState> work_states = {
+ PrefetchItemState::NEW_REQUEST,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE,
+ PrefetchItemState::RECEIVED_GCM,
+ PrefetchItemState::SENT_GET_OPERATION,
+ PrefetchItemState::RECEIVED_BUNDLE,
+ PrefetchItemState::DOWNLOADING,
+ PrefetchItemState::DOWNLOADED,
+ PrefetchItemState::IMPORTING,
+ PrefetchItemState::FINISHED};
+
+ for (auto& state : work_states) {
+ store_util()->DeleteStore();
+ store_util()->BuildStoreInMemory();
+ dispatcher()->task_schedule_count = 0;
+
+ PrefetchItem item = item_generator()->CreateItem(state);
+ ASSERT_TRUE(store_util()->InsertPrefetchItem(item))
+ << "Failed inserting item with state " << static_cast<int>(state);
+
+ StaleEntryFinalizerTask task(dispatcher(), store());
+ ExpectTaskCompletes(&task);
+ task.Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::MORE_WORK_NEEDED, task.final_status());
+
+ EXPECT_EQ(1, dispatcher()->task_schedule_count);
+ }
+}
+
+// Verifies that expired and non-expired items from all expirable states are
+// properly handled.
+TEST_F(StaleEntryFinalizerTaskTest, HandlesClockSetBackwardsCorrectly) {
+ // Insert fresh and stale items for all expirable states from all buckets.
+ PrefetchItem b1_item1_recent =
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 23);
+ PrefetchItem b1_item2_future =
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 25);
+
+ PrefetchItem b2_item1_recent =
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 23);
+ PrefetchItem b2_item2_future =
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 25);
+ PrefetchItem b2_item3_recent =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 23);
+ PrefetchItem b2_item4_future =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 25);
+ PrefetchItem b2_item5_recent =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 23);
+ PrefetchItem b2_item6_future =
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 25);
+
+ PrefetchItem b3_item1_recent =
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 23);
+ PrefetchItem b3_item2_future =
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 25);
+
+ PrefetchItem b4_item1_future =
+ CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, 25);
+
+ // Check inserted initial items.
+ std::set<PrefetchItem> initial_items = {
+ b1_item1_recent, b1_item2_future, b2_item1_recent, b2_item2_future,
+ b2_item3_recent, b2_item4_future, b2_item5_recent, b2_item6_future,
+ b3_item1_recent, b3_item2_future, b4_item1_future};
+ std::set<PrefetchItem> all_inserted_items;
+ EXPECT_EQ(11U, store_util()->GetAllItems(&all_inserted_items));
+ EXPECT_EQ(initial_items, all_inserted_items);
+
+ // Execute the expiration task.
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+ // Create the expected finished version of each stale item.
+ PrefetchItem b1_item2_finished(b1_item2_future);
+ b1_item2_finished.state = PrefetchItemState::FINISHED;
+ b1_item2_finished.error_code =
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+ PrefetchItem b2_item2_finished(b2_item2_future);
+ b2_item2_finished.state = PrefetchItemState::FINISHED;
+ b2_item2_finished.error_code =
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+ PrefetchItem b2_item4_finished(b2_item4_future);
+ b2_item4_finished.state = PrefetchItemState::FINISHED;
+ b2_item4_finished.error_code =
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+ PrefetchItem b2_item6_finished(b2_item6_future);
+ b2_item6_finished.state = PrefetchItemState::FINISHED;
+ b2_item6_finished.error_code =
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+ PrefetchItem b3_item2_finished(b3_item2_future);
+ b3_item2_finished.state = PrefetchItemState::FINISHED;
+ b3_item2_finished.error_code =
+ PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+ PrefetchItem b4_item_finished(b4_item1_future);
+ b4_item1_future.state = PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE;
+ b4_item1_future.error_code = PrefetchItemErrorCode::SUCCESS;
+
+ // Creates the expected set of final items and compares with what's in
+ // store.
+ std::set<PrefetchItem> expected_final_items = {
+ b1_item1_recent, b1_item2_finished, b2_item1_recent, b2_item2_finished,
+ b2_item3_recent, b2_item4_finished, b2_item5_recent, b2_item6_finished,
+ b3_item1_recent, b3_item2_finished, b4_item1_future};
+ EXPECT_EQ(11U, expected_final_items.size());
+ std::set<PrefetchItem> all_items_post_expiration;
+ EXPECT_EQ(11U, store_util()->GetAllItems(&all_items_post_expiration));
+ EXPECT_EQ(expected_final_items, all_items_post_expiration);
+}
+
+// Checks that items from all states are handled properly by the task when all
+// their freshness dates are really old.
+TEST_F(StaleEntryFinalizerTaskTest,
+ HandleClockChangeBackwardsInAllStatesCorrectly) {
+ // Insert "future" items for every state.
+ const int many_hours = 7 * 24;
+ CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, many_hours);
+ CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, many_hours);
+ CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, many_hours);
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, many_hours);
+ CreateAndInsertItem(PrefetchItemState::SENT_GET_OPERATION, many_hours);
+ CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, many_hours);
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADING, many_hours);
+ CreateAndInsertItem(PrefetchItemState::DOWNLOADED, many_hours);
+ CreateAndInsertItem(PrefetchItemState::IMPORTING, many_hours);
+ CreateAndInsertItem(PrefetchItemState::FINISHED, many_hours);
+ CreateAndInsertItem(PrefetchItemState::ZOMBIE, many_hours);
+ EXPECT_EQ(11, store_util()->CountPrefetchItems());
+
+ // Execute the expiration task.
+ ExpectTaskCompletes(stale_finalizer_task_.get());
+ stale_finalizer_task_->Run();
+ RunUntilIdle();
+ EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+ // Checks item counts for states expected to still exist.
+ std::set<PrefetchItem> post_items;
+ EXPECT_EQ(11U, store_util()->GetAllItems(&post_items));
+ EXPECT_EQ(
+ 1U,
+ Filter(post_items, PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE).size());
+ EXPECT_EQ(1U,
+ Filter(post_items, PrefetchItemState::SENT_GET_OPERATION).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::DOWNLOADED).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::IMPORTING).size());
+ EXPECT_EQ(6U, Filter(post_items, PrefetchItemState::FINISHED).size());
+ EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::ZOMBIE).size());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/README.md b/chromium/components/offline_pages/core/prefetch/store/README.md
new file mode 100644
index 00000000000..73453ddf3e2
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/store/README.md
@@ -0,0 +1,149 @@
+# Using offline prefetch store
+
+This document provides background for understanding and prescribes how to
+interact with the offline prefetch store.
+
+[TOC]
+
+## Simple interface
+
+There are 2 goals of the `PrefetchStoreSQL` class:
+
+* Provide a way to run a group of related commands in a transaction, to achieve
+ atomicity.
+* Remove the burden of switching threads between foreground and background from
+ the caller. (All SQL store interactions are actually running on the background
+ thread, but that fact is transparent to the caller.)
+
+Therefore the store offers the following interface:
+
+```cpp
+class PrefetchStore {
+ public:
+ // Definition of the callback that is going to run the core of the command in
+ // the |Execute| method.
+ template <typename T>
+ using RunCallback = base::OnceCallback<T(sql::Connection*)>;
+
+ // Definition of the callback used to pass the result back to the caller of
+ // |Execute| method.
+ template <typename T>
+ using ResultCallback = base::OnceCallback<void(T)>;
+
+ // Creates an instance of |PrefetchStore| with an in-memory SQLite database.
+ explicit PrefetchStore(
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+
+ // Creates an instance of |PrefetchStore| with a SQLite database stored in
+ // |database_dir|.
+ PrefetchStore(scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ const base::FilePath& database_dir);
+
+ ~PrefetchStore();
+
+ // Executes a |run_callback| on SQL store on the blocking thread, and posts
+ // its result back to calling thread through |result_callback|.
+ // Calling |Execute| when store is NOT_INITIALIZED will cause the store
+ // initialization to start.
+ // Store initialization status needs to be SUCCESS for test task to run, or
+ // FAILURE, in which case the |db| pointer passed to |run_callback| will be
+ // null and such case should be gracefully handled.
+ template <typename T>
+ void Execute(RunCallback<T> run_callback, ResultCallback<T> result_callback);
+
+ // Gets the initialization status of the store.
+ InitializationStatus initialization_status() const;
+};
+```
+
+It allows for enough flexibility to execute `run_callback` on a background
+(blocking) task runner with a `sql::Connection` pointer provided, and then
+return result using `result_callback`.
+
+## How to implement your command
+
+Running code against prefetch store requires defining 2 functions. First one
+responsible for working with the store on the background thread, while second to
+deliver results to the foreground.
+
+### Defining a RunCallback
+
+Signature of the callback to run on a background thread is defined by
+`PrefetchStoreSQL::RunCallback`. Basic implementation should contain the
+following (in this example `bool` is used as a sample return type.
+
+```cpp
+bool ExampleRunCallback(sql::Connection* db) {
+ // Run function should start from ensuring that provided `db` pointer is not
+ // nullptr. If it is, there has been an error opening or initializing the DB.
+ // Such case is possible and it would not be appropriate to CHECK/DCHECK in
+ // that case. Code written against PrefetchStore is supposed to handle error
+ // cases like that gracefully.
+ if (!db)
+ return false;
+
+ // Next it's best to start a transaction, which can be aborted without making
+ // changes to the data. This is one of the reasons to go with provided store
+ // interface.
+ sql::Transaction transaction(db);
+
+ // If transaction does not begin, we can leave. This is another error
+ // condition that should not be CHECK/DCHECKed, as failure to open transaction
+ // happens and should be handled gracefully by the caller.
+ if (!transaction.Begin())
+ return false;
+
+ // Code doing the work goes here.
+
+ // Because we are running in transaction code, whenever we run into an error,
+ // we can simply return and *transaction will be aborted*.
+ if (/* stuff went wrong */)
+ return false;
+
+ // If everything went well up to this point, we attempt to commit a
+ // transaction. If the attempt fails, we return false again and transaction
+ // will be aborted for us.
+ if (!transaction.Commit())
+ return false;
+
+ // Everything went right, transaction is committed at this point. We should
+ // return appropriate result without attempting any more work with the DB.
+ // It should be OK to report UMA if necessary.
+ return true;
+}
+```
+
+### Defining a ResultCallback
+
+Return of the RunCallback will be provided to ResultCallback using a move
+semantics. This is how result is made available on the foreground thread.
+ResultCallback takes over ownership of the passed in result.
+
+```cpp
+void ExampleResultCallback(bool success) {
+ if (!success) {
+ // Log error, UMA the problem or issue a retry.
+ LOG(ERROR) << "DB operation failed. All hope is lost.";
+ return;
+ }
+
+ // Do regular follow up work.
+}
+```
+
+In the simple example above, we are using `bool` as a return type, but it would
+be much better to use an enum, or a structure containing an enum, that gives a
+better detail of what went wrong.
+See `//components/offline_pages/core/prefetch/add_unique_urls_task.cc` for a
+good example of working consumer of the API.
+
+## Column ordering in table creation
+
+Column ordering is important to simplify data retrieval in SQLite 3 tables. When
+creating a table fixed-width columns should be declared first and variable-width
+ones later.
+
+Furthermore, when adding or removing columns, any existing column ordering might
+not be kept. This means that any query must not presume column ordering and must
+always explicitly refer to them by name. Using <code>SELECT * FROM ...</code>
+for obtaining data in all columns is therefore *unsafe and forbidden*.
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.cc
new file mode 100644
index 00000000000..8bb8a5e382b
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.cc
@@ -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.
+
+#include "components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
+
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+
+namespace offline_pages {
+
+// static
+const int64_t PrefetchDownloaderQuota::kMaxDailyQuotaBytes =
+ 20LL * 1024 * 1024; // 20 MB
+
+namespace {
+constexpr base::TimeDelta kQuotaPeriod = base::TimeDelta::FromDays(1);
+
+// Normalize quota to [0, kMaxDailyQuotaBytes].
+int64_t NormalizeQuota(int64_t quota) {
+ if (quota < 0)
+ return 0;
+ if (quota > PrefetchDownloaderQuota::kMaxDailyQuotaBytes)
+ return PrefetchDownloaderQuota::kMaxDailyQuotaBytes;
+ return quota;
+}
+
+} // namespace
+
+PrefetchDownloaderQuota::PrefetchDownloaderQuota(sql::Connection* db,
+ base::Clock* clock)
+ : db_(db), clock_(clock) {
+ DCHECK(db_);
+ DCHECK(clock_);
+}
+
+PrefetchDownloaderQuota::~PrefetchDownloaderQuota() = default;
+
+int64_t PrefetchDownloaderQuota::GetAvailableQuotaBytes() {
+ static const char kSql[] =
+ "SELECT update_time, available_quota FROM prefetch_downloader_quota"
+ " WHERE quota_id = 1";
+ if (db_ == nullptr || clock_ == nullptr)
+ return -1LL;
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+
+ if (!statement.Step()) {
+ if (!statement.Succeeded())
+ return -1LL;
+
+ return kMaxDailyQuotaBytes;
+ }
+
+ base::Time update_time = FromDatabaseTime(statement.ColumnInt64(0));
+ int64_t available_quota = statement.ColumnInt64(1);
+
+ int64_t remaining_quota =
+ available_quota +
+ (kMaxDailyQuotaBytes * (clock_->Now() - update_time)) / kQuotaPeriod;
+
+ if (remaining_quota < 0)
+ SetAvailableQuotaBytes(0);
+
+ return NormalizeQuota(remaining_quota);
+}
+
+bool PrefetchDownloaderQuota::SetAvailableQuotaBytes(int64_t quota) {
+ static const char kSql[] =
+ "INSERT OR REPLACE INTO prefetch_downloader_quota"
+ " (quota_id, update_time, available_quota)"
+ " VALUES (1, ?, ?)";
+ if (db_ == nullptr || clock_ == nullptr)
+ return false;
+
+ quota = NormalizeQuota(quota);
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, ToDatabaseTime(clock_->Now()));
+ statement.BindInt64(1, quota);
+ return statement.Run();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h
new file mode 100644
index 00000000000..4b12e2ab87a
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h
@@ -0,0 +1,49 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_STORE_PREFETCH_DOWNLOADER_QUOTA_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STORE_PREFETCH_DOWNLOADER_QUOTA_H_
+
+#include <cstdint>
+
+#include "base/macros.h"
+
+namespace base {
+class Clock;
+} // namespace base
+
+namespace sql {
+class Connection;
+} // namespace sql
+
+namespace offline_pages {
+
+// Handles retrieval, storage and calculation of quota for |PrefetchDownloader|.
+class PrefetchDownloaderQuota {
+ public:
+ static const int64_t kMaxDailyQuotaBytes;
+
+ PrefetchDownloaderQuota(sql::Connection* db, base::Clock* clock);
+ ~PrefetchDownloaderQuota();
+
+ // Gets the currently available quota, as read from the DB and adjusted for
+ // time elapsed since quota was last updated.
+ int64_t GetAvailableQuotaBytes();
+
+ // Sets available quota to the provided |quota| value, capped by
+ // [0, max daily quota].
+ bool SetAvailableQuotaBytes(int64_t quota);
+
+ private:
+ // DB connection. Not owned.
+ sql::Connection* db_;
+
+ // Clock used for time related calculation and quota updates in DB. Not owned.
+ base::Clock* clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefetchDownloaderQuota);
+};
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STORE_PREFETCH_DOWNLOADER_QUOTA_H_
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota_unittest.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota_unittest.cc
new file mode 100644
index 00000000000..51e7ad75c86
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_downloader_quota_unittest.cc
@@ -0,0 +1,114 @@
+// 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/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
+
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+class PrefetchDownloaderQuotaTest : public testing::Test {
+ public:
+ PrefetchDownloaderQuotaTest();
+ ~PrefetchDownloaderQuotaTest() override = default;
+
+ void SetUp() override { store_test_util_.BuildStoreInMemory(); }
+
+ void TearDown() override { store_test_util_.DeleteStore(); }
+
+ PrefetchStore* store() { return store_test_util_.store(); }
+
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+
+ private:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+ PrefetchStoreTestUtil store_test_util_;
+};
+
+PrefetchDownloaderQuotaTest::PrefetchDownloaderQuotaTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
+
+TEST_F(PrefetchDownloaderQuotaTest, GetQuotaWithNothingStored) {
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+}
+
+TEST_F(PrefetchDownloaderQuotaTest, SetQuotaToZeroAndRead) {
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(0));
+ EXPECT_EQ(0, store_util()->GetPrefetchQuota());
+}
+
+TEST_F(PrefetchDownloaderQuotaTest, SetQuotaToLessThanZero) {
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(-10000LL));
+ EXPECT_EQ(0, store_util()->GetPrefetchQuota());
+}
+
+TEST_F(PrefetchDownloaderQuotaTest, SetQuotaToMoreThanMaximum) {
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(
+ 2 * PrefetchDownloaderQuota::kMaxDailyQuotaBytes));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+}
+
+// This test verifies that advancing time by 12 hours (half of quota period),
+// recovers half of the quota, withing limits.
+TEST_F(PrefetchDownloaderQuotaTest, CheckQuotaForHalfDay) {
+ // Start with no quota, and wait for half a day, we should have half of quota.
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(0));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(12));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 2,
+ store_util()->GetPrefetchQuota());
+
+ // Now start with quota set to 1/4. Expecting 3/4 of quota.
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(
+ PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 4));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(12));
+ EXPECT_EQ(3 * PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 4,
+ store_util()->GetPrefetchQuota());
+
+ // Now start with quota set to 1/2. Expects full quota.
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(
+ PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 2));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(12));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+
+ // Now start with quota set to 3/4. Expects a limit on quota of daily quota
+ // maximum.
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(
+ 3 * PrefetchDownloaderQuota::kMaxDailyQuotaBytes / 4));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(12));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+}
+
+// This test deals with small and extreme time change scenarios.
+TEST_F(PrefetchDownloaderQuotaTest, CheckQuotaAfterTimeChange) {
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(0));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(-1));
+ EXPECT_EQ(0, store_util()->GetPrefetchQuota());
+
+ EXPECT_TRUE(store_util()->SetPrefetchQuota(
+ PrefetchDownloaderQuota::kMaxDailyQuotaBytes));
+ store_util()->clock()->Advance(base::TimeDelta::FromHours(1));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+
+ // When going back in time, we get a situation where quota would be negative,
+ // we detect it and write back a value of 0 with that date.
+ store_util()->clock()->Advance(base::TimeDelta::FromDays(-365));
+ EXPECT_EQ(0, store_util()->GetPrefetchQuota());
+ // Above implies that after another day our quota is back to full daily max.
+ store_util()->clock()->Advance(base::TimeDelta::FromDays(1));
+ EXPECT_EQ(PrefetchDownloaderQuota::kMaxDailyQuotaBytes,
+ store_util()->GetPrefetchQuota());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
index f6cecd57113..8624bff7b81 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
@@ -14,7 +14,6 @@
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/offline_store_types.h"
-#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
#include "sql/connection.h"
#include "sql/meta_table.h"
@@ -26,6 +25,7 @@ namespace {
// Name of the table with prefetch items.
const char kPrefetchItemsTableName[] = "prefetch_items";
+const char kPrefetchQuotaTableName[] = "prefetch_downloader_quota";
const char kPrefetchStoreFileName[] = "PrefetchStore.db";
const int kCurrentVersion = 1;
@@ -35,24 +35,51 @@ using InitializeCallback =
base::Callback<void(InitializationStatus,
std::unique_ptr<sql::Connection>)>;
+// IMPORTANT #1: when making changes to these columns please also reflect them
+// into:
+// - PrefetchItem: update existing fields and all method implementations
+// (operator=, operator<<, ToString, etc).
+// - PrefetchItemTest, PrefetchStoreTestUtil: update test related code to cover
+// the changed set of columns and PrefetchItem members.
+// - MockPrefetchItemGenerator: so that its generated items consider all fields.
+// IMPORTANT #2: the ordering of column types is important in SQLite 3 tables to
+// simplify data retrieval. Columns with fixed length types must come first and
+// variable length types must come later.
+static const char kTableCreationSql[] =
+ "CREATE TABLE prefetch_items"
+ // Fixed length columns come first.
+ "(offline_id INTEGER PRIMARY KEY NOT NULL,"
+ " state INTEGER NOT NULL DEFAULT 0,"
+ " generate_bundle_attempts INTEGER NOT NULL DEFAULT 0,"
+ " get_operation_attempts INTEGER NOT NULL DEFAULT 0,"
+ " download_initiation_attempts INTEGER NOT NULL DEFAULT 0,"
+ " archive_body_length INTEGER_NOT_NULL DEFAULT -1,"
+ " creation_time INTEGER NOT NULL,"
+ " freshness_time INTEGER NOT NULL,"
+ " error_code INTEGER NOT NULL DEFAULT 0,"
+ " file_size INTEGER NOT NULL DEFAULT -1,"
+ // Variable length columns come later.
+ " guid VARCHAR NOT NULL DEFAULT '',"
+ " client_namespace VARCHAR NOT NULL DEFAULT '',"
+ " client_id VARCHAR NOT NULL DEFAULT '',"
+ " requested_url VARCHAR NOT NULL DEFAULT '',"
+ " final_archived_url VARCHAR NOT NULL DEFAULT '',"
+ " operation_name VARCHAR NOT NULL DEFAULT '',"
+ " archive_body_name VARCHAR NOT NULL DEFAULT '',"
+ " title VARCHAR NOT NULL DEFAULT '',"
+ " file_path VARCHAR NOT NULL DEFAULT ''"
+ ")";
+
bool CreatePrefetchItemsTable(sql::Connection* db) {
+ return db->Execute(kTableCreationSql);
+}
+
+bool CreatePrefetchQuotaTable(sql::Connection* db) {
static const char kSql[] =
- "CREATE TABLE prefetch_items"
- "(offline_id INTEGER PRIMARY KEY NOT NULL,"
- " state INTEGER NOT NULL DEFAULT 0,"
- " request_archive_attempt_count INTEGER NOT NULL DEFAULT 0,"
- " archive_body_length INTEGER_NOT_NULL DEFAULT -1,"
- " creation_time INTEGER NOT NULL,"
- " freshness_time INTEGER NOT NULL,"
- " error_code INTEGER NOT NULL DEFAULT 0,"
- " guid VARCHAR NOT NULL DEFAULT '',"
- " client_namespace VARCHAR NOT NULL DEFAULT '',"
- " client_id VARCHAR NOT NULL DEFAULT '',"
- " requested_url VARCHAR NOT NULL DEFAULT '',"
- " final_archived_url VARCHAR NOT NULL DEFAULT '',"
- " operation_name VARCHAR NOT NULL DEFAULT '',"
- " archive_body_name VARCHAR NOT NULL DEFAULT ''"
- ")";
+ "CREATE TABLE prefetch_downloader_quota"
+ "(quota_id INTEGER PRIMARY KEY NOT NULL DEFAULT 1,"
+ " update_time INTEGER NOT NULL,"
+ " available_quota INTEGER NOT NULL DEFAULT 0)";
return db->Execute(kSql);
}
@@ -68,6 +95,11 @@ bool CreateSchema(sql::Connection* db) {
return false;
}
+ if (!db->DoesTableExist(kPrefetchQuotaTableName)) {
+ if (!CreatePrefetchQuotaTable(db))
+ return false;
+ }
+
sql::MetaTable meta_table;
meta_table.Init(db, kCurrentVersion, kCompatibleVersion);
@@ -170,4 +202,9 @@ void PrefetchStore::OnInitializeDone(base::OnceClosure pending_command,
initialization_status_ = InitializationStatus::NOT_INITIALIZED;
}
+// static
+const char* PrefetchStore::GetTableCreationSqlForTesting() {
+ return kTableCreationSql;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
index 15929a6b4e2..713573fa9a8 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
@@ -49,18 +49,21 @@ class PrefetchStore {
template <typename T>
using ResultCallback = base::OnceCallback<void(T)>;
+ // Creates an instance of |PrefetchStore| with an in-memory SQLite database.
explicit PrefetchStore(
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+
+ // Creates an instance of |PrefetchStore| with a SQLite database stored in
+ // |database_dir|.
PrefetchStore(scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
const base::FilePath& database_dir);
+
~PrefetchStore();
// Executes a |run_callback| on SQL store on the blocking thread, and posts
- // its result back to calling thread through |result_callback|. The work will
- // be postponed if the store is in NOT_INITIALIZED or INITIALIZING, in which
- // case the work will have to wait until initialization is completed. Calling
- // |Execute| when store is NOT_INITIALIZED will cause the store initialization
- // to start.
+ // its result back to calling thread through |result_callback|.
+ // Calling |Execute| when store is NOT_INITIALIZED will cause the store
+ // initialization to start.
// Store initialization status needs to be SUCCESS for test task to run, or
// FAILURE, in which case the |db| pointer passed to |run_callback| will be
// null and such case should be gracefully handled.
@@ -89,6 +92,8 @@ class PrefetchStore {
return initialization_status_;
}
+ static const char* GetTableCreationSqlForTesting();
+
private:
// Used internally to initialize connection.
void Initialize(base::OnceClosure pending_command);
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 b3fb7a43c6a..8b3f1d2aa53 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
@@ -1,19 +1,81 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
+// // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "url/gurl.h"
namespace offline_pages {
+const int kPrefetchStoreCommandFailed = -1;
+
namespace {
+// Comma separated list of all columns in the table, by convention following
+// their natural order.
+const char* kSqlAllColumnNames =
+ "offline_id, "
+ "state, "
+ "generate_bundle_attempts, "
+ "get_operation_attempts, "
+ "download_initiation_attempts, "
+ "archive_body_length, "
+ "creation_time, "
+ "freshness_time, "
+ "error_code, "
+ "guid, "
+ "client_namespace, "
+ "client_id, "
+ "requested_url, "
+ "final_archived_url, "
+ "operation_name, "
+ "archive_body_name, "
+ "title, "
+ "file_path, "
+ "file_size";
+
+bool InsertPrefetchItemSync(const PrefetchItem& item, sql::Connection* db) {
+ static const std::string kSql = base::StringPrintf(
+ "INSERT INTO prefetch_items (%s)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ kSqlAllColumnNames);
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql.c_str()));
+ statement.BindInt64(0, item.offline_id);
+ statement.BindInt(1, static_cast<int>(item.state));
+ statement.BindInt(2, item.generate_bundle_attempts);
+ statement.BindInt(3, item.get_operation_attempts);
+ statement.BindInt(4, item.download_initiation_attempts);
+ statement.BindInt64(5, item.archive_body_length);
+ statement.BindInt64(6, ToDatabaseTime(item.creation_time));
+ statement.BindInt64(7, ToDatabaseTime(item.freshness_time));
+ statement.BindInt(8, static_cast<int>(item.error_code));
+ statement.BindString(9, item.guid);
+ statement.BindString(10, item.client_id.name_space);
+ statement.BindString(11, item.client_id.id);
+ statement.BindString(12, item.url.spec());
+ statement.BindString(13, item.final_archived_url.spec());
+ statement.BindString(14, item.operation_name);
+ statement.BindString(15, item.archive_body_name);
+ statement.BindString16(16, item.title);
+ statement.BindString(17, item.file_path.AsUTF8Unsafe());
+ statement.BindInt64(18, item.file_size);
+
+ return statement.Run();
+}
+
int CountPrefetchItemsSync(sql::Connection* db) {
// Not starting transaction as this is a single read.
static const char kSql[] = "SELECT COUNT(offline_id) FROM prefetch_items";
@@ -21,7 +83,66 @@ int CountPrefetchItemsSync(sql::Connection* db) {
if (statement.Step())
return statement.ColumnInt(0);
- return kStoreCommandFailed;
+ return kPrefetchStoreCommandFailed;
+}
+
+// Populates the PrefetchItem with the data from the current row of the passed
+// in statement following the natural column ordering.
+void PopulatePrefetchItem(const sql::Statement& statement, PrefetchItem* item) {
+ DCHECK_EQ(19, statement.ColumnCount());
+ DCHECK(item);
+
+ // Fields are assigned to the item in the order they are stored in the SQL
+ // store (integer fields first).
+ item->offline_id = statement.ColumnInt64(0);
+ item->state = static_cast<PrefetchItemState>(statement.ColumnInt(1));
+ item->generate_bundle_attempts = statement.ColumnInt(2);
+ item->get_operation_attempts = statement.ColumnInt(3);
+ item->download_initiation_attempts = statement.ColumnInt(4);
+ item->archive_body_length = statement.ColumnInt64(5);
+ item->creation_time = FromDatabaseTime(statement.ColumnInt64(6));
+ item->freshness_time = FromDatabaseTime(statement.ColumnInt64(7));
+ item->error_code = static_cast<PrefetchItemErrorCode>(statement.ColumnInt(8));
+ item->guid = statement.ColumnString(9);
+ item->client_id.name_space = statement.ColumnString(10);
+ item->client_id.id = statement.ColumnString(11);
+ item->url = GURL(statement.ColumnString(12));
+ item->final_archived_url = GURL(statement.ColumnString(13));
+ item->operation_name = statement.ColumnString(14);
+ item->archive_body_name = statement.ColumnString(15);
+ item->title = statement.ColumnString16(16);
+ item->file_path = base::FilePath::FromUTF8Unsafe(statement.ColumnString(17));
+ item->file_size = statement.ColumnInt64(18);
+}
+
+std::unique_ptr<PrefetchItem> GetPrefetchItemSync(int64_t offline_id,
+ sql::Connection* db) {
+ static const std::string kSql = base::StringPrintf(
+ "SELECT %s FROM prefetch_items WHERE offline_id = ?", kSqlAllColumnNames);
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql.c_str()));
+ statement.BindInt64(0, offline_id);
+
+ if (!statement.Step())
+ return nullptr;
+
+ auto item = base::MakeUnique<PrefetchItem>();
+ PopulatePrefetchItem(statement, item.get());
+ return item;
+}
+
+std::size_t GetAllItemsSync(std::set<PrefetchItem>* items,
+ sql::Connection* db) {
+ // Not starting transaction as this is a single read.
+ static const std::string kSql =
+ base::StringPrintf("SELECT %s FROM prefetch_items", kSqlAllColumnNames);
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql.c_str()));
+ while (statement.Step()) {
+ PrefetchItem loaded_item;
+ PopulatePrefetchItem(statement, &loaded_item);
+ items->insert(loaded_item);
+ }
+ return items->size();
}
int UpdateItemsStateSync(const std::string& name_space,
@@ -40,12 +161,26 @@ int UpdateItemsStateSync(const std::string& name_space,
if (statement.Run())
return db->GetLastChangeCount();
- return kStoreCommandFailed;
+ return kPrefetchStoreCommandFailed;
+}
+
+int64_t GetPrefetchQuotaSync(base::Clock* clock, sql::Connection* db) {
+ PrefetchDownloaderQuota downloader_quota(db, clock);
+ return downloader_quota.GetAvailableQuotaBytes();
+}
+
+bool SetPrefetchQuotaSync(int64_t available_quota,
+ base::Clock* clock,
+ sql::Connection* db) {
+ PrefetchDownloaderQuota downloader_quota(db, clock);
+ return downloader_quota.SetAvailableQuotaBytes(available_quota);
}
} // namespace
-PrefetchStoreTestUtil::PrefetchStoreTestUtil() {}
+PrefetchStoreTestUtil::PrefetchStoreTestUtil(
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner)
+ : task_runner_(task_runner) {}
PrefetchStoreTestUtil::~PrefetchStoreTestUtil() = default;
@@ -53,12 +188,11 @@ void PrefetchStoreTestUtil::BuildStore() {
if (!temp_directory_.CreateUniqueTempDir())
DVLOG(1) << "temp_directory_ not created";
- store_.reset(new PrefetchStore(base::ThreadTaskRunnerHandle::Get(),
- temp_directory_.GetPath()));
+ store_.reset(new PrefetchStore(task_runner_, temp_directory_.GetPath()));
}
void PrefetchStoreTestUtil::BuildStoreInMemory() {
- store_.reset(new PrefetchStore(base::ThreadTaskRunnerHandle::Get()));
+ store_.reset(new PrefetchStore(task_runner_));
}
std::unique_ptr<PrefetchStore> PrefetchStoreTestUtil::ReleaseStore() {
@@ -71,20 +205,96 @@ void PrefetchStoreTestUtil::DeleteStore() {
if (!temp_directory_.Delete())
DVLOG(1) << "temp_directory_ not created";
}
+ task_runner_->RunUntilIdle();
+}
+
+bool PrefetchStoreTestUtil::InsertPrefetchItem(const PrefetchItem& item) {
+ bool success = false;
+ store_->Execute(
+ base::BindOnce(&InsertPrefetchItemSync, item),
+ base::BindOnce([](bool* alias, bool s) { *alias = s; }, &success));
+ RunUntilIdle();
+ return success;
+}
+
+int PrefetchStoreTestUtil::CountPrefetchItems() {
+ int count = 0;
+ store_->Execute(
+ base::BindOnce(&CountPrefetchItemsSync),
+ base::BindOnce([](int* alias, int result) { *alias = result; }, &count));
+ RunUntilIdle();
+ return count;
+}
+
+std::unique_ptr<PrefetchItem> PrefetchStoreTestUtil::GetPrefetchItem(
+ int64_t offline_id) {
+ std::unique_ptr<PrefetchItem> item;
+ store_->Execute(base::BindOnce(&GetPrefetchItemSync, offline_id),
+ base::BindOnce(
+ [](std::unique_ptr<PrefetchItem>* alias,
+ std::unique_ptr<PrefetchItem> result) {
+ *alias = std::move(result);
+ },
+ &item));
+ RunUntilIdle();
+ return item;
}
-void PrefetchStoreTestUtil::CountPrefetchItems(
- PrefetchStore::ResultCallback<int> result_callback) {
- store_->Execute(base::BindOnce(&CountPrefetchItemsSync),
- std::move(result_callback));
+std::size_t PrefetchStoreTestUtil::GetAllItems(
+ std::set<PrefetchItem>* all_items) {
+ std::size_t items_count;
+ store_->Execute(base::BindOnce(&GetAllItemsSync, all_items),
+ base::BindOnce([](std::size_t* alias,
+ std::size_t result) { *alias = result; },
+ &items_count));
+ RunUntilIdle();
+ return items_count;
}
-void PrefetchStoreTestUtil::ZombifyPrefetchItem(
- const std::string& name_space,
- const GURL& url,
- PrefetchStore::ResultCallback<int> result_callback) {
- store_->Execute(base::BindOnce(&UpdateItemsStateSync, name_space, url.spec(),
- PrefetchItemState::ZOMBIE),
- std::move(result_callback));
+int PrefetchStoreTestUtil::ZombifyPrefetchItems(const std::string& name_space,
+ const GURL& url) {
+ int count = -1;
+ store_->Execute(
+ base::BindOnce(&UpdateItemsStateSync, name_space, url.spec(),
+ PrefetchItemState::ZOMBIE),
+ base::BindOnce([](int* alias, int result) { *alias = result; }, &count));
+ RunUntilIdle();
+ return count;
}
+
+void PrefetchStoreTestUtil::RunUntilIdle() {
+ task_runner_->RunUntilIdle();
+}
+
+int PrefetchStoreTestUtil::LastCommandChangeCount() {
+ int count = 0;
+ store_->Execute(
+ base::BindOnce([](sql::Connection* connection) {
+ return connection->GetLastChangeCount();
+ }),
+ base::BindOnce([](int* result, int count) { *result = count; }, &count));
+ RunUntilIdle();
+ return count;
+}
+
+int64_t PrefetchStoreTestUtil::GetPrefetchQuota() {
+ int64_t result;
+ store_->Execute(
+ base::BindOnce(&GetPrefetchQuotaSync, clock()),
+ base::BindOnce([](int64_t* result, int64_t quota) { *result = quota; },
+ &result));
+ RunUntilIdle();
+ return result;
+}
+
+bool PrefetchStoreTestUtil::SetPrefetchQuota(int64_t available_quota) {
+ bool result;
+ store_->Execute(
+ base::BindOnce(&SetPrefetchQuotaSync, available_quota, clock()),
+ base::BindOnce([](bool* result, bool success) { *result = success; },
+ &result));
+ RunUntilIdle();
+ return result;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
index c330308a4f2..1070e8781e6 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
@@ -6,45 +6,87 @@
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STORE_PREFETCH_STORE_TEST_UTIL_H_
#include <memory>
+#include <set>
+#include <string>
+#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/test_simple_task_runner.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
class GURL;
namespace base {
class ScopedTempDir;
+class SimpleTestClock;
} // namespace base
namespace offline_pages {
-const int kStoreCommandFailed = -1;
+struct PrefetchItem;
+extern const int kPrefetchStoreCommandFailed;
+
+// Encapsulates the PrefetchStore and provides synchronous operations on the
+// store, for test writing convenience.
class PrefetchStoreTestUtil {
public:
- PrefetchStoreTestUtil();
+ explicit PrefetchStoreTestUtil(
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner);
~PrefetchStoreTestUtil();
+ // Builds a new store in a temporary directory.
void BuildStore();
+ // Builds the store in memory (no disk storage).
void BuildStoreInMemory();
+ // Releases the ownership of currently controlled store.
+ std::unique_ptr<PrefetchStore> ReleaseStore();
+ // Deletes the currently held store that was previously built.
+ void DeleteStore();
- void CountPrefetchItems(PrefetchStore::ResultCallback<int> result_callback);
+ // Inserts the provided item in store. Returns true if successful.
+ bool InsertPrefetchItem(const PrefetchItem& item);
- void ZombifyPrefetchItem(const std::string& name_space,
- const GURL& url,
- PrefetchStore::ResultCallback<int> reuslt_callback);
+ // Returns the total count of prefetch items in the store.
+ int CountPrefetchItems();
- // Releases the ownership of currently controlled store.
- std::unique_ptr<PrefetchStore> ReleaseStore();
+ // Gets the item with the provided |offline_id|. Returns null if the item was
+ // not found.
+ std::unique_ptr<PrefetchItem> GetPrefetchItem(int64_t offline_id);
- void DeleteStore();
+ // Gets all existing items from the store, inserting them into |all_items|.
+ // Returns the number of items found.
+ std::size_t GetAllItems(std::set<PrefetchItem>* all_items);
+
+ // Sets to the ZOMBIE state entries identified by |name_space| and
+ // |url|, returning the number of entries found.
+ int ZombifyPrefetchItems(const std::string& name_space, const GURL& url);
+
+ // Returns number of rows affected by last SQL statement.
+ int LastCommandChangeCount();
+
+ // Gets the prefetch downloader quota value for testing.
+ // Quota calculation will use |clock_| as time source.
+ int64_t GetPrefetchQuota();
+
+ // Sets the prefetch quota value for testing.
+ // Will use |clock_| as time source when writing back quota.
+ bool SetPrefetchQuota(int64_t available_quota);
PrefetchStore* store() { return store_.get(); }
+ base::SimpleTestClock* clock() { return &clock_; }
+
private:
+ void RunUntilIdle();
+
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ScopedTempDir temp_directory_;
std::unique_ptr<PrefetchStore> store_;
+ base::SimpleTestClock clock_;
DISALLOW_COPY_AND_ASSIGN(PrefetchStoreTestUtil);
};
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc
index a463fce8cb0..ca4f38f4508 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_unittest.cc
@@ -6,6 +6,10 @@
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/offline_time_utils.h"
+#include "components/offline_pages/core/prefetch/mock_prefetch_item_generator.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "sql/connection.h"
#include "sql/statement.h"
@@ -13,23 +17,6 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace offline_pages {
-namespace {
-
-int CountPrefetchItems(sql::Connection* db) {
- // Not starting transaction as this is a single read.
- static const char kSql[] = "SELECT COUNT(offline_id) FROM prefetch_items";
- sql::Statement statement(db->GetUniqueStatement(kSql));
- if (statement.Step())
- return statement.ColumnInt(0);
-
- return -1;
-}
-
-void CountPrefetchItemsResult(int expected_count, int actual_count) {
- EXPECT_EQ(expected_count, actual_count);
-}
-
-} // namespace
class PrefetchStoreTest : public testing::Test {
public:
@@ -40,27 +27,60 @@ class PrefetchStoreTest : public testing::Test {
void TearDown() override {
store_test_util_.DeleteStore();
- PumpLoop();
}
PrefetchStore* store() { return store_test_util_.store(); }
- void PumpLoop() { task_runner_->RunUntilIdle(); }
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+
+ MockPrefetchItemGenerator* item_generator() { return &item_generator_; }
private:
- PrefetchStoreTestUtil store_test_util_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
+ PrefetchStoreTestUtil store_test_util_;
+ MockPrefetchItemGenerator item_generator_;
};
PrefetchStoreTest::PrefetchStoreTest()
: task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_) {}
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
TEST_F(PrefetchStoreTest, InitializeStore) {
- store()->Execute<int>(base::BindOnce(&CountPrefetchItems),
- base::BindOnce(&CountPrefetchItemsResult, 0));
- PumpLoop();
+ EXPECT_EQ(0, store_util()->CountPrefetchItems());
+}
+
+TEST_F(PrefetchStoreTest, WriteAndLoadOneItem) {
+ // Create an item populated with unique, non-default values.
+ PrefetchItem item1(
+ item_generator()->CreateItem(PrefetchItemState::DOWNLOADED));
+ item1.generate_bundle_attempts = 10;
+ item1.get_operation_attempts = 11;
+ item1.download_initiation_attempts = 12;
+ item1.creation_time = FromDatabaseTime(1000L);
+ item1.freshness_time = FromDatabaseTime(2000L);
+ item1.error_code = PrefetchItemErrorCode::TOO_MANY_NEW_URLS;
+ item1.file_size = item1.archive_body_length + 1;
+
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item1));
+ std::set<PrefetchItem> all_items;
+ EXPECT_EQ(1U, store_util()->GetAllItems(&all_items));
+ EXPECT_EQ(1U, all_items.count(item1));
+}
+
+TEST_F(PrefetchStoreTest, ZombifyTestUtilWorks) {
+ PrefetchItem item1(
+ item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST));
+ EXPECT_EQ(0, store_util()->ZombifyPrefetchItems(item1.client_id.name_space,
+ item1.url));
+ store_util()->InsertPrefetchItem(item1);
+ EXPECT_EQ(1, store_util()->ZombifyPrefetchItems(item1.client_id.name_space,
+ item1.url));
+ EXPECT_EQ(PrefetchItemState::ZOMBIE,
+ store_util()->GetPrefetchItem(item1.offline_id)->state);
+ EXPECT_EQ(1, store_util()->ZombifyPrefetchItems(item1.client_id.name_space,
+ item1.url));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.cc
index e5c28d90c74..a1248940f4c 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.cc
@@ -7,18 +7,19 @@
#include <limits>
#include "base/rand_util.h"
-#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "sql/connection.h"
#include "sql/statement.h"
namespace offline_pages {
-int64_t GenerateOfflineId() {
+// static
+int64_t PrefetchStoreUtils::GenerateOfflineId() {
return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1;
}
-bool DeletePrefetchItemByOfflineIdSync(sql::Connection* db,
- int64_t offline_id) {
+// static
+bool PrefetchStoreUtils::DeletePrefetchItemByOfflineIdSync(sql::Connection* db,
+ int64_t offline_id) {
DCHECK(db);
static const char kSql[] = "DELETE FROM prefetch_items WHERE offline_id=?";
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.h
index d47696ba408..7c8a77de229 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.h
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_utils.h
@@ -13,13 +13,17 @@ class Connection;
namespace offline_pages {
-// Creates an offline ID for the prefetch item.
-int64_t GenerateOfflineId();
-
-// Deletes a prefetch item by its offline ID. Returns whether it was the item
-// was successfully deleted.
-bool DeletePrefetchItemByOfflineIdSync(sql::Connection* db, int64_t offline_id);
-
+// Useful helper functions to implement PrefetchStore related operations.
+class PrefetchStoreUtils {
+ public:
+ // Creates an offline ID for the prefetch item.
+ static int64_t GenerateOfflineId();
+
+ // Deletes a prefetch item by its offline ID. Returns whether it was the item
+ // was successfully deleted.
+ static bool DeletePrefetchItemByOfflineIdSync(sql::Connection* db,
+ int64_t offline_id);
+};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_STORE_PREFETCH_STORE_UTILS_H_
diff --git a/chromium/components/offline_pages/core/prefetch/suggested_articles_observer.cc b/chromium/components/offline_pages/core/prefetch/suggested_articles_observer.cc
index 75a7f333f85..e325ebf07bc 100644
--- a/chromium/components/offline_pages/core/prefetch/suggested_articles_observer.cc
+++ b/chromium/components/offline_pages/core/prefetch/suggested_articles_observer.cc
@@ -64,8 +64,8 @@ bool SuggestedArticlesObserver::GetCurrentSuggestions(
: content_suggestions_service_->GetSuggestionsForCategory(
ArticlesCategory());
for (const ContentSuggestion& suggestion : suggestions) {
- prefetch_urls.push_back(
- {suggestion.id().id_within_category(), suggestion.url()});
+ prefetch_urls.push_back({suggestion.id().id_within_category(),
+ suggestion.url(), suggestion.title()});
}
*result = prefetch_urls;
@@ -105,6 +105,11 @@ void SuggestedArticlesObserver::OnCategoryStatusChanged(
void SuggestedArticlesObserver::OnSuggestionInvalidated(
const ContentSuggestion::ID& suggestion_id) {
+ // TODO(dewittj): Change this to check whether a given category is not
+ // a _remote_ category.
+ if (suggestion_id.category() != ArticlesCategory())
+ return;
+
prefetch_service_->GetPrefetchDispatcher()->RemovePrefetchURLsByClientId(
ClientId(kSuggestedArticlesNamespace,
suggestion_id.id_within_category()));
diff --git a/chromium/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc b/chromium/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
index a243c2ecffc..ea865492062 100644
--- a/chromium/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
@@ -5,6 +5,7 @@
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/client_namespace_constants.h"
@@ -24,10 +25,15 @@ namespace offline_pages {
namespace {
+const base::string16 kTestTitle = base::ASCIIToUTF16("Title 1");
+
ContentSuggestion ContentSuggestionFromTestURL(const GURL& test_url) {
auto category =
Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES);
- return ContentSuggestion(category, test_url.spec(), test_url);
+ ContentSuggestion suggestion =
+ ContentSuggestion(category, test_url.spec(), test_url);
+ suggestion.set_title(kTestTitle);
+ return suggestion;
}
} // namespace
@@ -89,6 +95,8 @@ TEST_F(OfflinePageSuggestedArticlesObserverTest,
EXPECT_EQ(1U, test_prefetch_dispatcher()->latest_prefetch_urls.size());
EXPECT_EQ(test_url_1,
test_prefetch_dispatcher()->latest_prefetch_urls[0].url);
+ EXPECT_EQ(kTestTitle,
+ test_prefetch_dispatcher()->latest_prefetch_urls[0].title);
EXPECT_EQ(kSuggestedArticlesNamespace,
test_prefetch_dispatcher()->latest_name_space);
}
diff --git a/chromium/components/offline_pages/core/prefetch/task_test_base.cc b/chromium/components/offline_pages/core/prefetch/task_test_base.cc
index 555aaecd5b7..a5da01e94dc 100644
--- a/chromium/components/offline_pages/core/prefetch/task_test_base.cc
+++ b/chromium/components/offline_pages/core/prefetch/task_test_base.cc
@@ -7,6 +7,9 @@
#include "base/memory/ptr_util.h"
#include "base/test/mock_callback.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,19 +18,83 @@ using testing::_;
namespace offline_pages {
+// static
+std::vector<PrefetchItemState> TaskTestBase::GetAllStatesExcept(
+ PrefetchItemState state_to_exclude) {
+ static const PrefetchItemState all_states[] = {
+ PrefetchItemState::NEW_REQUEST,
+ PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE,
+ PrefetchItemState::AWAITING_GCM,
+ PrefetchItemState::RECEIVED_GCM,
+ PrefetchItemState::SENT_GET_OPERATION,
+ PrefetchItemState::RECEIVED_BUNDLE,
+ PrefetchItemState::DOWNLOADING,
+ PrefetchItemState::DOWNLOADED,
+ PrefetchItemState::IMPORTING,
+ PrefetchItemState::FINISHED,
+ PrefetchItemState::ZOMBIE,
+ };
+ std::vector<PrefetchItemState> states;
+ for (const auto& state : all_states) {
+ if (state != state_to_exclude)
+ states.push_back(state);
+ }
+ return states;
+}
+
TaskTestBase::TaskTestBase()
- : task_runner(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner) {}
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_),
+ store_test_util_(task_runner_) {}
TaskTestBase::~TaskTestBase() = default;
+void TaskTestBase::SetUp() {
+ testing::Test::SetUp();
+ store_test_util_.BuildStoreInMemory();
+}
+
+void TaskTestBase::TearDown() {
+ store_test_util_.DeleteStore();
+ RunUntilIdle();
+ testing::Test::TearDown();
+}
+
+void TaskTestBase::RunUntilIdle() {
+ task_runner_->RunUntilIdle();
+}
+
void TaskTestBase::ExpectTaskCompletes(Task* task) {
completion_callbacks_.push_back(
base::MakeUnique<base::MockCallback<Task::TaskCompletionCallback>>());
EXPECT_CALL(*completion_callbacks_.back(), Run(_));
task->SetTaskCompletionCallbackForTesting(
- task_runner.get(), completion_callbacks_.back()->Get());
+ task_runner_.get(), completion_callbacks_.back()->Get());
+}
+
+int64_t TaskTestBase::InsertPrefetchItemInStateWithOperation(
+ std::string operation_name,
+ PrefetchItemState state) {
+ PrefetchItem item;
+ item.state = state;
+ item.offline_id = PrefetchStoreUtils::GenerateOfflineId();
+ std::string offline_id_string = std::to_string(item.offline_id);
+ item.url = GURL("http://www.example.com/?id=" + offline_id_string);
+ item.operation_name = operation_name;
+ EXPECT_TRUE(store_util()->InsertPrefetchItem(item));
+ return item.offline_id;
+}
+
+std::set<PrefetchItem> TaskTestBase::FilterByState(
+ const std::set<PrefetchItem>& items,
+ PrefetchItemState state) const {
+ std::set<PrefetchItem> result;
+ for (const PrefetchItem& item : items) {
+ if (item.state == state)
+ result.insert(item);
+ }
+ return result;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/task_test_base.h b/chromium/components/offline_pages/core/prefetch/task_test_base.h
index 56c9c5478df..5ca918253d9 100644
--- a/chromium/components/offline_pages/core/prefetch/task_test_base.h
+++ b/chromium/components/offline_pages/core/prefetch/task_test_base.h
@@ -6,26 +6,39 @@
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TASK_TEST_BASE_H_
#include <memory>
+#include <set>
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/test/mock_callback.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/prefetch/mock_prefetch_item_generator.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "components/offline_pages/core/prefetch/test_prefetch_network_request_factory.h"
#include "components/offline_pages/core/task.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
namespace offline_pages {
+struct PrefetchItem;
+class PrefetchStore;
class Task;
// Base class for testing prefetch requests with simulated responses.
class TaskTestBase : public testing::Test {
public:
+ static std::vector<PrefetchItemState> GetAllStatesExcept(
+ PrefetchItemState state_to_exclude);
+
TaskTestBase();
~TaskTestBase() override;
+ void SetUp() override;
+ void TearDown() override;
+
+ void RunUntilIdle();
void ExpectTaskCompletes(Task* task);
TestPrefetchNetworkRequestFactory* prefetch_request_factory() {
@@ -36,12 +49,25 @@ class TaskTestBase : public testing::Test {
return &url_fetcher_factory_;
}
- scoped_refptr<base::TestSimpleTaskRunner> task_runner;
+ PrefetchStore* store() { return store_test_util_.store(); }
+
+ PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+
+ MockPrefetchItemGenerator* item_generator() { return &item_generator_; }
+
+ int64_t InsertPrefetchItemInStateWithOperation(std::string operation_name,
+ PrefetchItemState state);
+
+ std::set<PrefetchItem> FilterByState(const std::set<PrefetchItem>& items,
+ PrefetchItemState state) const;
private:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
net::TestURLFetcherFactory url_fetcher_factory_;
TestPrefetchNetworkRequestFactory prefetch_request_factory_;
+ PrefetchStoreTestUtil store_test_util_;
+ MockPrefetchItemGenerator item_generator_;
std::vector<std::unique_ptr<base::MockCallback<Task::TaskCompletionCallback>>>
completion_callbacks_;
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
index c0a555ebe6a..e35a2aa2fef 100644
--- a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
@@ -39,10 +39,31 @@ void TestPrefetchDispatcher::StopBackgroundTask() {}
void TestPrefetchDispatcher::SetService(PrefetchService* service) {}
+void TestPrefetchDispatcher::SchedulePipelineProcessing() {
+ processing_schedule_count++;
+}
+
+void TestPrefetchDispatcher::EnsureTaskScheduled() {
+ task_schedule_count++;
+}
+
void TestPrefetchDispatcher::GCMOperationCompletedMessageReceived(
const std::string& operation_name) {
operation_list.push_back(operation_name);
}
+void TestPrefetchDispatcher::CleanupDownloads(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) {}
+
+void TestPrefetchDispatcher::DownloadCompleted(
+ const PrefetchDownloadResult& download_result) {
+ download_results.push_back(download_result);
+}
+
+void TestPrefetchDispatcher::ImportCompleted(int64_t offline_id, bool success) {
+}
+
void TestPrefetchDispatcher::RequestFinishBackgroundTaskForTest() {}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
index fb6620d56ad..5b98a060f3b 100644
--- a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
@@ -29,18 +29,30 @@ class TestPrefetchDispatcher : public PrefetchDispatcher {
void BeginBackgroundTask(std::unique_ptr<ScopedBackgroundTask> task) override;
void StopBackgroundTask() override;
void SetService(PrefetchService* service) override;
+ void SchedulePipelineProcessing() override;
+ void EnsureTaskScheduled() override;
void GCMOperationCompletedMessageReceived(
const std::string& operation_name) override;
+ void CleanupDownloads(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) override;
+ void DownloadCompleted(
+ const PrefetchDownloadResult& download_result) override;
+ void ImportCompleted(int64_t offline_id, bool success) override;
void RequestFinishBackgroundTaskForTest() override;
std::string latest_name_space;
std::vector<PrefetchURL> latest_prefetch_urls;
std::unique_ptr<ClientId> last_removed_client_id;
std::vector<std::string> operation_list;
+ std::vector<PrefetchDownloadResult> download_results;
int new_suggestions_count = 0;
+ int processing_schedule_count = 0;
int remove_all_suggestions_count = 0;
int remove_by_client_id_count = 0;
+ int task_schedule_count = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.cc b/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.cc
new file mode 100644
index 00000000000..2ef9fd72f0d
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.cc
@@ -0,0 +1,43 @@
+// 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/offline_pages/core/prefetch/test_prefetch_downloader.h"
+
+namespace offline_pages {
+
+TestPrefetchDownloader::TestPrefetchDownloader() = default;
+
+TestPrefetchDownloader::~TestPrefetchDownloader() = default;
+
+void TestPrefetchDownloader::SetPrefetchService(PrefetchService* service) {}
+
+void TestPrefetchDownloader::StartDownload(
+ const std::string& download_id,
+ const std::string& download_location) {
+ requested_downloads_[download_id] = download_location;
+}
+
+void TestPrefetchDownloader::CancelDownload(const std::string& download_id) {}
+
+void TestPrefetchDownloader::OnDownloadServiceReady(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) {}
+
+void TestPrefetchDownloader::OnDownloadServiceUnavailable() {}
+
+void TestPrefetchDownloader::OnDownloadServiceShutdown() {}
+
+void TestPrefetchDownloader::OnDownloadSucceeded(
+ const std::string& download_id,
+ const base::FilePath& file_path,
+ int64_t file_size) {}
+
+void TestPrefetchDownloader::OnDownloadFailed(const std::string& download_id) {}
+
+void TestPrefetchDownloader::Reset() {
+ requested_downloads_.clear();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.h b/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.h
new file mode 100644
index 00000000000..a288bde9292
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_downloader.h
@@ -0,0 +1,49 @@
+// 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_OFFLINE_PAGES_CORE_PREFETCH_TEST_PREFETCH_DOWNLOADER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_PREFETCH_DOWNLOADER_H_
+
+#include <map>
+#include <string>
+
+#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
+#include "components/offline_pages/core/prefetch/prefetch_types.h"
+
+namespace offline_pages {
+
+// Mock implementation of prefetch downloader that is suitable for testing.
+class TestPrefetchDownloader : public PrefetchDownloader {
+ public:
+ TestPrefetchDownloader();
+ ~TestPrefetchDownloader() override;
+
+ void SetPrefetchService(PrefetchService* service) override;
+ void StartDownload(const std::string& download_id,
+ const std::string& download_location) override;
+ void CancelDownload(const std::string& download_id) override;
+ void OnDownloadServiceReady(
+ const std::set<std::string>& outstanding_download_ids,
+ const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+ success_downloads) override;
+ void OnDownloadServiceUnavailable() override;
+ void OnDownloadServiceShutdown() override;
+ void OnDownloadSucceeded(const std::string& download_id,
+ const base::FilePath& file_path,
+ int64_t file_size) override;
+ void OnDownloadFailed(const std::string& download_id) override;
+
+ void Reset();
+
+ const std::map<std::string, std::string>& requested_downloads() const {
+ return requested_downloads_;
+ }
+
+ private:
+ std::map<std::string, std::string> requested_downloads_;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_PREFETCH_DOWNLOADER_H_
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_importer.h b/chromium/components/offline_pages/core/prefetch/test_prefetch_importer.h
index 939b4eadda6..1600ef2eff5 100644
--- a/chromium/components/offline_pages/core/prefetch/test_prefetch_importer.h
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_importer.h
@@ -12,17 +12,10 @@ namespace offline_pages {
// Testing prefetch importer that does nothing.
class TestPrefetchImporter : public PrefetchImporter {
public:
- TestPrefetchImporter() {}
+ TestPrefetchImporter() : PrefetchImporter(nullptr) {}
~TestPrefetchImporter() override = default;
- void ImportFile(const GURL& url,
- const GURL& original_url,
- const base::string16& title,
- int64_t offline_id,
- const ClientId& client_id,
- const base::FilePath& file_path,
- int64_t file_size,
- const CompletedCallback& callback) override {}
+ void ImportArchive(const PrefetchArchiveInfo& archive) override {}
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/renovations/BUILD.gn b/chromium/components/offline_pages/core/renovations/BUILD.gn
new file mode 100644
index 00000000000..f7712136218
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/BUILD.gn
@@ -0,0 +1,43 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("renovations") {
+ sources = [
+ "page_renovation.h",
+ "page_renovation_loader.cc",
+ "page_renovation_loader.h",
+ "page_renovator.cc",
+ "page_renovator.h",
+ "script_injector.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/offline_pages/core",
+ "//components/resources:components_resources",
+ "//ui/base",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "page_renovation_loader_unittest.cc",
+ "page_renovator_unittest.cc",
+ ]
+
+ deps = [
+ ":renovations",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/offline_pages/core/renovations/DEPS b/chromium/components/offline_pages/core/renovations/DEPS
new file mode 100644
index 00000000000..65f9de27393
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/grit/components_resources.h",
+ "+ui/base/resource",
+]
diff --git a/chromium/components/offline_pages/core/renovations/page_renovation.h b/chromium/components/offline_pages/core/renovations/page_renovation.h
new file mode 100644
index 00000000000..6a8696f70fa
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovation.h
@@ -0,0 +1,29 @@
+// 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_OFFLINE_PAGES_CORE_PAGE_RENOVATION_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PAGE_RENOVATION_H_
+
+#include <string>
+
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+// Objects implementing this interface represent individual renovations
+// that can be run in a page pre-snapshot.
+class PageRenovation {
+ public:
+ virtual ~PageRenovation() {}
+
+ // Returns |true| if this renovation should run in the page from |url|.
+ virtual bool ShouldRun(const GURL& url) const = 0;
+ // Returns an ID that identifies this renovation's script. This ID
+ // can be passed to the PageRenovationLoader.
+ virtual std::string GetID() const = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PAGE_RENOVATION_H_
diff --git a/chromium/components/offline_pages/core/renovations/page_renovation_loader.cc b/chromium/components/offline_pages/core/renovations/page_renovation_loader.cc
new file mode 100644
index 00000000000..2bd63976929
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovation_loader.cc
@@ -0,0 +1,108 @@
+// 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/offline_pages/core/renovations/page_renovation_loader.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/grit/components_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace offline_pages {
+
+namespace {
+
+// Helper function used in WikipediaPageRenovation::ShouldRun.
+bool EndsWith(const std::string& host, const std::string& suffix) {
+ if (suffix.size() > host.size())
+ return false;
+
+ return std::equal(suffix.rbegin(), suffix.rend(), host.rbegin());
+}
+
+// Concrete PageRenovation instances
+class WikipediaPageRenovation : public PageRenovation {
+ public:
+ bool ShouldRun(const GURL& url) const override {
+ return EndsWith(url.host(), "m.wikipedia.org");
+ }
+
+ std::string GetID() const override { return "wikipedia"; }
+};
+
+// Construct list of implemented renovations
+std::vector<std::unique_ptr<PageRenovation>> MakeRenovationList() {
+ std::vector<std::unique_ptr<PageRenovation>> list;
+ list.emplace_back(new WikipediaPageRenovation);
+ return list;
+}
+
+} // namespace
+
+PageRenovationLoader::PageRenovationLoader()
+ : renovations_(MakeRenovationList()), is_loaded_(false) {}
+
+PageRenovationLoader::~PageRenovationLoader() {}
+
+bool PageRenovationLoader::GetRenovationScript(
+ const std::vector<std::string>& renovation_ids,
+ base::string16* script) {
+ if (!LoadSource()) {
+ return false;
+ }
+
+ // The loaded script contains a function called run_renovations
+ // which takes an array of renovation names and runs all the
+ // associated renovation code. Create call to run_renovations
+ // function in JavaScript file.
+ std::string jsCall = "\nrun_renovations([";
+ for (const std::string& renovation_id : renovation_ids) {
+ jsCall += "\"";
+ jsCall += renovation_id;
+ jsCall += "\",";
+ }
+ jsCall += "]);";
+
+ // Append run_renovations call to combined_source_, which contains
+ // the definition of run_renovations.
+ *script = combined_source_;
+ *script += base::UTF8ToUTF16(jsCall);
+
+ return true;
+}
+
+bool PageRenovationLoader::LoadSource() {
+ // We only need to load the script from storage once.
+ if (is_loaded_) {
+ return true;
+ }
+
+ // Our script file is stored in the resource bundle. Get this script.
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ combined_source_ = base::UTF8ToUTF16(
+ rb.GetRawDataResource(IDR_OFFLINE_PAGES_RENOVATIONS_JS).as_string());
+
+ // If built correctly, IDR_OFFLINE_PAGES_RENOVATIONS_JS should
+ // always exist in the resource pack and loading should never fail.
+ DCHECK_GT(combined_source_.size(), 0U);
+
+ is_loaded_ = true;
+ return true;
+}
+
+void PageRenovationLoader::SetSourceForTest(base::string16 combined_source) {
+ combined_source_ = std::move(combined_source);
+ is_loaded_ = true;
+}
+
+void PageRenovationLoader::SetRenovationsForTest(
+ std::vector<std::unique_ptr<PageRenovation>> renovations) {
+ renovations_ = std::move(renovations);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/renovations/page_renovation_loader.h b/chromium/components/offline_pages/core/renovations/page_renovation_loader.h
new file mode 100644
index 00000000000..bfdfd9dc8cb
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovation_loader.h
@@ -0,0 +1,59 @@
+// 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_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATION_LOADER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATION_LOADER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/offline_pages/core/renovations/page_renovation.h"
+
+namespace offline_pages {
+
+// Class for preparing page renovation scripts. Handles loading
+// JavaScript from storage and creating script to run particular
+// renovations.
+class PageRenovationLoader {
+ public:
+ PageRenovationLoader();
+ ~PageRenovationLoader();
+
+ // Takes a list of renovation IDs and outputs a script to be run in
+ // page. Returns whether loading was successful. The script is a
+ // string16 to match the rest of Chrome.
+ bool GetRenovationScript(const std::vector<std::string>& renovation_ids,
+ base::string16* script);
+
+ // Returns the list of known renovations.
+ const std::vector<std::unique_ptr<PageRenovation>>& renovations() {
+ return renovations_;
+ }
+
+ // Methods for testing.
+ void SetSourceForTest(base::string16 combined_source);
+ void SetRenovationsForTest(
+ std::vector<std::unique_ptr<PageRenovation>> renovations);
+
+ private:
+ // Called to load JavaScript source from storage.
+ bool LoadSource();
+
+ // List of registered page renovations
+ std::vector<std::unique_ptr<PageRenovation>> renovations_;
+
+ // Whether JavaScript source has been loaded.
+ bool is_loaded_;
+ // Contains JavaScript source.
+ base::string16 combined_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageRenovationLoader);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATION_LOADER_H_
diff --git a/chromium/components/offline_pages/core/renovations/page_renovation_loader_unittest.cc b/chromium/components/offline_pages/core/renovations/page_renovation_loader_unittest.cc
new file mode 100644
index 00000000000..66ad606c218
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovation_loader_unittest.cc
@@ -0,0 +1,76 @@
+// 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/offline_pages/core/renovations/page_renovation_loader.h"
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+const char kTestRenovationKey1[] = "abc_renovation";
+const char kTestRenovationKey2[] = "xyz_renovation";
+const char kTestRenovationScript[] =
+ "\nrun_renovations([\"abc_renovation\",\"xyz_renovation\",]);";
+} // namespace
+
+class PageRenovationLoaderTest : public testing::Test {
+ public:
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ std::unique_ptr<PageRenovationLoader> page_renovation_loader_;
+};
+
+void PageRenovationLoaderTest::SetUp() {
+ page_renovation_loader_.reset(new PageRenovationLoader);
+ page_renovation_loader_->SetSourceForTest(base::string16());
+}
+
+void PageRenovationLoaderTest::TearDown() {
+ page_renovation_loader_.reset();
+}
+
+TEST_F(PageRenovationLoaderTest, NoRenovations) {
+ std::vector<std::string> renovation_keys;
+ // Pass empty list
+ base::string16 script;
+ EXPECT_TRUE(
+ page_renovation_loader_->GetRenovationScript(renovation_keys, &script));
+
+ EXPECT_EQ(script, base::UTF8ToUTF16("\nrun_renovations([]);"));
+}
+
+TEST_F(PageRenovationLoaderTest, TestRenovations) {
+ std::vector<std::string> renovation_keys;
+ renovation_keys.push_back(kTestRenovationKey1);
+ renovation_keys.push_back(kTestRenovationKey2);
+
+ base::string16 script;
+ EXPECT_TRUE(
+ page_renovation_loader_->GetRenovationScript(renovation_keys, &script));
+
+ EXPECT_EQ(script, base::UTF8ToUTF16(kTestRenovationScript));
+}
+
+TEST_F(PageRenovationLoaderTest, ReturnsSameScript) {
+ std::vector<std::string> renovation_keys;
+ renovation_keys.push_back(kTestRenovationKey1);
+ renovation_keys.push_back(kTestRenovationKey2);
+
+ base::string16 script1, script2;
+ EXPECT_TRUE(
+ page_renovation_loader_->GetRenovationScript(renovation_keys, &script1));
+ EXPECT_TRUE(
+ page_renovation_loader_->GetRenovationScript(renovation_keys, &script2));
+
+ EXPECT_EQ(script1, script2);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/renovations/page_renovator.cc b/chromium/components/offline_pages/core/renovations/page_renovator.cc
new file mode 100644
index 00000000000..3c8e5df1934
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovator.cc
@@ -0,0 +1,55 @@
+// 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/offline_pages/core/renovations/page_renovator.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace offline_pages {
+
+PageRenovator::PageRenovator(PageRenovationLoader* renovation_loader,
+ std::unique_ptr<ScriptInjector> script_injector,
+ const GURL& request_url)
+ : renovation_loader_(renovation_loader),
+ script_injector_(std::move(script_injector)) {
+ DCHECK(renovation_loader);
+
+ PrepareScript(request_url);
+}
+
+PageRenovator::~PageRenovator() {}
+
+void PageRenovator::RunRenovations(base::Closure callback) {
+ // Prepare callback and inject combined script.
+ base::RepeatingCallback<void(const base::Value&)> cb = base::Bind(
+ [](base::Closure callback, const base::Value&) {
+ if (callback)
+ callback.Run();
+ },
+ std::move(callback));
+
+ script_injector_->Inject(script_, cb);
+}
+
+void PageRenovator::PrepareScript(const GURL& url) {
+ std::vector<std::string> renovation_keys;
+
+ // Pick which renovations to run.
+ for (const std::unique_ptr<PageRenovation>& renovation :
+ renovation_loader_->renovations()) {
+ if (renovation->ShouldRun(url)) {
+ renovation_keys.push_back(renovation->GetID());
+ }
+ }
+
+ // Store combined renovation script. TODO(crbug.com/736933): handle
+ // failed GetRenovationScript call.
+ renovation_loader_->GetRenovationScript(renovation_keys, &script_);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/renovations/page_renovator.h b/chromium/components/offline_pages/core/renovations/page_renovator.h
new file mode 100644
index 00000000000..62e02c50291
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovator.h
@@ -0,0 +1,51 @@
+// 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_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATOR_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATOR_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/offline_pages/core/renovations/page_renovation_loader.h"
+#include "components/offline_pages/core/renovations/script_injector.h"
+#include "components/offline_pages/core/snapshot_controller.h"
+
+namespace offline_pages {
+
+// This class runs renovations in a page being offlined. Upon
+// construction, it determines which renovations to run. The user
+// should then call RunRenovations when the page is sufficiently
+// loaded. When complete (if ever) the passed CompletionCallback will
+// be called.
+class PageRenovator {
+ public:
+ using CompletionCallback = base::RepeatingClosure;
+
+ // |renovation_loader| should be owned by the user and is expected to
+ // outlive this PageRenovator instance.
+ PageRenovator(PageRenovationLoader* renovation_loader,
+ std::unique_ptr<ScriptInjector> script_injector,
+ const GURL& request_url);
+ ~PageRenovator();
+
+ // Run renovation scripts and call callback when they complete.
+ void RunRenovations(CompletionCallback callback);
+
+ private:
+ // This method is used in the constructor to determine which
+ // renovations to run and populate |script_| with the renovations.
+ void PrepareScript(const GURL& url);
+
+ PageRenovationLoader* renovation_loader_;
+ std::unique_ptr<ScriptInjector> script_injector_;
+ base::string16 script_;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_PAGE_RENOVATOR_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
new file mode 100644
index 00000000000..7e9b2c8ce01
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc
@@ -0,0 +1,89 @@
+// 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/offline_pages/core/renovations/page_renovator.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/mock_callback.h"
+#include "base/values.h"
+#include "components/offline_pages/core/renovations/script_injector.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+class PageRenovatorTest : public testing::Test {
+ public:
+ PageRenovatorTest();
+ ~PageRenovatorTest() override;
+
+ protected:
+ // ScriptInjector for testing PageRenovator. When Inject is called,
+ // it sets |script_injector_inject_called_| in the fixture to true,
+ // then calls the callback.
+ class FakeScriptInjector : public ScriptInjector {
+ public:
+ FakeScriptInjector(PageRenovatorTest* fixture);
+ ~FakeScriptInjector() override = default;
+
+ void Inject(base::string16 script, ResultCallback callback) override;
+
+ private:
+ PageRenovatorTest* fixture_;
+ };
+
+ // Creates a PageRenovator with simple defaults for testing.
+ void CreatePageRenovator(const GURL& url);
+
+ PageRenovationLoader page_renovation_loader_;
+ bool script_injector_inject_called_ = false;
+
+ // PageRenovator under test.
+ std::unique_ptr<PageRenovator> page_renovator_;
+};
+
+PageRenovatorTest::FakeScriptInjector::FakeScriptInjector(
+ PageRenovatorTest* fixture)
+ : fixture_(fixture) {}
+
+void PageRenovatorTest::FakeScriptInjector::Inject(base::string16 script,
+ ResultCallback callback) {
+ if (callback)
+ callback.Run(base::Value());
+ fixture_->script_injector_inject_called_ = true;
+}
+
+PageRenovatorTest::PageRenovatorTest() {
+ // Set PageRenovationLoader to have empty script and Renovation list.
+ page_renovation_loader_.SetSourceForTest(base::string16());
+ page_renovation_loader_.SetRenovationsForTest(
+ std::vector<std::unique_ptr<PageRenovation>>());
+
+ page_renovator_ = base::MakeUnique<PageRenovator>(
+ &page_renovation_loader_, base::MakeUnique<FakeScriptInjector>(this),
+ GURL("example.com"));
+}
+
+PageRenovatorTest::~PageRenovatorTest() {}
+
+TEST_F(PageRenovatorTest, InjectsScript) {
+ EXPECT_FALSE(script_injector_inject_called_);
+ page_renovator_->RunRenovations(base::Closure());
+ EXPECT_TRUE(script_injector_inject_called_);
+}
+
+TEST_F(PageRenovatorTest, CallsCallback) {
+ base::MockCallback<base::Closure> mock_callback;
+ EXPECT_CALL(mock_callback, Run()).Times(1);
+
+ page_renovator_->RunRenovations(mock_callback.Get());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/renovations/script_injector.h b/chromium/components/offline_pages/core/renovations/script_injector.h
new file mode 100644
index 00000000000..aa80cf063d6
--- /dev/null
+++ b/chromium/components/offline_pages/core/renovations/script_injector.h
@@ -0,0 +1,33 @@
+// 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_OFFLINE_PAGES_CORE_RENOVATIONS_SCRIPT_INJECTOR_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_SCRIPT_INJECTOR_H_
+
+#include "base/callback_forward.h"
+#include "base/strings/string16.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace offline_pages {
+
+// Interface for injecting and running scripts in some
+// context. Inject() takes a string of JavaScript, injects it into the
+// context, then calls the ResultCallback with the expression value.
+class ScriptInjector {
+ public:
+ using ResultCallback = base::Callback<void(const base::Value&)>;
+
+ virtual ~ScriptInjector() = default;
+
+ // Takes a string of JavaScript, injects it into the context, then
+ // calls the ResultCallback with the expression value.
+ virtual void Inject(base::string16 script, ResultCallback callback) = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_RENOVATIONS_SCRIPT_INJECTOR_H_
diff --git a/chromium/components/offline_pages/core/snapshot_controller.cc b/chromium/components/offline_pages/core/snapshot_controller.cc
index 9d62297fb7b..27bb798c8e1 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller.cc
@@ -23,6 +23,11 @@ const int64_t kDefaultDelayAfterDocumentAvailableMs = 7000;
const int64_t kDelayAfterDocumentOnLoadCompletedMsForeground = 1000;
const int64_t kDelayAfterDocumentOnLoadCompletedMsBackground = 2000;
+// Default delay, in milliseconds, between renovations finishing and
+// taking a snapshot. Allows for page to update in response to the
+// renovations.
+const int64_t kDelayAfterRenovationsCompletedMs = 2000;
+
// Delay for testing to keep polling times reasonable.
const int64_t kDelayForTests = 0;
@@ -38,18 +43,21 @@ SnapshotController::CreateForForegroundOfflining(
return std::unique_ptr<SnapshotController>(new SnapshotController(
task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
kDelayAfterDocumentOnLoadCompletedMsForeground,
- kDocumentAvailableTriggersSnapshot));
+ kDelayAfterRenovationsCompletedMs, kDocumentAvailableTriggersSnapshot,
+ false));
}
// static
std::unique_ptr<SnapshotController>
SnapshotController::CreateForBackgroundOfflining(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- SnapshotController::Client* client) {
+ SnapshotController::Client* client,
+ bool renovations_enabled) {
return std::unique_ptr<SnapshotController>(new SnapshotController(
task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
kDelayAfterDocumentOnLoadCompletedMsBackground,
- !kDocumentAvailableTriggersSnapshot));
+ kDelayAfterRenovationsCompletedMs, !kDocumentAvailableTriggersSnapshot,
+ renovations_enabled));
}
SnapshotController::SnapshotController(
@@ -57,19 +65,25 @@ SnapshotController::SnapshotController(
SnapshotController::Client* client,
int64_t delay_after_document_available_ms,
int64_t delay_after_document_on_load_completed_ms,
- bool document_available_triggers_snapshot)
+ int64_t delay_after_renovations_completed_ms,
+ bool document_available_triggers_snapshot,
+ bool renovations_enabled)
: task_runner_(task_runner),
client_(client),
state_(State::READY),
delay_after_document_available_ms_(delay_after_document_available_ms),
delay_after_document_on_load_completed_ms_(
delay_after_document_on_load_completed_ms),
+ delay_after_renovations_completed_ms_(
+ delay_after_renovations_completed_ms),
document_available_triggers_snapshot_(
document_available_triggers_snapshot),
+ renovations_enabled_(renovations_enabled),
weak_ptr_factory_(this) {
if (offline_pages::ShouldUseTestingSnapshotDelay()) {
delay_after_document_available_ms_ = kDelayForTests;
delay_after_document_on_load_completed_ms_ = kDelayForTests;
+ delay_after_renovations_completed_ms_ = kDelayForTests;
}
}
@@ -94,6 +108,17 @@ void SnapshotController::PendingSnapshotCompleted() {
state_ = State::READY;
}
+void SnapshotController::RenovationsCompleted() {
+ if (renovations_enabled_) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SnapshotController::MaybeStartSnapshotThenStop,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(
+ delay_after_renovations_completed_ms_));
+ }
+}
+
void SnapshotController::DocumentAvailableInMainFrame() {
if (document_available_triggers_snapshot_) {
DCHECK_EQ(PageQuality::POOR, current_page_quality_);
@@ -108,12 +133,19 @@ void SnapshotController::DocumentAvailableInMainFrame() {
}
void SnapshotController::DocumentOnLoadCompletedInMainFrame() {
- // Post a delayed task to snapshot and then stop this controller.
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&SnapshotController::MaybeStartSnapshotThenStop,
- weak_ptr_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(
- delay_after_document_on_load_completed_ms_));
+ if (renovations_enabled_) {
+ // Run renovations. After renovations complete, a snapshot will be
+ // triggered after a delay.
+ client_->RunRenovations();
+ } else {
+ // Post a delayed task to snapshot and then stop this controller.
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SnapshotController::MaybeStartSnapshotThenStop,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(
+ delay_after_document_on_load_completed_ms_));
+ }
}
void SnapshotController::MaybeStartSnapshot(PageQuality updated_page_quality) {
@@ -138,4 +170,8 @@ int64_t SnapshotController::GetDelayAfterDocumentOnLoadCompletedForTest() {
return delay_after_document_on_load_completed_ms_;
}
+int64_t SnapshotController::GetDelayAfterRenovationsCompletedForTest() {
+ return delay_after_renovations_completed_ms_;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/snapshot_controller.h b/chromium/components/offline_pages/core/snapshot_controller.h
index bcd5ee00b1b..ff89102b270 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.h
+++ b/chromium/components/offline_pages/core/snapshot_controller.h
@@ -56,6 +56,11 @@ class SnapshotController {
// it is assumed that later snapshots are better then previous.
virtual void StartSnapshot() = 0;
+ // Invoked when the page is sufficiently loaded for running
+ // renovations. The client should call the RenovationsCompleted()
+ // when they finish.
+ virtual void RunRenovations() = 0;
+
protected:
virtual ~Client() {}
};
@@ -69,14 +74,17 @@ class SnapshotController {
// and ignores document available signal.
static std::unique_ptr<SnapshotController> CreateForBackgroundOfflining(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- SnapshotController::Client* client);
+ SnapshotController::Client* client,
+ bool renovations_enabled);
SnapshotController(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
SnapshotController::Client* client,
int64_t delay_after_document_available_ms,
int64_t delay_after_document_on_load_completed_ms,
- bool document_available_triggers_snapshot);
+ int64_t delay_after_renovations_completed_ms,
+ bool document_available_triggers_snapshot,
+ bool renovations_enabled);
virtual ~SnapshotController();
// Resets the 'session', returning controller to initial state.
@@ -91,6 +99,9 @@ class SnapshotController {
// now completed (so the next one can be started).
void PendingSnapshotCompleted();
+ // The Client calls this when renovations have completed.
+ void RenovationsCompleted();
+
// Invoked from WebContentObserver::DocumentAvailableInMainFrame
void DocumentAvailableInMainFrame();
@@ -99,6 +110,7 @@ class SnapshotController {
int64_t GetDelayAfterDocumentAvailableForTest();
int64_t GetDelayAfterDocumentOnLoadCompletedForTest();
+ int64_t GetDelayAfterRenovationsCompletedForTest();
PageQuality current_page_quality() const { return current_page_quality_; }
@@ -112,7 +124,9 @@ class SnapshotController {
SnapshotController::State state_;
int64_t delay_after_document_available_ms_;
int64_t delay_after_document_on_load_completed_ms_;
+ int64_t delay_after_renovations_completed_ms_;
bool document_available_triggers_snapshot_;
+ bool renovations_enabled_;
// The expected quality of a snapshot taken at the moment this value is
// queried.
diff --git a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
index 123437b4e48..fbd27e7a0f8 100644
--- a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
@@ -29,6 +29,7 @@ class SnapshotControllerTest : public testing::Test,
// SnapshotController::Client
void StartSnapshot() override;
+ void RunRenovations() override;
// Utility methods.
// Runs until all of the tasks that are not delayed are gone from the task
@@ -66,6 +67,10 @@ void SnapshotControllerTest::StartSnapshot() {
snapshot_count_++;
}
+void SnapshotControllerTest::RunRenovations() {
+ controller_->RenovationsCompleted();
+}
+
void SnapshotControllerTest::PumpLoop() {
task_runner_->RunUntilIdle();
}
diff --git a/chromium/components/offline_pages/core/stub_offline_page_model.cc b/chromium/components/offline_pages/core/stub_offline_page_model.cc
index 0398211fe6c..5808083002d 100644
--- a/chromium/components/offline_pages/core/stub_offline_page_model.cc
+++ b/chromium/components/offline_pages/core/stub_offline_page_model.cc
@@ -48,6 +48,9 @@ void StubOfflinePageModel::GetPagesByURL(
const GURL& url,
URLSearchMode url_search_mode,
const MultipleOfflinePageItemCallback& callback) {}
+void StubOfflinePageModel::GetPagesByRequestOrigin(
+ const std::string& origin,
+ const MultipleOfflinePageItemCallback& callback) {}
ClientPolicyController* StubOfflinePageModel::GetPolicyController() {
return &policy_controller_;
}
diff --git a/chromium/components/offline_pages/core/stub_offline_page_model.h b/chromium/components/offline_pages/core/stub_offline_page_model.h
index e540930d415..11d9c9f62be 100644
--- a/chromium/components/offline_pages/core/stub_offline_page_model.h
+++ b/chromium/components/offline_pages/core/stub_offline_page_model.h
@@ -58,6 +58,9 @@ class StubOfflinePageModel : public OfflinePageModel, public KeyedService {
const GURL& url,
URLSearchMode url_search_mode,
const MultipleOfflinePageItemCallback& callback) override;
+ void GetPagesByRequestOrigin(
+ const std::string& origin,
+ const MultipleOfflinePageItemCallback& callback) override;
ClientPolicyController* GetPolicyController() override;
bool is_loaded() const override;
OfflineEventLogger* GetLogger() override;
diff --git a/chromium/components/offline_pages/core/task_queue.cc b/chromium/components/offline_pages/core/task_queue.cc
index 777a82d3583..cb8b6ecea66 100644
--- a/chromium/components/offline_pages/core/task_queue.cc
+++ b/chromium/components/offline_pages/core/task_queue.cc
@@ -9,7 +9,10 @@
namespace offline_pages {
-TaskQueue::TaskQueue() : weak_ptr_factory_(this) {}
+TaskQueue::TaskQueue(Delegate* delegate)
+ : delegate_(delegate), weak_ptr_factory_(this) {
+ DCHECK(delegate_);
+}
TaskQueue::~TaskQueue() {}
@@ -32,8 +35,15 @@ bool TaskQueue::HasRunningTask() const {
void TaskQueue::StartTaskIfAvailable() {
DVLOG(2) << "running? " << HasRunningTask() << ", pending? "
<< HasPendingTasks() << " " << __func__;
- if (HasRunningTask() || !HasPendingTasks())
+ if (HasRunningTask())
+ return;
+
+ if (!HasPendingTasks()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&TaskQueue::InformTaskQueueIsIdle,
+ weak_ptr_factory_.GetWeakPtr()));
return;
+ }
current_task_ = std::move(tasks_.front());
tasks_.pop();
@@ -48,4 +58,8 @@ void TaskQueue::TaskCompleted(Task* task) {
}
}
+void TaskQueue::InformTaskQueueIsIdle() {
+ delegate_->OnTaskQueueIsIdle();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/task_queue.h b/chromium/components/offline_pages/core/task_queue.h
index 4d685603f18..6488f9a79b5 100644
--- a/chromium/components/offline_pages/core/task_queue.h
+++ b/chromium/components/offline_pages/core/task_queue.h
@@ -29,7 +29,15 @@ namespace offline_pages {
// the previous one calls |Task::TaskComplete|.
class TaskQueue {
public:
- TaskQueue();
+ class Delegate {
+ public:
+ virtual ~Delegate() {};
+
+ // Invoked once when TaskQueue reached 0 tasks.
+ virtual void OnTaskQueueIsIdle() = 0;
+ };
+
+ explicit TaskQueue(Delegate* delegate);
~TaskQueue();
// Adds a task to the queue. Queue takes ownership of the task.
@@ -48,6 +56,11 @@ class TaskQueue {
// Callback for informing the queue that a task was completed.
void TaskCompleted(Task* task);
+ void InformTaskQueueIsIdle();
+
+ // Owns and outlives this TaskQueue.
+ Delegate* delegate_;
+
// Currently running tasks.
std::unique_ptr<Task> current_task_;
diff --git a/chromium/components/offline_pages/core/task_queue_unittest.cc b/chromium/components/offline_pages/core/task_queue_unittest.cc
index 426e55efaf0..555bf1efc42 100644
--- a/chromium/components/offline_pages/core/task_queue_unittest.cc
+++ b/chromium/components/offline_pages/core/task_queue_unittest.cc
@@ -16,30 +16,39 @@ namespace offline_pages {
using TaskState = TestTask::TaskState;
-class OfflineTaskQueueTest : public testing::Test {
+class OfflineTaskQueueTest : public testing::Test, public TaskQueue::Delegate {
public:
OfflineTaskQueueTest();
+ ~OfflineTaskQueueTest() override = default;
+
+ // TaskQueue::Delegate
+ void OnTaskQueueIsIdle() override;
void TaskCompleted(Task* task);
void PumpLoop();
Task* completed_task() const { return completed_task_; }
+ bool on_idle_called() { return on_idle_called_; }
private:
- Task* completed_task_;
+ Task* completed_task_ = nullptr;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
+ bool on_idle_called_ = false;
};
OfflineTaskQueueTest::OfflineTaskQueueTest()
- : completed_task_(nullptr),
- task_runner_(new base::TestSimpleTaskRunner),
+ : task_runner_(new base::TestSimpleTaskRunner),
task_runner_handle_(task_runner_) {}
void OfflineTaskQueueTest::PumpLoop() {
task_runner_->RunUntilIdle();
}
+void OfflineTaskQueueTest::OnTaskQueueIsIdle() {
+ on_idle_called_ = true;
+}
+
void OfflineTaskQueueTest::TaskCompleted(Task* task) {
completed_task_ = task;
}
@@ -48,7 +57,8 @@ TEST_F(OfflineTaskQueueTest, AddAndRunSingleTask) {
ConsumedResource resource;
std::unique_ptr<TestTask> task(new TestTask(&resource));
TestTask* task_ptr = task.get();
- TaskQueue queue;
+ TaskQueue queue(this);
+ EXPECT_FALSE(on_idle_called());
EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state());
queue.AddTask(std::move(task));
EXPECT_TRUE(queue.HasPendingTasks());
@@ -65,6 +75,7 @@ TEST_F(OfflineTaskQueueTest, AddAndRunSingleTask) {
EXPECT_FALSE(resource.HasNextStep());
PumpLoop(); // Deletes task, task_ptr is invalid after that.
+ EXPECT_TRUE(on_idle_called());
EXPECT_FALSE(queue.HasRunningTask());
EXPECT_FALSE(queue.HasPendingTasks());
}
@@ -76,7 +87,7 @@ TEST_F(OfflineTaskQueueTest, AddAndRunMultipleTasks) {
std::unique_ptr<TestTask> task_2(new TestTask(&resource));
TestTask* task_2_ptr = task_2.get();
- TaskQueue queue;
+ TaskQueue queue(this);
EXPECT_EQ(TaskState::NOT_STARTED, task_1_ptr->state());
EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
queue.AddTask(std::move(task_1));
@@ -95,6 +106,7 @@ TEST_F(OfflineTaskQueueTest, AddAndRunMultipleTasks) {
EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
PumpLoop(); // Deletes task_1, task_1_ptr is invalid after that.
EXPECT_EQ(TaskState::STEP_1, task_2_ptr->state());
+ EXPECT_FALSE(on_idle_called());
}
TEST_F(OfflineTaskQueueTest, LeaveEarly) {
@@ -102,7 +114,7 @@ TEST_F(OfflineTaskQueueTest, LeaveEarly) {
std::unique_ptr<TestTask> task(
new TestTask(&resource, true /* leave early */));
TestTask* task_ptr = task.get();
- TaskQueue queue;
+ TaskQueue queue(this);
EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state());
queue.AddTask(std::move(task));
EXPECT_TRUE(queue.HasPendingTasks());
@@ -116,6 +128,7 @@ TEST_F(OfflineTaskQueueTest, LeaveEarly) {
EXPECT_FALSE(resource.HasNextStep());
PumpLoop(); // Deletes task, task_ptr is invalid after that.
+ EXPECT_TRUE(on_idle_called());
EXPECT_FALSE(queue.HasPendingTasks());
EXPECT_FALSE(queue.HasRunningTask());
}
diff --git a/chromium/components/offline_pages/resources/PRESUBMIT.py b/chromium/components/offline_pages/resources/PRESUBMIT.py
new file mode 100644
index 00000000000..957ea7a6a75
--- /dev/null
+++ b/chromium/components/offline_pages/resources/PRESUBMIT.py
@@ -0,0 +1,11 @@
+# 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.
+
+def PostUploadHook(cl, change, output_api):
+ return output_api.EnsureCQIncludeTrybotsAreAdded(
+ cl,
+ [
+ 'master.tryserver.chromium.linux:closure_compilation',
+ ],
+ 'Automatically added optional Closure bots to run on CQ.')
diff --git a/chromium/components/offline_pages/resources/compiled_resources2.gyp b/chromium/components/offline_pages/resources/compiled_resources2.gyp
new file mode 100644
index 00000000000..191a74acf85
--- /dev/null
+++ b/chromium/components/offline_pages/resources/compiled_resources2.gyp
@@ -0,0 +1,11 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'renovations',
+ 'includes': ['../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/components/offline_pages/resources/renovations.js b/chromium/components/offline_pages/resources/renovations.js
new file mode 100644
index 00000000000..80d3881d456
--- /dev/null
+++ b/chromium/components/offline_pages/resources/renovations.js
@@ -0,0 +1,48 @@
+// 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.
+
+function renovation_wikipedia() {
+ // Get list of elements to expand.
+ elems = document.querySelectorAll(
+ "div.collapsible-block,h2.collapsible-heading");
+
+ // Apply 'open-block' class to elements. This makes the sections'
+ // content visible.
+ for (i = 0; i < elems.length; ++i) {
+ // If a block was already expanded, re-adding the 'open-block'
+ // class will do nothing; no need to check if it's there already.
+ elems.item(i).className += " open-block";
+ }
+
+ // Now we force the page to load images inside the expanded
+ // sections. Wikipedia article images have a lazy image placeholder
+ // as well as a noscript element with an img tag (for if scripts are
+ // disabled). We get the list of these elements in order. For every
+ // lazy image placeholder, there is always a corresponding noscript
+ // element.
+ placeholders = document.querySelectorAll(
+ ".image > span.lazy-image-placeholder, \
+ .mwe-math-element > span.lazy-image-placeholder");
+ noscripts = document.querySelectorAll(
+ ".image > noscript, .mwe-math-element > noscript");
+
+ // Next we delete all the placeholders, then move the img elements
+ // out of the noscripts, deleting the noscript element in the
+ // process.
+ for (i = 0; i < placeholders.length; ++i) {
+ placeholders.item(i).remove();
+ innerText = noscripts.item(i).innerText;
+ noscripts.item(i).outerHTML = innerText;
+ }
+}
+
+var map_renovations = {
+ "wikipedia" : renovation_wikipedia,
+};
+
+function run_renovations(flist) {
+ for (var func_name of flist) {
+ map_renovations[func_name]();
+ }
+}
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index b7fbfc4e551..123256398d6 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -52,6 +52,8 @@ static_library("browser") {
"builtin_provider.h",
"clipboard_url_provider.cc",
"clipboard_url_provider.h",
+ "contextual_suggestions_service.cc",
+ "contextual_suggestions_service.h",
"history_match.cc",
"history_match.h",
"history_provider.cc",
@@ -152,6 +154,7 @@ static_library("browser") {
"//components/search",
"//components/search_engines",
"//components/sessions",
+ "//components/signin/core/browser",
"//components/strings",
"//components/toolbar",
"//components/url_formatter",
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index d2dbb8728dd..ea42fada575 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/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/chromecast_build.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//build/config/linux/pkg_config.gni")
@@ -69,7 +70,7 @@ static_library("os_crypt") {
libs = [ "crypt32.lib" ]
}
- if (is_desktop_linux) {
+ if (is_desktop_linux && !is_chromecast) {
sources -= [ "os_crypt_posix.cc" ]
sources += [
"key_storage_config_linux.cc",
diff --git a/chromium/components/os_crypt/os_crypt.h b/chromium/components/os_crypt/os_crypt.h
index bd079816a94..d5898bf86f4 100644
--- a/chromium/components/os_crypt/os_crypt.h
+++ b/chromium/components/os_crypt/os_crypt.h
@@ -74,8 +74,9 @@ class OSCrypt {
// |get_password_v11_mock| provides a password to derive the encryption key from
// If one parameter is |nullptr|, the function will be not be replaced.
// If all parameters are |nullptr|, the real implementation is restored.
-void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)());
+void UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
+ std::string* (*get_password_v11_mock)());
// Clears any caching and most lazy initialisations performed by the production
// code. Should be used after any test which required a password.
diff --git a/chromium/components/os_crypt/os_crypt_linux.cc b/chromium/components/os_crypt/os_crypt_linux.cc
index 1a141836f48..b39bb091746 100644
--- a/chromium/components/os_crypt/os_crypt_linux.cc
+++ b/chromium/components/os_crypt/os_crypt_linux.cc
@@ -50,12 +50,14 @@ const char kObfuscationPrefix[][4] = {
"v10", "v11",
};
+// Everything in Cache may be leaked on shutdown.
struct Cache {
- std::unique_ptr<KeyStorageLinux> key_storage_cache;
+ // For password_v10, null means uninitialised.
std::unique_ptr<std::string> password_v10_cache;
+ // For password_v11, null means no backend.
std::unique_ptr<std::string> password_v11_cache;
- bool is_key_storage_cached;
bool is_password_v11_cached;
+ // |config| is used to initialise |password_v11_cache| and then cleared.
std::unique_ptr<os_crypt::Config> config;
// Guards access to |g_cache|, making lazy initialization of individual parts
// thread safe.
@@ -64,21 +66,20 @@ struct Cache {
base::LazyInstance<Cache>::Leaky g_cache = LAZY_INSTANCE_INITIALIZER;
-// Lazy acquisition and caching of a KeyStorage. Will be null if no service is
-// found.
-KeyStorageLinux* GetKeyStorage() {
- if (!g_cache.Get().is_key_storage_cached) {
- DCHECK(g_cache.Get().config);
- g_cache.Get().is_key_storage_cached = true;
- g_cache.Get().key_storage_cache =
- KeyStorageLinux::CreateService(*g_cache.Get().config);
- }
- return g_cache.Get().key_storage_cache.get();
+// Create the KeyStorage. Will be null if no service is found. A Config must be
+// set before every call to this function.
+std::unique_ptr<KeyStorageLinux> CreateKeyStorage() {
+ DCHECK(g_cache.Get().config);
+ std::unique_ptr<KeyStorageLinux> key_storage =
+ KeyStorageLinux::CreateService(*g_cache.Get().config);
+ g_cache.Get().config.reset();
+ return key_storage;
}
// Pointer to a function that creates and returns the |KeyStorage| instance to
// be used. The function maintains ownership of the pointer.
-KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
+std::unique_ptr<KeyStorageLinux> (*g_key_storage_provider)() =
+ &CreateKeyStorage;
// Returns a cached string of "peanuts". Is thread-safe.
std::string* GetPasswordV10() {
@@ -94,10 +95,9 @@ std::string* GetPasswordV10() {
std::string* GetPasswordV11() {
base::AutoLock auto_lock(g_cache.Get().lock);
if (!g_cache.Get().is_password_v11_cached) {
+ std::unique_ptr<KeyStorageLinux> key_storage = g_key_storage_provider();
g_cache.Get().password_v11_cache.reset(
- g_key_storage_provider()
- ? new std::string(g_key_storage_provider()->GetKey())
- : nullptr);
+ key_storage ? new std::string(key_storage->GetKey()) : nullptr);
g_cache.Get().is_password_v11_cached = true;
}
return g_cache.Get().password_v11_cache.get();
@@ -230,7 +230,7 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
// static
void OSCrypt::SetConfig(std::unique_ptr<os_crypt::Config> config) {
// Setting initialisation parameters makes no sense after initializing.
- DCHECK(!g_cache.Get().is_key_storage_cached);
+ DCHECK(!g_cache.Get().is_password_v11_cached);
g_cache.Get().config = std::move(config);
}
@@ -240,15 +240,15 @@ bool OSCrypt::IsEncryptionAvailable() {
}
void ClearCacheForTesting() {
- g_cache.Get().key_storage_cache.reset();
g_cache.Get().password_v10_cache.reset();
g_cache.Get().password_v11_cache.reset();
- g_cache.Get().is_key_storage_cached = false;
g_cache.Get().is_password_v11_cached = false;
+ g_cache.Get().config.reset();
}
-void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)()) {
+void UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
+ std::string* (*get_password_v11_mock)()) {
// Save the real implementation to restore it later.
static bool is_get_password_saved = false;
static std::string* (*get_password_save[arraysize(g_get_password)])();
@@ -270,6 +270,6 @@ void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
// Restore real implementation
std::copy(std::begin(get_password_save), std::end(get_password_save),
std::begin(g_get_password));
- g_key_storage_provider = &GetKeyStorage;
+ g_key_storage_provider = &CreateKeyStorage;
}
}
diff --git a/chromium/components/os_crypt/os_crypt_linux_unittest.cc b/chromium/components/os_crypt/os_crypt_linux_unittest.cc
index dce4c4a20e7..58d6da381c9 100644
--- a/chromium/components/os_crypt/os_crypt_linux_unittest.cc
+++ b/chromium/components/os_crypt/os_crypt_linux_unittest.cc
@@ -12,35 +12,45 @@
namespace {
-KeyStorageLinux* GetNullKeyStorage() {
+std::unique_ptr<KeyStorageLinux> GetNullKeyStorage() {
return nullptr;
}
class OSCryptLinuxTest : public testing::Test {
public:
- OSCryptLinuxTest() = default;
- ~OSCryptLinuxTest() override = default;
+ OSCryptLinuxTest() : key_("something") { key_ptr_ = &key_; }
+
+ ~OSCryptLinuxTest() override { key_ptr_ = nullptr; };
void SetUp() override {
- OSCryptMockerLinux::SetUpWithSingleton();
- key_storage_ = OSCryptMockerLinux::GetInstance();
+ OSCryptMockerLinux::SetUp();
+ UseMockKeyStorageForTesting(nullptr, OSCryptLinuxTest::GetKey);
}
void TearDown() override { OSCryptMockerLinux::TearDown(); }
protected:
- OSCryptMockerLinux* key_storage_ = nullptr;
+ void SetEncryptionKey(const std::string& key) { key_ = key; }
+
+ // Get the key of the currently running test.
+ static std::string* GetKey() { return key_ptr_; }
private:
+ std::string key_;
+ // Points to the |key_| of the currently running test.
+ static std::string* key_ptr_;
+
DISALLOW_COPY_AND_ASSIGN(OSCryptLinuxTest);
};
+std::string* OSCryptLinuxTest::key_ptr_;
+
TEST_F(OSCryptLinuxTest, VerifyV0) {
const std::string originaltext = "hello";
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("");
+ SetEncryptionKey(std::string());
ciphertext = originaltext; // No encryption
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -51,9 +61,9 @@ TEST_F(OSCryptLinuxTest, VerifyV10) {
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("peanuts");
+ SetEncryptionKey("peanuts");
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
- key_storage_->ResetTo("not_peanuts");
+ SetEncryptionKey("not_peanuts");
ciphertext = ciphertext.substr(3).insert(0, "v10");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -64,7 +74,7 @@ TEST_F(OSCryptLinuxTest, VerifyV11) {
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("");
+ SetEncryptionKey(std::string());
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
ASSERT_EQ(ciphertext.substr(0, 3), "v11");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
diff --git a/chromium/components/os_crypt/os_crypt_mocker.cc b/chromium/components/os_crypt/os_crypt_mocker.cc
index 7f3afb3b425..5e8745bf6ea 100644
--- a/chromium/components/os_crypt/os_crypt_mocker.cc
+++ b/chromium/components/os_crypt/os_crypt_mocker.cc
@@ -11,11 +11,11 @@
#endif
// static
-void OSCryptMocker::SetUpWithSingleton() {
+void OSCryptMocker::SetUp() {
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(true);
#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
- OSCryptMockerLinux::SetUpWithSingleton();
+ OSCryptMockerLinux::SetUp();
#endif
}
diff --git a/chromium/components/os_crypt/os_crypt_mocker.h b/chromium/components/os_crypt/os_crypt_mocker.h
index a2992efdc96..6f394f8732e 100644
--- a/chromium/components/os_crypt/os_crypt_mocker.h
+++ b/chromium/components/os_crypt/os_crypt_mocker.h
@@ -12,7 +12,7 @@
class OSCryptMocker {
public:
// Inject mocking into OSCrypt.
- static void SetUpWithSingleton();
+ static void SetUp();
// Restore OSCrypt to its real behaviour.
static void TearDown();
diff --git a/chromium/components/os_crypt/os_crypt_mocker_linux.cc b/chromium/components/os_crypt/os_crypt_mocker_linux.cc
index 899616c99c2..f8f0504e985 100644
--- a/chromium/components/os_crypt/os_crypt_mocker_linux.cc
+++ b/chromium/components/os_crypt/os_crypt_mocker_linux.cc
@@ -15,45 +15,24 @@
namespace {
-static base::LazyInstance<OSCryptMockerLinux>::Leaky g_mocker =
- LAZY_INSTANCE_INITIALIZER;
-
-KeyStorageLinux* GetKeyStorage() {
- return OSCryptMockerLinux::GetInstance();
+std::unique_ptr<KeyStorageLinux> CreateNewMock() {
+ return base::MakeUnique<OSCryptMockerLinux>();
}
-std::string* GetPassword() {
- return OSCryptMockerLinux::GetInstance()->GetKeyPtr();
}
-} // namespace
-
std::string OSCryptMockerLinux::GetKey() {
- if (key_.empty())
- base::Base64Encode(base::RandBytesAsString(16), &key_);
return key_;
}
-bool OSCryptMockerLinux::Init() {
- return true;
-}
-
-void OSCryptMockerLinux::ResetTo(base::StringPiece new_key) {
- key_ = new_key.as_string();
-}
-
std::string* OSCryptMockerLinux::GetKeyPtr() {
return &key_;
}
// static
-OSCryptMockerLinux* OSCryptMockerLinux::GetInstance() {
- return g_mocker.Pointer();
-}
-
-// static
-void OSCryptMockerLinux::SetUpWithSingleton() {
- UseMockKeyStorageForTesting(&GetKeyStorage, &GetPassword);
+void OSCryptMockerLinux::SetUp() {
+ UseMockKeyStorageForTesting(
+ &CreateNewMock, nullptr /* get the key from the provider above */);
OSCrypt::SetConfig(base::MakeUnique<os_crypt::Config>());
}
@@ -62,3 +41,8 @@ void OSCryptMockerLinux::TearDown() {
UseMockKeyStorageForTesting(nullptr, nullptr);
ClearCacheForTesting();
}
+
+bool OSCryptMockerLinux::Init() {
+ key_ = "the_encryption_key";
+ return true;
+}
diff --git a/chromium/components/os_crypt/os_crypt_mocker_linux.h b/chromium/components/os_crypt/os_crypt_mocker_linux.h
index b9a65077b52..4a4c1cd20cd 100644
--- a/chromium/components/os_crypt/os_crypt_mocker_linux.h
+++ b/chromium/components/os_crypt/os_crypt_mocker_linux.h
@@ -20,17 +20,11 @@ class OSCryptMockerLinux : public KeyStorageLinux {
// KeyStorageLinux
std::string GetKey() override;
- // Set the password that OSCryptMockerLinux holds.
- void ResetTo(base::StringPiece new_key);
-
// Get a pointer to the stored password. OSCryptMockerLinux owns the pointer.
std::string* GetKeyPtr();
- // Getter for the singleton.
- static OSCryptMockerLinux* GetInstance();
-
- // Inject the singleton mock into OSCrypt.
- static void SetUpWithSingleton();
+ // Inject the mocking scheme into OSCrypt.
+ static void SetUp();
// Restore OSCrypt to its real behaviour.
static void TearDown();
diff --git a/chromium/components/os_crypt/os_crypt_unittest.cc b/chromium/components/os_crypt/os_crypt_unittest.cc
index b5abfc91db7..f3ef01fe0e5 100644
--- a/chromium/components/os_crypt/os_crypt_unittest.cc
+++ b/chromium/components/os_crypt/os_crypt_unittest.cc
@@ -26,7 +26,7 @@ namespace {
class OSCryptTest : public testing::Test {
public:
- OSCryptTest() { OSCryptMocker::SetUpWithSingleton(); }
+ OSCryptTest() { OSCryptMocker::SetUp(); }
~OSCryptTest() override { OSCryptMocker::TearDown(); }
@@ -150,16 +150,7 @@ TEST_F(OSCryptTest, DecryptError) {
class OSCryptConcurrencyTest : public testing::Test {
public:
- OSCryptConcurrencyTest() {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- // Mock the key storage, but not the process of getting the passwords.
- UseMockKeyStorageForTesting(
- []() -> KeyStorageLinux* { return OSCryptMockerLinux::GetInstance(); },
- nullptr);
-#else
- OSCryptMocker::SetUpWithSingleton();
-#endif
- }
+ OSCryptConcurrencyTest() { OSCryptMocker::SetUp(); }
~OSCryptConcurrencyTest() override { OSCryptMocker::TearDown(); };
diff --git a/chromium/components/page_info_strings.grdp b/chromium/components/page_info_strings.grdp
index 59764dd57c2..a84e8c0ad3e 100644
--- a/chromium/components/page_info_strings.grdp
+++ b/chromium/components/page_info_strings.grdp
@@ -212,6 +212,9 @@
<message name="IDS_PAGE_INFO_TYPE_MIDI_SYSEX" desc="The label used for MIDI system exclusive message permission controls in the Page Info popup.">
MIDI devices full control
</message>
+ <message name="IDS_PAGE_INFO_TYPE_SOUND" desc="The label used for the sound permission controls in the Page Info popup.">
+ Sound
+ </message>
<!-- TODO(crbug.com/716303): A few permissions are missing here. -->
<!-- Permission values -->
@@ -328,5 +331,34 @@
<message name="IDS_PAGE_INFO_INSECURE_WEBVR_CONTENT_PERMANENT" desc="Text that is displayed in a small permanent notification on a WebVR page loaded over non-secure transport. (Should be short, does not need to be a complete sentence.)">
Not secure
</message>
+
+ <!-- Password Protection -->
+ <if expr="not is_android">
+ <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if user has reuse their google password on current website.">
+ This site may have just stolen your password
+ </message>
+ <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY_SOFTER" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if user has reuse their google password on current website.">
+ Your password may be compromised
+ </message>
+ <if expr="_google_chrome">
+ <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS" desc="A short paragraph explaining to the user that they has reuse their google password on current website.">
+ You could lose access to your Google Account or experience identity theft. Chrome recommends changing your password now.
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS" desc="A short paragraph explaining to the user that they has reuse their google password on current website.">
+ You could lose access to your Google Account or experience identity theft. Chromium recommends changing your password now.
+ </message>
+ </if>
+ <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON" desc="The string used in the page info change password button.">
+ Help me fix this
+ </message>
+ <message name="IDS_PAGE_INFO_IGNORE_PASSWORD_WARNING_BUTTON" desc="The string used in the page info ignore password warning button.">
+ Ignore
+ </message>
+ <message name="IDS_PAGE_INFO_WHITELIST_PASSWORD_REUSE_BUTTON" desc="The string used in the page info whitelist password reuse button.">
+ Site is legitimate
+ </message>
+ </if>
</if>
</grit-part>
diff --git a/chromium/components/pairing/message_buffer.h b/chromium/components/pairing/message_buffer.h
index 8b2fcc0186d..74a18224feb 100644
--- a/chromium/components/pairing/message_buffer.h
+++ b/chromium/components/pairing/message_buffer.h
@@ -5,8 +5,7 @@
#ifndef COMPONENTS_PAIRING_MESSAGE_BUFFER_H_
#define COMPONENTS_PAIRING_MESSAGE_BUFFER_H_
-#include <deque>
-
+#include "base/containers/circular_deque.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -42,7 +41,8 @@ class MessageBuffer {
// Total number of bytes in IOBuffers in |pending_data_|, including bytes that
// have already been read.
int total_buffer_size_;
- std::deque<std::pair<scoped_refptr<net::IOBuffer>, int> > pending_data_;
+ base::circular_deque<std::pair<scoped_refptr<net::IOBuffer>, int>>
+ pending_data_;
DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
};
diff --git a/chromium/components/password_manager/content/browser/BUILD.gn b/chromium/components/password_manager/content/browser/BUILD.gn
index 3081181f703..e2f2f293021 100644
--- a/chromium/components/password_manager/content/browser/BUILD.gn
+++ b/chromium/components/password_manager/content/browser/BUILD.gn
@@ -6,12 +6,12 @@ static_library("browser") {
sources = [
"bad_message.cc",
"bad_message.h",
+ "content_credential_manager.cc",
+ "content_credential_manager.h",
"content_password_manager_driver.cc",
"content_password_manager_driver.h",
"content_password_manager_driver_factory.cc",
"content_password_manager_driver_factory.h",
- "credential_manager_impl.cc",
- "credential_manager_impl.h",
"password_manager_internals_service_factory.cc",
"password_manager_internals_service_factory.h",
]
@@ -36,7 +36,6 @@ source_set("unit_tests") {
testonly = true
sources = [
"content_password_manager_driver_unittest.cc",
- "credential_manager_impl_unittest.cc",
]
deps = [
":browser",
diff --git a/chromium/components/password_manager/content/browser/bad_message.h b/chromium/components/password_manager/content/browser/bad_message.h
index 20fee3f5b76..c0feba10860 100644
--- a/chromium/components/password_manager/content/browser/bad_message.h
+++ b/chromium/components/password_manager/content/browser/bad_message.h
@@ -27,6 +27,7 @@ enum class BadMessageReason {
CPMD_BAD_ORIGIN_PASSWORD_NO_LONGER_GENERATED = 6,
CPMD_BAD_ORIGIN_PRESAVE_GENERATED_PASSWORD = 7,
CPMD_BAD_ORIGIN_SAVE_GENERATION_FIELD_DETECTED_BY_CLASSIFIER = 8,
+ CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING = 9,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. ContentPasswordManagerDriver becomes CPMD) plus a unique
diff --git a/chromium/components/password_manager/content/browser/content_credential_manager.cc b/chromium/components/password_manager/content/browser/content_credential_manager.cc
new file mode 100644
index 00000000000..97323103cb0
--- /dev/null
+++ b/chromium/components/password_manager/content/browser/content_credential_manager.cc
@@ -0,0 +1,62 @@
+// 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/password_manager/content/browser/content_credential_manager.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+
+namespace password_manager {
+
+// ContentCredentialManager -------------------------------------------------
+
+ContentCredentialManager::ContentCredentialManager(
+ PasswordManagerClient* client)
+ : impl_(client), binding_(this) {}
+
+ContentCredentialManager::~ContentCredentialManager() {}
+
+void ContentCredentialManager::BindRequest(
+ mojom::CredentialManagerAssociatedRequest request) {
+ DCHECK(!binding_.is_bound());
+ binding_.Bind(std::move(request));
+
+ // The browser side will close the message pipe on DidFinishNavigation before
+ // the renderer side would be destroyed, and the renderer never explicitly
+ // closes the pipe. So a connection error really means an error here, in which
+ // case the renderer will try to reconnect when the next call to the API is
+ // made. Make sure this implementation will no longer be bound to a broken
+ // pipe once that happens, so the DCHECK above will succeed.
+ binding_.set_connection_error_handler(base::Bind(
+ &ContentCredentialManager::DisconnectBinding, base::Unretained(this)));
+}
+
+bool ContentCredentialManager::HasBinding() const {
+ return binding_.is_bound();
+}
+
+void ContentCredentialManager::DisconnectBinding() {
+ binding_.Close();
+}
+
+void ContentCredentialManager::Store(const CredentialInfo& credential,
+ StoreCallback callback) {
+ impl_.Store(credential, std::move(callback));
+}
+
+void ContentCredentialManager::PreventSilentAccess(
+ PreventSilentAccessCallback callback) {
+ impl_.PreventSilentAccess(std::move(callback));
+}
+
+void ContentCredentialManager::Get(CredentialMediationRequirement mediation,
+ bool include_passwords,
+ const std::vector<GURL>& federations,
+ GetCallback callback) {
+ impl_.Get(mediation, include_passwords, federations, std::move(callback));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/content/browser/content_credential_manager.h b/chromium/components/password_manager/content/browser/content_credential_manager.h
new file mode 100644
index 00000000000..8e3f02c3327
--- /dev/null
+++ b/chromium/components/password_manager/content/browser/content_credential_manager.h
@@ -0,0 +1,49 @@
+// 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_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_H_
+
+#include "components/password_manager/core/browser/credential_manager_impl.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom.h"
+
+class GURL;
+
+namespace password_manager {
+class PasswordManagerClient;
+struct CredentialInfo;
+
+// Implements mojom::CredentialManager using core class CredentialManagerImpl.
+// Methods Store, PreventSilentAccess and Get are invoked from the renderer
+// with callbacks as arguments. PasswordManagerClient is used to invoke UI.
+class ContentCredentialManager : public mojom::CredentialManager {
+ public:
+ explicit ContentCredentialManager(PasswordManagerClient* client);
+ ~ContentCredentialManager() override;
+
+ void BindRequest(mojom::CredentialManagerAssociatedRequest request);
+ bool HasBinding() const;
+ void DisconnectBinding();
+
+ // mojom::CredentialManager methods:
+ void Store(const CredentialInfo& credential, StoreCallback callback) override;
+ void PreventSilentAccess(PreventSilentAccessCallback callback) override;
+ void Get(CredentialMediationRequirement mediation,
+ bool include_passwords,
+ const std::vector<GURL>& federations,
+ GetCallback callback) override;
+
+ private:
+ CredentialManagerImpl impl_;
+
+ mojo::AssociatedBinding<mojom::CredentialManager> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentCredentialManager);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_H_
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 6e3e0af169d..c1f4971ac62 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
@@ -38,12 +38,11 @@ ContentPasswordManagerDriver::ContentPasswordManagerDriver(
: render_frame_host_(render_frame_host),
client_(client),
password_generation_manager_(client, this),
- password_autofill_manager_(this, autofill_client),
+ password_autofill_manager_(this, autofill_client, client),
next_free_key_(0),
is_main_frame_(render_frame_host->GetParent() == nullptr),
password_manager_binding_(this),
weak_factory_(this) {
-
// For some frames |this| may be instantiated before log manager creation, so
// here we can not send logging state to renderer process for them. For such
// cases, after the log manager got ready later,
@@ -137,6 +136,19 @@ void ContentPasswordManagerDriver::ForceSavePassword() {
weak_factory_.GetWeakPtr()));
}
+void ContentPasswordManagerDriver::ShowManualFallbackForSaving(
+ const autofill::PasswordForm& password_form) {
+ if (!CheckChildProcessSecurityPolicy(
+ password_form.origin,
+ BadMessageReason::CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING))
+ return;
+ GetPasswordManager()->ShowManualFallbackForSaving(this, password_form);
+}
+
+void ContentPasswordManagerDriver::HideManualFallbackForSaving() {
+ GetPasswordManager()->HideManualFallbackForSaving();
+}
+
void ContentPasswordManagerDriver::GeneratePassword() {
GetPasswordGenerationAgent()->UserTriggeredGeneratePassword();
}
@@ -159,6 +171,10 @@ bool ContentPasswordManagerDriver::IsMainFrame() const {
return is_main_frame_;
}
+void ContentPasswordManagerDriver::MatchingBlacklistedFormFound() {
+ GetPasswordAutofillAgent()->BlacklistedFormFound();
+}
+
PasswordGenerationManager*
ContentPasswordManagerDriver::GetPasswordGenerationManager() {
return &password_generation_manager_;
@@ -293,6 +309,13 @@ void ContentPasswordManagerDriver::ShowNotSecureWarning(
text_direction, TransformToRootCoordinates(bounds));
}
+void ContentPasswordManagerDriver::ShowManualFallbackSuggestion(
+ base::i18n::TextDirection text_direction,
+ const gfx::RectF& bounds) {
+ password_autofill_manager_.OnShowManualFallbackSuggestion(
+ text_direction, TransformToRootCoordinates(bounds));
+}
+
void ContentPasswordManagerDriver::RecordSavePasswordProgress(
const std::string& log) {
client_->GetLogManager()->LogSavePasswordProgress(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 8f948f83440..31cdbd65221 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
@@ -71,11 +71,14 @@ class ContentPasswordManagerDriver
const autofill::PasswordFormFillData& form_data) override;
void ClearPreviewedForm() override;
void ForceSavePassword() override;
+ void ShowManualFallbackForSaving(const autofill::PasswordForm& form) override;
+ void HideManualFallbackForSaving() override;
void GeneratePassword() override;
void SendLoggingAvailability() override;
void AllowToRunFormClassifier() override;
autofill::AutofillDriver* GetAutofillDriver() override;
bool IsMainFrame() const override;
+ void MatchingBlacklistedFormFound() override;
PasswordGenerationManager* GetPasswordGenerationManager() override;
PasswordManager* GetPasswordManager() override;
@@ -103,6 +106,8 @@ class ContentPasswordManagerDriver
const gfx::RectF& bounds) override;
void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) override;
+ void ShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
+ const gfx::RectF& bounds) override;
void RecordSavePasswordProgress(const std::string& log) override;
void UserModifiedPasswordField() override;
void SaveGenerationFieldDetectedByClassifier(
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 0283690a766..6b8bb2ec1f3 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
@@ -82,6 +82,8 @@ class FakePasswordAutofillAgent
MOCK_METHOD2(FillPasswordForm,
void(int, const autofill::PasswordFormFillData&));
+ MOCK_METHOD0(BlacklistedFormFound, void());
+
private:
void SetLoggingState(bool active) override {
called_set_logging_state_ = true;
@@ -130,10 +132,8 @@ PasswordFormFillData GetTestPasswordFormFillData() {
return result;
}
-MATCHER_P(WerePasswordsCleared,
- should_preferred_password_cleared,
- "Passwords not cleared") {
- if (should_preferred_password_cleared && !arg.password_field.value.empty())
+MATCHER(WerePasswordsCleared, "Passwords not cleared") {
+ if (!arg.password_field.value.empty())
return false;
for (auto& credentials : arg.additional_logins)
@@ -228,13 +228,20 @@ TEST_F(ContentPasswordManagerDriverTest, ClearPasswordsOnAutofill) {
new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
&autofill_client_));
- for (bool wait_for_username : {false, true}) {
PasswordFormFillData fill_data = GetTestPasswordFormFillData();
- fill_data.wait_for_username = wait_for_username;
- EXPECT_CALL(fake_agent_,
- FillPasswordForm(_, WerePasswordsCleared(wait_for_username)));
+ fill_data.wait_for_username = true;
+ EXPECT_CALL(fake_agent_, FillPasswordForm(_, WerePasswordsCleared()));
driver->FillPasswordForm(fill_data);
- }
+}
+
+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);
}
#if defined(SAFE_BROWSING_DB_LOCAL)
diff --git a/chromium/components/password_manager/content/common/credential_manager.typemap b/chromium/components/password_manager/content/common/credential_manager.typemap
index b3f4a5ae2d9..e77f29f14d7 100644
--- a/chromium/components/password_manager/content/common/credential_manager.typemap
+++ b/chromium/components/password_manager/content/common/credential_manager.typemap
@@ -18,4 +18,5 @@ type_mappings = [
"password_manager.mojom.CredentialType=password_manager::CredentialType",
"password_manager.mojom.CredentialMediationRequirement=password_manager::CredentialMediationRequirement",
"password_manager.mojom.CredentialInfo=password_manager::CredentialInfo",
+ "password_manager.mojom.CredentialManagerError=password_manager::CredentialManagerError",
]
diff --git a/chromium/components/password_manager/content/common/credential_manager_struct_traits.cc b/chromium/components/password_manager/content/common/credential_manager_struct_traits.cc
index 4ca8787b46d..b55a2d9fa02 100644
--- a/chromium/components/password_manager/content/common/credential_manager_struct_traits.cc
+++ b/chromium/components/password_manager/content/common/credential_manager_struct_traits.cc
@@ -49,6 +49,53 @@ bool EnumTraits<mojom::CredentialType, CredentialType>::FromMojom(
}
// static
+mojom::CredentialManagerError
+EnumTraits<mojom::CredentialManagerError, CredentialManagerError>::ToMojom(
+ CredentialManagerError input) {
+ switch (input) {
+ case CredentialManagerError::SUCCESS:
+ return mojom::CredentialManagerError::SUCCESS;
+ case CredentialManagerError::DISABLED:
+ return mojom::CredentialManagerError::DISABLED;
+ case CredentialManagerError::PENDINGREQUEST:
+ return mojom::CredentialManagerError::PENDINGREQUEST;
+ case CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
+ return mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE;
+ case CredentialManagerError::UNKNOWN:
+ return mojom::CredentialManagerError::UNKNOWN;
+ }
+
+ NOTREACHED();
+ return mojom::CredentialManagerError::UNKNOWN;
+}
+
+// static
+bool EnumTraits<mojom::CredentialManagerError, CredentialManagerError>::
+ FromMojom(mojom::CredentialManagerError input,
+ CredentialManagerError* output) {
+ switch (input) {
+ case mojom::CredentialManagerError::SUCCESS:
+ *output = CredentialManagerError::SUCCESS;
+ return true;
+ case mojom::CredentialManagerError::DISABLED:
+ *output = CredentialManagerError::DISABLED;
+ return true;
+ case mojom::CredentialManagerError::PENDINGREQUEST:
+ *output = CredentialManagerError::PENDINGREQUEST;
+ return true;
+ case mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
+ *output = CredentialManagerError::PASSWORDSTOREUNAVAILABLE;
+ return true;
+ case mojom::CredentialManagerError::UNKNOWN:
+ *output = CredentialManagerError::UNKNOWN;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
mojom::CredentialMediationRequirement EnumTraits<
mojom::CredentialMediationRequirement,
CredentialMediationRequirement>::ToMojom(CredentialMediationRequirement
diff --git a/chromium/components/password_manager/content/common/credential_manager_struct_traits.h b/chromium/components/password_manager/content/common/credential_manager_struct_traits.h
index 1fffa0d69b5..9f4fec56226 100644
--- a/chromium/components/password_manager/content/common/credential_manager_struct_traits.h
+++ b/chromium/components/password_manager/content/common/credential_manager_struct_traits.h
@@ -22,6 +22,15 @@ struct EnumTraits<password_manager::mojom::CredentialType,
};
template <>
+struct EnumTraits<password_manager::mojom::CredentialManagerError,
+ password_manager::CredentialManagerError> {
+ static password_manager::mojom::CredentialManagerError ToMojom(
+ password_manager::CredentialManagerError input);
+ static bool FromMojom(password_manager::mojom::CredentialManagerError input,
+ password_manager::CredentialManagerError* output);
+};
+
+template <>
struct EnumTraits<password_manager::mojom::CredentialMediationRequirement,
password_manager::CredentialMediationRequirement> {
static password_manager::mojom::CredentialMediationRequirement ToMojom(
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client.cc b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
index f0e3081fb3a..5f96590a103 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
@@ -89,21 +89,21 @@ CredentialMediationRequirement GetCredentialMediationRequirementFromBlink(
}
blink::WebCredentialManagerError GetWebCredentialManagerErrorFromMojo(
- mojom::CredentialManagerError error) {
+ CredentialManagerError error) {
switch (error) {
- case mojom::CredentialManagerError::DISABLED:
+ case CredentialManagerError::DISABLED:
return blink::WebCredentialManagerError::
kWebCredentialManagerDisabledError;
- case mojom::CredentialManagerError::PENDINGREQUEST:
+ case CredentialManagerError::PENDINGREQUEST:
return blink::WebCredentialManagerError::
kWebCredentialManagerPendingRequestError;
- case mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
+ case CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
return blink::WebCredentialManagerError::
kWebCredentialManagerPasswordStoreUnavailableError;
- case mojom::CredentialManagerError::UNKNOWN:
+ case CredentialManagerError::UNKNOWN:
return blink::WebCredentialManagerError::
kWebCredentialManagerUnknownError;
- case mojom::CredentialManagerError::SUCCESS:
+ case CredentialManagerError::SUCCESS:
NOTREACHED();
break;
}
@@ -161,7 +161,7 @@ class RequestCallbacksWrapper {
void NotifySuccess(const CredentialInfo& info);
- void NotifyError(mojom::CredentialManagerError error);
+ void NotifyError(CredentialManagerError error);
private:
std::unique_ptr<blink::WebCredentialManagerClient::RequestCallbacks>
@@ -188,7 +188,7 @@ void RequestCallbacksWrapper::NotifySuccess(const CredentialInfo& info) {
}
}
-void RequestCallbacksWrapper::NotifyError(mojom::CredentialManagerError error) {
+void RequestCallbacksWrapper::NotifyError(CredentialManagerError error) {
if (callbacks_) {
callbacks_->OnError(GetWebCredentialManagerErrorFromMojo(error));
callbacks_.reset();
@@ -201,9 +201,9 @@ void RespondToNotificationCallback(
}
void RespondToRequestCallback(RequestCallbacksWrapper* callbacks_wrapper,
- mojom::CredentialManagerError error,
+ CredentialManagerError error,
const base::Optional<CredentialInfo>& info) {
- if (error == mojom::CredentialManagerError::SUCCESS) {
+ if (error == CredentialManagerError::SUCCESS) {
DCHECK(info);
callbacks_wrapper->NotifySuccess(*info);
} else {
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
index 85647cb9ea6..42ced0e7728 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
@@ -63,14 +63,13 @@ class FakeCredentialManager : public mojom::CredentialManager {
if (url == kTestCredentialPassword) {
CredentialInfo info;
info.type = CredentialType::CREDENTIAL_TYPE_PASSWORD;
- std::move(callback).Run(mojom::CredentialManagerError::SUCCESS, info);
+ std::move(callback).Run(CredentialManagerError::SUCCESS, info);
} else if (url == kTestCredentialEmpty) {
- std::move(callback).Run(mojom::CredentialManagerError::SUCCESS,
+ std::move(callback).Run(CredentialManagerError::SUCCESS,
CredentialInfo());
} else if (url == kTestCredentialReject) {
- std::move(callback).Run(
- mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
- base::nullopt);
+ std::move(callback).Run(CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
+ base::nullopt);
}
}
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index ddaef4ea34b..83880086d69 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -35,6 +35,8 @@ static_library("browser") {
"android_affiliation/test_affiliation_fetcher_factory.h",
"browser_save_password_progress_logger.cc",
"browser_save_password_progress_logger.h",
+ "credential_manager_impl.cc",
+ "credential_manager_impl.h",
"credential_manager_logger.cc",
"credential_manager_logger.h",
"credential_manager_password_form_manager.cc",
@@ -186,6 +188,7 @@ static_library("browser") {
"//google_apis",
"//net",
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql",
"//third_party/protobuf:protobuf_lite",
"//third_party/re2",
@@ -310,6 +313,7 @@ source_set("unit_tests") {
"android_affiliation/affiliation_utils_unittest.cc",
"android_affiliation/facet_manager_unittest.cc",
"browser_save_password_progress_logger_unittest.cc",
+ "credential_manager_impl_unittest.cc",
"credential_manager_logger_unittest.cc",
"credential_manager_password_form_manager_unittest.cc",
"export/csv_writer_unittest.cc",
@@ -383,6 +387,7 @@ source_set("unit_tests") {
"//components/ukm:test_support",
"//components/variations",
"//net:test_support",
+ "//services/metrics/public/cpp:ukm_builders",
"//sql:test_support",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index cf549c2f44a..0a0aeeabe7c 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -15,6 +15,9 @@ include_rules = [
]
specific_include_rules = {
+ "password_autofill_manager_unittest\.cc": [
+ "+components/ukm",
+ ],
"password_form_manager_unittest\.cc": [
"+components/ukm",
],
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index db62fe2ed5e..37563b8dee4 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -329,6 +329,7 @@ class AffiliatedMatchHelperTest : public testing::Test {
mock_affiliation_service_ = service.get();
password_store_ = new TestPasswordStore;
+ password_store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
match_helper_.reset(
new AffiliatedMatchHelper(password_store_.get(), std::move(service)));
@@ -338,6 +339,8 @@ class AffiliatedMatchHelperTest : public testing::Test {
match_helper_.reset();
password_store_->ShutdownOnUIThread();
password_store_ = nullptr;
+ // Clean up on the background thread.
+ RunUntilIdle();
}
base::MessageLoop message_loop_;
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
index 7ecac02c139..7878fea2278 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc
@@ -114,7 +114,7 @@ void AffiliationFetcher::StartRequest() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature either by stoping "
"syncing passwords to Google (via unchecking 'Passwords' in "
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl.cc b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
index e50d8372a89..17b0ba65fe0 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -1,87 +1,40 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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/password_manager/core/browser/credential_manager_impl.h"
-#include "components/password_manager/content/browser/credential_manager_impl.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/user_metrics.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.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/content_password_manager_driver_factory.h"
-#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
#include "components/password_manager/core/browser/credential_manager_logger.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_client.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "content/public/browser/web_contents.h"
namespace password_manager {
namespace {
-void RunMojoGetCallback(mojom::CredentialManager::GetCallback callback,
- const CredentialInfo& info) {
- std::move(callback).Run(mojom::CredentialManagerError::SUCCESS, info);
+void RunGetCallback(GetCallback callback, const CredentialInfo& info) {
+ std::move(callback).Run(CredentialManagerError::SUCCESS, info);
}
} // namespace
-// CredentialManagerImpl -------------------------------------------------
-
-CredentialManagerImpl::CredentialManagerImpl(content::WebContents* web_contents,
- PasswordManagerClient* client)
- : WebContentsObserver(web_contents),
- client_(client),
- binding_(this),
- weak_factory_(this) {
- DCHECK(web_contents);
+CredentialManagerImpl::CredentialManagerImpl(PasswordManagerClient* client)
+ : client_(client) {
auto_signin_enabled_.Init(prefs::kCredentialsEnableAutosignin,
client_->GetPrefs());
}
CredentialManagerImpl::~CredentialManagerImpl() {}
-void CredentialManagerImpl::BindRequest(
- mojom::CredentialManagerAssociatedRequest request) {
- DCHECK(!binding_.is_bound());
- binding_.Bind(std::move(request));
-
- // The browser side will close the message pipe on DidFinishNavigation before
- // the renderer side would be destroyed, and the renderer never explicitly
- // closes the pipe. So a connection error really means an error here, in which
- // case the renderer will try to reconnect when the next call to the API is
- // made. Make sure this implementation will no longer be bound to a broken
- // pipe once that happens, so the DCHECK above will succeed.
- binding_.set_connection_error_handler(base::Bind(
- &CredentialManagerImpl::DisconnectBinding, base::Unretained(this)));
-}
-
-bool CredentialManagerImpl::HasBinding() const {
- return binding_.is_bound();
-}
-
-void CredentialManagerImpl::DisconnectBinding() {
- binding_.Close();
-}
-
void CredentialManagerImpl::Store(const CredentialInfo& credential,
StoreCallback callback) {
DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential.type);
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogStoreCredential(web_contents()->GetLastCommittedURL(),
- credential.type);
+ .LogStoreCredential(GetLastCommittedURL(), credential.type);
}
// Send acknowledge response back.
@@ -93,7 +46,7 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential,
client_->NotifyStorePasswordCalled();
- GURL origin = web_contents()->GetLastCommittedURL().GetOrigin();
+ GURL origin = GetLastCommittedURL().GetOrigin();
std::unique_ptr<autofill::PasswordForm> form(
CreatePasswordFormFromCredentialInfo(credential, origin));
@@ -105,54 +58,16 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential,
auto form_fetcher = base::MakeUnique<FormFetcherImpl>(
PasswordStore::FormDigest(*observed_form), client_, false, false);
form_manager_ = base::MakeUnique<CredentialManagerPasswordFormManager>(
- client_, GetDriver(), *observed_form, std::move(form), this, nullptr,
+ client_, *observed_form, std::move(form), this, nullptr,
std::move(form_fetcher));
form_manager_->Init(nullptr);
}
-void CredentialManagerImpl::OnProvisionalSaveComplete() {
- DCHECK(form_manager_);
- DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
- const autofill::PasswordForm& form = form_manager_->pending_credentials();
-
- if (form_manager_->IsPendingCredentialsPublicSuffixMatch()) {
- // Having a credential with a PSL match implies there is no credential with
- // an exactly matching origin and username. In order to avoid showing a save
- // bubble to the user Save() is called directly.
- form_manager_->Save();
- return;
- }
-
- if (!form.federation_origin.unique()) {
- // If this is a federated credential, check it against the federated matches
- // produced by the PasswordFormManager. If a match is found, update it and
- // return.
- for (auto* match : form_manager_->form_fetcher()->GetFederatedMatches()) {
- if (match->username_value == form.username_value &&
- match->federation_origin.IsSameOriginWith(form.federation_origin)) {
- form_manager_->Update(*match);
- return;
- }
- }
- } else if (!form_manager_->IsNewLogin()) {
- // Otherwise, if this is not a new password credential, update the existing
- // credential without prompting the user. This will also update the
- // 'skip_zero_click' state, as we've gotten an explicit signal that the page
- // understands the credential management API and so can be trusted to notify
- // us when they sign the user out.
- form_manager_->Update(*form_manager_->preferred_match());
- return;
- }
-
- // Otherwise, this is a new form, so as the user if they'd like to save.
- client_->PromptUserToSaveOrUpdatePassword(std::move(form_manager_), false);
-}
-
void CredentialManagerImpl::PreventSilentAccess(
PreventSilentAccessCallback callback) {
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogPreventSilentAccess(web_contents()->GetLastCommittedURL());
+ .LogPreventSilentAccess(GetLastCommittedURL());
}
// Send acknowledge response back.
std::move(callback).Run();
@@ -178,15 +93,13 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
PasswordStore* store = GetPasswordStore();
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogRequestCredential(web_contents()->GetLastCommittedURL(), mediation,
- federations);
+ .LogRequestCredential(GetLastCommittedURL(), mediation, federations);
}
if (pending_request_ || !store) {
// Callback error.
std::move(callback).Run(
- pending_request_
- ? mojom::CredentialManagerError::PENDINGREQUEST
- : mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
+ pending_request_ ? CredentialManagerError::PENDINGREQUEST
+ : CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
base::nullopt);
LogCredentialManagerGetResult(metrics_util::CREDENTIAL_MANAGER_GET_REJECTED,
mediation);
@@ -197,8 +110,7 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
// page is being prerendered.
if (!client_->IsFillingEnabledForCurrentPage() ||
!client_->OnCredentialManagerUsed()) {
- std::move(callback).Run(mojom::CredentialManagerError::SUCCESS,
- CredentialInfo());
+ std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
LogCredentialManagerGetResult(metrics_util::CREDENTIAL_MANAGER_GET_NONE,
mediation);
return;
@@ -207,15 +119,14 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
if (mediation == CredentialMediationRequirement::kSilent &&
!IsZeroClickAllowed()) {
// Callback with empty credential info.
- std::move(callback).Run(mojom::CredentialManagerError::SUCCESS,
- CredentialInfo());
+ std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
LogCredentialManagerGetResult(
metrics_util::CREDENTIAL_MANAGER_GET_NONE_ZERO_CLICK_OFF, mediation);
return;
}
pending_request_.reset(new CredentialManagerPendingRequestTask(
- this, base::Bind(&RunMojoGetCallback, base::Passed(&callback)), mediation,
+ this, base::Bind(&RunGetCallback, base::Passed(&callback)), mediation,
include_passwords, federations));
// This will result in a callback to
// PendingRequestTask::OnGetPasswordStoreResults().
@@ -227,17 +138,17 @@ bool CredentialManagerImpl::IsZeroClickAllowed() const {
return *auto_signin_enabled_ && !client_->IsIncognito();
}
-GURL CredentialManagerImpl::GetOrigin() const {
- return web_contents()->GetLastCommittedURL().GetOrigin();
+PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
+ const {
+ PasswordStore::FormDigest digest = {autofill::PasswordForm::SCHEME_HTML,
+ std::string(),
+ GetLastCommittedURL().GetOrigin()};
+ digest.signon_realm = digest.origin.spec();
+ return digest;
}
-base::WeakPtr<PasswordManagerDriver> CredentialManagerImpl::GetDriver() {
- ContentPasswordManagerDriverFactory* driver_factory =
- ContentPasswordManagerDriverFactory::FromWebContents(web_contents());
- DCHECK(driver_factory);
- PasswordManagerDriver* driver =
- driver_factory->GetDriverForFrame(web_contents()->GetMainFrame());
- return driver->AsWeakPtr();
+GURL CredentialManagerImpl::GetOrigin() const {
+ return GetLastCommittedURL().GetOrigin();
}
void CredentialManagerImpl::SendCredential(
@@ -248,7 +159,7 @@ void CredentialManagerImpl::SendCredential(
if (password_manager_util::IsLoggingActive(client_)) {
CredentialManagerLogger(client_->GetLogManager())
- .LogSendCredential(web_contents()->GetLastCommittedURL(), info.type);
+ .LogSendCredential(GetLastCommittedURL(), info.type);
}
send_callback.Run(info);
pending_request_.reset();
@@ -298,13 +209,46 @@ void CredentialManagerImpl::DoneRequiringUserMediation() {
pending_require_user_mediation_.reset();
}
-PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
- const {
- PasswordStore::FormDigest digest = {
- autofill::PasswordForm::SCHEME_HTML, std::string(),
- web_contents()->GetLastCommittedURL().GetOrigin()};
- digest.signon_realm = digest.origin.spec();
- return digest;
+void CredentialManagerImpl::OnProvisionalSaveComplete() {
+ DCHECK(form_manager_);
+ DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
+ const autofill::PasswordForm& form = form_manager_->pending_credentials();
+
+ if (form_manager_->IsPendingCredentialsPublicSuffixMatch()) {
+ // Having a credential with a PSL match implies there is no credential with
+ // an exactly matching origin and username. In order to avoid showing a save
+ // bubble to the user Save() is called directly.
+ form_manager_->Save();
+ return;
+ }
+
+ if (!form.federation_origin.unique()) {
+ // If this is a federated credential, check it against the federated matches
+ // produced by the PasswordFormManager. If a match is found, update it and
+ // return.
+ for (auto* match : form_manager_->form_fetcher()->GetFederatedMatches()) {
+ if (match->username_value == form.username_value &&
+ match->federation_origin.IsSameOriginWith(form.federation_origin)) {
+ form_manager_->Update(*match);
+ return;
+ }
+ }
+ } else if (!form_manager_->IsNewLogin()) {
+ // Otherwise, if this is not a new password credential, update the existing
+ // credential without prompting the user. This will also update the
+ // 'skip_zero_click' state, as we've gotten an explicit signal that the page
+ // understands the credential management API and so can be trusted to notify
+ // us when they sign the user out.
+ form_manager_->Update(*form_manager_->preferred_match());
+ return;
+ }
+
+ // Otherwise, this is a new form, so as the user if they'd like to save.
+ client_->PromptUserToSaveOrUpdatePassword(std::move(form_manager_), false);
+}
+
+GURL CredentialManagerImpl::GetLastCommittedURL() const {
+ return client_->GetLastCommittedEntryURL();
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl.h b/chromium/components/password_manager/core/browser/credential_manager_impl.h
index 8a4bf3d66e5..24b45bdb099 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.h
@@ -1,67 +1,53 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_IMPL_H_
-#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
-#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
#include "components/password_manager/core/browser/credential_manager_pending_prevent_silent_access_task.h"
#include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
-#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/common/credential_manager_types.h"
#include "components/prefs/pref_member.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/platform/modules/credentialmanager/credential_manager.mojom.h"
-
-class GURL;
-
-namespace autofill {
-struct PasswordForm;
-}
-
-namespace content {
-class WebContents;
-}
namespace password_manager {
-class CredentialManagerPasswordFormManager;
-class PasswordManagerClient;
-class PasswordManagerDriver;
-class PasswordStore;
-struct CredentialInfo;
+using StoreCallback = base::OnceCallback<void()>;
+using PreventSilentAccessCallback = base::OnceCallback<void()>;
+using GetCallback =
+ base::OnceCallback<void(CredentialManagerError,
+ const base::Optional<CredentialInfo>&)>;
+
+// Class implementing Credential Manager methods Store, PreventSilentAccess
+// and Get in a platform independent way. Each method takes a callback as an
+// argument and runs the callback with the result. Platform specific code
+// and UI invocations are performed by PasswordManagerClient taken in
+// constructor.
class CredentialManagerImpl
- : public mojom::CredentialManager,
- public content::WebContentsObserver,
- public CredentialManagerPasswordFormManagerDelegate,
+ : public CredentialManagerPendingPreventSilentAccessTaskDelegate,
public CredentialManagerPendingRequestTaskDelegate,
- public CredentialManagerPendingPreventSilentAccessTaskDelegate {
+ public CredentialManagerPasswordFormManagerDelegate {
public:
- CredentialManagerImpl(content::WebContents* web_contents,
- PasswordManagerClient* client);
+ explicit CredentialManagerImpl(PasswordManagerClient* client);
~CredentialManagerImpl() override;
- void BindRequest(mojom::CredentialManagerAssociatedRequest request);
- bool HasBinding() const;
- void DisconnectBinding();
-
- // mojom::CredentialManager methods:
- void Store(const CredentialInfo& credential, StoreCallback callback) override;
- void PreventSilentAccess(PreventSilentAccessCallback callback) override;
+ void Store(const CredentialInfo& credential, StoreCallback callback);
+ void PreventSilentAccess(PreventSilentAccessCallback callback);
void Get(CredentialMediationRequirement mediation,
bool include_passwords,
const std::vector<GURL>& federations,
- GetCallback callback) override;
+ GetCallback callback);
// CredentialManagerPendingRequestTaskDelegate:
+ // Exposed publicly for testing.
bool IsZeroClickAllowed() const override;
+
+ // Returns FormDigest for the current URL.
+ // Exposed publicly for testing.
+ PasswordStore::FormDigest GetSynthesizedFormForOrigin() const;
+
+ private:
+ // CredentialManagerPendingRequestTaskDelegate:
GURL GetOrigin() const override;
void SendCredential(const SendCredentialCallback& send_callback,
const CredentialInfo& info) override;
@@ -70,42 +56,35 @@ class CredentialManagerImpl
const autofill::PasswordForm* form) override;
PasswordManagerClient* client() const override;
- // CredentialManagerPendingSignedOutTaskDelegate:
+ // CredentialManagerPendingPreventSilentAccessTaskDelegate:
PasswordStore* GetPasswordStore() override;
void DoneRequiringUserMediation() override;
// CredentialManagerPasswordFormManagerDelegate:
void OnProvisionalSaveComplete() override;
- // Returns FormDigest for the current URL.
- PasswordStore::FormDigest GetSynthesizedFormForOrigin() const;
-
- private:
- // Returns the driver for the current main frame.
- // Virtual for testing.
- virtual base::WeakPtr<PasswordManagerDriver> GetDriver();
+ GURL GetLastCommittedURL() const;
PasswordManagerClient* client_;
- std::unique_ptr<CredentialManagerPasswordFormManager> form_manager_;
// Set to false to disable automatic signing in.
BooleanPrefMember auto_signin_enabled_;
- // When 'OnRequestCredential' is called, it in turn calls out to the
- // PasswordStore; we push enough data into Pending*Task objects so that
- // they can properly respond to the request once the PasswordStore gives
- // us data.
+ // Used to store or update a credential. Calls OnProvisionalSaveComplete
+ // on this delegate.
+ std::unique_ptr<CredentialManagerPasswordFormManager> form_manager_;
+ // Retrieves credentials from the PasswordStore and calls
+ // SendCredential on this delegate. SendCredential then runs a callback
+ // which was passed as an argument to Get().
std::unique_ptr<CredentialManagerPendingRequestTask> pending_request_;
+ // Notifies the PasswordStore that the origin requires user mediation.
+ // Calls DoneRequiringUserMediation on this delegate.
std::unique_ptr<CredentialManagerPendingPreventSilentAccessTask>
pending_require_user_mediation_;
- mojo::AssociatedBinding<mojom::CredentialManager> binding_;
-
- base::WeakPtrFactory<CredentialManagerImpl> weak_factory_;
-
DISALLOW_COPY_AND_ASSIGN(CredentialManagerImpl);
};
} // namespace password_manager
-#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_IMPL_H_
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index af7f513ebf5..2460275fb8f 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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/password_manager/content/browser/credential_manager_impl.h"
+#include "components/password_manager/core/browser/credential_manager_impl.h"
#include <stdint.h>
@@ -12,37 +12,24 @@
#include <vector>
#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/test/scoped_task_environment.h"
#include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
-#include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/common/credential_manager_types.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/url_constants.h"
-using content::BrowserContext;
-using content::WebContents;
-
using testing::_;
using testing::ElementsAre;
using testing::Pointee;
@@ -72,7 +59,8 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
const GURL& origin,
const CredentialsCallback& callback));
- explicit MockPasswordManagerClient(PasswordStore* store) : store_(store) {
+ explicit MockPasswordManagerClient(PasswordStore* store)
+ : store_(store), password_manager_(this) {
prefs_.registry()->RegisterBooleanPref(prefs::kCredentialsEnableAutosignin,
true);
prefs_.registry()->RegisterBooleanPref(
@@ -97,6 +85,14 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
PrefService* GetPrefs() override { return &prefs_; }
+ const PasswordManager* GetPasswordManager() const override {
+ return &password_manager_;
+ }
+
+ const GURL& GetLastCommittedEntryURL() const override {
+ return last_committed_url_;
+ }
+
bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
const GURL& origin,
@@ -133,63 +129,29 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
first_run_seen);
}
+ void set_last_committed_url(GURL last_committed_url) {
+ last_committed_url_ = std::move(last_committed_url);
+ }
+
private:
TestingPrefServiceSimple prefs_;
PasswordStore* store_;
std::unique_ptr<PasswordFormManager> manager_;
+ PasswordManager password_manager_;
+ GURL last_committed_url_{kTestWebOrigin};
DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
};
-class TestCredentialManagerImpl : public CredentialManagerImpl {
- public:
- TestCredentialManagerImpl(content::WebContents* web_contents,
- PasswordManagerClient* client,
- PasswordManagerDriver* driver);
-
- private:
- base::WeakPtr<PasswordManagerDriver> GetDriver() override;
-
- base::WeakPtr<PasswordManagerDriver> driver_;
-};
-
-TestCredentialManagerImpl::TestCredentialManagerImpl(
- content::WebContents* web_contents,
- PasswordManagerClient* client,
- PasswordManagerDriver* driver)
- : CredentialManagerImpl(web_contents, client),
- driver_(driver->AsWeakPtr()) {}
-
-base::WeakPtr<PasswordManagerDriver> TestCredentialManagerImpl::GetDriver() {
- return driver_;
-}
-
-void RunAllPendingTasks() {
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-class SlightlyLessStubbyPasswordManagerDriver
- : public StubPasswordManagerDriver {
- public:
- explicit SlightlyLessStubbyPasswordManagerDriver(
- PasswordManagerClient* client)
- : password_manager_(client) {}
-
- PasswordManager* GetPasswordManager() override { return &password_manager_; }
-
- private:
- PasswordManager password_manager_;
-};
-
// Callbacks from CredentialManagerImpl methods
void RespondCallback(bool* called) {
*called = true;
}
void GetCredentialCallback(bool* called,
- mojom::CredentialManagerError* out_error,
+ CredentialManagerError* out_error,
base::Optional<CredentialInfo>* out_info,
- mojom::CredentialManagerError error,
+ CredentialManagerError error,
const base::Optional<CredentialInfo>& info) {
*called = true;
*out_error = error;
@@ -204,19 +166,16 @@ GURL HttpURLFromHttps(const GURL& https_url) {
} // namespace
-class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
+class CredentialManagerImplTest : public testing::Test {
public:
CredentialManagerImplTest() {}
void SetUp() override {
- content::RenderViewHostTestHarness::SetUp();
store_ = new TestPasswordStore;
+ store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
client_.reset(
new testing::NiceMock<MockPasswordManagerClient>(store_.get()));
- stub_driver_.reset(
- new SlightlyLessStubbyPasswordManagerDriver(client_.get()));
- cm_service_impl_.reset(new TestCredentialManagerImpl(
- web_contents(), client_.get(), stub_driver_.get()));
+ cm_service_impl_.reset(new CredentialManagerImpl(client_.get()));
ON_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
.WillByDefault(testing::Return(true));
ON_CALL(*client_, IsFillingEnabledForCurrentPage())
@@ -225,13 +184,11 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
.WillByDefault(testing::Return(true));
ON_CALL(*client_, IsIncognito()).WillByDefault(testing::Return(false));
- NavigateAndCommit(GURL("https://example.com/test.html"));
-
form_.username_value = base::ASCIIToUTF16("Username");
form_.display_name = base::ASCIIToUTF16("Display Name");
form_.icon_url = GURL("https://example.com/icon.png");
form_.password_value = base::ASCIIToUTF16("Password");
- form_.origin = web_contents()->GetLastCommittedURL().GetOrigin();
+ form_.origin = client_->GetLastCommittedEntryURL();
form_.signon_realm = form_.origin.GetOrigin().spec();
form_.scheme = autofill::PasswordForm::SCHEME_HTML;
form_.skip_zero_click = false;
@@ -286,14 +243,16 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
cm_service_impl_.reset();
store_->ShutdownOnUIThread();
- content::RenderViewHostTestHarness::TearDown();
+
+ // It's needed to cleanup the password store asynchronously.
+ RunAllPendingTasks();
}
void ExpectZeroClickSignInFailure(CredentialMediationRequirement mediation,
bool include_passwords,
const std::vector<GURL>& federations) {
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
.Times(testing::Exactly(0));
@@ -304,7 +263,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY, credential->type);
}
@@ -313,7 +272,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
const std::vector<GURL>& federations,
CredentialType type) {
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
.Times(testing::Exactly(0));
@@ -324,7 +283,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
EXPECT_EQ(type, credential->type);
}
@@ -333,7 +292,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
const std::vector<GURL>& federations,
CredentialType type) {
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
CallGet(mediation, include_passwords, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -341,32 +300,33 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
EXPECT_EQ(type, credential->type);
}
CredentialManagerImpl* cm_service_impl() { return cm_service_impl_.get(); }
// Helpers for testing CredentialManagerImpl methods.
- void CallStore(const CredentialInfo& info,
- CredentialManagerImpl::StoreCallback callback) {
+ void CallStore(const CredentialInfo& info, StoreCallback callback) {
cm_service_impl_->Store(info, std::move(callback));
}
- void CallPreventSilentAccess(
- CredentialManagerImpl::PreventSilentAccessCallback callback) {
+ void CallPreventSilentAccess(PreventSilentAccessCallback callback) {
cm_service_impl_->PreventSilentAccess(std::move(callback));
}
void CallGet(CredentialMediationRequirement mediation,
bool include_passwords,
const std::vector<GURL>& federations,
- CredentialManagerImpl::GetCallback callback) {
+ GetCallback callback) {
cm_service_impl_->Get(mediation, include_passwords, federations,
std::move(callback));
}
+ void RunAllPendingTasks() { scoped_task_environment_.RunUntilIdle(); }
+
protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
autofill::PasswordForm form_;
autofill::PasswordForm affiliated_form1_;
autofill::PasswordForm affiliated_form2_;
@@ -375,7 +335,6 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
autofill::PasswordForm cross_origin_form_;
scoped_refptr<TestPasswordStore> store_;
std::unique_ptr<testing::NiceMock<MockPasswordManagerClient>> client_;
- std::unique_ptr<SlightlyLessStubbyPasswordManagerDriver> stub_driver_;
std::unique_ptr<CredentialManagerImpl> cm_service_impl_;
};
@@ -675,7 +634,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
CallGet(CredentialMediationRequirement::kOptional, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -683,7 +642,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
// Verify that the update toggled the skip_zero_click flag.
TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
@@ -908,7 +867,7 @@ TEST_F(CredentialManagerImplTest,
_, _));
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
std::vector<GURL> federations;
federations.push_back(GURL("https://google.com/"));
@@ -944,7 +903,7 @@ TEST_F(CredentialManagerImplTest,
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
CallGet(CredentialMediationRequirement::kOptional, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -952,7 +911,7 @@ TEST_F(CredentialManagerImplTest,
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
}
TEST_F(
@@ -1232,14 +1191,14 @@ TEST_F(CredentialManagerImplTest,
// 1st request.
bool called_1 = false;
- mojom::CredentialManagerError error_1;
+ CredentialManagerError error_1;
base::Optional<CredentialInfo> credential_1;
CallGet(
CredentialMediationRequirement::kOptional, true, federations,
base::Bind(&GetCredentialCallback, &called_1, &error_1, &credential_1));
// 2nd request.
bool called_2 = false;
- mojom::CredentialManagerError error_2;
+ CredentialManagerError error_2;
base::Optional<CredentialInfo> credential_2;
CallGet(
CredentialMediationRequirement::kOptional, true, federations,
@@ -1254,12 +1213,12 @@ TEST_F(CredentialManagerImplTest,
// Check that the second request triggered a rejection.
EXPECT_TRUE(called_2);
- EXPECT_EQ(mojom::CredentialManagerError::PENDINGREQUEST, error_2);
+ EXPECT_EQ(CredentialManagerError::PENDINGREQUEST, error_2);
EXPECT_FALSE(credential_2);
// Check that the first request resolves.
EXPECT_TRUE(called_1);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error_1);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error_1);
EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential_1->type);
}
@@ -1297,7 +1256,7 @@ TEST_F(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
CallGet(CredentialMediationRequirement::kOptional, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -1333,7 +1292,7 @@ TEST_F(CredentialManagerImplTest, NoResetSkipZeroClickAfterPromptInIncognito) {
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
CallGet(CredentialMediationRequirement::kOptional, true, std::vector<GURL>(),
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -1490,9 +1449,9 @@ TEST_F(CredentialManagerImplTest, ZeroClickAfterMigratingHttpCredential) {
CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
-TEST_F(CredentialManagerImplTest, MigrateWithEmptyStore) {
+TEST_F(CredentialManagerImplTest, ZeroClickOnLocalhost) {
// HTTP scheme is valid for localhost. Nothing should crash.
- NavigateAndCommit(GURL("http://127.0.0.1:8000/"));
+ client_->set_last_committed_url(GURL("http://127.0.0.1:8000/"));
std::vector<GURL> federations;
ExpectZeroClickSignInFailure(CredentialMediationRequirement::kOptional, true,
@@ -1505,7 +1464,7 @@ TEST_F(CredentialManagerImplTest, MediationRequiredPreventsAutoSignIn) {
std::vector<GURL> federations;
bool called = false;
- mojom::CredentialManagerError error;
+ CredentialManagerError error;
base::Optional<CredentialInfo> credential;
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
@@ -1517,7 +1476,7 @@ TEST_F(CredentialManagerImplTest, MediationRequiredPreventsAutoSignIn) {
RunAllPendingTasks();
EXPECT_TRUE(called);
- EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+ EXPECT_EQ(CredentialManagerError::SUCCESS, error);
EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_PASSWORD, credential->type);
}
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
index ee3dd044892..6ba306b25a9 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
@@ -21,15 +21,14 @@ namespace password_manager {
CredentialManagerPasswordFormManager::CredentialManagerPasswordFormManager(
PasswordManagerClient* client,
- base::WeakPtr<PasswordManagerDriver> driver,
const PasswordForm& observed_form,
std::unique_ptr<autofill::PasswordForm> saved_form,
CredentialManagerPasswordFormManagerDelegate* delegate,
std::unique_ptr<FormSaver> form_saver,
std::unique_ptr<FormFetcher> form_fetcher)
- : PasswordFormManager(driver->GetPasswordManager(),
+ : PasswordFormManager(client->GetPasswordManager(),
client,
- driver,
+ nullptr,
observed_form,
(form_saver ? std::move(form_saver)
: base::MakeUnique<FormSaverImpl>(
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 6f052bbaed3..052e3a1b66e 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
@@ -16,7 +16,6 @@ struct PasswordForm;
namespace password_manager {
class PasswordManagerClient;
-class PasswordManagerDriver;
// A delegate that is notified when CredentialManagerPasswordFormManager
// finishes working with password forms.
@@ -40,7 +39,6 @@ class CredentialManagerPasswordFormManager : public PasswordFormManager {
// This class does not take ownership of |delegate|.
CredentialManagerPasswordFormManager(
PasswordManagerClient* client,
- base::WeakPtr<PasswordManagerDriver> driver,
const autofill::PasswordForm& observed_form,
std::unique_ptr<autofill::PasswordForm> saved_form,
CredentialManagerPasswordFormManagerDelegate* delegate,
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
index 585d88e00dd..0dbde46497f 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
@@ -14,7 +14,6 @@
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,7 +40,6 @@ class CredentialManagerPasswordFormManagerTest : public testing::Test {
base::MessageLoop message_loop_;
StubPasswordManagerClient client_;
- StubPasswordManagerDriver driver_;
DISALLOW_COPY_AND_ASSIGN(CredentialManagerPasswordFormManagerTest);
};
@@ -51,9 +49,9 @@ TEST_F(CredentialManagerPasswordFormManagerTest, AbortEarly) {
PasswordForm observed_form;
MockDelegate delegate;
auto form_manager = base::MakeUnique<CredentialManagerPasswordFormManager>(
- &client_, driver_.AsWeakPtr(), observed_form,
- base::MakeUnique<PasswordForm>(observed_form), &delegate,
- base::MakeUnique<StubFormSaver>(), base::MakeUnique<FakeFormFetcher>());
+ &client_, observed_form, base::MakeUnique<PasswordForm>(observed_form),
+ &delegate, base::MakeUnique<StubFormSaver>(),
+ base::MakeUnique<FakeFormFetcher>());
form_manager->Init(nullptr);
auto deleter = [&form_manager]() { form_manager.reset(); };
@@ -81,9 +79,9 @@ TEST_F(CredentialManagerPasswordFormManagerTest, GetCredentialSource) {
PasswordForm observed_form;
MockDelegate delegate;
auto form_manager = base::MakeUnique<CredentialManagerPasswordFormManager>(
- &client_, driver_.AsWeakPtr(), observed_form,
- base::MakeUnique<PasswordForm>(observed_form), &delegate,
- base::MakeUnique<StubFormSaver>(), base::MakeUnique<FakeFormFetcher>());
+ &client_, observed_form, base::MakeUnique<PasswordForm>(observed_form),
+ &delegate, base::MakeUnique<StubFormSaver>(),
+ base::MakeUnique<FakeFormFetcher>());
form_manager->Init(nullptr);
ASSERT_EQ(metrics_util::CredentialSourceType::kCredentialManagementAPI,
form_manager->GetCredentialSource());
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
index 07cf4325d65..45d41d15e9b 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -11,12 +11,11 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/mock_password_store.h"
@@ -195,7 +194,8 @@ class FormFetcherImplTest : public testing::Test {
: form_digest_(PasswordForm::SCHEME_HTML,
kTestHttpURL,
GURL(kTestHttpURL)) {
- mock_store_ = new MockPasswordStore();
+ mock_store_ = new MockPasswordStore;
+ mock_store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
client_.set_store(mock_store_.get());
form_fetcher_ = base::MakeUnique<FormFetcherImpl>(
@@ -214,7 +214,7 @@ class FormFetcherImplTest : public testing::Test {
#endif
EXPECT_CALL(*mock_store_, GetLogins(form_digest_, form_fetcher_.get()));
form_fetcher_->Fetch();
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(mock_store_.get());
}
@@ -267,7 +267,7 @@ class FormFetcherImplTest : public testing::Test {
ASSERT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
}
- base::MessageLoop message_loop_; // Used by mock_store_.
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
PasswordStore::FormDigest form_digest_;
std::unique_ptr<FormFetcherImpl> form_fetcher_;
MockConsumer consumer_;
@@ -455,7 +455,7 @@ TEST_F(FormFetcherImplTest, FetchStatistics) {
EXPECT_CALL(*mock_store_, GetSiteStatsImpl(stats.origin_domain))
.WillOnce(Return(db_stats));
form_fetcher_->Fetch();
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_THAT(form_fetcher_->GetInteractionsStats(),
UnorderedElementsAre(stats));
@@ -465,7 +465,7 @@ TEST_F(FormFetcherImplTest, DontFetchStatistics) {
EXPECT_CALL(*mock_store_, GetLogins(form_digest_, form_fetcher_.get()));
EXPECT_CALL(*mock_store_, GetSiteStatsImpl(_)).Times(0);
form_fetcher_->Fetch();
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
#endif
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 050fb761c87..7c4314017bb 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -26,7 +26,7 @@ class HashPasswordManagerTest : public testing::Test {
PrefRegistry::NO_REGISTRATION_FLAGS);
// Mock OSCrypt. There is a call to OSCrypt on initializling
// PasswordReuseDetector, so it should be mocked.
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
}
~HashPasswordManagerTest() override { OSCryptMocker::TearDown(); }
diff --git a/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc b/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc
index 4e04980cfbb..6fe6d987f3f 100644
--- a/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_data_cleaner_unittest.cc
@@ -7,9 +7,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -75,6 +74,7 @@ class HTTPDataCleanerTest : public testing::Test {
base::ThreadTaskRunnerHandle::Get())) {
prefs()->registry()->RegisterBooleanPref(prefs::kWasObsoleteHttpDataCleaned,
false);
+ store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
}
~HTTPDataCleanerTest() override { store_->ShutdownOnUIThread(); }
@@ -87,8 +87,10 @@ class HTTPDataCleanerTest : public testing::Test {
return request_context_;
}
+ void WaitUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
private:
- base::MessageLoop message_loop_; // Used by store_ and request_context_.
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<MockPasswordStore> store_;
std::unique_ptr<TestingPrefServiceSimple> prefs_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
@@ -130,7 +132,7 @@ TEST_F(HTTPDataCleanerTest, TestBlacklistDeletion) {
// completion.
CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
store(), prefs(), request_context());
- base::RunLoop().RunUntilIdle();
+ WaitUntilIdle();
// Verify and clear all expectations as well as the preference.
Mock::VerifyAndClearExpectations(store());
@@ -191,7 +193,7 @@ TEST_F(HTTPDataCleanerTest, TestAutofillableDeletion) {
// completion.
CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
store(), prefs(), request_context());
- base::RunLoop().RunUntilIdle();
+ WaitUntilIdle();
// Verify and clear all expectations as well as the preference.
Mock::VerifyAndClearExpectations(store());
@@ -229,7 +231,7 @@ TEST_F(HTTPDataCleanerTest, TestSiteStatsDeletion) {
// completion.
CleanObsoleteHttpDataForPasswordStoreAndPrefsForTesting(
store(), prefs(), request_context());
- base::RunLoop().RunUntilIdle();
+ WaitUntilIdle();
// Verify and clear all expectations as well as the preference.
Mock::VerifyAndClearExpectations(store());
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
index 6aa5d2b74fc..a21d5cb6987 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -5,9 +5,8 @@
#include "components/password_manager/core/browser/http_password_store_migrator.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -99,7 +98,9 @@ class HttpPasswordStoreMigratorTest : public testing::Test {
public:
HttpPasswordStoreMigratorTest()
: mock_store_(new testing::StrictMock<MockPasswordStore>),
- client_(mock_store_.get()) {}
+ client_(mock_store_.get()) {
+ mock_store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+ }
~HttpPasswordStoreMigratorTest() override {
mock_store_->ShutdownOnUIThread();
@@ -109,13 +110,15 @@ class HttpPasswordStoreMigratorTest : public testing::Test {
MockPasswordStore& store() { return *mock_store_; }
MockPasswordManagerClient& client() { return client_; }
+ void WaitForPasswordStore() { scoped_task_environment_.RunUntilIdle(); }
+
protected:
void TestEmptyStore(bool is_hsts);
void TestFullStore(bool is_hsts);
void TestMigratorDeletionByConsumer(bool is_hsts);
private:
- base::MessageLoop message_loop_; // Used by mock_store_.
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
MockConsumer consumer_;
scoped_refptr<MockPasswordStore> mock_store_;
MockPasswordManagerClient client_;
@@ -137,7 +140,7 @@ void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
EXPECT_CALL(consumer(), ProcessForms(std::vector<autofill::PasswordForm*>()));
migrator.OnGetPasswordStoreResults(
@@ -158,7 +161,7 @@ void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
PasswordForm form = CreateTestForm();
PasswordForm psl_form = CreateTestPSLForm();
@@ -203,7 +206,7 @@ void HttpPasswordStoreMigratorTest::TestMigratorDeletionByConsumer(
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
}
TEST_F(HttpPasswordStoreMigratorTest, EmptyStoreWithHSTS) {
diff --git a/chromium/components/password_manager/core/browser/login_database_ios.cc b/chromium/components/password_manager/core/browser/login_database_ios.cc
index 0019abb66a9..41bd8deaa49 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios.cc
@@ -48,7 +48,7 @@ LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
// item as long as it uniquely identifies it. We are arbitrarily choosing the
// |kSecAttrAccount| attribute for this purpose.
CFDictionarySetValue(attributes, kSecAttrAccount, item_ref);
- std::string plain_text_utf8 = UTF16ToUTF8(plain_text);
+ std::string plain_text_utf8 = base::UTF16ToUTF8(plain_text);
ScopedCFTypeRef<CFDataRef> data(
CFDataCreate(NULL, reinterpret_cast<const UInt8*>(plain_text_utf8.data()),
plain_text_utf8.size()));
diff --git a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
index 4ada9cfe88b..761a0e6067b 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -17,6 +17,7 @@
#include "testing/platform_test.h"
using base::ScopedCFTypeRef;
+using base::UTF16ToUTF8;
using autofill::PasswordForm;
namespace password_manager {
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 b6a1011b182..c994b41409d 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -142,7 +142,7 @@ class LoginDatabaseTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase");
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
db_.reset(new LoginDatabase(file_));
ASSERT_TRUE(db_->Init());
@@ -794,34 +794,39 @@ TEST_F(LoginDatabaseTest,
GetLoginsForSameOrganizationName_OnlyWebHTTPFormsAreConsidered) {
static constexpr const struct {
const PasswordFormData form_data;
+ bool use_federated_login;
const char* other_queried_signon_realm;
bool expected_matches_itself;
bool expected_matches_other_realm;
} kTestCases[] = {
{{PasswordForm::SCHEME_HTML, "https://example.com/",
"https://example.com/origin", "", L"", L"", L"", L"u", L"p", false, 1},
+ false,
nullptr,
true,
true},
{{PasswordForm::SCHEME_BASIC, "http://example.com/realm",
"http://example.com/", "", L"", L"", L"", L"u", L"p", false, 1},
+ false,
nullptr,
false,
false},
{{PasswordForm::SCHEME_OTHER, "ftp://example.com/realm",
"ftp://example.com/", "", L"", L"", L"", L"u", L"p", false, 1},
+ false,
"http://example.com/realm",
false,
false},
{{PasswordForm::SCHEME_HTML,
"federation://example.com/accounts.google.com",
- "https://example.com/orgin", "", L"", L"", L"", L"u",
- kTestingFederatedLoginMarker, false, 1},
+ "https://example.com/orgin", "", L"", L"", L"", L"u", L"", false, 1},
+ true,
"http://example.com/",
false,
false},
{{PasswordForm::SCHEME_HTML, "android://hash@example.com/",
"android://hash@example.com/", "", L"", L"", L"", L"u", L"p", false, 1},
+ false,
"http://example.com/",
false,
false},
@@ -830,8 +835,8 @@ TEST_F(LoginDatabaseTest,
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.form_data.signon_realm);
- std::unique_ptr<PasswordForm> form =
- CreatePasswordFormFromDataForTesting(test_case.form_data);
+ std::unique_ptr<PasswordForm> form = FillPasswordFormWithData(
+ test_case.form_data, test_case.use_federated_login);
ASSERT_EQ(AddChangeForForm(*form), db().AddLogin(*form));
std::vector<std::unique_ptr<PasswordForm>> same_organization_forms;
@@ -918,7 +923,7 @@ TEST_F(LoginDatabaseTest, GetLoginsForSameOrganizationName_DetailsOfMatching) {
SCOPED_TRACE(test_case.saved_signon_realm);
SCOPED_TRACE(test_case.queried_signon_realm);
- std::unique_ptr<PasswordForm> form = CreatePasswordFormFromDataForTesting(
+ std::unique_ptr<PasswordForm> form = FillPasswordFormWithData(
{PasswordForm::SCHEME_HTML, test_case.saved_signon_realm,
test_case.saved_signon_realm, "", L"", L"", L"", L"u", L"p", true, 1});
std::vector<std::unique_ptr<PasswordForm>> result;
@@ -1697,7 +1702,7 @@ class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
.AppendASCII("data")
.AppendASCII("password_manager");
database_path_ = temp_dir_.GetPath().AppendASCII("test.db");
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
}
void TearDown() override { OSCryptMocker::TearDown(); }
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.cc b/chromium/components/password_manager/core/browser/mock_password_store.cc
index 7992d2b0e16..c83e0dc44bd 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.cc
+++ b/chromium/components/password_manager/core/browser/mock_password_store.cc
@@ -9,11 +9,16 @@
namespace password_manager {
-MockPasswordStore::MockPasswordStore()
- : PasswordStore(base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get()) {}
+MockPasswordStore::MockPasswordStore() = default;
-MockPasswordStore::~MockPasswordStore() {
+MockPasswordStore::~MockPasswordStore() = default;
+
+scoped_refptr<base::SequencedTaskRunner>
+MockPasswordStore::CreateBackgroundTaskRunner() const {
+ return base::SequencedTaskRunnerHandle::Get();
}
+void MockPasswordStore::InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare) {}
+
} // namespace password_manager
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 7c67c9bd263..18a9cc62bfb 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -13,18 +13,12 @@
#include "components/password_manager/core/browser/statistics_table.h"
#include "testing/gmock/include/gmock/gmock.h"
-class PrefService;
-
namespace password_manager {
class MockPasswordStore : public PasswordStore {
public:
MockPasswordStore();
- bool Init(const syncer::SyncableService::StartSyncFlare& flare,
- PrefService* prefs) override {
- return true;
- };
MOCK_METHOD1(RemoveLogin, void(const autofill::PasswordForm&));
MOCK_METHOD2(GetLogins,
void(const PasswordStore::FormDigest&, PasswordStoreConsumer*));
@@ -91,7 +85,14 @@ class MockPasswordStore : public PasswordStore {
PasswordStoreSync* GetSyncInterface() { return this; }
protected:
- virtual ~MockPasswordStore();
+ ~MockPasswordStore() override;
+
+ private:
+ // PasswordStore:
+ scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
+ const override;
+ void InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare) override;
};
} // namespace password_manager
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 7ffed22d491..152129786cd 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
@@ -17,6 +17,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/popup_item_ids.h"
@@ -25,12 +26,19 @@
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
namespace password_manager {
namespace {
@@ -128,6 +136,17 @@ void GetSuggestions(const autofill::PasswordFormFillData& fill_data,
}
}
+bool ShouldShowManualFallbackForPreLollipop(syncer::SyncService* sync_service) {
+#if defined(OS_ANDROID)
+ return ((base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_LOLLIPOP) ||
+ (password_manager_util::GetPasswordSyncState(sync_service) ==
+ SYNCING_NORMAL_ENCRYPTION));
+#else
+ return true;
+#endif
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -135,9 +154,12 @@ void GetSuggestions(const autofill::PasswordFormFillData& fill_data,
PasswordAutofillManager::PasswordAutofillManager(
PasswordManagerDriver* password_manager_driver,
- autofill::AutofillClient* autofill_client)
- : password_manager_driver_(password_manager_driver),
+ autofill::AutofillClient* autofill_client,
+ PasswordManagerClient* password_client)
+ : form_data_key_(-1),
+ password_manager_driver_(password_manager_driver),
autofill_client_(autofill_client),
+ password_client_(password_client),
weak_ptr_factory_(this) {}
PasswordAutofillManager::~PasswordAutofillManager() {
@@ -184,6 +206,18 @@ void PasswordAutofillManager::OnAddPasswordFormMapping(
login_to_password_info_[key] = fill_data;
}
+autofill::Suggestion PasswordAutofillManager::CreateFormNotSecureWarning() {
+ autofill::Suggestion http_warning_suggestion(
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE),
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
+ "httpWarning", autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE);
+ if (!did_show_form_not_secure_warning_) {
+ did_show_form_not_secure_warning_ = true;
+ metrics_util::LogShowedFormNotSecureWarningOnCurrentNavigation();
+ }
+ return http_warning_suggestion;
+}
+
void PasswordAutofillManager::OnShowPasswordSuggestions(
int key,
base::i18n::TextDirection text_direction,
@@ -246,6 +280,30 @@ void PasswordAutofillManager::OnShowPasswordSuggestions(
}
}
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kEnableManualFallbacksFilling) &&
+ (options & autofill::IS_PASSWORD_FIELD) && password_client_ &&
+ password_client_->IsFillingFallbackEnabledForCurrentPage()) {
+#if !defined(OS_ANDROID)
+ suggestions.push_back(autofill::Suggestion());
+ suggestions.back().frontend_id = autofill::POPUP_ITEM_ID_SEPARATOR;
+#endif
+
+ if (ShouldShowManualFallbackForPreLollipop(
+ autofill_client_->GetSyncService())) {
+ autofill::Suggestion all_saved_passwords(
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK),
+ std::string(), std::string(),
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
+ suggestions.push_back(all_saved_passwords);
+
+ show_all_saved_passwords_shown_context_ =
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD;
+ metrics_util::LogContextOfShowAllSavedPasswordsShown(
+ show_all_saved_passwords_shown_context_);
+ }
+ }
+
autofill_client_->ShowAutofillPopup(bounds,
text_direction,
suggestions,
@@ -267,19 +325,40 @@ void PasswordAutofillManager::OnShowNotSecureWarning(
return;
std::vector<autofill::Suggestion> suggestions;
- autofill::Suggestion http_warning_suggestion(
- l10n_util::GetStringUTF8(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE),
- l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
- "httpWarning", autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE);
+ autofill::Suggestion http_warning_suggestion = CreateFormNotSecureWarning();
suggestions.insert(suggestions.begin(), http_warning_suggestion);
autofill_client_->ShowAutofillPopup(bounds, text_direction, suggestions,
weak_ptr_factory_.GetWeakPtr());
+}
- if (did_show_form_not_secure_warning_)
+void PasswordAutofillManager::OnShowManualFallbackSuggestion(
+ base::i18n::TextDirection text_direction,
+ const gfx::RectF& bounds) {
+ // https://crbug.com/699197
+ // CroS SimpleWebviewDialog used for the captive portal dialog is a special
+ // case because it doesn't instantiate many helper classes. |autofill_client_|
+ // is NULL too.
+ if (!autofill_client_ || !ShouldShowManualFallbackForPreLollipop(
+ autofill_client_->GetSyncService()))
return;
- did_show_form_not_secure_warning_ = true;
- metrics_util::LogShowedFormNotSecureWarningOnCurrentNavigation();
+ if (!password_client_ ||
+ !password_client_->IsFillingFallbackEnabledForCurrentPage())
+ return;
+ std::vector<autofill::Suggestion> suggestions;
+ autofill::Suggestion all_saved_passwords(
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK),
+ std::string(), std::string(),
+ autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
+ suggestions.push_back(all_saved_passwords);
+
+ show_all_saved_passwords_shown_context_ =
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK;
+ metrics_util::LogContextOfShowAllSavedPasswordsShown(
+ show_all_saved_passwords_shown_context_);
+
+ autofill_client_->ShowAutofillPopup(bounds, text_direction, suggestions,
+ weak_ptr_factory_.GetWeakPtr());
}
void PasswordAutofillManager::DidNavigateMainFrame() {
@@ -308,7 +387,8 @@ void PasswordAutofillManager::OnPopupHidden() {
void PasswordAutofillManager::DidSelectSuggestion(const base::string16& value,
int identifier) {
ClearPreviewedForm();
- if (identifier == autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE)
+ if (identifier == autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE ||
+ identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY)
return;
bool success =
PreviewSuggestion(form_data_key_, GetUsernameFromSuggestion(value));
@@ -318,14 +398,40 @@ void PasswordAutofillManager::DidSelectSuggestion(const base::string16& value,
void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
int identifier,
int position) {
- if (identifier == autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
- metrics_util::LogShowedHttpNotSecureExplanation();
- autofill_client_->ShowHttpNotSecureExplanation();
- } else {
+ autofill_client_->ExecuteCommand(identifier);
+ if (identifier != autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE &&
+ identifier != autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
bool success =
FillSuggestion(form_data_key_, GetUsernameFromSuggestion(value));
DCHECK(success);
}
+
+ if (identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
+ DCHECK_NE(show_all_saved_passwords_shown_context_,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_NONE);
+
+ metrics_util::LogContextOfShowAllSavedPasswordsAccepted(
+ show_all_saved_passwords_shown_context_);
+
+ if (password_client_) {
+ using UserAction =
+ password_manager::PasswordManagerMetricsRecorder::PageLevelUserAction;
+ switch (show_all_saved_passwords_shown_context_) {
+ case metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD:
+ password_client_->GetMetricsRecorder().RecordPageLevelUserAction(
+ UserAction::kShowAllPasswordsWhileSomeAreSuggested);
+ break;
+ case metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK:
+ password_client_->GetMetricsRecorder().RecordPageLevelUserAction(
+ UserAction::kShowAllPasswordsWhileNoneAreSuggested);
+ break;
+ case metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_NONE:
+ case metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT:
+ NOTREACHED();
+ }
+ }
+ }
+
autofill_client_->HideAutofillPopup();
}
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h
index 737bc926e3a..1b05f882038 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.h
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h
@@ -12,6 +12,7 @@
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_popup_delegate.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
namespace gfx {
class RectF;
@@ -19,13 +20,15 @@ class RectF;
namespace password_manager {
+class PasswordManagerClient;
class PasswordManagerDriver;
// This class is responsible for filling password forms.
class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
public:
PasswordAutofillManager(PasswordManagerDriver* password_manager_driver,
- autofill::AutofillClient* autofill_client);
+ autofill::AutofillClient* autofill_client,
+ PasswordManagerClient* password_client);
virtual ~PasswordAutofillManager();
// AutofillPopupDelegate implementation.
@@ -65,6 +68,11 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
void OnShowNotSecureWarning(base::i18n::TextDirection text_direction,
const gfx::RectF& bounds);
+ // Handles a request from the renderer to show a popup with an option to check
+ // user's saved passwords, used when a password field is not autofilled.
+ void OnShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
+ const gfx::RectF& bounds);
+
// Called when main frame navigates. Not called for in-page navigations.
void DidNavigateMainFrame();
@@ -104,6 +112,10 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
// Finds login information for a |node| that was previously filled.
bool FindLoginInfo(int key, autofill::PasswordFormFillData* found_password);
+ // Creates suggestion and records the metrics for the "Form not secure
+ // warning".
+ autofill::Suggestion CreateFormNotSecureWarning();
+
// The logins we have filled so far with their associated info.
LoginToPasswordInfoMap login_to_password_info_;
@@ -118,8 +130,15 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
// navigation. Used for metrics.
bool did_show_form_not_secure_warning_ = false;
+ // Context in which the "Show all saved passwords" fallback was shown.
+ metrics_util::ShowAllSavedPasswordsContext
+ show_all_saved_passwords_shown_context_ =
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_NONE;
+
autofill::AutofillClient* autofill_client_; // weak
+ PasswordManagerClient* password_client_;
+
base::WeakPtrFactory<PasswordAutofillManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillManager);
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 80926358ce2..9def6d19e26 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
@@ -12,6 +12,7 @@
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/user_action_tester.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/popup_item_ids.h"
#include "components/autofill/core/browser/suggestion_test_helpers.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -20,15 +21,23 @@
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.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/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
+#include "components/ukm/test_ukm_recorder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect_f.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
// The name of the username/password element in the form.
const char kUsernameName[] = "username";
const char kInvalidUsername[] = "no-username";
@@ -51,20 +60,28 @@ namespace password_manager {
namespace {
+constexpr char kMainFrameUrl[] = "https://example.com/";
+
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
public:
MOCK_METHOD2(FillSuggestion,
void(const base::string16&, const base::string16&));
MOCK_METHOD2(PreviewSuggestion,
void(const base::string16&, const base::string16&));
+ MOCK_METHOD0(GetPasswordManager, PasswordManager*());
};
class TestPasswordManagerClient : public StubPasswordManagerClient {
public:
+ TestPasswordManagerClient() : main_frame_url_(kMainFrameUrl) {}
+ ~TestPasswordManagerClient() override = default;
+
MockPasswordManagerDriver* mock_driver() { return &driver_; }
+ const GURL& GetMainFrameURL() const override { return main_frame_url_; }
private:
MockPasswordManagerDriver driver_;
+ GURL main_frame_url_;
};
class MockAutofillClient : public autofill::TestAutofillClient {
@@ -75,9 +92,18 @@ class MockAutofillClient : public autofill::TestAutofillClient {
const std::vector<Suggestion>& suggestions,
base::WeakPtr<autofill::AutofillPopupDelegate> delegate));
MOCK_METHOD0(HideAutofillPopup, void());
- MOCK_METHOD0(ShowHttpNotSecureExplanation, void());
+ MOCK_METHOD1(ExecuteCommand, void(int));
};
+bool IsPreLollipopAndroid() {
+#if defined(OS_ANDROID)
+ return (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_LOLLIPOP);
+#else
+ return false;
+#endif
+}
+
} // namespace
class PasswordAutofillManagerTest : public testing::Test {
@@ -103,8 +129,8 @@ class PasswordAutofillManagerTest : public testing::Test {
void InitializePasswordAutofillManager(
TestPasswordManagerClient* client,
autofill::AutofillClient* autofill_client) {
- password_autofill_manager_.reset(
- new PasswordAutofillManager(client->mock_driver(), autofill_client));
+ password_autofill_manager_.reset(new PasswordAutofillManager(
+ client->mock_driver(), autofill_client, client));
password_autofill_manager_->OnAddPasswordFormMapping(fill_data_id_,
fill_data_);
}
@@ -118,6 +144,22 @@ class PasswordAutofillManagerTest : public testing::Test {
security_state::kHttpFormWarningFeature);
}
+ void SetManualFallbacksForFilling(bool enabled) {
+ if (enabled) {
+ scoped_feature_list_.InitAndEnableFeature(
+ password_manager::features::kEnableManualFallbacksFilling);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ password_manager::features::kEnableManualFallbacksFilling);
+ }
+ }
+
+ static bool IsManualFallbackForFillingEnabled() {
+ return base::FeatureList::IsEnabled(
+ password_manager::features::kEnableManualFallbacksFilling) &&
+ !IsPreLollipopAndroid();
+ }
+
std::unique_ptr<PasswordAutofillManager> password_autofill_manager_;
base::string16 test_username_;
@@ -203,16 +245,22 @@ TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
EXPECT_CALL(*client->mock_driver(),
FillSuggestion(test_username_, test_password_));
- // The enums must be cast to ints to prevent compile errors on linux_rel.
- auto suggestion_ids_matcher =
- is_suggestion_on_password_field
- ? SuggestionVectorIdsAre(
- testing::ElementsAre(autofill::POPUP_ITEM_ID_TITLE,
- autofill::POPUP_ITEM_ID_PASSWORD_ENTRY))
- : SuggestionVectorIdsAre(
- testing::ElementsAre(autofill::POPUP_ITEM_ID_USERNAME_ENTRY));
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(_, _, suggestion_ids_matcher, _));
+ std::vector<autofill::PopupItemId> ids = {
+ autofill::POPUP_ITEM_ID_USERNAME_ENTRY};
+ if (is_suggestion_on_password_field) {
+ ids = {autofill::POPUP_ITEM_ID_TITLE,
+ autofill::POPUP_ITEM_ID_PASSWORD_ENTRY};
+ if (IsManualFallbackForFillingEnabled()) {
+#if !defined(OS_ANDROID)
+ ids.push_back(autofill::POPUP_ITEM_ID_SEPARATOR);
+#endif
+ ids.push_back(autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
+ }
+ }
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ _, _, SuggestionVectorIdsAre(testing::ElementsAreArray(ids)), _));
int show_suggestion_options =
is_suggestion_on_password_field ? autofill::IS_PASSWORD_FIELD : 0;
@@ -373,13 +421,23 @@ TEST_F(PasswordAutofillManagerTest, FillSuggestionPasswordField) {
// field is a password field.
base::string16 title = l10n_util::GetStringUTF16(
IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- title,
- test_username_)),
- _));
+ std::vector<base::string16> elements = {title, test_username_};
+ if (IsManualFallbackForFillingEnabled()) {
+ elements = {
+ title,
+ test_username_,
+#if !defined(OS_ANDROID)
+ base::string16(),
+#endif
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
+ };
+ }
+
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
@@ -633,7 +691,9 @@ TEST_F(PasswordAutofillManagerTest, ShowStandaloneNotSecureWarning) {
// Accepting the warning message should trigger a call to open an explanation
// of the message and hide the popup.
- EXPECT_CALL(*autofill_client, ShowHttpNotSecureExplanation());
+ EXPECT_CALL(
+ *autofill_client,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
EXPECT_CALL(*autofill_client, HideAutofillPopup());
password_autofill_manager_->DidAcceptSuggestion(
base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
@@ -664,12 +724,22 @@ TEST_F(PasswordAutofillManagerTest, NonSecurePasswordFieldHttpWarningMessage) {
base::string16 title =
l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
+ base::string16 show_all_saved_row_text =
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK);
+ std::vector<base::string16> elements = {title, test_username_};
+ if (IsManualFallbackForFillingEnabled()) {
+#if !defined(OS_ANDROID)
+ elements.push_back(base::string16());
+#endif
+ elements.push_back(show_all_saved_row_text);
+ }
+
// Http warning message won't show with switch flag off.
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAre(
- title, test_username_)),
- _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
@@ -679,22 +749,35 @@ TEST_F(PasswordAutofillManagerTest, NonSecurePasswordFieldHttpWarningMessage) {
// Http warning message shows for non-secure context and switch flag on, so
// there are 3 suggestions (+ 1 separator on desktop) in total, and the
// message comes first among suggestions.
- auto elements = testing::ElementsAre(warning_message,
+ elements = {
+ warning_message,
#if !defined(OS_ANDROID)
- base::string16(),
+ base::string16(),
#endif
- title, test_username_);
+ title,
+ test_username_
+ };
+ if (IsManualFallbackForFillingEnabled()) {
+#if !defined(OS_ANDROID)
+ elements.push_back(base::string16());
+#endif
+ elements.push_back(show_all_saved_row_text);
+ }
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(elements), _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
// Accepting the warning message should trigger a call to open an explanation
// of the message and hide the popup.
- EXPECT_CALL(*autofill_client, ShowHttpNotSecureExplanation());
+ EXPECT_CALL(
+ *autofill_client,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
EXPECT_CALL(*autofill_client, HideAutofillPopup());
password_autofill_manager_->DidAcceptSuggestion(
base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
@@ -750,7 +833,9 @@ TEST_F(PasswordAutofillManagerTest, NonSecureUsernameFieldHttpWarningMessage) {
// Accepting the warning message should trigger a call to open an explanation
// of the message and hide the popup.
- EXPECT_CALL(*autofill_client, ShowHttpNotSecureExplanation());
+ EXPECT_CALL(
+ *autofill_client,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
EXPECT_CALL(*autofill_client, HideAutofillPopup());
password_autofill_manager_->DidAcceptSuggestion(
base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
@@ -776,12 +861,23 @@ TEST_F(PasswordAutofillManagerTest, SecurePasswordFieldHttpWarningMessage) {
base::string16 title =
l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
+ std::vector<base::string16> elements = {title, test_username_};
+ if (IsManualFallbackForFillingEnabled()) {
+ elements = {
+ title,
+ test_username_,
+#if !defined(OS_ANDROID)
+ base::string16(),
+#endif
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
+ };
+ }
// Http warning message won't show with switch flag off.
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAre(
- title, test_username_)),
- _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
@@ -790,31 +886,16 @@ TEST_F(PasswordAutofillManagerTest, SecurePasswordFieldHttpWarningMessage) {
// Http warning message won't show for secure context, even with switch flag
// on.
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAre(
- title, test_username_)),
- _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
}
-// Test that a user action is logged when the user selects the Form-Not-Secure
-// warning to receive more information about the warning.
-TEST_F(PasswordAutofillManagerTest, FormNotSecureUserAction) {
- std::unique_ptr<TestPasswordManagerClient> client(
- new TestPasswordManagerClient);
- std::unique_ptr<MockAutofillClient> autofill_client(new MockAutofillClient);
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
- base::UserActionTester user_action_tester;
- password_autofill_manager_->DidAcceptSuggestion(
- test_username_, autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
- 0);
- EXPECT_EQ(1, user_action_tester.GetActionCount(
- "PasswordManager_ShowedHttpNotSecureExplanation"));
-}
-
// Tests that the Form-Not-Secure warning is recorded in UMA, at most once per
// navigation.
TEST_F(PasswordAutofillManagerTest, ShowedFormNotSecureHistogram) {
@@ -830,6 +911,7 @@ TEST_F(PasswordAutofillManagerTest, ShowedFormNotSecureHistogram) {
// Test that the standalone warning (with no autofill suggestions) records the
// histogram.
gfx::RectF element_bounds;
+ EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
password_autofill_manager_->OnShowNotSecureWarning(base::i18n::RIGHT_TO_LEFT,
element_bounds);
histograms.ExpectUniqueSample(kHistogram, true, 1);
@@ -847,15 +929,279 @@ TEST_F(PasswordAutofillManagerTest, ShowedFormNotSecureHistogram) {
data.origin = GURL("http://foo.test");
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
+ EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
autofill::IS_PASSWORD_FIELD, element_bounds);
histograms.ExpectUniqueSample(kHistogram, true, 2);
// The histogram should not be recorded again on the same navigation.
+ EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
password_autofill_manager_->OnShowNotSecureWarning(base::i18n::RIGHT_TO_LEFT,
element_bounds);
histograms.ExpectUniqueSample(kHistogram, true, 2);
}
+// Tests that the "Show all passwords" suggestion isn't shown along with
+// "Use password for" in the popup when the feature which controls its
+// appearance is disabled.
+TEST_F(PasswordAutofillManagerTest,
+ NotShowAllPasswordsOptionOnPasswordFieldWhenFeatureDisabled) {
+ auto client = base::MakeUnique<TestPasswordManagerClient>();
+ auto autofill_client = base::MakeUnique<MockAutofillClient>();
+ InitializePasswordAutofillManager(client.get(), autofill_client.get());
+
+ gfx::RectF element_bounds;
+ autofill::PasswordFormFillData data;
+ data.username_field.value = test_username_;
+ data.password_field.value = test_password_;
+ data.origin = GURL("https://foo.test");
+
+ int dummy_key = 0;
+ password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
+
+ // String "Use password for:" shown when displaying suggestions matching a
+ // username and specifying that the field is a password field.
+ base::string16 title =
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
+
+ SetManualFallbacksForFilling(false);
+
+ // No "Show all passwords row" when feature is disabled.
+ EXPECT_CALL(*autofill_client,
+ ShowAutofillPopup(element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAre(
+ title, test_username_)),
+ _));
+ password_autofill_manager_->OnShowPasswordSuggestions(
+ dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
+ autofill::IS_PASSWORD_FIELD, element_bounds);
+}
+
+// Tests that the "Show all passwords" suggestion is shown along with
+// "Use password for" in the popup when the feature which controls its
+// appearance is enabled.
+TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnPasswordField) {
+ const char kShownContextHistogram[] =
+ "PasswordManager.ShowAllSavedPasswordsShownContext";
+ const char kAcceptedContextHistogram[] =
+ "PasswordManager.ShowAllSavedPasswordsAcceptedContext";
+ base::HistogramTester histograms;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+
+ auto client = base::MakeUnique<TestPasswordManagerClient>();
+ auto autofill_client = base::MakeUnique<MockAutofillClient>();
+ auto manager =
+ base::MakeUnique<password_manager::PasswordManager>(client.get());
+ InitializePasswordAutofillManager(client.get(), autofill_client.get());
+
+ ON_CALL(*(client->mock_driver()), GetPasswordManager())
+ .WillByDefault(testing::Return(manager.get()));
+
+ gfx::RectF element_bounds;
+ autofill::PasswordFormFillData data;
+ data.username_field.value = test_username_;
+ data.password_field.value = test_password_;
+ data.origin = GURL("https://foo.test");
+
+ int dummy_key = 0;
+ password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
+
+ // String "Use password for:" shown when displaying suggestions matching a
+ // username and specifying that the field is a password field.
+ base::string16 title =
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
+
+ SetManualFallbacksForFilling(true);
+
+ std::vector<base::string16> elements = {title, test_username_};
+ if (!IsPreLollipopAndroid()) {
+ elements = {
+ title,
+ test_username_,
+#if !defined(OS_ANDROID)
+ base::string16(),
+#endif
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
+ };
+ }
+
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
+
+ password_autofill_manager_->OnShowPasswordSuggestions(
+ dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
+ autofill::IS_PASSWORD_FIELD, element_bounds);
+
+ if (!IsPreLollipopAndroid()) {
+ // Expect a sample only in the shown histogram.
+ histograms.ExpectUniqueSample(
+ kShownContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD, 1);
+ // Clicking at the "Show all passwords row" should trigger a call to open
+ // the Password Manager settings page and hide the popup.
+ EXPECT_CALL(
+ *autofill_client,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
+ EXPECT_CALL(*autofill_client, HideAutofillPopup());
+ password_autofill_manager_->DidAcceptSuggestion(
+ base::string16(), autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY, 0);
+ // Expect a sample in both the shown and accepted histogram.
+ histograms.ExpectUniqueSample(
+ kShownContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD, 1);
+ histograms.ExpectUniqueSample(
+ kAcceptedContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD, 1);
+ // Trigger UKM reporting, which happens at destruction time.
+ manager.reset();
+ autofill_client.reset();
+ client.reset();
+ const ukm::UkmSource* source =
+ test_ukm_recorder.GetSourceForUrl(kMainFrameUrl);
+ ASSERT_TRUE(source);
+
+ test_ukm_recorder.ExpectMetric(
+ *source, "PageWithPassword", password_manager::kUkmPageLevelUserAction,
+ static_cast<int64_t>(
+ password_manager::PasswordManagerMetricsRecorder::
+ PageLevelUserAction::kShowAllPasswordsWhileSomeAreSuggested));
+
+ } else {
+ EXPECT_THAT(histograms.GetAllSamples(kShownContextHistogram),
+ testing::IsEmpty());
+ EXPECT_THAT(histograms.GetAllSamples(kAcceptedContextHistogram),
+ testing::IsEmpty());
+ }
+}
+
+TEST_F(PasswordAutofillManagerTest, ShowStandaloneShowAllPasswords) {
+ const char kShownContextHistogram[] =
+ "PasswordManager.ShowAllSavedPasswordsShownContext";
+ const char kAcceptedContextHistogram[] =
+ "PasswordManager.ShowAllSavedPasswordsAcceptedContext";
+ base::HistogramTester histograms;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+
+ auto client = base::MakeUnique<TestPasswordManagerClient>();
+ auto autofill_client = base::MakeUnique<MockAutofillClient>();
+ auto manager =
+ base::MakeUnique<password_manager::PasswordManager>(client.get());
+ InitializePasswordAutofillManager(client.get(), autofill_client.get());
+
+ ON_CALL(*(client->mock_driver()), GetPasswordManager())
+ .WillByDefault(testing::Return(manager.get()));
+
+ gfx::RectF element_bounds;
+ autofill::PasswordFormFillData data;
+ data.username_field.value = test_username_;
+ data.password_field.value = test_password_;
+ data.origin = GURL("http://foo.test");
+
+ // String for the "Show all passwords" fallback.
+ base::string16 show_all_saved_row_text =
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK);
+
+ SetManualFallbacksForFilling(true);
+
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAreArray(
+ {show_all_saved_row_text})),
+ _))
+ .Times(IsPreLollipopAndroid() ? 0 : 1);
+ password_autofill_manager_->OnShowManualFallbackSuggestion(
+ base::i18n::RIGHT_TO_LEFT, element_bounds);
+
+ if (IsPreLollipopAndroid()) {
+ EXPECT_THAT(histograms.GetAllSamples(kShownContextHistogram),
+ testing::IsEmpty());
+ } else {
+ // Expect a sample only in the shown histogram.
+ histograms.ExpectUniqueSample(
+ kShownContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK, 1);
+ }
+
+ if (!IsPreLollipopAndroid()) {
+ // Clicking at the "Show all passwords row" should trigger a call to open
+ // the Password Manager settings page and hide the popup.
+ EXPECT_CALL(
+ *autofill_client,
+ ExecuteCommand(autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY));
+ EXPECT_CALL(*autofill_client, HideAutofillPopup());
+ password_autofill_manager_->DidAcceptSuggestion(
+ base::string16(), autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY, 0);
+ // Expect a sample in both the shown and accepted histogram.
+ histograms.ExpectUniqueSample(
+ kShownContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK, 1);
+ histograms.ExpectUniqueSample(
+ kAcceptedContextHistogram,
+ metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK, 1);
+ // Trigger UKM reporting, which happens at destruction time.
+ manager.reset();
+ autofill_client.reset();
+ client.reset();
+ const ukm::UkmSource* source =
+ test_ukm_recorder.GetSourceForUrl(kMainFrameUrl);
+ ASSERT_TRUE(source);
+
+ test_ukm_recorder.ExpectMetric(
+ *source, "PageWithPassword", password_manager::kUkmPageLevelUserAction,
+ static_cast<int64_t>(
+ password_manager::PasswordManagerMetricsRecorder::
+ PageLevelUserAction::kShowAllPasswordsWhileNoneAreSuggested));
+ } else {
+ EXPECT_THAT(histograms.GetAllSamples(kShownContextHistogram),
+ testing::IsEmpty());
+ EXPECT_THAT(histograms.GetAllSamples(kAcceptedContextHistogram),
+ testing::IsEmpty());
+ }
+}
+
+// Tests that the "Show all passwords" fallback doesn't shows up in non-password
+// fields of login forms.
+TEST_F(PasswordAutofillManagerTest,
+ NotShowAllPasswordsOptionOnNonPasswordField) {
+ auto client = base::MakeUnique<TestPasswordManagerClient>();
+ auto autofill_client = base::MakeUnique<MockAutofillClient>();
+ InitializePasswordAutofillManager(client.get(), autofill_client.get());
+
+ gfx::RectF element_bounds;
+ autofill::PasswordFormFillData data;
+ data.username_field.value = test_username_;
+ data.password_field.value = test_password_;
+ data.origin = GURL("https://foo.test");
+
+ int dummy_key = 0;
+ password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
+
+ SetManualFallbacksForFilling(true);
+
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(
+ element_bounds, _,
+ SuggestionVectorValuesAre(testing::ElementsAre(test_username_)), _));
+ password_autofill_manager_->OnShowPasswordSuggestions(
+ dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
+}
+
+// SimpleWebviewDialog doesn't have an autofill client. Nothing should crash if
+// the filling fallback is invoked.
+TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsWithoutAutofillClient) {
+ auto client = base::MakeUnique<TestPasswordManagerClient>();
+ InitializePasswordAutofillManager(client.get(), nullptr);
+
+ SetManualFallbacksForFilling(true);
+
+ password_autofill_manager_->OnShowManualFallbackSuggestion(
+ base::i18n::RIGHT_TO_LEFT, gfx::RectF());
+}
+
} // namespace password_manager
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 12f6263d09f..4702e788f4c 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -176,10 +176,13 @@ void SetFieldLabelsOnSave(const autofill::ServerFieldType password_type,
// Label username and password fields with autofill types in |form_structure|
// based on |field_types|. The function also adds the types to
-// |available_field_types|.
+// |available_field_types|. For field of |USERNAME| type, the username vote
+// type will be set to |username_vote_type|.
void LabelFields(const FieldTypeMap& field_types,
FormStructure* form_structure,
- autofill::ServerFieldTypeSet* available_field_types) {
+ autofill::ServerFieldTypeSet* available_field_types,
+ autofill::AutofillUploadContents::Field::UsernameVoteType
+ username_vote_type) {
for (size_t i = 0; i < form_structure->field_count(); ++i) {
autofill::AutofillField* field = form_structure->field(i);
@@ -189,6 +192,8 @@ void LabelFields(const FieldTypeMap& field_types,
if (iter != field_types.end()) {
type = iter->second;
available_field_types->insert(type);
+ if (type == autofill::USERNAME)
+ field->set_username_vote_type(username_vote_type);
}
}
@@ -332,19 +337,18 @@ PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage(
result |= RESULT_ORIGINS_OR_FRAMES_MATCH;
- // Autofill predictions can overwrite our default username selection so
- // if this form was parsed with autofill predictions then allow the username
- // element to be different.
- if ((form.was_parsed_using_autofill_predictions ||
- form.username_element == observed_form_.username_element) &&
- form.password_element == observed_form_.password_element) {
- result |= RESULT_HTML_ATTRIBUTES_MATCH;
- }
+ if (CalculateFormSignature(form.form_data) ==
+ CalculateFormSignature(observed_form_.form_data))
+ result |= RESULT_SIGNATURE_MATCH;
+
+ if (!form.form_data.name.empty() &&
+ form.form_data.name == observed_form_.form_data.name)
+ result |= RESULT_FORM_NAME_MATCH;
// Note: although saved password forms might actually have an empty action
// URL if they were imported (see bug 1107719), the |form| we see here comes
// never from the password store, and should have an exactly matching action.
- if (form.action == observed_form_.action)
+ if (!form.action.is_empty() && form.action == observed_form_.action)
result |= RESULT_ACTION_MATCH;
return result;
@@ -454,6 +458,8 @@ void PasswordFormManager::Update(
form_saver_->Update(pending_credentials_, best_matches_,
&more_credentials_to_update,
old_primary_key ? &old_primary_key.value() : nullptr);
+
+ password_manager_->UpdateFormManagers();
}
void PasswordFormManager::UpdateUsername(const base::string16& new_username) {
@@ -461,6 +467,24 @@ void PasswordFormManager::UpdateUsername(const base::string16& new_username) {
// Check if the username already exists.
const PasswordForm* match = FindBestSavedMatch(&pending_credentials_);
is_new_login_ = !match || match->is_public_suffix_match;
+ // Searching for the field of |match| where |new_username| was typed. If it is
+ // found, the field name is saved to |corrected_username_element_|. Otherwise,
+ // |corrected_username_element_| has no value.
+ base::string16 trimmed_username_value;
+ base::TrimString(new_username, base::ASCIIToUTF16(" "),
+ &trimmed_username_value);
+ corrected_username_element_.reset();
+ if (!trimmed_username_value.empty()) {
+ for (size_t i = 0; i < pending_credentials_.other_possible_usernames.size();
+ ++i) {
+ if (pending_credentials_.other_possible_usernames[i].first ==
+ trimmed_username_value) {
+ corrected_username_element_ =
+ pending_credentials_.other_possible_usernames[i].second;
+ break;
+ }
+ }
+ }
}
void PasswordFormManager::PresaveGeneratedPassword(
@@ -482,7 +506,8 @@ void PasswordFormManager::PasswordNoLongerGenerated() {
generated_password_changed_ = false;
}
-void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) {
+void PasswordFormManager::SaveSubmittedFormTypeForMetrics(
+ const autofill::PasswordForm& form) {
bool is_change_password_form =
!form.new_password_value.empty() && !form.password_value.empty();
bool is_signup_form =
@@ -567,6 +592,7 @@ void PasswordFormManager::ProcessMatches(
size_t filtered_count) {
blacklisted_matches_.clear();
new_blacklisted_.reset();
+ blacklisted_origin_found_ = false;
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
@@ -583,6 +609,15 @@ void PasswordFormManager::ProcessMatches(
[this](const PasswordForm* form) { return IsMatch(*form); });
ScoreMatches(matches);
+ auto find_blacklisted_match_it = std::find_if(
+ non_federated.begin(), non_federated.end(),
+ [this](const PasswordForm* form) {
+ return form->blacklisted_by_user &&
+ form->origin.GetOrigin() == observed_form_.origin.GetOrigin();
+ });
+ blacklisted_origin_found_ =
+ (find_blacklisted_match_it != non_federated.end());
+
// Copy out blacklisted matches.
blacklisted_matches_.resize(std::count_if(
non_federated.begin(), non_federated.end(),
@@ -628,6 +663,9 @@ void PasswordFormManager::ProcessFrameInternal(
if (!driver)
return;
+ if (blacklisted_origin_found_)
+ driver->MatchingBlacklistedFormFound();
+
driver->AllowPasswordGenerationForForm(observed_form_);
if (best_matches_.empty()) {
@@ -830,10 +868,12 @@ bool PasswordFormManager::UploadPasswordVote(
}
autofill::ServerFieldTypeSet available_field_types;
+ // A map from field names to field types.
+ FieldTypeMap field_types;
+ autofill::AutofillUploadContents::Field::UsernameVoteType username_vote_type =
+ autofill::AutofillUploadContents::Field::NO_INFORMATION;
if (password_type != autofill::USERNAME) {
if (has_autofill_vote) {
- // A map from field names to field types.
- FieldTypeMap field_types;
DCHECK(submitted_form_);
bool is_update = password_type == autofill::NEW_PASSWORD ||
password_type == autofill::PROBABLY_NEW_PASSWORD ||
@@ -847,21 +887,31 @@ bool PasswordFormManager::UploadPasswordVote(
}
field_types[submitted_form_->confirmation_password_element] =
autofill::CONFIRMATION_PASSWORD;
- LabelFields(field_types, &form_structure, &available_field_types);
}
if (password_type != autofill::ACCOUNT_CREATION_PASSWORD) {
if (generation_popup_was_shown_)
AddGeneratedVote(&form_structure);
if (form_classifier_outcome_ != kNoOutcome)
AddFormClassifierVote(&form_structure);
+ } else { // User reuses credentials.
+ field_types[form_to_upload.username_element] = autofill::USERNAME;
+ username_vote_type =
+ autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
+ }
+ if (corrected_username_element_.has_value()) {
+ field_types[corrected_username_element_.value()] = autofill::USERNAME;
+ username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_EDITED;
}
- } else { // Username correction vote.
- FieldTypeMap field_types;
+ } else { // User overwrites username.
field_types[form_to_upload.username_element] = autofill::USERNAME;
field_types[form_to_upload.password_element] =
autofill::ACCOUNT_CREATION_PASSWORD;
- LabelFields(field_types, &form_structure, &available_field_types);
+ username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
}
+ LabelFields(field_types, &form_structure, &available_field_types,
+ username_vote_type);
// Force uploading as these events are relatively rare and we want to make
// sure to receive them.
@@ -1422,7 +1472,6 @@ void PasswordFormManager::SendVotesOnSave() {
// to detect username autofill type.
form_data.fields[0].value = pending_credentials_.username_value;
SendSignInVote(form_data);
- return;
}
// Upload credentials the first time they are saved. This data is used
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 3c56130a783..2530bd74b14 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -72,15 +72,17 @@ class PasswordFormManager : public FormFetcher::Consumer {
// RESULT_COMPLETE_MATCH will also be returned to indicate non-HTML forms
// completely matching.
// The ordering of these flags is important. Larger matches are more
- // preferred than lower matches. That is, since RESULT_HTML_ATTRIBUTES_MATCH
- // is greater than RESULT_ACTION_MATCH, a match of only attributes and not
- // actions will be preferred to one of actions and not attributes.
+ // preferred than lower matches. That is, since RESULT_FORM_NAME_MATCH
+ // is greater than RESULT_ACTION_MATCH, a match of only names and not
+ // actions will be preferred to one of actions and not names.
enum MatchResultFlags {
RESULT_NO_MATCH = 0,
RESULT_ACTION_MATCH = 1 << 0,
- RESULT_HTML_ATTRIBUTES_MATCH = 1 << 1,
- RESULT_ORIGINS_OR_FRAMES_MATCH = 1 << 2,
- RESULT_COMPLETE_MATCH = RESULT_ACTION_MATCH | RESULT_HTML_ATTRIBUTES_MATCH |
+ RESULT_FORM_NAME_MATCH = 1 << 1,
+ RESULT_SIGNATURE_MATCH = 1 << 2,
+ RESULT_ORIGINS_OR_FRAMES_MATCH = 1 << 3,
+ RESULT_COMPLETE_MATCH = RESULT_ACTION_MATCH | RESULT_FORM_NAME_MATCH |
+ RESULT_SIGNATURE_MATCH |
RESULT_ORIGINS_OR_FRAMES_MATCH
};
// Use MatchResultMask to contain combinations of MatchResultFlags values.
@@ -105,10 +107,8 @@ class PasswordFormManager : public FormFetcher::Consumer {
const autofill::PasswordForm& form,
const password_manager::PasswordManagerDriver* driver) const;
- // Update |this| with the |form| that was actually submitted. Used to
- // determine what type the submitted form is for
- // IsIgnorableChangePasswordForm() and UMA stats.
- void SetSubmittedForm(const autofill::PasswordForm& form);
+ // Used to determine what type the submitted form is for UMA stats.
+ void SaveSubmittedFormTypeForMetrics(const autofill::PasswordForm& form);
// Determines if the user opted to 'never remember' passwords for this form.
bool IsBlacklisted() const;
@@ -582,6 +582,15 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Make sure to call Init before using |*this|, to ensure it is not null.
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
+ // Set if the user has edited username value in prompt. The value is the
+ // matched field name from |PasswordForm.other_possible_usernames| if the
+ // match found.
+ base::Optional<base::string16> corrected_username_element_;
+
+ // Tracks if a form with same origin as |observed_form_| found in blacklisted
+ // forms.
+ bool blacklisted_origin_found_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PasswordFormManager);
};
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 57fb1d3d344..53648b56232 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
@@ -127,10 +127,11 @@ MATCHER_P(CheckUsernamePtr, username_value, "Username incorrect") {
return arg && arg->username_value == username_value;
}
-MATCHER_P3(CheckUploadedAutofillTypesAndSignature,
+MATCHER_P4(CheckUploadedAutofillTypesAndSignature,
form_signature,
expected_types,
expect_generation_vote,
+ expected_username_vote_type,
"Unexpected autofill types or form signature") {
if (form_signature != arg.FormSignatureAsStr()) {
// Unexpected form's signature.
@@ -138,6 +139,7 @@ MATCHER_P3(CheckUploadedAutofillTypesAndSignature,
<< ", but found " << arg.FormSignatureAsStr();
return false;
}
+
bool found_generation_vote = false;
for (const auto& field : arg) {
if (field->possible_types().size() > 1) {
@@ -161,6 +163,20 @@ MATCHER_P3(CheckUploadedAutofillTypesAndSignature,
<< ", but found " << actual_vote;
return false;
}
+ if (expected_vote == autofill::USERNAME) {
+ if (field->username_vote_type() != expected_username_vote_type) {
+ ADD_FAILURE() << field->name
+ << " field has expected username vote type "
+ << expected_username_vote_type << ", but found "
+ << field->username_vote_type();
+ }
+ } else {
+ if (field->username_vote_type() !=
+ autofill::AutofillUploadContents::Field::NO_INFORMATION) {
+ ADD_FAILURE() << field->name
+ << " field should not have any username vote type";
+ }
+ }
}
EXPECT_EQ(expect_generation_vote, found_generation_vote);
return true;
@@ -313,6 +329,7 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
void(const autofill::PasswordFormFillData&));
MOCK_METHOD1(AllowPasswordGenerationForForm,
void(const autofill::PasswordForm&));
+ MOCK_METHOD0(MatchingBlacklistedFormFound, void());
MockAutofillManager* mock_autofill_manager() {
return &mock_autofill_manager_;
@@ -373,6 +390,7 @@ class PasswordFormManagerTest : public testing::Test {
observed_form_.password_element = ASCIIToUTF16("Passwd");
observed_form_.submit_element = ASCIIToUTF16("signIn");
observed_form_.signon_realm = "http://accounts.google.com";
+ observed_form_.form_data.name = ASCIIToUTF16("the-form-name");
saved_match_ = observed_form_;
saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth");
@@ -453,7 +471,19 @@ class PasswordFormManagerTest : public testing::Test {
autofill::ServerFieldTypeSet expected_available_field_types;
FieldTypeMap expected_types;
expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
- expected_types[match.username_element] = autofill::UNKNOWN_TYPE;
+
+ // When we're voting for an account creation form, we should also vote
+ // for its username field.
+ if (field_type && *field_type == autofill::ACCOUNT_CREATION_PASSWORD) {
+ expected_types[match.username_element] = autofill::USERNAME;
+ expected_available_field_types.insert(autofill::USERNAME);
+ } else {
+ expected_types[match.username_element] = autofill::UNKNOWN_TYPE;
+ }
+
+ autofill::AutofillUploadContents::Field::UsernameVoteType
+ expected_username_vote_type =
+ autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
bool expect_generation_vote = false;
if (field_type) {
@@ -469,13 +499,13 @@ class PasswordFormManagerTest : public testing::Test {
}
if (field_type) {
- EXPECT_CALL(
- *client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(),
- expected_types, expect_generation_vote),
- false, expected_available_field_types,
- expected_login_signature, true));
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
+ pending_structure.FormSignatureAsStr(),
+ expected_types, expect_generation_vote,
+ expected_username_vote_type),
+ false, expected_available_field_types,
+ expected_login_signature, true));
} else {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, _, _, _, _))
@@ -572,11 +602,14 @@ class PasswordFormManagerTest : public testing::Test {
expected_login_signature = pending_structure.FormSignatureAsStr();
}
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types,
- false /* expect_generation_vote */),
- false, expected_available_field_types,
- expected_login_signature, true));
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ observed_form_signature, expected_types,
+ false /* expect_generation_vote */,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION
+ /* expected_username_vote_type */),
+ false, expected_available_field_types,
+ expected_login_signature, true));
switch (field_type) {
case autofill::NEW_PASSWORD:
@@ -1104,6 +1137,7 @@ TEST_F(PasswordFormManagerTest, PSLMatchedCredentialsMetadataUpdated) {
autofill::ServerFieldTypeSet expected_available_field_types;
expected_available_field_types.insert(autofill::ACCOUNT_CREATION_PASSWORD);
+ expected_available_field_types.insert(autofill::USERNAME);
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, false, expected_available_field_types, _, true));
@@ -1442,11 +1476,10 @@ TEST_F(PasswordFormManagerTest,
}
TEST_F(PasswordFormManagerTest,
- TestSendNotBlacklistedMessage_BlacklistedCredentials) {
+ TestSendMachedBlacklistedFoundMessage_BlacklistedCredentials) {
// Signing up on a previously visited site. Credentials are found in the
- // password store, but they are blacklisted. AllowPasswordGenerationForForm
- // is still called.
- EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_));
+ // password store, but they are blacklisted.
+ EXPECT_CALL(*client()->mock_driver(), MatchingBlacklistedFormFound());
PasswordForm simulated_result = CreateSavedMatch(true);
fake_form_fetcher()->SetNonFederated({&simulated_result}, 0u);
}
@@ -1795,8 +1828,8 @@ TEST_F(PasswordFormManagerTest, NonHTMLFormsDoNotMatchHTMLForms) {
ASSERT_EQ(PasswordForm::SCHEME_HTML, observed_form()->scheme);
PasswordForm non_html_form(*observed_form());
non_html_form.scheme = PasswordForm::SCHEME_DIGEST;
- EXPECT_EQ(0, form_manager()->DoesManage(non_html_form, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ form_manager()->DoesManage(non_html_form, nullptr));
// The other way round: observing a non-HTML form, don't match a HTML form.
PasswordForm html_form(*observed_form());
@@ -1804,8 +1837,8 @@ TEST_F(PasswordFormManagerTest, NonHTMLFormsDoNotMatchHTMLForms) {
password_manager(), client(), kNoDriver, non_html_form,
base::MakeUnique<MockFormSaver>(), fake_form_fetcher());
non_html_manager.Init(nullptr);
- EXPECT_EQ(0, non_html_manager.DoesManage(html_form, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ non_html_manager.DoesManage(html_form, nullptr));
}
TEST_F(PasswordFormManagerTest, OriginCheck_HostsMatchExactly) {
@@ -1813,8 +1846,8 @@ TEST_F(PasswordFormManagerTest, OriginCheck_HostsMatchExactly) {
PasswordForm form_longer_host(*observed_form());
form_longer_host.origin = GURL("http://accounts.google.com.au/a/LoginAuth");
// Check that accounts.google.com does not match accounts.google.com.au.
- EXPECT_EQ(0, form_manager()->DoesManage(form_longer_host, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ form_manager()->DoesManage(form_longer_host, nullptr));
}
TEST_F(PasswordFormManagerTest, OriginCheck_MoreSecureSchemePathsMatchPrefix) {
@@ -1823,7 +1856,7 @@ TEST_F(PasswordFormManagerTest, OriginCheck_MoreSecureSchemePathsMatchPrefix) {
PasswordForm form_longer_path(*observed_form());
form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec");
EXPECT_NE(0, form_manager()->DoesManage(form_longer_path, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ PasswordFormManager::RESULT_ORIGINS_OR_FRAMES_MATCH);
}
TEST_F(PasswordFormManagerTest,
@@ -1833,8 +1866,8 @@ TEST_F(PasswordFormManagerTest,
PasswordForm form_longer_path(*observed_form());
form_longer_path.origin = GURL("http://accounts.google.com/a/LoginAuth/sec");
// Check that /a/LoginAuth does not match /a/LoginAuth/more.
- EXPECT_EQ(0, form_manager()->DoesManage(form_longer_path, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ form_manager()->DoesManage(form_longer_path, nullptr));
PasswordForm secure_observed_form(*observed_form());
secure_observed_form.origin = GURL("https://accounts.google.com/a/LoginAuth");
@@ -1844,27 +1877,64 @@ TEST_F(PasswordFormManagerTest,
secure_manager.Init(nullptr);
// Also for HTTPS in the observed form, and HTTP in the compared form, an
// exact path match is expected.
- EXPECT_EQ(0, secure_manager.DoesManage(form_longer_path, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ secure_manager.DoesManage(form_longer_path, nullptr));
// Not even upgrade to HTTPS in the compared form should help.
form_longer_path.origin = GURL("https://accounts.google.com/a/LoginAuth/sec");
- EXPECT_EQ(0, secure_manager.DoesManage(form_longer_path, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
+ secure_manager.DoesManage(form_longer_path, nullptr));
}
TEST_F(PasswordFormManagerTest, OriginCheck_OnlyOriginsMatch) {
// Make sure DoesManage() can distinguish when only origins match.
- PasswordForm different_html_attributes(*observed_form());
- different_html_attributes.password_element = ASCIIToUTF16("random_pass");
- different_html_attributes.username_element = ASCIIToUTF16("random_user");
-
- EXPECT_EQ(0, form_manager()->DoesManage(different_html_attributes, nullptr) &
- PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
+ PasswordForm same_origin_only(*observed_form());
+ same_origin_only.form_data.name = ASCIIToUTF16("other_name");
+ same_origin_only.action = GURL("https://somewhere/else");
EXPECT_EQ(PasswordFormManager::RESULT_ORIGINS_OR_FRAMES_MATCH,
- form_manager()->DoesManage(different_html_attributes, nullptr) &
- PasswordFormManager::RESULT_ORIGINS_OR_FRAMES_MATCH);
+ form_manager()->DoesManage(same_origin_only, nullptr));
+}
+
+TEST_F(PasswordFormManagerTest, FormsMatchIfNamesMatch) {
+ PasswordForm other_form(*observed_form());
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("another-field-name");
+ other_form.form_data.fields.push_back(field);
+ other_form.action = GURL("https://somewhere/else");
+ // Names should match, other things may not.
+ EXPECT_EQ(PasswordFormManager::RESULT_FORM_NAME_MATCH,
+ form_manager()->DoesManage(other_form, nullptr) &
+ PasswordFormManager::RESULT_FORM_NAME_MATCH);
+}
+
+TEST_F(PasswordFormManagerTest, FormsMatchIfSignaturesMatch) {
+ PasswordForm other_form(*observed_form());
+ other_form.action = GURL("https://somewhere/else");
+ // Signatures should match, other things may not.
+ EXPECT_EQ(PasswordFormManager::RESULT_SIGNATURE_MATCH,
+ form_manager()->DoesManage(other_form, nullptr) &
+ PasswordFormManager::RESULT_SIGNATURE_MATCH);
+}
+
+TEST_F(PasswordFormManagerTest, NoMatchForEmptyNames) {
+ // If two forms have no name, it's not evidence for a match.
+ PasswordForm other_form(*observed_form());
+ const_cast<PasswordForm&>(form_manager()->observed_form())
+ .form_data.name.clear();
+ other_form.form_data.name.clear();
+ EXPECT_EQ(0, form_manager()->DoesManage(other_form, nullptr) &
+ PasswordFormManager::RESULT_FORM_NAME_MATCH);
+}
+
+TEST_F(PasswordFormManagerTest, NoMatchForEmtpyActions) {
+ // If two forms have no actions, it's not evidence for a match.
+ PasswordForm other_form(*observed_form());
+ const_cast<PasswordForm&>(form_manager()->observed_form()).form_data.action =
+ GURL::EmptyGURL();
+ other_form.action = GURL::EmptyGURL();
+ EXPECT_EQ(0, form_manager()->DoesManage(other_form, nullptr) &
+ PasswordFormManager::RESULT_ACTION_MATCH);
}
// Test that if multiple credentials with the same username are stored, and the
@@ -2294,12 +2364,13 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
TEST_F(PasswordFormManagerTest, TestUpdateUsernameMethod) {
fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
- // User logs in, edits username.
+ // User enters credential in the form.
PasswordForm credential(*observed_form());
credential.username_value = ASCIIToUTF16("oldusername");
credential.password_value = ASCIIToUTF16("password");
form_manager()->ProvisionallySave(
credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ // User edits username in a prompt.
form_manager()->UpdateUsername(ASCIIToUTF16("newusername"));
EXPECT_EQ(form_manager()->pending_credentials().username_value,
ASCIIToUTF16("newusername"));
@@ -2322,7 +2393,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateUsernameToExisting) {
// We have an already existing credential.
fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
- // User submits credential to the observed form.
+ // User enters credential in the form.
PasswordForm credential(*observed_form());
credential.username_value = ASCIIToUTF16("different_username");
credential.password_value = ASCIIToUTF16("different_pass");
@@ -2330,7 +2401,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateUsernameToExisting) {
form_manager()->ProvisionallySave(
credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- // User edits the username to the already existing one.
+ // User edits username in a prompt to one already existing.
form_manager()->UpdateUsername(saved_match()->username_value);
// The username in credentials is expected to be updated.
@@ -2512,8 +2583,8 @@ TEST_F(PasswordFormManagerTest, ProcessFrame_StoreUpdatesCausesAutofill) {
}
// TODO(crbug.com/639786): Restore the following test:
-// when PasswordFormManager::Save is called, then PasswordFormManager also
-// calls PasswordManager::UpdateFormManagers.
+// when PasswordFormManager::Save or PasswordFormManager::Update is called, then
+// PasswordFormManager also calls PasswordManager::UpdateFormManagers.
TEST_F(PasswordFormManagerTest, UploadChangePasswordForm) {
autofill::ServerFieldType kChangePasswordVotes[] = {
@@ -2864,11 +2935,14 @@ TEST_F(PasswordFormManagerTest,
autofill::FormStructure(saved_match()->form_data).FormSignatureAsStr();
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types,
- false /* expect_generation_vote */),
- false, expected_available_field_types,
- expected_login_signature, true));
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ observed_form_signature, expected_types,
+ false /* expect_generation_vote */,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION
+ /* expected_username_vote_type */),
+ false, expected_available_field_types,
+ expected_login_signature, true));
form_manager.Update(*saved_match());
}
@@ -3071,6 +3145,7 @@ TEST_F(PasswordFormManagerTest, SkipZeroClickIntact) {
TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
PasswordForm form(*observed_form());
form.form_data = saved_match()->form_data;
+ form.other_possible_usernames = saved_match()->other_possible_usernames;
FakeFormFetcher fetcher;
fetcher.Fetch();
@@ -3088,22 +3163,33 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
fetcher.SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+ // A user submits a form and edits the username in the prompt.
+ form_manager.ProvisionallySave(
+ form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.UpdateUsername(ASCIIToUTF16(" test2@gmail.com"));
+
autofill::FormStructure pending_structure(form_to_save.form_data);
autofill::ServerFieldTypeSet expected_available_field_types;
std::map<base::string16, autofill::ServerFieldType> expected_types;
- expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
expected_types[saved_match()->username_element] = autofill::UNKNOWN_TYPE;
- expected_available_field_types.insert(
- autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
+ expected_types[ASCIIToUTF16("full_name")] = autofill::USERNAME;
expected_types[saved_match()->password_element] =
autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD;
+ expected_available_field_types.insert(
+ autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
+ expected_available_field_types.insert(autofill::USERNAME);
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(), expected_types,
- false /* expect_generation_vote */),
- false, expected_available_field_types, std::string(), true));
+ autofill::AutofillUploadContents::Field::UsernameVoteType
+ expected_username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_EDITED;
+
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ pending_structure.FormSignatureAsStr(), expected_types,
+ false /* expect_generation_vote */, expected_username_vote_type),
+ false, expected_available_field_types, std::string(), true));
form_manager.ProvisionallySave(
form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
@@ -3242,6 +3328,11 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
expected_username_vote.username_element =
saved_match()->other_possible_usernames[0].second;
+ // Checks the username vote type is saved.
+ autofill::AutofillUploadContents::Field::UsernameVoteType
+ expected_username_vote_type =
+ autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
+
// Checks the upload.
autofill::ServerFieldTypeSet expected_available_field_types;
expected_available_field_types.insert(autofill::USERNAME);
@@ -3260,11 +3351,12 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
expected_types[ASCIIToUTF16("Email")] = autofill::UNKNOWN_TYPE;
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- expected_upload.FormSignatureAsStr(),
- expected_types, false),
- false, expected_available_field_types,
- expected_login_signature, true));
+ StartUploadRequest(
+ CheckUploadedAutofillTypesAndSignature(
+ expected_upload.FormSignatureAsStr(), expected_types,
+ false, expected_username_vote_type),
+ false, expected_available_field_types,
+ expected_login_signature, true));
form_manager()->Save();
}
@@ -3859,9 +3951,30 @@ TEST_F(PasswordFormManagerTest, TestUkmForFilling) {
const auto* source =
test_ukm_recorder.GetSourceForUrl(form_to_fill.origin.spec().c_str());
ASSERT_TRUE(source);
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm",
- kUkmManagerFillEvent, test.expected_event);
+ test_ukm_recorder.ExpectMetric(
+ *source, ukm::builders::PasswordForm::kEntryName,
+ ukm::builders::PasswordForm::kManagerFill_ActionName,
+ test.expected_event);
}
}
+TEST_F(PasswordFormManagerTest,
+ TestSendNotBlacklistedMessage_BlacklistedCredentials) {
+ // Signing up on a previously visited site. Credentials are found in the
+ // password store, but they are blacklisted. AllowPasswordGenerationForForm
+ // is still called.
+ EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_));
+ PasswordForm simulated_result = CreateSavedMatch(true);
+ fake_form_fetcher()->SetNonFederated({&simulated_result}, 0u);
+}
+
+TEST_F(PasswordFormManagerTest,
+ TestSendMachedBlacklistedFoundMessage_Credentials) {
+ // Signing up on a previously visited site. Credentials are found in the
+ // password store, and are not blacklisted.
+ EXPECT_CALL(*client()->mock_driver(), MatchingBlacklistedFormFound())
+ .Times(0);
+ PasswordForm simulated_result = CreateSavedMatch(false);
+ fake_form_fetcher()->SetNonFederated({&simulated_result}, 0u);
+}
} // namespace password_manager
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 c90e449422f..9751f545fd5 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
@@ -17,18 +17,47 @@ using autofill::PasswordForm;
namespace password_manager {
-const char kUkmSubmissionObserved[] = "Submission.Observed";
-const char kUkmSubmissionResult[] = "Submission.SubmissionResult";
-const char kUkmSubmissionFormType[] = "Submission.SubmittedFormType";
-const char kUkmUpdatingPromptShown[] = "Updating.Prompt.Shown";
-const char kUkmUpdatingPromptTrigger[] = "Updating.Prompt.Trigger";
-const char kUkmUpdatingPromptInteraction[] = "Updating.Prompt.Interaction";
-const char kUkmSavingPromptShown[] = "Saving.Prompt.Shown";
-const char kUkmSavingPromptTrigger[] = "Saving.Prompt.Trigger";
-const char kUkmSavingPromptInteraction[] = "Saving.Prompt.Interaction";
-const char kUkmManagerFillEvent[] = "ManagerFill.Action";
-const char kUkmUserActionSimplified[] = "User.ActionSimplified";
-const char kUkmUserAction[] = "User.Action";
+namespace {
+
+PasswordFormMetricsRecorder::BubbleDismissalReason GetBubbleDismissalReason(
+ metrics_util::UIDismissalReason ui_dismissal_reason) {
+ using BubbleDismissalReason =
+ PasswordFormMetricsRecorder::BubbleDismissalReason;
+ switch (ui_dismissal_reason) {
+ // Accepted by user.
+ case metrics_util::CLICKED_SAVE:
+ return BubbleDismissalReason::kAccepted;
+
+ // Declined by user.
+ case metrics_util::CLICKED_CANCEL:
+ case metrics_util::CLICKED_NEVER:
+ return BubbleDismissalReason::kDeclined;
+
+ // Ignored by user.
+ case metrics_util::NO_DIRECT_INTERACTION:
+ return BubbleDismissalReason::kIgnored;
+
+ // Ignore these for metrics collection:
+ case metrics_util::CLICKED_MANAGE:
+ case metrics_util::CLICKED_DONE:
+ case metrics_util::CLICKED_OK:
+ case metrics_util::CLICKED_BRAND_NAME:
+ case metrics_util::CLICKED_PASSWORDS_DASHBOARD:
+ case metrics_util::AUTO_SIGNIN_TOAST_TIMEOUT:
+ break;
+
+ // These should not reach here:
+ case metrics_util::CLICKED_UNBLACKLIST_OBSOLETE:
+ case metrics_util::CLICKED_CREDENTIAL_OBSOLETE:
+ case metrics_util::AUTO_SIGNIN_TOAST_CLICKED_OBSOLETE:
+ case metrics_util::NUM_UI_RESPONSES:
+ NOTREACHED();
+ break;
+ }
+ return BubbleDismissalReason::kUnknown;
+}
+
+} // namespace
PasswordFormMetricsRecorder::PasswordFormMetricsRecorder(
bool is_main_frame_secure,
@@ -39,15 +68,13 @@ PasswordFormMetricsRecorder::PasswordFormMetricsRecorder(
ukm_recorder_(ukm_recorder),
source_id_(source_id),
main_frame_url_(main_frame_url),
- ukm_entry_builder_(
- ukm_recorder
- ? ukm_recorder->GetEntryBuilder(source_id, "PasswordForm")
- : nullptr) {}
+ ukm_entry_builder_(source_id) {}
PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.ActionsTakenV3", GetActionsTaken(),
kMaxNumActionsTaken);
- RecordUkmMetric(kUkmUserActionSimplified, static_cast<int64_t>(user_action_));
+ ukm_entry_builder_.SetUser_ActionSimplified(
+ static_cast<int64_t>(user_action_));
// Use the visible main frame URL at the time the PasswordFormManager
// is created, in case a navigation has already started and the
@@ -65,7 +92,7 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
metrics_util::LogPasswordGenerationAvailableSubmissionEvent(
metrics_util::PASSWORD_NOT_SUBMITTED);
}
- RecordUkmMetric(kUkmSubmissionObserved, 0 /*false*/);
+ ukm_entry_builder_.SetSubmission_Observed(0 /*false*/);
}
if (submitted_form_type_ != kSubmittedFormTypeUnspecified) {
@@ -76,14 +103,17 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
submitted_form_type_, kSubmittedFormTypeMax);
}
- RecordUkmMetric(kUkmSubmissionFormType, submitted_form_type_);
+ ukm_entry_builder_.SetSubmission_SubmittedFormType(submitted_form_type_);
}
- RecordUkmMetric(kUkmUpdatingPromptShown, update_prompt_shown_);
- RecordUkmMetric(kUkmSavingPromptShown, save_prompt_shown_);
+ ukm_entry_builder_.SetUpdating_Prompt_Shown(update_prompt_shown_);
+ ukm_entry_builder_.SetSaving_Prompt_Shown(save_prompt_shown_);
+ // TODO(crbug/755407): This shouldn't depend on UKM keeping repeated metrics.
for (const DetailedUserAction& action : one_time_report_user_actions_)
- RecordUkmMetric(kUkmUserAction, static_cast<int64_t>(action));
+ ukm_entry_builder_.SetUser_Action(static_cast<int64_t>(action));
+
+ ukm_entry_builder_.Record(ukm_recorder_);
// Bind |main_frame_url_| to |source_id_| directly before sending the content
// of |ukm_recorder_| to ensure that the binding has not been purged already.
@@ -135,8 +165,8 @@ void PasswordFormMetricsRecorder::LogSubmitPassed() {
}
}
base::RecordAction(base::UserMetricsAction("PasswordManager_LoginPassed"));
- RecordUkmMetric(kUkmSubmissionObserved, 1 /*true*/);
- RecordUkmMetric(kUkmSubmissionResult, kSubmitResultPassed);
+ ukm_entry_builder_.SetSubmission_Observed(1 /*true*/);
+ ukm_entry_builder_.SetSubmission_SubmissionResult(kSubmitResultPassed);
submit_result_ = kSubmitResultPassed;
}
@@ -149,8 +179,8 @@ void PasswordFormMetricsRecorder::LogSubmitFailed() {
metrics_util::PASSWORD_SUBMISSION_FAILED);
}
base::RecordAction(base::UserMetricsAction("PasswordManager_LoginFailed"));
- RecordUkmMetric(kUkmSubmissionObserved, 1 /*true*/);
- RecordUkmMetric(kUkmSubmissionResult, kSubmitResultFailed);
+ ukm_entry_builder_.SetSubmission_Observed(1 /*true*/);
+ ukm_entry_builder_.SetSubmission_SubmissionResult(kSubmitResultFailed);
submit_result_ = kSubmitResultFailed;
}
@@ -181,7 +211,8 @@ void PasswordFormMetricsRecorder::RecordDetailedUserAction(
return;
}
// Repeated actions can be reported immediately.
- RecordUkmMetric(kUkmUserAction, static_cast<int64_t>(action));
+ // TODO(crbug/755407): This shouldn't depend on UKM keeping repeated metrics.
+ ukm_entry_builder_.SetUser_Action(static_cast<int64_t>(action));
}
int PasswordFormMetricsRecorder::GetActionsTaken() const {
@@ -210,7 +241,7 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Generated.HTTPSNotHTTP",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Generated.HTTPSNotHTTP", best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Generated_HTTPSNotHTTP(best_match);
best_match = GetBestMatchingSuppressedAccount(
form_fetcher.GetSuppressedHTTPSForms(), PasswordForm::TYPE_MANUAL,
@@ -219,7 +250,7 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Manual.HTTPSNotHTTP",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Manual.HTTPSNotHTTP", best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Manual_HTTPSNotHTTP(best_match);
}
best_match = GetBestMatchingSuppressedAccount(
@@ -229,7 +260,7 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Generated.PSLMatching",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Generated.PSLMatching", best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Generated_PSLMatching(best_match);
best_match = GetBestMatchingSuppressedAccount(
form_fetcher.GetSuppressedPSLMatchingForms(), PasswordForm::TYPE_MANUAL,
pending_credentials);
@@ -237,7 +268,7 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Manual.PSLMatching",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Manual.PSLMatching", best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Manual_PSLMatching(best_match);
best_match = GetBestMatchingSuppressedAccount(
form_fetcher.GetSuppressedSameOrganizationNameForms(),
@@ -246,8 +277,8 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Generated.SameOrganizationName",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Generated.SameOrganizationName",
- best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Generated_SameOrganizationName(
+ best_match);
best_match = GetBestMatchingSuppressedAccount(
form_fetcher.GetSuppressedSameOrganizationNameForms(),
PasswordForm::TYPE_MANUAL, pending_credentials);
@@ -255,7 +286,8 @@ void PasswordFormMetricsRecorder::RecordHistogramsOnSuppressedAccounts(
"PasswordManager.SuppressedAccount.Manual.SameOrganizationName",
GetHistogramSampleForSuppressedAccounts(best_match),
kMaxSuppressedAccountStats);
- RecordUkmMetric("SuppressedAccount.Manual.SameOrganizationName", best_match);
+ ukm_entry_builder_.SetSuppressedAccount_Manual_SameOrganizationName(
+ best_match);
if (current_bubble_ != CurrentBubbleOfInterest::kNone)
RecordUIDismissalReason(metrics_util::NO_DIRECT_INTERACTION);
@@ -283,28 +315,28 @@ void PasswordFormMetricsRecorder::RecordPasswordBubbleShown(
case metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING:
current_bubble_ = CurrentBubbleOfInterest::kSaveBubble;
save_prompt_shown_ = true;
- RecordUkmMetric(kUkmSavingPromptTrigger,
- static_cast<int64_t>(automatic_trigger_type));
+ ukm_entry_builder_.SetSaving_Prompt_Trigger(
+ static_cast<int64_t>(automatic_trigger_type));
break;
case metrics_util::MANUAL_WITH_PASSWORD_PENDING:
current_bubble_ = CurrentBubbleOfInterest::kSaveBubble;
save_prompt_shown_ = true;
- RecordUkmMetric(kUkmSavingPromptTrigger,
- static_cast<int64_t>(manual_trigger_type));
+ ukm_entry_builder_.SetSaving_Prompt_Trigger(
+ static_cast<int64_t>(manual_trigger_type));
break;
// Update cases:
case metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING_UPDATE:
current_bubble_ = CurrentBubbleOfInterest::kUpdateBubble;
update_prompt_shown_ = true;
- RecordUkmMetric(kUkmUpdatingPromptTrigger,
- static_cast<int64_t>(automatic_trigger_type));
+ ukm_entry_builder_.SetUpdating_Prompt_Trigger(
+ static_cast<int64_t>(automatic_trigger_type));
break;
case metrics_util::MANUAL_WITH_PASSWORD_PENDING_UPDATE:
current_bubble_ = CurrentBubbleOfInterest::kUpdateBubble;
update_prompt_shown_ = true;
- RecordUkmMetric(kUkmUpdatingPromptTrigger,
- static_cast<int64_t>(manual_trigger_type));
+ ukm_entry_builder_.SetUpdating_Prompt_Trigger(
+ static_cast<int64_t>(manual_trigger_type));
break;
// Other reasons to show a bubble:
@@ -328,52 +360,22 @@ void PasswordFormMetricsRecorder::RecordUIDismissalReason(
if (current_bubble_ != CurrentBubbleOfInterest::kUpdateBubble &&
current_bubble_ != CurrentBubbleOfInterest::kSaveBubble)
return;
- const char* metric = current_bubble_ == CurrentBubbleOfInterest::kUpdateBubble
- ? kUkmUpdatingPromptInteraction
- : kUkmSavingPromptInteraction;
- switch (ui_dismissal_reason) {
- // Accepted by user.
- case metrics_util::CLICKED_SAVE:
- RecordUkmMetric(metric,
- static_cast<int64_t>(BubbleDismissalReason::kAccepted));
- break;
-
- // Declined by user.
- case metrics_util::CLICKED_CANCEL:
- case metrics_util::CLICKED_NEVER:
- RecordUkmMetric(metric,
- static_cast<int64_t>(BubbleDismissalReason::kDeclined));
- break;
-
- // Ignored by user.
- case metrics_util::NO_DIRECT_INTERACTION:
- RecordUkmMetric(metric,
- static_cast<int64_t>(BubbleDismissalReason::kIgnored));
- break;
-
- // Ignore these for metrics collection:
- case metrics_util::CLICKED_MANAGE:
- case metrics_util::CLICKED_DONE:
- case metrics_util::CLICKED_OK:
- case metrics_util::CLICKED_BRAND_NAME:
- case metrics_util::CLICKED_PASSWORDS_DASHBOARD:
- case metrics_util::AUTO_SIGNIN_TOAST_TIMEOUT:
- break;
-
- // These should not reach here:
- case metrics_util::CLICKED_UNBLACKLIST_OBSOLETE:
- case metrics_util::CLICKED_CREDENTIAL_OBSOLETE:
- case metrics_util::AUTO_SIGNIN_TOAST_CLICKED_OBSOLETE:
- case metrics_util::NUM_UI_RESPONSES:
- NOTREACHED();
- break;
+ auto bubble_dismissal_reason = GetBubbleDismissalReason(ui_dismissal_reason);
+ if (bubble_dismissal_reason != BubbleDismissalReason::kUnknown) {
+ if (current_bubble_ == CurrentBubbleOfInterest::kUpdateBubble) {
+ ukm_entry_builder_.SetUpdating_Prompt_Interaction(
+ static_cast<int64_t>(bubble_dismissal_reason));
+ } else {
+ ukm_entry_builder_.SetSaving_Prompt_Interaction(
+ static_cast<int64_t>(bubble_dismissal_reason));
+ }
}
current_bubble_ = CurrentBubbleOfInterest::kNone;
}
void PasswordFormMetricsRecorder::RecordFillEvent(ManagerAutofillEvent event) {
- RecordUkmMetric(kUkmManagerFillEvent, event);
+ ukm_entry_builder_.SetManagerFill_Action(event);
}
PasswordFormMetricsRecorder::SuppressedAccountExistence
@@ -412,12 +414,6 @@ int PasswordFormMetricsRecorder::GetHistogramSampleForSuppressedAccounts(
return mixed_base_encoding;
}
-void PasswordFormMetricsRecorder::RecordUkmMetric(const char* metric_name,
- int64_t value) {
- if (ukm_entry_builder_)
- ukm_entry_builder_->AddMetric(metric_name, value);
-}
-
// static
bool PasswordFormMetricsRecorder::IsRepeatedUserAction(
DetailedUserAction action) {
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 9d5203b6208..6437b6bfeb8 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
@@ -16,69 +16,12 @@
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_form_user_action.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"
#include "url/gurl.h"
namespace password_manager {
-// URL Keyed Metrics.
-
-// This metric records whether a submission of a password form has been
-// observed. The values 0 and 1 correspond to false and true respectively.
-extern const char kUkmSubmissionObserved[];
-
-// This metric records the outcome of a password form submission. The values are
-// numbered according to PasswordFormMetricsRecorder::SubmitResult.
-// Note that no metric is recorded for kSubmitResultNotSubmitted.
-extern const char kUkmSubmissionResult[];
-
-// This metric records the classification of a form at submission time. The
-// values correspond to PasswordFormMetricsRecorder::SubmittedFormType.
-// Note that no metric is recorded for kSubmittedFormTypeUnspecified.
-extern const char kUkmSubmissionFormType[];
-
-// This metric records the boolean value indicating whether a password update
-// prompt was shown, which asked the user for permission to update a password.
-extern const char kUkmUpdatingPromptShown[];
-
-// This metric records the reason why a password update prompt was shown to ask
-// the user for permission to update a password. The values correspond to
-// PasswordFormMetricsRecorder::BubbleTrigger.
-extern const char kUkmUpdatingPromptTrigger[];
-
-// This metric records how a user interacted with an updating prompt. The values
-// correspond to PasswordFormMetricsRecorder::BubbleDismissalReason.
-extern const char kUkmUpdatingPromptInteraction[];
-
-// This metric records the boolean value indicating whether a password save
-// prompt was shown, which asked the user for permission to save a new
-// credential.
-extern const char kUkmSavingPromptShown[];
-
-// This metric records the reason why a password save prompt was shown to ask
-// the user for permission to save a new credential. The values correspond to
-// PasswordFormMetricsRecorder::BubbleTrigger.
-extern const char kUkmSavingPromptTrigger[];
-
-// This metric records how a user interacted with a saving prompt. The values
-// correspond to PasswordFormMetricsRecorder::BubbleDismissalReason.
-extern const char kUkmSavingPromptInteraction[];
-
-// This metric records attempts to fill a password form. Values correspond to
-// PasswordFormMetricsRecorder::ManagerFillEvent.
-extern const char kUkmManagerFillEvent[];
-
-// This metric records what the user does with a form. Values correspond to the
-// enum UserAction.
-extern const char kUkmUserActionSimplified[];
-
-// This metric records what the user does with all UI entry points of the
-// password manager, like bubbles, context menus, forms, form fields, etc.
-// in relation to a given form. Values correspond to the enum
-// DetailedUserAction. In contrast to kUkmUserActionSimplified, ths metric is
-// intended to be extensible with new user action types.
-extern const char kUkmUserAction[];
-
class FormFetcher;
// The pupose of this class is to record various types of metrics about the
@@ -329,9 +272,6 @@ class PasswordFormMetricsRecorder
int GetHistogramSampleForSuppressedAccounts(
SuppressedAccountExistence best_matching_account) const;
- // Records a metric into |ukm_entry_builder_| if it is not nullptr.
- void RecordUkmMetric(const char* metric_name, int64_t value);
-
// Returns true if an |action| should be recorded multiple times per life-cyle
// of a PasswordFormMetricsRecorder.
static bool IsRepeatedUserAction(DetailedUserAction action);
@@ -379,9 +319,8 @@ class PasswordFormMetricsRecorder
// URL for which UKMs are reported.
GURL main_frame_url_;
- // Records URL keyed metrics (UKMs) and submits them on its destruction. May
- // be a nullptr in which case no recording is expected.
- std::unique_ptr<ukm::UkmEntryBuilder> ukm_entry_builder_;
+ // Holds URL keyed metrics (UKMs) to be recorded on destruction.
+ ukm::builders::PasswordForm ukm_entry_builder_;
// Set of observed user actions that are only recorded once for the lifetime
// of a PasswordFormMetricsRecorder.
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
index b75b0ebe1f1..a503283ce00 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
@@ -11,6 +11,7 @@
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/ukm/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,6 +22,8 @@ namespace {
constexpr char kTestUrl[] = "https://www.example.com/";
+using UkmEntry = ukm::builders::PasswordForm;
+
// Create a UkmEntryBuilder with a SourceId that is initialized for kTestUrl.
scoped_refptr<PasswordFormMetricsRecorder> CreatePasswordFormMetricsRecorder(
bool is_main_frame_secure,
@@ -107,7 +110,7 @@ TEST(PasswordFormMetricsRecorder, Generation) {
}
ExpectUkmValueCount(
- &test_ukm_recorder, kUkmSubmissionObserved,
+ &test_ukm_recorder, UkmEntry::kSubmission_ObservedName,
test.submission !=
PasswordFormMetricsRecorder::kSubmitResultNotSubmitted
? 1
@@ -119,7 +122,8 @@ TEST(PasswordFormMetricsRecorder, Generation) {
: 0;
EXPECT_EQ(expected_login_failed,
user_action_tester.GetActionCount("PasswordManager_LoginFailed"));
- ExpectUkmValueCount(&test_ukm_recorder, kUkmSubmissionResult,
+ ExpectUkmValueCount(&test_ukm_recorder,
+ UkmEntry::kSubmission_SubmissionResultName,
PasswordFormMetricsRecorder::kSubmitResultFailed,
expected_login_failed);
@@ -128,7 +132,8 @@ TEST(PasswordFormMetricsRecorder, Generation) {
: 0;
EXPECT_EQ(expected_login_passed,
user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
- ExpectUkmValueCount(&test_ukm_recorder, kUkmSubmissionResult,
+ ExpectUkmValueCount(&test_ukm_recorder,
+ UkmEntry::kSubmission_SubmissionResultName,
PasswordFormMetricsRecorder::kSubmitResultPassed,
expected_login_passed);
@@ -296,8 +301,8 @@ TEST(PasswordFormMetricsRecorder, Actions) {
const ukm::UkmSource* source = test_ukm_recorder.GetSourceForUrl(kTestUrl);
ASSERT_TRUE(source);
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm",
- kUkmUserActionSimplified,
+ test_ukm_recorder.ExpectMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kUser_ActionSimplifiedName,
static_cast<int64_t>(test.user_action));
}
}
@@ -364,7 +369,8 @@ TEST(PasswordFormMetricsRecorder, SubmittedFormType) {
if (test.form_type !=
PasswordFormMetricsRecorder::kSubmittedFormTypeUnspecified) {
- ExpectUkmValueCount(&test_ukm_recorder, kUkmSubmissionFormType,
+ ExpectUkmValueCount(&test_ukm_recorder,
+ UkmEntry::kSubmission_SubmittedFormTypeName,
test.form_type, 1);
}
@@ -401,39 +407,44 @@ TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
} kTests[] = {
// Source = PasswordManager, Saving.
{metrics_util::CredentialSourceType::kPasswordManager,
- metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING, kUkmSavingPromptTrigger,
+ metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING,
+ UkmEntry::kSaving_Prompt_TriggerName,
Trigger::kPasswordManagerSuggestionAutomatic, true, false},
{metrics_util::CredentialSourceType::kPasswordManager,
- metrics_util::MANUAL_WITH_PASSWORD_PENDING, kUkmSavingPromptTrigger,
+ metrics_util::MANUAL_WITH_PASSWORD_PENDING,
+ UkmEntry::kSaving_Prompt_TriggerName,
Trigger::kPasswordManagerSuggestionManual, true, false},
// Source = PasswordManager, Updating.
{metrics_util::CredentialSourceType::kPasswordManager,
metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING_UPDATE,
- kUkmUpdatingPromptTrigger, Trigger::kPasswordManagerSuggestionAutomatic,
- false, true},
+ UkmEntry::kUpdating_Prompt_TriggerName,
+ Trigger::kPasswordManagerSuggestionAutomatic, false, true},
{metrics_util::CredentialSourceType::kPasswordManager,
metrics_util::MANUAL_WITH_PASSWORD_PENDING_UPDATE,
- kUkmUpdatingPromptTrigger, Trigger::kPasswordManagerSuggestionManual,
- false, true},
+ UkmEntry::kUpdating_Prompt_TriggerName,
+ Trigger::kPasswordManagerSuggestionManual, false, true},
// Source = Credential Management API, Saving.
{metrics_util::CredentialSourceType::kCredentialManagementAPI,
- metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING, kUkmSavingPromptTrigger,
+ metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING,
+ UkmEntry::kSaving_Prompt_TriggerName,
Trigger::kCredentialManagementAPIAutomatic, true, false},
{metrics_util::CredentialSourceType::kCredentialManagementAPI,
- metrics_util::MANUAL_WITH_PASSWORD_PENDING, kUkmSavingPromptTrigger,
+ metrics_util::MANUAL_WITH_PASSWORD_PENDING,
+ UkmEntry::kSaving_Prompt_TriggerName,
Trigger::kCredentialManagementAPIManual, true, false},
// Source = Credential Management API, Updating.
{metrics_util::CredentialSourceType::kCredentialManagementAPI,
metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING_UPDATE,
- kUkmUpdatingPromptTrigger, Trigger::kCredentialManagementAPIAutomatic,
- false, true},
+ UkmEntry::kUpdating_Prompt_TriggerName,
+ Trigger::kCredentialManagementAPIAutomatic, false, true},
{metrics_util::CredentialSourceType::kCredentialManagementAPI,
metrics_util::MANUAL_WITH_PASSWORD_PENDING_UPDATE,
- kUkmUpdatingPromptTrigger, Trigger::kCredentialManagementAPIManual,
- false, true},
+ UkmEntry::kUpdating_Prompt_TriggerName,
+ Trigger::kCredentialManagementAPIManual, false, true},
// Source = Unknown, Saving.
{metrics_util::CredentialSourceType::kUnknown,
- metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING, kUkmSavingPromptTrigger,
+ metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING,
+ UkmEntry::kSaving_Prompt_TriggerName,
Trigger::kPasswordManagerSuggestionAutomatic, false, false},
};
@@ -455,19 +466,20 @@ TEST(PasswordFormMetricsRecorder, RecordPasswordBubbleShown) {
if (test.credential_source_type !=
metrics_util::CredentialSourceType::kUnknown) {
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", test.expected_trigger_metric,
+ *source, UkmEntry::kEntryName, test.expected_trigger_metric,
static_cast<int64_t>(test.expected_trigger_value));
} else {
- EXPECT_FALSE(test_ukm_recorder.HasMetric(*source, "PasswordForm",
- kUkmSavingPromptTrigger));
- EXPECT_FALSE(test_ukm_recorder.HasMetric(*source, "PasswordForm",
- kUkmUpdatingPromptTrigger));
+ EXPECT_FALSE(test_ukm_recorder.HasMetric(
+ *source, UkmEntry::kEntryName, UkmEntry::kSaving_Prompt_TriggerName));
+ EXPECT_FALSE(
+ test_ukm_recorder.HasMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kUpdating_Prompt_TriggerName));
}
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm",
- kUkmSavingPromptShown,
+ test_ukm_recorder.ExpectMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kSaving_Prompt_ShownName,
test.expected_save_prompt_shown);
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm",
- kUkmUpdatingPromptShown,
+ test_ukm_recorder.ExpectMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kUpdating_Prompt_ShownName,
test.expected_update_prompt_shown);
}
}
@@ -482,16 +494,17 @@ TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
PasswordFormMetricsRecorder::BubbleDismissalReason expected_metric_value;
} kTests[] = {
{metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING,
- metrics_util::CLICKED_SAVE, kUkmSavingPromptInteraction,
+ metrics_util::CLICKED_SAVE, UkmEntry::kSaving_Prompt_InteractionName,
PasswordFormMetricsRecorder::BubbleDismissalReason::kAccepted},
{metrics_util::MANUAL_WITH_PASSWORD_PENDING, metrics_util::CLICKED_CANCEL,
- kUkmSavingPromptInteraction,
+ UkmEntry::kSaving_Prompt_InteractionName,
PasswordFormMetricsRecorder::BubbleDismissalReason::kDeclined},
{metrics_util::AUTOMATIC_WITH_PASSWORD_PENDING_UPDATE,
- metrics_util::CLICKED_NEVER, kUkmUpdatingPromptInteraction,
+ metrics_util::CLICKED_NEVER, UkmEntry::kUpdating_Prompt_InteractionName,
PasswordFormMetricsRecorder::BubbleDismissalReason::kDeclined},
{metrics_util::MANUAL_WITH_PASSWORD_PENDING_UPDATE,
- metrics_util::NO_DIRECT_INTERACTION, kUkmUpdatingPromptInteraction,
+ metrics_util::NO_DIRECT_INTERACTION,
+ UkmEntry::kUpdating_Prompt_InteractionName,
PasswordFormMetricsRecorder::BubbleDismissalReason::kIgnored},
};
@@ -512,7 +525,7 @@ TEST(PasswordFormMetricsRecorder, RecordUIDismissalReason) {
const ukm::UkmSource* source = test_ukm_recorder.GetSourceForUrl(kTestUrl);
ASSERT_TRUE(source);
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", test.expected_trigger_metric,
+ *source, UkmEntry::kEntryName, test.expected_trigger_metric,
static_cast<int64_t>(test.expected_metric_value));
}
}
@@ -542,20 +555,20 @@ TEST(PasswordFormMetricsRecorder, SequencesOfBubbles) {
const ukm::UkmSource* source = test_ukm_recorder.GetSourceForUrl(kTestUrl);
ASSERT_TRUE(source);
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", kUkmSavingPromptInteraction,
+ *source, UkmEntry::kEntryName, UkmEntry::kSaving_Prompt_InteractionName,
static_cast<int64_t>(BubbleDismissalReason::kAccepted));
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", kUkmUpdatingPromptInteraction,
+ *source, UkmEntry::kEntryName, UkmEntry::kUpdating_Prompt_InteractionName,
static_cast<int64_t>(BubbleDismissalReason::kAccepted));
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm",
- kUkmUpdatingPromptShown, 1);
- test_ukm_recorder.ExpectMetric(*source, "PasswordForm", kUkmSavingPromptShown,
- 1);
+ test_ukm_recorder.ExpectMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kUpdating_Prompt_ShownName, 1);
+ test_ukm_recorder.ExpectMetric(*source, UkmEntry::kEntryName,
+ UkmEntry::kSaving_Prompt_ShownName, 1);
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", kUkmSavingPromptTrigger,
+ *source, UkmEntry::kEntryName, UkmEntry::kSaving_Prompt_TriggerName,
static_cast<int64_t>(BubbleTrigger::kPasswordManagerSuggestionAutomatic));
test_ukm_recorder.ExpectMetric(
- *source, "PasswordForm", kUkmUpdatingPromptTrigger,
+ *source, UkmEntry::kEntryName, UkmEntry::kUpdating_Prompt_TriggerName,
static_cast<int64_t>(BubbleTrigger::kPasswordManagerSuggestionManual));
}
@@ -577,7 +590,8 @@ TEST(PasswordFormMetricsRecorder, RecordDetailedUserAction) {
}
const ukm::UkmSource* source = test_ukm_recorder.GetSourceForUrl(kTestUrl);
ASSERT_TRUE(source);
- test_ukm_recorder.ExpectMetrics(*source, "PasswordForm", kUkmUserAction,
+ test_ukm_recorder.ExpectMetrics(*source, UkmEntry::kEntryName,
+ UkmEntry::kUser_ActionName,
{static_cast<int64_t>(kOneTimeAction),
static_cast<int64_t>(kRepeatedAction),
static_cast<int64_t>(kRepeatedAction)});
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
index 9a08022a83e..b7c7202592c 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
@@ -46,7 +46,7 @@ class TestPasswordManagerDriver : public StubPasswordManagerDriver {
explicit TestPasswordManagerDriver(PasswordManagerClient* client)
: password_manager_(client),
password_generation_manager_(client, this),
- password_autofill_manager_(this, nullptr) {}
+ password_autofill_manager_(this, nullptr, client) {}
~TestPasswordManagerDriver() override {}
// PasswordManagerDriver implementation.
@@ -70,6 +70,7 @@ class TestPasswordManagerDriver : public StubPasswordManagerDriver {
}
MOCK_METHOD0(AllowToRunFormClassifier, void());
+ MOCK_METHOD0(MatchingBlacklistedFormFound, void());
private:
PasswordManager password_manager_;
@@ -245,7 +246,7 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
- autofill::FormStructure::ParseQueryResponse(response_string, forms, NULL);
+ autofill::FormStructure::ParseQueryResponse(response_string, forms);
DetectFormsEligibleForGeneration(forms);
EXPECT_EQ(2u, GetTestDriver()->GetFoundEligibleForGenerationForms().size());
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index 2c1f81b2557..24702a272bb 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -137,6 +137,62 @@ bool AreAllFieldsEmpty(const PasswordForm& form) {
form.new_password_value.empty();
}
+// Helper function that determines whether update or save prompt should be
+// shown for credentials in |provisional_save_manager|.
+bool IsPasswordUpdate(const PasswordFormManager& provisional_save_manager) {
+ return (!provisional_save_manager.best_matches().empty() &&
+ provisional_save_manager
+ .is_possible_change_password_form_without_username()) ||
+ provisional_save_manager.password_overridden() ||
+ provisional_save_manager.retry_password_form_password_update();
+}
+
+// Finds the matched form manager for |form| in |pending_login_managers|.
+PasswordFormManager* FindMatchedManager(
+ const autofill::PasswordForm& form,
+ const std::vector<std::unique_ptr<PasswordFormManager>>&
+ pending_login_managers,
+ const password_manager::PasswordManagerDriver* driver,
+ BrowserSavePasswordProgressLogger* logger) {
+ auto matched_manager_it = pending_login_managers.end();
+ PasswordFormManager::MatchResultMask current_match_result =
+ PasswordFormManager::RESULT_NO_MATCH;
+ // Below, "matching" is in DoesManage-sense and "not ready" in the sense of
+ // FormFetcher being ready. We keep track of such PasswordFormManager
+ // instances for UMA.
+ for (auto iter = pending_login_managers.begin();
+ iter != pending_login_managers.end(); ++iter) {
+ PasswordFormManager::MatchResultMask result =
+ (*iter)->DoesManage(form, driver);
+
+ if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
+ // If we find a manager that exactly matches the submitted form including
+ // the action URL, exit the loop.
+ if (logger)
+ logger->LogMessage(Logger::STRING_EXACT_MATCH);
+ matched_manager_it = iter;
+ break;
+ }
+
+ if (result > current_match_result) {
+ current_match_result = result;
+ matched_manager_it = iter;
+
+ if (logger) {
+ if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
+ ~PasswordFormManager::RESULT_ACTION_MATCH))
+ logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
+ if (IsSignupForm(form))
+ logger->LogMessage(Logger::STRING_ORIGINS_MATCH);
+ }
+ }
+ }
+
+ return matched_manager_it == pending_login_managers.end()
+ ? nullptr
+ : matched_manager_it->get();
+}
+
} // namespace
// static
@@ -289,84 +345,21 @@ void PasswordManager::ProvisionallySavePassword(
return;
}
- auto matched_manager_it = pending_login_managers_.end();
- PasswordFormManager::MatchResultMask current_match_result =
- PasswordFormManager::RESULT_NO_MATCH;
- // Below, "matching" is in DoesManage-sense and "not ready" in the sense of
- // FormFetcher being ready. We keep track of such PasswordFormManager
- // instances for UMA.
- for (auto iter = pending_login_managers_.begin();
- iter != pending_login_managers_.end(); ++iter) {
- PasswordFormManager::MatchResultMask result =
- (*iter)->DoesManage(form, driver);
-
- if (result == PasswordFormManager::RESULT_NO_MATCH)
- continue;
-
- (*iter)->SetSubmittedForm(form);
+ PasswordFormManager* matched_manager =
+ FindMatchedManager(form, pending_login_managers_, driver, logger.get());
- if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
- // If we find a manager that exactly matches the submitted form including
- // the action URL, exit the loop.
- if (logger)
- logger->LogMessage(Logger::STRING_EXACT_MATCH);
- matched_manager_it = iter;
- break;
- } else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
- ~PasswordFormManager::RESULT_ACTION_MATCH) &&
- result > current_match_result) {
- // If the current manager matches the submitted form excluding the action
- // URL, remember it as a candidate and continue searching for an exact
- // match. See http://crbug.com/27246 for an example where actions can
- // change.
- if (logger)
- logger->LogMessage(Logger::STRING_MATCH_WITHOUT_ACTION);
- matched_manager_it = iter;
- current_match_result = result;
- } else if (IsSignupForm(form) && result > current_match_result) {
- // Signup forms don't require HTML attributes to match because we don't
- // need to fill these saved passwords on the same form in the future.
- // Prefer the best possible match (e.g. action and origins match instead
- // or just origin matching). Don't break in case there exists a better
- // match.
- // TODO(gcasto): Matching in this way is very imprecise. Having some
- // better way to match the same form when the HTML elements change (e.g.
- // text element changed to password element) would be useful.
- if (logger)
- logger->LogMessage(Logger::STRING_ORIGINS_MATCH);
- matched_manager_it = iter;
- current_match_result = result;
- }
- }
// If we didn't find a manager, this means a form was submitted without
// first loading the page containing the form. Don't offer to save
// passwords in this case.
- if (matched_manager_it == pending_login_managers_.end()) {
+ if (!matched_manager) {
client_->GetMetricsRecorder().RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::NO_MATCHING_FORM, main_frame_url_,
form.origin, logger.get());
return;
}
+ matched_manager->SaveSubmittedFormTypeForMetrics(form);
- std::unique_ptr<PasswordFormManager> manager = (*matched_manager_it)->Clone();
-
- PasswordForm submitted_form(form);
- submitted_form.preferred = true;
- if (logger) {
- logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
- submitted_form);
- }
- PasswordFormManager::OtherPossibleUsernamesAction action =
- PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
- if (OtherPossibleUsernamesEnabled())
- action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
- if (logger) {
- logger->LogBoolean(
- Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
- action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- }
- manager->ProvisionallySave(submitted_form, action);
- provisional_save_manager_.swap(manager);
+ ProvisionallySaveManager(form, matched_manager, logger.get());
// Cache the user-visible URL (i.e., the one seen in the omnibox). Once the
// post-submit navigation concludes, we compare the landing URL against the
@@ -463,6 +456,37 @@ void PasswordManager::OnPasswordFormForceSaveRequested(
OnLoginSuccessful();
}
+void PasswordManager::ShowManualFallbackForSaving(
+ password_manager::PasswordManagerDriver* driver,
+ const PasswordForm& password_form) {
+ if (!client_->IsSavingAndFillingEnabledForCurrentPage() ||
+ ShouldBlockPasswordForSameOriginButDifferentScheme(password_form))
+ return;
+
+ PasswordFormManager* matched_manager = FindMatchedManager(
+ password_form, pending_login_managers_, driver, nullptr);
+ if (!matched_manager)
+ return;
+ // TODO(crbug.com/741537): Process manual saving request even if there is
+ // still no response from the store.
+ if (matched_manager->form_fetcher()->GetState() ==
+ FormFetcher::State::WAITING) {
+ return;
+ }
+ ProvisionallySaveManager(password_form, matched_manager, nullptr);
+
+ DCHECK(provisional_save_manager_);
+ bool is_update = IsPasswordUpdate(*provisional_save_manager_);
+ bool has_generated_password =
+ provisional_save_manager_->has_generated_password();
+ client_->ShowManualFallbackForSaving(std::move(provisional_save_manager_),
+ has_generated_password, is_update);
+}
+
+void PasswordManager::HideManualFallbackForSaving() {
+ client_->HideManualFallbackForSaving();
+}
+
void PasswordManager::OnPasswordFormsParsed(
password_manager::PasswordManagerDriver* driver,
const std::vector<PasswordForm>& forms) {
@@ -540,6 +564,36 @@ void PasswordManager::CreatePendingLoginManagers(
}
}
+bool PasswordManager::OtherPossibleUsernamesEnabled() const {
+ return false;
+}
+
+void PasswordManager::ProvisionallySaveManager(
+ const PasswordForm& form,
+ PasswordFormManager* matched_manager,
+ BrowserSavePasswordProgressLogger* logger) {
+ DCHECK(matched_manager);
+ std::unique_ptr<PasswordFormManager> manager = matched_manager->Clone();
+
+ PasswordForm submitted_form(form);
+ submitted_form.preferred = true;
+ if (logger) {
+ logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
+ submitted_form);
+ }
+ PasswordFormManager::OtherPossibleUsernamesAction action =
+ PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
+ if (OtherPossibleUsernamesEnabled())
+ action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
+ if (logger) {
+ logger->LogBoolean(
+ Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
+ action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ }
+ manager->ProvisionallySave(submitted_form, action);
+ provisional_save_manager_.swap(manager);
+}
+
bool PasswordManager::CanProvisionalManagerSave() {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
@@ -746,12 +800,7 @@ void PasswordManager::OnLoginSuccessful() {
empty_password);
if (logger)
logger->LogMessage(Logger::STRING_DECISION_ASK);
- bool update_password =
- (!provisional_save_manager_->best_matches().empty() &&
- provisional_save_manager_
- ->is_possible_change_password_form_without_username()) ||
- provisional_save_manager_->password_overridden() ||
- provisional_save_manager_->retry_password_form_password_update();
+ bool update_password = IsPasswordUpdate(*provisional_save_manager_);
if (client_->PromptUserToSaveOrUpdatePassword(
std::move(provisional_save_manager_), update_password)) {
if (logger)
@@ -775,10 +824,6 @@ void PasswordManager::OnLoginSuccessful() {
}
}
-bool PasswordManager::OtherPossibleUsernamesEnabled() const {
- return false;
-}
-
void PasswordManager::Autofill(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& form_for_autofill,
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index 68281080eb8..fe7a21ba58a 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -33,6 +33,7 @@ class FormStructure;
namespace password_manager {
+class BrowserSavePasswordProgressLogger;
class PasswordManagerClient;
class PasswordManagerDriver;
class PasswordFormManager;
@@ -153,6 +154,15 @@ class PasswordManager : public LoginModel {
password_manager::PasswordManagerDriver* driver,
const autofill::PasswordForm& password_form);
+ // Handles a request to show manual fallback for password saving, i.e. the
+ // omnibox icon with the anchored hidden prompt.
+ void ShowManualFallbackForSaving(
+ password_manager::PasswordManagerDriver* driver,
+ const autofill::PasswordForm& password_form);
+
+ // Handles a request to hide manual fallback for password saving.
+ void HideManualFallbackForSaving();
+
// Called if |password_form| was filled upon in-page navigation. This often
// means history.pushState being called from JavaScript. If this causes false
// positive in password saving, update http://crbug.com/357696.
@@ -194,6 +204,12 @@ class PasswordManager : public LoginModel {
// the username for the form is ambigious.
bool OtherPossibleUsernamesEnabled() const;
+ // Clones |matched_manager| and keeps it as |provisional_save_manager_|.
+ // |form| is saved provisionally to |provisional_save_manager_|.
+ void ProvisionallySaveManager(const autofill::PasswordForm& form,
+ PasswordFormManager* matched_manager,
+ BrowserSavePasswordProgressLogger* logger);
+
// Returns true if |provisional_save_manager_| is ready for saving and
// non-blacklisted.
bool CanProvisionalManagerSave();
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 6ed6f1e7a8e..ead9e485d92 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -15,6 +15,10 @@ bool PasswordManagerClient::IsFillingEnabledForCurrentPage() const {
return true;
}
+bool PasswordManagerClient::IsFillingFallbackEnabledForCurrentPage() const {
+ return true;
+}
+
void PasswordManagerClient::PostHSTSQueryForHost(
const GURL& origin,
const HSTSCallback& callback) const {
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 58bc5ed1cfb..7d45719bb23 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -62,6 +62,9 @@ class PasswordManagerClient {
// password manager is disabled, or in the presence of SSL errors on a page.
virtual bool IsFillingEnabledForCurrentPage() const;
+ // Checks if manual filling fallback is enabled for the current page.
+ virtual bool IsFillingFallbackEnabledForCurrentPage() const;
+
// Checks asynchronously whether HTTP Strict Transport Security (HSTS) is
// active for the host of the given origin. Notifies |callback| with the
// result on the calling thread.
@@ -94,7 +97,18 @@ class PasswordManagerClient {
// that was overidden.
virtual bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> form_to_save,
- bool update_password) = 0;
+ bool is_update) = 0;
+
+ // Informs the embedder that the user started typing a password and a password
+ // prompt should be available on click on the omnibox icon.
+ virtual void ShowManualFallbackForSaving(
+ std::unique_ptr<PasswordFormManager> form_to_save,
+ bool has_generated_password,
+ bool is_update) = 0;
+
+ // Informs the embedder that the user cleared the password field and the
+ // fallback for password saving should be not available.
+ virtual void HideManualFallbackForSaving() = 0;
// Informs the embedder of a password forms that the user should choose from.
// Returns true if the prompt is indeed displayed. If the prompt is not
@@ -205,16 +219,23 @@ class PasswordManagerClient {
virtual safe_browsing::PasswordProtectionService*
GetPasswordProtectionService() const = 0;
- // Checks the safe browsing reputation of the webpage where the focused
- // username/password field is on.
+ // Checks the safe browsing reputation of the webpage when the
+ // user focuses on a username/password field. This is used for reporting
+ // only, and won't trigger a warning.
virtual void CheckSafeBrowsingReputation(const GURL& form_action,
const GURL& frame_url) = 0;
// Checks the safe browsing reputation of the webpage where password reuse
- // happens.
+ // happens. This is called by the PasswordReuseDetectionManager when either
+ // the sync password or a saved password is typed on the wrong domain.
+ // This may trigger a warning dialog if it looks like the page is phishy.
virtual void CheckProtectedPasswordEntry(
- const std::string& password_saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
bool password_field_exists) = 0;
+
+ // Records a Chrome Sync event that sync password reuse was detected.
+ virtual void LogPasswordReuseDetectedEvent() = 0;
#endif
// Gets the UKM service associated with this client (for metrics).
diff --git a/chromium/components/password_manager/core/browser/password_manager_driver.h b/chromium/components/password_manager/core/browser/password_manager_driver.h
index af6551c4256..2689afaf618 100644
--- a/chromium/components/password_manager/core/browser/password_manager_driver.h
+++ b/chromium/components/password_manager/core/browser/password_manager_driver.h
@@ -78,6 +78,14 @@ class PasswordManagerDriver
// the corresponding password form, so that it can be saved.
virtual void ForceSavePassword() {}
+ // Tells the driver to show the manual fallback for password saving, i.e. to
+ // show the omnibox icon with anchored hidden save prompt.
+ virtual void ShowManualFallbackForSaving(const autofill::PasswordForm& form) {
+ }
+
+ // Tells the driver to hide the manual fallback for saving.
+ virtual void HideManualFallbackForSaving() {}
+
// Tells the driver to find the focused password field and to show generation
// popup at it.
virtual void GeneratePassword() {}
@@ -104,6 +112,9 @@ class PasswordManagerDriver
// Return true iff the driver corresponds to the main frame.
virtual bool IsMainFrame() const = 0;
+ // Tells the driver that the matching blacklisted form was found.
+ virtual void MatchingBlacklistedFormFound() = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerDriver);
};
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
index 14d2026fd06..b92e79a28c0 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
@@ -18,6 +18,7 @@ namespace password_manager {
// URL Keyed Metrics.
const char kUkmUserModifiedPasswordField[] = "UserModifiedPasswordField";
const char kUkmProvisionalSaveFailure[] = "ProvisionalSaveFailure";
+const char kUkmPageLevelUserAction[] = "PageLevelUserAction";
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
ukm::UkmRecorder* ukm_recorder,
@@ -96,6 +97,11 @@ void PasswordManagerMetricsRecorder::RecordProvisionalSaveFailure(
}
}
+void PasswordManagerMetricsRecorder::RecordPageLevelUserAction(
+ PasswordManagerMetricsRecorder::PageLevelUserAction action) {
+ RecordUkmMetric(kUkmPageLevelUserAction, static_cast<int64_t>(action));
+}
+
void PasswordManagerMetricsRecorder::RecordUkmMetric(const char* metric_name,
int64_t value) {
if (ukm_entry_builder_)
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
index 8b95daa8897..551f4ebbdf7 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
@@ -28,6 +28,9 @@ extern const char kUkmUserModifiedPasswordField[];
// offer to save a credential.
extern const char kUkmProvisionalSaveFailure[];
+// UKM that records a PasswordManagerMetricsRecorder::PageLevelUserAction.
+extern const char kUkmPageLevelUserAction[];
+
class BrowserSavePasswordProgressLogger;
// The pupose of this class is to record various types of metrics about the
@@ -62,6 +65,16 @@ class PasswordManagerMetricsRecorder {
MAX_FAILURE_VALUE
};
+ // This enum represents user actions on a page with a password form that
+ // cannot (reliably) be attributed to a specific form manager.
+ enum class PageLevelUserAction {
+ kUnknown = 0,
+
+ // User chose to open the password viewer as part of a manual fallback.
+ kShowAllPasswordsWhileSomeAreSuggested,
+ kShowAllPasswordsWhileNoneAreSuggested,
+ };
+
// Records UKM metrics and reports them on destruction. The |source_id| is
// (re-)bound to |main_frame_url| shortly before reporting. As such it is
// crucial that the |source_id| is never bound to a different URL by another
@@ -92,6 +105,9 @@ class PasswordManagerMetricsRecorder {
const GURL& form_origin,
BrowserSavePasswordProgressLogger* logger);
+ // Records a user action.
+ void RecordPageLevelUserAction(PageLevelUserAction action);
+
private:
// Records a metric into |ukm_entry_builder_| if it is not nullptr.
void RecordUkmMetric(const char* metric_name, int64_t value);
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 3dc8207fd38..8ddf90ccd11 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
@@ -178,6 +178,19 @@ void LogShowedFormNotSecureWarningOnCurrentNavigation() {
"PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation", true);
}
+void LogContextOfShowAllSavedPasswordsShown(
+ ShowAllSavedPasswordsContext context) {
+ UMA_HISTOGRAM_ENUMERATION("PasswordManager.ShowAllSavedPasswordsShownContext",
+ context, SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT);
+}
+
+void LogContextOfShowAllSavedPasswordsAccepted(
+ ShowAllSavedPasswordsContext context) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "PasswordManager.ShowAllSavedPasswordsAcceptedContext", context,
+ SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT);
+}
+
void LogPasswordSuccessfulSubmissionIndicatorEvent(
autofill::PasswordForm::SubmissionIndicatorEvent event) {
UMA_HISTOGRAM_ENUMERATION(
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 5605db72859..aa247738779 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
@@ -242,6 +242,23 @@ enum class IsSyncPasswordHashSaved {
};
#endif
+// Specifies the context in which the "Show all saved passwords" fallback is
+// shown or accepted.
+// Metrics:
+// - PasswordManager.ShowAllSavedPasswordsAcceptedContext
+// - PasswordManager.ShowAllSavedPasswordsShownContext
+enum ShowAllSavedPasswordsContext {
+ SHOW_ALL_SAVED_PASSWORDS_CONTEXT_NONE,
+ // The "Show all saved passwords..." fallback is shown below a list of
+ // available passwords.
+ SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD,
+ // The "Show all saved passwords..." fallback is shown when no available
+ // passwords can be suggested to the user, e.g. because none are saved or
+ // because of technical issues.
+ SHOW_ALL_SAVED_PASSWORDS_CONTEXT_MANUAL_FALLBACK,
+ SHOW_ALL_SAVED_PASSWORDS_CONTEXT_COUNT
+};
+
// A version of the UMA_HISTOGRAM_BOOLEAN macro that allows the |name|
// to vary over the program's runtime.
void LogUMAHistogramBoolean(const std::string& name, bool sample);
@@ -319,6 +336,15 @@ void LogShowedHttpNotSecureExplanation();
// per main-frame navigation.
void LogShowedFormNotSecureWarningOnCurrentNavigation();
+// Log the context in which the "Show all saved passwords" fallback was shown.
+void LogContextOfShowAllSavedPasswordsShown(
+ ShowAllSavedPasswordsContext context);
+
+// Log the context in which the "Show all saved passwords" fallback was
+// accepted.
+void LogContextOfShowAllSavedPasswordsAccepted(
+ ShowAllSavedPasswordsContext context);
+
// Log a password successful submission event.
void LogPasswordSuccessfulSubmissionIndicatorEvent(
autofill::PasswordForm::SubmissionIndicatorEvent event);
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 8eb289b508e..00252a67a1d 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
@@ -17,20 +17,12 @@ using autofill::PasswordForm;
namespace password_manager {
-const char kTestingIconUrlSpec[] = "https://accounts.google.com/Icon";
-const char kTestingFederationUrlSpec[] = "https://accounts.google.com/login";
-const int kTestingDaysAfterPasswordsAreSynced = 1;
-const wchar_t kTestingFederatedLoginMarker[] = L"__federated__";
-
-std::unique_ptr<PasswordForm> CreatePasswordFormFromDataForTesting(
+std::unique_ptr<PasswordForm> PasswordFormFromData(
const PasswordFormData& form_data) {
- std::unique_ptr<PasswordForm> form(new PasswordForm());
+ auto form = base::MakeUnique<PasswordForm>();
form->scheme = form_data.scheme;
form->preferred = form_data.preferred;
form->date_created = base::Time::FromDoubleT(form_data.creation_time);
- form->date_synced =
- form->date_created +
- base::TimeDelta::FromDays(kTestingDaysAfterPasswordsAreSynced);
if (form_data.signon_realm)
form->signon_realm = std::string(form_data.signon_realm);
if (form_data.origin)
@@ -43,19 +35,28 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromDataForTesting(
form->username_element = base::WideToUTF16(form_data.username_element);
if (form_data.password_element)
form->password_element = base::WideToUTF16(form_data.password_element);
- if (form_data.username_value) {
+ if (form_data.username_value)
form->username_value = base::WideToUTF16(form_data.username_value);
+ if (form_data.password_value)
+ form->password_value = base::WideToUTF16(form_data.password_value);
+ return form;
+}
+
+std::unique_ptr<PasswordForm> FillPasswordFormWithData(
+ const PasswordFormData& form_data,
+ bool use_federated_login) {
+ auto form = PasswordFormFromData(form_data);
+ form->date_synced = form->date_created + base::TimeDelta::FromDays(1);
+ if (form_data.username_value)
form->display_name = form->username_value;
- if (form_data.password_value) {
- if (wcscmp(form_data.password_value, kTestingFederatedLoginMarker) == 0)
- form->federation_origin = url::Origin(GURL(kTestingFederationUrlSpec));
- else
- form->password_value = base::WideToUTF16(form_data.password_value);
- }
- } else {
+ else
form->blacklisted_by_user = true;
+ form->icon_url = GURL("https://accounts.google.com/Icon");
+ if (use_federated_login) {
+ form->password_value.clear();
+ form->federation_origin =
+ url::Origin(GURL("https://accounts.google.com/login"));
}
- form->icon_url = GURL(kTestingIconUrlSpec);
return form;
}
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 893c75f7137..8e877c295d5 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
@@ -32,16 +32,6 @@ scoped_refptr<RefcountedKeyedService> BuildPasswordStore(Context* context) {
return store;
}
-// These constants are used by CreatePasswordFormFromDataForTesting to supply
-// values not covered by PasswordFormData.
-extern const char kTestingIconUrlSpec[];
-extern const char kTestingFederationUrlSpec[];
-extern const int kTestingDaysAfterPasswordsAreSynced;
-
-// Magic value for PasswordFormData::password_value to indicate a federated
-// login.
-extern const wchar_t kTestingFederatedLoginMarker[];
-
// Struct used for creation of PasswordForms from static arrays of data.
// Note: This is only meant to be used in unit test.
struct PasswordFormData {
@@ -58,10 +48,18 @@ struct PasswordFormData {
const double creation_time;
};
-// Creates and returns a new PasswordForm built from form_data.
-std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromDataForTesting(
+// Creates and returns a new PasswordForm built from |form_data|.
+std::unique_ptr<autofill::PasswordForm> PasswordFormFromData(
const PasswordFormData& form_data);
+// Like PasswordFormFromData(), but also fills arbitrary values into fields not
+// specified by |form_data|. This may be useful e.g. for tests looking to
+// verify the handling of these fields. If |use_federated_login| is true, this
+// function will set the form's |federation_origin|.
+std::unique_ptr<autofill::PasswordForm> FillPasswordFormWithData(
+ const PasswordFormData& form_data,
+ bool use_federated_login = false);
+
// Convenience method that wraps the passed in forms in unique ptrs and returns
// the result.
std::vector<std::unique_ptr<autofill::PasswordForm>> WrapForms(
@@ -99,7 +97,7 @@ class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
~MockPasswordReuseDetectorConsumer() override;
MOCK_METHOD4(OnReuseFound,
- void(const base::string16&, const std::string&, int, int));
+ void(size_t, bool, const std::vector<std::string>&, int));
};
#endif
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 485458a8e53..536e505641f 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -62,9 +62,12 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
MOCK_CONST_METHOD0(DidLastPageLoadEncounterSSLErrors, bool());
MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
- // The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr owns
- // the PasswordFormManager* argument.
+ // The code inside EXPECT_CALL for PromptUserToSaveOrUpdatePasswordPtr and
+ // ShowManualFallbackForSavingPtr owns the PasswordFormManager* argument.
MOCK_METHOD1(PromptUserToSaveOrUpdatePasswordPtr, void(PasswordFormManager*));
+ MOCK_METHOD3(ShowManualFallbackForSavingPtr,
+ void(PasswordFormManager*, bool, bool));
+ MOCK_METHOD0(HideManualFallbackForSaving, void());
MOCK_METHOD1(NotifySuccessfulLoginWithExistingPassword,
void(const autofill::PasswordForm&));
MOCK_METHOD0(AutomaticPasswordSaveIndicator, void());
@@ -80,6 +83,12 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
PromptUserToSaveOrUpdatePasswordPtr(manager.release());
return false;
}
+ void ShowManualFallbackForSaving(std::unique_ptr<PasswordFormManager> manager,
+ bool has_generated_password,
+ bool is_update) override {
+ ShowManualFallbackForSavingPtr(manager.release(), has_generated_password,
+ is_update);
+ }
void AutomaticPasswordSave(
std::unique_ptr<PasswordFormManager> manager) override {
AutomaticPasswordSaveIndicator();
@@ -135,7 +144,7 @@ class PasswordManagerTest : public testing::Test {
manager_.reset(new PasswordManager(&client_));
password_autofill_manager_.reset(
- new PasswordAutofillManager(client_.GetDriver(), nullptr));
+ new PasswordAutofillManager(client_.GetDriver(), nullptr, &client_));
EXPECT_CALL(driver_, GetPasswordManager())
.WillRepeatedly(Return(manager_.get()));
@@ -158,10 +167,11 @@ class PasswordManagerTest : public testing::Test {
form.action = GURL("http://www.google.com/a/Login");
form.username_element = ASCIIToUTF16("Email");
form.password_element = ASCIIToUTF16("Passwd");
- form.username_value = ASCIIToUTF16("google");
- form.password_value = ASCIIToUTF16("password");
+ form.username_value = ASCIIToUTF16("googleuser");
+ form.password_value = ASCIIToUTF16("p4ssword");
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = "http://www.google.com";
+ form.form_data.name = ASCIIToUTF16("the-form-name");
return form;
}
@@ -371,6 +381,112 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
form_manager_to_save->Save();
}
+TEST_F(PasswordManagerTest, BestMatchFormToManager) {
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
+
+ std::vector<PasswordForm> observed;
+ // Observe the form that will be submitted.
+ PasswordForm form(MakeSimpleForm());
+
+ // This form is different from the on that will be submitted.
+ PasswordForm no_match_form(MakeSimpleForm());
+ no_match_form.form_data.name = ASCIIToUTF16("another-name");
+ no_match_form.action = GURL("http://www.google.com/somethingelse");
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("another-field-name");
+ no_match_form.form_data.fields.push_back(field);
+
+ observed.push_back(no_match_form);
+ observed.push_back(form);
+
+ // Simulate observing forms after navigation the page.
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+ // The form is modified before being submitted and does not match perfectly.
+ // Out of the criteria {name, action, signature}, we keep the signature the
+ // same and change the rest.
+ PasswordForm changed_form(form);
+ changed_form.username_element = ASCIIToUTF16("changed-name");
+ changed_form.action = GURL("http://www.google.com/changed-action");
+ OnPasswordFormSubmitted(changed_form);
+ EXPECT_EQ(CalculateFormSignature(form.form_data),
+ CalculateFormSignature(changed_form.form_data));
+
+ std::unique_ptr<PasswordFormManager> form_manager_to_save;
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+
+ // Now the password manager waits for the navigation to complete.
+ observed.clear();
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // Verify that PasswordFormManager to be save owns the correct pair of
+ // observed and submitted forms.
+ EXPECT_EQ(form.action, form_manager_to_save->observed_form().action);
+ EXPECT_EQ(form.form_data.name,
+ form_manager_to_save->observed_form().form_data.name);
+ EXPECT_EQ(changed_form.action,
+ form_manager_to_save->submitted_form()->action);
+ EXPECT_EQ(changed_form.form_data.name,
+ form_manager_to_save->submitted_form()->form_data.name);
+}
+
+// As long as the is a PasswordFormManager that matches the origin, we should
+// not fail to match a submitted PasswordForm to a PasswordFormManager.
+TEST_F(PasswordManagerTest, AnyMatchFormToManager) {
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
+
+ // Observe the form that will be submitted.
+ std::vector<PasswordForm> observed;
+ PasswordForm form(MakeSimpleForm());
+ observed.push_back(form);
+
+ // Simulate observing forms after navigation the page.
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+ // The form is modified before being submitted and does not match perfectly.
+ // We change all of the criteria: {name, action, signature}.
+ PasswordForm changed_form(form);
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("another-field-name");
+ changed_form.form_data.fields.push_back(field);
+ changed_form.username_element = ASCIIToUTF16("changed-name");
+ changed_form.action = GURL("http://www.google.com/changed-action");
+ OnPasswordFormSubmitted(changed_form);
+ EXPECT_NE(CalculateFormSignature(form.form_data),
+ CalculateFormSignature(changed_form.form_data));
+
+ std::unique_ptr<PasswordFormManager> form_manager_to_save;
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+
+ // Now the password manager waits for the navigation to complete.
+ observed.clear();
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // Verify that we matched the form to a PasswordFormManager, although with the
+ // worst possible match.
+ EXPECT_EQ(form.action, form_manager_to_save->observed_form().action);
+ EXPECT_EQ(form.form_data.name,
+ form_manager_to_save->observed_form().form_data.name);
+ EXPECT_EQ(changed_form.action,
+ form_manager_to_save->submitted_form()->action);
+ EXPECT_EQ(changed_form.form_data.name,
+ form_manager_to_save->submitted_form()->form_data.name);
+}
+
TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
@@ -1809,4 +1925,109 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
}
#endif
+TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+
+ std::vector<PasswordForm> observed;
+ PasswordForm form(MakeSimpleForm());
+ observed.push_back(form);
+ PasswordForm stored_form = form;
+ stored_form.password_value = ASCIIToUTF16("old_password");
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillOnce(WithArg<1>(InvokeConsumer(stored_form)));
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // The username of the stored form is the same, there should be update bubble.
+ std::unique_ptr<PasswordFormManager> form_manager_to_save;
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+ ASSERT_TRUE(form_manager_to_save);
+ EXPECT_THAT(form_manager_to_save->pending_credentials(), FormMatches(form));
+
+ // The username of the stored form is different, there should be save bubble.
+ PasswordForm new_form = form;
+ new_form.username_value = ASCIIToUTF16("another_username");
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->ShowManualFallbackForSaving(&driver_, new_form);
+ ASSERT_TRUE(form_manager_to_save);
+ EXPECT_THAT(form_manager_to_save->pending_credentials(),
+ FormMatches(new_form));
+
+ // Hide the manual fallback.
+ EXPECT_CALL(client_, HideManualFallbackForSaving());
+ manager()->HideManualFallbackForSaving();
+}
+
+// Tests that the manual fallback for saving isn't shown if there is no response
+// from the password storage. When crbug.com/741537 is fixed, change this test.
+TEST_F(PasswordManagerTest, ManualFallbackForSaving_SlowBackend) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+
+ std::vector<PasswordForm> observed;
+ PasswordForm form(MakeSimpleForm());
+ observed.push_back(form);
+ PasswordStoreConsumer* store_consumer = nullptr;
+ EXPECT_CALL(*store_, GetLogins(_, _)).WillOnce(SaveArg<1>(&store_consumer));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // There is no response from the store. Don't show the fallback.
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _)).Times(0);
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+
+ // The storage responded. The fallback can be shown.
+ ASSERT_TRUE(store_consumer);
+ store_consumer->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
+ std::unique_ptr<PasswordFormManager> form_manager_to_save;
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+}
+
+TEST_F(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+
+ std::vector<PasswordForm> observed;
+ PasswordForm form(MakeSimpleForm());
+ observed.push_back(form);
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillOnce(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // A user accepts a password generated by Chrome. It triggers password
+ // presaving and showing manual fallback.
+ std::unique_ptr<PasswordFormManager> form_manager_to_save;
+ EXPECT_CALL(*store_, AddLogin(_));
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, true, false))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->OnPresaveGeneratedPassword(form);
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+ ASSERT_TRUE(form_manager_to_save);
+ EXPECT_THAT(form_manager_to_save->pending_credentials(), FormMatches(form));
+
+ // A user edits the generated password. And again it causes password presaving
+ // and showing manual fallback.
+ EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _));
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, true, false))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->OnPresaveGeneratedPassword(form);
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+
+ // A user removes the generated password. The presaved password is removed,
+ // the fallback is disabled.
+ EXPECT_CALL(*store_, RemoveLogin(_));
+ EXPECT_CALL(client_, HideManualFallbackForSaving());
+ manager()->OnPasswordNoLongerGenerated(form);
+ manager()->HideManualFallbackForSaving();
+}
+
} // namespace password_manager
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 27dd2931285..56fbd222f92 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
@@ -70,17 +70,23 @@ void PasswordReuseDetectionManager::OnKeyPressed(const base::string16& text) {
}
void PasswordReuseDetectionManager::OnReuseFound(
- const base::string16& password,
- const std::string& legitimate_domain,
- int saved_passwords,
- int number_matches) {
+ size_t password_length,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) {
reuse_on_this_page_was_found_ = true;
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) {
logger.reset(
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogString(BrowserSavePasswordProgressLogger::STRING_REUSE_FOUND,
- legitimate_domain);
+ std::vector<std::string> domains_to_log(matching_domains);
+ if (matches_sync_password)
+ domains_to_log.push_back("CHROME SYNC PASSWORD");
+ // TODO(nparker): Implement LogList() to log all domains in one call.
+ for (const auto& domain : domains_to_log) {
+ logger->LogString(BrowserSavePasswordProgressLogger::STRING_REUSE_FOUND,
+ domain);
+ }
}
// PasswordManager could be nullptr in tests.
@@ -89,12 +95,17 @@ void PasswordReuseDetectionManager::OnReuseFound(
? client_->GetPasswordManager()->IsPasswordFieldDetectedOnPage()
: false;
- metrics_util::LogPasswordReuse(password.size(), saved_passwords,
- number_matches, password_field_detected);
+ metrics_util::LogPasswordReuse(password_length, saved_passwords,
+ matching_domains.size(),
+ password_field_detected);
#if defined(SAFE_BROWSING_DB_LOCAL)
// TODO(jialiul): After CSD whitelist being added to Android, we should gate
// this by either SAFE_BROWSING_DB_LOCAL or SAFE_BROWSING_DB_REMOTE.
- client_->CheckProtectedPasswordEntry(legitimate_domain,
+ if (matches_sync_password) {
+ client_->LogPasswordReuseDetectedEvent();
+ }
+
+ client_->CheckProtectedPasswordEntry(matches_sync_password, matching_domains,
password_field_detected);
#endif
}
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
index bad3370f762..71711ecbad7 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
@@ -29,11 +29,11 @@ class PasswordReuseDetectionManager : public PasswordReuseDetectorConsumer {
void DidNavigateMainFrame(const GURL& main_frame_url);
void OnKeyPressed(const base::string16& text);
- // PasswordReuseDetectorConsumer
- void OnReuseFound(const base::string16& password,
- const std::string& legitimate_domain,
- int saved_passwords,
- int number_matches) override;
+ // PasswordReuseDetectorConsumer implementation
+ void OnReuseFound(size_t password_length,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) override;
void SetClockForTesting(std::unique_ptr<base::Clock> clock);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
index 50e0c8903f4..8471137064a 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
@@ -138,7 +138,7 @@ TEST_F(PasswordReuseDetectionManagerTest, NoReuseCheckingAfterReuseFound) {
PasswordReuseDetectionManager manager(&client_);
// Simulate that reuse found.
- manager.OnReuseFound(base::string16(), std::string(), 0, 0);
+ manager.OnReuseFound(0ul, true, {}, 0);
// Expect no checking of reuse.
EXPECT_CALL(*store_, CheckReuse(_, _, _)).Times(0);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector.cc b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
index 7d6e1ca7b81..cce9c4c5316 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
@@ -36,8 +36,6 @@ bool IsSuffix(const base::string16& str,
} // namespace
-const char kSyncPasswordDomain[] = "CHROME SYNC";
-
bool ReverseStringLess::operator()(const base::string16& lhs,
const base::string16& rhs) const {
return std::lexicographical_compare(lhs.rbegin(), lhs.rend(), rhs.rbegin(),
@@ -71,26 +69,35 @@ void PasswordReuseDetector::CheckReuse(
if (input.size() < kMinPasswordLengthToCheck)
return;
- if (CheckSyncPasswordReuse(input, domain, consumer))
- return;
+ size_t sync_reused_password_length = CheckSyncPasswordReuse(input, domain);
- if (CheckSavedPasswordReuse(input, domain, consumer))
- return;
+ std::vector<std::string> matching_domains;
+ size_t saved_reused_password_length =
+ CheckSavedPasswordReuse(input, domain, &matching_domains);
+
+ size_t max_reused_password_length =
+ std::max(sync_reused_password_length, saved_reused_password_length);
+
+ if (max_reused_password_length != 0) {
+ consumer->OnReuseFound(
+ max_reused_password_length,
+ sync_reused_password_length != 0 /* matches_sync_password */,
+ matching_domains, saved_passwords_);
+ }
}
-bool PasswordReuseDetector::CheckSyncPasswordReuse(
+size_t PasswordReuseDetector::CheckSyncPasswordReuse(
const base::string16& input,
- const std::string& domain,
- PasswordReuseDetectorConsumer* consumer) {
+ const std::string& domain) {
if (!sync_password_data_.has_value())
- return false;
+ return 0;
const Origin gaia_origin(GaiaUrls::GetInstance()->gaia_url().GetOrigin());
if (Origin(GURL(domain)).IsSameOriginWith(gaia_origin))
- return false;
+ return 0;
if (input.size() < sync_password_data_->length)
- return false;
+ return 0;
size_t offset = input.size() - sync_password_data_->length;
base::string16 reuse_candidate = input.substr(offset);
@@ -98,33 +105,47 @@ bool PasswordReuseDetector::CheckSyncPasswordReuse(
if (password_manager_util::CalculateSyncPasswordHash(
reuse_candidate, sync_password_data_->salt) ==
sync_password_data_->hash) {
- consumer->OnReuseFound(reuse_candidate, kSyncPasswordDomain, 1, 0);
- return true;
+ return reuse_candidate.size();
}
- return false;
+ return 0;
}
-bool PasswordReuseDetector::CheckSavedPasswordReuse(
+size_t PasswordReuseDetector::CheckSavedPasswordReuse(
const base::string16& input,
const std::string& domain,
- PasswordReuseDetectorConsumer* consumer) {
+ std::vector<std::string>* matching_domains_out) {
const std::string registry_controlled_domain =
GetRegistryControlledDomain(GURL(domain));
- auto passwords_iterator = FindSavedPassword(input);
- if (passwords_iterator == passwords_.end())
- return false;
- const std::set<std::string>& domains = passwords_iterator->second;
- DCHECK(!domains.empty());
- if (domains.find(registry_controlled_domain) == domains.end()) {
- // Return only one domain.
- const std::string& legitimate_domain = *domains.begin();
- consumer->OnReuseFound(passwords_iterator->first, legitimate_domain,
- saved_passwords_, domains.size());
- return true;
+ // More than one password call match |input| if they share a common suffix
+ // with |input|. Collect the set of domains for all matches.
+ std::set<std::string> matching_domains_set;
+
+ // The longest password match is kept for metrics.
+ size_t longest_match_len = 0;
+
+ for (auto passwords_iterator = FindFirstSavedPassword(input);
+ passwords_iterator != passwords_.end();
+ passwords_iterator = FindNextSavedPassword(input, passwords_iterator)) {
+ const std::set<std::string>& domains = passwords_iterator->second;
+ DCHECK(!domains.empty());
+ // If the page's URL matches a saved domain for this password,
+ // this isn't password-reuse.
+ if (domains.find(registry_controlled_domain) != domains.end())
+ continue;
+
+ matching_domains_set.insert(domains.begin(), domains.end());
+ DCHECK(passwords_iterator->first.size());
+ if (longest_match_len < passwords_iterator->first.size())
+ longest_match_len = passwords_iterator->first.size();
}
+ if (matching_domains_set.size() == 0)
+ return 0;
- return false;
+ *matching_domains_out = std::vector<std::string>(matching_domains_set.begin(),
+ matching_domains_set.end());
+
+ return longest_match_len;
}
void PasswordReuseDetector::UseSyncPasswordHash(
@@ -149,12 +170,13 @@ void PasswordReuseDetector::AddPassword(const autofill::PasswordForm& form) {
}
PasswordReuseDetector::passwords_iterator
-PasswordReuseDetector::FindSavedPassword(const base::string16& input) {
+PasswordReuseDetector::FindFirstSavedPassword(const base::string16& input) {
// Keys in |passwords_| are ordered by lexicographical order of reversed
- // strings. In order to check a password reuse a key of |passwords_| that is a
- // suffix of |input| should be found. The longest such key should be the
+ // strings. In order to check a password reuse a key of |passwords_| that is
+ // a suffix of |input| should be found. The longest such key should be the
// largest key in the |passwords_| keys order that is equal or smaller to
- // |input|.
+ // |input|. There may be more, shorter, matches as well -- call
+ // FindNextSavedPassword(it) to find the next one.
if (passwords_.empty())
return passwords_.end();
@@ -166,9 +188,15 @@ PasswordReuseDetector::FindSavedPassword(const base::string16& input) {
}
// Otherwise the previous key is a candidate for password reuse.
+ return FindNextSavedPassword(input, it);
+}
+
+PasswordReuseDetector::passwords_iterator
+PasswordReuseDetector::FindNextSavedPassword(
+ const base::string16& input,
+ PasswordReuseDetector::passwords_iterator it) {
if (it == passwords_.begin())
return passwords_.end();
-
--it;
return IsSuffix(input, it->first) ? it : passwords_.end();
}
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector.h b/chromium/components/password_manager/core/browser/password_reuse_detector.h
index 4453debc4b2..0f260930a0d 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector.h
@@ -28,9 +28,6 @@ struct ReverseStringLess {
bool operator()(const base::string16& lhs, const base::string16& rhs) const;
};
-// Used to identify chrome sync password in password entry event.
-extern const char kSyncPasswordDomain[];
-
// Per-profile class responsible for detection of password reuse, i.e. that the
// user input on some site contains the password saved on another site.
// It receives saved passwords through PasswordStoreConsumer interface.
@@ -71,23 +68,30 @@ class PasswordReuseDetector : public PasswordStoreConsumer {
// Add password from |form| to |passwords_|.
void AddPassword(const autofill::PasswordForm& form);
- // Returns true iff a reuse of a sync password is found. If reuse is found it
- // is reported to |consumer|.
- bool CheckSyncPasswordReuse(const base::string16& input,
- const std::string& domain,
- PasswordReuseDetectorConsumer* consumer);
+ // If sync-password reuse is found, return the length of the reused
+ // password. If no reuse is found, return 0.
+ size_t CheckSyncPasswordReuse(const base::string16& input,
+ const std::string& domain);
- // Returns true iff a reuse of a saved password is found. If reuse is found it
- // is reported to |consumer|.
- bool CheckSavedPasswordReuse(const base::string16& input,
- const std::string& domain,
- PasswordReuseDetectorConsumer* consumer);
+ // If saved-password reuse is found, fill in the registry-controlled
+ // domains that match any reused password, and return the length of the
+ // longest password matched. If no reuse is found, return 0.
+ size_t CheckSavedPasswordReuse(
+ const base::string16& input,
+ const std::string& domain,
+ std::vector<std::string>* matching_domains_out);
// Returns the iterator to |passwords_| that corresponds to the longest key in
// |passwords_| that is a suffix of |input|. Returns passwords_.end() in case
// when no key in |passwords_| is a prefix of |input|.
- passwords_iterator FindSavedPassword(const base::string16& input);
-
+ passwords_iterator FindFirstSavedPassword(const base::string16& input);
+
+ // Call this repeatedly with iterator from |FindFirstSavedPassword| to
+ // find other matching passwords. This returns the iterator to |passwords_|
+ // that is the next previous matching entry that's a suffix of |input|, or
+ // passwords_.end() if there are no more.
+ passwords_iterator FindNextSavedPassword(const base::string16& input,
+ passwords_iterator it);
// Contains all passwords.
// A key is a password.
// A value is a set of registry controlled domains on which the password
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
index fb6dc8c817a..0c9779099ac 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DETECTOR_CONSUMER_H_
#include <string>
+#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -21,14 +22,15 @@ class PasswordReuseDetectorConsumer
virtual ~PasswordReuseDetectorConsumer();
// Called when a password reuse is found.
- // |legitimate_domain| is the domain on which |password| is saved or
- // safe_browsing::kChromeSyncDomain if |password| is a sync password.
- // |saved_passwords| is total number of passwords stored in Password Manager.
- // |number_matches| is a number of sites on which |password| is saved.
- virtual void OnReuseFound(const base::string16& password,
- const std::string& legitimate_domain,
- int saved_passwords,
- int number_matches) = 0;
+ // |password_length| is the length of the re-used password, or the max length
+ // if multiple passwords were matched. |matching_domains| is the list of
+ // domains for which |password| is saved (may be empty if
+ // |matches_sync_password| == true), |saved_passwords| is the total number
+ // of passwords (with unique domains) stored in Password Manager.
+ virtual void OnReuseFound(size_t password_length,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) = 0;
};
} // namespace password_manager
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 8b510f85b52..93bb2454197 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
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
@@ -24,9 +25,15 @@ namespace password_manager {
namespace {
+using StringVector = std::vector<std::string>;
+
+// Constants to make the tests more readable.
+const bool SYNC_REUSE_NO = false;
+const bool SYNC_REUSE_YES = true;
+
std::vector<std::pair<std::string, std::string>> GetTestDomainsPasswords() {
return {
- {"https://accounts.google.com", "password"},
+ {"https://accounts.google.com", "saved_password"},
{"https://facebook.com", "123456789"},
{"https://a.appspot.com", "abcdefghi"},
{"https://twitter.com", "short"},
@@ -35,19 +42,27 @@ std::vector<std::pair<std::string, std::string>> GetTestDomainsPasswords() {
};
}
-std::unique_ptr<PasswordForm> GetForm(
- const std::pair<std::string, std::string>& domain_password) {
+std::unique_ptr<PasswordForm> GetForm(const std::string& domain,
+ const std::string& password) {
std::unique_ptr<PasswordForm> form(new PasswordForm);
- form->signon_realm = domain_password.first;
- form->password_value = ASCIIToUTF16(domain_password.second);
+ form->signon_realm = domain;
+ form->password_value = ASCIIToUTF16(password);
return form;
}
+// Convert a vector of pairs of strings ("domain[,domain...]", "password")
+// into a vector of PasswordForms.
std::vector<std::unique_ptr<PasswordForm>> GetForms(
const std::vector<std::pair<std::string, std::string>>& domains_passwords) {
std::vector<std::unique_ptr<PasswordForm>> result;
- for (const auto& domain_password : domains_passwords)
- result.push_back(GetForm(domain_password));
+ for (const auto& domains_password : domains_passwords) {
+ // Some passwords are used on multiple domains.
+ for (const auto& domain :
+ base::SplitString(domains_password.first, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ result.push_back(GetForm(domain, domains_password.second));
+ }
+ }
return result;
}
@@ -76,27 +91,30 @@ TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) {
MockPasswordReuseDetectorConsumer mockConsumer;
EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
- reuse_detector.CheckReuse(ASCIIToUTF16("123passwo"), "https://evil.com",
- &mockConsumer);
- reuse_detector.CheckReuse(ASCIIToUTF16("123passwor"), "https://evil.com",
+ reuse_detector.CheckReuse(ASCIIToUTF16("123saved_passwo"), "https://evil.com",
&mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("123saved_passwor"),
+ "https://evil.com", &mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
- reuse_detector.CheckReuse(ASCIIToUTF16("123password"), "https://evil.com",
- &mockConsumer);
+ OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
+ StringVector({"google.com"}), 5));
+ reuse_detector.CheckReuse(ASCIIToUTF16("123saved_password"),
+ "https://evil.com", &mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
- reuse_detector.CheckReuse(ASCIIToUTF16("password"), "https://evil.com",
+ OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
+ StringVector({"google.com"}), 5));
+ reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("secretword"), "example1.com", 5, 2));
+ OnReuseFound(strlen("secretword"), SYNC_REUSE_NO,
+ StringVector({"example1.com", "example2.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("abcdsecretword"), "https://evil.com",
&mockConsumer);
}
@@ -118,8 +136,8 @@ TEST(PasswordReuseDetectorTest, NoPSLMatchReuseEvent) {
// a.appspot.com and b.appspot.com are not PSL matches. So reuse event should
// be raised.
- EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("abcdefghi"), "a.appspot.com", 5, 1));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("abcdefghi"), SYNC_REUSE_NO,
+ StringVector({"a.appspot.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("abcdefghi"), "https://b.appspot.com",
&mockConsumer);
}
@@ -159,18 +177,22 @@ TEST(PasswordReuseDetectorTest, OnLoginsChanged) {
EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
} else {
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
+ OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
+ StringVector({"google.com"}), 5));
}
- reuse_detector.CheckReuse(ASCIIToUTF16("123password"), "https://evil.com",
- &mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("123saved_password"),
+ "https://evil.com", &mockConsumer);
}
}
-TEST(PasswordReuseDetectorTest, CheckLongestPasswordMatchReturn) {
+TEST(PasswordReuseDetectorTest, MatchMultiplePasswords) {
+ // These all have different length passwods so we can check the
+ // returned length.
const std::vector<std::pair<std::string, std::string>> domain_passwords = {
- {"https://example1.com", "234567890"},
- {"https://example2.com", "01234567890"},
- {"https://example3.com", "1234567890"},
+ {"https://a.com, https://all.com", "34567890"},
+ {"https://b.com, https://b2.com, https://all.com", "01234567890"},
+ {"https://c.com, https://all.com", "1234567890"},
+ {"https://d.com", "123456789"},
};
PasswordReuseDetector reuse_detector;
@@ -178,20 +200,24 @@ TEST(PasswordReuseDetectorTest, CheckLongestPasswordMatchReturn) {
MockPasswordReuseDetectorConsumer mockConsumer;
- EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("01234567890"), "example2.com", 3, 1));
+ EXPECT_CALL(
+ mockConsumer,
+ OnReuseFound(
+ strlen("01234567890"), SYNC_REUSE_NO,
+ StringVector({"a.com", "all.com", "b.com", "b2.com", "c.com"}), 8));
reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("1234567890"), "example3.com", 3, 1));
+ OnReuseFound(strlen("1234567890"), SYNC_REUSE_NO,
+ StringVector({"a.com", "all.com", "c.com"}), 8));
reuse_detector.CheckReuse(ASCIIToUTF16("1234567890"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
- reuse_detector.CheckReuse(ASCIIToUTF16("34567890"), "https://evil.com",
+ reuse_detector.CheckReuse(ASCIIToUTF16("4567890"), "https://evil.com",
&mockConsumer);
}
@@ -220,13 +246,41 @@ TEST(PasswordReuseDetectorTest, SyncPasswordReuseFound) {
std::string sync_password = "sync_password";
reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
- EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("sync_password"),
- std::string(kSyncPasswordDomain), 1, 0));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("sync_password"),
+ SYNC_REUSE_YES, StringVector(), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"), "https://evil.com",
&mockConsumer);
}
+TEST(PasswordReuseDetectorTest, MatchSyncAndMultiplePasswords) {
+ const std::vector<std::pair<std::string, std::string>> domain_passwords = {
+ {"https://a.com", "34567890"}, {"https://b.com", "01234567890"},
+ };
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords));
+
+ std::string sync_password = "1234567890";
+ reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("01234567890"), SYNC_REUSE_YES,
+ StringVector({"a.com", "b.com"}), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("1234567890"), SYNC_REUSE_YES,
+ StringVector(), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("xyz1234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ reuse_detector.CheckReuse(ASCIIToUTF16("4567890"), "https://evil.com",
+ &mockConsumer);
+}
+
TEST(PasswordReuseDetectorTest, SavedPasswordsReuseSyncPasswordAvailable) {
// Check that reuse of saved passwords is detected also if the sync password
// hash is saved.
@@ -238,8 +292,26 @@ TEST(PasswordReuseDetectorTest, SavedPasswordsReuseSyncPasswordAvailable) {
reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
EXPECT_CALL(mockConsumer,
- OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
- reuse_detector.CheckReuse(ASCIIToUTF16("password"), "https://evil.com",
+ OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
+ StringVector({"google.com"}), 5));
+ reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
+ &mockConsumer);
+}
+
+TEST(PasswordReuseDetectorTest, SavedPasswordAndSyncPasswordReuse) {
+ // Verify we can detect that a password matches BOTH the sync password
+ // and saved password.
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ std::string sync_password = "saved_password"; // matches saved password
+ reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+
+ EXPECT_CALL(mockConsumer,
+ OnReuseFound(strlen("saved_password"), SYNC_REUSE_YES,
+ StringVector({"google.com"}), 5));
+ reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
&mockConsumer);
}
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 5adf79f2de2..7add9f725f2 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -14,7 +14,9 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
#include "components/password_manager/core/browser/password_manager_util.h"
@@ -70,14 +72,15 @@ PasswordStore::CheckReuseRequest::CheckReuseRequest(
PasswordStore::CheckReuseRequest::~CheckReuseRequest() {}
void PasswordStore::CheckReuseRequest::OnReuseFound(
- const base::string16& password,
- const std::string& legitimate_domain,
- int saved_passwords,
- int number_matches) {
+ size_t password_length,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) {
origin_task_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordReuseDetectorConsumer::OnReuseFound, consumer_weak_,
- password, legitimate_domain, saved_passwords, number_matches));
+ password_length, matches_sync_password, matching_domains,
+ saved_passwords));
}
#endif
@@ -106,18 +109,19 @@ bool PasswordStore::FormDigest::operator==(const FormDigest& other) const {
origin == other.origin;
}
-PasswordStore::PasswordStore(
- scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
- scoped_refptr<base::SequencedTaskRunner> db_thread_runner)
- : main_thread_runner_(main_thread_runner),
- db_thread_runner_(db_thread_runner),
- observers_(new base::ObserverListThreadSafe<Observer>()),
+PasswordStore::PasswordStore()
+ : observers_(new base::ObserverListThreadSafe<Observer>()),
is_propagating_password_changes_to_web_credentials_enabled_(false),
shutdown_called_(false) {}
bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
PrefService* prefs) {
- ScheduleTask(base::Bind(&PasswordStore::InitOnBackgroundThread, this, flare));
+ main_task_runner_ = base::SequencedTaskRunnerHandle::Get();
+ DCHECK(main_task_runner_);
+ background_task_runner_ = CreateBackgroundTaskRunner();
+ DCHECK(background_task_runner_);
+ ScheduleTask(
+ base::Bind(&PasswordStore::InitOnBackgroundSequence, this, flare));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
hash_password_manager_.set_prefs(prefs);
ScheduleTask(
@@ -261,14 +265,12 @@ void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformation(
void PasswordStore::ReportMetrics(const std::string& sync_username,
bool custom_passphrase_sync_enabled) {
- scoped_refptr<base::SequencedTaskRunner> task_runner(
- GetBackgroundTaskRunner());
- if (task_runner) {
+ if (background_task_runner_) {
base::Closure task =
base::Bind(&PasswordStore::ReportMetricsImpl, this, sync_username,
custom_passphrase_sync_enabled);
- task_runner->PostDelayedTask(FROM_HERE, task,
- base::TimeDelta::FromSeconds(30));
+ background_task_runner_->PostDelayedTask(FROM_HERE, task,
+ base::TimeDelta::FromSeconds(30));
}
#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
@@ -309,16 +311,14 @@ void PasswordStore::RemoveObserver(Observer* observer) {
}
bool PasswordStore::ScheduleTask(const base::Closure& task) {
- scoped_refptr<base::SequencedTaskRunner> task_runner(
- GetBackgroundTaskRunner());
- if (task_runner.get())
- return task_runner->PostTask(FROM_HERE, task);
+ if (background_task_runner_)
+ return background_task_runner_->PostTask(FROM_HERE, task);
return false;
}
void PasswordStore::ShutdownOnUIThread() {
- ScheduleTask(base::Bind(&PasswordStore::DestroyOnBackgroundThread, this));
- // The AffiliationService must be destroyed from the main thread.
+ ScheduleTask(base::Bind(&PasswordStore::DestroyOnBackgroundSequence, this));
+ // The AffiliationService must be destroyed from the main sequence.
affiliated_match_helper_.reset();
shutdown_called_ = true;
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
@@ -329,7 +329,7 @@ void PasswordStore::ShutdownOnUIThread() {
base::WeakPtr<syncer::SyncableService>
PasswordStore::GetPasswordSyncableService() {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
DCHECK(syncable_service_);
return syncable_service_->AsWeakPtr();
}
@@ -374,8 +374,23 @@ PasswordStore::~PasswordStore() {
}
scoped_refptr<base::SequencedTaskRunner>
-PasswordStore::GetBackgroundTaskRunner() {
- return db_thread_runner_;
+PasswordStore::CreateBackgroundTaskRunner() const {
+ return base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
+}
+
+void PasswordStore::InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(!syncable_service_);
+ syncable_service_.reset(new PasswordSyncableService(this));
+ syncable_service_->InjectStartSyncFlare(flare);
+// TODO(crbug.com/706392): Fix password reuse detection for Android.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ reuse_detector_ = new PasswordReuseDetector;
+ GetAutofillableLoginsImpl(
+ base::MakeUnique<GetLoginsRequest>(reuse_detector_));
+#endif
}
void PasswordStore::GetLoginsImpl(const FormDigest& form,
@@ -428,7 +443,7 @@ PasswordStoreChangeList PasswordStore::RemoveLoginSync(
void PasswordStore::NotifyLoginsChanged(
const PasswordStoreChangeList& changes) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
if (!changes.empty()) {
observers_->Notify(FROM_HERE, &Observer::OnLoginsChanged, changes);
if (syncable_service_)
@@ -467,8 +482,8 @@ void PasswordStore::Schedule(
PasswordStoreConsumer* consumer) {
std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
consumer->cancelable_task_tracker()->PostTask(
- GetBackgroundTaskRunner().get(), FROM_HERE,
- base::Bind(func, this, base::Passed(&request)));
+ background_task_runner_.get(), FROM_HERE,
+ base::BindOnce(func, this, base::Passed(&request)));
}
void PasswordStore::WrapModificationTask(ModificationTask task) {
@@ -509,7 +524,7 @@ void PasswordStore::RemoveLoginsByURLAndTimeInternal(
RemoveLoginsByURLAndTimeImpl(url_filter, delete_begin, delete_end);
NotifyLoginsChanged(changes);
if (!completion.is_null())
- main_thread_runner_->PostTask(FROM_HERE, completion);
+ main_task_runner_->PostTask(FROM_HERE, completion);
}
void PasswordStore::RemoveLoginsCreatedBetweenInternal(
@@ -520,7 +535,7 @@ void PasswordStore::RemoveLoginsCreatedBetweenInternal(
RemoveLoginsCreatedBetweenImpl(delete_begin, delete_end);
NotifyLoginsChanged(changes);
if (!completion.is_null())
- main_thread_runner_->PostTask(FROM_HERE, completion);
+ main_task_runner_->PostTask(FROM_HERE, completion);
}
void PasswordStore::RemoveLoginsSyncedBetweenInternal(base::Time delete_begin,
@@ -537,7 +552,7 @@ void PasswordStore::RemoveStatisticsByOriginAndTimeInternal(
const base::Closure& completion) {
RemoveStatisticsByOriginAndTimeImpl(origin_filter, delete_begin, delete_end);
if (!completion.is_null())
- main_thread_runner_->PostTask(FROM_HERE, completion);
+ main_task_runner_->PostTask(FROM_HERE, completion);
}
void PasswordStore::DisableAutoSignInForOriginsInternal(
@@ -545,7 +560,7 @@ void PasswordStore::DisableAutoSignInForOriginsInternal(
const base::Closure& completion) {
DisableAutoSignInForOriginsImpl(origin_filter);
if (!completion.is_null())
- main_thread_runner_->PostTask(FROM_HERE, completion);
+ main_task_runner_->PostTask(FROM_HERE, completion);
}
void PasswordStore::GetLoginsForSameOrganizationNameImpl(
@@ -571,7 +586,7 @@ void PasswordStore::
obtained_forms.clear();
// Since AffiliatedMatchHelper's requests should be sent from UI thread,
// post a request to UI thread.
- main_thread_runner_->PostTask(
+ main_task_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
base::Passed(&obtained_forms), base::Passed(&request)));
@@ -592,7 +607,7 @@ void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl(
obtained_forms.clear();
// Since AffiliatedMatchHelper's requests should be sent from UI thread,
// post a request to UI thread.
- main_thread_runner_->PostTask(
+ main_task_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
base::Passed(&obtained_forms), base::Passed(&request)));
@@ -612,7 +627,7 @@ void PasswordStore::GetLoginsWithAffiliationsImpl(
const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<PasswordForm>> results(FillMatchingLogins(form));
for (const std::string& realm : additional_android_realms) {
std::vector<std::unique_ptr<PasswordForm>> more_results(
@@ -652,7 +667,7 @@ void PasswordStore::ScheduleGetLoginsWithAffiliations(
std::unique_ptr<PasswordForm> PasswordStore::GetLoginImpl(
const PasswordForm& primary_key) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
std::vector<std::unique_ptr<PasswordForm>> candidates(
FillMatchingLogins(FormDigest(primary_key)));
for (auto& candidate : candidates) {
@@ -678,7 +693,7 @@ void PasswordStore::FindAndUpdateAffiliatedWebLogins(
void PasswordStore::ScheduleFindAndUpdateAffiliatedWebLogins(
const PasswordForm& added_or_updated_android_form) {
- main_thread_runner_->PostTask(
+ main_task_runner_->PostTask(
FROM_HERE, base::Bind(&PasswordStore::FindAndUpdateAffiliatedWebLogins,
this, added_or_updated_android_form));
}
@@ -686,7 +701,7 @@ void PasswordStore::ScheduleFindAndUpdateAffiliatedWebLogins(
void PasswordStore::UpdateAffiliatedWebLoginsImpl(
const PasswordForm& updated_android_form,
const std::vector<std::string>& affiliated_web_realms) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
PasswordStoreChangeList all_changes;
for (const std::string& affiliated_web_realm : affiliated_web_realms) {
std::vector<std::unique_ptr<PasswordForm>> web_logins(FillMatchingLogins(
@@ -770,26 +785,13 @@ void PasswordStore::ScheduleUpdateAffiliatedWebLoginsImpl(
updated_android_form, affiliated_web_realms));
}
-void PasswordStore::InitOnBackgroundThread(
- const syncer::SyncableService::StartSyncFlare& flare) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
- DCHECK(!syncable_service_);
- syncable_service_.reset(new PasswordSyncableService(this));
- syncable_service_->InjectStartSyncFlare(flare);
-// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
- reuse_detector_ = base::MakeUnique<PasswordReuseDetector>();
- GetAutofillableLoginsImpl(
- base::MakeUnique<GetLoginsRequest>(reuse_detector_.get()));
-#endif
-}
-
-void PasswordStore::DestroyOnBackgroundThread() {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+void PasswordStore::DestroyOnBackgroundSequence() {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
syncable_service_.reset();
// TODO(crbug.com/706392): Fix password reuse detection for Android.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
- reuse_detector_.reset();
+ delete reuse_detector_;
+ reuse_detector_ = nullptr;
#endif
}
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index 5616935d49e..be44ebadefb 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -16,6 +16,7 @@
#include "base/observer_list_threadsafe.h"
#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/keyed_service/core/refcounted_keyed_service.h"
#include "components/password_manager/core/browser/password_reuse_defines.h"
#include "components/password_manager/core/browser/password_store_change.h"
@@ -51,12 +52,12 @@ struct InteractionsStats;
// The login request/manipulation API is not threadsafe and must be used
// from the UI thread.
// Implementations, however, should carry out most tasks asynchronously on a
-// background thread: the base class provides functionality to facilitate this.
-// I/O heavy initialization should also be performed asynchronously in this
-// manner. If this deferred initialization fails, all subsequent method calls
-// should fail without side effects, return no data, and send no notifications.
-// PasswordStoreSync is a hidden base class because only PasswordSyncableService
-// needs to access these methods.
+// background sequence: the base class provides functionality to facilitate
+// this. I/O heavy initialization should also be performed asynchronously in
+// this manner. If this deferred initialization fails, all subsequent method
+// calls should fail without side effects, return no data, and send no
+// notifications. PasswordStoreSync is a hidden base class because only
+// PasswordSyncableService needs to access these methods.
class PasswordStore : protected PasswordStoreSync,
public RefcountedKeyedService {
public:
@@ -91,10 +92,10 @@ class PasswordStore : protected PasswordStoreSync,
GURL origin;
};
- PasswordStore(scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
- scoped_refptr<base::SequencedTaskRunner> db_thread_runner);
+ PasswordStore();
- // Reimplement this to add custom initialization. Always call this too.
+ // Reimplement this to add custom initialization. Always call this too on the
+ // UI thread.
virtual bool Init(const syncer::SyncableService::StartSyncFlare& flare,
PrefService* prefs);
@@ -137,7 +138,7 @@ class PasswordStore : protected PasswordStoreSync,
// Remove all logins whose origins match the given filter and that were
// created
// in the given date range. |completion| will be posted to the
- // |main_thread_runner_| after deletions have been completed and notification
+ // |main_task_runner_| after deletions have been completed and notification
// have been sent out.
void RemoveLoginsByURLAndTime(
const base::Callback<bool(const GURL&)>& url_filter,
@@ -146,8 +147,8 @@ class PasswordStore : protected PasswordStoreSync,
const base::Closure& completion);
// Removes all logins created in the given date range. If |completion| is not
- // null, it will be posted to the |main_thread_runner_| after deletions have
- // be completed and notification have been sent out.
+ // null, it will be posted to the |main_task_runner_| after deletions have
+ // been completed and notification have been sent out.
void RemoveLoginsCreatedBetween(base::Time delete_begin,
base::Time delete_end,
const base::Closure& completion);
@@ -159,7 +160,7 @@ class PasswordStore : protected PasswordStoreSync,
// Removes all the stats created in the given date range.
// If |origin_filter| is not null, only statistics for matching origins are
// removed. If |completion| is not null, it will be posted to the
- // |main_thread_runner_| after deletions have been completed.
+ // |main_task_runner_| after deletions have been completed.
// Should be called on the UI thread.
void RemoveStatisticsByOriginAndTime(
const base::Callback<bool(const GURL&)>& origin_filter,
@@ -168,9 +169,9 @@ class PasswordStore : protected PasswordStoreSync,
const base::Closure& completion);
// Sets the 'skip_zero_click' flag for all logins in the database that match
- // |origin_filter| to 'true'. |completion| will be posted to
- // the |main_thread_runner_| after these modifications are completed
- // and notifications are sent out.
+ // |origin_filter| to 'true'. |completion| will be posted to the
+ // |main_task_runner_| after these modifications are completed and
+ // notifications are sent out.
void DisableAutoSignInForOrigins(
const base::Callback<bool(const GURL&)>& origin_filter,
const base::Closure& completion);
@@ -251,7 +252,7 @@ class PasswordStore : protected PasswordStoreSync,
// Checks that some suffix of |input| equals to a password saved on another
// registry controlled domain than |domain|.
// If such suffix is found, |consumer|->OnReuseFound() is called on the same
- // thread on which this method is called.
+ // sequence on which this method is called.
// |consumer| must not be null.
virtual void CheckReuse(const base::string16& input,
const std::string& domain,
@@ -308,7 +309,7 @@ class PasswordStore : protected PasswordStoreSync,
// TODO(crbug.com/706392): Fix password reuse detection for Android.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Represents a single CheckReuse() request. Implements functionality to
- // listen to reuse events and propagate them to |consumer| on the thread on
+ // listen to reuse events and propagate them to |consumer| on the sequence on
// which CheckReuseRequest is created.
class CheckReuseRequest : public PasswordReuseDetectorConsumer {
public:
@@ -317,10 +318,10 @@ class PasswordStore : protected PasswordStoreSync,
~CheckReuseRequest() override;
// PasswordReuseDetectorConsumer
- void OnReuseFound(const base::string16& password,
- const std::string& legitimate_domain,
- int saved_passwords,
- int number_matches) override;
+ void OnReuseFound(size_t password_length,
+ bool matches_sync_password,
+ const std::vector<std::string>& matches_domains,
+ int saved_passwords) override;
private:
const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
@@ -332,12 +333,16 @@ class PasswordStore : protected PasswordStoreSync,
~PasswordStore() override;
- // Get the TaskRunner to use for PasswordStore background tasks.
- // By default, a SequencedTaskRunner on the DB thread is used, but
- // subclasses can override.
- virtual scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner();
+ // Create a TaskRunner to be saved in |background_task_runner_|.
+ virtual scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
+ const;
- // Methods below will be run in PasswordStore's own thread.
+ // Creates PasswordSyncableService and PasswordReuseDetector instances on the
+ // background sequence. Subclasses can add more logic.
+ virtual void InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare);
+
+ // Methods below will be run in PasswordStore's own sequence.
// Synchronous implementation that reports usage metrics.
virtual void ReportMetricsImpl(const std::string& sync_username,
bool custom_passphrase_sync_enabled) = 0;
@@ -443,28 +448,28 @@ class PasswordStore : protected PasswordStoreSync,
void ClearSyncPasswordHashImpl();
#endif
- // TaskRunner for tasks that run on the main thread (usually the UI thread).
- scoped_refptr<base::SequencedTaskRunner> main_thread_runner_;
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner() const {
+ return main_task_runner_;
+ }
- // TaskRunner for the DB thread. By default, this is the task runner used for
- // background tasks -- see |GetBackgroundTaskRunner|.
- scoped_refptr<base::SequencedTaskRunner> db_thread_runner_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner() const {
+ return background_task_runner_;
+ }
private:
- FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest, GetLoginImpl);
FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest,
UpdatePasswordsStoredForAffiliatedWebsites);
- // Schedule the given |func| to be run in the PasswordStore's own thread with
- // responses delivered to |consumer| on the current thread.
+ // Schedule the given |func| to be run in the PasswordStore's own sequence
+ // with responses delivered to |consumer| on the current sequence.
void Schedule(void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>),
PasswordStoreConsumer* consumer);
- // Wrapper method called on the destination thread (DB for non-mac) that
- // invokes |task| and then calls back into the source thread to notify
- // observers that the password store may have been modified via
- // NotifyLoginsChanged(). Note that there is no guarantee that the called
- // method will actually modify the password store data.
+ // Wrapper method called on the destination sequence that invokes |task| and
+ // then calls back into the source sequence to notify observers that the
+ // password store may have been modified via NotifyLoginsChanged(). Note that
+ // there is no guarantee that the called method will actually modify the
+ // password store data.
void WrapModificationTask(ModificationTask task);
// Temporary specializations of WrapModificationTask for a better stack trace.
@@ -535,12 +540,13 @@ class PasswordStore : protected PasswordStoreSync,
const std::vector<std::string>& additional_android_realms);
// Retrieves and fills in affiliation and branding information for Android
- // credentials in |forms|. Called on the main thread.
+ // credentials in |forms|. Called on the main sequence.
void InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
std::unique_ptr<GetLoginsRequest> request);
- // Schedules GetLoginsWithAffiliationsImpl() to be run on the DB thread.
+ // Schedules GetLoginsWithAffiliationsImpl() to be run on the background
+ // sequence.
void ScheduleGetLoginsWithAffiliations(
const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
@@ -549,42 +555,45 @@ class PasswordStore : protected PasswordStoreSync,
// Retrieves the currently stored form, if any, with the same primary key as
// |form|, that is, with the same signon_realm, origin, username_element,
// username_value and password_element attributes. To be called on the
- // background thread.
+ // background sequence.
std::unique_ptr<autofill::PasswordForm> GetLoginImpl(
const autofill::PasswordForm& primary_key);
// Called when a password is added or updated for an Android application, and
// triggers finding web sites affiliated with the Android application and
// propagating the new password to credentials for those web sites, if any.
- // Called on the main thread.
+ // Called on the main sequence.
void FindAndUpdateAffiliatedWebLogins(
const autofill::PasswordForm& added_or_updated_android_form);
- // Posts FindAndUpdateAffiliatedWebLogins() to the main thread. Should be
- // called from the background thread.
+ // Posts FindAndUpdateAffiliatedWebLogins() to the main sequence. Should be
+ // called from the background sequence.
void ScheduleFindAndUpdateAffiliatedWebLogins(
const autofill::PasswordForm& added_or_updated_android_form);
// Called when a password is added or updated for an Android application, and
// propagates these changes to credentials stored for |affiliated_web_realms|
- // under the same username, if there are any. Called on the background thread.
+ // under the same username, if there are any. Called on the background
+ // sequence.
void UpdateAffiliatedWebLoginsImpl(
const autofill::PasswordForm& updated_android_form,
const std::vector<std::string>& affiliated_web_realms);
- // Schedules UpdateAffiliatedWebLoginsImpl() to run on the background thread.
- // Should be called from the main thread.
+ // Schedules UpdateAffiliatedWebLoginsImpl() to run on the background
+ // sequence. Should be called from the main sequence.
void ScheduleUpdateAffiliatedWebLoginsImpl(
const autofill::PasswordForm& updated_android_form,
const std::vector<std::string>& affiliated_web_realms);
- // Creates PasswordSyncableService and PasswordReuseDetector instances on the
- // background thread.
- void InitOnBackgroundThread(
- const syncer::SyncableService::StartSyncFlare& flare);
+ // Deletes object that should be destroyed on the background sequence.
+ // WARNING: this method can be skipped on shutdown.
+ void DestroyOnBackgroundSequence();
+
+ // TaskRunner for tasks that run on the main sequence (usually the UI thread).
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
- // Deletes objest that should be destroyed on the background thread.
- void DestroyOnBackgroundThread();
+ // TaskRunner for all the background operations.
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
// The observers.
scoped_refptr<base::ObserverListThreadSafe<Observer>> observers_;
@@ -593,7 +602,10 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
// TODO(crbug.com/706392): Fix password reuse detection for Android.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
- std::unique_ptr<PasswordReuseDetector> reuse_detector_;
+ // 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;
#endif
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
std::unique_ptr<PasswordStoreSigninNotifier> notifier_;
diff --git a/chromium/components/password_manager/core/browser/password_store_default.cc b/chromium/components/password_manager/core/browser/password_store_default.cc
index 64261d99f93..1e83accf7c0 100644
--- a/chromium/components/password_manager/core/browser/password_store_default.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default.cc
@@ -17,34 +17,26 @@ using autofill::PasswordForm;
namespace password_manager {
PasswordStoreDefault::PasswordStoreDefault(
- scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
- scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
std::unique_ptr<LoginDatabase> login_db)
- : PasswordStore(main_thread_runner, db_thread_runner),
- login_db_(std::move(login_db)) {}
+ : login_db_(std::move(login_db)) {}
PasswordStoreDefault::~PasswordStoreDefault() {
}
-bool PasswordStoreDefault::Init(
- const syncer::SyncableService::StartSyncFlare& flare,
- PrefService* prefs) {
- ScheduleTask(base::Bind(&PasswordStoreDefault::InitOnDBThread, this));
- return PasswordStore::Init(flare, prefs);
-}
-
void PasswordStoreDefault::ShutdownOnUIThread() {
PasswordStore::ShutdownOnUIThread();
ScheduleTask(base::Bind(&PasswordStoreDefault::ResetLoginDB, this));
}
-void PasswordStoreDefault::InitOnDBThread() {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+void PasswordStoreDefault::InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare) {
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
DCHECK(login_db_);
if (!login_db_->Init()) {
login_db_.reset();
LOG(ERROR) << "Could not create/open login database.";
}
+ PasswordStore::InitOnBackgroundSequence(flare);
}
void PasswordStoreDefault::ReportMetricsImpl(
@@ -52,13 +44,13 @@ void PasswordStoreDefault::ReportMetricsImpl(
bool custom_passphrase_sync_enabled) {
if (!login_db_)
return;
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
login_db_->ReportMetrics(sync_username, custom_passphrase_sync_enabled);
}
PasswordStoreChangeList PasswordStoreDefault::AddLoginImpl(
const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
if (!login_db_)
return PasswordStoreChangeList();
return login_db_->AddLogin(form);
@@ -66,7 +58,7 @@ PasswordStoreChangeList PasswordStoreDefault::AddLoginImpl(
PasswordStoreChangeList PasswordStoreDefault::UpdateLoginImpl(
const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
if (!login_db_)
return PasswordStoreChangeList();
return login_db_->UpdateLogin(form);
@@ -74,7 +66,7 @@ PasswordStoreChangeList PasswordStoreDefault::UpdateLoginImpl(
PasswordStoreChangeList PasswordStoreDefault::RemoveLoginImpl(
const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
PasswordStoreChangeList changes;
if (login_db_ && login_db_->RemoveLogin(form))
changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
@@ -194,43 +186,43 @@ PasswordStoreDefault::FillLoginsForSameOrganizationName(
bool PasswordStoreDefault::FillAutofillableLogins(
std::vector<std::unique_ptr<PasswordForm>>* forms) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
return login_db_ && login_db_->GetAutofillableLogins(forms);
}
bool PasswordStoreDefault::FillBlacklistLogins(
std::vector<std::unique_ptr<PasswordForm>>* forms) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
return login_db_ && login_db_->GetBlacklistLogins(forms);
}
void PasswordStoreDefault::AddSiteStatsImpl(const InteractionsStats& stats) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
if (login_db_)
login_db_->stats_table().AddRow(stats);
}
void PasswordStoreDefault::RemoveSiteStatsImpl(const GURL& origin_domain) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
if (login_db_)
login_db_->stats_table().RemoveRow(origin_domain);
}
std::vector<InteractionsStats> PasswordStoreDefault::GetAllSiteStatsImpl() {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
return login_db_ ? login_db_->stats_table().GetAllRows()
: std::vector<InteractionsStats>();
}
std::vector<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl(
const GURL& origin_domain) {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
return login_db_ ? login_db_->stats_table().GetRows(origin_domain)
: std::vector<InteractionsStats>();
}
void PasswordStoreDefault::ResetLoginDB() {
- DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
+ DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
login_db_.reset();
}
diff --git a/chromium/components/password_manager/core/browser/password_store_default.h b/chromium/components/password_manager/core/browser/password_store_default.h
index 4fd557081f9..876bfbab683 100644
--- a/chromium/components/password_manager/core/browser/password_store_default.h
+++ b/chromium/components/password_manager/core/browser/password_store_default.h
@@ -10,12 +10,9 @@
#include <vector>
#include "base/macros.h"
-#include "base/sequenced_task_runner.h"
#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/password_store.h"
-class PrefService;
-
namespace password_manager {
// Simple password store implementation that delegates everything to
@@ -23,14 +20,8 @@ namespace password_manager {
class PasswordStoreDefault : public PasswordStore {
public:
// The |login_db| must not have been Init()-ed yet. It will be initialized in
- // a deferred manner on the DB thread.
- PasswordStoreDefault(
- scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
- scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
- std::unique_ptr<LoginDatabase> login_db);
-
- bool Init(const syncer::SyncableService::StartSyncFlare& flare,
- PrefService* prefs) override;
+ // a deferred manner on the background sequence.
+ explicit PasswordStoreDefault(std::unique_ptr<LoginDatabase> login_db);
void ShutdownOnUIThread() override;
@@ -40,8 +31,9 @@ class PasswordStoreDefault : public PasswordStore {
protected:
~PasswordStoreDefault() override;
- // Opens |login_db_| on the DB thread.
- void InitOnDBThread();
+ // Opens |login_db_| on the background sequence.
+ void InitOnBackgroundSequence(
+ const syncer::SyncableService::StartSyncFlare& flare) override;
// Implements PasswordStore interface.
void ReportMetricsImpl(const std::string& sync_username,
@@ -87,13 +79,13 @@ class PasswordStoreDefault : public PasswordStore {
}
private:
- // Resets |login_db_| on the background thread.
+ // Resets |login_db_| on the background sequence.
void ResetLoginDB();
// The login SQL database. The LoginDatabase instance is received via the
// in an uninitialized state, so as to allow injecting mocks, then Init() is
- // called on the DB thread in a deferred manner. If opening the DB fails,
- // |login_db_| will be reset and stay NULL for the lifetime of |this|.
+ // called on the background sequence in a deferred manner. If opening the DB
+ // fails, |login_db_| will be reset and stay NULL for the lifetime of |this|.
std::unique_ptr<LoginDatabase> login_db_;
DISALLOW_COPY_AND_ASSIGN(PasswordStoreDefault);
diff --git a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
index 8a7374a965a..3ee7bac6c65 100644
--- a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
@@ -16,7 +15,6 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -86,7 +84,7 @@ class PasswordStoreDefaultTestDelegate {
PasswordStoreDefault* store() { return store_.get(); }
- static void FinishAsyncProcessing();
+ void FinishAsyncProcessing();
private:
void SetupTempDir();
@@ -126,7 +124,7 @@ PasswordStoreDefaultTestDelegate::~PasswordStoreDefaultTestDelegate() {
}
void PasswordStoreDefaultTestDelegate::FinishAsyncProcessing() {
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
void PasswordStoreDefaultTestDelegate::SetupTempDir() {
@@ -135,16 +133,15 @@ void PasswordStoreDefaultTestDelegate::SetupTempDir() {
void PasswordStoreDefaultTestDelegate::ClosePasswordStore() {
store_->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
+ FinishAsyncProcessing();
ASSERT_TRUE(temp_dir_.Delete());
}
scoped_refptr<PasswordStoreDefault>
PasswordStoreDefaultTestDelegate::CreateInitializedStore(
std::unique_ptr<LoginDatabase> database) {
- scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(), std::move(database)));
+ scoped_refptr<PasswordStoreDefault> store(
+ new PasswordStoreDefault(std::move(database)));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
return store;
@@ -175,13 +172,10 @@ TEST(PasswordStoreDefaultTest, NonASCIIData) {
// Build the expected forms vector and add the forms to the store.
std::vector<std::unique_ptr<PasswordForm>> expected_forms;
for (unsigned int i = 0; i < arraysize(form_data); ++i) {
- expected_forms.push_back(
- CreatePasswordFormFromDataForTesting(form_data[i]));
+ expected_forms.push_back(FillPasswordFormWithData(form_data[i]));
store->AddLogin(*expected_forms.back());
}
- base::RunLoop().RunUntilIdle();
-
MockPasswordStoreConsumer consumer;
// We expect to get the same data back, even though it's not all ASCII.
@@ -191,7 +185,7 @@ TEST(PasswordStoreDefaultTest, NonASCIIData) {
password_manager::UnorderedPasswordFormElementsAre(&expected_forms)));
store->GetAutofillableLogins(&consumer);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
}
TEST(PasswordStoreDefaultTest, Notifications) {
@@ -199,7 +193,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
PasswordStoreDefault* store = delegate.store();
std::unique_ptr<PasswordForm> form =
- CreatePasswordFormFromDataForTesting(CreateTestPasswordFormData());
+ FillPasswordFormWithData(CreateTestPasswordFormData());
MockPasswordStoreObserver observer;
store->AddObserver(&observer);
@@ -213,7 +207,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Adding a login should trigger a notification.
store->AddLogin(*form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
// Change the password.
form->password_value = base::ASCIIToUTF16("a different password");
@@ -227,7 +221,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Updating the login with the new password should trigger a notification.
store->UpdateLogin(*form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
const PasswordStoreChange expected_delete_changes[] = {
PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
@@ -238,7 +232,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// Deleting the login should trigger a notification.
store->RemoveLogin(*form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
store->RemoveObserver(&observer);
}
@@ -248,9 +242,9 @@ TEST(PasswordStoreDefaultTest, Notifications) {
// notifications.
TEST(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
PasswordStoreDefaultTestDelegate delegate(
- base::WrapUnique(new BadLoginDatabase));
+ base::MakeUnique<BadLoginDatabase>());
PasswordStoreDefault* bad_store = delegate.store();
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
ASSERT_EQ(nullptr, bad_store->login_db());
testing::StrictMock<MockPasswordStoreObserver> mock_observer;
@@ -258,7 +252,7 @@ TEST(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
// Add a new autofillable login + a blacklisted login.
std::unique_ptr<PasswordForm> form =
- CreatePasswordFormFromDataForTesting(CreateTestPasswordFormData());
+ FillPasswordFormWithData(CreateTestPasswordFormData());
std::unique_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
blacklisted_form->signon_realm = "http://foo.example.com";
blacklisted_form->origin = GURL("http://foo.example.com/origin");
@@ -266,41 +260,42 @@ TEST(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
blacklisted_form->blacklisted_by_user = true;
bad_store->AddLogin(*form);
bad_store->AddLogin(*blacklisted_form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
// Get all logins; autofillable logins; blacklisted logins.
testing::StrictMock<MockPasswordStoreConsumer> mock_consumer;
EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
bad_store->GetLogins(PasswordStore::FormDigest(*form), &mock_consumer);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
testing::Mock::VerifyAndClearExpectations(&mock_consumer);
EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
bad_store->GetAutofillableLogins(&mock_consumer);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
testing::Mock::VerifyAndClearExpectations(&mock_consumer);
EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
bad_store->GetBlacklistLogins(&mock_consumer);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
+ testing::Mock::VerifyAndClearExpectations(&mock_consumer);
// Report metrics.
bad_store->ReportMetrics("Test Username", true);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
// Change the login.
form->password_value = base::ASCIIToUTF16("a different password");
bad_store->UpdateLogin(*form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
// Delete one login; a range of logins.
bad_store->RemoveLogin(*form);
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
base::RunLoop run_loop;
bad_store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
run_loop.QuitClosure());
run_loop.Run();
bad_store->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
- base::RunLoop().RunUntilIdle();
+ delegate.FinishAsyncProcessing();
// Ensure no notifications and no explosions during shutdown either.
bad_store->RemoveObserver(&mock_observer);
diff --git a/chromium/components/password_manager/core/browser/password_store_origin_unittest.h b/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
index a5358d7693e..2e23e3b0086 100644
--- a/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
+++ b/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
@@ -63,8 +63,8 @@ TYPED_TEST_CASE_P(PasswordStoreOriginTest);
TYPED_TEST_P(PasswordStoreOriginTest,
RemoveLoginsByURLAndTimeImpl_AllFittingOriginAndTime) {
const char origin_url[] = "http://foo.example.com/";
- std::unique_ptr<PasswordForm> form = CreatePasswordFormFromDataForTesting(
- CreateTestPasswordFormDataByOrigin(origin_url));
+ std::unique_ptr<PasswordForm> form =
+ FillPasswordFormWithData(CreateTestPasswordFormDataByOrigin(origin_url));
this->delegate_.store()->AddLogin(*form);
this->delegate_.FinishAsyncProcessing();
@@ -86,12 +86,12 @@ TYPED_TEST_P(PasswordStoreOriginTest,
TYPED_TEST_P(PasswordStoreOriginTest,
RemoveLoginsByURLAndTimeImpl_SomeFittingOriginAndTime) {
const char fitting_url[] = "http://foo.example.com/";
- std::unique_ptr<PasswordForm> form = CreatePasswordFormFromDataForTesting(
- CreateTestPasswordFormDataByOrigin(fitting_url));
+ std::unique_ptr<PasswordForm> form =
+ FillPasswordFormWithData(CreateTestPasswordFormDataByOrigin(fitting_url));
this->delegate_.store()->AddLogin(*form);
const char nonfitting_url[] = "http://bar.example.com/";
- this->delegate_.store()->AddLogin(*CreatePasswordFormFromDataForTesting(
+ this->delegate_.store()->AddLogin(*FillPasswordFormWithData(
CreateTestPasswordFormDataByOrigin(nonfitting_url)));
this->delegate_.FinishAsyncProcessing();
@@ -116,8 +116,7 @@ TYPED_TEST_P(PasswordStoreOriginTest,
RemoveLoginsByURLAndTimeImpl_NonMatchingOrigin) {
const char origin_url[] = "http://foo.example.com/";
std::unique_ptr<autofill::PasswordForm> form =
- CreatePasswordFormFromDataForTesting(
- CreateTestPasswordFormDataByOrigin(origin_url));
+ FillPasswordFormWithData(CreateTestPasswordFormDataByOrigin(origin_url));
this->delegate_.store()->AddLogin(*form);
this->delegate_.FinishAsyncProcessing();
@@ -140,8 +139,7 @@ TYPED_TEST_P(PasswordStoreOriginTest,
RemoveLoginsByURLAndTimeImpl_NotWithinTimeInterval) {
const char origin_url[] = "http://foo.example.com/";
std::unique_ptr<autofill::PasswordForm> form =
- CreatePasswordFormFromDataForTesting(
- CreateTestPasswordFormDataByOrigin(origin_url));
+ FillPasswordFormWithData(CreateTestPasswordFormDataByOrigin(origin_url));
this->delegate_.store()->AddLogin(*form);
this->delegate_.FinishAsyncProcessing();
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 3cf24b2b7eb..9d58931ce42 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// The passwords in the tests below are all empty because PasswordStoreDefault
-// does not store the actual passwords on OS X (they are stored in the Keychain
-// instead). We could special-case it, but it is easier to just have empty
-// passwords. This will not be needed anymore if crbug.com/466638 is fixed.
-
#include <stddef.h>
#include <utility>
@@ -15,13 +10,11 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_task_environment.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/os_crypt/os_crypt_mocker.h"
@@ -83,6 +76,8 @@ constexpr const char kTestAndroidIconURL2[] = "https://example.com/icon_2.png";
class MockPasswordStoreConsumer : public PasswordStoreConsumer {
public:
+ MockPasswordStoreConsumer() = default;
+
MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
void(const std::vector<std::unique_ptr<PasswordForm>>&));
@@ -91,6 +86,9 @@ class MockPasswordStoreConsumer : public PasswordStoreConsumer {
std::vector<std::unique_ptr<PasswordForm>> results) override {
OnGetPasswordStoreResultsConstRef(results);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreConsumer);
};
class MockPasswordStoreSigninNotifier : public PasswordStoreSigninNotifier {
@@ -101,10 +99,12 @@ class MockPasswordStoreSigninNotifier : public PasswordStoreSigninNotifier {
class StartSyncFlareMock {
public:
- StartSyncFlareMock() {}
- ~StartSyncFlareMock() {}
+ StartSyncFlareMock() = default;
MOCK_METHOD1(StartSyncFlare, void(syncer::ModelType));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StartSyncFlareMock);
};
} // namespace
@@ -119,26 +119,28 @@ class PasswordStoreTest : public testing::Test {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
// Mock OSCrypt. There is a call to OSCrypt on initializling
// PasswordReuseDetector, so it should be mocked.
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
}
void TearDown() override {
- ASSERT_TRUE(temp_dir_.Delete());
OSCryptMocker::TearDown();
}
+ void WaitForPasswordStore() { scoped_task_environment_.RunUntilIdle(); }
+
base::FilePath test_login_db_file_path() const {
return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test"));
}
- base::test::ScopedTaskEnvironment scoped_task_environment_;
+ private:
base::ScopedTempDir temp_dir_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStoreTest);
};
TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
@@ -177,10 +179,9 @@ TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
// Build the forms vector and add the forms to the store.
std::vector<std::unique_ptr<PasswordForm>> all_forms;
for (size_t i = 0; i < arraysize(form_data); ++i) {
- all_forms.push_back(CreatePasswordFormFromDataForTesting(form_data[i]));
+ all_forms.push_back(FillPasswordFormWithData(form_data[i]));
store->AddLogin(*all_forms.back());
}
- base::RunLoop().RunUntilIdle();
// We expect to get back only the "recent" www.google.com login.
// Theoretically these should never actually exist since there are no longer
@@ -224,87 +225,27 @@ TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
store->GetLogins(accounts_google, &consumer);
store->GetLogins(bar_example, &consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
TEST_F(PasswordStoreTest, StartSyncFlare) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
StartSyncFlareMock mock;
store->Init(
base::Bind(&StartSyncFlareMock::StartSyncFlare, base::Unretained(&mock)),
nullptr);
- {
- PasswordForm form;
- form.origin = GURL("http://accounts.google.com/LoginAuth");
- form.signon_realm = "http://accounts.google.com/";
- EXPECT_CALL(mock, StartSyncFlare(syncer::PASSWORDS));
- store->AddLogin(form);
- base::RunLoop().RunUntilIdle();
- }
- store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(PasswordStoreTest, GetLoginImpl) {
- /* clang-format off */
- static const PasswordFormData kTestCredential = {
- PasswordForm::SCHEME_HTML,
- kTestWebRealm1,
- kTestWebOrigin1,
- "", L"", L"username_element", L"password_element",
- L"username_value",
- L"", true, 1};
- /* clang-format on */
-
- scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
- base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
- store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
- // For each attribute in the primary key, create one form that mismatches on
- // that attribute.
- std::unique_ptr<PasswordForm> test_form(
- CreatePasswordFormFromDataForTesting(kTestCredential));
- std::unique_ptr<PasswordForm> mismatching_form_1(
- new PasswordForm(*test_form));
- mismatching_form_1->signon_realm = kTestPSLMatchingWebRealm;
- std::unique_ptr<PasswordForm> mismatching_form_2(
- new PasswordForm(*test_form));
- mismatching_form_2->origin = GURL(kTestPSLMatchingWebOrigin);
- std::unique_ptr<PasswordForm> mismatching_form_3(
- new PasswordForm(*test_form));
- mismatching_form_3->username_element = base::ASCIIToUTF16("other_element");
- std::unique_ptr<PasswordForm> mismatching_form_4(
- new PasswordForm(*test_form));
- mismatching_form_4->password_element = base::ASCIIToUTF16("other_element");
- std::unique_ptr<PasswordForm> mismatching_form_5(
- new PasswordForm(*test_form));
- mismatching_form_5->username_value =
- base::ASCIIToUTF16("other_username_value");
-
- store->AddLogin(*mismatching_form_1);
- store->AddLogin(*mismatching_form_2);
- store->AddLogin(*mismatching_form_3);
- store->AddLogin(*mismatching_form_4);
- store->AddLogin(*mismatching_form_5);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(store->GetLoginImpl(*test_form));
-
- store->AddLogin(*test_form);
- base::RunLoop().RunUntilIdle();
- std::unique_ptr<PasswordForm> returned_form = store->GetLoginImpl(*test_form);
- ASSERT_TRUE(returned_form);
- EXPECT_EQ(*test_form, *returned_form);
+ PasswordForm form;
+ form.origin = GURL("http://accounts.google.com/LoginAuth");
+ form.signon_realm = "http://accounts.google.com/";
+ EXPECT_CALL(mock, StartSyncFlare(syncer::PASSWORDS));
+ store->AddLogin(form);
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
@@ -327,21 +268,19 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
std::unique_ptr<PasswordForm> old_form(
- CreatePasswordFormFromDataForTesting(kTestCredentials[0]));
+ FillPasswordFormWithData(kTestCredentials[0]));
store->AddLogin(*old_form);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
MockPasswordStoreObserver mock_observer;
store->AddObserver(&mock_observer);
std::unique_ptr<PasswordForm> new_form(
- CreatePasswordFormFromDataForTesting(kTestCredentials[1]));
+ FillPasswordFormWithData(kTestCredentials[1]));
EXPECT_CALL(mock_observer, OnLoginsChanged(testing::SizeIs(2u)));
PasswordForm old_primary_key;
old_primary_key.signon_realm = old_form->signon_realm;
@@ -350,7 +289,8 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
old_primary_key.username_value = old_form->username_value;
old_primary_key.password_element = old_form->password_element;
store->UpdateLoginWithPrimaryKey(*new_form, old_primary_key);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
+ testing::Mock::VerifyAndClearExpectations(&mock_observer);
MockPasswordStoreConsumer mock_consumer;
std::vector<std::unique_ptr<PasswordForm>> expected_forms;
@@ -359,11 +299,10 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_forms)));
store->GetAutofillableLogins(&mock_consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->RemoveObserver(&mock_observer);
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
// Verify that RemoveLoginsCreatedBetween() fires the completion callback after
@@ -381,29 +320,27 @@ TEST_F(PasswordStoreTest, RemoveLoginsCreatedBetweenCallbackIsCalled) {
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
std::unique_ptr<PasswordForm> test_form(
- CreatePasswordFormFromDataForTesting(kTestCredential));
+ FillPasswordFormWithData(kTestCredential));
store->AddLogin(*test_form);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
MockPasswordStoreObserver mock_observer;
store->AddObserver(&mock_observer);
EXPECT_CALL(mock_observer, OnLoginsChanged(testing::SizeIs(1u)));
- store->RemoveLoginsCreatedBetween(
- base::Time::FromDoubleT(0), base::Time::FromDoubleT(2),
- base::MessageLoop::current()->QuitWhenIdleClosure());
- base::RunLoop().Run();
+ base::RunLoop run_loop;
+ store->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(0),
+ base::Time::FromDoubleT(2),
+ run_loop.QuitClosure());
+ run_loop.Run();
testing::Mock::VerifyAndClearExpectations(&mock_observer);
store->RemoveObserver(&mock_observer);
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
// When no Android applications are actually affiliated with the realm of the
@@ -435,8 +372,6 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
@@ -445,16 +380,13 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
- all_credentials.push_back(
- CreatePasswordFormFromDataForTesting(kTestCredentials[i]));
+ all_credentials.push_back(FillPasswordFormWithData(kTestCredentials[i]));
store->AddLogin(*all_credentials.back());
- base::RunLoop().RunUntilIdle();
}
PasswordStore::FormDigest observed_form = {
PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
- MockPasswordStoreConsumer mock_consumer;
std::vector<std::unique_ptr<PasswordForm>> expected_results;
expected_results.push_back(
base::MakeUnique<PasswordForm>(*all_credentials[0]));
@@ -469,12 +401,13 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
mock_helper->ExpectCallToGetAffiliatedAndroidRealms(
observed_form, no_affiliated_android_realms);
+ MockPasswordStoreConsumer mock_consumer;
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
store->GetLogins(observed_form, &mock_consumer);
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
// There are 3 Android applications affiliated with the realm of the observed
@@ -483,66 +416,63 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
// and PSL matching credentials, and the credentials for these two Android
// applications, but not for the unaffiliated Android application.
TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
- /* clang-format off */
- static const PasswordFormData kTestCredentials[] = {
+ static constexpr const struct {
+ PasswordFormData form_data;
+ bool use_federated_login;
+ } kTestCredentials[] = {
// Credential that is an exact match of the observed form.
- {PasswordForm::SCHEME_HTML,
- kTestWebRealm1,
- kTestWebOrigin1,
- "", L"", L"", L"",
- L"username_value_1",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"",
+ L"", L"", L"username_value_1", L"", true, 1},
+ false,
+ },
// Credential that is a PSL match of the observed form.
- {PasswordForm::SCHEME_HTML,
- kTestPSLMatchingWebRealm,
- kTestPSLMatchingWebOrigin,
- "", L"", L"", L"",
- L"username_value_2",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestPSLMatchingWebRealm,
+ kTestPSLMatchingWebOrigin, "", L"", L"", L"", L"username_value_2",
+ L"", true, 1},
+ false,
+ },
// Credential for an Android application affiliated with the realm of the
// observed from.
- {PasswordForm::SCHEME_HTML,
- kTestAndroidRealm1,
- "", "", L"", L"", L"",
- L"username_value_3",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
+ L"username_value_3", L"", true, 1},
+ false,
+ },
// Second credential for the same Android application.
- {PasswordForm::SCHEME_HTML,
- kTestAndroidRealm1,
- "", "", L"", L"", L"",
- L"username_value_3b",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
+ L"username_value_3b", L"", true, 1},
+ false,
+ },
// Third credential for the same application which is username-only.
- {PasswordForm::SCHEME_USERNAME_ONLY,
- kTestAndroidRealm1,
- "", "", L"", L"", L"",
- L"username_value_3c",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_USERNAME_ONLY, kTestAndroidRealm1, "", "", L"",
+ L"", L"", L"username_value_3c", L"", true, 1},
+ false,
+ },
// Credential for another Android application affiliated with the realm
// of the observed from.
- {PasswordForm::SCHEME_HTML,
- kTestAndroidRealm2,
- "", "", L"", L"", L"",
- L"username_value_4",
- L"", true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
+ L"username_value_4", L"", true, 1},
+ false,
+ },
// Federated credential for this second Android application.
- {PasswordForm::SCHEME_HTML,
- kTestAndroidRealm2,
- "", "", L"", L"", L"",
- L"username_value_4b",
- kTestingFederatedLoginMarker, true, 1},
+ {
+ {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
+ L"username_value_4b", L"", true, 1},
+ true,
+ },
// Credential for an unrelated Android application.
- {PasswordForm::SCHEME_HTML,
- kTestUnrelatedAndroidRealm,
- "", "", L"", L"", L"",
- L"username_value_5",
- L"", true, 1}
- };
- /* clang-format on */
+ {
+ {PasswordForm::SCHEME_HTML, kTestUnrelatedAndroidRealm, "", "", L"",
+ L"", L"", L"username_value_5", L"", true, 1},
+ false,
+ }};
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
@@ -550,17 +480,15 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
store->SetAffiliatedMatchHelper(base::WrapUnique(mock_helper));
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
- for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
+ for (const auto& i : kTestCredentials) {
all_credentials.push_back(
- CreatePasswordFormFromDataForTesting(kTestCredentials[i]));
+ FillPasswordFormWithData(i.form_data, i.use_federated_login));
store->AddLogin(*all_credentials.back());
- base::RunLoop().RunUntilIdle();
}
PasswordStore::FormDigest observed_form = {
PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
- MockPasswordStoreConsumer mock_consumer;
std::vector<std::unique_ptr<PasswordForm>> expected_results;
expected_results.push_back(
base::MakeUnique<PasswordForm>(*all_credentials[0]));
@@ -590,30 +518,20 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
mock_helper->ExpectCallToGetAffiliatedAndroidRealms(
observed_form, affiliated_android_realms);
+ MockPasswordStoreConsumer mock_consumer;
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
store->GetLogins(observed_form, &mock_consumer);
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
-// This test must use passwords, which are not stored on Mac, therefore the test
-// is disabled on Mac. This should not be a huge issue as functionality in the
-// platform-independent base class is tested. See also the file-level comment.
-#if defined(OS_MACOSX)
-#define MAYBE_UpdatePasswordsStoredForAffiliatedWebsites \
- DISABLED_UpdatePasswordsStoredForAffiliatedWebsites
-#else
-#define MAYBE_UpdatePasswordsStoredForAffiliatedWebsites \
- UpdatePasswordsStoredForAffiliatedWebsites
-#endif
-
// When the password stored for an Android application is updated, credentials
// with the same username stored for affiliated web sites should also be updated
// automatically.
-TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
+TEST_F(PasswordStoreTest, UpdatePasswordsStoredForAffiliatedWebsites) {
const wchar_t kTestUsername[] = L"username_value_1";
const wchar_t kTestOtherUsername[] = L"username_value_2";
const wchar_t kTestOldPassword[] = L"old_password_value";
@@ -725,8 +643,6 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
<< test_remove_and_add_login);
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
@@ -736,12 +652,12 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
all_credentials.push_back(
- CreatePasswordFormFromDataForTesting(kTestCredentials[i]));
+ FillPasswordFormWithData(kTestCredentials[i]));
all_credentials.back()->date_synced =
all_credentials.back()->date_created;
store->AddLogin(*all_credentials.back());
- base::RunLoop().RunUntilIdle();
}
+ WaitForPasswordStore();
// The helper must be injected after the initial test data is set up,
// otherwise it will already start propagating updates as new Android
@@ -791,12 +707,18 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
expected_number_of_propageted_updates)));
}
if (test_remove_and_add_login) {
- store->RemoveLoginSync(*all_credentials[0]);
- store->AddLoginSync(*expected_credentials_after_update[0]);
+ store->ScheduleTask(
+ base::Bind(IgnoreResult(&PasswordStore::RemoveLoginSync), store,
+ *all_credentials[0]));
+ store->ScheduleTask(
+ base::Bind(IgnoreResult(&PasswordStore::AddLoginSync), store,
+ *expected_credentials_after_update[0]));
} else {
- store->UpdateLoginSync(*expected_credentials_after_update[0]);
+ store->ScheduleTask(
+ base::Bind(IgnoreResult(&PasswordStore::UpdateLoginSync), store,
+ *expected_credentials_after_update[0]));
}
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->RemoveObserver(&mock_observer);
MockPasswordStoreConsumer mock_consumer;
@@ -804,8 +726,11 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
UnorderedPasswordFormElementsAre(
&expected_credentials_after_update)));
store->GetAutofillableLogins(&mock_consumer);
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
+ store = nullptr;
+ // Finish processing so that the database isn't locked next iteration.
+ WaitForPasswordStore();
}
}
}
@@ -824,8 +749,6 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliationAndBrandingInformation) {
for (bool blacklisted : {false, true}) {
SCOPED_TRACE(testing::Message("use blacklisted logins: ") << blacklisted);
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
@@ -833,11 +756,9 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliationAndBrandingInformation) {
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
for (const auto& test_credential : kTestCredentials) {
- all_credentials.push_back(
- CreatePasswordFormFromDataForTesting(test_credential));
+ all_credentials.push_back(FillPasswordFormWithData(test_credential));
all_credentials.back()->blacklisted_by_user = blacklisted;
store->AddLogin(*all_credentials.back());
- base::RunLoop().RunUntilIdle();
}
MockPasswordStoreConsumer mock_consumer;
@@ -879,9 +800,11 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliationAndBrandingInformation) {
// Since GetAutofillableLoginsWithAffiliationAndBrandingInformation
// schedules a request for affiliation information to UI thread, don't
// shutdown UI thread until there are no tasks in the UI queue.
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
+ store = nullptr;
+ // Finish processing so that the database isn't locked next iteration.
+ WaitForPasswordStore();
}
}
@@ -915,19 +838,17 @@ TEST_F(PasswordStoreTest, GetLoginsForSameOrganizationName) {
L"username_value_6", L"", true, 1}};
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
std::vector<std::unique_ptr<PasswordForm>> expected_results;
for (const auto& form_data : kSameOrganizationCredentials) {
- expected_results.push_back(CreatePasswordFormFromDataForTesting(form_data));
+ expected_results.push_back(FillPasswordFormWithData(form_data));
store->AddLogin(*expected_results.back());
}
for (const auto& form_data : kNotSameOrganizationCredentials) {
- store->AddLogin(*CreatePasswordFormFromDataForTesting(form_data));
+ store->AddLogin(*FillPasswordFormWithData(form_data));
}
const std::string observed_form_realm = kTestWebRealm1;
@@ -936,9 +857,8 @@ TEST_F(PasswordStoreTest, GetLoginsForSameOrganizationName) {
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
store->GetLoginsForSameOrganizationName(observed_form_realm, &mock_consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
// TODO(crbug.com/706392): Fix password reuse detection for Android.
@@ -951,53 +871,49 @@ TEST_F(PasswordStoreTest, CheckPasswordReuse) {
"https://facebook.com", "", L"", L"", L"", L"", L"topsecret", true, 1}};
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
for (const auto& test_credentials : kTestCredentials) {
- auto credentials = CreatePasswordFormFromDataForTesting(test_credentials);
+ auto credentials = FillPasswordFormWithData(test_credentials);
store->AddLogin(*credentials);
- base::RunLoop().RunUntilIdle();
}
- static constexpr struct {
+ struct {
const wchar_t* input;
const char* domain;
- const wchar_t* reused_password; // Set to nullptr if no reuse is expected.
+ const size_t reused_password_len; // Set to 0 if no reuse is expected.
const char* reuse_domain;
} kReuseTestData[] = {
- {L"12345password", "https://evil.com", L"password", "google.com"},
- {L"1234567890", "https://evil.com", nullptr, nullptr},
- {L"topsecret", "https://m.facebook.com", nullptr, nullptr},
+ {L"12345password", "https://evil.com", strlen("password"), "google.com"},
+ {L"1234567890", "https://evil.com", 0, nullptr},
+ {L"topsecret", "https://m.facebook.com", 0, nullptr},
};
for (const auto& test_data : kReuseTestData) {
MockPasswordReuseDetectorConsumer mock_consumer;
- if (test_data.reused_password) {
- EXPECT_CALL(mock_consumer,
- OnReuseFound(base::WideToUTF16(test_data.reused_password),
- std::string(test_data.reuse_domain), 2, 1));
+ if (test_data.reused_password_len != 0) {
+ EXPECT_CALL(
+ mock_consumer,
+ OnReuseFound(test_data.reused_password_len,
+ false /* matches_sync_password */,
+ std::vector<std::string>({test_data.reuse_domain}), 2));
} else {
EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
}
store->CheckReuse(base::WideToUTF16(test_data.input), test_data.domain,
&mock_consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
}
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
#endif
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
TEST_F(PasswordStoreTest, SavingClearingSyncPassword) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
TestingPrefServiceSimple prefs;
@@ -1012,16 +928,16 @@ TEST_F(PasswordStoreTest, SavingClearingSyncPassword) {
const base::string16 sync_password = base::ASCIIToUTF16("password");
const base::string16 input = base::ASCIIToUTF16("123password");
store->SaveSyncPasswordHash(sync_password);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
EXPECT_TRUE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
// Check that sync password reuse is found.
MockPasswordReuseDetectorConsumer mock_consumer;
- EXPECT_CALL(
- mock_consumer,
- OnReuseFound(sync_password, std::string(kSyncPasswordDomain), 1, 0));
+ EXPECT_CALL(mock_consumer, OnReuseFound(sync_password.size(),
+ true /* matches_sync_password */,
+ std::vector<std::string>(), 0));
store->CheckReuse(input, "https://facebook.com", &mock_consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
testing::Mock::VerifyAndClearExpectations(&mock_consumer);
// Check that no sync password reuse is found after clearing the saved sync
@@ -1030,16 +946,13 @@ TEST_F(PasswordStoreTest, SavingClearingSyncPassword) {
EXPECT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
store->CheckReuse(input, "https://facebook.com", &mock_consumer);
- base::RunLoop().RunUntilIdle();
+ WaitForPasswordStore();
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
TEST_F(PasswordStoreTest, SubscriptionAndUnsubscriptionFromSignInEvents) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
- base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get(),
base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
std::unique_ptr<MockPasswordStoreSigninNotifier> notifier =
@@ -1054,7 +967,6 @@ TEST_F(PasswordStoreTest, SubscriptionAndUnsubscriptionFromSignInEvents) {
// Check that |store| is unsubscribed from sign-in events on shutdown.
EXPECT_CALL(*notifier_weak, UnsubscribeFromSigninEvents());
store->ShutdownOnUIThread();
- base::RunLoop().RunUntilIdle();
}
#endif
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service.cc b/chromium/components/password_manager/core/browser/password_syncable_service.cc
index 6584b88d194..a1c2dd628f1 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service.cc
@@ -340,9 +340,7 @@ PasswordSyncableService::PasswordSyncableService(
clock_(new base::DefaultClock),
is_processing_sync_changes_(false) {}
-PasswordSyncableService::~PasswordSyncableService() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
+PasswordSyncableService::~PasswordSyncableService() = default;
syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
syncer::ModelType type,
@@ -516,9 +514,10 @@ bool PasswordSyncableService::ReadFromPasswordStore(
!password_store_->FillBlacklistLogins(&blacklist_entries)) {
// Password store often fails to load passwords. Track failures with UMA.
// (http://crbug.com/249000)
+ // TODO(wychen): enum uma should be strongly typed. crbug.com/661401
UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
ModelTypeToHistogramInt(syncer::PASSWORDS),
- syncer::MODEL_TYPE_COUNT);
+ static_cast<int>(syncer::MODEL_TYPE_COUNT));
return false;
}
password_entries->resize(autofillable_entries.size() +
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
index c487e6682cc..5c38bc553ce 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
@@ -184,6 +184,7 @@ class PasswordSyncableServiceWrapper {
public:
PasswordSyncableServiceWrapper() {
password_store_ = new testing::StrictMock<MockPasswordStore>;
+ password_store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
service_.reset(
new PasswordSyncableService(password_store_->GetSyncInterface()));
auto clock = base::MakeUnique<base::SimpleTestClock>();
@@ -746,7 +747,7 @@ class PasswordSyncableServiceAndroidAutofillTest : public testing::Test {
}
static autofill::PasswordForm FormWithCorrectTag(PasswordFormData data) {
- autofill::PasswordForm form = *CreatePasswordFormFromDataForTesting(data);
+ autofill::PasswordForm form = *FillPasswordFormWithData(data);
form.signon_realm = kAndroidCorrectRealm;
form.origin = GURL(kAndroidCorrectRealm);
form.date_synced = PasswordSyncableServiceWrapper::time();
@@ -755,7 +756,7 @@ class PasswordSyncableServiceAndroidAutofillTest : public testing::Test {
static autofill::PasswordForm FormWithAndroidAutofillTag(
PasswordFormData data) {
- autofill::PasswordForm form = *CreatePasswordFormFromDataForTesting(data);
+ autofill::PasswordForm form = *FillPasswordFormWithData(data);
form.signon_realm = kAndroidAutofillRealm;
form.origin = GURL(kAndroidAutofillRealm);
form.date_synced = PasswordSyncableServiceWrapper::time();
@@ -777,7 +778,7 @@ class PasswordSyncableServiceAndroidAutofillTest : public testing::Test {
testing::Message message;
message << prefix;
if (data)
- message << *CreatePasswordFormFromDataForTesting(*data);
+ message << *FillPasswordFormWithData(*data);
else
message << "NULL";
return message;
@@ -807,19 +808,17 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, FourWayMerge) {
expected_sync_updates.push_back(FormWithCorrectTag(*latest_data));
if (latest_data != &data[1])
expected_sync_updates.push_back(FormWithAndroidAutofillTag(*latest_data));
- autofill::PasswordForm local_correct =
- *CreatePasswordFormFromDataForTesting(data[2]);
- autofill::PasswordForm local_incorrect =
- *CreatePasswordFormFromDataForTesting(data[3]);
+ autofill::PasswordForm local_correct = *FillPasswordFormWithData(data[2]);
+ autofill::PasswordForm local_incorrect = *FillPasswordFormWithData(data[3]);
syncer::SyncData sync_correct =
- SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data[0]));
+ SyncDataFromPassword(*FillPasswordFormWithData(data[0]));
syncer::SyncData sync_incorrect =
- SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data[1]));
+ SyncDataFromPassword(*FillPasswordFormWithData(data[1]));
- SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[0]));
- SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[1]));
- SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[2]));
- SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[3]));
+ SCOPED_TRACE(*FillPasswordFormWithData(data[0]));
+ SCOPED_TRACE(*FillPasswordFormWithData(data[1]));
+ SCOPED_TRACE(*FillPasswordFormWithData(data[2]));
+ SCOPED_TRACE(*FillPasswordFormWithData(data[3]));
for (bool correct_sync_first : {true, false}) {
auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>();
@@ -930,15 +929,14 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, ThreeWayMerge) {
std::vector<autofill::PasswordForm> stored_forms;
for (int i = 2; i < 4; ++i) {
if (data[i])
- stored_forms.push_back(
- *CreatePasswordFormFromDataForTesting(*data[i]));
+ stored_forms.push_back(*FillPasswordFormWithData(*data[i]));
}
SyncDataList sync_list;
for (int i = 0; i < 2; ++i) {
if (data[i]) {
- sync_list.push_back(SyncDataFromPassword(
- *CreatePasswordFormFromDataForTesting(*data[i])));
+ sync_list.push_back(
+ SyncDataFromPassword(*FillPasswordFormWithData(*data[i])));
}
}
@@ -1026,8 +1024,7 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, TwoWayServerAndLocalMerge) {
base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>();
EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(
- AppendForm(*CreatePasswordFormFromDataForTesting(local_data)));
+ .WillOnce(AppendForm(*FillPasswordFormWithData(local_data)));
EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_))
.WillOnce(Return(true));
if (!local_data_correct || latest_data == &sync_data) {
@@ -1089,8 +1086,8 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, TwoWayServerAndLocalMerge) {
expected_sync_updates[1].second))));
}
- SyncDataList sync_list = {SyncDataFromPassword(
- *CreatePasswordFormFromDataForTesting(sync_data))};
+ SyncDataList sync_list = {
+ SyncDataFromPassword(*FillPasswordFormWithData(sync_data))};
wrapper->service()->MergeDataAndStartSyncing(
syncer::PASSWORDS, sync_list, std::move(processor),
std::unique_ptr<syncer::SyncErrorFactory>());
@@ -1122,7 +1119,7 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, OneEntryOnly) {
if (entry_is_local) {
EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
- .WillOnce(AppendForm(*CreatePasswordFormFromDataForTesting(data)));
+ .WillOnce(AppendForm(*FillPasswordFormWithData(data)));
} else {
EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_))
.WillOnce(Return(true));
@@ -1150,7 +1147,7 @@ TEST_F(PasswordSyncableServiceAndroidAutofillTest, OneEntryOnly) {
SyncDataList sync_list;
if (!entry_is_local) {
sync_list.push_back(
- SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data)));
+ SyncDataFromPassword(*FillPasswordFormWithData(data)));
}
wrapper->service()->MergeDataAndStartSyncing(
syncer::PASSWORDS, sync_list, std::move(processor),
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc b/chromium/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
index 22ca913a1bd..4523e616075 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
@@ -45,7 +45,7 @@ void AssetLinkRetriever::Start(net::URLRequestContextGetter* context_getter) {
destination: WEBSITE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "No setting"
policy_exception_justification:
"The file is considered to be a resource of the page loaded."
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 14a3cbba52e..b24baff278b 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
@@ -24,6 +24,13 @@ bool StubPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
return false;
}
+void StubPasswordManagerClient::ShowManualFallbackForSaving(
+ std::unique_ptr<PasswordFormManager> form_to_save,
+ bool has_generated_password,
+ bool update_password) {}
+
+void StubPasswordManagerClient::HideManualFallbackForSaving() {}
+
bool StubPasswordManagerClient::PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
const GURL& origin,
@@ -78,8 +85,11 @@ void StubPasswordManagerClient::CheckSafeBrowsingReputation(
const GURL& frame_url) {}
void StubPasswordManagerClient::CheckProtectedPasswordEntry(
- const std::string& password_saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
bool password_field_exists) {}
+
+void StubPasswordManagerClient::LogPasswordReuseDetectedEvent() {}
#endif
ukm::UkmRecorder* StubPasswordManagerClient::GetUkmRecorder() {
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 a33c7b2c8cd..1578d649981 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
@@ -26,6 +26,11 @@ class StubPasswordManagerClient : public PasswordManagerClient {
bool PromptUserToSaveOrUpdatePassword(
std::unique_ptr<PasswordFormManager> form_to_save,
bool update_password) override;
+ void ShowManualFallbackForSaving(
+ std::unique_ptr<PasswordFormManager> form_to_save,
+ bool has_generated_password,
+ bool update_password) override;
+ void HideManualFallbackForSaving() override;
bool PromptUserToChooseCredentials(
std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
const GURL& origin,
@@ -50,8 +55,11 @@ class StubPasswordManagerClient : public PasswordManagerClient {
const override;
void CheckSafeBrowsingReputation(const GURL& form_action,
const GURL& frame_url) override;
- void CheckProtectedPasswordEntry(const std::string& password_saved_domain,
- bool password_field_exists) override;
+ void CheckProtectedPasswordEntry(
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ bool password_field_exists) override;
+ void LogPasswordReuseDetectedEvent() override;
#endif
ukm::UkmRecorder* GetUkmRecorder() override;
ukm::SourceId GetUkmSourceId() override;
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
index 4a9145faa38..2cb66c1695c 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
@@ -64,4 +64,6 @@ bool StubPasswordManagerDriver::IsMainFrame() const {
return true;
}
+void StubPasswordManagerDriver::MatchingBlacklistedFormFound() {}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
index 406190aef35..f914a783791 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
@@ -38,6 +38,7 @@ class StubPasswordManagerDriver : public PasswordManagerDriver {
PasswordAutofillManager* GetPasswordAutofillManager() override;
autofill::AutofillDriver* GetAutofillDriver() override;
bool IsMainFrame() const override;
+ void MatchingBlacklistedFormFound() override;
private:
DISALLOW_COPY_AND_ASSIGN(StubPasswordManagerDriver);
diff --git a/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
index d4caa0422a2..c3ac57d0959 100644
--- a/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
@@ -135,13 +135,11 @@ TEST_F(SuppressedFormFetcherTest, FullStore) {
std::vector<std::unique_ptr<PasswordForm>> simulated_store_results;
std::vector<std::unique_ptr<PasswordForm>> expected_results;
for (const auto& form_data : kSuppressedCredentials) {
- expected_results.push_back(CreatePasswordFormFromDataForTesting(form_data));
- simulated_store_results.push_back(
- CreatePasswordFormFromDataForTesting(form_data));
+ expected_results.push_back(FillPasswordFormWithData(form_data));
+ simulated_store_results.push_back(FillPasswordFormWithData(form_data));
}
for (const auto& form_data : kNotSuppressedCredentials) {
- simulated_store_results.push_back(
- CreatePasswordFormFromDataForTesting(form_data));
+ simulated_store_results.push_back(FillPasswordFormWithData(form_data));
}
EXPECT_CALL(*mock_store(), GetLoginsForSameOrganizationName(kTestHttpURL, _));
diff --git a/chromium/components/password_manager/core/browser/test_password_store.cc b/chromium/components/password_manager/core/browser/test_password_store.cc
index 5c4c585e11d..bccc22955a5 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.cc
+++ b/chromium/components/password_manager/core/browser/test_password_store.cc
@@ -14,12 +14,9 @@
namespace password_manager {
-TestPasswordStore::TestPasswordStore()
- : PasswordStore(base::SequencedTaskRunnerHandle::Get(),
- base::SequencedTaskRunnerHandle::Get()) {}
+TestPasswordStore::TestPasswordStore() = default;
-TestPasswordStore::~TestPasswordStore() {
-}
+TestPasswordStore::~TestPasswordStore() = default;
const TestPasswordStore::PasswordMap& TestPasswordStore::stored_passwords()
const {
@@ -41,6 +38,11 @@ bool TestPasswordStore::IsEmpty() const {
return number_of_passwords == 0u;
}
+scoped_refptr<base::SequencedTaskRunner>
+TestPasswordStore::CreateBackgroundTaskRunner() const {
+ return base::SequencedTaskRunnerHandle::Get();
+}
+
PasswordStoreChangeList TestPasswordStore::AddLoginImpl(
const autofill::PasswordForm& form) {
PasswordStoreChangeList changes;
diff --git a/chromium/components/password_manager/core/browser/test_password_store.h b/chromium/components/password_manager/core/browser/test_password_store.h
index 837dfaa6c7d..47c691d53cb 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.h
+++ b/chromium/components/password_manager/core/browser/test_password_store.h
@@ -37,6 +37,9 @@ class TestPasswordStore : public PasswordStore {
protected:
~TestPasswordStore() override;
+ scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
+ const override;
+
// PasswordStore interface
PasswordStoreChangeList AddLoginImpl(
const autofill::PasswordForm& form) override;
diff --git a/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.cc b/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.cc
index 8a432564fb4..efbc3916a09 100644
--- a/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.cc
+++ b/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.cc
@@ -12,10 +12,9 @@
PasswordWebDataService::PasswordWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const ProfileErrorCallback& callback)
- : WebDataServiceBase(wdbs, callback, ui_thread) {
-}
+ : WebDataServiceBase(wdbs, callback, ui_task_runner) {}
void PasswordWebDataService::AddIE7Login(const IE7PasswordInfo& info) {
wdbs_->ScheduleDBTask(
@@ -64,9 +63,8 @@ std::unique_ptr<WDTypedResult> PasswordWebDataService::GetIE7LoginImpl(
////////////////////////////////////////////////////////////////////////////////
PasswordWebDataService::PasswordWebDataService(
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread)
- : WebDataServiceBase(nullptr, ProfileErrorCallback(), ui_thread) {
-}
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : WebDataServiceBase(nullptr, ProfileErrorCallback(), ui_task_runner) {}
PasswordWebDataService::~PasswordWebDataService() {
}
diff --git a/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.h b/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.h
index 2957b6ddbef..08d0e5359d2 100644
--- a/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.h
+++ b/chromium/components/password_manager/core/browser/webdata/password_web_data_service_win.h
@@ -37,9 +37,10 @@ class PasswordWebDataService : public WebDataServiceBase {
static scoped_refptr<PasswordWebDataService> FromBrowserContext(
content::BrowserContext* context);
- PasswordWebDataService(scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- const ProfileErrorCallback& callback);
+ PasswordWebDataService(
+ scoped_refptr<WebDatabaseService> wdbs,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const ProfileErrorCallback& callback);
// Adds |info| to the list of imported passwords from ie7/ie8.
void AddIE7Login(const IE7PasswordInfo& info);
@@ -57,12 +58,13 @@ class PasswordWebDataService : public WebDataServiceBase {
protected:
// For unit tests, passes a null callback.
- PasswordWebDataService(scoped_refptr<base::SingleThreadTaskRunner> ui_thread);
+ PasswordWebDataService(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
~PasswordWebDataService() override;
private:
- // The following methods are only invoked on the DB thread.
+ // The following methods are only invoked on the DB sequence.
WebDatabase::State AddIE7LoginImpl(const IE7PasswordInfo& info,
WebDatabase* db);
WebDatabase::State RemoveIE7LoginImpl(const IE7PasswordInfo& info,
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 b9fffab9380..876b44790d1 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.h
+++ b/chromium/components/password_manager/core/common/credential_manager_types.h
@@ -33,6 +33,14 @@ enum class CredentialType {
CREDENTIAL_TYPE_LAST = CREDENTIAL_TYPE_FEDERATED
};
+enum class CredentialManagerError {
+ SUCCESS,
+ DISABLED,
+ PENDINGREQUEST,
+ PASSWORDSTOREUNAVAILABLE,
+ UNKNOWN,
+};
+
enum class CredentialMediationRequirement { kSilent, kOptional, kRequired };
std::string CredentialTypeToString(CredentialType value);
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 5dce1e7eba2..f84366b8576 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/common/password_manager_features.h"
+#include "build/build_config.h"
+
namespace password_manager {
namespace features {
@@ -18,6 +20,17 @@ const base::Feature kAffiliationBasedMatching = {
const base::Feature kDropSyncCredential = {"drop-sync-credential",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Enable additional elements in the form popup UI, which will allow the user to
+// view all saved passwords.
+const base::Feature kEnableManualFallbacksFilling = {
+ "EnableManualFallbacksFilling", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enable that an omnibox icon is shown when the user types into a password
+// field. When the user clicks on the icon, a password save/update bubble is
+// shown.
+const base::Feature kEnableManualSaving = {"EnableManualSaving",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Enable a context menu item in the password field that allows the user
// to manually enforce saving of their password.
const base::Feature kEnablePasswordForceSaving = {
@@ -29,7 +42,11 @@ extern const base::Feature kEnableManualPasswordGeneration = {
// Enables username correction while saving username and password details.
extern const base::Feature kEnableUsernameCorrection{
- "EnableUsernameCorrection", base::FEATURE_DISABLED_BY_DEFAULT};
+ "EnableUsernameCorrection", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables password selection while saving username and password details.
+extern const base::Feature kEnablePasswordSelection{
+ "EnablePasswordSelection", base::FEATURE_DISABLED_BY_DEFAULT};
// Disallow autofilling of the sync credential.
const base::Feature kProtectSyncCredential = {
@@ -47,7 +64,7 @@ const base::Feature kPasswordImportExport = {"password-import-export",
// mobile, the desktop version of Chrome always allows users to view
// passwords.
const base::Feature kViewPasswords = {"view-passwords",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Enables the experiment for the password manager to only fill on account
// selection, rather than autofilling on page load, with highlighting of fields.
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 ba39cbdaba5..96cc8f432b7 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,11 @@ namespace features {
extern const base::Feature kAffiliationBasedMatching;
extern const base::Feature kDropSyncCredential;
+extern const base::Feature kEnableManualFallbacksFilling;
extern const base::Feature kEnableManualPasswordGeneration;
+extern const base::Feature kEnableManualSaving;
extern const base::Feature kEnablePasswordForceSaving;
+extern const base::Feature kEnablePasswordSelection;
extern const base::Feature kEnableUsernameCorrection;
extern const base::Feature kProtectSyncCredential;
extern const base::Feature kProtectSyncCredentialOnReauth;
diff --git a/chromium/components/payments/android/payment_manifest_web_data_service.cc b/chromium/components/payments/android/payment_manifest_web_data_service.cc
index b217c3d0e33..7b08631818e 100644
--- a/chromium/components/payments/android/payment_manifest_web_data_service.cc
+++ b/chromium/components/payments/android/payment_manifest_web_data_service.cc
@@ -12,8 +12,8 @@ namespace payments {
PaymentManifestWebDataService::PaymentManifestWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread)
- : WebDataServiceBase(wdbs, callback, ui_thread) {}
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
+ : WebDataServiceBase(wdbs, callback, ui_task_runner) {}
PaymentManifestWebDataService::~PaymentManifestWebDataService() {}
diff --git a/chromium/components/payments/android/payment_manifest_web_data_service.h b/chromium/components/payments/android/payment_manifest_web_data_service.h
index 525172722f1..5e33db9dcb9 100644
--- a/chromium/components/payments/android/payment_manifest_web_data_service.h
+++ b/chromium/components/payments/android/payment_manifest_web_data_service.h
@@ -22,7 +22,7 @@ class PaymentManifestWebDataService : public WebDataServiceBase {
PaymentManifestWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread);
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
// Adds the web app |manifest|.
void AddPaymentWebAppManifest(
diff --git a/chromium/components/payments/content/BUILD.gn b/chromium/components/payments/content/BUILD.gn
index c856ae90c14..e7ea8512eb6 100644
--- a/chromium/components/payments/content/BUILD.gn
+++ b/chromium/components/payments/content/BUILD.gn
@@ -26,10 +26,12 @@ static_library("content") {
"//components/payments/core",
"//components/prefs",
"//components/strings:components_strings_grit",
+ "//components/url_formatter",
"//content/public/browser",
"//mojo/public/cpp/bindings",
"//third_party/WebKit/public:blink_headers",
"//third_party/libphonenumber",
+ "//url",
]
}
@@ -39,28 +41,19 @@ static_library("utils") {
"origin_security_checker.h",
"payment_details_validation.cc",
"payment_details_validation.h",
- "payment_manifest_downloader.cc",
- "payment_manifest_downloader.h",
"payment_manifest_parser_host.cc",
"payment_manifest_parser_host.h",
- "payments_validators.cc",
- "payments_validators.h",
]
deps = [
- "//base",
"//components/autofill/core/browser",
- "//components/data_use_measurement/core",
- "//components/link_header_util",
"//components/payments/core",
"//components/payments/mojom:mojom_parser",
"//components/strings",
"//content/public/browser",
"//net",
"//third_party/WebKit/public:blink_headers",
- "//third_party/re2",
"//ui/base",
- "//url",
]
public_deps = [
@@ -72,11 +65,9 @@ static_library("utils") {
source_set("unit_tests") {
testonly = true
sources = [
- "payment_manifest_downloader_unittest.cc",
"payment_request_spec_unittest.cc",
"payment_request_state_unittest.cc",
"payment_response_helper_unittest.cc",
- "payments_validators_unittest.cc",
]
deps = [
@@ -90,7 +81,6 @@ source_set("unit_tests") {
"//components/payments/core:test_support",
"//components/strings:components_strings_grit",
"//content/test:test_support",
- "//net:test_support",
"//testing/gtest",
"//third_party/WebKit/public:blink_headers",
"//third_party/icu",
diff --git a/chromium/components/payments/content/DEPS b/chromium/components/payments/content/DEPS
index 0d4155ddae1..78d416a1a86 100644
--- a/chromium/components/payments/content/DEPS
+++ b/chromium/components/payments/content/DEPS
@@ -2,16 +2,14 @@ include_rules = [
"-components/payments/content/android",
"-components/payments/content/utility",
"+components/autofill",
- "+components/data_use_measurement",
"+components/keyed_service/content",
- "+components/link_header_util",
"+components/prefs",
"+components/strings",
+ "+components/url_formatter",
"+content/public",
"+mojo/public/cpp",
"+net",
"+third_party/WebKit/public/platform/modules/payments",
"+third_party/libphonenumber",
- "+third_party/re2",
"+ui/base",
]
diff --git a/chromium/components/payments/content/android/payment_manifest_downloader_android.h b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
index cfbb4cbe908..8143429f8cd 100644
--- a/chromium/components/payments/content/android/payment_manifest_downloader_android.h
+++ b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
@@ -10,7 +10,7 @@
#include "base/android/jni_android.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "components/payments/content/payment_manifest_downloader.h"
+#include "components/payments/core/payment_manifest_downloader.h"
namespace net {
class URLRequestContextGetter;
diff --git a/chromium/components/payments/content/android/payment_manifest_parser_android.cc b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
index a740ecb4e5e..938d21aad61 100644
--- a/chromium/components/payments/content/android/payment_manifest_parser_android.cc
+++ b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
@@ -30,32 +30,46 @@ class ParseCallback {
// Copies payment method manifest into Java.
void OnPaymentMethodManifestParsed(
const std::vector<GURL>& web_app_manifest_urls,
- const std::vector<url::Origin>& unused_supported_origins,
- bool unused_all_origins_supported) {
+ const std::vector<url::Origin>& supported_origins,
+ bool all_origins_supported) {
DCHECK_GE(100U, web_app_manifest_urls.size());
+ DCHECK_GE(100000U, supported_origins.size());
JNIEnv* env = base::android::AttachCurrentThread();
- if (web_app_manifest_urls.empty()) {
+ if (web_app_manifest_urls.empty() && supported_origins.empty() &&
+ !all_origins_supported) {
// Can trigger synchronous deletion of PaymentManifestParserAndroid.
Java_ManifestParseCallback_onManifestParseFailure(env, jcallback_);
return;
}
base::android::ScopedJavaLocalRef<jobjectArray> juris =
- Java_PaymentManifestParser_createWebAppManifestUris(
- env, web_app_manifest_urls.size());
+ Java_PaymentManifestParser_createUriArray(env,
+ web_app_manifest_urls.size());
for (size_t i = 0; i < web_app_manifest_urls.size(); ++i) {
bool is_valid_uri = Java_PaymentManifestParser_addUri(
- env, juris.obj(), base::checked_cast<int>(i),
+ env, juris, base::checked_cast<int>(i),
base::android::ConvertUTF8ToJavaString(
env, web_app_manifest_urls[i].spec()));
DCHECK(is_valid_uri);
}
+ base::android::ScopedJavaLocalRef<jobjectArray> jorigins =
+ Java_PaymentManifestParser_createUriArray(env,
+ supported_origins.size());
+
+ for (size_t i = 0; i < supported_origins.size(); ++i) {
+ bool is_valid_uri = Java_PaymentManifestParser_addUri(
+ env, jorigins, base::checked_cast<int>(i),
+ base::android::ConvertUTF8ToJavaString(
+ env, supported_origins[i].Serialize()));
+ DCHECK(is_valid_uri);
+ }
+
// Can trigger synchronous deletion of PaymentManifestParserAndroid.
Java_ManifestParseCallback_onPaymentMethodManifestParseSuccess(
- env, jcallback_, juris.obj());
+ env, jcallback_, juris, jorigins, all_origins_supported);
}
// Copies web app manifest into Java.
@@ -78,7 +92,7 @@ class ParseCallback {
DCHECK_GE(100U, section->fingerprints.size());
Java_PaymentManifestParser_addSectionToManifest(
- env, jmanifest.obj(), base::checked_cast<int>(i),
+ env, jmanifest, base::checked_cast<int>(i),
base::android::ConvertUTF8ToJavaString(env, section->id),
section->min_version,
base::checked_cast<int>(section->fingerprints.size()));
@@ -86,7 +100,7 @@ class ParseCallback {
for (size_t j = 0; j < section->fingerprints.size(); ++j) {
const std::vector<uint8_t>& fingerprint = section->fingerprints[j];
Java_PaymentManifestParser_addFingerprintToSection(
- env, jmanifest.obj(), base::checked_cast<int>(i),
+ env, jmanifest, base::checked_cast<int>(i),
base::checked_cast<int>(j),
base::android::ToJavaByteArray(env, fingerprint));
}
@@ -94,7 +108,7 @@ class ParseCallback {
// Can trigger synchronous deletion of PaymentManifestParserAndroid.
Java_ManifestParseCallback_onWebAppManifestParseSuccess(env, jcallback_,
- jmanifest.obj());
+ jmanifest);
}
private:
diff --git a/chromium/components/payments/content/payment_details_validation.cc b/chromium/components/payments/content/payment_details_validation.cc
index c61946e216b..9e92682a905 100644
--- a/chromium/components/payments/content/payment_details_validation.cc
+++ b/chromium/components/payments/content/payment_details_validation.cc
@@ -7,7 +7,7 @@
#include <set>
#include <vector>
-#include "components/payments/content/payments_validators.h"
+#include "components/payments/core/payments_validators.h"
#include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
namespace payments {
@@ -40,13 +40,13 @@ bool validateShippingOptionOrPaymentItem(
return false;
}
- if (!payments::PaymentsValidators::isValidCurrencyCodeFormat(
+ if (!payments::PaymentsValidators::IsValidCurrencyCodeFormat(
item->amount->currency, item->amount->currency_system,
error_message)) {
return false;
}
- if (!payments::PaymentsValidators::isValidAmountFormat(item->amount->value,
+ if (!payments::PaymentsValidators::IsValidAmountFormat(item->amount->value,
error_message)) {
return false;
}
@@ -160,7 +160,7 @@ bool validatePaymentDetails(const mojom::PaymentDetailsPtr& details,
error_message))
return false;
}
- if (!PaymentsValidators::isValidErrorMsgFormat(details->error, error_message))
+ if (!PaymentsValidators::IsValidErrorMsgFormat(details->error, error_message))
return false;
return true;
}
diff --git a/chromium/components/payments/content/payment_manifest_parser_host.cc b/chromium/components/payments/content/payment_manifest_parser_host.cc
index aaea07c4aab..3e918fe2449 100644
--- a/chromium/components/payments/content/payment_manifest_parser_host.cc
+++ b/chromium/components/payments/content/payment_manifest_parser_host.cc
@@ -90,10 +90,12 @@ void PaymentManifestParserHost::OnPaymentMethodParse(
return;
}
+ const size_t kMaximumNumberOfSupportedOrigins = 100000;
if (web_app_manifest_urls.size() > kMaximumNumberOfItems ||
- supported_origins.size() > kMaximumNumberOfItems) {
- // If more than 100 items, then something went wrong in the utility
- // process. Stop the utility process and notify all callbacks.
+ supported_origins.size() > kMaximumNumberOfSupportedOrigins) {
+ // If more than 100 web app manifests URLs or more than 100,000 supported
+ // origins, then something went wrong in the utility process. Stop the
+ // utility process and notify all callbacks.
OnUtilityProcessStopped();
return;
}
diff --git a/chromium/components/payments/content/payment_request.cc b/chromium/components/payments/content/payment_request.cc
index 1a6e063a587..342e457a717 100644
--- a/chromium/components/payments/content/payment_request.cc
+++ b/chromium/components/payments/content/payment_request.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
#include "components/payments/content/can_make_payment_query_factory.h"
#include "components/payments/content/origin_security_checker.h"
#include "components/payments/content/payment_details_validation.h"
@@ -15,6 +16,7 @@
#include "components/payments/core/can_make_payment_query.h"
#include "components/payments/core/payment_prefs.h"
#include "components/prefs/pref_service.h"
+#include "components/url_formatter/elide_url.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -32,7 +34,10 @@ PaymentRequest::PaymentRequest(
delegate_(std::move(delegate)),
manager_(manager),
binding_(this, std::move(request)),
- frame_origin_(GURL(render_frame_host->GetLastCommittedURL()).GetOrigin()),
+ top_level_origin_(url_formatter::FormatUrlForSecurityDisplay(
+ web_contents_->GetLastCommittedURL())),
+ frame_origin_(url_formatter::FormatUrlForSecurityDisplay(
+ render_frame_host->GetLastCommittedURL())),
observer_for_testing_(observer_for_testing),
journey_logger_(delegate_->IsIncognito(),
web_contents_->GetLastCommittedURL(),
@@ -109,6 +114,30 @@ void PaymentRequest::Init(mojom::PaymentRequestClientPtr client,
state_ = base::MakeUnique<PaymentRequestState>(
spec_.get(), this, delegate_->GetApplicationLocale(),
delegate_->GetPersonalDataManager(), delegate_.get(), &journey_logger_);
+
+ journey_logger_.SetRequestedInformation(
+ spec_->request_shipping(), spec_->request_payer_email(),
+ spec_->request_payer_phone(), spec_->request_payer_name());
+
+ // Log metrics around which payment methods are requested by the merchant.
+ GURL google_pay_url(kGooglePayMethodName);
+ GURL android_pay_url(kAndroidPayMethodName);
+ // Looking for payment methods that are NOT google-related payment methods.
+ auto non_google_it =
+ std::find_if(spec_->url_payment_method_identifiers().begin(),
+ spec_->url_payment_method_identifiers().end(),
+ [google_pay_url, android_pay_url](const GURL& url) {
+ return url != google_pay_url && url != android_pay_url;
+ });
+ journey_logger_.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/!spec_->supported_card_networks().empty(),
+ /*requested_method_google=*/
+ base::ContainsValue(spec_->url_payment_method_identifiers(),
+ google_pay_url) ||
+ base::ContainsValue(spec_->url_payment_method_identifiers(),
+ android_pay_url),
+ /*requested_method_other=*/non_google_it !=
+ spec_->url_payment_method_identifiers().end());
}
void PaymentRequest::Show() {
@@ -123,7 +152,6 @@ void PaymentRequest::Show() {
LOG(ERROR) << "A PaymentRequest UI is already showing";
journey_logger_.SetNotShown(
JourneyLogger::NOT_SHOWN_REASON_CONCURRENT_REQUESTS);
- has_recorded_completion_ = true;
client_->OnError(mojom::PaymentErrorReason::USER_CANCEL);
OnConnectionTerminated();
return;
@@ -132,7 +160,6 @@ void PaymentRequest::Show() {
if (!state_->AreRequestedMethodsSupported()) {
journey_logger_.SetNotShown(
JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
- has_recorded_completion_ = true;
client_->OnError(mojom::PaymentErrorReason::NOT_SUPPORTED);
if (observer_for_testing_)
observer_for_testing_->OnNotSupportedError();
@@ -140,11 +167,7 @@ void PaymentRequest::Show() {
return;
}
- journey_logger_.SetShowCalled();
journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
- journey_logger_.SetRequestedInformation(
- spec_->request_shipping(), spec_->request_payer_email(),
- spec_->request_payer_phone(), spec_->request_payer_name());
delegate_->ShowDialog(this);
}
@@ -215,7 +238,8 @@ void PaymentRequest::CanMakePayment() {
journey_logger_.SetCanMakePaymentValue(true);
} else if (CanMakePaymentQueryFactory::GetInstance()
->GetForContext(web_contents_->GetBrowserContext())
- ->CanQuery(frame_origin_, spec()->stringified_method_data())) {
+ ->CanQuery(top_level_origin_, frame_origin_,
+ spec()->stringified_method_data())) {
client_->OnCanMakePayment(
can_make_payment
? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
@@ -296,8 +320,7 @@ void PaymentRequest::OnConnectionTerminated() {
void PaymentRequest::Pay() {
journey_logger_.SetEventOccurred(JourneyLogger::EVENT_PAY_CLICKED);
- journey_logger_.SetSelectedPaymentMethod(
- JourneyLogger::SELECTED_PAYMENT_METHOD_CREDIT_CARD);
+ journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SELECTED_CREDIT_CARD);
state_->GeneratePaymentResponse();
}
diff --git a/chromium/components/payments/content/payment_request.h b/chromium/components/payments/content/payment_request.h
index d4145f843a2..9be4d539965 100644
--- a/chromium/components/payments/content/payment_request.h
+++ b/chromium/components/payments/content/payment_request.h
@@ -22,7 +22,7 @@
namespace content {
class RenderFrameHost;
class WebContents;
-}
+} // namespace content
namespace payments {
@@ -115,6 +115,10 @@ class PaymentRequest : public mojom::PaymentRequest,
std::unique_ptr<PaymentRequestSpec> spec_;
std::unique_ptr<PaymentRequestState> state_;
+ // The RFC 6454 origin of the top level frame that has invoked PaymentRequest
+ // API. This is what the user sees in the address bar.
+ const GURL top_level_origin_;
+
// The RFC 6454 origin of the frame that has invoked PaymentRequest API. This
// can be either the main frame or an iframe.
const GURL frame_origin_;
diff --git a/chromium/components/payments/content/payment_request_spec.cc b/chromium/components/payments/content/payment_request_spec.cc
index 364214bc72f..e328318ffdf 100644
--- a/chromium/components/payments/content/payment_request_spec.cc
+++ b/chromium/components/payments/content/payment_request_spec.cc
@@ -87,7 +87,7 @@ void PopulateValidatedMethodData(
std::set<std::string>* basic_card_specified_networks,
std::set<std::string>* supported_card_networks_set,
std::set<autofill::CreditCard::CardType>* supported_card_types_set,
- std::vector<std::string>* url_payment_method_identifiers,
+ std::vector<GURL>* url_payment_method_identifiers,
std::map<std::string, std::set<std::string>>* stringified_method_data) {
data_util::ParseSupportedMethods(method_data_vector, supported_card_networks,
basic_card_specified_networks,
@@ -105,7 +105,7 @@ void PopulateValidatedMethodData(
std::set<std::string>* basic_card_specified_networks,
std::set<std::string>* supported_card_networks_set,
std::set<autofill::CreditCard::CardType>* supported_card_types_set,
- std::vector<std::string>* url_payment_method_identifiers,
+ std::vector<GURL>* url_payment_method_identifiers,
std::map<std::string, std::set<std::string>>* stringified_method_data) {
std::vector<PaymentMethodData> method_data_vector;
method_data_vector.reserve(method_data_mojom.size());
@@ -129,6 +129,8 @@ void PopulateValidatedMethodData(
} // namespace
const char kBasicCardMethodName[] = "basic-card";
+const char kGooglePayMethodName[] = "https://google.com/pay";
+const char kAndroidPayMethodName[] = "https://android.com/pay";
PaymentRequestSpec::PaymentRequestSpec(
mojom::PaymentOptionsPtr options,
@@ -275,7 +277,7 @@ PaymentRequestSpec::GetApplicableModifier(
// The following 4 are unused but required by PopulateValidatedMethodData.
std::set<std::string> basic_card_specified_networks;
std::set<std::string> supported_card_networks_set;
- std::vector<std::string> url_payment_method_identifiers;
+ std::vector<GURL> url_payment_method_identifiers;
std::map<std::string, std::set<std::string>> stringified_method_data;
PopulateValidatedMethodData(
{CreatePaymentMethodData(modifier->method_data)}, &supported_networks,
@@ -284,8 +286,8 @@ PaymentRequestSpec::GetApplicableModifier(
&stringified_method_data);
if (selected_instrument->IsValidForModifier(
- modifier->method_data->supported_methods, supported_types,
- supported_networks)) {
+ modifier->method_data->supported_methods, supported_networks,
+ supported_types, !modifier->method_data->supported_types.empty())) {
return &modifier;
}
}
diff --git a/chromium/components/payments/content/payment_request_spec.h b/chromium/components/payments/content/payment_request_spec.h
index 798e31dd360..01a9e8cc7d7 100644
--- a/chromium/components/payments/content/payment_request_spec.h
+++ b/chromium/components/payments/content/payment_request_spec.h
@@ -17,13 +17,17 @@
#include "components/payments/core/currency_formatter.h"
#include "components/payments/core/payment_options_provider.h"
#include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
+#include "url/gurl.h"
namespace payments {
class PaymentInstrument;
-// Identifier for the basic card payment method in the PaymentMethodData.
+// Identifier for the basic card payment method and google-related payment
+// methods in the PaymentMethodData.
extern const char kBasicCardMethodName[];
+extern const char kGooglePayMethodName[];
+extern const char kAndroidPayMethodName[];
// The spec contains all the options that the merchant has specified about this
// Payment Request. It's a (mostly) read-only view, which can be updated in
@@ -89,7 +93,7 @@ class PaymentRequestSpec : public PaymentOptionsProvider {
const {
return supported_card_types_set_;
}
- const std::vector<std::string>& url_payment_method_identifiers() const {
+ const std::vector<GURL>& url_payment_method_identifiers() const {
return url_payment_method_identifiers_;
}
// Returns whether the |method_name| was specified as supported through the
@@ -188,7 +192,7 @@ class PaymentRequestSpec : public PaymentOptionsProvider {
// merchant. This encompasses one of the two types of payment method
// identifers, the other being standardized payment method identifiers i.e.,
// basic-card.
- std::vector<std::string> url_payment_method_identifiers_;
+ std::vector<GURL> url_payment_method_identifiers_;
// A mapping of the payment method names to the corresponding JSON-stringified
// payment method specific data.
diff --git a/chromium/components/payments/content/payment_request_state_unittest.cc b/chromium/components/payments/content/payment_request_state_unittest.cc
index 0e0a014ddae..9147b82ee82 100644
--- a/chromium/components/payments/content/payment_request_state_unittest.cc
+++ b/chromium/components/payments/content/payment_request_state_unittest.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/guid.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile.h"
@@ -26,7 +27,7 @@ class PaymentRequestStateTest : public testing::Test,
protected:
PaymentRequestStateTest()
: num_on_selected_information_changed_called_(0),
- test_payment_request_delegate_(/*personal_data_manager=*/nullptr),
+ test_payment_request_delegate_(&test_personal_data_manager_),
journey_logger_(test_payment_request_delegate_.IsIncognito(),
GURL("http://www.test.com"),
test_payment_request_delegate_.GetUkmRecorder()),
@@ -329,4 +330,59 @@ TEST_F(PaymentRequestStateTest, SelectedShippingAddressMessage_Normalized) {
EXPECT_EQ("16502111111", selected_shipping_address()->phone);
}
+TEST_F(PaymentRequestStateTest, JaLatnShippingAddress) {
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_shipping = true;
+ RecreateStateWithOptions(std::move(options));
+
+ // Make the normalization not be instantaneous.
+ test_payment_request_delegate()
+ ->test_address_normalizer()
+ ->DelayNormalization();
+
+ EXPECT_EQ(0, num_on_selected_information_changed_called());
+
+ // Select an address, nothing should happen until the normalization is
+ // completed and the merchant has validated the address.
+ autofill::AutofillProfile profile(base::GenerateGUID(),
+ "https://example.com");
+ autofill::test::SetProfileInfo(&profile, "Jon", "V.", "Doe",
+ "jon.doe@exampl.com", "Example Inc",
+ "Roppongi", "6 Chrome-10-1", "Tokyo", "",
+ "106-6126", "JP", "+81363849000");
+ profile.set_language_code("ja-Latn");
+
+ state()->SetSelectedShippingProfile(&profile);
+ EXPECT_EQ(1, num_on_selected_information_changed_called());
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ // Complete the normalization.
+ test_payment_request_delegate()
+ ->test_address_normalizer()
+ ->CompleteAddressNormalization();
+ EXPECT_EQ(1, num_on_selected_information_changed_called());
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ // Simulate that the merchant has validated the shipping address change.
+ spec()->UpdateWith(CreateDefaultDetails());
+ EXPECT_EQ(2, num_on_selected_information_changed_called());
+ // Not ready to pay because there's no selected shipping option.
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ // Check that all the expected values were set for the shipping address.
+ EXPECT_EQ("JP", selected_shipping_address()->country);
+ EXPECT_EQ("Roppongi", selected_shipping_address()->address_line[0]);
+ EXPECT_EQ("6 Chrome-10-1", selected_shipping_address()->address_line[1]);
+ EXPECT_EQ("", selected_shipping_address()->region);
+ EXPECT_EQ("Tokyo", selected_shipping_address()->city);
+ EXPECT_EQ("", selected_shipping_address()->dependent_locality);
+ EXPECT_EQ("106-6126", selected_shipping_address()->postal_code);
+ EXPECT_EQ("", selected_shipping_address()->sorting_code);
+ EXPECT_EQ("ja", selected_shipping_address()->language_code);
+ EXPECT_EQ("Latn", selected_shipping_address()->script_code);
+ EXPECT_EQ("Example Inc", selected_shipping_address()->organization);
+ EXPECT_EQ("Jon V. Doe", selected_shipping_address()->recipient);
+ EXPECT_EQ("+81363849000", selected_shipping_address()->phone);
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/payment_response_helper.cc b/chromium/components/payments/content/payment_response_helper.cc
index 4e6a2994622..06a6687a1ff 100644
--- a/chromium/components/payments/content/payment_response_helper.cc
+++ b/chromium/components/payments/content/payment_response_helper.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_country.h"
@@ -14,6 +15,7 @@
#include "components/payments/content/payment_request_spec.h"
#include "components/payments/core/payment_request_data_util.h"
#include "components/payments/core/payment_request_delegate.h"
+#include "components/payments/core/payments_validators.h"
namespace payments {
@@ -76,26 +78,34 @@ PaymentResponseHelper::GetMojomPaymentAddressFromAutofillProfile(
payment_address->country =
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
- payment_address->address_line = base::SplitString(
- base::UTF16ToUTF8(profile.GetInfo(
- autofill::AutofillType(autofill::ADDRESS_HOME_STREET_ADDRESS),
- app_locale)),
- "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- payment_address->region =
- base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_STATE));
- payment_address->city =
- base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_CITY));
+ DCHECK(PaymentsValidators::IsValidCountryCodeFormat(payment_address->country,
+ nullptr));
+
+ payment_address->address_line =
+ base::SplitString(base::UTF16ToUTF8(profile.GetInfo(
+ autofill::ADDRESS_HOME_STREET_ADDRESS, app_locale)),
+ "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ payment_address->region = base::UTF16ToUTF8(
+ profile.GetInfo(autofill::ADDRESS_HOME_STATE, app_locale));
+ payment_address->city = base::UTF16ToUTF8(
+ profile.GetInfo(autofill::ADDRESS_HOME_CITY, app_locale));
payment_address->dependent_locality = base::UTF16ToUTF8(
- profile.GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY));
- payment_address->postal_code =
- base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP));
+ profile.GetInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, app_locale));
+ payment_address->postal_code = base::UTF16ToUTF8(
+ profile.GetInfo(autofill::ADDRESS_HOME_ZIP, app_locale));
payment_address->sorting_code = base::UTF16ToUTF8(
- profile.GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE));
- payment_address->language_code = profile.language_code();
+ profile.GetInfo(autofill::ADDRESS_HOME_SORTING_CODE, app_locale));
payment_address->organization =
- base::UTF16ToUTF8(profile.GetRawInfo(autofill::COMPANY_NAME));
- payment_address->recipient = base::UTF16ToUTF8(
- profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), app_locale));
+ base::UTF16ToUTF8(profile.GetInfo(autofill::COMPANY_NAME, app_locale));
+ payment_address->recipient =
+ base::UTF16ToUTF8(profile.GetInfo(autofill::NAME_FULL, app_locale));
+
+ // The autofill profile |language_code| is the BCP-47 language tag (e.g.,
+ // "ja-Latn"), which can be split into a language code (e.g., "ja") and a
+ // script code (e.g., "Latn").
+ PaymentsValidators::SplitLanguageTag(profile.language_code(),
+ &payment_address->language_code,
+ &payment_address->script_code);
// TODO(crbug.com/705945): Format phone number according to spec.
payment_address->phone =
@@ -159,9 +169,8 @@ void PaymentResponseHelper::GeneratePaymentResponse() {
// Contact Details section.
if (spec_->request_payer_name()) {
DCHECK(selected_contact_profile_);
- payment_response->payer_name =
- base::UTF16ToUTF8(selected_contact_profile_->GetInfo(
- autofill::AutofillType(autofill::NAME_FULL), app_locale_));
+ payment_response->payer_name = base::UTF16ToUTF8(
+ selected_contact_profile_->GetInfo(autofill::NAME_FULL, app_locale_));
}
if (spec_->request_payer_email()) {
DCHECK(selected_contact_profile_);
@@ -177,8 +186,7 @@ void PaymentResponseHelper::GeneratePaymentResponse() {
// https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm
const std::string original_number =
base::UTF16ToUTF8(selected_contact_profile_->GetInfo(
- autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
- app_locale_));
+ autofill::PHONE_HOME_WHOLE_NUMBER, app_locale_));
const std::string default_region_code =
autofill::AutofillCountry::CountryCodeForLocale(app_locale_);
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
index 4ef5cf1a6ee..e6637140848 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -102,9 +102,10 @@ bool ParseSupportedOrigins(base::DictionaryValue* dict,
}
size_t supported_origins_number = list->GetSize();
- if (supported_origins_number > kMaximumNumberOfEntries) {
+ const size_t kMaximumNumberOfSupportedOrigins = 100000;
+ if (supported_origins_number > kMaximumNumberOfSupportedOrigins) {
LOG(ERROR) << "\"" << kSupportedOrigins << "\" must contain at most "
- << kMaximumNumberOfEntries << " entires.";
+ << kMaximumNumberOfSupportedOrigins << " entires.";
return false;
}
@@ -118,7 +119,8 @@ bool ParseSupportedOrigins(base::DictionaryValue* dict,
GURL url(item);
if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme) ||
- url.path() != "/" || url.has_query() || url.has_ref()) {
+ url.path() != "/" || url.has_query() || url.has_ref() ||
+ url.has_username() || url.has_password()) {
LOG(ERROR) << "\"" << item << "\" entry in \"" << kSupportedOrigins
<< "\" is not a valid origin with HTTPS scheme.";
supported_origins->clear();
diff --git a/chromium/components/payments/core/BUILD.gn b/chromium/components/payments/core/BUILD.gn
index ed5343e61d5..8895c1bd1e0 100644
--- a/chromium/components/payments/core/BUILD.gn
+++ b/chromium/components/payments/core/BUILD.gn
@@ -23,8 +23,18 @@ static_library("core") {
"journey_logger.h",
"payment_address.cc",
"payment_address.h",
+ "payment_currency_amount.cc",
+ "payment_currency_amount.h",
+ "payment_details.cc",
+ "payment_details.h",
+ "payment_details_modifier.cc",
+ "payment_details_modifier.h",
"payment_instrument.cc",
"payment_instrument.h",
+ "payment_item.cc",
+ "payment_item.h",
+ "payment_manifest_downloader.cc",
+ "payment_manifest_downloader.h",
"payment_method_data.cc",
"payment_method_data.h",
"payment_options_provider.h",
@@ -34,8 +44,12 @@ static_library("core") {
"payment_request_data_util.cc",
"payment_request_data_util.h",
"payment_request_delegate.h",
+ "payment_shipping_option.cc",
+ "payment_shipping_option.h",
"payments_profile_comparator.cc",
"payments_profile_comparator.h",
+ "payments_validators.cc",
+ "payments_validators.h",
"strings_util.cc",
"strings_util.h",
"subkey_requester.cc",
@@ -45,11 +59,15 @@ static_library("core") {
deps = [
"//base",
"//components/autofill/core/browser",
+ "//components/data_use_measurement/core",
"//components/keyed_service/core",
+ "//components/link_header_util",
"//components/pref_registry",
"//components/strings:components_strings_grit",
"//components/ukm",
+ "//net",
"//third_party/libphonenumber",
+ "//third_party/re2",
"//ui/base",
"//url",
]
@@ -78,6 +96,7 @@ static_library("test_support") {
"//components/autofill/core/browser:test_support",
"//components/pref_registry",
"//components/prefs",
+ "//net:test_support",
]
}
@@ -88,12 +107,20 @@ source_set("unit_tests") {
"address_normalizer_impl_unittest.cc",
"autofill_payment_instrument_unittest.cc",
"basic_card_response_unittest.cc",
+ "can_make_payment_query_unittest.cc",
"currency_formatter_unittest.cc",
"journey_logger_unittest.cc",
"payment_address_unittest.cc",
+ "payment_currency_amount_unittest.cc",
+ "payment_details_modifier_unittest.cc",
+ "payment_details_unittest.cc",
+ "payment_item_unittest.cc",
+ "payment_manifest_downloader_unittest.cc",
"payment_method_data_unittest.cc",
"payment_request_data_util_unittest.cc",
+ "payment_shipping_option_unittest.cc",
"payments_profile_comparator_unittest.cc",
+ "payments_validators_unittest.cc",
"strings_util_unittest.cc",
"subkey_requester_unittest.cc",
]
@@ -109,6 +136,7 @@ source_set("unit_tests") {
"//components/strings:components_strings_grit",
"//components/ukm",
"//components/ukm:test_support",
+ "//net:test_support",
"//testing/gmock",
"//testing/gtest",
"//third_party/libaddressinput:test_support",
@@ -116,98 +144,94 @@ source_set("unit_tests") {
]
}
-bundle_data("payments_test_bundle_data") {
- testonly = true
+if (is_ios) {
+ bundle_data("payments_test_bundle_data") {
+ testonly = true
- sources = [
- "//components/test/data/payments/abort.js",
- "//components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js",
- "//components/test/data/payments/app.json",
- "//components/test/data/payments/blob_url.js",
- "//components/test/data/payments/bobpay.js",
- "//components/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js",
- "//components/test/data/payments/bobpay_and_basic_card_with_modifiers.js",
- "//components/test/data/payments/bobpay_and_cards.js",
- "//components/test/data/payments/bobpay_ui_skip.js",
- "//components/test/data/payments/bobpay_ui_skip_preload.js",
- "//components/test/data/payments/can_make_payment_metrics.js",
- "//components/test/data/payments/can_make_payment_query.js",
- "//components/test/data/payments/can_make_payment_query_bobpay.js",
- "//components/test/data/payments/can_make_payment_query_cc.js",
- "//components/test/data/payments/contact_details.js",
- "//components/test/data/payments/contact_details_and_free_shipping.js",
- "//components/test/data/payments/debit.js",
- "//components/test/data/payments/dynamic_shipping.js",
- "//components/test/data/payments/email.js",
- "//components/test/data/payments/email_and_free_shipping.js",
- "//components/test/data/payments/email_and_phone.js",
- "//components/test/data/payments/extra_shipping_options.js",
- "//components/test/data/payments/fail_complete.js",
- "//components/test/data/payments/free_shipping.js",
- "//components/test/data/payments/initiated.js",
- "//components/test/data/payments/initiated_test.html",
- "//components/test/data/payments/long_id.js",
- "//components/test/data/payments/metrics.js",
- "//components/test/data/payments/modifier.js",
- "//components/test/data/payments/multiple_show.js",
- "//components/test/data/payments/name.js",
- "//components/test/data/payments/name_and_free_shipping.js",
- "//components/test/data/payments/no_shipping.js",
- "//components/test/data/payments/payment-manifest.json",
- "//components/test/data/payments/payment_method_identifier.js",
- "//components/test/data/payments/payment_request.html",
- "//components/test/data/payments/payment_request.js",
- "//components/test/data/payments/payment_request_abort_test.html",
- "//components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html",
- "//components/test/data/payments/payment_request_blob_url_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_basic_card_with_basic_card_modifiers_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_cards_test.html",
- "//components/test/data/payments/payment_request_bobpay_test.html",
- "//components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html",
- "//components/test/data/payments/payment_request_bobpay_ui_skip_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_metrics_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_cc_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_test.html",
- "//components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_contact_details_test.html",
- "//components/test/data/payments/payment_request_debit_test.html",
- "//components/test/data/payments/payment_request_dynamic_shipping_test.html",
- "//components/test/data/payments/payment_request_email_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_email_and_phone_test.html",
- "//components/test/data/payments/payment_request_email_test.html",
- "//components/test/data/payments/payment_request_extra_shipping_options_test.html",
- "//components/test/data/payments/payment_request_fail_complete_test.html",
- "//components/test/data/payments/payment_request_free_shipping_test.html",
- "//components/test/data/payments/payment_request_id.js",
- "//components/test/data/payments/payment_request_id_test.html",
- "//components/test/data/payments/payment_request_iframe.html",
- "//components/test/data/payments/payment_request_long_id_test.html",
- "//components/test/data/payments/payment_request_main.html",
- "//components/test/data/payments/payment_request_metrics_test.html",
- "//components/test/data/payments/payment_request_modifier_test.html",
- "//components/test/data/payments/payment_request_multiple_requests.html",
- "//components/test/data/payments/payment_request_multiple_show_test.html",
- "//components/test/data/payments/payment_request_name_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_name_test.html",
- "//components/test/data/payments/payment_request_no_shipping_test.html",
- "//components/test/data/payments/payment_request_payment_method_identifier_test.html",
- "//components/test/data/payments/payment_request_phone_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_phone_test.html",
- "//components/test/data/payments/payment_request_shipping_address_change_test.html",
- "//components/test/data/payments/payment_request_show_twice_test.html",
- "//components/test/data/payments/phone.js",
- "//components/test/data/payments/phone_and_free_shipping.js",
- "//components/test/data/payments/shipping_address_change.js",
- "//components/test/data/payments/show_twice.js",
- "//components/test/data/payments/style.css",
- "//components/test/data/payments/util.js",
- "//components/test/data/payments/webpay",
- "//components/test/data/payments/webpay.mock-http-headers",
- ]
- outputs = [
- "{{bundle_resources_dir}}/" +
- "{{source_root_relative_dir}}/{{source_file_part}}",
- ]
+ sources = [
+ "//components/test/data/payments/abort.js",
+ "//components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js",
+ "//components/test/data/payments/blob_url.js",
+ "//components/test/data/payments/bobpay.js",
+ "//components/test/data/payments/bobpay_and_basic_card_with_modifiers.js",
+ "//components/test/data/payments/bobpay_and_cards.js",
+ "//components/test/data/payments/bobpay_ui_skip.js",
+ "//components/test/data/payments/bobpay_ui_skip_preload.js",
+ "//components/test/data/payments/can_make_payment_metrics.js",
+ "//components/test/data/payments/can_make_payment_query.js",
+ "//components/test/data/payments/can_make_payment_query_bobpay.js",
+ "//components/test/data/payments/can_make_payment_query_cc.js",
+ "//components/test/data/payments/contact_details.js",
+ "//components/test/data/payments/contact_details_and_free_shipping.js",
+ "//components/test/data/payments/debit.js",
+ "//components/test/data/payments/dynamic_shipping.js",
+ "//components/test/data/payments/email.js",
+ "//components/test/data/payments/email_and_free_shipping.js",
+ "//components/test/data/payments/email_and_phone.js",
+ "//components/test/data/payments/extra_shipping_options.js",
+ "//components/test/data/payments/fail_complete.js",
+ "//components/test/data/payments/free_shipping.js",
+ "//components/test/data/payments/initiated.js",
+ "//components/test/data/payments/initiated_test.html",
+ "//components/test/data/payments/long_id.js",
+ "//components/test/data/payments/metrics.js",
+ "//components/test/data/payments/modifier.js",
+ "//components/test/data/payments/multiple_show.js",
+ "//components/test/data/payments/name.js",
+ "//components/test/data/payments/name_and_free_shipping.js",
+ "//components/test/data/payments/no_shipping.js",
+ "//components/test/data/payments/payment_method_identifier.js",
+ "//components/test/data/payments/payment_request.html",
+ "//components/test/data/payments/payment_request.js",
+ "//components/test/data/payments/payment_request_abort_test.html",
+ "//components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html",
+ "//components/test/data/payments/payment_request_blob_url_test.html",
+ "//components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html",
+ "//components/test/data/payments/payment_request_bobpay_and_cards_test.html",
+ "//components/test/data/payments/payment_request_bobpay_test.html",
+ "//components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html",
+ "//components/test/data/payments/payment_request_bobpay_ui_skip_test.html",
+ "//components/test/data/payments/payment_request_can_make_payment_metrics_test.html",
+ "//components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html",
+ "//components/test/data/payments/payment_request_can_make_payment_query_cc_test.html",
+ "//components/test/data/payments/payment_request_can_make_payment_query_test.html",
+ "//components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html",
+ "//components/test/data/payments/payment_request_contact_details_test.html",
+ "//components/test/data/payments/payment_request_debit_test.html",
+ "//components/test/data/payments/payment_request_dynamic_shipping_test.html",
+ "//components/test/data/payments/payment_request_email_and_free_shipping_test.html",
+ "//components/test/data/payments/payment_request_email_and_phone_test.html",
+ "//components/test/data/payments/payment_request_email_test.html",
+ "//components/test/data/payments/payment_request_extra_shipping_options_test.html",
+ "//components/test/data/payments/payment_request_fail_complete_test.html",
+ "//components/test/data/payments/payment_request_free_shipping_test.html",
+ "//components/test/data/payments/payment_request_id.js",
+ "//components/test/data/payments/payment_request_id_test.html",
+ "//components/test/data/payments/payment_request_iframe.html",
+ "//components/test/data/payments/payment_request_long_id_test.html",
+ "//components/test/data/payments/payment_request_main.html",
+ "//components/test/data/payments/payment_request_metrics_test.html",
+ "//components/test/data/payments/payment_request_modifier_test.html",
+ "//components/test/data/payments/payment_request_multiple_requests.html",
+ "//components/test/data/payments/payment_request_multiple_show_test.html",
+ "//components/test/data/payments/payment_request_name_and_free_shipping_test.html",
+ "//components/test/data/payments/payment_request_name_test.html",
+ "//components/test/data/payments/payment_request_no_shipping_test.html",
+ "//components/test/data/payments/payment_request_payment_method_identifier_test.html",
+ "//components/test/data/payments/payment_request_phone_and_free_shipping_test.html",
+ "//components/test/data/payments/payment_request_phone_test.html",
+ "//components/test/data/payments/payment_request_shipping_address_change_test.html",
+ "//components/test/data/payments/payment_request_show_twice_test.html",
+ "//components/test/data/payments/phone.js",
+ "//components/test/data/payments/phone_and_free_shipping.js",
+ "//components/test/data/payments/shipping_address_change.js",
+ "//components/test/data/payments/show_twice.js",
+ "//components/test/data/payments/style.css",
+ "//components/test/data/payments/util.js",
+ ]
+ outputs = [
+ "{{bundle_resources_dir}}/" +
+ "{{source_root_relative_dir}}/{{source_file_part}}",
+ ]
+ }
}
diff --git a/chromium/components/payments/core/DEPS b/chromium/components/payments/core/DEPS
index 8325aae1337..207e47c59a9 100644
--- a/chromium/components/payments/core/DEPS
+++ b/chromium/components/payments/core/DEPS
@@ -2,14 +2,18 @@ include_rules = [
"-components/payments/content",
"-content",
"+components/autofill/core",
+ "+components/data_use_measurement",
"+components/keyed_service/core",
+ "+components/link_header_util",
"+components/metrics",
"+components/prefs",
"+components/pref_registry",
"+components/strings",
+ "+net",
"+services/metrics/public",
"+third_party/libaddressinput",
"+third_party/libphonenumber",
+ "+third_party/re2",
"+ui/base",
]
diff --git a/chromium/components/payments/core/address_normalizer_impl_unittest.cc b/chromium/components/payments/core/address_normalizer_impl_unittest.cc
index 495dd04030c..f38ac145115 100644
--- a/chromium/components/payments/core/address_normalizer_impl_unittest.cc
+++ b/chromium/components/payments/core/address_normalizer_impl_unittest.cc
@@ -6,9 +6,8 @@
#include <utility>
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_scheduler.h"
+#include "base/test/scoped_task_environment.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
@@ -119,7 +118,7 @@ class AddressNormalizerTest : public testing::Test {
const std::unique_ptr<TestAddressNormalizer> normalizer_;
- base::test::ScopedTaskScheduler scoped_task_scheduler_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
private:
DISALLOW_COPY_AND_ASSIGN(AddressNormalizerTest);
@@ -170,7 +169,7 @@ TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillNotLoad) {
normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
// Let the timeout execute.
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
// Since the rules are never loaded and the timeout is 0, the delegate should
// get notified that the address could not be normalized.
@@ -234,7 +233,7 @@ TEST_F(AddressNormalizerTest, FormatPhone_AddressNotNormalized) {
normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate);
// Let the timeout execute.
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
// Make sure the address was not normalized.
EXPECT_TRUE(delegate.not_normalized_called());
diff --git a/chromium/components/payments/core/autofill_payment_instrument.cc b/chromium/components/payments/core/autofill_payment_instrument.cc
index 86d98f02771..dfed1848fd8 100644
--- a/chromium/components/payments/core/autofill_payment_instrument.cc
+++ b/chromium/components/payments/core/autofill_payment_instrument.cc
@@ -125,8 +125,9 @@ base::string16 AutofillPaymentInstrument::GetSublabel() const {
bool AutofillPaymentInstrument::IsValidForModifier(
const std::vector<std::string>& method,
+ const std::vector<std::string>& supported_networks,
const std::set<autofill::CreditCard::CardType>& supported_types,
- const std::vector<std::string>& supported_networks) const {
+ bool supported_types_specified) const {
// This instrument only matches basic-card.
if (std::find(method.begin(), method.end(), "basic-card") == method.end())
return false;
@@ -136,16 +137,16 @@ bool AutofillPaymentInstrument::IsValidForModifier(
// contain this card's type to be applicable. The same is true for
// supported_networks.
bool is_supported_type =
- supported_types.empty() ||
std::find(supported_types.begin(), supported_types.end(),
credit_card_.card_type()) != supported_types.end();
// supported_types may contain CARD_TYPE_UNKNOWN because of the parsing
- // function but the modifiers shouldn't be applied since the website can't be
- // sure that the instrument is an applicable card.
+ // function so the local card only matches if it's because the website didn't
+ // specify types (meaning they don't care).
if (is_supported_type &&
credit_card_.card_type() ==
- autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN)
+ autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN &&
+ supported_types_specified)
return false;
bool is_supported_network = supported_networks.empty();
@@ -162,6 +163,7 @@ bool AutofillPaymentInstrument::IsValidForModifier(
}
void AutofillPaymentInstrument::OnFullCardRequestSucceeded(
+ const autofill::payments::FullCardRequest& /* full_card_request */,
const autofill::CreditCard& card,
const base::string16& cvc) {
DCHECK(delegate_);
diff --git a/chromium/components/payments/core/autofill_payment_instrument.h b/chromium/components/payments/core/autofill_payment_instrument.h
index 3600918a79f..55cd074c366 100644
--- a/chromium/components/payments/core/autofill_payment_instrument.h
+++ b/chromium/components/payments/core/autofill_payment_instrument.h
@@ -50,12 +50,15 @@ class AutofillPaymentInstrument
base::string16 GetSublabel() const override;
bool IsValidForModifier(
const std::vector<std::string>& method,
+ const std::vector<std::string>& supported_networks,
const std::set<autofill::CreditCard::CardType>& supported_types,
- const std::vector<std::string>& supported_networks) const override;
+ bool supported_types_specified) const override;
// autofill::payments::FullCardRequest::ResultDelegate:
- void OnFullCardRequestSucceeded(const autofill::CreditCard& card,
- const base::string16& cvc) override;
+ void OnFullCardRequestSucceeded(
+ const autofill::payments::FullCardRequest& full_card_request,
+ const autofill::CreditCard& card,
+ const base::string16& cvc) override;
void OnFullCardRequestFailed() override;
// AddressNormalizer::Delegate:
diff --git a/chromium/components/payments/core/autofill_payment_instrument_unittest.cc b/chromium/components/payments/core/autofill_payment_instrument_unittest.cc
index 117d587bf30..328163bada3 100644
--- a/chromium/components/payments/core/autofill_payment_instrument_unittest.cc
+++ b/chromium/components/payments/core/autofill_payment_instrument_unittest.cc
@@ -10,9 +10,15 @@
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/payments/core/address_normalizer.h"
#include "components/payments/core/test_payment_request_delegate.h"
#include "components/strings/grit/components_strings.h"
+#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
@@ -78,10 +84,20 @@ class FakeAddressNormalizer : public AddressNormalizer {
AddressNormalizer::Delegate* requester_;
};
-class FakePaymentRequestDelegate : public PaymentRequestDelegate {
+class FakePaymentRequestDelegate
+ : public PaymentRequestDelegate,
+ public autofill::payments::PaymentsClientDelegate {
public:
FakePaymentRequestDelegate()
- : locale_("en-US"), last_committed_url_("https://shop.com") {}
+ : locale_("en-US"),
+ last_committed_url_("https://shop.com"),
+ personal_data_("en-US"),
+ request_context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())),
+ payments_client_(request_context_.get(), this),
+ full_card_request_(&autofill_client_,
+ &payments_client_,
+ &personal_data_) {}
void ShowDialog(PaymentRequest* request) override {}
void CloseDialog() override {}
@@ -120,7 +136,7 @@ class FakePaymentRequestDelegate : public PaymentRequestDelegate {
void CompleteFullCardRequest() {
full_card_result_delegate_->OnFullCardRequestSucceeded(
- full_card_request_card_, base::ASCIIToUTF16("123"));
+ full_card_request_, full_card_request_card_, base::ASCIIToUTF16("123"));
}
autofill::RegionDataLoader* GetRegionDataLoader() override { return nullptr; }
@@ -131,7 +147,11 @@ class FakePaymentRequestDelegate : public PaymentRequestDelegate {
std::string locale_;
const GURL last_committed_url_;
FakeAddressNormalizer address_normalizer_;
-
+ autofill::PersonalDataManager personal_data_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+ autofill::TestAutofillClient autofill_client_;
+ autofill::payments::PaymentsClient payments_client_;
+ autofill::payments::FullCardRequest full_card_request_;
autofill::CreditCard full_card_request_card_;
base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
full_card_result_delegate_;
@@ -328,7 +348,9 @@ TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_NoNumber) {
// the billing address has been normalized and the card has been unmasked.
TEST_F(AutofillPaymentInstrumentTest,
InvokePaymentApp_NormalizationBeforeUnmask) {
- TestPaymentRequestDelegate delegate(/*personal_data_manager=*/nullptr);
+ auto personal_data_manager =
+ base::MakeUnique<autofill::TestPersonalDataManager>();
+ TestPaymentRequestDelegate delegate(personal_data_manager.get());
delegate.DelayFullCardRequestCompletion();
delegate.test_address_normalizer()->DelayNormalization();
@@ -357,7 +379,9 @@ TEST_F(AutofillPaymentInstrumentTest,
// the billing address has been normalized and the card has been unmasked.
TEST_F(AutofillPaymentInstrumentTest,
InvokePaymentApp_UnmaskBeforeNormalization) {
- TestPaymentRequestDelegate delegate(/*personal_data_manager=*/nullptr);
+ auto personal_data_manager =
+ base::MakeUnique<autofill::TestPersonalDataManager>();
+ TestPaymentRequestDelegate delegate(personal_data_manager.get());
delegate.DelayFullCardRequestCompletion();
delegate.test_address_normalizer()->DelayNormalization();
diff --git a/chromium/components/payments/core/can_make_payment_query.cc b/chromium/components/payments/core/can_make_payment_query.cc
index c4264be89be..8836b4a52e7 100644
--- a/chromium/components/payments/core/can_make_payment_query.cc
+++ b/chromium/components/payments/core/can_make_payment_query.cc
@@ -11,6 +11,7 @@
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
+#include "url/gurl.h"
namespace payments {
@@ -19,26 +20,29 @@ CanMakePaymentQuery::CanMakePaymentQuery() {}
CanMakePaymentQuery::~CanMakePaymentQuery() {}
bool CanMakePaymentQuery::CanQuery(
+ const GURL& top_level_origin,
const GURL& frame_origin,
const std::map<std::string, std::set<std::string>>& query) {
- const auto& it = queries_.find(frame_origin);
+ const std::string id = frame_origin.spec() + ":" + top_level_origin.spec();
+
+ const auto& it = queries_.find(id);
if (it == queries_.end()) {
std::unique_ptr<base::OneShotTimer> timer =
base::MakeUnique<base::OneShotTimer>();
timer->Start(FROM_HERE, base::TimeDelta::FromMinutes(30),
base::Bind(&CanMakePaymentQuery::ExpireQuotaForFrameOrigin,
- base::Unretained(this), frame_origin));
- timers_.insert(std::make_pair(frame_origin, std::move(timer)));
- queries_.insert(std::make_pair(frame_origin, query));
+ base::Unretained(this), id));
+ timers_.insert(std::make_pair(id, std::move(timer)));
+ queries_.insert(std::make_pair(id, query));
return true;
}
return it->second == query;
}
-void CanMakePaymentQuery::ExpireQuotaForFrameOrigin(const GURL& frame_origin) {
- timers_.erase(frame_origin);
- queries_.erase(frame_origin);
+void CanMakePaymentQuery::ExpireQuotaForFrameOrigin(const std::string& id) {
+ timers_.erase(id);
+ queries_.erase(id);
}
} // namespace payments
diff --git a/chromium/components/payments/core/can_make_payment_query.h b/chromium/components/payments/core/can_make_payment_query.h
index 69da5761453..db2f7cf1798 100644
--- a/chromium/components/payments/core/can_make_payment_query.h
+++ b/chromium/components/payments/core/can_make_payment_query.h
@@ -13,7 +13,8 @@
#include "base/macros.h"
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "url/gurl.h"
+
+class GURL;
namespace payments {
@@ -23,24 +24,38 @@ class CanMakePaymentQuery : public KeyedService {
CanMakePaymentQuery();
~CanMakePaymentQuery() override;
- // Returns whether |frame_origin| can call canMakePayment() with |query|,
- // which is a mapping of payment method names to the corresponding
- // JSON-stringified payment method data. Remembers the frame-to-query mapping
- // for 30 minutes to enforce the quota.
- bool CanQuery(const GURL& frame_origin,
+ // Returns whether |top_level_origin| and |frame_origin| can call
+ // canMakePayment() with |query|, which is a mapping of payment method names
+ // to the corresponding JSON-stringified payment method data. Remembers the
+ // origins-to-query mapping for 30 minutes to enforce the quota.
+ //
+ // GURL type is used instead of url::Origin to represent origins, because they
+ // need to be serialized into map keys and url::Origin serializations must not
+ // be relied upon for security checks, according to url/origin.h.
+ //
+ // The best method to retrieve the origin of GURL for serialization is
+ // url_formatter::FormatUrlForSecurityDisplay() found in
+ // components/url_formatter/elide_url.h, because it preserves the path part of
+ // a file:// scheme GURL, in contrast to to GURL::GetOrigin(), which strips
+ // the path part of a file:// scheme GURL. There's no difference between these
+ // two methods for localhost and https:// schemes, where PaymentRequest is
+ // also allowed.
+ bool CanQuery(const GURL& top_level_origin,
+ const GURL& frame_origin,
const std::map<std::string, std::set<std::string>>& query);
private:
- void ExpireQuotaForFrameOrigin(const GURL& frame_origin);
+ void ExpireQuotaForFrameOrigin(const std::string& id);
- // A mapping of frame origin to the timer that, when fired, allows the frame
- // to invoke canMakePayment() with a different query.
- std::map<GURL, std::unique_ptr<base::OneShotTimer>> timers_;
+ // A mapping of frame origin and top level origin to the timer that, when
+ // fired, allows the frame to invoke canMakePayment() with a different set of
+ // supported payment methods.
+ std::map<std::string, std::unique_ptr<base::OneShotTimer>> timers_;
- // A mapping of frame origin to its last query. Each query is a mapping of
- // payment method names to the corresponding JSON-stringified payment method
- // data.
- std::map<GURL, std::map<std::string, std::set<std::string>>> queries_;
+ // A mapping of frame origin and top level origin to its last query. Each
+ // query is a mapping of payment method names to the corresponding
+ // JSON-stringified payment method data.
+ std::map<std::string, std::map<std::string, std::set<std::string>>> queries_;
DISALLOW_COPY_AND_ASSIGN(CanMakePaymentQuery);
};
diff --git a/chromium/components/payments/core/can_make_payment_query_unittest.cc b/chromium/components/payments/core/can_make_payment_query_unittest.cc
new file mode 100644
index 00000000000..eb3ea094d14
--- /dev/null
+++ b/chromium/components/payments/core/can_make_payment_query_unittest.cc
@@ -0,0 +1,66 @@
+// 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/core/can_make_payment_query.h"
+
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace payments {
+namespace {
+
+struct TestCase {
+ TestCase(const char* first_origin,
+ const char* second_origin,
+ bool expected_second_origin_different_query_allowed)
+ : first_origin(first_origin),
+ second_origin(second_origin),
+ expected_second_origin_different_query_allowed(
+ expected_second_origin_different_query_allowed) {}
+
+ ~TestCase() {}
+
+ const char* const first_origin;
+ const char* const second_origin;
+ const bool expected_second_origin_different_query_allowed;
+};
+
+class CanMakePaymentQueryTest : public ::testing::TestWithParam<TestCase> {
+ private:
+ base::MessageLoop message_loop_;
+};
+
+TEST_P(CanMakePaymentQueryTest, SecondOriginDifferentQuery) {
+ std::map<std::string, std::set<std::string>> query1;
+ query1["amex"] = std::set<std::string>();
+ std::map<std::string, std::set<std::string>> query2;
+ query2["visa"] = std::set<std::string>();
+ CanMakePaymentQuery guard;
+ EXPECT_TRUE(guard.CanQuery(GURL(GetParam().first_origin),
+ GURL(GetParam().first_origin), query1));
+
+ EXPECT_EQ(GetParam().expected_second_origin_different_query_allowed,
+ guard.CanQuery(GURL(GetParam().second_origin),
+ GURL(GetParam().second_origin), query2));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ Denied,
+ CanMakePaymentQueryTest,
+ testing::Values(
+ TestCase("https://example.com", "https://example.com", false),
+ TestCase("http://localhost", "http://localhost", false),
+ TestCase("file:///tmp/test.html", "file:///tmp/test.html", false)));
+
+INSTANTIATE_TEST_CASE_P(
+ Allowed,
+ CanMakePaymentQueryTest,
+ testing::Values(
+ TestCase("https://example.com", "https://not-example.com", true),
+ TestCase("http://localhost", "http://not-localhost", true),
+ TestCase("file:///tmp/test.html", "file:///tmp/not-test.html", true)));
+
+} // namespace
+} // namespace payments
diff --git a/chromium/components/payments/core/currency_formatter_unittest.cc b/chromium/components/payments/core/currency_formatter_unittest.cc
index 41793ef4c0c..8a4f235791a 100644
--- a/chromium/components/payments/core/currency_formatter_unittest.cc
+++ b/chromium/components/payments/core/currency_formatter_unittest.cc
@@ -9,6 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace payments {
+namespace {
struct TestCase {
TestCase(const char* amount,
@@ -182,4 +183,5 @@ INSTANTIATE_TEST_CASE_P(
"USD",
"http://currsystem.com")));
+} // namespace
} // namespace payments
diff --git a/chromium/components/payments/core/features.cc b/chromium/components/payments/core/features.cc
index e3694b24811..f60eae5362e 100644
--- a/chromium/components/payments/core/features.cc
+++ b/chromium/components/payments/core/features.cc
@@ -9,11 +9,17 @@ namespace features {
#if defined(OS_IOS)
const base::Feature kWebPayments{"WebPayments",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kWebPaymentsNativeApps{"WebPaymentsNativeApps",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif
+const base::Feature kWebPaymentsMethodSectionOrderV2{
+ "WebPaymentsMethodSectionOrderV2", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kWebPaymentsModifiers{"WebPaymentsModifiers",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace payments
diff --git a/chromium/components/payments/core/features.h b/chromium/components/payments/core/features.h
index 926e267cef4..a7e4a48cf1d 100644
--- a/chromium/components/payments/core/features.h
+++ b/chromium/components/payments/core/features.h
@@ -14,8 +14,16 @@ namespace features {
#if defined(OS_IOS)
// Used to control the state of the Payment Request API feature.
extern const base::Feature kWebPayments;
+
+// Used to control the support for iOS third party apps as payment methods.
+extern const base::Feature kWebPaymentsNativeApps;
#endif
+// Used to control payment method section order on payment request UI. Payment
+// method section should be put on top of the address section when this feature
+// is enabled instead of under it.
+extern const base::Feature kWebPaymentsMethodSectionOrderV2;
+
// Used to control the support for Payment Details modifiers.
extern const base::Feature kWebPaymentsModifiers;
diff --git a/chromium/components/payments/core/journey_logger.cc b/chromium/components/payments/core/journey_logger.cc
index ffdd5b837d2..85ed916d4e8 100644
--- a/chromium/components/payments/core/journey_logger.cc
+++ b/chromium/components/payments/core/journey_logger.cc
@@ -72,7 +72,7 @@ JourneyLogger::JourneyLogger(bool is_incognito,
ukm_recorder_(ukm_recorder) {}
JourneyLogger::~JourneyLogger() {
- if (was_show_called_)
+ if (WasPaymentRequestTriggered())
DCHECK(has_recorded_);
}
@@ -101,46 +101,57 @@ void JourneyLogger::SetNumberOfSuggestionsShown(Section section,
}
void JourneyLogger::SetCanMakePaymentValue(bool value) {
- was_can_make_payments_used_ = true;
- could_make_payment_ |= value;
-}
+ // Do not log the outcome of canMakePayment in incognito mode.
+ if (is_incognito_)
+ return;
-void JourneyLogger::SetShowCalled() {
- was_show_called_ = true;
+ SetEventOccurred(value ? EVENT_CAN_MAKE_PAYMENT_TRUE
+ : EVENT_CAN_MAKE_PAYMENT_FALSE);
}
void JourneyLogger::SetEventOccurred(Event event) {
events_ |= event;
}
-void JourneyLogger::SetSelectedPaymentMethod(
- SelectedPaymentMethod payment_method) {
- payment_method_ = payment_method;
-}
-
void JourneyLogger::SetRequestedInformation(bool requested_shipping,
bool requested_email,
bool requested_phone,
bool requested_name) {
// This method should only be called once per Payment Request.
- DCHECK(requested_information_ == REQUESTED_INFORMATION_MAX);
+ if (requested_shipping)
+ SetEventOccurred(EVENT_REQUEST_SHIPPING);
+
+ if (requested_email)
+ SetEventOccurred(EVENT_REQUEST_PAYER_EMAIL);
+
+ if (requested_phone)
+ SetEventOccurred(EVENT_REQUEST_PAYER_PHONE);
- requested_information_ =
- (requested_shipping ? REQUESTED_INFORMATION_SHIPPING : 0) |
- (requested_email ? REQUESTED_INFORMATION_EMAIL : 0) |
- (requested_phone ? REQUESTED_INFORMATION_PHONE : 0) |
- (requested_name ? REQUESTED_INFORMATION_NAME : 0);
+ if (requested_name)
+ SetEventOccurred(EVENT_REQUEST_PAYER_NAME);
}
-void JourneyLogger::SetCompleted() {
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Completed", true);
+void JourneyLogger::SetRequestedPaymentMethodTypes(
+ bool requested_basic_card,
+ bool requested_method_google,
+ bool requested_method_other) {
+ if (requested_basic_card)
+ SetEventOccurred(EVENT_REQUEST_METHOD_BASIC_CARD);
+
+ if (requested_method_google)
+ SetEventOccurred(EVENT_REQUEST_METHOD_GOOGLE);
+
+ if (requested_method_other)
+ SetEventOccurred(EVENT_REQUEST_METHOD_OTHER);
+}
+void JourneyLogger::SetCompleted() {
RecordJourneyStatsHistograms(COMPLETION_STATUS_COMPLETED);
}
void JourneyLogger::SetAborted(AbortReason reason) {
- // Don't log abort reasons if the Payment Request was not shown to the user.
- if (was_show_called_) {
+ // Don't log abort reasons if the Payment Request was not triggered.
+ if (WasPaymentRequestTriggered()) {
base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.Aborted",
reason, ABORT_REASON_MAX);
}
@@ -155,10 +166,6 @@ void JourneyLogger::SetAborted(AbortReason reason) {
void JourneyLogger::SetNotShown(NotShownReason reason) {
base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.NoShow", reason,
NOT_SHOWN_REASON_MAX);
-
- // Record that that Payment Request was initiated here, because nothing else
- // will be recorded for a Payment Request that was not shown to the user.
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Initiated", true);
}
void JourneyLogger::RecordJourneyStatsHistograms(
@@ -166,59 +173,20 @@ void JourneyLogger::RecordJourneyStatsHistograms(
DCHECK(!has_recorded_);
has_recorded_ = true;
- RecordCheckoutFlowMetrics();
- RecordCanMakePaymentStats(completion_status);
RecordUrlKeyedMetrics(completion_status);
RecordEventsMetric(completion_status);
- // These following metrics only make sense if the UI was shown to the user.
- if (was_show_called_) {
- RecordPaymentMethodMetric();
- RecordRequestedInformationMetrics();
+ // These following metrics only make sense if the Payment Request was
+ // triggered.
+ if (WasPaymentRequestTriggered()) {
RecordSectionSpecificStats(completion_status);
}
}
-void JourneyLogger::RecordCheckoutFlowMetrics() {
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Initiated", true);
-
- if (events_ & EVENT_SHOWN)
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Shown", true);
-
- if (events_ & EVENT_PAY_CLICKED)
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.PayClicked", true);
-
- if (events_ & EVENT_RECEIVED_INSTRUMENT_DETAILS)
- UMA_HISTOGRAM_BOOLEAN(
- "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", true);
-
- if (events_ & EVENT_SKIPPED_SHOW)
- UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.SkippedShow", true);
-}
-
-void JourneyLogger::RecordPaymentMethodMetric() {
- base::UmaHistogramEnumeration("PaymentRequest.SelectedPaymentMethod",
- payment_method_, SELECTED_PAYMENT_METHOD_MAX);
-}
-
-void JourneyLogger::RecordRequestedInformationMetrics() {
- DCHECK(requested_information_ != REQUESTED_INFORMATION_MAX);
- UMA_HISTOGRAM_ENUMERATION("PaymentRequest.RequestedInformation",
- requested_information_, REQUESTED_INFORMATION_MAX);
-}
-
void JourneyLogger::RecordSectionSpecificStats(
CompletionStatus completion_status) {
- // Record whether the user had suggestions for each requested information.
- bool user_had_all_requested_information = true;
-
- // Record whether the user had at least one complete suggestion for each
- // requested section.
- bool user_had_complete_suggestions_ = true;
-
for (int i = 0; i < NUMBER_OF_SECTIONS; ++i) {
std::string name_suffix = GetHistogramNameSuffix(i, completion_status);
-
// Only log the metrics for a section if it was requested by the merchant.
if (sections_[i].is_requested_) {
base::UmaHistogramCustomCounts(
@@ -237,93 +205,8 @@ void JourneyLogger::RecordSectionSpecificStats(
"PaymentRequest.NumberOfSuggestionsShown." + name_suffix,
std::min(sections_[i].number_suggestions_shown_, MAX_EXPECTED_SAMPLE),
MIN_EXPECTED_SAMPLE, MAX_EXPECTED_SAMPLE, NUMBER_BUCKETS);
-
- if (sections_[i].number_suggestions_shown_ == 0) {
- user_had_all_requested_information = false;
- user_had_complete_suggestions_ = false;
- } else if (!sections_[i].has_complete_suggestion_) {
- user_had_complete_suggestions_ = false;
- }
}
}
-
- // Record metrics about completion based on whether the user had suggestions
- // for each requested information.
- if (user_had_all_requested_information) {
- base::UmaHistogramEnumeration(
- "PaymentRequest.UserHadSuggestionsForEverything."
- "EffectOnCompletion",
- completion_status, COMPLETION_STATUS_MAX);
- } else {
- base::UmaHistogramEnumeration(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- completion_status, COMPLETION_STATUS_MAX);
- }
-
- // Record metrics about completion based on whether the user had complete
- // suggestions for each requested information.
- if (user_had_complete_suggestions_) {
- base::UmaHistogramEnumeration(
- "PaymentRequest.UserHadCompleteSuggestionsForEverything."
- "EffectOnCompletion",
- completion_status, COMPLETION_STATUS_MAX);
- } else {
- base::UmaHistogramEnumeration(
- "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
- "EffectOnCompletion",
- completion_status, COMPLETION_STATUS_MAX);
- }
-}
-
-void JourneyLogger::RecordCanMakePaymentStats(
- CompletionStatus completion_status) {
- // CanMakePayment always returns true in incognito mode. Don't log the
- // metrics.
- if (is_incognito_)
- return;
-
- // Record CanMakePayment usage.
- UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Usage",
- was_can_make_payments_used_
- ? CAN_MAKE_PAYMENT_USED
- : CAN_MAKE_PAYMENT_NOT_USED,
- CAN_MAKE_PAYMENT_USE_MAX);
-
- RecordCanMakePaymentEffectOnShow();
- RecordCanMakePaymentEffectOnCompletion(completion_status);
-}
-
-void JourneyLogger::RecordCanMakePaymentEffectOnShow() {
- if (!was_can_make_payments_used_)
- return;
-
- int effect_on_show = 0;
- if (was_show_called_)
- effect_on_show |= CMP_EFFECT_ON_SHOW_DID_SHOW;
- if (could_make_payment_)
- effect_on_show |= CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT;
-
- UMA_HISTOGRAM_ENUMERATION("PaymentRequest.CanMakePayment.Used.EffectOnShow",
- effect_on_show, CMP_EFFECT_ON_SHOW_MAX);
-}
-
-void JourneyLogger::RecordCanMakePaymentEffectOnCompletion(
- CompletionStatus completion_status) {
- if (!was_show_called_)
- return;
-
- std::string histogram_name = "PaymentRequest.CanMakePayment.";
- if (!was_can_make_payments_used_) {
- histogram_name += "NotUsed.WithShowEffectOnCompletion";
- } else if (could_make_payment_) {
- histogram_name += "Used.TrueWithShowEffectOnCompletion";
- } else {
- histogram_name += "Used.FalseWithShowEffectOnCompletion";
- }
-
- base::UmaHistogramEnumeration(histogram_name, completion_status,
- COMPLETION_STATUS_MAX);
}
void JourneyLogger::RecordEventsMetric(CompletionStatus completion_status) {
@@ -379,4 +262,8 @@ void JourneyLogger::RecordUrlKeyedMetrics(CompletionStatus completion_status) {
builder->AddMetric(internal::kUKMEventsMetricName, events_);
}
+bool JourneyLogger::WasPaymentRequestTriggered() {
+ return (events_ & EVENT_SHOWN) > 0 || (events_ & EVENT_SKIPPED_SHOW) > 0;
+}
+
} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.h b/chromium/components/payments/core/journey_logger.h
index 6db0e978ce1..f79e088e32a 100644
--- a/chromium/components/payments/core/journey_logger.h
+++ b/chromium/components/payments/core/journey_logger.h
@@ -43,48 +43,6 @@ class JourneyLogger {
SECTION_MAX,
};
- // For the CanMakePayment histograms.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
- // GENERATED_JAVA_CLASS_NAME_OVERRIDE: CanMakePaymentUsage
- enum CanMakePaymentUsage {
- CAN_MAKE_PAYMENT_USED = 0,
- CAN_MAKE_PAYMENT_NOT_USED = 1,
- CAN_MAKE_PAYMENT_USE_MAX,
- };
-
- // The information requested by the merchant.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
- // GENERATED_JAVA_CLASS_NAME_OVERRIDE: RequestedInformation
- enum RequestedInformation {
- REQUESTED_INFORMATION_NONE = 0,
- REQUESTED_INFORMATION_EMAIL = 1 << 0,
- REQUESTED_INFORMATION_PHONE = 1 << 1,
- REQUESTED_INFORMATION_SHIPPING = 1 << 2,
- REQUESTED_INFORMATION_NAME = 1 << 3,
- REQUESTED_INFORMATION_MAX = 16,
- };
-
- // The payment method that was used by the user to complete the transaction.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
- // GENERATED_JAVA_CLASS_NAME_OVERRIDE: SelectedPaymentMethod
- enum SelectedPaymentMethod {
- SELECTED_PAYMENT_METHOD_CREDIT_CARD = 0,
- SELECTED_PAYMENT_METHOD_ANDROID_PAY = 1,
- SELECTED_PAYMENT_METHOD_OTHER_PAYMENT_APP = 2,
- SELECTED_PAYMENT_METHOD_MAX = 3,
- };
-
- // Used to mesure the impact of the CanMakePayment return value on whether the
- // Payment Request is shown to the user.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
- // GENERATED_JAVA_CLASS_NAME_OVERRIDE: CanMakePaymentEffectOnShow
- enum CmpEffectOnShow {
- CMP_EFFECT_ON_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW = 0,
- CMP_EFFECT_ON_SHOW_DID_SHOW = 1 << 0,
- CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT = 1 << 1,
- CMP_EFFECT_ON_SHOW_MAX = 4,
- };
-
// Used to log different parameters' effect on whether the transaction was
// completed.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
@@ -101,17 +59,50 @@ class JourneyLogger {
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.payments
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: Event
enum Event {
+ // Initiated means the PaymentRequest object was constructed.
EVENT_INITIATED = 0,
+ // PaymentRequest was triggered via .show() and a native UI was shown.
EVENT_SHOWN = 1 << 0,
EVENT_PAY_CLICKED = 1 << 1,
EVENT_RECEIVED_INSTRUMENT_DETAILS = 1 << 2,
+ // PaymentRequest was triggered via .show() and no UI was shown because we
+ // skipped directly to the payment app.
EVENT_SKIPPED_SHOW = 1 << 3,
+ // .complete() was called by the merchant, completing the flow.
EVENT_COMPLETED = 1 << 4,
+ // The user aborted the flow by either dismissing it explicitely, or
+ // navigating away (if possible).
EVENT_USER_ABORTED = 1 << 5,
+ // Other reasons for aborting include the merchant calling .abort(), the
+ // merchant triggering a navigation, the tab closing, the browser closing,
+ // etc. See implementation for details.
EVENT_OTHER_ABORTED = 1 << 6,
EVENT_HAD_INITIAL_FORM_OF_PAYMENT = 1 << 7,
EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS = 1 << 8,
- EVENT_ENUM_MAX = 512,
+ // canMakePayment was called with a result of "true" or "false",
+ // respectively. An absence of both events means canMakePayment was not
+ // called, or the user was in incognito mode.
+ EVENT_CAN_MAKE_PAYMENT_TRUE = 1 << 9,
+ EVENT_CAN_MAKE_PAYMENT_FALSE = 1 << 10,
+ // Correspond to the merchant specifying requestShipping, requestPayerName,
+ // requestPayerEmail, requestPayerPhone.
+ EVENT_REQUEST_SHIPPING = 1 << 11,
+ EVENT_REQUEST_PAYER_NAME = 1 << 12,
+ EVENT_REQUEST_PAYER_EMAIL = 1 << 13,
+ EVENT_REQUEST_PAYER_PHONE = 1 << 14,
+ // The merchant requested at least one basic-card method.
+ EVENT_REQUEST_METHOD_BASIC_CARD = 1 << 15,
+ // The merchant requested a Google payment method.
+ EVENT_REQUEST_METHOD_GOOGLE = 1 << 16,
+ // The merchant requested a non-Google, non-basic-card payment method.
+ EVENT_REQUEST_METHOD_OTHER = 1 << 17,
+ // The user initiated the transaction using a saved credit card, a Google
+ // payment app (e.g., Android Pay), or another payment instrument,
+ // respectively.
+ EVENT_SELECTED_CREDIT_CARD = 1 << 18,
+ EVENT_SELECTED_GOOGLE = 1 << 19,
+ EVENT_SELECTED_OTHER = 1 << 20,
+ EVENT_ENUM_MAX = 2097152,
};
// The reason why the Payment Request was aborted.
@@ -166,21 +157,23 @@ class JourneyLogger {
// return value.
void SetCanMakePaymentValue(bool value);
- // Records the fact that the Payment Request was shown to the user.
- void SetShowCalled();
-
// Records that an event occurred.
void SetEventOccurred(Event event);
- // Records the payment method that was used to complete the Payment Request.
- void SetSelectedPaymentMethod(SelectedPaymentMethod payment_method);
-
// Records the user information requested by the merchant.
void SetRequestedInformation(bool requested_shipping,
bool requested_email,
bool requested_phone,
bool requested_name);
+ // Records the requested payment method types. A value should be true if at
+ // least one payment method in the category (basic-card, google payment method
+ // or other url-based payment method, respectively) is requested.
+ // TODO(crbug.com/754811): Add support for non-basic-card, non-URL methods.
+ void SetRequestedPaymentMethodTypes(bool requested_basic_card,
+ bool requested_method_google,
+ bool requested_method_other);
+
// Records that the Payment Request was completed successfully, and starts the
// logging of all the journey metrics.
void SetCompleted();
@@ -228,33 +221,10 @@ class JourneyLogger {
// either been completed or aborted.
void RecordJourneyStatsHistograms(CompletionStatus completion_status);
- // Records the histograms for all the steps of a complete checkout flow that
- // were reached.
- void RecordCheckoutFlowMetrics();
-
- // Records the metric about the selected payment method.
- void RecordPaymentMethodMetric();
-
- // Records the user information that the merchant requested.
- void RecordRequestedInformationMetrics();
-
// Records the histograms for all the sections that were requested by the
// merchant.
void RecordSectionSpecificStats(CompletionStatus completion_status);
- // Records the metrics related the the CanMakePayment method unless in
- // incognito mode.
- void RecordCanMakePaymentStats(CompletionStatus completion_status);
-
- // Records CanMakePayment's return value effect on whether the Payment Request
- // was shown or not.
- void RecordCanMakePaymentEffectOnShow();
-
- // Records the completion status depending on the the usage and return value
- // of the CanMakePaymentMethod.
- void RecordCanMakePaymentEffectOnCompletion(
- CompletionStatus completion_status);
-
// Records the metric about the different events that happened during the
// Payment Request.
void RecordEventsMetric(CompletionStatus completion_status);
@@ -262,22 +232,16 @@ class JourneyLogger {
// Records the Payment Request Url Keyed Metrics.
void RecordUrlKeyedMetrics(CompletionStatus completion_status);
+ // Returns whether this Payment Request was triggered (shown or skipped show).
+ bool WasPaymentRequestTriggered();
+
SectionStats sections_[NUMBER_OF_SECTIONS];
bool has_recorded_ = false;
- bool was_can_make_payments_used_ = false;
- bool could_make_payment_ = false;
- bool was_show_called_ = false;
bool is_incognito_;
// Accumulates the many events that have happened during the Payment Request.
int events_;
- // To keep track of the selected payment method.
- SelectedPaymentMethod payment_method_ = SELECTED_PAYMENT_METHOD_MAX;
-
- // Keeps track of the user information requested by the merchant.
- int requested_information_ = REQUESTED_INFORMATION_MAX;
-
const GURL url_;
// Not owned, will outlive this object.
diff --git a/chromium/components/payments/core/journey_logger_unittest.cc b/chromium/components/payments/core/journey_logger_unittest.cc
index f62931072ab..389a2bf7cb3 100644
--- a/chromium/components/payments/core/journey_logger_unittest.cc
+++ b/chromium/components/payments/core/journey_logger_unittest.cc
@@ -27,15 +27,13 @@ TEST(JourneyLoggerTest,
logger.SetCompleted();
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
- 1);
-
- // There should be no completion stats since PR was not shown to the user
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
}
// Tests the canMakePayment stats for the case where the merchant does not use
@@ -46,26 +44,20 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// The merchant does not query CanMakePayment, show the PaymentRequest and the
// user aborts it.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
- 1);
-
- // There should be a record for an abort when CanMakePayment is not used but
- // the PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant does not use
@@ -76,26 +68,20 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// The merchant does not query CanMakePayment, show the PaymentRequest and
// there is an abort not initiated by the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
- 1);
-
- // There should be a record for an abort when CanMakePayment is not used but
- // the PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant does not use
@@ -106,26 +92,20 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// The merchant does not query CanMakePayment, show the PaymentRequest and the
// user completes it.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCompleted();
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
- 1);
-
- // There should be a record for an abort when CanMakePayment is not used but
- // the PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -136,30 +116,18 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// The user cannot make payment and the PaymentRequest is not shown.
logger.SetCanMakePaymentValue(false);
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being false and not
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_NOT_MAKE_PAYMENT_AND_DID_NOT_SHOW,
- 1);
-
- // There should be no completion stats since PR was not shown to the user.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -170,29 +138,18 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
+ // The user can make payment and the PaymentRequest is not shown.
logger.SetCanMakePaymentValue(true);
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being true and not
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT, 1);
-
- // There should be no completion stats since PR was not shown to the user.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -203,30 +160,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user cannot make payment, the Payment Request is shown but is aborted
+ // by the user.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(false);
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being false and
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
- // There should be a record for an abort when CanMakePayment is false but the
- // PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -237,30 +185,20 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user cannot make payment, the Payment Request is shown but is aborted.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(false);
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being false and
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
- // There should be a record for an abort when CanMakePayment is false but the
- // PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -271,31 +209,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user cannot make payment, the payment request is shown and is
+ // completed.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(false);
logger.SetCompleted();
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being false and
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW, 1);
-
- // There should be a record for an completion when CanMakePayment is false but
- // the PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -306,32 +234,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user can make payment, the Payment Request is shown and aborted by the
+ // user.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(true);
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being true and not
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
- JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
- 1);
- // There should be a record for an abort when CanMakePayment is true and the
- // PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -342,32 +259,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user can make a payment, the request is shown but the transaction is
+ // aborted.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(true);
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being true and not
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
- JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
- 1);
- // There should be a record for an abort when CanMakePayment is true and the
- // PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
}
// Tests the canMakePayment stats for the case where the merchant uses it,
@@ -378,32 +284,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user can make a payment, the request is shown and the user completes
+ // the checkout.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(true);
logger.SetCompleted();
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
-
- // The CanMakePayment effect on show should be recorded as being true and not
- // shown.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.EffectOnShow",
- JourneyLogger::CMP_EFFECT_ON_SHOW_DID_SHOW |
- JourneyLogger::CMP_EFFECT_ON_SHOW_COULD_MAKE_PAYMENT,
- 1);
- // There should be a record for a completion when CanMakePayment is true and
- // the PR is shown to the user.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
}
// Tests the canMakePayment metrics are not logged if the Payment Request was
@@ -414,21 +309,21 @@ TEST(JourneyLoggerTest,
JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""),
/*ukm_recorder=*/nullptr);
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
- // The user cannot make payment and the PaymentRequest is not shown.
- logger.SetShowCalled();
+ // The user can make a payment, the request is shown and the user completes
+ // the checkout.
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger.SetRequestedInformation(true, false, false, false);
logger.SetCanMakePaymentValue(true);
logger.SetCompleted();
- // Expect no log for CanMakePayment.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix("PaymentRequest.CanMakePayment"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
}
// Tests that the completion status metrics based on whether the user had
@@ -443,28 +338,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for all the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 1,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user completes the checkout.
logger.SetCompleted();
- // Make sure that the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -476,6 +363,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -490,28 +384,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for all the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 1,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user aborts the checkout.
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -523,6 +409,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -537,28 +430,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for all the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 1,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the checkout is aborted.
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
- // Make sure that the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -570,6 +455,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -585,28 +477,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for all the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 1,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user completes the checkout.
logger.SetCompleted();
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -618,6 +502,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -632,29 +523,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for none of the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 0,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user completes the checkout.
logger.SetCompleted();
- // Make sure the expected metrics was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
- // Make sure the opposite metrics was not logged.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -666,6 +548,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -680,29 +569,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for none of the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 0,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user aborts the checkout.
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- // Make sure the metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -714,6 +594,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -728,29 +615,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for none of the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 0,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the the checkout is aborted.
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -762,6 +640,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -777,29 +662,20 @@ TEST(JourneyLoggerTest,
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had suggestions for none of the requested sections.
logger.SetNumberOfSuggestionsShown(JourneyLogger::SECTION_PAYMENT_METHOD, 0,
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the user aborts the checkout.
logger.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
-
- // Make sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -811,6 +687,13 @@ TEST(JourneyLoggerTest,
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -826,6 +709,9 @@ TEST(
logger.SetRequestedInformation(
/*requested_shipping=*/false, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had incomplete suggestions for the requested
// sections.
@@ -833,23 +719,11 @@ TEST(
/*has_complete_suggestion=*/false);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the the checkout is aborted.
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- // Make sure the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
- // Makes sure the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadCompleteSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -861,6 +735,13 @@ TEST(
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -876,6 +757,9 @@ TEST(
logger.SetRequestedInformation(
/*requested_shipping=*/true, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had incomplete suggestions for one of the requested
// sections.
@@ -885,23 +769,11 @@ TEST(
/*has_complete_suggestion=*/true);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the the checkout is aborted.
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- // Make sure that the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
- // Make sure that the opposite metric was not logged.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserHadCompleteSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -913,6 +785,13 @@ TEST(
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the completion status metrics based on whether the user had
@@ -928,6 +807,9 @@ TEST(
logger.SetRequestedInformation(
/*requested_shipping=*/true, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/false);
// Simulate that the user had incomplete suggestions for one of the requested
// sections.
@@ -937,24 +819,11 @@ TEST(
/*has_complete_suggestion=*/true);
// Simulate that the Payment Request was shown to the user.
- logger.SetShowCalled();
+ logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
// Simulate that the the checkout is aborted.
logger.SetAborted(JourneyLogger::ABORT_REASON_OTHER);
- // Make sure that the expected metric was logged.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadCompleteSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_OTHER_ABORTED, 1);
-
- // Make sure that the opposite metric was not logged.
- EXPECT_THAT(
- histogram_tester.GetTotalCountsForPrefix(
- "PaymentRequest.UserDidNotHaveCompleteSuggestionsForEverything."
- "EffectOnCompletion"),
- testing::ContainerEq(base::HistogramTester::CountsMap()));
-
// Make sure the correct events were logged.
std::vector<base::Bucket> buckets =
histogram_tester.GetAllSamples("PaymentRequest.Events");
@@ -966,6 +835,13 @@ TEST(
EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the metrics are logged correctly for two simultaneous Payment
@@ -978,14 +854,20 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_TwoPaymentRequests) {
/*ukm_recorder=*/nullptr);
// Make the two loggers have different data.
- logger1.SetShowCalled();
+ logger1.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger1.SetRequestedInformation(
/*requested_shipping=*/true, /*requested_email=*/true,
/*requested_phone=*/false, /*requested_name=*/false);
- logger2.SetShowCalled();
+ logger1.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/true,
+ /*requested_method_other=*/true);
+ logger2.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
logger2.SetRequestedInformation(
/*requested_shipping=*/true, /*requested_email=*/false,
/*requested_phone=*/false, /*requested_name=*/false);
+ logger2.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/false, /*requested_method_google=*/false,
+ /*requested_method_other=*/true);
logger1.SetCanMakePaymentValue(true);
@@ -998,27 +880,46 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_TwoPaymentRequests) {
logger1.SetCompleted();
logger2.SetAborted(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
- // Make sure the appropriate metrics were logged for logger1.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserHadSuggestionsForEverything.EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_USED, 1);
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_COMPLETED, 1);
-
- // Make sure the appropriate metrics were logged for logger2.
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.UserDidNotHaveSuggestionsForEverything."
- "EffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
- histogram_tester.ExpectBucketCount("PaymentRequest.CanMakePayment.Usage",
- JourneyLogger::CAN_MAKE_PAYMENT_NOT_USED,
- 1);
- histogram_tester.ExpectBucketCount(
- "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion",
- JourneyLogger::COMPLETION_STATUS_USER_ABORTED, 1);
+ // Make sure the correct events were logged.
+ std::vector<base::Bucket> buckets =
+ histogram_tester.GetAllSamples("PaymentRequest.Events");
+ ASSERT_EQ(2U, buckets.size());
+ // logger2
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[0].min &
+ JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+ EXPECT_FALSE(buckets[0].min &
+ JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
+ // logger1
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_SHOWN);
+ EXPECT_FALSE(buckets[1].min &
+ JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS);
+ EXPECT_TRUE(buckets[1].min &
+ JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT);
+ EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_OTHER_ABORTED);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_COMPLETED);
+ EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_USER_ABORTED);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_SHIPPING);
+ EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME);
+ EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE);
+ EXPECT_FALSE(buckets[1].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE);
+ EXPECT_TRUE(buckets[1].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER);
}
// Tests that the Payment Request UKMs are logged correctly when the user aborts
@@ -1031,6 +932,12 @@ TEST(JourneyLoggerTest,
base::HistogramTester histogram_tester;
JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(test_url),
/*ukm_recorder=*/&ukm_recorder);
+ logger.SetRequestedInformation(
+ /*requested_shipping=*/true, /*requested_email=*/true,
+ /*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/false,
+ /*requested_method_other=*/false);
// Simulate that the user aborts after being shown the Payment Request and
// clicking pay.
@@ -1058,7 +965,10 @@ TEST(JourneyLoggerTest,
const ukm::mojom::UkmMetric* step_metric =
ukm::TestUkmRecorder::FindMetric(entry, internal::kUKMEventsMetricName);
ASSERT_NE(nullptr, step_metric);
- EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_PAY_CLICKED,
+ EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_PAY_CLICKED |
+ JourneyLogger::EVENT_REQUEST_SHIPPING |
+ JourneyLogger::EVENT_REQUEST_PAYER_EMAIL |
+ JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD,
step_metric->value);
}
@@ -1072,6 +982,12 @@ TEST(JourneyLoggerTest,
base::HistogramTester histogram_tester;
JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(test_url),
/*ukm_recorder=*/&ukm_recorder);
+ logger.SetRequestedInformation(
+ /*requested_shipping=*/true, /*requested_email=*/true,
+ /*requested_phone=*/false, /*requested_name=*/false);
+ logger.SetRequestedPaymentMethodTypes(
+ /*requested_basic_card=*/true, /*requested_method_google=*/false,
+ /*requested_method_other=*/false);
// Simulate that the user aborts after being shown the Payment Request.
logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
@@ -1096,7 +1012,10 @@ TEST(JourneyLoggerTest,
const ukm::mojom::UkmMetric* step_metric =
ukm::TestUkmRecorder::FindMetric(entry, internal::kUKMEventsMetricName);
ASSERT_NE(nullptr, step_metric);
- EXPECT_EQ(JourneyLogger::EVENT_SHOWN, step_metric->value);
+ EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_REQUEST_SHIPPING |
+ JourneyLogger::EVENT_REQUEST_PAYER_EMAIL |
+ JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD,
+ step_metric->value);
}
} // namespace payments
diff --git a/chromium/components/payments/core/payment_address.h b/chromium/components/payments/core/payment_address.h
index 01403fe3746..76a5ae0148c 100644
--- a/chromium/components/payments/core/payment_address.h
+++ b/chromium/components/payments/core/payment_address.h
@@ -12,7 +12,7 @@
// C++ bindings for the PaymentRequest API PaymentAddress. Conforms to the
// following spec:
-// https://w3c.github.io/browser-payment-api/#paymentaddress-interface
+// https://w3c.github.io/payment-request/#dom-paymentaddress
namespace base {
class DictionaryValue;
diff --git a/chromium/components/payments/core/payment_address_unittest.cc b/chromium/components/payments/core/payment_address_unittest.cc
index 38dac5190aa..67a7c3fe167 100644
--- a/chromium/components/payments/core/payment_address_unittest.cc
+++ b/chromium/components/payments/core/payment_address_unittest.cc
@@ -4,8 +4,6 @@
#include "components/payments/core/payment_address.h"
-#include <vector>
-
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/payments/core/payment_currency_amount.cc b/chromium/components/payments/core/payment_currency_amount.cc
new file mode 100644
index 00000000000..0eb7c228dd5
--- /dev/null
+++ b/chromium/components/payments/core/payment_currency_amount.cc
@@ -0,0 +1,71 @@
+// 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/core/payment_currency_amount.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#dom-paymentcurrencyamount
+static const char kPaymentCurrencyAmountCurrencySystemISO4217[] =
+ "urn:iso:std:iso:4217";
+static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
+static const char kPaymentCurrencyAmountCurrency[] = "currency";
+static const char kPaymentCurrencyAmountValue[] = "value";
+
+} // namespace
+
+PaymentCurrencyAmount::PaymentCurrencyAmount()
+ // By default, the currency is defined by [ISO4217]. For example, USD for
+ // US Dollars.
+ : currency_system(kPaymentCurrencyAmountCurrencySystemISO4217) {}
+
+PaymentCurrencyAmount::~PaymentCurrencyAmount() = default;
+
+bool PaymentCurrencyAmount::operator==(
+ const PaymentCurrencyAmount& other) const {
+ return this->currency == other.currency && this->value == other.value;
+}
+
+bool PaymentCurrencyAmount::operator!=(
+ const PaymentCurrencyAmount& other) const {
+ return !(*this == other);
+}
+
+bool PaymentCurrencyAmount::FromDictionaryValue(
+ const base::DictionaryValue& value) {
+ if (!value.GetString(kPaymentCurrencyAmountCurrency, &this->currency)) {
+ return false;
+ }
+
+ if (!value.GetString(kPaymentCurrencyAmountValue, &this->value)) {
+ return false;
+ }
+
+ // Currency_system is optional
+ value.GetString(kPaymentCurrencyAmountCurrencySystem, &this->currency_system);
+
+ return true;
+}
+
+std::unique_ptr<base::DictionaryValue>
+PaymentCurrencyAmount::ToDictionaryValue() const {
+ std::unique_ptr<base::DictionaryValue> result =
+ base::MakeUnique<base::DictionaryValue>();
+
+ result->SetString(kPaymentCurrencyAmountCurrency, this->currency);
+ result->SetString(kPaymentCurrencyAmountValue, this->value);
+ if (!this->currency_system.empty())
+ result->SetString(kPaymentCurrencyAmountCurrencySystem,
+ this->currency_system);
+
+ return result;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_currency_amount.h b/chromium/components/payments/core/payment_currency_amount.h
new file mode 100644
index 00000000000..f35f60e560a
--- /dev/null
+++ b/chromium/components/payments/core/payment_currency_amount.h
@@ -0,0 +1,53 @@
+// 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_CORE_PAYMENT_CURRENCY_AMOUNT_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_
+
+#include <memory>
+#include <string>
+
+// C++ bindings for the PaymentRequest API PaymentCurrencyAmount. Conforms to
+// the following spec:
+// https://w3c.github.io/browser-payment-api/#dom-paymentcurrencyamount
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Supplies monetary amounts.
+class PaymentCurrencyAmount {
+ public:
+ PaymentCurrencyAmount();
+ ~PaymentCurrencyAmount();
+
+ bool operator==(const PaymentCurrencyAmount& other) const;
+ bool operator!=(const PaymentCurrencyAmount& other) const;
+
+ // Populates the properties of this PaymentCurrencyAmount from |value|.
+ // Returns true if the required values are present.
+ bool FromDictionaryValue(const base::DictionaryValue& value);
+
+ // Creates a base::DictionaryValue with the properties of this
+ // PaymentCurrencyAmount.
+ std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+ // A currency identifier. The most common identifiers are three-letter
+ // alphabetic codes as defined by ISO 4217 (for example, "USD" for US Dollars)
+ // however any string is considered valid.
+ std::string currency;
+
+ // A string containing the decimal monetary value.
+ std::string value;
+
+ // A URL that indicates the currency system that the currency identifier
+ // belongs to.
+ std::string currency_system;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_
diff --git a/chromium/components/payments/core/payment_currency_amount_unittest.cc b/chromium/components/payments/core/payment_currency_amount_unittest.cc
new file mode 100644
index 00000000000..bddca30e371
--- /dev/null
+++ b/chromium/components/payments/core/payment_currency_amount_unittest.cc
@@ -0,0 +1,106 @@
+// 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/core/payment_currency_amount.h"
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentCurrencyAmount from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueSuccess) {
+ PaymentCurrencyAmount expected;
+ expected.currency = "AUD";
+ expected.value = "-438.23";
+
+ base::DictionaryValue amount_dict;
+ amount_dict.SetString("currency", "AUD");
+ amount_dict.SetString("value", "-438.23");
+
+ PaymentCurrencyAmount actual;
+ EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
+
+ EXPECT_EQ(expected, actual);
+
+ expected.currency_system = "urn:iso:std:iso:123456789";
+ amount_dict.SetString("currencySystem", "urn:iso:std:iso:123456789");
+ EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentCurrencyAmount from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueFailure) {
+ // Both a currency and a value are required.
+ PaymentCurrencyAmount actual;
+ base::DictionaryValue amount_dict;
+ EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+
+ // Both values must be strings.
+ amount_dict.SetInteger("currency", 842);
+ amount_dict.SetString("value", "-438.23");
+ EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+
+ amount_dict.SetString("currency", "NZD");
+ amount_dict.SetDouble("value", -438.23);
+ EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+}
+
+// Tests that two currency amount objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+TEST(PaymentRequestTest, PaymentCurrencyAmountEquality) {
+ PaymentCurrencyAmount currency_amount1;
+ PaymentCurrencyAmount currency_amount2;
+ EXPECT_EQ(currency_amount1, currency_amount2);
+
+ currency_amount1.currency = "HKD";
+ EXPECT_NE(currency_amount1, currency_amount2);
+ currency_amount2.currency = "USD";
+ EXPECT_NE(currency_amount1, currency_amount2);
+ currency_amount2.currency = "HKD";
+ EXPECT_EQ(currency_amount1, currency_amount2);
+
+ currency_amount1.value = "49.89";
+ EXPECT_NE(currency_amount1, currency_amount2);
+ currency_amount2.value = "49.99";
+ EXPECT_NE(currency_amount1, currency_amount2);
+ currency_amount2.value = "49.89";
+ EXPECT_EQ(currency_amount1, currency_amount2);
+}
+
+// Tests that serializing a default PaymentCurrencyAmount yields the expected
+// result.
+TEST(PaymentRequestTest, EmptyPaymentCurrencyAmountDictionary) {
+ base::DictionaryValue expected_value;
+
+ expected_value.SetString("currency", "");
+ expected_value.SetString("value", "");
+ expected_value.SetString("currencySystem", "urn:iso:std:iso:4217");
+
+ PaymentCurrencyAmount payment_currency_amount;
+ EXPECT_TRUE(
+ expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentCurrencyAmount yields the expected
+// result.
+TEST(PaymentRequestTest, PopulatedCurrencyAmountDictionary) {
+ base::DictionaryValue expected_value;
+
+ expected_value.SetString("currency", "AUD");
+ expected_value.SetString("value", "-438.23");
+ expected_value.SetString("currencySystem", "urn:iso:std:iso:123456789");
+
+ PaymentCurrencyAmount payment_currency_amount;
+ payment_currency_amount.currency = "AUD";
+ payment_currency_amount.value = "-438.23";
+ payment_currency_amount.currency_system = "urn:iso:std:iso:123456789";
+
+ EXPECT_TRUE(
+ expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_details.cc b/chromium/components/payments/core/payment_details.cc
new file mode 100644
index 00000000000..cae50682afb
--- /dev/null
+++ b/chromium/components/payments/core/payment_details.cc
@@ -0,0 +1,115 @@
+// 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/core/payment_details.h"
+
+#include <algorithm>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#payment-details-dictionaries
+static const char kPaymentDetailsId[] = "id";
+static const char kPaymentDetailsDisplayItems[] = "displayItems";
+static const char kPaymentDetailsError[] = "error";
+static const char kPaymentDetailsShippingOptions[] = "shippingOptions";
+static const char kPaymentDetailsTotal[] = "total";
+
+} // namespace
+
+PaymentDetails::PaymentDetails() {}
+PaymentDetails::~PaymentDetails() = default;
+
+PaymentDetails::PaymentDetails(const PaymentDetails& other) {
+ *this = other;
+}
+
+PaymentDetails& PaymentDetails::operator=(const PaymentDetails& other) {
+ this->id = other.id;
+ if (other.total)
+ this->total = base::MakeUnique<PaymentItem>(*other.total);
+ else
+ this->total.reset(nullptr);
+ this->display_items = std::vector<PaymentItem>(other.display_items);
+ this->shipping_options =
+ std::vector<PaymentShippingOption>(other.shipping_options);
+ this->modifiers = std::vector<PaymentDetailsModifier>(other.modifiers);
+ return *this;
+}
+
+bool PaymentDetails::operator==(const PaymentDetails& other) const {
+ return this->id == other.id &&
+ ((!this->total && !other.total) ||
+ (this->total && other.total && *this->total == *other.total)) &&
+ this->display_items == other.display_items &&
+ this->shipping_options == other.shipping_options &&
+ this->modifiers == other.modifiers && this->error == other.error;
+}
+
+bool PaymentDetails::operator!=(const PaymentDetails& other) const {
+ return !(*this == other);
+}
+
+bool PaymentDetails::FromDictionaryValue(const base::DictionaryValue& value,
+ bool requires_total) {
+ this->display_items.clear();
+ this->shipping_options.clear();
+ this->modifiers.clear();
+
+ // ID is optional.
+ value.GetString(kPaymentDetailsId, &this->id);
+
+ const base::DictionaryValue* total_dict = nullptr;
+ if (!value.GetDictionary(kPaymentDetailsTotal, &total_dict) &&
+ requires_total) {
+ return false;
+ }
+ if (total_dict) {
+ this->total = base::MakeUnique<PaymentItem>();
+ if (!this->total->FromDictionaryValue(*total_dict))
+ return false;
+ }
+
+ const base::ListValue* display_items_list = nullptr;
+ if (value.GetList(kPaymentDetailsDisplayItems, &display_items_list)) {
+ for (size_t i = 0; i < display_items_list->GetSize(); ++i) {
+ const base::DictionaryValue* payment_item_dict;
+ if (!display_items_list->GetDictionary(i, &payment_item_dict)) {
+ return false;
+ }
+ PaymentItem payment_item;
+ if (!payment_item.FromDictionaryValue(*payment_item_dict)) {
+ return false;
+ }
+ this->display_items.push_back(payment_item);
+ }
+ }
+
+ const base::ListValue* shipping_options_list = nullptr;
+ if (value.GetList(kPaymentDetailsShippingOptions, &shipping_options_list)) {
+ for (size_t i = 0; i < shipping_options_list->GetSize(); ++i) {
+ const base::DictionaryValue* shipping_option_dict;
+ if (!shipping_options_list->GetDictionary(i, &shipping_option_dict)) {
+ return false;
+ }
+ PaymentShippingOption shipping_option;
+ if (!shipping_option.FromDictionaryValue(*shipping_option_dict)) {
+ return false;
+ }
+ this->shipping_options.push_back(shipping_option);
+ }
+ }
+
+ // Error is optional.
+ value.GetString(kPaymentDetailsError, &this->error);
+
+ return true;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_details.h b/chromium/components/payments/core/payment_details.h
new file mode 100644
index 00000000000..788c6c55ce2
--- /dev/null
+++ b/chromium/components/payments/core/payment_details.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_PAYMENTS_CORE_PAYMENT_DETAILS_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "components/payments/core/payment_details_modifier.h"
+#include "components/payments/core/payment_item.h"
+#include "components/payments/core/payment_shipping_option.h"
+
+// C++ bindings for the PaymentRequest API PaymentDetails. Conforms to the
+// following spec:
+// https://w3c.github.io/payment-request/#payment-details-dictionaries
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Details about the requested transaction.
+class PaymentDetails {
+ public:
+ PaymentDetails();
+ PaymentDetails(const PaymentDetails& other);
+ ~PaymentDetails();
+
+ PaymentDetails& operator=(const PaymentDetails& other);
+ bool operator==(const PaymentDetails& other) const;
+ bool operator!=(const PaymentDetails& other) const;
+
+ // Populates the properties of this PaymentDetails from |value|. Returns true
+ // if the required values are present. If |requires_total| is true, the total
+ // property has to be present.
+ bool FromDictionaryValue(const base::DictionaryValue& value,
+ bool requires_total);
+
+ // The unique free-form identifier for this payment request.
+ std::string id;
+
+ // The total amount of the payment request.
+ std::unique_ptr<PaymentItem> total;
+
+ // Line items for the payment request that the user agent may display. For
+ // example, it might include details of products or breakdown of tax and
+ // shipping.
+ std::vector<PaymentItem> display_items;
+
+ // The different shipping options for the user to choose from. If empty, this
+ // indicates that the merchant cannot ship to the current shipping address.
+ std::vector<PaymentShippingOption> shipping_options;
+
+ // Modifiers for particular payment method identifiers. For example, it allows
+ // adjustment to the total amount based on payment method.
+ std::vector<PaymentDetailsModifier> modifiers;
+
+ // If non-empty, this is the error message the user agent should display to
+ // the user when the payment request is updated using updateWith.
+ std::string error;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_H_
diff --git a/chromium/components/payments/core/payment_details_modifier.cc b/chromium/components/payments/core/payment_details_modifier.cc
new file mode 100644
index 00000000000..cae48306417
--- /dev/null
+++ b/chromium/components/payments/core/payment_details_modifier.cc
@@ -0,0 +1,76 @@
+// 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/core/payment_details_modifier.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#dom-paymentdetailsmodifier
+static const char kPaymentDetailsModifierTotal[] = "total";
+static const char kPaymentDetailsModifierSupportedMethods[] =
+ "supportedMethods";
+static const char kPaymentDetailsModifierData[] = "data";
+
+} // namespace
+
+PaymentDetailsModifier::PaymentDetailsModifier() {}
+PaymentDetailsModifier::~PaymentDetailsModifier() = default;
+
+PaymentDetailsModifier::PaymentDetailsModifier(
+ const PaymentDetailsModifier& other) {
+ *this = other;
+}
+
+PaymentDetailsModifier& PaymentDetailsModifier::operator=(
+ const PaymentDetailsModifier& other) {
+ this->method_data = other.method_data;
+ if (other.total)
+ this->total = base::MakeUnique<PaymentItem>(*other.total);
+ else
+ this->total.reset(nullptr);
+ this->additional_display_items = other.additional_display_items;
+ return *this;
+}
+
+bool PaymentDetailsModifier::operator==(
+ const PaymentDetailsModifier& other) const {
+ return this->method_data == other.method_data &&
+ ((!this->total && !other.total) ||
+ (this->total && other.total && *this->total == *other.total)) &&
+ this->additional_display_items == other.additional_display_items;
+}
+
+bool PaymentDetailsModifier::operator!=(
+ const PaymentDetailsModifier& other) const {
+ return !(*this == other);
+}
+
+std::unique_ptr<base::DictionaryValue>
+PaymentDetailsModifier::ToDictionaryValue() const {
+ std::unique_ptr<base::DictionaryValue> result =
+ base::MakeUnique<base::DictionaryValue>();
+
+ std::unique_ptr<base::ListValue> methods =
+ base::MakeUnique<base::ListValue>();
+ size_t numMethods = this->method_data.supported_methods.size();
+ for (size_t i = 0; i < numMethods; i++) {
+ methods->GetList().emplace_back(this->method_data.supported_methods[i]);
+ }
+ result->SetList(kPaymentDetailsModifierSupportedMethods, std::move(methods));
+ result->SetString(kPaymentDetailsModifierData, this->method_data.data);
+ if (this->total) {
+ result->SetDictionary(kPaymentDetailsModifierTotal,
+ this->total->ToDictionaryValue());
+ }
+
+ return result;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_details_modifier.h b/chromium/components/payments/core/payment_details_modifier.h
new file mode 100644
index 00000000000..d749236ebb8
--- /dev/null
+++ b/chromium/components/payments/core/payment_details_modifier.h
@@ -0,0 +1,61 @@
+// 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_CORE_PAYMENT_DETAILS_MODIFIER_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "components/payments/core/payment_item.h"
+#include "components/payments/core/payment_method_data.h"
+
+// C++ bindings for the PaymentRequest API PaymentDetailsModifier. Conforms to
+// the following spec:
+// https://w3c.github.io/payment-request/#dom-paymentdetailsmodifier
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Details that modify the PaymentDetails based on the payment method
+// identifier.
+class PaymentDetailsModifier {
+ public:
+ PaymentDetailsModifier();
+ PaymentDetailsModifier(const PaymentDetailsModifier& other);
+ ~PaymentDetailsModifier();
+
+ PaymentDetailsModifier& operator=(const PaymentDetailsModifier& other);
+ bool operator==(const PaymentDetailsModifier& other) const;
+ bool operator!=(const PaymentDetailsModifier& other) const;
+
+ // Creates a base::DictionaryValue with the properties of this
+ // PaymentDetailsModifier.
+ std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+ // A payment method identifier and any associated payment method specific
+ // data. The remaining fields in the PaymentDetailsModifier apply only if the
+ // user selects this payment method.
+ PaymentMethodData method_data;
+
+ // This value overrides the total field in the PaymentDetails dictionary for
+ // the payment method identifiers in the supportedMethods field.
+ std::unique_ptr<PaymentItem> total;
+
+ // Provides additional display items that are appended to the displayItems
+ // field in the PaymentDetails dictionary for the payment method identifiers
+ // in the supportedMethods field. This field is commonly used to add a
+ // discount or surcharge line item indicating the reason for the different
+ // total amount for the selected payment method that the user agent may
+ // display.
+ std::vector<PaymentItem> additional_display_items;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_
diff --git a/chromium/components/payments/core/payment_details_modifier_unittest.cc b/chromium/components/payments/core/payment_details_modifier_unittest.cc
new file mode 100644
index 00000000000..310f415d33f
--- /dev/null
+++ b/chromium/components/payments/core/payment_details_modifier_unittest.cc
@@ -0,0 +1,120 @@
+// 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/core/payment_details_modifier.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "components/payments/core/payment_method_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests that serializing a default PaymentDetailsModifier yields the expected
+// result.
+TEST(PaymentRequestTest, EmptyPaymentDetailsModifierDictionary) {
+ base::DictionaryValue expected_value;
+
+ std::unique_ptr<base::ListValue> supported_methods_list =
+ base::MakeUnique<base::ListValue>();
+ expected_value.SetList("supportedMethods", std::move(supported_methods_list));
+ expected_value.SetString("data", "");
+
+ PaymentDetailsModifier payment_details_modifier;
+ EXPECT_TRUE(expected_value.Equals(
+ payment_details_modifier.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentDetailsModifier yields the expected
+// result.
+TEST(PaymentRequestTest, PopulatedDetailsModifierDictionary) {
+ base::DictionaryValue expected_value;
+
+ std::unique_ptr<base::ListValue> supported_methods_list =
+ base::MakeUnique<base::ListValue>();
+ supported_methods_list->GetList().emplace_back("basic-card");
+ supported_methods_list->GetList().emplace_back("amex");
+ expected_value.SetList("supportedMethods", std::move(supported_methods_list));
+ expected_value.SetString("data",
+ "{\"supportedNetworks\":[\"visa\",\"mastercard\"]}");
+ std::unique_ptr<base::DictionaryValue> item_dict =
+ base::MakeUnique<base::DictionaryValue>();
+ item_dict->SetString("label", "Gratuity");
+ std::unique_ptr<base::DictionaryValue> amount_dict =
+ base::MakeUnique<base::DictionaryValue>();
+ amount_dict->SetString("currency", "USD");
+ amount_dict->SetString("value", "139.99");
+ amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+ item_dict->SetDictionary("amount", std::move(amount_dict));
+ item_dict->SetBoolean("pending", false);
+ expected_value.SetDictionary("total", std::move(item_dict));
+
+ PaymentDetailsModifier payment_details_modifier;
+ payment_details_modifier.method_data.supported_methods.push_back(
+ "basic-card");
+ payment_details_modifier.method_data.supported_methods.push_back("amex");
+ payment_details_modifier.method_data.data =
+ "{\"supportedNetworks\":[\"visa\",\"mastercard\"]}";
+ payment_details_modifier.total = base::MakeUnique<PaymentItem>();
+ payment_details_modifier.total->label = "Gratuity";
+ payment_details_modifier.total->amount.currency = "USD";
+ payment_details_modifier.total->amount.value = "139.99";
+
+ EXPECT_TRUE(expected_value.Equals(
+ payment_details_modifier.ToDictionaryValue().get()));
+}
+
+// Tests that two details modifier objects are not equal if their property
+// values differ or one is missing a value present in the other, and equal
+// otherwise. Doesn't test all properties of child objects, relying instead on
+// their respective tests.
+TEST(PaymentRequestTest, PaymentDetailsModifierEquality) {
+ PaymentDetailsModifier details_modifier1;
+ PaymentDetailsModifier details_modifier2;
+ EXPECT_EQ(details_modifier1, details_modifier2);
+
+ std::vector<std::string> supported_methods1;
+ supported_methods1.push_back("China UnionPay");
+ supported_methods1.push_back("BobPay");
+ details_modifier1.method_data.supported_methods = supported_methods1;
+ EXPECT_NE(details_modifier1, details_modifier2);
+ std::vector<std::string> supported_methods2;
+ supported_methods2.push_back("BobPay");
+ details_modifier2.method_data.supported_methods = supported_methods2;
+ EXPECT_NE(details_modifier1, details_modifier2);
+ details_modifier2.method_data.supported_methods = supported_methods1;
+ EXPECT_EQ(details_modifier1, details_modifier2);
+
+ details_modifier1.method_data.data =
+ "{\"supportedNetworks\":[\"visa\",\"mastercard\"]}";
+ EXPECT_NE(details_modifier1, details_modifier2);
+ details_modifier2.method_data.data =
+ "{\"supportedNetworks\":[\"visa\",\"mastercard\"]}";
+ EXPECT_EQ(details_modifier1, details_modifier2);
+
+ details_modifier1.total = base::MakeUnique<PaymentItem>();
+ details_modifier1.total->label = "Total";
+ EXPECT_NE(details_modifier1, details_modifier2);
+ details_modifier2.total = base::MakeUnique<PaymentItem>();
+ details_modifier2.total->label = "Gratuity";
+ EXPECT_NE(details_modifier1, details_modifier2);
+ details_modifier2.total->label = "Total";
+ EXPECT_EQ(details_modifier1, details_modifier2);
+
+ PaymentItem payment_item;
+ payment_item.label = "Tax";
+ std::vector<PaymentItem> display_items1;
+ display_items1.push_back(payment_item);
+ details_modifier1.additional_display_items = display_items1;
+ EXPECT_NE(details_modifier1, details_modifier2);
+ std::vector<PaymentItem> display_items2;
+ display_items2.push_back(payment_item);
+ display_items2.push_back(payment_item);
+ details_modifier2.additional_display_items = display_items2;
+ EXPECT_NE(details_modifier1, details_modifier2);
+ details_modifier2.additional_display_items = display_items1;
+ EXPECT_EQ(details_modifier1, details_modifier2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_details_unittest.cc b/chromium/components/payments/core/payment_details_unittest.cc
new file mode 100644
index 00000000000..b460292bb86
--- /dev/null
+++ b/chromium/components/payments/core/payment_details_unittest.cc
@@ -0,0 +1,136 @@
+// 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/core/payment_details.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentDetails from a dictionary.
+TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueSuccess) {
+ PaymentDetails expected;
+ expected.error = "Error in details";
+
+ base::DictionaryValue details_dict;
+ details_dict.SetString("error", "Error in details");
+ PaymentDetails actual;
+ EXPECT_TRUE(
+ actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
+ EXPECT_EQ(expected, actual);
+
+ expected.total = base::MakeUnique<PaymentItem>();
+ expected.total->label = "TOTAL";
+ expected.total->amount.currency = "GBP";
+ expected.total->amount.value = "6.66";
+
+ std::unique_ptr<base::DictionaryValue> total_dict(new base::DictionaryValue);
+ total_dict->SetString("label", "TOTAL");
+ std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+ amount_dict->SetString("currency", "GBP");
+ amount_dict->SetString("value", "6.66");
+ total_dict->Set("amount", std::move(amount_dict));
+ details_dict.Set("total", std::move(total_dict));
+
+ EXPECT_TRUE(
+ actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
+ EXPECT_EQ(expected, actual);
+
+ EXPECT_TRUE(
+ actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentDetails from a dictionary.
+TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueFailure) {
+ PaymentDetails expected;
+ expected.total = base::MakeUnique<PaymentItem>();
+ expected.total->label = "TOTAL";
+ expected.total->amount.currency = "GBP";
+ expected.total->amount.value = "6.66";
+ expected.error = "Error in details";
+
+ base::DictionaryValue details_dict;
+ details_dict.SetString("error", "Error in details");
+
+ PaymentDetails actual;
+ EXPECT_FALSE(
+ actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
+}
+
+// Tests that two payment details objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentDetailsEquality) {
+ PaymentDetails details1;
+ PaymentDetails details2;
+ EXPECT_EQ(details1, details2);
+
+ details1.id = "12345";
+ EXPECT_NE(details1, details2);
+ details2.id = "54321";
+ EXPECT_NE(details1, details2);
+ details2.id = details1.id;
+ EXPECT_EQ(details1, details2);
+
+ details1.total = base::MakeUnique<PaymentItem>();
+ details1.total->label = "Total";
+ EXPECT_NE(details1, details2);
+ details2.total = base::MakeUnique<PaymentItem>();
+ details2.total->label = "Shipping";
+ EXPECT_NE(details1, details2);
+ details2.total->label = "Total";
+ EXPECT_EQ(details1, details2);
+
+ details1.error = "Foo";
+ EXPECT_NE(details1, details2);
+ details2.error = "Bar";
+ EXPECT_NE(details1, details2);
+ details2.error = "Foo";
+ EXPECT_EQ(details1, details2);
+
+ PaymentItem payment_item;
+ payment_item.label = "Tax";
+ std::vector<PaymentItem> display_items1;
+ display_items1.push_back(payment_item);
+ details1.display_items = display_items1;
+ EXPECT_NE(details1, details2);
+ std::vector<PaymentItem> display_items2;
+ display_items2.push_back(payment_item);
+ display_items2.push_back(payment_item);
+ details2.display_items = display_items2;
+ EXPECT_NE(details1, details2);
+ details2.display_items = display_items1;
+ EXPECT_EQ(details1, details2);
+
+ PaymentShippingOption shipping_option;
+ shipping_option.label = "Overnight";
+ std::vector<PaymentShippingOption> shipping_options1;
+ shipping_options1.push_back(shipping_option);
+ details1.shipping_options = shipping_options1;
+ EXPECT_NE(details1, details2);
+ std::vector<PaymentShippingOption> shipping_options2;
+ shipping_options2.push_back(shipping_option);
+ shipping_options2.push_back(shipping_option);
+ details2.shipping_options = shipping_options2;
+ EXPECT_NE(details1, details2);
+ details2.shipping_options = shipping_options1;
+ EXPECT_EQ(details1, details2);
+
+ PaymentDetailsModifier details_modifier;
+
+ details_modifier.total = base::MakeUnique<PaymentItem>();
+ details_modifier.total->label = "Total";
+ details1.modifiers.push_back(details_modifier);
+ EXPECT_NE(details1, details2);
+ details2.modifiers.push_back(details_modifier);
+ EXPECT_EQ(details1, details2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_instrument.h b/chromium/components/payments/core/payment_instrument.h
index 24b1d14cac2..868b6ca67bd 100644
--- a/chromium/components/payments/core/payment_instrument.h
+++ b/chromium/components/payments/core/payment_instrument.h
@@ -19,7 +19,7 @@ namespace payments {
class PaymentInstrument {
public:
// The type of this instrument instance.
- enum class Type { AUTOFILL };
+ enum class Type { AUTOFILL, NATIVE_MOBILE_APP };
class Delegate {
public:
@@ -61,8 +61,9 @@ class PaymentInstrument {
// specifying |method| as a supported method of payment, false otherwise.
virtual bool IsValidForModifier(
const std::vector<std::string>& method,
+ const std::vector<std::string>& supported_networks,
const std::set<autofill::CreditCard::CardType>& supported_types,
- const std::vector<std::string>& supported_networks) const = 0;
+ bool supported_types_specified) const = 0;
const std::string& method_name() const { return method_name_; }
int icon_resource_id() const { return icon_resource_id_; }
diff --git a/chromium/components/payments/core/payment_item.cc b/chromium/components/payments/core/payment_item.cc
new file mode 100644
index 00000000000..d8775a8ad7b
--- /dev/null
+++ b/chromium/components/payments/core/payment_item.cc
@@ -0,0 +1,64 @@
+// 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/core/payment_item.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#dom-paymentitem
+static const char kPaymentItemAmount[] = "amount";
+static const char kPaymentItemLabel[] = "label";
+static const char kPaymentItemPending[] = "pending";
+
+} // namespace
+
+PaymentItem::PaymentItem() : pending(false) {}
+PaymentItem::~PaymentItem() = default;
+
+bool PaymentItem::operator==(const PaymentItem& other) const {
+ return this->label == other.label && this->amount == other.amount &&
+ this->pending == other.pending;
+}
+
+bool PaymentItem::operator!=(const PaymentItem& other) const {
+ return !(*this == other);
+}
+
+bool PaymentItem::FromDictionaryValue(const base::DictionaryValue& value) {
+ if (!value.GetString(kPaymentItemLabel, &this->label)) {
+ return false;
+ }
+
+ const base::DictionaryValue* amount_dict = nullptr;
+ if (!value.GetDictionary(kPaymentItemAmount, &amount_dict)) {
+ return false;
+ }
+ if (!this->amount.FromDictionaryValue(*amount_dict)) {
+ return false;
+ }
+
+ // Pending is optional.
+ value.GetBoolean(kPaymentItemPending, &this->pending);
+
+ return true;
+}
+
+std::unique_ptr<base::DictionaryValue> PaymentItem::ToDictionaryValue() const {
+ std::unique_ptr<base::DictionaryValue> result =
+ base::MakeUnique<base::DictionaryValue>();
+
+ result->SetString(kPaymentItemLabel, this->label);
+ result->SetDictionary(kPaymentItemAmount, this->amount.ToDictionaryValue());
+ result->SetBoolean(kPaymentItemPending, this->pending);
+
+ return result;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_item.h b/chromium/components/payments/core/payment_item.h
new file mode 100644
index 00000000000..0a4776a0034
--- /dev/null
+++ b/chromium/components/payments/core/payment_item.h
@@ -0,0 +1,55 @@
+// 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_CORE_PAYMENT_ITEM_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_ITEM_H_
+
+#include <memory>
+#include <string>
+
+#include "components/payments/core/payment_currency_amount.h"
+
+// C++ bindings for the PaymentRequest API PaymentItem. Conforms to the
+// following spec:
+// https://w3c.github.io/payment-request/#dom-paymentitem
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Information indicating what the payment request is for and the value asked
+// for.
+class PaymentItem {
+ public:
+ PaymentItem();
+ ~PaymentItem();
+
+ bool operator==(const PaymentItem& other) const;
+ bool operator!=(const PaymentItem& other) const;
+
+ // Populates the properties of this PaymentItem from |value|. Returns true if
+ // the required values are present.
+ bool FromDictionaryValue(const base::DictionaryValue& value);
+
+ // Creates a base::DictionaryValue with the properties of this
+ // PaymentItem.
+ std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+ // A human-readable description of the item.
+ std::string label;
+
+ // The monetary amount for the item.
+ PaymentCurrencyAmount amount;
+
+ // When set to true this flag means that the amount field is not final. This
+ // is commonly used to show items such as shipping or tax amounts that depend
+ // upon selection of shipping address or shipping option.
+ bool pending;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_ITEM_H_
diff --git a/chromium/components/payments/core/payment_item_unittest.cc b/chromium/components/payments/core/payment_item_unittest.cc
new file mode 100644
index 00000000000..a2fe8b83efd
--- /dev/null
+++ b/chromium/components/payments/core/payment_item_unittest.cc
@@ -0,0 +1,121 @@
+// 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/core/payment_item.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentItem from a dictionary.
+TEST(PaymentRequestTest, PaymentItemFromDictionaryValueSuccess) {
+ PaymentItem expected;
+ expected.label = "Payment Total";
+ expected.amount.currency = "NZD";
+ expected.amount.value = "2,242,093.00";
+
+ base::DictionaryValue item_dict;
+ item_dict.SetString("label", "Payment Total");
+ std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+ amount_dict->SetString("currency", "NZD");
+ amount_dict->SetString("value", "2,242,093.00");
+ item_dict.Set("amount", std::move(amount_dict));
+
+ PaymentItem actual;
+ EXPECT_TRUE(actual.FromDictionaryValue(item_dict));
+
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentItem from a dictionary.
+TEST(PaymentRequestTest, PaymentItemFromDictionaryValueFailure) {
+ // Both a label and an amount are required.
+ PaymentItem actual;
+ base::DictionaryValue item_dict;
+ EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+
+ item_dict.SetString("label", "Payment Total");
+ EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+
+ // Even with both present, the label must be a string.
+ std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+ amount_dict->SetString("currency", "NZD");
+ amount_dict->SetString("value", "2,242,093.00");
+ item_dict.Set("amount", std::move(amount_dict));
+ item_dict.SetInteger("label", 42);
+ EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+}
+
+// Tests that two payment item objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentItemEquality) {
+ PaymentItem item1;
+ PaymentItem item2;
+ EXPECT_EQ(item1, item2);
+
+ item1.label = "Subtotal";
+ EXPECT_NE(item1, item2);
+ item2.label = "Total";
+ EXPECT_NE(item1, item2);
+ item2.label = "Subtotal";
+ EXPECT_EQ(item1, item2);
+
+ item1.amount.value = "104.34";
+ EXPECT_NE(item1, item2);
+ item2.amount.value = "104";
+ EXPECT_NE(item1, item2);
+ item2.amount.value = "104.34";
+ EXPECT_EQ(item1, item2);
+
+ item1.pending = true;
+ EXPECT_NE(item1, item2);
+ item2.pending = true;
+ EXPECT_EQ(item1, item2);
+}
+
+// Tests that serializing a default PaymentItem yields the expected result.
+TEST(PaymentRequestTest, EmptyPaymentItemDictionary) {
+ base::DictionaryValue expected_value;
+
+ expected_value.SetString("label", "");
+ std::unique_ptr<base::DictionaryValue> amount_dict =
+ base::MakeUnique<base::DictionaryValue>();
+ amount_dict->SetString("currency", "");
+ amount_dict->SetString("value", "");
+ amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+ expected_value.SetDictionary("amount", std::move(amount_dict));
+ expected_value.SetBoolean("pending", false);
+
+ PaymentItem payment_item;
+ EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentItem yields the expected result.
+TEST(PaymentRequestTest, PopulatedPaymentItemDictionary) {
+ base::DictionaryValue expected_value;
+
+ expected_value.SetString("label", "Payment Total");
+ std::unique_ptr<base::DictionaryValue> amount_dict =
+ base::MakeUnique<base::DictionaryValue>();
+ amount_dict->SetString("currency", "NZD");
+ amount_dict->SetString("value", "2,242,093.00");
+ amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+ expected_value.SetDictionary("amount", std::move(amount_dict));
+ expected_value.SetBoolean("pending", true);
+
+ PaymentItem payment_item;
+ payment_item.label = "Payment Total";
+ payment_item.amount.currency = "NZD";
+ payment_item.amount.value = "2,242,093.00";
+ payment_item.pending = true;
+
+ EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_downloader.cc b/chromium/components/payments/core/payment_manifest_downloader.cc
index 63c4e077d87..8d3990f2d94 100644
--- a/chromium/components/payments/content/payment_manifest_downloader.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader.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/payments/content/payment_manifest_downloader.h"
+#include "components/payments/core/payment_manifest_downloader.h"
#include <algorithm>
#include <unordered_map>
@@ -145,7 +145,7 @@ void PaymentManifestDownloader::InitiateDownload(
destination: WEBSITE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"This feature cannot be disabled in settings. Users can uninstall/"
"disable all payment apps to stop this feature."
@@ -175,7 +175,8 @@ void PaymentManifestDownloader::InitiateDownload(
bool PaymentManifestDownloader::IsValidManifestUrl(const GURL& url) {
return url.is_valid() &&
(url.SchemeIs(url::kHttpsScheme) ||
- (url.SchemeIs(url::kHttpScheme) && allow_http_for_test_));
+ (allow_http_for_test_ && url.SchemeIs(url::kHttpScheme) &&
+ url.host() == "127.0.0.1"));
}
} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_downloader.h b/chromium/components/payments/core/payment_manifest_downloader.h
index 6ef80d3bff0..2e7e824c961 100644
--- a/chromium/components/payments/content/payment_manifest_downloader.h
+++ b/chromium/components/payments/core/payment_manifest_downloader.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_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
-#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_
#include <map>
#include <memory>
@@ -115,4 +115,4 @@ class PaymentManifestDownloader : public net::URLFetcherDelegate {
} // namespace payments
-#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENT_MANIFEST_DOWNLOADER_H_
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_
diff --git a/chromium/components/payments/content/payment_manifest_downloader_unittest.cc b/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
index a1266601f58..b84cfc4f592 100644
--- a/chromium/components/payments/content/payment_manifest_downloader_unittest.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader_unittest.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/payments/content/payment_manifest_downloader.h"
+#include "components/payments/core/payment_manifest_downloader.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/test/test_browser_thread_bundle.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
@@ -34,7 +34,7 @@ class PaymentMethodManifestDownloaderTest : public testing::Test {
net::TestURLFetcher* fetcher() { return factory_.GetFetcherByID(0); }
private:
- content::TestBrowserThreadBundle thread_bundle_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
net::TestURLFetcherFactory factory_;
scoped_refptr<net::TestURLRequestContextGetter> context_;
PaymentManifestDownloader downloader_;
@@ -237,7 +237,7 @@ class WebAppManifestDownloaderTest : public testing::Test {
net::TestURLFetcher* fetcher() { return factory_.GetFetcherByID(0); }
private:
- content::TestBrowserThreadBundle thread_bundle_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
net::TestURLFetcherFactory factory_;
scoped_refptr<net::TestURLRequestContextGetter> context_;
PaymentManifestDownloader downloader_;
diff --git a/chromium/components/payments/core/payment_method_data.cc b/chromium/components/payments/core/payment_method_data.cc
index b0bb839d699..b323c03ff31 100644
--- a/chromium/components/payments/core/payment_method_data.cc
+++ b/chromium/components/payments/core/payment_method_data.cc
@@ -64,21 +64,31 @@ bool PaymentMethodData::FromDictionaryValue(
this->supported_networks.clear();
this->supported_types.clear();
+ // The value of supportedMethods can be an array or a string.
const base::ListValue* supported_methods_list = nullptr;
- // At least one supported method is required.
- if (!value.GetList(kSupportedMethods, &supported_methods_list) ||
- supported_methods_list->GetSize() == 0) {
- return false;
- }
- for (size_t i = 0; i < supported_methods_list->GetSize(); ++i) {
+ if (value.GetList(kSupportedMethods, &supported_methods_list)) {
+ for (size_t i = 0; i < supported_methods_list->GetSize(); ++i) {
+ std::string supported_method;
+ if (!supported_methods_list->GetString(i, &supported_method) ||
+ !base::IsStringASCII(supported_method)) {
+ return false;
+ }
+ if (!supported_method.empty())
+ this->supported_methods.push_back(supported_method);
+ }
+ } else {
std::string supported_method;
- if (!supported_methods_list->GetString(i, &supported_method) ||
- !base::IsStringASCII(supported_method)) {
+ if (!value.GetString(kSupportedMethods, &supported_method) ||
+ !base::IsStringASCII(supported_method) || supported_method.empty()) {
return false;
}
this->supported_methods.push_back(supported_method);
}
+ // At least one supported method is required.
+ if (supported_methods.empty())
+ return false;
+
// Data is optional, but if a dictionary is present, save a stringified
// version and attempt to parse supportedNetworks/supportedTypes.
const base::DictionaryValue* data_dict = nullptr;
diff --git a/chromium/components/payments/core/payment_method_data_unittest.cc b/chromium/components/payments/core/payment_method_data_unittest.cc
index b44a23161d3..dfb69cf8185 100644
--- a/chromium/components/payments/core/payment_method_data_unittest.cc
+++ b/chromium/components/payments/core/payment_method_data_unittest.cc
@@ -9,8 +9,9 @@
namespace payments {
-// Tests the success case when populating a PaymentMethodData from a dictionary.
-TEST(PaymentMethodData, FromDictionaryValueSuccess) {
+// Tests the success case when populating a PaymentMethodData from a dictionary
+// when the supportedMethods is an array of strings.
+TEST(PaymentMethodData, FromDictionaryValueSuccess_SupportedMethodsArray) {
PaymentMethodData expected;
expected.supported_methods.push_back("visa");
expected.supported_methods.push_back("basic-card");
@@ -42,7 +43,38 @@ TEST(PaymentMethodData, FromDictionaryValueSuccess) {
EXPECT_EQ(expected, actual);
}
-// Tests the failure case when populating a PaymentMethodData from a dictionary.
+// Tests the success case when populating a PaymentMethodData from a dictionary
+// when the supportedMethods is a string.
+TEST(PaymentMethodData, FromDictionaryValueSuccess_SupportedMethodsString) {
+ PaymentMethodData expected;
+ expected.supported_methods.push_back("basic-card");
+ expected.data =
+ "{\"supportedNetworks\":[\"mastercard\"],"
+ "\"supportedTypes\":[\"debit\",\"credit\"]}";
+ expected.supported_networks.push_back("mastercard");
+ expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_DEBIT);
+ expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_CREDIT);
+
+ base::DictionaryValue method_data_dict;
+ method_data_dict.SetString("supportedMethods", "basic-card");
+ std::unique_ptr<base::DictionaryValue> data_dict(new base::DictionaryValue);
+ std::unique_ptr<base::ListValue> supported_networks_list(new base::ListValue);
+ supported_networks_list->AppendString("mastercard");
+ data_dict->Set("supportedNetworks", std::move(supported_networks_list));
+ std::unique_ptr<base::ListValue> supported_types_list(new base::ListValue);
+ supported_types_list->AppendString("debit");
+ supported_types_list->AppendString("credit");
+ data_dict->Set("supportedTypes", std::move(supported_types_list));
+ method_data_dict.Set("data", std::move(data_dict));
+
+ PaymentMethodData actual;
+ EXPECT_TRUE(actual.FromDictionaryValue(method_data_dict));
+
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure cases when populating a PaymentMethodData from a
+// dictionary.
TEST(PaymentMethodData, FromDictionaryValueFailure) {
// At least one supported method is required.
PaymentMethodData actual;
@@ -50,9 +82,23 @@ TEST(PaymentMethodData, FromDictionaryValueFailure) {
EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
// The value in the supported methods list must be a string.
- std::unique_ptr<base::ListValue> supported_methods_list(new base::ListValue);
- supported_methods_list->AppendInteger(13);
- method_data_dict.Set("supportedMethods", std::move(supported_methods_list));
+ std::unique_ptr<base::ListValue> supported_methods_list1(new base::ListValue);
+ supported_methods_list1->AppendInteger(13);
+ method_data_dict.Set("supportedMethods", std::move(supported_methods_list1));
+ EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
+
+ // The value in the supported methods list must be a non-empty string.
+ std::unique_ptr<base::ListValue> supported_methods_list2(new base::ListValue);
+ supported_methods_list2->AppendString("");
+ method_data_dict.Set("supportedMethods", std::move(supported_methods_list2));
+ EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
+
+ // The value in the supported methods must be a string.
+ method_data_dict.SetInteger("supportedMethods", 13);
+ EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
+
+ // The value in the supported methods must be a non-empty string.
+ method_data_dict.SetString("supportedMethods", "");
EXPECT_FALSE(actual.FromDictionaryValue(method_data_dict));
}
diff --git a/chromium/components/payments/core/payment_request_data_util.cc b/chromium/components/payments/core/payment_request_data_util.cc
index 43e7f2c36d8..33d80570131 100644
--- a/chromium/components/payments/core/payment_request_data_util.cc
+++ b/chromium/components/payments/core/payment_request_data_util.cc
@@ -19,7 +19,6 @@
#include "components/payments/core/payment_address.h"
#include "components/payments/core/payment_method_data.h"
#include "third_party/libphonenumber/phonenumber_api.h"
-#include "url/gurl.h"
#include "url/url_constants.h"
namespace payments {
@@ -54,21 +53,18 @@ PaymentAddress GetPaymentAddressFromAutofillProfile(
PaymentAddress address;
address.country = profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY);
address.address_line = base::SplitString(
- profile.GetInfo(
- autofill::AutofillType(autofill::ADDRESS_HOME_STREET_ADDRESS),
- app_locale),
+ profile.GetInfo(autofill::ADDRESS_HOME_STREET_ADDRESS, app_locale),
base::ASCIIToUTF16("\n"), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- address.region = profile.GetRawInfo(autofill::ADDRESS_HOME_STATE);
- address.city = profile.GetRawInfo(autofill::ADDRESS_HOME_CITY);
+ address.region = profile.GetInfo(autofill::ADDRESS_HOME_STATE, app_locale);
+ address.city = profile.GetInfo(autofill::ADDRESS_HOME_CITY, app_locale);
address.dependent_locality =
- profile.GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY);
- address.postal_code = profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP);
+ profile.GetInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, app_locale);
+ address.postal_code = profile.GetInfo(autofill::ADDRESS_HOME_ZIP, app_locale);
address.sorting_code =
- profile.GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE);
+ profile.GetInfo(autofill::ADDRESS_HOME_SORTING_CODE, app_locale);
address.language_code = base::UTF8ToUTF16(profile.language_code());
- address.organization = profile.GetRawInfo(autofill::COMPANY_NAME);
- address.recipient =
- profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), app_locale);
+ address.organization = profile.GetInfo(autofill::COMPANY_NAME, app_locale);
+ address.recipient = profile.GetInfo(autofill::NAME_FULL, app_locale);
address.phone = profile.GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER);
return address;
@@ -97,7 +93,7 @@ void ParseSupportedMethods(
const std::vector<PaymentMethodData>& method_data,
std::vector<std::string>* out_supported_networks,
std::set<std::string>* out_basic_card_specified_networks,
- std::vector<std::string>* out_url_payment_method_identifiers) {
+ std::vector<GURL>* out_url_payment_method_identifiers) {
DCHECK(out_supported_networks->empty());
DCHECK(out_basic_card_specified_networks->empty());
DCHECK(out_url_payment_method_identifiers->empty());
@@ -168,7 +164,7 @@ void ParseSupportedMethods(
!url.has_username() && !url.has_password()) {
const auto result = url_payment_method_identifiers.insert(url);
if (result.second)
- out_url_payment_method_identifiers->push_back(method);
+ out_url_payment_method_identifiers->push_back(url);
}
}
}
diff --git a/chromium/components/payments/core/payment_request_data_util.h b/chromium/components/payments/core/payment_request_data_util.h
index 7ede39a384a..9e5b56e9084 100644
--- a/chromium/components/payments/core/payment_request_data_util.h
+++ b/chromium/components/payments/core/payment_request_data_util.h
@@ -11,6 +11,7 @@
#include "base/strings/string16.h"
#include "components/autofill/core/browser/credit_card.h"
+#include "url/gurl.h"
namespace autofill {
class AutofillProfile;
@@ -55,7 +56,7 @@ void ParseSupportedMethods(
const std::vector<PaymentMethodData>& method_data,
std::vector<std::string>* out_supported_networks,
std::set<std::string>* out_basic_card_supported_networks,
- std::vector<std::string>* out_url_payment_method_identifiers);
+ std::vector<GURL>* out_url_payment_method_identifiers);
// Parses the supported card types (e.g., credit, debit, prepaid) from
// supportedTypes. |out_supported_card_types_set| is expected to be empty. It
diff --git a/chromium/components/payments/core/payment_shipping_option.cc b/chromium/components/payments/core/payment_shipping_option.cc
new file mode 100644
index 00000000000..5e91a4b449a
--- /dev/null
+++ b/chromium/components/payments/core/payment_shipping_option.cc
@@ -0,0 +1,62 @@
+// 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/core/payment_shipping_option.h"
+
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#dom-paymentshippingoption
+static const char kPaymentShippingOptionAmount[] = "amount";
+static const char kPaymentShippingOptionId[] = "id";
+static const char kPaymentShippingOptionLabel[] = "label";
+static const char kPaymentShippingOptionSelected[] = "selected";
+
+} // namespace
+
+PaymentShippingOption::PaymentShippingOption() : selected(false) {}
+PaymentShippingOption::PaymentShippingOption(
+ const PaymentShippingOption& other) = default;
+PaymentShippingOption::~PaymentShippingOption() = default;
+
+bool PaymentShippingOption::operator==(
+ const PaymentShippingOption& other) const {
+ return this->id == other.id && this->label == other.label &&
+ this->amount == other.amount && this->selected == other.selected;
+}
+
+bool PaymentShippingOption::operator!=(
+ const PaymentShippingOption& other) const {
+ return !(*this == other);
+}
+
+bool PaymentShippingOption::FromDictionaryValue(
+ const base::DictionaryValue& value) {
+ if (!value.GetString(kPaymentShippingOptionId, &this->id)) {
+ return false;
+ }
+
+ if (!value.GetString(kPaymentShippingOptionLabel, &this->label)) {
+ return false;
+ }
+
+ const base::DictionaryValue* amount_dict = nullptr;
+ if (!value.GetDictionary(kPaymentShippingOptionAmount, &amount_dict)) {
+ return false;
+ }
+ if (!this->amount.FromDictionaryValue(*amount_dict)) {
+ return false;
+ }
+
+ // Selected is optional.
+ value.GetBoolean(kPaymentShippingOptionSelected, &this->selected);
+
+ return true;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payment_shipping_option.h b/chromium/components/payments/core/payment_shipping_option.h
new file mode 100644
index 00000000000..676b07b9f29
--- /dev/null
+++ b/chromium/components/payments/core/payment_shipping_option.h
@@ -0,0 +1,54 @@
+// 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_CORE_PAYMENT_SHIPPING_OPTION_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_SHIPPING_OPTION_H_
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_currency_amount.h"
+
+// C++ bindings for the PaymentRequest API PaymentShippingOption. Conforms to
+// the following spec:
+// https://w3c.github.io/browser-payment-api/#dom-paymentshippingoption
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Information describing a shipping option.
+class PaymentShippingOption {
+ public:
+ PaymentShippingOption();
+ PaymentShippingOption(const PaymentShippingOption& other);
+ ~PaymentShippingOption();
+
+ bool operator==(const PaymentShippingOption& other) const;
+ bool operator!=(const PaymentShippingOption& other) const;
+
+ // Populates the properties of this PaymentShippingOption from |value|.
+ // Returns true if the required values are present.
+ bool FromDictionaryValue(const base::DictionaryValue& value);
+
+ // An identifier used to reference this PaymentShippingOption. It is unique
+ // for a given PaymentRequest.
+ std::string id;
+
+ // A human-readable description of the item. The user agent should use this
+ // string to display the shipping option to the user.
+ std::string label;
+
+ // A PaymentCurrencyAmount containing the monetary amount for the option.
+ PaymentCurrencyAmount amount;
+
+ // This is set to true to indicate that this is the default selected
+ // PaymentShippingOption in a sequence. User agents should display this option
+ // by default in the user interface.
+ bool selected;
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENT_SHIPPING_OPTION_H_
diff --git a/chromium/components/payments/core/payment_shipping_option_unittest.cc b/chromium/components/payments/core/payment_shipping_option_unittest.cc
new file mode 100644
index 00000000000..e124ffc5eb1
--- /dev/null
+++ b/chromium/components/payments/core/payment_shipping_option_unittest.cc
@@ -0,0 +1,110 @@
+// 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/core/payment_shipping_option.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentShippingOption from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueSuccess) {
+ PaymentShippingOption expected;
+ expected.id = "123";
+ expected.label = "Ground Shipping";
+ expected.amount.currency = "BRL";
+ expected.amount.value = "4,000.32";
+ expected.selected = true;
+
+ base::DictionaryValue shipping_option_dict;
+ shipping_option_dict.SetString("id", "123");
+ shipping_option_dict.SetString("label", "Ground Shipping");
+ std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+ amount_dict->SetString("currency", "BRL");
+ amount_dict->SetString("value", "4,000.32");
+ shipping_option_dict.Set("amount", std::move(amount_dict));
+ shipping_option_dict.SetBoolean("selected", true);
+
+ PaymentShippingOption actual;
+ EXPECT_TRUE(actual.FromDictionaryValue(shipping_option_dict));
+
+ EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentShippingOption from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueFailure) {
+ PaymentShippingOption expected;
+ expected.id = "123";
+ expected.label = "Ground Shipping";
+ expected.amount.currency = "BRL";
+ expected.amount.value = "4,000.32";
+ expected.selected = true;
+
+ PaymentShippingOption actual;
+ base::DictionaryValue shipping_option_dict;
+
+ // Id, Label, and amount are required.
+ shipping_option_dict.SetString("id", "123");
+ EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+ shipping_option_dict.SetString("label", "Ground Shipping");
+ EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+ // Id must be a string.
+ std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+ amount_dict->SetString("currency", "BRL");
+ amount_dict->SetString("value", "4,000.32");
+ shipping_option_dict.Set("amount", std::move(amount_dict));
+ shipping_option_dict.SetInteger("id", 123);
+ EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+ // Label must be a string.
+ shipping_option_dict.SetString("id", "123");
+ shipping_option_dict.SetInteger("label", 123);
+ EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+}
+
+// Tests that two shipping option objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentShippingOptionEquality) {
+ PaymentShippingOption shipping_option1;
+ PaymentShippingOption shipping_option2;
+ EXPECT_EQ(shipping_option1, shipping_option2);
+
+ shipping_option1.id = "a8df2";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.id = "k42jk";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.id = "a8df2";
+ EXPECT_EQ(shipping_option1, shipping_option2);
+
+ shipping_option1.label = "Overnight";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.label = "Ground";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.label = "Overnight";
+ EXPECT_EQ(shipping_option1, shipping_option2);
+
+ shipping_option1.amount.currency = "AUD";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.amount.currency = "HKD";
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.amount.currency = "AUD";
+ EXPECT_EQ(shipping_option1, shipping_option2);
+
+ shipping_option1.selected = true;
+ EXPECT_NE(shipping_option1, shipping_option2);
+ shipping_option2.selected = true;
+ EXPECT_EQ(shipping_option1, shipping_option2);
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/payments_profile_comparator.cc b/chromium/components/payments/core/payments_profile_comparator.cc
index faeab2d7f10..8be6829d52f 100644
--- a/chromium/components/payments/core/payments_profile_comparator.cc
+++ b/chromium/components/payments/core/payments_profile_comparator.cc
@@ -136,12 +136,6 @@ bool PaymentsProfileComparator::IsContactInfoComplete(
GetRequiredProfileFieldsForContact());
}
-base::string16 PaymentsProfileComparator::GetStringForMissingContactFields(
- const autofill::AutofillProfile& profile) const {
- return GetStringForMissingFields(GetMissingProfileFields(&profile) &
- GetRequiredProfileFieldsForContact());
-}
-
std::vector<autofill::AutofillProfile*>
PaymentsProfileComparator::FilterProfilesForShipping(
const std::vector<autofill::AutofillProfile*>& profiles) const {
@@ -182,12 +176,30 @@ bool PaymentsProfileComparator::IsShippingComplete(
GetRequiredProfileFieldsForShipping());
}
+base::string16 PaymentsProfileComparator::GetStringForMissingContactFields(
+ const autofill::AutofillProfile& profile) const {
+ return GetStringForMissingFields(GetMissingProfileFields(&profile) &
+ GetRequiredProfileFieldsForContact());
+}
+
+base::string16 PaymentsProfileComparator::GetTitleForMissingContactFields(
+ const autofill::AutofillProfile& profile) const {
+ return GetTitleForMissingFields(GetMissingProfileFields(&profile) &
+ GetRequiredProfileFieldsForContact());
+}
+
base::string16 PaymentsProfileComparator::GetStringForMissingShippingFields(
const autofill::AutofillProfile& profile) const {
return GetStringForMissingFields(GetMissingProfileFields(&profile) &
GetRequiredProfileFieldsForShipping());
}
+base::string16 PaymentsProfileComparator::GetTitleForMissingShippingFields(
+ const autofill::AutofillProfile& profile) const {
+ return GetTitleForMissingFields(GetMissingProfileFields(&profile) &
+ GetRequiredProfileFieldsForShipping());
+}
+
void PaymentsProfileComparator::Invalidate(
const autofill::AutofillProfile& profile) {
cache_.erase(profile.guid());
@@ -266,6 +278,28 @@ base::string16 PaymentsProfileComparator::GetStringForMissingFields(
}
}
+base::string16 PaymentsProfileComparator::GetTitleForMissingFields(
+ PaymentsProfileComparator::ProfileFields fields) const {
+ switch (fields) {
+ case 0:
+ NOTREACHED() << "Title should not be requested if no fields are missing";
+ return base::string16();
+ case kName:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_NAME);
+ case kPhone:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_PHONE_NUMBER);
+ case kEmail:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_EMAIL);
+ case kAddress:
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_VALID_ADDRESS);
+ default:
+ // Either multiple bits are set (likely) or one bit that doesn't
+ // correspond to a named constant is set (shouldn't happen). Return a
+ // generic "More information" message.
+ return l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_MORE_INFORMATION);
+ }
+}
+
bool PaymentsProfileComparator::AreRequiredAddressFieldsPresent(
const autofill::AutofillProfile& profile) const {
std::unique_ptr<::i18n::addressinput::AddressData> data =
diff --git a/chromium/components/payments/core/payments_profile_comparator.h b/chromium/components/payments/core/payments_profile_comparator.h
index 61e76092bb7..38d43320654 100644
--- a/chromium/components/payments/core/payments_profile_comparator.h
+++ b/chromium/components/payments/core/payments_profile_comparator.h
@@ -89,12 +89,24 @@ class PaymentsProfileComparator : public autofill::AutofillProfileComparator {
base::string16 GetStringForMissingContactFields(
const autofill::AutofillProfile& profile) const;
+ // Returns a localized string to be displayed as the title of a piece of UI,
+ // indicating what action must be taken for the given profile to be used as
+ // contact info.
+ base::string16 GetTitleForMissingContactFields(
+ const autofill::AutofillProfile& profile) const;
+
// Returns a localized string to be displayed in UI indicating what action,
// if any, must be taken for the given profile to be used as a shipping
// address.
base::string16 GetStringForMissingShippingFields(
const autofill::AutofillProfile& profile) const;
+ // Returns a localized string to be displayed as the title of a piece of UI,
+ // indicating what action must be taken for the given profile to be used as
+ // shipping address.
+ base::string16 GetTitleForMissingShippingFields(
+ const autofill::AutofillProfile& profile) const;
+
// Clears the cached evaluation result for |profile|. Must be called when a
// profile is modified and saved during the course of a PaymentRequest.
virtual void Invalidate(const autofill::AutofillProfile& profile);
@@ -105,6 +117,7 @@ class PaymentsProfileComparator : public autofill::AutofillProfileComparator {
ProfileFields GetRequiredProfileFieldsForContact() const;
ProfileFields GetRequiredProfileFieldsForShipping() const;
base::string16 GetStringForMissingFields(ProfileFields fields) const;
+ base::string16 GetTitleForMissingFields(ProfileFields fields) const;
bool AreRequiredAddressFieldsPresent(
const autofill::AutofillProfile& profile) const;
diff --git a/chromium/components/payments/core/payments_profile_comparator_unittest.cc b/chromium/components/payments/core/payments_profile_comparator_unittest.cc
index 18f3e58ae15..a1b0dc7e4b0 100644
--- a/chromium/components/payments/core/payments_profile_comparator_unittest.cc
+++ b/chromium/components/payments/core/payments_profile_comparator_unittest.cc
@@ -417,6 +417,35 @@ TEST(PaymentRequestProfileUtilTest, GetStringForMissingContactFields) {
comp.GetStringForMissingContactFields(p5));
}
+TEST(PaymentRequestProfileUtilTest, GetTitleForMissingContactFields) {
+ MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone |
+ kRequestPayerEmail | kRequestShipping);
+ PaymentsProfileComparator comp("en-US", provider);
+
+ // Error message for email address if email address is missing and required.
+ AutofillProfile p1 = CreateProfileWithContactInfo("Homer", "", "6515553226");
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_EMAIL),
+ comp.GetTitleForMissingContactFields(p1));
+
+ // Error message for phone number if phone is missing and required.
+ AutofillProfile p2 =
+ CreateProfileWithContactInfo("Homer", "homer@simpson.net", "");
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_PHONE_NUMBER),
+ comp.GetTitleForMissingContactFields(p2));
+
+ // Error message for name if name is missing and required.
+ AutofillProfile p3 =
+ CreateProfileWithContactInfo("", "homer@simpson.net", "6515553226");
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_NAME),
+ comp.GetTitleForMissingContactFields(p3));
+
+ // Generic error message if multiple fields missing.
+ AutofillProfile p4 =
+ CreateProfileWithContactInfo("", "homer@simpson.net", "");
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_MORE_INFORMATION),
+ comp.GetTitleForMissingContactFields(p4));
+}
+
TEST(PaymentRequestProfileUtilTest, GetStringForMissingShippingFields) {
MockPaymentOptionsProvider provider(kRequestPayerName | kRequestPayerPhone |
kRequestPayerEmail | kRequestShipping);
diff --git a/chromium/components/payments/content/payments_validators.cc b/chromium/components/payments/core/payments_validators.cc
index ed2b448c205..e4c21724f50 100644
--- a/chromium/components/payments/content/payments_validators.cc
+++ b/chromium/components/payments/core/payments_validators.cc
@@ -2,17 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/payments/content/payments_validators.h"
+#include "components/payments/core/payments_validators.h"
#include "third_party/re2/src/re2/re2.h"
#include "url/gurl.h"
namespace payments {
+namespace {
// We limit the maximum length of string to 2048 bytes for security reasons.
-static const int maximumStringLength = 2048;
+static const size_t maximumStringLength = 2048;
-bool PaymentsValidators::isValidCurrencyCodeFormat(
+} // namespace
+
+// static
+bool PaymentsValidators::IsValidCurrencyCodeFormat(
const std::string& code,
const std::string& system,
std::string* optional_error_message) {
@@ -24,7 +28,7 @@ bool PaymentsValidators::isValidCurrencyCodeFormat(
*optional_error_message =
"'" + code +
"' is not a valid ISO 4217 currency code, should "
- "be 3 upper case letters [A-Z]";
+ "be well-formed 3-letter alphabetic code.";
return false;
}
@@ -43,7 +47,8 @@ bool PaymentsValidators::isValidCurrencyCodeFormat(
return true;
}
-bool PaymentsValidators::isValidAmountFormat(
+// static
+bool PaymentsValidators::IsValidAmountFormat(
const std::string& amount,
std::string* optional_error_message) {
if (RE2::FullMatch(amount, "-?[0-9]+(\\.[0-9]+)?"))
@@ -55,7 +60,8 @@ bool PaymentsValidators::isValidAmountFormat(
return false;
}
-bool PaymentsValidators::isValidCountryCodeFormat(
+// static
+bool PaymentsValidators::IsValidCountryCodeFormat(
const std::string& code,
std::string* optional_error_message) {
if (RE2::FullMatch(code, "[A-Z]{2}"))
@@ -69,7 +75,8 @@ bool PaymentsValidators::isValidCountryCodeFormat(
return false;
}
-bool PaymentsValidators::isValidLanguageCodeFormat(
+// static
+bool PaymentsValidators::IsValidLanguageCodeFormat(
const std::string& code,
std::string* optional_error_message) {
if (RE2::FullMatch(code, "([a-z]{2,3})?"))
@@ -84,7 +91,8 @@ bool PaymentsValidators::isValidLanguageCodeFormat(
return false;
}
-bool PaymentsValidators::isValidScriptCodeFormat(
+// static
+bool PaymentsValidators::IsValidScriptCodeFormat(
const std::string& code,
std::string* optional_error_message) {
if (RE2::FullMatch(code, "([A-Z][a-z]{3})?"))
@@ -100,31 +108,16 @@ bool PaymentsValidators::isValidScriptCodeFormat(
return false;
}
-bool PaymentsValidators::isValidShippingAddress(
- const mojom::PaymentAddressPtr& address,
- std::string* optional_error_message) {
- if (!isValidCountryCodeFormat(address->country, optional_error_message))
- return false;
-
- if (!isValidLanguageCodeFormat(address->language_code,
- optional_error_message))
- return false;
-
- if (!isValidScriptCodeFormat(address->script_code, optional_error_message))
- return false;
-
- if (address->language_code.empty() && !address->script_code.empty()) {
- if (optional_error_message)
- *optional_error_message =
- "If language code is empty, then script code should also be empty";
-
- return false;
- }
-
- return true;
+// static
+void PaymentsValidators::SplitLanguageTag(const std::string& tag,
+ std::string* language_code,
+ std::string* script_code) {
+ RE2::FullMatch(tag, "^([a-z]{2})(-([A-Z][a-z]{3}))?(-[A-Za-z]+)*$",
+ language_code, (void*)nullptr, script_code);
}
-bool PaymentsValidators::isValidErrorMsgFormat(
+// static
+bool PaymentsValidators::IsValidErrorMsgFormat(
const std::string& error,
std::string* optional_error_message) {
if (error.length() <= maximumStringLength)
diff --git a/chromium/components/payments/content/payments_validators.h b/chromium/components/payments/core/payments_validators.h
index 331e185e2b9..4fed720d4e5 100644
--- a/chromium/components/payments/content/payments_validators.h
+++ b/chromium/components/payments/core/payments_validators.h
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_VALIDATORS_H_
-#define COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_VALIDATORS_H_
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENTS_VALIDATORS_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENTS_VALIDATORS_H_
#include <string>
#include "base/macros.h"
-#include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
namespace payments {
@@ -21,37 +20,34 @@ class PaymentsValidators {
// that currency is defined by [[ISO4217]], however any string of at most
// 2048 characters is considered valid in other currencySystem. Returns
// false if currency |code| is too long (greater than 2048).
- static bool isValidCurrencyCodeFormat(const std::string& code,
+ static bool IsValidCurrencyCodeFormat(const std::string& code,
const std::string& system,
std::string* optional_error_message);
// Returns true if |amount| is a valid currency code as defined in ISO 20022
// CurrencyAnd30Amount.
- static bool isValidAmountFormat(const std::string& amount,
+ static bool IsValidAmountFormat(const std::string& amount,
std::string* optional_error_message);
// Returns true if |code| is a valid ISO 3166 country code.
- static bool isValidCountryCodeFormat(const std::string& code,
+ static bool IsValidCountryCodeFormat(const std::string& code,
std::string* optional_error_message);
// Returns true if |code| is a valid ISO 639 language code.
- static bool isValidLanguageCodeFormat(const std::string& code,
+ static bool IsValidLanguageCodeFormat(const std::string& code,
std::string* optional_error_message);
// Returns true if |code| is a valid ISO 15924 script code.
- static bool isValidScriptCodeFormat(const std::string& code,
+ static bool IsValidScriptCodeFormat(const std::string& code,
std::string* optional_error_message);
- // Returns true if the payment address is valid:
- // - Has a valid region code
- // - Has a valid language code, if any.
- // - Has a valid script code, if any.
- // A script code should be present only if language code is present.
- static bool isValidShippingAddress(const mojom::PaymentAddressPtr& address,
- std::string* optional_error_message);
+ // Splits BCP-57 |tag| into |language_code| and |script_code|.
+ static void SplitLanguageTag(const std::string& tag,
+ std::string* language_code,
+ std::string* script_code);
// Returns false if |error| is too long (greater than 2048).
- static bool isValidErrorMsgFormat(const std::string& code,
+ static bool IsValidErrorMsgFormat(const std::string& code,
std::string* optional_error_message);
private:
@@ -60,4 +56,4 @@ class PaymentsValidators {
} // namespace payments
-#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_VALIDATORS_H_
+#endif // COMPONENTS_PAYMENTS_CORE_PAYMENTS_VALIDATORS_H_
diff --git a/chromium/components/payments/content/payments_validators_unittest.cc b/chromium/components/payments/core/payments_validators_unittest.cc
index 8214ce148dc..4e459b92878 100644
--- a/chromium/components/payments/content/payments_validators_unittest.cc
+++ b/chromium/components/payments/core/payments_validators_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/payments/content/payments_validators.h"
+#include "components/payments/core/payments_validators.h"
#include <ostream> // NOLINT
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,44 +11,46 @@ namespace payments {
namespace {
struct CurrencyCodeTestCase {
- CurrencyCodeTestCase(const char* code, const char* system, bool expectedValid)
- : code(code), system(system), expectedValid(expectedValid) {}
+ CurrencyCodeTestCase(const char* code,
+ const char* system,
+ bool expected_valid)
+ : code(code), system(system), expected_valid(expected_valid) {}
~CurrencyCodeTestCase() {}
const char* code;
const char* system;
- bool expectedValid;
+ bool expected_valid;
};
class PaymentsCurrencyValidatorTest
: public testing::TestWithParam<CurrencyCodeTestCase> {};
const char* longString2048() {
- static char longString[2049];
+ static char long_string[2049];
for (int i = 0; i < 2048; i++)
- longString[i] = 'a';
- longString[2048] = '\0';
- return longString;
+ long_string[i] = 'a';
+ long_string[2048] = '\0';
+ return long_string;
}
const char* longString2049() {
- static char longString[2050];
+ static char long_string[2050];
for (int i = 0; i < 2049; i++)
- longString[i] = 'a';
- longString[2049] = '\0';
- return longString;
+ long_string[i] = 'a';
+ long_string[2049] = '\0';
+ return long_string;
}
TEST_P(PaymentsCurrencyValidatorTest, IsValidCurrencyCodeFormat) {
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidCurrencyCodeFormat(
- GetParam().code, GetParam().system, &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidCurrencyCodeFormat(
+ std::string error_message;
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidCurrencyCodeFormat(
+ GetParam().code, GetParam().system, &error_message))
+ << error_message;
+ EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
+
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidCurrencyCodeFormat(
GetParam().code, GetParam().system, nullptr));
}
@@ -84,32 +86,32 @@ INSTANTIATE_TEST_CASE_P(
false)));
struct TestCase {
- TestCase(const char* input, bool expectedValid)
- : input(input), expectedValid(expectedValid) {}
+ TestCase(const char* input, bool expected_valid)
+ : input(input), expected_valid(expected_valid) {}
~TestCase() {}
const char* input;
- bool expectedValid;
+ bool expected_valid;
};
-std::ostream& operator<<(std::ostream& out, const TestCase& testCase) {
- out << "'" << testCase.input << "' is expected to be "
- << (testCase.expectedValid ? "valid" : "invalid");
+std::ostream& operator<<(std::ostream& out, const TestCase& test_case) {
+ out << "'" << test_case.input << "' is expected to be "
+ << (test_case.expected_valid ? "valid" : "invalid");
return out;
}
class PaymentsAmountValidatorTest : public testing::TestWithParam<TestCase> {};
TEST_P(PaymentsAmountValidatorTest, IsValidAmountFormat) {
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidAmountFormat(GetParam().input,
- &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidAmountFormat(GetParam().input,
+ std::string error_message;
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidAmountFormat(GetParam().input,
+ &error_message))
+ << error_message;
+ EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
+
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidAmountFormat(GetParam().input,
nullptr));
}
@@ -146,15 +148,15 @@ INSTANTIATE_TEST_CASE_P(
class PaymentsRegionValidatorTest : public testing::TestWithParam<TestCase> {};
TEST_P(PaymentsRegionValidatorTest, IsValidCountryCodeFormat) {
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidCountryCodeFormat(
- GetParam().input, &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidCountryCodeFormat(
+ std::string error_message;
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidCountryCodeFormat(
+ GetParam().input, &error_message))
+ << error_message;
+ EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
+
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidCountryCodeFormat(
GetParam().input, nullptr));
}
@@ -172,15 +174,15 @@ class PaymentsLanguageValidatorTest : public testing::TestWithParam<TestCase> {
};
TEST_P(PaymentsLanguageValidatorTest, IsValidLanguageCodeFormat) {
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidLanguageCodeFormat(
- GetParam().input, &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidLanguageCodeFormat(
+ std::string error_message;
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidLanguageCodeFormat(
+ GetParam().input, &error_message))
+ << error_message;
+ EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
+
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidLanguageCodeFormat(
GetParam().input, nullptr));
}
@@ -199,15 +201,15 @@ INSTANTIATE_TEST_CASE_P(LanguageCodes,
class PaymentsScriptValidatorTest : public testing::TestWithParam<TestCase> {};
TEST_P(PaymentsScriptValidatorTest, IsValidScriptCodeFormat) {
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidScriptCodeFormat(
- GetParam().input, &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidScriptCodeFormat(
+ std::string error_message;
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidScriptCodeFormat(
+ GetParam().input, &error_message))
+ << error_message;
+ EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
+
+ EXPECT_EQ(GetParam().expected_valid,
+ payments::PaymentsValidators::IsValidScriptCodeFormat(
GetParam().input, nullptr));
}
@@ -223,58 +225,52 @@ INSTANTIATE_TEST_CASE_P(ScriptCodes,
TestCase("latn", false),
TestCase("LATN", false)));
-struct ShippingAddressTestCase {
- ShippingAddressTestCase(const char* countryCode,
- const char* languageCode,
- const char* scriptCode,
- bool expectedValid)
- : countryCode(countryCode),
- languageCode(languageCode),
- scriptCode(scriptCode),
- expectedValid(expectedValid) {}
- ~ShippingAddressTestCase() {}
-
- const char* countryCode;
- const char* languageCode;
- const char* scriptCode;
- bool expectedValid;
+struct LanguageTagTestCase {
+ LanguageTagTestCase(const char* language_tag,
+ const char* expected_language_code,
+ const char* expected_script_code)
+ : language_tag(language_tag),
+ expected_language_code(expected_language_code),
+ expected_script_code(expected_script_code) {}
+ ~LanguageTagTestCase() {}
+
+ const char* language_tag;
+ const char* expected_language_code;
+ const char* expected_script_code;
};
-class PaymentsShippingAddressValidatorTest
- : public testing::TestWithParam<ShippingAddressTestCase> {};
-
-TEST_P(PaymentsShippingAddressValidatorTest, IsValidShippingAddress) {
- payments::mojom::PaymentAddressPtr address =
- payments::mojom::PaymentAddress::New();
- address->country = GetParam().countryCode;
- address->language_code = GetParam().languageCode;
- address->script_code = GetParam().scriptCode;
-
- std::string errorMessage;
- EXPECT_EQ(GetParam().expectedValid,
- payments::PaymentsValidators::isValidShippingAddress(address,
- &errorMessage))
- << errorMessage;
- EXPECT_EQ(GetParam().expectedValid, errorMessage.empty()) << errorMessage;
-
- EXPECT_EQ(
- GetParam().expectedValid,
- payments::PaymentsValidators::isValidShippingAddress(address, nullptr));
+class PaymentsLanguageTagSplitTest
+ : public testing::TestWithParam<LanguageTagTestCase> {};
+
+TEST_P(PaymentsLanguageTagSplitTest, Test) {
+ std::string language_code;
+ std::string script_code;
+
+ PaymentsValidators::SplitLanguageTag(GetParam().language_tag, &language_code,
+ &script_code);
+
+ EXPECT_EQ(GetParam().expected_language_code, language_code);
+ EXPECT_EQ(GetParam().expected_script_code, script_code);
+ EXPECT_TRUE(
+ PaymentsValidators::IsValidLanguageCodeFormat(language_code, nullptr));
+ EXPECT_TRUE(
+ PaymentsValidators::IsValidScriptCodeFormat(script_code, nullptr));
}
INSTANTIATE_TEST_CASE_P(
- ShippingAddresses,
- PaymentsShippingAddressValidatorTest,
- testing::Values(
- ShippingAddressTestCase("US", "en", "Latn", true),
- ShippingAddressTestCase("US", "en", "", true),
- ShippingAddressTestCase("US", "", "", true),
- // Invalid shipping addresses
- ShippingAddressTestCase("", "", "", false),
- ShippingAddressTestCase("InvalidCountryCode", "", "", false),
- ShippingAddressTestCase("US", "InvalidLanguageCode", "", false),
- ShippingAddressTestCase("US", "en", "InvalidScriptCode", false),
- ShippingAddressTestCase("US", "", "Latn", false)));
+ LanguageTags,
+ PaymentsLanguageTagSplitTest,
+ testing::Values(LanguageTagTestCase("", "", ""),
+ LanguageTagTestCase("ja", "ja", ""),
+ LanguageTagTestCase("ja-Latn", "ja", "Latn"),
+ LanguageTagTestCase("ja-Latn-JP", "ja", "Latn"),
+ LanguageTagTestCase("ja-JP", "ja", ""),
+ LanguageTagTestCase("Latn", "", ""),
+ LanguageTagTestCase("JP", "", ""),
+ LanguageTagTestCase("en", "en", ""),
+ LanguageTagTestCase("en-Latn", "en", "Latn"),
+ LanguageTagTestCase("en-Latn-US", "en", "Latn"),
+ LanguageTagTestCase("en-US", "en", "")));
} // namespace
} // namespace payments
diff --git a/chromium/components/payments/core/subkey_requester_unittest.cc b/chromium/components/payments/core/subkey_requester_unittest.cc
index 474700c76df..e6c29aecf9f 100644
--- a/chromium/components/payments/core/subkey_requester_unittest.cc
+++ b/chromium/components/payments/core/subkey_requester_unittest.cc
@@ -7,9 +7,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_scheduler.h"
+#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
@@ -100,7 +99,6 @@ class TestSubKeyRequester : public SubKeyRequester {
private:
bool should_load_rules_;
- base::test::ScopedTaskScheduler scoped_task_scheduler_;
DISALLOW_COPY_AND_ASSIGN(TestSubKeyRequester);
};
@@ -116,6 +114,7 @@ class SubKeyRequesterTest : public testing::Test {
~SubKeyRequesterTest() override {}
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
const std::unique_ptr<TestSubKeyRequester> requester_;
private:
@@ -170,7 +169,7 @@ TEST_F(SubKeyRequesterTest, StartRequest_RulesNotLoaded_WillNotLoad) {
requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb));
// Let the timeout execute.
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
// Since the rules are never loaded and the timeout is 0, the delegate should
// get notified that the subkeys could not be received.
diff --git a/chromium/components/payments/core/test_payment_request_delegate.cc b/chromium/components/payments/core/test_payment_request_delegate.cc
index 66794195362..d379997499d 100644
--- a/chromium/components/payments/core/test_payment_request_delegate.cc
+++ b/chromium/components/payments/core/test_payment_request_delegate.cc
@@ -12,7 +12,12 @@ TestPaymentRequestDelegate::TestPaymentRequestDelegate(
autofill::PersonalDataManager* personal_data_manager)
: personal_data_manager_(personal_data_manager),
locale_("en-US"),
- last_committed_url_("https://shop.com") {}
+ last_committed_url_("https://shop.com"),
+ request_context_(new TestURLRequestContextGetter(loop_.task_runner())),
+ payments_client_(request_context_.get(), &payments_cleint_delegate_),
+ full_card_request_(&autofill_client_,
+ &payments_client_,
+ personal_data_manager) {}
TestPaymentRequestDelegate::~TestPaymentRequestDelegate() {}
@@ -42,7 +47,7 @@ void TestPaymentRequestDelegate::DoFullCardRequest(
base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
result_delegate) {
if (instantaneous_full_card_request_result_) {
- result_delegate->OnFullCardRequestSucceeded(credit_card,
+ result_delegate->OnFullCardRequestSucceeded(full_card_request_, credit_card,
base::ASCIIToUTF16("123"));
return;
}
@@ -74,7 +79,7 @@ void TestPaymentRequestDelegate::DelayFullCardRequestCompletion() {
void TestPaymentRequestDelegate::CompleteFullCardRequest() {
DCHECK(instantaneous_full_card_request_result_ == false);
full_card_result_delegate_->OnFullCardRequestSucceeded(
- full_card_request_card_, base::ASCIIToUTF16("123"));
+ full_card_request_, full_card_request_card_, base::ASCIIToUTF16("123"));
}
std::string TestPaymentRequestDelegate::GetAuthenticatedEmail() const {
@@ -85,4 +90,40 @@ PrefService* TestPaymentRequestDelegate::GetPrefService() {
return nullptr;
}
+TestPaymentsClientDelegate::TestPaymentsClientDelegate() {}
+
+TestPaymentsClientDelegate::~TestPaymentsClientDelegate() {}
+
+void TestPaymentsClientDelegate::OnDidGetRealPan(
+ autofill::AutofillClient::PaymentsRpcResult result,
+ const std::string& real_pan) {}
+
+IdentityProvider* TestPaymentsClientDelegate::GetIdentityProvider() {
+ return nullptr;
+}
+
+void TestPaymentsClientDelegate::OnDidGetUploadDetails(
+ autofill::AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ std::unique_ptr<base::DictionaryValue> legal_message) {}
+
+void TestPaymentsClientDelegate::OnDidUploadCard(
+ autofill::AutofillClient::PaymentsRpcResult result,
+ const std::string& server_id) {}
+
+TestURLRequestContextGetter::TestURLRequestContextGetter(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(task_runner) {}
+
+TestURLRequestContextGetter::~TestURLRequestContextGetter() {}
+
+net::URLRequestContext* TestURLRequestContextGetter::GetURLRequestContext() {
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+TestURLRequestContextGetter::GetNetworkTaskRunner() const {
+ return task_runner_;
+}
+
} // namespace payments
diff --git a/chromium/components/payments/core/test_payment_request_delegate.h b/chromium/components/payments/core/test_payment_request_delegate.h
index e0697a7d326..7bca98f3b2a 100644
--- a/chromium/components/payments/core/test_payment_request_delegate.h
+++ b/chromium/components/payments/core/test_payment_request_delegate.h
@@ -7,11 +7,48 @@
#include <string>
+#include "base/message_loop/message_loop.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/payments/core/payment_request_delegate.h"
#include "components/payments/core/test_address_normalizer.h"
+#include "net/url_request/url_request_test_util.h"
namespace payments {
+class TestPaymentsClientDelegate
+ : public autofill::payments::PaymentsClientDelegate {
+ public:
+ TestPaymentsClientDelegate();
+ ~TestPaymentsClientDelegate();
+
+ private:
+ void OnDidGetRealPan(autofill::AutofillClient::PaymentsRpcResult result,
+ const std::string& real_pan) override;
+ IdentityProvider* GetIdentityProvider() override;
+ void OnDidGetUploadDetails(
+ autofill::AutofillClient::PaymentsRpcResult result,
+ const base::string16& context_token,
+ std::unique_ptr<base::DictionaryValue> legal_message) override;
+ void OnDidUploadCard(autofill::AutofillClient::PaymentsRpcResult result,
+ const std::string& server_id) override;
+};
+
+class TestURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ explicit TestURLRequestContextGetter(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ net::URLRequestContext* GetURLRequestContext() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override;
+
+ private:
+ ~TestURLRequestContextGetter() override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
class TestPaymentRequestDelegate : public PaymentRequestDelegate {
public:
TestPaymentRequestDelegate(
@@ -42,10 +79,16 @@ class TestPaymentRequestDelegate : public PaymentRequestDelegate {
void CompleteFullCardRequest();
private:
+ base::MessageLoop loop_;
+ TestPaymentsClientDelegate payments_cleint_delegate_;
autofill::PersonalDataManager* personal_data_manager_;
std::string locale_;
const GURL last_committed_url_;
TestAddressNormalizer address_normalizer_;
+ scoped_refptr<TestURLRequestContextGetter> request_context_;
+ autofill::TestAutofillClient autofill_client_;
+ autofill::payments::PaymentsClient payments_client_;
+ autofill::payments::FullCardRequest full_card_request_;
bool instantaneous_full_card_request_result_ = true;
autofill::CreditCard full_card_request_card_;
diff --git a/chromium/components/payments_strings.grdp b/chromium/components/payments_strings.grdp
index f5b95551f8e..cf64037cf9c 100644
--- a/chromium/components/payments_strings.grdp
+++ b/chromium/components/payments_strings.grdp
@@ -1,9 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <message name="IDS_PAYMENTS_TITLE" desc="Title of the dialog that presents a request for payment for some good or service [Desktop and iOS only].">
- Your Payment
- </message>
+ <!-- Titles and buttons which are title-cased on certain platforms. Make sure to keep the title-cased and sentence-cased variants in sync. -->
+
+
+ <!-- General titles, sentence-cased -->
+ <if expr="not use_titlecase">
+ <message name="IDS_PAYMENTS_TITLE" desc="Title of the dialog that presents a request for payment for some good or service. Sentence-cased.">
+ Your payment
+ </message>
+ <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment. Sentence-cased." formatter_data="android_java">
+ Payment method
+ </message>
+ <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted. Sentence-cased." formatter_data="android_java">
+ Contact info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number. Sentence-cased." formatter_data="android_java">
+ Add contact info
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number. Sentence-cased." formatter_data="android_java">
+ Edit contact info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CARD_LABEL" desc="The title of the dialog for user to add new payment card. Sentence-cased.">
+ Add card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_BILLING_ADDRESS" desc="The title of the dialog for user to add billing address to payment card. Sentence-cased." formatter_data="android_java">
+ Add billing address
+ </message>
+ <message name="IDS_PAYMENTS_ADD_NAME_ON_CARD" desc="The title of the dialog for user to add name on card to payment card. Sentence-cased." formatter_data="android_java">
+ Add name on card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number. Sentence-cased." formatter_data="android_java">
+ Add valid card number
+ </message>
+ <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title in the Android app title bar for user to add more information to payment card or shipping address or contact info. Sentence-cased." formatter_data="android_java">
+ Add more information
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card. Sentence-cased." formatter_data="android_java">
+ Edit card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination. Sentence-cased." formatter_data="android_java">
+ Add phone number
+ </message>
+ <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add the name in the shipping address. This name identifies the person that will receive the shipped package. Sentence-cased." formatter_data="android_java">
+ Add name
+ </message>
+ <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name. Sentence-cased." formatter_data="android_java">
+ Add valid address
+ </message>
+ <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer. Sentence-cased." formatter_data="android_java">
+ Add email
+ </message>
+ <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer. Sentence-cased." formatter_data="android_java">
+ Add name
+ </message>
+ <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill. Sentence-cased." formatter_data="android_java">
+ Order summary
+ </message>
+ <message name="IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME" desc="The name of the Payment Method section in the Payment Sheet of the Payment Request dialog. Sentence-cased.">
+ Payment
+ </message>
+ <message name="IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME" desc="The name of the Contact Info section in the Payment Sheet of the Payment Request dialog. Sentence-cased.">
+ Contact info
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is used for packages and things that are mailed. In American English, 'shipping' is differentiated from 'delivery'. 'Delivery' is used, for example, for food delivery. Sentence-cased." formatter_data="android_java">
+ Shipping
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages. Sentence-cased." formatter_data="android_java">
+ Shipping address
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages. Sentence-cased." formatter_data="android_java">
+ Shipping method
+ </message>
+ </if> <!-- not use_titlecase -->
+ <!-- General Titles, Title-Cased -->
+ <if expr="use_titlecase">
+ <message name="IDS_PAYMENTS_TITLE" desc="Title of the dialog that presents a request for payment for some good or service. Title-Cased.">
+ Your Payment
+ </message>
+ <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment. Title-Cased.">
+ Payment Method
+ </message>
+ <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted. Title-Cased.">
+ Contact Info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number. Title-Cased.">
+ Add Contact Info
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number. Title-Cased.">
+ Edit Contact Info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CARD_LABEL" desc="The title of the dialog for user to add new payment card. Title-Cased.">
+ Add Card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_BILLING_ADDRESS" desc="The title of the dialog for user to add billing address to payment card. Title-Cased.">
+ Add Billing Address
+ </message>
+ <message name="IDS_PAYMENTS_ADD_NAME_ON_CARD" desc="The title of the dialog for user to add name on card to payment card. Title-Cased.">
+ Add Name on Card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number. Title-Cased.">
+ Add Valid Card Number
+ </message>
+ <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title in the Android app title bar for user to add more information to payment card or shipping address or contact info. Title-Cased.">
+ Add More Information
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card. Title-Cased.">
+ Edit Card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination. Title-Cased.">
+ Add Phone Number
+ </message>
+ <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add the name in the shipping address. This name identifies the person that will receive the shipped package. Title-Cased.">
+ Add Name
+ </message>
+ <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name. Title-Cased.">
+ Add Valid Address
+ </message>
+ <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer. Title-Cased.">
+ Add Email
+ </message>
+ <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer. Title-Cased.">
+ Add Name
+ </message>
+ <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill. Title-Cased.">
+ Order Summary
+ </message>
+ <message name="IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME" desc="The name of the Payment Method section in the Payment Sheet of the Payment Request dialog. Title-Cased.">
+ Payment
+ </message>
+ <message name="IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME" desc="The name of the Contact Info section in the Payment Sheet of the Payment Request dialog. Title-Cased.">
+ Contact Info
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is used for packages and things that are mailed. In American English, 'shipping' is differentiated from 'delivery'. 'Delivery' is used, for example, for food delivery. Title-Cased.">
+ Shipping
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages. Title-Cased.">
+ Shipping Address
+ </message>
+ <message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages. Title-Cased.">
+ Shipping Method
+ </message>
+ </if> <!-- use_titlecase -->
+
+ <!-- Delivery titles, sentence-cased -->
+ <if expr="not use_titlecase">
+ <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery. Sentence-cased." formatter_data="android_java">
+ Delivery
+ </message>
+ <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. In English, 'delivery' is differentiated from 'shipping.' For example, 'delivery' might be used for meals or meal items or items that need to be immediately sent to a recipient. Sentence-cased." formatter_data="android_java">
+ Delivery address
+ </message>
+ <message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery. Sentence-cased." formatter_data="android_java">
+ Delivery method
+ </message>
+ </if> <!-- not use_titlecase -->
+ <!-- Delivery Titles, Title-Cased -->
+ <if expr="use_titlecase">
+ <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery. Title-Cased.">
+ Delivery
+ </message>
+ <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. In English, 'delivery' is differentiated from 'shipping.' For example, 'delivery' might be used for meals or meal items or items that need to be immediately sent to a recipient. Title-Cased.">
+ Delivery Address
+ </message>
+ <message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery. Title-Cased.">
+ Delivery Method
+ </message>
+ </if> <!-- use_titlecase -->
+
+ <!-- Pickup titles, sentence-cased -->
+ <if expr="not use_titlecase">
+ <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of information needed for a service to pick up items from a customer. For example, this could be the address for laundry pickup. 'Pickup' is a noun. Sentence-cased." formatter_data="android_java">
+ Pickup
+ </message>
+ <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where a service item should be picked up. For example, the pickup address is where a laundry service picks up a customer’s items to be laundered. 'Pickup' functions as an adjective. Sentence-cased." formatter_data="android_java">
+ Pickup address
+ </message>
+ <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their service item should be picked up. This item can be laundry to be cleaned, for example. 'Pickup' functions as an adjective. Sentence-cased." formatter_data="android_java">
+ Pickup method
+ </message>
+ </if> <!-- not use_titlecase -->
+ <!-- Pickup Titles, Title-Cased -->
+ <if expr="use_titlecase">
+ <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of information needed for a service to pick up items from a customer. For example, this could be the address for laundry pickup. 'Pickup' is a noun. Title-Cased.">
+ Pickup
+ </message>
+ <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where a service item should be picked up. For example, the pickup address is where a laundry service picks up a customer’s items to be laundered. 'Pickup' functions as an adjective. Title-Cased.">
+ Pickup Address
+ </message>
+ <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their service item should be picked up. This item can be laundry to be cleaned, for example. 'Pickup' functions as an adjective. Title-Cased.">
+ Pickup Method
+ </message>
+ </if> <!-- use_titlecase -->
+
+ <!-- Buttons, sentence-cased -->
+ <if expr="not use_titlecase">
+ <message name="IDS_PAYMENTS_EDIT_BUTTON" desc="The label for the button that lets the user edit their payment options. Sentence-cased." formatter_data="android_java">
+ Edit
+ </message>
+ <message name="IDS_PAYMENTS_PAY_BUTTON" desc="The label for the button that finishes the payment process. Sentence-cased." formatter_data="android_java">
+ Pay
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number. Sentence-cased." formatter_data="android_java">
+ Add contact info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CARD" desc="Text on a button that lets a user add new payment card. Sentence-cased." formatter_data="android_java">
+ Add card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_ADDRESS" desc="Text on a button that lets a user add new address. Sentence-cased." formatter_data="android_java">
+ Add address
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_ADDRESS" desc="Text on a button that lets a user edit an existing address. Sentence-cased." formatter_data="android_java">
+ Edit address
+ </message>
+ <message name="IDS_PAYMENTS_CANCEL_PAYMENT" desc="Label of the secondary button in payment request editors. Clicking that button closes the dialog and aborts the payment request completely. Sentence-cased.">
+ Cancel payment
+ </message>
+ </if> <!-- not use_titlecase -->
+ <!-- Buttons, Title-Cased -->
+ <if expr="use_titlecase">
+ <message name="IDS_PAYMENTS_EDIT_BUTTON" desc="The label for the button that lets the user edit their payment options. Title-Cased.">
+ Edit
+ </message>
+ <message name="IDS_PAYMENTS_PAY_BUTTON" desc="The label for the button that finishes the payment process. Title-Cased.">
+ Pay
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number. Title-Cased.">
+ Add Contact Info
+ </message>
+ <message name="IDS_PAYMENTS_ADD_CARD" desc="Text on a button that lets a user add new payment card. Title-Cased.">
+ Add Card
+ </message>
+ <message name="IDS_PAYMENTS_ADD_ADDRESS" desc="Text on a button that lets a user add new address. Title-Cased.">
+ Add Address
+ </message>
+ <message name="IDS_PAYMENTS_EDIT_ADDRESS" desc="Text on a button that lets a user edit an existing address. Title-Cased.">
+ Edit Address
+ </message>
+ <message name="IDS_PAYMENTS_CANCEL_PAYMENT" desc="Label of the secondary button in payment request editors. Clicking that button closes the dialog and aborts the payment request completely. Title-Cased.">
+ Cancel Payment
+ </message>
+ </if> <!-- use_titlecase -->
+
+
+ <!-- Fields, descriptive sentences, and other strings which are never title-cased. -->
+
+
+ <!-- Fields & Editors -->
<message name="IDS_PAYMENTS_NAME_FIELD_IN_CONTACT_DETAILS" desc="The label for text input field containing the full name of a person. [CHAR-LIMIT=32]" formatter_data="android_java">
Name
</message>
@@ -55,67 +298,13 @@
<message name="IDS_PAYMENTS_DEBIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's debit and prepaid cards that the merchant accepts." formatter_data="android_java">
Debit and prepaid cards are accepted.
</message>
- <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment." formatter_data="android_java">
- Payment method
- </message>
- <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted." formatter_data="android_java">
- Contact info
- </message>
- <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number." formatter_data="android_java">
- Add contact info
- </message>
- <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number." formatter_data="android_java">
- Edit contact info
- </message>
- <message name="IDS_PAYMENTS_ADD_CARD_LABEL" desc="The title of the dialog for user to add new payment card." formatter_data="android_java">
- Add card
- </message>
- <message name="IDS_PAYMENTS_ADD_BILLING_ADDRESS" desc="The title of the dialog for user to add billing address to payment card." formatter_data="android_java">
- Add billing address
- </message>
- <message name="IDS_PAYMENTS_ADD_NAME_ON_CARD" desc="The title of the dialog for user to add name on card to payment card." formatter_data="android_java">
- Add name on card
- </message>
- <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number." formatter_data="android_java">
- Add valid card number
- </message>
- <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title in the Android app title bar for user to add more information to payment card or shipping address or contact info." formatter_data="android_java">
- Add more information
- </message>
- <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card." formatter_data="android_java">
- Edit card
- </message>
<message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]" formatter_data="android_java">
Expires <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph>
</message>
- <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination." formatter_data="android_java">
- Add phone number
- </message>
- <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add the name in the shipping address. This name identifies the person that will receive the shipped package." formatter_data="android_java">
- Add name
- </message>
- <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name." formatter_data="android_java">
- Add valid address
- </message>
- <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer." formatter_data="android_java">
- Add email
- </message>
- <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer." formatter_data="android_java">
- Add name
- </message>
- <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill." formatter_data="android_java">
- Order summary
- </message>
- <message name="IDS_PAYMENTS_EDIT_BUTTON" desc="The label for the button that lets the user edit their payment options." formatter_data="android_java">
- Edit
- </message>
- <message name="IDS_PAYMENTS_PAY_BUTTON" desc="The label for the button that finishes the payment process." formatter_data="android_java">
- Pay
- </message>
<message name="IDS_PAYMENTS_LOADING_MESSAGE" desc="The text that informs the user that payment information is being loaded up." formatter_data="android_java">
Loading
</message>
- <message name="IDS_PAYMENTS_PROCESSING_MESSAGE" desc="The text that informs the user that payment is being processed." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_PROCESSING_MESSAGE" desc="The text that informs the user that payment is being processed.">
Processing
</message>
<message name="IDS_PAYMENTS_ERROR_MESSAGE_DIALOG_TITLE" desc="The title of the dialog that informs the user that there is error in verifying and charging the payment.">
@@ -124,18 +313,6 @@
<message name="IDS_PAYMENTS_ERROR_MESSAGE" desc="The text that informs the user that there is error in verifying and charging the payment." formatter_data="android_java">
There was an error processing your order. Please try again.
</message>
- <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number." formatter_data="android_java">
- Add contact info
- </message>
- <message name="IDS_PAYMENTS_ADD_CARD" desc="Text on a button that lets a user add new payment card." formatter_data="android_java">
- Add card
- </message>
- <message name="IDS_PAYMENTS_ADD_ADDRESS" desc="Text on a button that lets a user add new address." formatter_data="android_java">
- Add address
- </message>
- <message name="IDS_PAYMENTS_EDIT_ADDRESS" desc="Text on a button that lets a user edit an existing address." formatter_data="android_java">
- Edit address
- </message>
<message name="IDS_PAYMENTS_CHECKING_OPTION" desc="Text explaining that the option the user selected is being checked and verified." formatter_data="android_java">
Checking
</message>
@@ -158,11 +335,8 @@
<message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in." formatter_data="android_java">
Cards and addresses are from Chrome. You can manage them in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
</message>
- <message name="IDS_PAYMENTS_CANCEL_PAYMENT" desc="Label of the secondary button in payment request editors. Clicking that button closes the dialog and aborts the payment request completely">
- Cancel Payment
- </message>
- <!-- Credit Card form -->
+ <!-- iOS Credit Card form -->
<if expr="is_ios">
<message name="IDS_PAYMENTS_CARD_NUMBER" desc="Title of the field representing the number (PAN) on a credit card.">
Card Number
@@ -200,7 +374,7 @@
<message name="IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE" desc="The text that informs the user that '*' character indicates an input field that is required. The '*' character should not be changed." formatter_data="android_java">
* Field is required
</message>
- <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required. “Required” is an adjective." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required. 'Required' is an adjective." formatter_data="android_java">
Required field
</message>
<message name="IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the phone number they have entered is not valid." formatter_data="android_java">
@@ -218,10 +392,10 @@
<message name="IDS_PAYMENTS_BILLING_ADDRESS_REQUIRED" desc="The label to indicate billing address is required for payment card." formatter_data="android_java">
Billing address required
</message>
- <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate the cardholder name (the name of the owner or “holder” of the credit card) must be entered." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate the cardholder name (the name of the owner or 'holder' of the credit card) must be entered." formatter_data="android_java">
Cardholder name required
</message>
- <message name="IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED" desc="The label to indicate the billing address of the credit card must be entered." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED" desc="The label to indicate the billing address of the credit card must be entered.">
Card billing address required
</message>
<message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info." formatter_data="android_java">
@@ -243,16 +417,10 @@
Name required
</message>
- <!-- Payment Request (Sections mode) -->
- <message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_NAME" desc="The name of the Order Summary section in the Payment Sheet of the Payment Request dialog.">
- Order summary
- </message>
+ <!-- Order Summary Data Formatting -->
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_TOTAL_FORMAT" desc="The format specifier of the Total label in the Order Summary section of the Payment Sheet of the Payment Request dialog.">
<ph name="TOTAL_LABEL">$1<ex>Total</ex></ph> <ph name="CURRENCY_CODE">$2<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$3<ex>$ 12.34</ex></ph>
</message>
- <message name="IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME" desc="The name of the Payment Method section in the Payment Sheet of the Payment Request dialog.">
- Payment
- </message>
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT" desc="The format specifier of the Total label in the Order Summary Sheet of the Payment Request dialog.">
<ph name="CURRENCY_CODE">$1<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$2<ex>$ 12.34</ex></ph>
</message>
@@ -261,79 +429,47 @@
=1 {<ph name="ITEM_COUNT">#<ex>1</ex></ph> more item}
other {<ph name="ITEM_COUNT">#<ex>2</ex></ph> more items}}
</message>
- <message name="IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME" desc="The name of the Shipping Address section in the Payment Sheet of the Payment Request dialog.">
- Shipping address
- </message>
- <message name="IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME" desc="The name of the Contact Info section in the Payment Sheet of the Payment Request dialog.">
- Contact info
- </message>
<message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_MULTIPLE_CURRENCY_INDICATOR" desc="The label that indicates that there are multiple currencies among the display items">
Multiple
</message>
- <!-- Shipping address in web payments API -->
- <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is used for packages and things that are mailed. In American English, “shipping” is differentiated from “delivery”. “Delivery” is used, for example, for food delivery." formatter_data="android_java">
- Shipping
- </message>
- <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages." formatter_data="android_java">
- Shipping address
- </message>
- <message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages." formatter_data="android_java">
- Shipping method
- </message>
+ <!-- Shipping address descriptive strings -->
<message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods. Shipping is typically used for packages." formatter_data="android_java">
To see shipping methods and requirements, select an address
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. “Ship” is typically used for packages and items that are sent through the mail. In American English, we differentiate “ship” from “deliver." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. 'Ship' is typically used for packages and items that are sent through the mail. In American English, we differentiate 'ship' from 'deliver." formatter_data="android_java">
Can’t ship to this address. Select a different address.
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION" desc="Text implying that a user needs to pick a different shipping option, because the currently selected option is not supported. “Ship” is typically used for packages and items that are sent through the mail. In American English, we differentiate “ship” from deliver." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION" desc="Text implying that a user needs to pick a different shipping option, because the currently selected option is not supported. 'Ship' is typically used for packages and items that are sent through the mail. In American English, we differentiate 'ship' from deliver.">
This shipping method isn’t available. Try a different method.
</message>
- <!-- Delivery address in web payments API -->
- <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- Delivery
- </message>
- <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. In English, “delivery” is differentiated from “shipping.” For example, “delivery” might be used for meals or meal items or items that need to be immediately sent to a recipient." formatter_data="android_java">
- Delivery address
- </message>
- <message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
- Delivery method
- </message>
+ <!-- Delivery address descriptive strings -->
<message name="IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS" desc="Text implying that a user needs to pick a delivery address to see the delivery methods. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
To see delivery methods and requirements, select an address
</message>
<message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS" desc="Text implying that a user needs to pick a different delivery address, because the currently selected address is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
Can’t deliver to this address. Select a different address.
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_OPTION" desc="Text implying that a user needs to pick a different delivery option, because the currently selected option is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_OPTION" desc="Text implying that a user needs to pick a different delivery option, because the currently selected option is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery.">
This delivery method isn’t available. Try a different method.
</message>
- <!-- Pickup address in web payments API -->
- <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of information needed for a service to pick up items from a customer. For example, this could be the address for laundry pickup. “Pickup” is a noun." formatter_data="android_java">
- Pickup
- </message>
- <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where a service item should be picked up. For example, the pickup address is where a laundry service picks up a customer’s items to be laundered. “Pickup” functions as an adjective." formatter_data="android_java">
- Pickup address
- </message>
- <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their service item should be picked up. This item can be laundry to be cleaned, for example. “Pickup” functions as an adjective." formatter_data="android_java">
- Pickup method
- </message>
- <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup. “Pickup” functions as an adjective." formatter_data="android_java">
+ <!-- Pickup address descriptive strings-->
+ <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup. 'Pickup' functions as an adjective." formatter_data="android_java">
To see pickup methods and requirements, select an address
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the service can’t pick up items from that address. This address can be used, for example, for laundry pickup. Note that here, “pick up” is a verb." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the service can’t pick up items from that address. This address can be used, for example, for laundry pickup. Note that here, 'pick up' is a verb." formatter_data="android_java">
Can’t pick up from this address. Select a different address.
</message>
- <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_OPTION" desc="Text implying that a user needs to choose a different pickup option, because the currently selected option is not supported. This option can be used, for example, for laundry pickup." formatter_data="android_java">
+ <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_OPTION" desc="Text implying that a user needs to choose a different pickup option, because the currently selected option is not supported. This option can be used, for example, for laundry pickup.">
This pickup method isn’t available. Try a different method.
</message>
+
+ <!-- Payment Apps -->
<message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start." formatter_data="android_java">
Can’t open payment app
</message>
-
<message name="IDS_UTILITY_PROCESS_PAYMENT_MANIFEST_PARSER_NAME" desc="The name of the utility process used for parsing payment manifest files.">
Payment Manifest Parser
</message>
@@ -351,7 +487,7 @@
=1 {<ph name="PAYMENT_METHOD_PREVIEW">{1}<ex>VISA ....1234</ex></ph> and <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS">{2}<ex>1</ex></ph> more}
other {<ph name="PAYMENT_METHOD_PREVIEW">{1}<ex>VISA ....1234</ex></ph> and <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS">{2}<ex>2</ex></ph> more}}
</message>
- <message name="IDS_PAYMENT_REQUEST_SHIPPING_ADDRESSES_PREVIEW" desc="This is a snippet of a shipping address a user has saved to Chrome, plus an indication of the number of additional shipping addresses the user has saved. Its function is to show the user has shipping addresses that can be used to complete a purchase, and thus doesn't have to type the entire address. [ICU Syntax]" formatter_data="android_java">
+ <message name="IDS_PAYMENT_REQUEST_SHIPPING_ADDRESSES_PREVIEW" desc="This is a snippet of a shipping address a user has saved to Chrome, plus an indication of the number of additional shipping addresses the user has saved. Its function is to show the user has shipping addresses that can be used to complete a purchase, and thus doesn't have to type the entire address. [ICU Syntax]">
{SHIPPING_ADDRESS, plural,
=0 {<ph name="SHIPPING_ADDRESS_PREVIEW">{1}<ex>Jerry, 1253 Mcgill college</ex></ph>}
=1 {<ph name="SHIPPING_ADDRESS_PREVIEW">{1}<ex>Jerry, 1253 Mcgill college</ex></ph> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES">{2}<ex>1</ex></ph> more}
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.cc b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
index 25066d26952..761d8d21cc9 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.cc
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
@@ -36,7 +36,8 @@ PDFWebContentsHelper::PDFWebContentsHelper(
pdf_service_bindings_(web_contents, this),
client_(std::move(client)),
touch_selection_controller_client_manager_(nullptr),
- has_selection_(false) {}
+ has_selection_(false),
+ remote_pdf_client_(nullptr) {}
PDFWebContentsHelper::~PDFWebContentsHelper() {
if (!touch_selection_controller_client_manager_)
@@ -46,9 +47,13 @@ PDFWebContentsHelper::~PDFWebContentsHelper() {
touch_selection_controller_client_manager_->RemoveObserver(this);
}
-void PDFWebContentsHelper::SelectionChanged(const gfx::Point& left,
+void PDFWebContentsHelper::SetListener(mojom::PdfListenerPtr listener) {
+ remote_pdf_client_ = std::move(listener);
+}
+
+void PDFWebContentsHelper::SelectionChanged(const gfx::PointF& left,
int32_t left_height,
- const gfx::Point& right,
+ const gfx::PointF& right,
int32_t right_height) {
if (!touch_selection_controller_client_manager_)
InitTouchSelectionClientManager();
@@ -56,11 +61,11 @@ void PDFWebContentsHelper::SelectionChanged(const gfx::Point& left,
if (touch_selection_controller_client_manager_) {
gfx::SelectionBound start;
gfx::SelectionBound end;
- start.SetEdgeTop(gfx::PointF(left.x(), left.y()));
+ start.SetEdgeTop(left);
start.SetEdgeBottom(gfx::PointF(left.x(), left.y() + left_height));
start.set_type(gfx::SelectionBound::LEFT);
start.set_visible(true);
- end.SetEdgeTop(gfx::PointF(right.x(), right.y()));
+ end.SetEdgeTop(right);
end.SetEdgeBottom(gfx::PointF(right.x(), right.y() + right_height));
end.set_type(gfx::SelectionBound::RIGHT);
end.set_visible(true);
@@ -77,16 +82,22 @@ bool PDFWebContentsHelper::SupportsAnimation() const {
}
void PDFWebContentsHelper::MoveCaret(const gfx::PointF& position) {
- // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement.
+ if (!remote_pdf_client_)
+ return;
+ remote_pdf_client_->SetCaretPosition(position);
}
void PDFWebContentsHelper::MoveRangeSelectionExtent(const gfx::PointF& extent) {
- // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement.
+ if (!remote_pdf_client_)
+ return;
+ remote_pdf_client_->MoveRangeSelectionExtent(extent);
}
void PDFWebContentsHelper::SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent) {
- // TODO(wjmaclean, dsinclair): Implement connection to PDFium to implement.
+ if (!remote_pdf_client_)
+ return;
+ remote_pdf_client_->SetSelectionBounds(base, extent);
}
void PDFWebContentsHelper::OnSelectionEvent(ui::SelectionEventType event) {}
@@ -112,16 +123,20 @@ bool PDFWebContentsHelper::IsCommandIdEnabled(int command_id) const {
switch (command_id) {
case IDS_APP_COPY:
return readable && has_selection_;
- // TODO(wjmaclean): add logic for copy/paste as the information required
+ // TODO(wjmaclean): add logic for cut/paste as the information required
// from PDFium becomes available.
}
return false;
}
void PDFWebContentsHelper::ExecuteCommand(int command_id, int event_flags) {
- // TODO(wjmaclean, dsinclair): Need to communicate to PDFium to get it to copy
- // the selection onto the clipboard (and eventually accept cut/paste commands
- // too).
+ // TODO(wjmaclean, dsinclair): Need to communicate to PDFium to accept
+ // cut/paste commands.
+ switch (command_id) {
+ case IDS_APP_COPY:
+ web_contents()->Copy();
+ break;
+ }
}
void PDFWebContentsHelper::RunContextMenu() {
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.h b/chromium/components/pdf/browser/pdf_web_contents_helper.h
index e91790f39b2..2937f0ca5d7 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.h
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.h
@@ -42,11 +42,6 @@ class PDFWebContentsHelper
content::WebContents* contents,
std::unique_ptr<PDFWebContentsHelperClient> client);
- void SelectionChanged(const gfx::Point& left,
- int32_t left_height,
- const gfx::Point& right,
- int32_t right_height);
-
// ui::TouchSelectionControllerClient :
bool SupportsAnimation() const override;
void SetNeedsAnimate() override {}
@@ -73,15 +68,21 @@ class PDFWebContentsHelper
void InitTouchSelectionClientManager();
// mojom::PdfService:
+ void SetListener(mojom::PdfListenerPtr listener) override;
void HasUnsupportedFeature() override;
void SaveUrlAs(const GURL& url, const content::Referrer& referrer) override;
void UpdateContentRestrictions(int32_t content_restrictions) override;
+ void SelectionChanged(const gfx::PointF& left,
+ int32_t left_height,
+ const gfx::PointF& right,
+ int32_t right_height) override;
content::WebContentsFrameBindingSet<mojom::PdfService> pdf_service_bindings_;
std::unique_ptr<PDFWebContentsHelperClient> client_;
content::TouchSelectionControllerClientManager*
touch_selection_controller_client_manager_;
bool has_selection_;
+ mojom::PdfListenerPtr remote_pdf_client_;
DISALLOW_COPY_AND_ASSIGN(PDFWebContentsHelper);
};
diff --git a/chromium/components/pdf/common/BUILD.gn b/chromium/components/pdf/common/BUILD.gn
index c0aa0b38073..370b7a98a2b 100644
--- a/chromium/components/pdf/common/BUILD.gn
+++ b/chromium/components/pdf/common/BUILD.gn
@@ -20,4 +20,6 @@ mojom("interfaces") {
overridden_deps_blink = [ "//third_party/WebKit/public:mojo_bindings" ]
component_deps_blink = [ "//third_party/WebKit/Source/platform" ]
+
+ cpp_only = true
}
diff --git a/chromium/components/pdf/common/pdf.mojom b/chromium/components/pdf/common/pdf.mojom
index 0aaed7ba38f..f6e44274ff6 100644
--- a/chromium/components/pdf/common/pdf.mojom
+++ b/chromium/components/pdf/common/pdf.mojom
@@ -5,9 +5,24 @@
module pdf.mojom;
import "third_party/WebKit/public/platform/referrer.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
import "url/mojo/url.mojom";
+interface PdfListener {
+ // Sets the current caret position.
+ SetCaretPosition(gfx.mojom.PointF position);
+
+ // Move the end of the range selection to |extent|.
+ MoveRangeSelectionExtent(gfx.mojom.PointF extent);
+
+ // Sets the selection to be between |base| and |extent|. The |extent| will
+ // be moved if the selection is modified.
+ SetSelectionBounds(gfx.mojom.PointF base, gfx.mojom.PointF extent);
+};
+
interface PdfService {
+ SetListener(PdfListener client);
+
// Updates the content restrictions, i.e. to disable print/copy.
UpdateContentRestrictions(int32 restrictions);
@@ -16,4 +31,9 @@ interface PdfService {
// Brings up SaveAs... dialog to save specified URL.
SaveUrlAs(url.mojom.Url url, blink.mojom.Referrer referrer);
+
+ // Notifies the embedder of the top-left and bottom-right coordinates of the
+ // current selection.
+ SelectionChanged(gfx.mojom.PointF left, int32 left_height,
+ gfx.mojom.PointF right, int32 right_height);
};
diff --git a/chromium/components/pdf/renderer/DEPS b/chromium/components/pdf/renderer/DEPS
index 7113287c54f..94012530304 100644
--- a/chromium/components/pdf/renderer/DEPS
+++ b/chromium/components/pdf/renderer/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+components/strings/grit/components_strings.h",
"+gin",
+ "+mojo/public/cpp/bindings",
"+skia/ext",
"+ui/accessibility",
"+ui/gfx",
diff --git a/chromium/components/pdf/renderer/OWNERS b/chromium/components/pdf/renderer/OWNERS
index 502f38cbabe..70fce223441 100644
--- a/chromium/components/pdf/renderer/OWNERS
+++ b/chromium/components/pdf/renderer/OWNERS
@@ -1,5 +1,5 @@
per-file pdf_accessibility_tree.*=dmazzoni@chromium.org
-per-file ppb_pdf_impl.*=bbudge@chromium.org
-per-file ppb_pdf_impl.*=raymes@chromium.org
+per-file pepper_pdf_host.*=bbudge@chromium.org
+per-file pepper_pdf_host.*=raymes@chromium.org
# COMPONENT: Internals>Plugins>PDF
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.cc b/chromium/components/pdf/renderer/pepper_pdf_host.cc
index 158c3b672e8..ee9b3f5a4cf 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.cc
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.cc
@@ -43,7 +43,16 @@ PepperPDFHost::PepperPDFHost(content::RendererPpapiHost* host,
PP_Instance instance,
PP_Resource resource)
: ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
- host_(host) {}
+ host_(host),
+ binding_(this) {
+ mojom::PdfService* service = GetRemotePdfService();
+ if (!service)
+ return;
+
+ mojom::PdfListenerPtr listener;
+ binding_.Bind(mojo::MakeRequest(&listener));
+ service->SetListener(std::move(listener));
+}
PepperPDFHost::~PepperPDFHost() {}
@@ -91,6 +100,8 @@ int32_t PepperPDFHost::OnResourceMessageReceived(
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_PDF_SetAccessibilityPageInfo,
OnHostMsgSetAccessibilityPageInfo)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SelectionChanged,
+ OnHostMsgSelectionChanged)
PPAPI_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
@@ -226,6 +237,21 @@ int32_t PepperPDFHost::OnHostMsgSetAccessibilityPageInfo(
return PP_OK;
}
+int32_t PepperPDFHost::OnHostMsgSelectionChanged(
+ ppapi::host::HostMessageContext* context,
+ const PP_FloatPoint& left,
+ int32_t left_height,
+ const PP_FloatPoint& right,
+ int32_t right_height) {
+ mojom::PdfService* service = GetRemotePdfService();
+ if (!service)
+ return PP_ERROR_FAILED;
+
+ service->SelectionChanged(gfx::PointF(left.x, left.y), left_height,
+ gfx::PointF(right.x, right.y), right_height);
+ return PP_OK;
+}
+
void PepperPDFHost::CreatePdfAccessibilityTreeIfNeeded() {
if (!pdf_accessibility_tree_) {
pdf_accessibility_tree_ =
@@ -251,4 +277,26 @@ mojom::PdfService* PepperPDFHost::GetRemotePdfService() {
return remote_pdf_service_.get();
}
+void PepperPDFHost::SetCaretPosition(const gfx::PointF& position) {
+ content::PepperPluginInstance* instance =
+ host_->GetPluginInstance(pp_instance());
+ if (instance)
+ instance->SetCaretPosition(position);
+}
+
+void PepperPDFHost::MoveRangeSelectionExtent(const gfx::PointF& extent) {
+ content::PepperPluginInstance* instance =
+ host_->GetPluginInstance(pp_instance());
+ if (instance)
+ instance->MoveRangeSelectionExtent(extent);
+}
+
+void PepperPDFHost::SetSelectionBounds(const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ content::PepperPluginInstance* instance =
+ host_->GetPluginInstance(pp_instance());
+ if (instance)
+ instance->SetSelectionBounds(base, extent);
+}
+
} // namespace pdf
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.h b/chromium/components/pdf/renderer/pepper_pdf_host.h
index b5de8c27bdb..7943b6061e0 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.h
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.h
@@ -16,6 +16,7 @@
#include "base/strings/string16.h"
#include "components/pdf/common/pdf.mojom.h"
#include "ipc/ipc_platform_file.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "ppapi/c/ppb_image_data.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/host/resource_host.h"
@@ -36,7 +37,8 @@ namespace pdf {
class PdfAccessibilityTree;
-class PepperPDFHost : public ppapi::host::ResourceHost {
+class PepperPDFHost : public ppapi::host::ResourceHost,
+ public mojom::PdfListener {
public:
class PrintClient {
public:
@@ -71,6 +73,12 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) override;
+ // mojom::PdfListener
+ void SetCaretPosition(const gfx::PointF& position) override;
+ void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+ void SetSelectionBounds(const gfx::PointF& base,
+ const gfx::PointF& extent) override;
+
private:
int32_t OnHostMsgDidStartLoading(ppapi::host::HostMessageContext* context);
int32_t OnHostMsgDidStopLoading(ppapi::host::HostMessageContext* context);
@@ -99,6 +107,11 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
const PP_PrivateAccessibilityPageInfo& page_info,
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars);
+ int32_t OnHostMsgSelectionChanged(ppapi::host::HostMessageContext* context,
+ const PP_FloatPoint& left,
+ int32_t left_height,
+ const PP_FloatPoint& right,
+ int32_t right_height);
void CreatePdfAccessibilityTreeIfNeeded();
@@ -109,6 +122,7 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
std::unique_ptr<PdfAccessibilityTree> pdf_accessibility_tree_;
content::RendererPpapiHost* const host_;
mojom::PdfServiceAssociatedPtr remote_pdf_service_;
+ mojo::Binding<mojom::PdfListener> binding_;
DISALLOW_COPY_AND_ASSIGN(PepperPDFHost);
};
diff --git a/chromium/components/plugins/renderer/DEPS b/chromium/components/plugins/renderer/DEPS
index 2547bea5679..8718dee429c 100644
--- a/chromium/components/plugins/renderer/DEPS
+++ b/chromium/components/plugins/renderer/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+content/public/renderer",
"+content/public/common",
"+content/public/test",
+ "+services/service_manager/public/cpp",
"+third_party/WebKit/public",
"+third_party/re2",
"+skia",
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
index c5b3b05876d..e05a23a1542 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -206,20 +206,17 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
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(GetPluginParams().url);
RenderFrame::PeripheralContentStatus status =
render_frame()->GetPeripheralContentStatus(
- render_frame()->GetWebFrame()->Top()->GetSecurityOrigin(),
- content_origin, gfx::Size(width, height),
+ main_frame_origin, content_origin, gfx::Size(width, height),
heuristic_run_before_ ? RenderFrame::DONT_RECORD_DECISION
: RenderFrame::RECORD_DECISION);
- bool plugin_is_tiny_and_blocked =
- is_blocked_for_tinyness_ && status == RenderFrame::CONTENT_STATUS_TINY;
-
// Early exit for plugins that we've discovered to be essential.
- if (!plugin_is_tiny_and_blocked &&
- status != RenderFrame::CONTENT_STATUS_PERIPHERAL &&
+ if (status != RenderFrame::CONTENT_STATUS_PERIPHERAL &&
status != RenderFrame::CONTENT_STATUS_TINY) {
MarkPluginEssential(
heuristic_run_before_
@@ -233,16 +230,16 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
return;
}
- heuristic_run_before_ = true;
- if (is_blocked_for_tinyness_) {
- if (plugin_is_tiny_and_blocked) {
- OnBlockedTinyContent();
- } else {
- is_blocked_for_tinyness_ = false;
- if (!LoadingBlocked()) {
- LoadPlugin();
- }
+ 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();
}
}
@@ -255,6 +252,8 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
plugin()->main_frame()->ExecuteScript(
blink::WebScriptSource(blink::WebString::FromUTF8(script)));
}
+
+ heuristic_run_before_ = true;
}
void LoadablePluginPlaceholder::WasShown() {
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
index f4a05997471..551b8b49826 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
@@ -101,8 +101,10 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
// Plugin creation is embedder-specific.
virtual blink::WebPlugin* CreatePlugin() = 0;
- // Embedder-specific behavior.
- virtual void OnBlockedTinyContent() = 0;
+ // Embedder-specific behavior. This will only be called once per placeholder.
+ virtual void OnBlockedContent(
+ content::RenderFrame::PeripheralContentStatus status,
+ bool is_same_origin) = 0;
content::WebPluginInfo plugin_info_;
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index 6b580b16f05..53ca290bce6 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -252,9 +252,9 @@ void WebViewPlugin::DidFailLoading(const WebURLError& error) {
error_.reset(new WebURLError(error));
}
-WebViewPlugin::WebViewHelper::WebViewHelper(
- WebViewPlugin* plugin,
- const WebPreferences& preferences) : plugin_(plugin) {
+WebViewPlugin::WebViewHelper::WebViewHelper(WebViewPlugin* plugin,
+ const WebPreferences& preferences)
+ : plugin_(plugin) {
web_view_ = WebView::Create(this, blink::kWebPageVisibilityStateVisible);
// ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
// consistent view of our preferences.
@@ -262,6 +262,9 @@ WebViewPlugin::WebViewHelper::WebViewHelper(
WebLocalFrame* web_frame =
WebLocalFrame::CreateMainFrame(web_view_, this, nullptr, nullptr);
WebFrameWidget::Create(this, web_frame);
+ service_manager::mojom::InterfaceProviderPtr provider;
+ mojo::MakeRequest(&provider);
+ interface_provider_.Bind(std::move(provider));
}
WebViewPlugin::WebViewHelper::~WebViewHelper() {
@@ -357,12 +360,14 @@ void WebViewPlugin::WebViewHelper::DidClearWindowObject() {
plugin_->delegate_->GetV8Handle(isolate));
}
-void WebViewPlugin::WebViewHelper::FrameDetached(blink::WebLocalFrame* frame,
- DetachType type) {
- if (frame->FrameWidget())
- frame->FrameWidget()->Close();
+void WebViewPlugin::WebViewHelper::FrameDetached(DetachType type) {
+ main_frame()->FrameWidget()->Close();
+ main_frame()->Close();
+}
- frame->Close();
+service_manager::InterfaceProvider*
+WebViewPlugin::WebViewHelper::GetInterfaceProvider() {
+ return &interface_provider_;
}
void WebViewPlugin::OnZoomLevelChanged() {
diff --git a/chromium/components/plugins/renderer/webview_plugin.h b/chromium/components/plugins/renderer/webview_plugin.h
index 240dfe5e059..b6bac6f327a 100644
--- a/chromium/components/plugins/renderer/webview_plugin.h
+++ b/chromium/components/plugins/renderer/webview_plugin.h
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner_helpers.h"
#include "content/public/renderer/render_view_observer.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
@@ -181,10 +182,12 @@ class WebViewPlugin : public blink::WebPlugin,
// WebFrameClient methods:
void DidClearWindowObject() override;
- void FrameDetached(blink::WebLocalFrame*, DetachType) override;
+ void FrameDetached(DetachType) override;
+ service_manager::InterfaceProvider* GetInterfaceProvider() override;
private:
WebViewPlugin* plugin_;
+ service_manager::InterfaceProvider interface_provider_;
// 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 3e00ac2bf7b..8fc77e135f6 100644
--- a/chromium/components/policy/BUILD.gn
+++ b/chromium/components/policy/BUILD.gn
@@ -233,7 +233,12 @@ component("cloud_policy_proto_generated_compile") {
]
}
proto_library("cloud_policy_proto_generated_compile_proto") {
- visibility = [ ":cloud_policy_proto_generated_compile" ]
+ visibility = [
+ ":cloud_policy_proto_generated_compile",
+ ":chrome_settings_proto_generated_compile",
+ ":chrome_settings_proto_generated_compile_proto",
+ ":chrome_settings_proto_generated_compile_proto_gen",
+ ]
sources = [
cloud_policy_proto_path,
]
@@ -250,16 +255,29 @@ proto_library("cloud_policy_proto_generated_compile_proto") {
}
# This target builds the "full" protobuf, used for tests only.
-proto_library("chrome_settings_proto") {
+component("chrome_settings_proto_generated_compile") {
+ testonly = true
+ public_deps = [
+ ":chrome_settings_proto_generated_compile_proto",
+ ":cloud_policy_proto_generated_compile_proto",
+ ]
+}
+proto_library("chrome_settings_proto_generated_compile_proto") {
testonly = true
+ visibility = [ ":chrome_settings_proto_generated_compile" ]
sources = [
chrome_settings_proto_path,
]
+
proto_out_dir = "components/policy/proto"
+ cc_generator_options = "dllexport_decl=POLICY_PROTO_EXPORT:"
+ cc_include = "components/policy/proto/policy_proto_export.h"
+ component_build_force_source_set = true
+ defines = [ "POLICY_PROTO_COMPILATION" ]
deps = [
":cloud_policy_code_generate",
- ":cloud_policy_proto_generated_compile",
+ ":cloud_policy_proto_generated_compile_proto",
]
}
@@ -371,8 +389,9 @@ if (gen_policy_templates_android && is_android) {
}
create_bundle("chrome_manifest_bundle") {
- bundle_root_dir = "$root_out_dir/$chrome_mac_bundle_id.manifest/Contents"
- bundle_resources_dir = "$bundle_root_dir/Resources"
+ bundle_root_dir = "$root_out_dir/$chrome_mac_bundle_id.manifest"
+ bundle_contents_dir = "$bundle_root_dir/Contents"
+ bundle_resources_dir = "$bundle_contents_dir/Resources"
deps = [
":manifest_bundle_data",
diff --git a/chromium/components/policy/core/common/BUILD.gn b/chromium/components/policy/core/common/BUILD.gn
index d5093840495..4255ff237ec 100644
--- a/chromium/components/policy/core/common/BUILD.gn
+++ b/chromium/components/policy/core/common/BUILD.gn
@@ -259,6 +259,7 @@ static_library("test_support") {
public_deps = [
":common",
"//base",
+ "//base/test:test_support",
# Explicitly link in the generated policy target into the test support
# so it will be linked to dependent targets. Otherwise in component
diff --git a/chromium/components/policy_strings.grdp b/chromium/components/policy_strings.grdp
index 4b96b8140df..2d0599b6dad 100644
--- a/chromium/components/policy_strings.grdp
+++ b/chromium/components/policy_strings.grdp
@@ -234,6 +234,9 @@
<message name="IDS_POLICY_RELOAD_POLICIES" desc="Label for the button that reloads policies.">
Reload policies
</message>
+ <message name="IDS_EXPORT_POLICIES_JSON" desc="Label for the button that exports policies in JSON format.">
+ Export to JSON
+ </message>
<message name="IDS_POLICY_CHROME_FOR_WORK" desc="Title of the link to the chrome for work website.">
Using Chrome at work? Businesses can manage Chrome settings for their employees. Learn more
</message>
diff --git a/chromium/components/pref_registry/pref_registry_syncable.cc b/chromium/components/pref_registry/pref_registry_syncable.cc
index a81cea05a8a..f00f0c6d3f1 100644
--- a/chromium/components/pref_registry/pref_registry_syncable.cc
+++ b/chromium/components/pref_registry/pref_registry_syncable.cc
@@ -43,6 +43,8 @@ scoped_refptr<PrefRegistrySyncable> PrefRegistrySyncable::ForkForIncognito() {
// unregistration.
scoped_refptr<PrefRegistrySyncable> registry(new PrefRegistrySyncable());
registry->defaults_ = defaults_;
+ registry->registration_flags_ = registration_flags_;
+ registry->foreign_pref_keys_ = foreign_pref_keys_;
return registry;
}
diff --git a/chromium/components/prefs/in_memory_pref_store.h b/chromium/components/prefs/in_memory_pref_store.h
index 8d49f6c0458..41d06c0ed2a 100644
--- a/chromium/components/prefs/in_memory_pref_store.h
+++ b/chromium/components/prefs/in_memory_pref_store.h
@@ -48,6 +48,7 @@ class COMPONENTS_PREFS_EXPORT InMemoryPrefStore : public PersistentPrefStore {
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {}
void SchedulePendingLossyWrites() override {}
void ClearMutableValues() override {}
+ void OnStoreDeletionFromDisk() override {}
protected:
~InMemoryPrefStore() override;
diff --git a/chromium/components/prefs/in_memory_pref_store_unittest.cc b/chromium/components/prefs/in_memory_pref_store_unittest.cc
index 14da3ef0b64..46f98625ee5 100644
--- a/chromium/components/prefs/in_memory_pref_store_unittest.cc
+++ b/chromium/components/prefs/in_memory_pref_store_unittest.cc
@@ -106,7 +106,7 @@ TEST_F(InMemoryPrefStoreTest, ReadPrefs) {
}
TEST_F(InMemoryPrefStoreTest, CommitPendingWriteWithCallback) {
- TestCommitPendingWriteWithCallback(store_.get());
+ TestCommitPendingWriteWithCallback(store_.get(), &scoped_task_environment_);
}
} // namespace
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index 0b6b0f1803e..31280be8507 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -393,6 +393,11 @@ void JsonPrefStore::ClearMutableValues() {
NOTIMPLEMENTED();
}
+void JsonPrefStore::OnStoreDeletionFromDisk() {
+ if (pref_filter_)
+ pref_filter_->OnStoreDeletionFromDisk();
+}
+
void JsonPrefStore::OnFileRead(std::unique_ptr<ReadResult> read_result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/components/prefs/json_pref_store.h b/chromium/components/prefs/json_pref_store.h
index 1321a1e19dc..ac2b18989a7 100644
--- a/chromium/components/prefs/json_pref_store.h
+++ b/chromium/components/prefs/json_pref_store.h
@@ -118,6 +118,8 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
void ClearMutableValues() override;
+ void OnStoreDeletionFromDisk() override;
+
private:
// Represents a histogram for recording the number of writes to the pref file
// that occur every kHistogramWriteReportIntervalInMins minutes.
diff --git a/chromium/components/prefs/json_pref_store_unittest.cc b/chromium/components/prefs/json_pref_store_unittest.cc
index 54f878445b4..75469669c91 100644
--- a/chromium/components/prefs/json_pref_store_unittest.cc
+++ b/chromium/components/prefs/json_pref_store_unittest.cc
@@ -82,6 +82,7 @@ class InterceptingPrefFilter : public PrefFilter {
base::DictionaryValue* pref_store_contents) override {
return on_write_callback_pair_;
}
+ void OnStoreDeletionFromDisk() override {}
bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
@@ -143,14 +144,17 @@ void CommitPendingWrite(
pref_store->CommitPendingWrite(OnceClosure());
scoped_task_environment->RunUntilIdle();
} else {
- TestCommitPendingWriteWithCallback(pref_store);
+ TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment);
}
}
class JsonPrefStoreTest
: public testing::TestWithParam<CommitPendingWriteMode> {
public:
- JsonPrefStoreTest() = default;
+ JsonPrefStoreTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+ base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
protected:
void SetUp() override {
@@ -947,13 +951,7 @@ class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
};
-// Flaky on Linux TSAN. http://crbug.com/732445.
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestSerializeDataCallbacks DISABLED_TestSerializeDataCallbacks
-#else
-#define MAYBE_TestSerializeDataCallbacks TestSerializeDataCallbacks
-#endif
-TEST_F(JsonPrefStoreCallbackTest, MAYBE_TestSerializeDataCallbacks) {
+TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0,
base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
diff --git a/chromium/components/prefs/overlay_user_pref_store.cc b/chromium/components/prefs/overlay_user_pref_store.cc
index 55f3f687e2e..285b20633b1 100644
--- a/chromium/components/prefs/overlay_user_pref_store.cc
+++ b/chromium/components/prefs/overlay_user_pref_store.cc
@@ -74,7 +74,9 @@ bool OverlayUserPrefStore::GetValue(const std::string& key,
const base::Value** result) const {
// If the |key| shall NOT be stored in the overlay store, there must not
// be an entry.
- DCHECK(ShallBeStoredInOverlay(key) || !overlay_->GetValue(key, NULL));
+ // TODO(crbug.com/761123): Put back this DCHECK. It should be fixed by:
+ // https://chromium-review.googlesource.com/c/chromium/src/+/624772
+ // DCHECK(ShallBeStoredInOverlay(key) || !overlay_->GetValue(key, NULL));
if (overlay_->GetValue(key, result))
return true;
@@ -197,6 +199,10 @@ void OverlayUserPrefStore::ClearMutableValues() {
}
}
+void OverlayUserPrefStore::OnStoreDeletionFromDisk() {
+ underlay_->OnStoreDeletionFromDisk();
+}
+
OverlayUserPrefStore::~OverlayUserPrefStore() {
overlay_->RemoveObserver(overlay_observer_.get());
underlay_->RemoveObserver(underlay_observer_.get());
diff --git a/chromium/components/prefs/overlay_user_pref_store.h b/chromium/components/prefs/overlay_user_pref_store.h
index 23cace53f80..6865bd90333 100644
--- a/chromium/components/prefs/overlay_user_pref_store.h
+++ b/chromium/components/prefs/overlay_user_pref_store.h
@@ -63,6 +63,7 @@ class COMPONENTS_PREFS_EXPORT OverlayUserPrefStore
void RegisterOverlayPref(const std::string& key);
void ClearMutableValues() override;
+ void OnStoreDeletionFromDisk() override;
protected:
~OverlayUserPrefStore() override;
diff --git a/chromium/components/prefs/overlay_user_pref_store_unittest.cc b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
index 26241494b8c..7d754e5bcae 100644
--- a/chromium/components/prefs/overlay_user_pref_store_unittest.cc
+++ b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
@@ -150,7 +150,7 @@ TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified));
ASSERT_TRUE(modified);
ASSERT_TRUE(modified->IsType(Value::Type::DICTIONARY));
- EXPECT_TRUE(Value::Equals(modify, static_cast<DictionaryValue*>(modified)));
+ EXPECT_EQ(*modify, *modified);
}
// Here we consider a global preference that is not overlayed.
@@ -275,7 +275,7 @@ TEST_F(OverlayUserPrefStoreTest, GetValues) {
}
TEST_F(OverlayUserPrefStoreTest, CommitPendingWriteWithCallback) {
- TestCommitPendingWriteWithCallback(overlay_.get());
+ TestCommitPendingWriteWithCallback(overlay_.get(), &scoped_task_environment_);
}
} // namespace base
diff --git a/chromium/components/prefs/persistent_pref_store.h b/chromium/components/prefs/persistent_pref_store.h
index 2eba3dcaf56..803f50af254 100644
--- a/chromium/components/prefs/persistent_pref_store.h
+++ b/chromium/components/prefs/persistent_pref_store.h
@@ -76,6 +76,9 @@ class COMPONENTS_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore {
// It should be called only for Incognito pref store.
virtual void ClearMutableValues() = 0;
+ // Cleans preference data that may have been saved outside of the store.
+ virtual void OnStoreDeletionFromDisk() = 0;
+
protected:
~PersistentPrefStore() override {}
};
diff --git a/chromium/components/prefs/persistent_pref_store_unittest.cc b/chromium/components/prefs/persistent_pref_store_unittest.cc
index e2a65416453..d297858b812 100644
--- a/chromium/components/prefs/persistent_pref_store_unittest.cc
+++ b/chromium/components/prefs/persistent_pref_store_unittest.cc
@@ -7,9 +7,12 @@
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/sequence_checker_impl.h"
+#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
-void TestCommitPendingWriteWithCallback(PersistentPrefStore* store) {
+void TestCommitPendingWriteWithCallback(
+ PersistentPrefStore* store,
+ base::test::ScopedTaskEnvironment* scoped_task_environment) {
base::RunLoop run_loop;
base::SequenceCheckerImpl sequence_checker;
store->CommitPendingWrite(base::BindOnce(
@@ -18,5 +21,6 @@ void TestCommitPendingWriteWithCallback(PersistentPrefStore* store) {
run_loop->Quit();
},
base::Unretained(&sequence_checker), base::Unretained(&run_loop)));
+ scoped_task_environment->RunUntilIdle();
run_loop.Run();
}
diff --git a/chromium/components/prefs/persistent_pref_store_unittest.h b/chromium/components/prefs/persistent_pref_store_unittest.h
index 99442336c7b..ea658e1c7c7 100644
--- a/chromium/components/prefs/persistent_pref_store_unittest.h
+++ b/chromium/components/prefs/persistent_pref_store_unittest.h
@@ -5,11 +5,20 @@
#ifndef COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_
#define COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_
+namespace base {
+namespace test {
+class ScopedTaskEnvironment;
+}
+} // namespace base
+
class PersistentPrefStore;
// Calls CommitPendingWrite() on |store| with a callback. Verifies that the
-// callback runs on the appropriate sequence. This function is meant to be
-// reused in the tests of various PersistentPrefStore implementations.
-void TestCommitPendingWriteWithCallback(PersistentPrefStore* store);
+// callback runs on the appropriate sequence. |scoped_task_environment| is the
+// test's ScopedTaskEnvironment. This function is meant to be reused in the
+// tests of various PersistentPrefStore implementations.
+void TestCommitPendingWriteWithCallback(
+ PersistentPrefStore* store,
+ base::test::ScopedTaskEnvironment* scoped_task_environment);
#endif // COMPONENTS_PREFS_PERSISTENT_PREF_STORE_UNITTEST_H_
diff --git a/chromium/components/prefs/pref_filter.h b/chromium/components/prefs/pref_filter.h
index 9bc2244b412..bd133da449a 100644
--- a/chromium/components/prefs/pref_filter.h
+++ b/chromium/components/prefs/pref_filter.h
@@ -58,6 +58,9 @@ class COMPONENTS_PREFS_EXPORT PrefFilter {
// must not be bound to thread-unsafe member state).
virtual OnWriteCallbackPair FilterSerializeData(
base::DictionaryValue* pref_store_contents) = 0;
+
+ // Cleans preference data that may have been saved outside of the store.
+ virtual void OnStoreDeletionFromDisk() = 0;
};
#endif // COMPONENTS_PREFS_PREF_FILTER_H_
diff --git a/chromium/components/prefs/pref_member.cc b/chromium/components/prefs/pref_member.cc
index f0be267ed5d..6907f667a06 100644
--- a/chromium/components/prefs/pref_member.cc
+++ b/chromium/components/prefs/pref_member.cc
@@ -102,13 +102,12 @@ bool PrefMemberBase::Internal::IsOnCorrectThread() const {
return thread_task_runner_->BelongsToCurrentThread();
}
-void PrefMemberBase::Internal::UpdateValue(
- base::Value* v,
- bool is_managed,
- bool is_user_modifiable,
- const base::Closure& callback) const {
+void PrefMemberBase::Internal::UpdateValue(base::Value* v,
+ bool is_managed,
+ bool is_user_modifiable,
+ base::OnceClosure callback) const {
std::unique_ptr<base::Value> value(v);
- base::ScopedClosureRunner closure_runner(callback);
+ base::ScopedClosureRunner closure_runner(std::move(callback));
if (IsOnCorrectThread()) {
bool rv = UpdateValueInternal(*value);
DCHECK(rv);
@@ -116,9 +115,10 @@ void PrefMemberBase::Internal::UpdateValue(
is_user_modifiable_ = is_user_modifiable;
} else {
bool may_run = thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
- value.release(), is_managed, is_user_modifiable,
- closure_runner.Release()));
+ FROM_HERE,
+ base::BindOnce(&PrefMemberBase::Internal::UpdateValue, this,
+ value.release(), is_managed, is_user_modifiable,
+ closure_runner.Release()));
DCHECK(may_run);
}
}
diff --git a/chromium/components/prefs/pref_member.h b/chromium/components/prefs/pref_member.h
index f46e368603c..205f43284c9 100644
--- a/chromium/components/prefs/pref_member.h
+++ b/chromium/components/prefs/pref_member.h
@@ -63,7 +63,7 @@ class COMPONENTS_PREFS_EXPORT PrefMemberBase : public PrefObserver {
void UpdateValue(base::Value* value,
bool is_managed,
bool is_user_modifiable,
- const base::Closure& callback) const;
+ base::OnceClosure callback) const;
void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
diff --git a/chromium/components/prefs/pref_notifier_impl.h b/chromium/components/prefs/pref_notifier_impl.h
index c5448d3b53e..5a8a1372c02 100644
--- a/chromium/components/prefs/pref_notifier_impl.h
+++ b/chromium/components/prefs/pref_notifier_impl.h
@@ -22,8 +22,7 @@
class PrefService;
// The PrefNotifier implementation used by the PrefService.
-class COMPONENTS_PREFS_EXPORT PrefNotifierImpl
- : public NON_EXPORTED_BASE(PrefNotifier) {
+class COMPONENTS_PREFS_EXPORT PrefNotifierImpl : public PrefNotifier {
public:
PrefNotifierImpl();
explicit PrefNotifierImpl(PrefService* pref_service);
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index 57eb09d87f4..fd1dea3bc86 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -256,6 +256,14 @@ PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
}
}
+PrefService::PrefInitializationStatus
+PrefService::GetAllPrefStoresInitializationStatus() const {
+ if (!pref_value_store_->IsInitializationComplete())
+ return INITIALIZATION_STATUS_WAITING;
+
+ return GetInitializationStatus();
+}
+
bool PrefService::IsManagedPreference(const std::string& pref_name) const {
const Preference* pref = FindPreference(pref_name);
return pref && pref->IsManaged();
@@ -378,6 +386,10 @@ void PrefService::ClearMutableValues() {
user_pref_store_->ClearMutableValues();
}
+void PrefService::OnStoreDeletionFromDisk() {
+ user_pref_store_->OnStoreDeletionFromDisk();
+}
+
void PrefService::Set(const std::string& path, const base::Value& value) {
SetUserPrefValue(path, value.CreateDeepCopy());
}
diff --git a/chromium/components/prefs/pref_service.h b/chromium/components/prefs/pref_service.h
index ca7ad8fa0c3..5d3b101b675 100644
--- a/chromium/components/prefs/pref_service.h
+++ b/chromium/components/prefs/pref_service.h
@@ -283,8 +283,12 @@ class COMPONENTS_PREFS_EXPORT PrefService {
bool ReadOnly() const;
+ // Returns the initialization state, taking only user prefs into account.
PrefInitializationStatus GetInitializationStatus() const;
+ // Returns the initialization state, taking all pref stores into account.
+ PrefInitializationStatus GetAllPrefStoresInitializationStatus() const;
+
// Tell our PrefValueStore to update itself to |command_line_store|.
// Takes ownership of the store.
virtual void UpdateCommandLinePrefStore(PrefStore* command_line_store);
@@ -312,6 +316,10 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// Clears mutable values.
void ClearMutableValues();
+ // Invoked when the store is deleted from disk. Allows this PrefService
+ // to tangentially cleanup data it may have saved outside the store.
+ void OnStoreDeletionFromDisk();
+
protected:
// The PrefNotifier handles registering and notifying preference observers.
// It is created and owned by this PrefService. Subclasses may access it for
diff --git a/chromium/components/prefs/pref_value_store.cc b/chromium/components/prefs/pref_value_store.cc
index da58b231840..f76d3a580ea 100644
--- a/chromium/components/prefs/pref_value_store.cc
+++ b/chromium/components/prefs/pref_value_store.cc
@@ -198,6 +198,15 @@ void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) {
delegate_->UpdateCommandLinePrefStore(command_line_prefs);
}
+bool PrefValueStore::IsInitializationComplete() const {
+ for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+ const PrefStore* pref_store = GetPrefStore(static_cast<PrefStoreType>(i));
+ if (pref_store && !pref_store->IsInitializationComplete())
+ return false;
+ }
+ return true;
+}
+
bool PrefValueStore::PrefValueInStore(
const std::string& name,
PrefValueStore::PrefStoreType store) const {
diff --git a/chromium/components/prefs/pref_value_store.h b/chromium/components/prefs/pref_value_store.h
index 9fb9ed10996..ea6962d98ad 100644
--- a/chromium/components/prefs/pref_value_store.h
+++ b/chromium/components/prefs/pref_value_store.h
@@ -175,6 +175,8 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
// Update the command line PrefStore with |command_line_prefs|.
void UpdateCommandLinePrefStore(PrefStore* command_line_prefs);
+ bool IsInitializationComplete() const;
+
private:
// Keeps a PrefStore reference on behalf of the PrefValueStore and monitors
// the PrefStore for changes, forwarding notifications to PrefValueStore. This
diff --git a/chromium/components/prefs/testing_pref_store.cc b/chromium/components/prefs/testing_pref_store.cc
index f214da8f2ad..cccf6b4e0d3 100644
--- a/chromium/components/prefs/testing_pref_store.cc
+++ b/chromium/components/prefs/testing_pref_store.cc
@@ -183,6 +183,8 @@ void TestingPrefStore::ClearMutableValues() {
NOTIMPLEMENTED();
}
+void TestingPrefStore::OnStoreDeletionFromDisk() {}
+
void TestingPrefStore::set_read_only(bool read_only) {
read_only_ = read_only;
}
diff --git a/chromium/components/prefs/testing_pref_store.h b/chromium/components/prefs/testing_pref_store.h
index cc40c1d0da9..c011815d962 100644
--- a/chromium/components/prefs/testing_pref_store.h
+++ b/chromium/components/prefs/testing_pref_store.h
@@ -71,6 +71,7 @@ class TestingPrefStore : public PersistentPrefStore {
void SetBlockAsyncRead(bool block_async_read);
void ClearMutableValues() override;
+ void OnStoreDeletionFromDisk() override;
// Getter and Setter methods for setting and getting the state of the
// |TestingPrefStore|.
diff --git a/chromium/components/previews/core/previews_experiments.cc b/chromium/components/previews/core/previews_experiments.cc
index b654c75a2ff..352c4053145 100644
--- a/chromium/components/previews/core/previews_experiments.cc
+++ b/chromium/components/previews/core/previews_experiments.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
+#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -17,16 +18,12 @@ namespace previews {
namespace {
-// The group of client-side previews experiments. Actually, this group is only
-// expected to control one PreviewsType (OFFLINE) as well as the blacklist.
-// Other PreviewsType's will be control by different field trial groups.
+// The group of client-side previews experiments. This controls paramters of the
+// client side blacklist.
const char kClientSidePreviewsFieldTrial[] = "ClientSidePreviews";
const char kEnabled[] = "Enabled";
-// Allow offline pages to show for prohibitively slow networks.
-const char kOfflinePagesSlowNetwork[] = "show_offline_pages";
-
// Name for the version parameter of a field trial. Version changes will
// result in older blacklist entries being removed.
const char kVersion[] = "version";
@@ -37,9 +34,6 @@ const char kVersion[] = "version";
const char kEffectiveConnectionTypeThreshold[] =
"max_allowed_effective_connection_type";
-// The string that corresponds to enabled for the variation param experiments.
-const char kExperimentEnabled[] = "true";
-
const char kClientLoFiExperimentName[] = "PreviewsClientLoFi";
size_t GetParamValueAsSizeT(const std::string& trial_name,
@@ -68,21 +62,9 @@ net::EffectiveConnectionType GetParamValueAsECT(
const std::string& trial_name,
const std::string& param_name,
net::EffectiveConnectionType default_value) {
- net::EffectiveConnectionType value;
- if (!net::GetEffectiveConnectionTypeForName(
- base::GetFieldTrialParamValue(trial_name, param_name), &value)) {
- return default_value;
- }
- return value;
-}
-
-bool IsIncludedInClientSidePreviewsExperimentsFieldTrial() {
- // By convention, an experiment in the client-side previews study enables use
- // of at least one client-side previews optimization if its name begins with
- // "Enabled."
- return base::StartsWith(
- base::FieldTrialList::FindFullName(kClientSidePreviewsFieldTrial),
- kEnabled, base::CompareCase::SENSITIVE);
+ return net::GetEffectiveConnectionTypeForName(
+ base::GetFieldTrialParamValue(trial_name, param_name))
+ .value_or(default_value);
}
} // namespace
@@ -111,7 +93,7 @@ int PerHostBlackListOptOutThreshold() {
int HostIndifferentBlackListOptOutThreshold() {
return GetParamValueAsInt(kClientSidePreviewsFieldTrial,
- "host_indifferent_opt_out_threshold", 4);
+ "host_indifferent_opt_out_threshold", 6);
}
base::TimeDelta PerHostBlackListDuration() {
@@ -141,16 +123,11 @@ base::TimeDelta OfflinePreviewFreshnessDuration() {
net::EffectiveConnectionType DefaultEffectiveConnectionTypeThreshold() {
return GetParamValueAsECT(kClientSidePreviewsFieldTrial,
kEffectiveConnectionTypeThreshold,
- net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
}
bool IsOfflinePreviewsEnabled() {
- // Check if "show_offline_pages" is set to "true".
- return base::FeatureList::IsEnabled(features::kOfflinePreviews) ||
- (IsIncludedInClientSidePreviewsExperimentsFieldTrial() &&
- base::GetFieldTrialParamValue(kClientSidePreviewsFieldTrial,
- kOfflinePagesSlowNetwork) ==
- kExperimentEnabled);
+ return base::FeatureList::IsEnabled(features::kOfflinePreviews);
}
int OfflinePreviewsVersion() {
diff --git a/chromium/components/previews/core/previews_experiments_unittest.cc b/chromium/components/previews/core/previews_experiments_unittest.cc
index eb71c6d52e4..932d345fdd2 100644
--- a/chromium/components/previews/core/previews_experiments_unittest.cc
+++ b/chromium/components/previews/core/previews_experiments_unittest.cc
@@ -24,36 +24,19 @@ const char kClientSidePreviewsFieldTrial[] = "ClientSidePreviews";
const char kClientLoFiFieldTrial[] = "PreviewsClientLoFi";
const char kEnabled[] = "Enabled";
-// Verifies that we can enable offline previews via field trial.
-TEST(PreviewsExperimentsTest, TestFieldTrialOfflinePage) {
- EXPECT_FALSE(params::IsOfflinePreviewsEnabled());
-
- base::FieldTrialList field_trial_list(nullptr);
-
- std::map<std::string, std::string> params;
- params["show_offline_pages"] = "true";
- EXPECT_TRUE(base::AssociateFieldTrialParams(kClientSidePreviewsFieldTrial,
- kEnabled, params));
- EXPECT_TRUE(base::FieldTrialList::CreateFieldTrial(
- kClientSidePreviewsFieldTrial, kEnabled));
-
- EXPECT_TRUE(params::IsOfflinePreviewsEnabled());
- variations::testing::ClearAllVariationParams();
-}
-
// Verifies that we can enable offline previews via comand line.
TEST(PreviewsExperimentsTest, TestCommandLineOfflinePage) {
- EXPECT_FALSE(params::IsOfflinePreviewsEnabled());
+ EXPECT_TRUE(params::IsOfflinePreviewsEnabled());
std::unique_ptr<base::FeatureList> feature_list =
base::MakeUnique<base::FeatureList>();
// The feature is explicitly enabled on the command-line.
- feature_list->InitializeFromCommandLine("OfflinePreviews", "");
+ feature_list->InitializeFromCommandLine("", "OfflinePreviews");
base::FeatureList::ClearInstanceForTesting();
base::FeatureList::SetInstance(std::move(feature_list));
- EXPECT_TRUE(params::IsOfflinePreviewsEnabled());
+ EXPECT_FALSE(params::IsOfflinePreviewsEnabled());
base::FeatureList::ClearInstanceForTesting();
}
@@ -65,7 +48,7 @@ TEST(PreviewsExperimentsTest, TestParamsForBlackListAndOffline) {
EXPECT_EQ(10u, params::MaxStoredHistoryLengthForHostIndifferentBlackList());
EXPECT_EQ(100u, params::MaxInMemoryHostsInBlackList());
EXPECT_EQ(2, params::PerHostBlackListOptOutThreshold());
- EXPECT_EQ(4, params::HostIndifferentBlackListOptOutThreshold());
+ EXPECT_EQ(6, params::HostIndifferentBlackListOptOutThreshold());
EXPECT_EQ(base::TimeDelta::FromDays(30), params::PerHostBlackListDuration());
EXPECT_EQ(base::TimeDelta::FromDays(365 * 100),
params::HostIndifferentBlackListPerHostDuration());
@@ -73,7 +56,7 @@ TEST(PreviewsExperimentsTest, TestParamsForBlackListAndOffline) {
params::SingleOptOutDuration());
EXPECT_EQ(base::TimeDelta::FromDays(7),
params::OfflinePreviewFreshnessDuration());
- EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
params::DefaultEffectiveConnectionTypeThreshold());
EXPECT_EQ(0, params::OfflinePreviewsVersion());
diff --git a/chromium/components/previews/core/previews_features.cc b/chromium/components/previews/core/previews_features.cc
index 01f15dae36f..1a28bc141d9 100644
--- a/chromium/components/previews/core/previews_features.cc
+++ b/chromium/components/previews/core/previews_features.cc
@@ -7,9 +7,9 @@
namespace previews {
namespace features {
-// Enables the Offline previews on Android.
+// Enables the Offline previews on android slow connections.
const base::Feature kOfflinePreviews{"OfflinePreviews",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Enables the Client Lo-Fi previews on Android.
const base::Feature kClientLoFi{"ClientLoFi",
diff --git a/chromium/components/previews/core/previews_io_data_unittest.cc b/chromium/components/previews/core/previews_io_data_unittest.cc
index 101092284bd..a68e4d63498 100644
--- a/chromium/components/previews/core/previews_io_data_unittest.cc
+++ b/chromium/components/previews/core/previews_io_data_unittest.cc
@@ -211,10 +211,6 @@ TEST_F(PreviewsIODataTest, TestDisallowPreviewBecauseOfBlackListState) {
histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 2);
- // Enable Offline previews field trial.
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"}});
-
// Return one of the failing statuses from the blacklist; cause the blacklist
// to not be loaded by clearing the blacklist.
base::Time now = base::Time::Now();
@@ -225,43 +221,11 @@ TEST_F(PreviewsIODataTest, TestDisallowPreviewBecauseOfBlackListState) {
"Previews.EligibilityReason.Offline",
static_cast<int>(PreviewsEligibilityReason::BLACKLIST_DATA_NOT_LOADED),
1);
-}
-
-TEST_F(PreviewsIODataTest, TestDisallowOfflineByDefault) {
- InitializeUIService();
-
- base::HistogramTester histogram_tester;
- EXPECT_FALSE(
- io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
- histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
-}
-
-TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenInDisabledGroup) {
- InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Disabled",
- {{"show_offline_pages", "true"}});
-
- base::HistogramTester histogram_tester;
- EXPECT_FALSE(
- io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
- histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
-}
-
-TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenDisabled) {
- InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "false"}});
-
- base::HistogramTester histogram_tester;
- EXPECT_FALSE(
- io_data()->ShouldAllowPreview(*CreateRequest(), PreviewsType::OFFLINE));
- histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityUnavailable) {
InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"}});
network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
@@ -278,9 +242,6 @@ TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityUnavailable) {
TEST_F(PreviewsIODataTest, TestAllowLitePageWhenNetworkQualityFast) {
// LoFi and LitePage check NQE on their own.
InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"},
- {"max_allowed_effective_connection_type", "2G"}});
network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_3G);
@@ -296,9 +257,6 @@ TEST_F(PreviewsIODataTest, TestAllowLitePageWhenNetworkQualityFast) {
TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityFast) {
InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"},
- {"max_allowed_effective_connection_type", "2G"}});
network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_3G);
@@ -313,9 +271,6 @@ TEST_F(PreviewsIODataTest, TestDisallowOfflineWhenNetworkQualityFast) {
TEST_F(PreviewsIODataTest, TestDisallowOfflineOnReload) {
InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"},
- {"max_allowed_effective_connection_type", "2G"}});
network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_2G);
@@ -332,9 +287,6 @@ TEST_F(PreviewsIODataTest, TestDisallowOfflineOnReload) {
TEST_F(PreviewsIODataTest, TestAllowOffline) {
InitializeUIService();
- CreateFieldTrialWithParams("ClientSidePreviews", "Enabled",
- {{"show_offline_pages", "true"},
- {"max_allowed_effective_connection_type", "2G"}});
network_quality_estimator()->set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_2G);
@@ -368,6 +320,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenFieldTrialDisabled) {
params::EffectiveConnectionTypeThresholdForClientLoFi(),
params::GetBlackListedHostsForClientLoFiFieldTrial()));
histogram_tester.ExpectTotalCount("Previews.EligibilityReason.LoFi", 0);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkQualityUnavailable) {
@@ -386,6 +339,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkQualityUnavailable) {
"Previews.EligibilityReason.LoFi",
static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
1);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkFast) {
@@ -404,6 +358,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiDisallowedWhenNetworkFast) {
histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.LoFi",
static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, ClientLoFiAllowed) {
@@ -422,6 +377,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiAllowed) {
histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.LoFi",
static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, ClientLoFiAllowedOnReload) {
@@ -443,6 +399,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiAllowedOnReload) {
histogram_tester.ExpectUniqueSample(
"Previews.EligibilityReason.LoFi",
static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+ variations::testing::ClearAllVariationParams();
}
TEST_F(PreviewsIODataTest, ClientLoFiObeysHostBlackListFromServer) {
@@ -486,6 +443,7 @@ TEST_F(PreviewsIODataTest, ClientLoFiObeysHostBlackListFromServer) {
: PreviewsEligibilityReason::HOST_BLACKLISTED_BY_SERVER),
1);
}
+ variations::testing::ClearAllVariationParams();
}
} // namespace
diff --git a/chromium/components/printing/DEPS b/chromium/components/printing/DEPS
index 057bda25ce5..abfcfb6c9d8 100644
--- a/chromium/components/printing/DEPS
+++ b/chromium/components/printing/DEPS
@@ -1,5 +1,7 @@
include_rules = [
- "+content/public",
+ "-components/printing",
+ "+components/printing/common",
+ "+content/public/common",
"+ipc",
"+printing",
"+third_party/WebKit/public",
diff --git a/chromium/components/printing/browser/DEPS b/chromium/components/printing/browser/DEPS
new file mode 100644
index 00000000000..1c35d9ca694
--- /dev/null
+++ b/chromium/components/printing/browser/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+content/public/browser",
+]
diff --git a/chromium/components/printing/browser/print_manager_utils.cc b/chromium/components/printing/browser/print_manager_utils.cc
index 7be67b197e5..3d71a985f6b 100644
--- a/chromium/components/printing/browser/print_manager_utils.cc
+++ b/chromium/components/printing/browser/print_manager_utils.cc
@@ -32,6 +32,7 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings,
params->display_header_footer = settings.display_header_footer();
params->title = settings.title();
params->url = settings.url();
+ params->printed_doc_type = SkiaDocumentType::PDF;
}
} // namespace printing
diff --git a/chromium/components/printing/common/BUILD.gn b/chromium/components/printing/common/BUILD.gn
index e3f8e731441..11fca1b1722 100644
--- a/chromium/components/printing/common/BUILD.gn
+++ b/chromium/components/printing/common/BUILD.gn
@@ -13,6 +13,7 @@ static_library("common") {
"//base",
"//ipc",
"//printing",
+ "//printing/common:common",
"//third_party/WebKit/public:blink_headers",
"//ui/gfx",
"//ui/gfx/geometry",
diff --git a/chromium/components/printing/common/print_messages.cc b/chromium/components/printing/common/print_messages.cc
index de036345130..4a7c94d1cdd 100644
--- a/chromium/components/printing/common/print_messages.cc
+++ b/chromium/components/printing/common/print_messages.cc
@@ -61,7 +61,8 @@ PrintMsg_Print_Params::PrintMsg_Print_Params()
display_header_footer(false),
title(),
url(),
- should_print_backgrounds(false) {}
+ should_print_backgrounds(false),
+ printed_doc_type(printing::SkiaDocumentType::PDF) {}
PrintMsg_Print_Params::PrintMsg_Print_Params(
const PrintMsg_Print_Params& other) = default;
@@ -89,6 +90,7 @@ void PrintMsg_Print_Params::Reset() {
title = base::string16();
url = base::string16();
should_print_backgrounds = false;
+ printed_doc_type = printing::SkiaDocumentType::PDF;
}
PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
diff --git a/chromium/components/printing/common/print_messages.h b/chromium/components/printing/common/print_messages.h
index fd395915885..f9b1daf905f 100644
--- a/chromium/components/printing/common/print_messages.h
+++ b/chromium/components/printing/common/print_messages.h
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "components/printing/common/printing_param_traits_macros.h"
#include "ipc/ipc_message_macros.h"
+#include "printing/common/pdf_metafile_utils.h"
#include "printing/features/features.h"
#include "printing/page_range.h"
#include "printing/page_size_margins.h"
@@ -60,6 +61,7 @@ struct PrintMsg_Print_Params {
base::string16 title;
base::string16 url;
bool should_print_backgrounds;
+ printing::SkiaDocumentType printed_doc_type;
};
struct PrintMsg_PrintPages_Params {
@@ -101,6 +103,8 @@ struct PrintHostMsg_SetOptionsFromDocument_Params {
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption,
blink::kWebPrintScalingOptionLast)
+IPC_ENUM_TRAITS_MAX_VALUE(printing::SkiaDocumentType,
+ printing::SkiaDocumentType::MAX)
// Parameters for a render request.
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
@@ -166,6 +170,9 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// True if print backgrounds is requested by the user.
IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds)
+
+ // The document type of printed page(s) from render.
+ IPC_STRUCT_TRAITS_MEMBER(printed_doc_type)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(printing::PageRange)
diff --git a/chromium/components/printing/renderer/BUILD.gn b/chromium/components/printing/renderer/BUILD.gn
index e2cbf163b0f..1902a859479 100644
--- a/chromium/components/printing/renderer/BUILD.gn
+++ b/chromium/components/printing/renderer/BUILD.gn
@@ -4,12 +4,12 @@
static_library("renderer") {
sources = [
- "print_web_view_helper.cc",
- "print_web_view_helper.h",
- "print_web_view_helper_android.cc",
- "print_web_view_helper_linux.cc",
- "print_web_view_helper_mac.mm",
- "print_web_view_helper_pdf_win.cc",
+ "print_render_frame_helper.cc",
+ "print_render_frame_helper.h",
+ "print_render_frame_helper_android.cc",
+ "print_render_frame_helper_linux.cc",
+ "print_render_frame_helper_mac.mm",
+ "print_render_frame_helper_pdf_win.cc",
]
deps = [
diff --git a/chromium/components/printing/renderer/DEPS b/chromium/components/printing/renderer/DEPS
index 70bf501b1a1..d6b6f93dee7 100644
--- a/chromium/components/printing/renderer/DEPS
+++ b/chromium/components/printing/renderer/DEPS
@@ -1,6 +1,8 @@
include_rules = [
"+components/grit/components_resources.h",
+ "+content/public/renderer",
"+net/base",
+ "+services/service_manager/public/cpp",
"+third_party/skia",
"+ui/base",
]
diff --git a/chromium/components/printing/renderer/print_web_view_helper.cc b/chromium/components/printing/renderer/print_render_frame_helper.cc
index 3c9dfc0d1ed..18469953e9f 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper.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/printing/renderer/print_web_view_helper.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
#include <stddef.h>
#include <stdint.h>
@@ -36,6 +36,7 @@
#include "printing/metafile_skia_wrapper.h"
#include "printing/pdf_metafile_skia.h"
#include "printing/units.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebDoubleSize.h"
#include "third_party/WebKit/public/platform/WebSize.h"
@@ -144,16 +145,15 @@ PrintMsg_Print_Params GetCssPrintParams(
int margin_top_in_pixels =
ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
int margin_right_in_pixels = ConvertUnit(
- page_params.page_size.width() -
- page_params.content_size.width() - page_params.margin_left,
+ page_params.page_size.width() - page_params.content_size.width() -
+ page_params.margin_left,
dpi, kPixelsPerInch);
int margin_bottom_in_pixels = ConvertUnit(
- page_params.page_size.height() -
- page_params.content_size.height() - page_params.margin_top,
- dpi, kPixelsPerInch);
- int margin_left_in_pixels = ConvertUnit(
- page_params.margin_left,
+ page_params.page_size.height() - page_params.content_size.height() -
+ page_params.margin_top,
dpi, kPixelsPerInch);
+ int margin_left_in_pixels =
+ ConvertUnit(page_params.margin_left, dpi, kPixelsPerInch);
if (frame) {
frame->PageSizeAndMarginsInPixels(
@@ -178,7 +178,7 @@ PrintMsg_Print_Params GetCssPrintParams(
ConvertUnit(page_size_in_pixels.Height(), kPixelsPerInch, dpi));
page_css_params.content_size =
gfx::Size(ConvertUnit(new_content_width, kPixelsPerInch, dpi),
- ConvertUnit(new_content_height, kPixelsPerInch, dpi));
+ ConvertUnit(new_content_height, kPixelsPerInch, dpi));
page_css_params.margin_top =
ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi);
@@ -234,7 +234,7 @@ void CalculatePageLayoutFromPrintParams(
int content_height = params.content_size.height();
// Scale the content to its normal size for purpose of computing page layout.
// Otherwise we will get negative margins.
- if (scale_factor >= PrintWebViewHelper::kEpsilon &&
+ if (scale_factor >= PrintRenderFrameHelper::kEpsilon &&
(fit_to_page || params.print_to_pdf)) {
content_width =
static_cast<int>(static_cast<double>(content_width) * scale_factor);
@@ -393,8 +393,9 @@ bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
MarginType GetMarginsForPdf(blink::WebLocalFrame* frame,
const blink::WebNode& node,
const PrintMsg_Print_Params& params) {
- return PDFShouldDisableScaling(frame, node, params, false) ?
- NO_MARGINS : PRINTABLE_AREA_MARGINS;
+ return PDFShouldDisableScaling(frame, node, params, false)
+ ? NO_MARGINS
+ : PRINTABLE_AREA_MARGINS;
}
#endif
@@ -434,8 +435,7 @@ blink::WebPrintScalingOption GetPrintScalingOption(
if (!FitToPageEnabled(job_settings))
return blink::kWebPrintScalingOptionNone;
- bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params,
- true);
+ bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params, true);
if (params.is_first_request && no_plugin_scaling)
return blink::kWebPrintScalingOptionNone;
}
@@ -532,12 +532,17 @@ FrameReference::FrameReference() {
Reset(NULL);
}
-FrameReference::~FrameReference() {
-}
+FrameReference::~FrameReference() {}
void FrameReference::Reset(blink::WebLocalFrame* frame) {
if (frame) {
view_ = frame->View();
+ // Make sure this isn't called too early in the |frame| lifecycle... i.e.
+ // calling this in WebFrameClient::BindToFrame() doesn't work.
+ // TODO(dcheng): It's a bit awkward that lifetime details like this leak out
+ // of Blink. Fixing https://crbug.com/727166 should allow this to be
+ // addressed.
+ DCHECK(view_);
frame_ = frame;
} else {
view_ = NULL;
@@ -561,7 +566,7 @@ blink::WebView* FrameReference::view() {
}
// static - Not anonymous so that platform implementations can use it.
-void PrintWebViewHelper::PrintHeaderAndFooter(
+void PrintRenderFrameHelper::PrintHeaderAndFooter(
blink::WebCanvas* canvas,
int page_number,
int total_pages,
@@ -583,11 +588,25 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
class HeaderAndFooterClient final : public blink::WebFrameClient {
public:
- void FrameDetached(blink::WebLocalFrame* frame,
- DetachType detach_type) override {
- frame->FrameWidget()->Close();
- frame->Close();
+ HeaderAndFooterClient() {
+ service_manager::mojom::InterfaceProviderPtr provider;
+ mojo::MakeRequest(&provider);
+ interface_provider_.Bind(std::move(provider));
+ }
+ // WebFrameClient:
+ void BindToFrame(blink::WebLocalFrame* frame) override { frame_ = frame; }
+ void FrameDetached(DetachType detach_type) override {
+ frame_->FrameWidget()->Close();
+ frame_->Close();
+ frame_ = nullptr;
+ }
+ service_manager::InterfaceProvider* GetInterfaceProvider() override {
+ return &interface_provider_;
}
+
+ private:
+ blink::WebLocalFrame* frame_;
+ service_manager::InterfaceProvider interface_provider_;
};
HeaderAndFooterClient frame_client;
blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
@@ -627,12 +646,12 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
}
// static - Not anonymous so that platform implementations can use it.
-float PrintWebViewHelper::RenderPageContent(blink::WebLocalFrame* frame,
- int page_number,
- const gfx::Rect& canvas_area,
- const gfx::Rect& content_area,
- double scale_factor,
- blink::WebCanvas* canvas) {
+float PrintRenderFrameHelper::RenderPageContent(blink::WebLocalFrame* frame,
+ int page_number,
+ const gfx::Rect& canvas_area,
+ const gfx::Rect& content_area,
+ double scale_factor,
+ blink::WebCanvas* canvas) {
cc::PaintCanvasAutoRestore auto_restore(canvas, true);
canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
(content_area.y() - canvas_area.y()) / scale_factor);
@@ -687,11 +706,11 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
blink::WebSandboxFlags sandbox_flags,
const blink::WebParsedFeaturePolicy& container_policy,
const blink::WebFrameOwnerProperties& frame_owner_properties) override;
- void FrameDetached(blink::WebLocalFrame* frame,
- DetachType detach_type) override;
+ void FrameDetached(DetachType detach_type) override;
std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
const blink::WebURLRequest& request,
base::SingleThreadTaskRunner* task_runner) override;
+ service_manager::InterfaceProvider* GetInterfaceProvider() override;
void CallOnReady();
void ResizeForPrinting();
@@ -709,6 +728,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
bool should_print_backgrounds_;
bool should_print_selection_only_;
bool is_printing_started_;
+ service_manager::InterfaceProvider interface_provider_;
base::WeakPtrFactory<PrepareFrameAndViewForPrint> weak_ptr_factory_;
@@ -736,13 +756,16 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
frame->PrintBegin(web_print_params_, node_to_print_);
double scale_factor = 1.0f;
- if (print_params.scale_factor >= PrintWebViewHelper::kEpsilon)
+ if (print_params.scale_factor >= PrintRenderFrameHelper::kEpsilon)
scale_factor = print_params.scale_factor;
print_params = CalculatePrintParamsForCss(
frame, 0, print_params, ignore_css_margins, fit_to_page, &scale_factor);
frame->PrintEnd();
}
ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
+ service_manager::mojom::InterfaceProviderPtr provider;
+ mojo::MakeRequest(&provider);
+ interface_provider_.Bind(std::move(provider));
}
PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
@@ -767,6 +790,11 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() {
if (!frame())
return;
+ // Plugins do not need to be resized. Resizing the PDF plugin causes a
+ // flicker in the top left corner behind the preview. See crbug.com/739973.
+ if (PrintingNodeOrPdfFrame(frame(), node_to_print_))
+ return;
+
// Backup size and offset if it's a local frame.
blink::WebView* web_view = frame_.view();
if (blink::WebFrame* web_frame = web_view->MainFrame()) {
@@ -776,7 +804,6 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() {
prev_scroll_offset_ = web_frame->ToWebLocalFrame()->GetScrollOffset();
}
prev_view_size_ = web_view->Size();
-
web_view->Resize(print_layout_size);
}
@@ -820,8 +847,8 @@ void PrepareFrameAndViewForPrint::CopySelection(
content::RenderView::ApplyWebPreferences(prefs, web_view);
blink::WebLocalFrame* main_frame =
blink::WebLocalFrame::CreateMainFrame(web_view, this, nullptr, nullptr);
+ frame_.Reset(main_frame);
blink::WebFrameWidget::Create(this, main_frame);
- frame_.Reset(web_view->MainFrame()->ToWebLocalFrame());
node_to_print_.Reset();
// When loading is done this will call didStopLoading() and that will do the
@@ -858,10 +885,12 @@ blink::WebLocalFrame* PrepareFrameAndViewForPrint::CreateChildFrame(
return nullptr;
}
-void PrepareFrameAndViewForPrint::FrameDetached(blink::WebLocalFrame* frame,
- DetachType detach_type) {
+void PrepareFrameAndViewForPrint::FrameDetached(DetachType detach_type) {
+ blink::WebLocalFrame* frame = frame_.GetFrame();
+ DCHECK(frame);
frame->FrameWidget()->Close();
frame->Close();
+ frame_.Reset(nullptr);
}
std::unique_ptr<blink::WebURLLoader>
@@ -872,6 +901,11 @@ PrepareFrameAndViewForPrint::CreateURLLoader(
return blink::Platform::Current()->CreateURLLoader(request, task_runner);
}
+service_manager::InterfaceProvider*
+PrepareFrameAndViewForPrint::GetInterfaceProvider() {
+ return &interface_provider_;
+}
+
void PrepareFrameAndViewForPrint::CallOnReady() {
return on_ready_.Run(); // Can delete |this|.
}
@@ -880,6 +914,10 @@ void PrepareFrameAndViewForPrint::RestoreSize() {
if (!frame())
return;
+ // Do not restore plugins, since they are not resized.
+ if (PrintingNodeOrPdfFrame(frame(), node_to_print_))
+ return;
+
blink::WebView* web_view = frame_.GetFrame()->View();
web_view->Resize(prev_view_size_);
if (blink::WebFrame* web_frame = web_view->MainFrame()) {
@@ -912,24 +950,25 @@ void PrepareFrameAndViewForPrint::FinishPrinting() {
on_ready_.Reset();
}
-bool PrintWebViewHelper::Delegate::IsAskPrintSettingsEnabled() {
+bool PrintRenderFrameHelper::Delegate::IsAskPrintSettingsEnabled() {
return true;
}
-bool PrintWebViewHelper::Delegate::IsScriptedPrintEnabled() {
+bool PrintRenderFrameHelper::Delegate::IsScriptedPrintEnabled() {
return true;
}
#if defined(OS_MACOSX)
-bool PrintWebViewHelper::Delegate::UseSingleMetafile() {
+bool PrintRenderFrameHelper::Delegate::UseSingleMetafile() {
return false;
}
#endif
-PrintWebViewHelper::PrintWebViewHelper(content::RenderFrame* render_frame,
- std::unique_ptr<Delegate> delegate)
+PrintRenderFrameHelper::PrintRenderFrameHelper(
+ content::RenderFrame* render_frame,
+ std::unique_ptr<Delegate> delegate)
: content::RenderFrameObserver(render_frame),
- content::RenderFrameObserverTracker<PrintWebViewHelper>(render_frame),
+ content::RenderFrameObserverTracker<PrintRenderFrameHelper>(render_frame),
reset_prep_frame_view_(false),
is_print_ready_metafile_sent_(false),
ignore_css_margins_(false),
@@ -947,15 +986,14 @@ PrintWebViewHelper::PrintWebViewHelper(content::RenderFrame* render_frame,
DisablePreview();
}
-PrintWebViewHelper::~PrintWebViewHelper() {
-}
+PrintRenderFrameHelper::~PrintRenderFrameHelper() {}
// static
-void PrintWebViewHelper::DisablePreview() {
+void PrintRenderFrameHelper::DisablePreview() {
g_is_preview_enabled = false;
}
-bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
+bool PrintRenderFrameHelper::IsScriptInitiatedPrintAllowed(
blink::WebLocalFrame* frame,
bool user_initiated) {
if (!is_printing_enabled_ || !delegate_->IsScriptedPrintEnabled())
@@ -969,17 +1007,17 @@ bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed(
scripting_throttler_.IsAllowed(frame);
}
-void PrintWebViewHelper::DidStartProvisionalLoad(
- blink::WebDataSource* data_source) {
+void PrintRenderFrameHelper::DidStartProvisionalLoad(
+ blink::WebDocumentLoader* document_loader) {
is_loading_ = true;
}
-void PrintWebViewHelper::DidFailProvisionalLoad(
+void PrintRenderFrameHelper::DidFailProvisionalLoad(
const blink::WebURLError& error) {
DidFinishLoad();
}
-void PrintWebViewHelper::DidFinishLoad() {
+void PrintRenderFrameHelper::DidFinishLoad() {
is_loading_ = false;
if (!on_stop_loading_closure_.is_null()) {
on_stop_loading_closure_.Run();
@@ -987,7 +1025,7 @@ void PrintWebViewHelper::DidFinishLoad() {
}
}
-void PrintWebViewHelper::ScriptedPrint(bool user_initiated) {
+void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
// Allow Prerendering to cancel this print request if necessary.
if (delegate_->CancelPrerender(render_frame()))
return;
@@ -1013,7 +1051,7 @@ void PrintWebViewHelper::ScriptedPrint(bool user_initiated) {
// just return.
}
-bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
+bool PrintRenderFrameHelper::OnMessageReceived(const IPC::Message& message) {
// The class is not designed to handle recursive messages. This is not
// expected during regular flow. However, during rendering of content for
// printing, lower level code may run nested run loop. E.g. PDF may has
@@ -1024,7 +1062,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
++ipc_nesting_level_;
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
+ IPC_BEGIN_MESSAGE_MAP(PrintRenderFrameHelper, message)
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog)
@@ -1047,7 +1085,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void PrintWebViewHelper::OnDestruct() {
+void PrintRenderFrameHelper::OnDestruct() {
if (ipc_nesting_level_ > 0) {
render_frame_gone_ = true;
return;
@@ -1056,8 +1094,8 @@ void PrintWebViewHelper::OnDestruct() {
}
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::OnPrintPages() {
- if (ipc_nesting_level_> 1)
+void PrintRenderFrameHelper::OnPrintPages() {
+ if (ipc_nesting_level_ > 1)
return;
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
@@ -1070,8 +1108,8 @@ void PrintWebViewHelper::OnPrintPages() {
// just return.
}
-void PrintWebViewHelper::OnPrintForSystemDialog() {
- if (ipc_nesting_level_> 1)
+void PrintRenderFrameHelper::OnPrintForSystemDialog() {
+ if (ipc_nesting_level_ > 1)
return;
blink::WebLocalFrame* frame = print_preview_context_.source_frame();
if (!frame) {
@@ -1085,7 +1123,7 @@ void PrintWebViewHelper::OnPrintForSystemDialog() {
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if BUILDFLAG(ENABLE_BASIC_PRINTING) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::OnPrintForPrintPreview(
+void PrintRenderFrameHelper::OnPrintForPrintPreview(
const base::DictionaryValue& job_settings) {
CHECK_LE(ipc_nesting_level_, 1);
// If still not finished with earlier print request simply ignore.
@@ -1146,7 +1184,7 @@ void PrintWebViewHelper::OnPrintForPrintPreview(
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
+void PrintRenderFrameHelper::GetPageSizeAndContentAreaFromPageLayout(
const PageSizeMargins& page_layout_in_points,
gfx::Size* page_size,
gfx::Rect* content_area) {
@@ -1161,7 +1199,7 @@ void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout(
page_layout_in_points.content_height);
}
-void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
+void PrintRenderFrameHelper::UpdateFrameMarginsCssInfo(
const base::DictionaryValue& settings) {
int margins_type = 0;
if (!settings.GetInteger(kSettingMarginsType, &margins_type))
@@ -1170,7 +1208,8 @@ void PrintWebViewHelper::UpdateFrameMarginsCssInfo(
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) {
+void PrintRenderFrameHelper::OnPrintPreview(
+ const base::DictionaryValue& settings) {
if (ipc_nesting_level_ > 1)
return;
@@ -1217,7 +1256,7 @@ void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) {
PrepareFrameForPreviewDocument();
}
-void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
+void PrintRenderFrameHelper::PrepareFrameForPreviewDocument() {
reset_prep_frame_view_ = false;
if (!print_pages_params_ || CheckForCancel()) {
@@ -1238,11 +1277,11 @@ void PrintWebViewHelper::PrepareFrameForPreviewDocument() {
print_preview_context_.source_node(), ignore_css_margins_);
prep_frame_view_->CopySelectionIfNeeded(
render_frame()->GetWebkitPreferences(),
- base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument,
+ base::Bind(&PrintRenderFrameHelper::OnFramePreparedForPreviewDocument,
weak_ptr_factory_.GetWeakPtr()));
}
-void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
+void PrintRenderFrameHelper::OnFramePreparedForPreviewDocument() {
if (reset_prep_frame_view_) {
PrepareFrameForPreviewDocument();
return;
@@ -1250,7 +1289,7 @@ void PrintWebViewHelper::OnFramePreparedForPreviewDocument() {
DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW);
}
-bool PrintWebViewHelper::CreatePreviewDocument() {
+bool PrintRenderFrameHelper::CreatePreviewDocument() {
if (!print_pages_params_ || CheckForCancel())
return false;
@@ -1260,8 +1299,8 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
const PrintMsg_Print_Params& print_params = print_pages_params_->params;
const std::vector<int>& pages = print_pages_params_->pages;
- if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(),
- pages)) {
+ if (!print_preview_context_.CreatePreviewDocument(
+ std::move(prep_frame_view_), pages, print_params.printed_doc_type)) {
return false;
}
@@ -1316,10 +1355,9 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
}
int fit_to_page_scaling = static_cast<int>(100.0f * fit_to_page_scale_factor);
// Margins: Send default page layout to browser process.
- Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
- default_page_layout,
- printable_area_in_points,
- has_page_size_style));
+ Send(new PrintHostMsg_DidGetDefaultPageLayout(
+ routing_id(), default_page_layout, printable_area_in_points,
+ has_page_size_style));
PrintHostMsg_DidGetPreviewPageCount_Params params;
params.page_count = print_preview_context_.total_page_count();
@@ -1362,13 +1400,14 @@ bool PrintWebViewHelper::CreatePreviewDocument() {
}
#if !defined(OS_MACOSX) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
-bool PrintWebViewHelper::RenderPreviewPage(
+bool PrintRenderFrameHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
std::unique_ptr<PdfMetafileSkia> draft_metafile;
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
- draft_metafile = base::MakeUnique<PdfMetafileSkia>(PDF_SKIA_DOCUMENT_TYPE);
+ draft_metafile =
+ base::MakeUnique<PdfMetafileSkia>(print_params.printed_doc_type);
initial_render_metafile = draft_metafile.get();
}
@@ -1377,8 +1416,8 @@ bool PrintWebViewHelper::RenderPreviewPage(
print_preview_context_.total_page_count(),
print_preview_context_.prepared_frame(),
initial_render_metafile, nullptr, nullptr, nullptr);
- print_preview_context_.RenderedPreviewPage(
- base::TimeTicks::Now() - begin_time);
+ print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
+ begin_time);
if (draft_metafile.get()) {
draft_metafile->FinishDocument();
} else if (print_preview_context_.IsModifiable() &&
@@ -1386,22 +1425,21 @@ bool PrintWebViewHelper::RenderPreviewPage(
DCHECK(!draft_metafile.get());
draft_metafile =
print_preview_context_.metafile()->GetMetafileForCurrentPage(
- PDF_SKIA_DOCUMENT_TYPE);
+ print_params.printed_doc_type);
}
return PreviewPageRendered(page_number, draft_metafile.get());
}
#endif // !defined(OS_MACOSX) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
-bool PrintWebViewHelper::FinalizePrintReadyDocument() {
+bool PrintRenderFrameHelper::FinalizePrintReadyDocument() {
DCHECK(!is_print_ready_metafile_sent_);
print_preview_context_.FinalizePrintReadyDocument();
PdfMetafileSkia* metafile = print_preview_context_.metafile();
PrintHostMsg_DidPreviewDocument_Params preview_params;
- // Ask the browser to create the shared memory for us.
if (!CopyMetafileDataToSharedMem(*metafile,
- &(preview_params.metafile_data_handle))) {
+ &preview_params.metafile_data_handle)) {
LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
return false;
@@ -1422,7 +1460,7 @@ bool PrintWebViewHelper::FinalizePrintReadyDocument() {
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::OnPrintingDone(bool success) {
+void PrintRenderFrameHelper::OnPrintingDone(bool success) {
if (ipc_nesting_level_ > 1)
return;
notify_browser_of_print_failure_ = false;
@@ -1431,12 +1469,12 @@ void PrintWebViewHelper::OnPrintingDone(bool success) {
DidFinishPrinting(success ? OK : FAIL_PRINT);
}
-void PrintWebViewHelper::OnSetPrintingEnabled(bool enabled) {
+void PrintRenderFrameHelper::OnSetPrintingEnabled(bool enabled) {
is_printing_enabled_ = enabled;
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::OnInitiatePrintPreview(bool has_selection) {
+void PrintRenderFrameHelper::OnInitiatePrintPreview(bool has_selection) {
if (ipc_nesting_level_ > 1)
return;
@@ -1456,11 +1494,11 @@ void PrintWebViewHelper::OnInitiatePrintPreview(bool has_selection) {
}
#endif
-bool PrintWebViewHelper::IsPrintingEnabled() const {
+bool PrintRenderFrameHelper::IsPrintingEnabled() const {
return is_printing_enabled_;
}
-void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
+void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
if (node.IsNull() || !node.GetDocument().GetFrame()) {
// This can occur when the context menu refers to an invalid WebNode.
// See http://crbug.com/100890#c17 for a repro case.
@@ -1500,9 +1538,9 @@ void PrintWebViewHelper::PrintNode(const blink::WebNode& node) {
}
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::Print(blink::WebLocalFrame* frame,
- const blink::WebNode& node,
- bool is_scripted) {
+void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ bool is_scripted) {
// If still not finished with earlier print request simply ignore.
if (prep_frame_view_)
return;
@@ -1553,7 +1591,7 @@ void PrintWebViewHelper::Print(blink::WebLocalFrame* frame,
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
+void PrintRenderFrameHelper::DidFinishPrinting(PrintingResult result) {
int cookie =
print_pages_params_ ? print_pages_params_->params.document_cookie : 0;
switch (result) {
@@ -1595,12 +1633,12 @@ void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
}
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::OnFramePreparedForPrintPages() {
+void PrintRenderFrameHelper::OnFramePreparedForPrintPages() {
PrintPages();
FinishFramePrinting();
}
-void PrintWebViewHelper::PrintPages() {
+void PrintRenderFrameHelper::PrintPages() {
if (!prep_frame_view_) // Printing is already canceled or failed.
return;
@@ -1618,9 +1656,8 @@ void PrintWebViewHelper::PrintPages() {
#if !defined(OS_ANDROID)
// TODO(vitalybuka): should be page_count or valid pages from params.pages.
// See http://crbug.com/161576
- Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
- print_params.document_cookie,
- page_count));
+ Send(new PrintHostMsg_DidGetPrintedPagesCount(
+ routing_id(), print_params.document_cookie, page_count));
#endif // !defined(OS_ANDROID)
if (print_params.preview_ui_id < 0) {
@@ -1635,13 +1672,13 @@ void PrintWebViewHelper::PrintPages() {
}
}
-void PrintWebViewHelper::FinishFramePrinting() {
+void PrintRenderFrameHelper::FinishFramePrinting() {
prep_frame_view_.reset();
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// static - Not anonymous so that platform implementations can use it.
-void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
+void PrintRenderFrameHelper::ComputePageLayoutInPointsForCss(
blink::WebLocalFrame* frame,
int page_index,
const PrintMsg_Print_Params& page_params,
@@ -1657,7 +1694,7 @@ void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
}
// static - Not anonymous so that platform implementations can use it.
-std::vector<int> PrintWebViewHelper::GetPrintedPages(
+std::vector<int> PrintRenderFrameHelper::GetPrintedPages(
const PrintMsg_PrintPages_Params& params,
int page_count) {
std::vector<int> printed_pages;
@@ -1675,7 +1712,7 @@ std::vector<int> PrintWebViewHelper::GetPrintedPages(
return printed_pages;
}
-bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
+bool PrintRenderFrameHelper::InitPrintSettings(bool fit_to_paper_size) {
PrintMsg_PrintPages_Params settings;
Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
&settings.params));
@@ -1701,9 +1738,9 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) {
return result;
}
-bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
- const blink::WebNode& node,
- int* number_of_pages) {
+bool PrintRenderFrameHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ int* number_of_pages) {
DCHECK(frame);
bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node));
if (!InitPrintSettings(fit_to_paper_size)) {
@@ -1721,7 +1758,7 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-bool PrintWebViewHelper::SetOptionsFromPdfDocument(
+bool PrintRenderFrameHelper::SetOptionsFromPdfDocument(
PrintHostMsg_SetOptionsFromDocument_Params* options) {
blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
const blink::WebNode& source_node = print_preview_context_.source_node();
@@ -1752,7 +1789,7 @@ bool PrintWebViewHelper::SetOptionsFromPdfDocument(
return true;
}
-bool PrintWebViewHelper::UpdatePrintSettings(
+bool PrintRenderFrameHelper::UpdatePrintSettings(
blink::WebLocalFrame* frame,
const blink::WebNode& node,
const base::DictionaryValue& passed_job_settings) {
@@ -1830,7 +1867,7 @@ bool PrintWebViewHelper::UpdatePrintSettings(
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::GetPrintSettingsFromUser(
+void PrintRenderFrameHelper::GetPrintSettingsFromUser(
blink::WebLocalFrame* frame,
const blink::WebNode& node,
int expected_pages_count,
@@ -1851,16 +1888,16 @@ void PrintWebViewHelper::GetPrintSettingsFromUser(
print_pages_params_.reset();
- auto msg = base::MakeUnique<PrintHostMsg_ScriptedPrint>(
- routing_id(), params, print_settings);
+ auto msg = base::MakeUnique<PrintHostMsg_ScriptedPrint>(routing_id(), params,
+ print_settings);
msg->EnableMessagePumping();
Send(msg.release());
// WARNING: |this| may be gone at this point. Do not do any more work here
// and just return.
}
-bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
- const blink::WebNode& node) {
+bool PrintRenderFrameHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
+ const blink::WebNode& node) {
if (!frame || prep_frame_view_)
return false;
@@ -1872,21 +1909,22 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
print_pages_params_->pages.empty());
prep_frame_view_->CopySelectionIfNeeded(
render_frame()->GetWebkitPreferences(),
- base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages,
+ base::Bind(&PrintRenderFrameHelper::OnFramePreparedForPrintPages,
weak_ptr_factory_.GetWeakPtr()));
return true;
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if !defined(OS_MACOSX)
-void PrintWebViewHelper::PrintPageInternal(const PrintMsg_Print_Params& params,
- int page_number,
- int page_count,
- blink::WebLocalFrame* frame,
- PdfMetafileSkia* metafile,
- gfx::Size* page_size_in_dpi,
- gfx::Rect* content_area_in_dpi,
- gfx::Rect* printable_area_in_dpi) {
+void PrintRenderFrameHelper::PrintPageInternal(
+ const PrintMsg_Print_Params& params,
+ int page_number,
+ int page_count,
+ blink::WebLocalFrame* frame,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size_in_dpi,
+ gfx::Rect* content_area_in_dpi,
+ gfx::Rect* printable_area_in_dpi) {
PageSizeMargins page_layout_in_points;
double css_scale_factor = 1.0f;
@@ -1962,7 +2000,7 @@ void PrintWebViewHelper::PrintPageInternal(const PrintMsg_Print_Params& params,
}
#endif // !defined(OS_MACOSX)
-bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
+bool PrintRenderFrameHelper::CopyMetafileDataToSharedMem(
const PdfMetafileSkia& metafile,
base::SharedMemoryHandle* shared_mem_handle) {
uint32_t buf_size = metafile.GetDataSize();
@@ -1986,7 +2024,7 @@ bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::ShowScriptedPrintPreview() {
+void PrintRenderFrameHelper::ShowScriptedPrintPreview() {
if (is_scripted_preview_delayed_) {
is_scripted_preview_delayed_ = false;
Send(new PrintHostMsg_ShowScriptedPrintPreview(
@@ -1994,7 +2032,7 @@ void PrintWebViewHelper::ShowScriptedPrintPreview() {
}
}
-void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
+void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
const bool is_modifiable = print_preview_context_.IsModifiable();
const bool has_selection = print_preview_context_.HasSelection();
PrintHostMsg_RequestPrintPreview_Params params;
@@ -2013,12 +2051,13 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
// |is_modifiable| value until they are fully loaded, which occurs when
// DidStopLoading() is called. Defer showing the preview until then.
on_stop_loading_closure_ =
- base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
+ base::Bind(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
weak_ptr_factory_.GetWeakPtr());
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview,
- weak_ptr_factory_.GetWeakPtr()));
+ FROM_HERE,
+ base::Bind(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
+ weak_ptr_factory_.GetWeakPtr()));
}
auto msg = base::MakeUnique<PrintHostMsg_SetupScriptedPrintPreview>(
routing_id());
@@ -2036,7 +2075,7 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
// print a PDF document.
if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
on_stop_loading_closure_ =
- base::Bind(&PrintWebViewHelper::RequestPrintPreview,
+ base::Bind(&PrintRenderFrameHelper::RequestPrintPreview,
weak_ptr_factory_.GetWeakPtr(), type);
return;
}
@@ -2052,7 +2091,7 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
on_stop_loading_closure_ =
- base::Bind(&PrintWebViewHelper::RequestPrintPreview,
+ base::Bind(&PrintRenderFrameHelper::RequestPrintPreview,
weak_ptr_factory_.GetWeakPtr(), type);
return;
}
@@ -2068,11 +2107,10 @@ void PrintWebViewHelper::RequestPrintPreview(PrintPreviewRequestType type) {
Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params));
}
-bool PrintWebViewHelper::CheckForCancel() {
+bool PrintRenderFrameHelper::CheckForCancel() {
const PrintMsg_Print_Params& print_params = print_pages_params_->params;
bool cancel = false;
- Send(new PrintHostMsg_CheckForCancel(routing_id(),
- print_params.preview_ui_id,
+ Send(new PrintHostMsg_CheckForCancel(routing_id(), print_params.preview_ui_id,
print_params.preview_request_id,
&cancel));
if (cancel)
@@ -2080,8 +2118,8 @@ bool PrintWebViewHelper::CheckForCancel() {
return cancel;
}
-bool PrintWebViewHelper::PreviewPageRendered(int page_number,
- PdfMetafileSkia* metafile) {
+bool PrintRenderFrameHelper::PreviewPageRendered(int page_number,
+ PdfMetafileSkia* metafile) {
DCHECK_GE(page_number, FIRST_PAGE_INDEX);
// For non-modifiable files, |metafile| should be NULL, so do not bother
@@ -2101,13 +2139,13 @@ bool PrintWebViewHelper::PreviewPageRendered(int page_number,
}
PrintHostMsg_DidPreviewPage_Params preview_page_params;
- // Get the size of the resulting metafile.
- if (!CopyMetafileDataToSharedMem(
- *metafile, &(preview_page_params.metafile_data_handle))) {
+ if (!CopyMetafileDataToSharedMem(*metafile,
+ &preview_page_params.metafile_data_handle)) {
LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
return false;
}
+
preview_page_params.data_size = metafile->GetDataSize();
preview_page_params.page_number = page_number;
preview_page_params.preview_request_id =
@@ -2118,7 +2156,7 @@ bool PrintWebViewHelper::PreviewPageRendered(int page_number,
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
-PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
+PrintRenderFrameHelper::PrintPreviewContext::PrintPreviewContext()
: total_page_count_(0),
current_page_index_(0),
generate_draft_pages_(true),
@@ -2127,10 +2165,9 @@ PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
error_(PREVIEW_ERROR_NONE),
state_(UNINITIALIZED) {}
-PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
-}
+PrintRenderFrameHelper::PrintPreviewContext::~PrintPreviewContext() {}
-void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
+void PrintRenderFrameHelper::PrintPreviewContext::InitWithFrame(
blink::WebLocalFrame* web_frame) {
DCHECK(web_frame);
DCHECK(!IsRendering());
@@ -2140,7 +2177,7 @@ void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
CalculateIsModifiable();
}
-void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
+void PrintRenderFrameHelper::PrintPreviewContext::InitWithNode(
const blink::WebNode& web_node) {
DCHECK(!web_node.IsNull());
DCHECK(web_node.GetDocument().GetFrame());
@@ -2151,19 +2188,20 @@ void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
CalculateIsModifiable();
}
-void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
+void PrintRenderFrameHelper::PrintPreviewContext::OnPrintPreview() {
DCHECK_EQ(INITIALIZED, state_);
ClearContext();
}
-bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
- PrepareFrameAndViewForPrint* prepared_frame,
- const std::vector<int>& pages) {
+bool PrintRenderFrameHelper::PrintPreviewContext::CreatePreviewDocument(
+ std::unique_ptr<PrepareFrameAndViewForPrint> prepared_frame,
+ const std::vector<int>& pages,
+ SkiaDocumentType doc_type) {
DCHECK_EQ(INITIALIZED, state_);
state_ = RENDERING;
// Need to make sure old object gets destroyed first.
- prep_frame_view_.reset(prepared_frame);
+ prep_frame_view_ = std::move(prepared_frame);
prep_frame_view_->StartPrinting();
total_page_count_ = prep_frame_view_->GetExpectedPageCount();
@@ -2173,7 +2211,7 @@ bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
return false;
}
- metafile_ = base::MakeUnique<PdfMetafileSkia>(PDF_SKIA_DOCUMENT_TYPE);
+ metafile_ = base::MakeUnique<PdfMetafileSkia>(doc_type);
CHECK(metafile_->Init());
current_page_index_ = 0;
@@ -2212,20 +2250,20 @@ bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument(
return true;
}
-void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
+void PrintRenderFrameHelper::PrintPreviewContext::RenderedPreviewPage(
const base::TimeDelta& page_time) {
DCHECK_EQ(RENDERING, state_);
document_render_time_ += page_time;
UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
}
-void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() {
+void PrintRenderFrameHelper::PrintPreviewContext::AllPagesRendered() {
DCHECK_EQ(RENDERING, state_);
state_ = DONE;
prep_frame_view_->FinishPrinting();
}
-void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
+void PrintRenderFrameHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
DCHECK(IsRendering());
base::TimeTicks begin_time = base::TimeTicks::Now();
@@ -2246,13 +2284,13 @@ void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
total_time / pages_to_render_.size());
}
-void PrintWebViewHelper::PrintPreviewContext::Finished() {
+void PrintRenderFrameHelper::PrintPreviewContext::Finished() {
DCHECK_EQ(DONE, state_);
state_ = INITIALIZED;
ClearContext();
}
-void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
+void PrintRenderFrameHelper::PrintPreviewContext::Failed(bool report_error) {
DCHECK(state_ == INITIALIZED || state_ == RENDERING);
state_ = INITIALIZED;
if (report_error) {
@@ -2263,112 +2301,112 @@ void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
ClearContext();
}
-int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
+int PrintRenderFrameHelper::PrintPreviewContext::GetNextPageNumber() {
DCHECK_EQ(RENDERING, state_);
if (IsFinalPageRendered())
return -1;
return pages_to_render_[current_page_index_++];
}
-bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
+bool PrintRenderFrameHelper::PrintPreviewContext::IsRendering() const {
return state_ == RENDERING || state_ == DONE;
}
-bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const {
+bool PrintRenderFrameHelper::PrintPreviewContext::IsModifiable() const {
DCHECK(state_ != UNINITIALIZED);
return is_modifiable_;
}
-bool PrintWebViewHelper::PrintPreviewContext::HasSelection() {
+bool PrintRenderFrameHelper::PrintPreviewContext::HasSelection() {
return IsModifiable() && source_frame()->HasSelection();
}
-bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
- const {
+bool PrintRenderFrameHelper::PrintPreviewContext::
+ IsLastPageOfPrintReadyMetafile() const {
DCHECK(IsRendering());
return current_page_index_ == print_ready_metafile_page_count_;
}
-bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
+bool PrintRenderFrameHelper::PrintPreviewContext::IsFinalPageRendered() const {
DCHECK(IsRendering());
return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
}
-void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
+void PrintRenderFrameHelper::PrintPreviewContext::set_generate_draft_pages(
bool generate_draft_pages) {
DCHECK_EQ(INITIALIZED, state_);
generate_draft_pages_ = generate_draft_pages;
}
-void PrintWebViewHelper::PrintPreviewContext::set_error(
+void PrintRenderFrameHelper::PrintPreviewContext::set_error(
enum PrintPreviewErrorBuckets error) {
error_ = error;
}
-blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() {
+blink::WebLocalFrame*
+PrintRenderFrameHelper::PrintPreviewContext::source_frame() {
DCHECK(state_ != UNINITIALIZED);
return source_frame_.GetFrame();
}
-const blink::WebNode&
- PrintWebViewHelper::PrintPreviewContext::source_node() const {
+const blink::WebNode& PrintRenderFrameHelper::PrintPreviewContext::source_node()
+ const {
DCHECK(state_ != UNINITIALIZED);
return source_node_;
}
blink::WebLocalFrame*
-PrintWebViewHelper::PrintPreviewContext::prepared_frame() {
+PrintRenderFrameHelper::PrintPreviewContext::prepared_frame() {
DCHECK(state_ != UNINITIALIZED);
return prep_frame_view_->frame();
}
const blink::WebNode&
- PrintWebViewHelper::PrintPreviewContext::prepared_node() const {
+PrintRenderFrameHelper::PrintPreviewContext::prepared_node() const {
DCHECK(state_ != UNINITIALIZED);
return prep_frame_view_->node();
}
-int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
+int PrintRenderFrameHelper::PrintPreviewContext::total_page_count() const {
DCHECK(state_ != UNINITIALIZED);
return total_page_count_;
}
-bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const {
+bool PrintRenderFrameHelper::PrintPreviewContext::generate_draft_pages() const {
return generate_draft_pages_;
}
-PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() {
+PdfMetafileSkia* PrintRenderFrameHelper::PrintPreviewContext::metafile() {
DCHECK(IsRendering());
return metafile_.get();
}
-int PrintWebViewHelper::PrintPreviewContext::last_error() const {
+int PrintRenderFrameHelper::PrintPreviewContext::last_error() const {
return error_;
}
-void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
+void PrintRenderFrameHelper::PrintPreviewContext::ClearContext() {
prep_frame_view_.reset();
metafile_.reset();
pages_to_render_.clear();
error_ = PREVIEW_ERROR_NONE;
}
-void PrintWebViewHelper::PrintPreviewContext::CalculateIsModifiable() {
+void PrintRenderFrameHelper::PrintPreviewContext::CalculateIsModifiable() {
// The only kind of node we can print right now is a PDF node.
is_modifiable_ = !PrintingNodeOrPdfFrame(source_frame(), source_node_);
}
-void PrintWebViewHelper::SetPrintPagesParams(
+void PrintRenderFrameHelper::SetPrintPagesParams(
const PrintMsg_PrintPages_Params& settings) {
print_pages_params_ = base::MakeUnique<PrintMsg_PrintPages_Params>(settings);
Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
settings.params.document_cookie));
}
-PrintWebViewHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {
-}
+PrintRenderFrameHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {}
-bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(
+bool PrintRenderFrameHelper::ScriptingThrottler::IsAllowed(
blink::WebLocalFrame* frame) {
const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32;
@@ -2406,7 +2444,7 @@ bool PrintWebViewHelper::ScriptingThrottler::IsAllowed(
return false;
}
-void PrintWebViewHelper::ScriptingThrottler::Reset() {
+void PrintRenderFrameHelper::ScriptingThrottler::Reset() {
// Reset counter on successful print.
count_ = 0;
}
diff --git a/chromium/components/printing/renderer/print_web_view_helper.h b/chromium/components/printing/renderer/print_render_frame_helper.h
index fc5e9648a33..6a52cd8bb78 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.h
+++ b/chromium/components/printing/renderer/print_render_frame_helper.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_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
-#define COMPONENTS_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
+#ifndef COMPONENTS_PRINTING_RENDERER_PRINT_RENDER_FRAME_HELPER_H_
+#define COMPONENTS_PRINTING_RENDERER_PRINT_RENDER_FRAME_HELPER_H_
#include <memory>
#include <vector>
@@ -31,12 +31,13 @@ struct PrintHostMsg_SetOptionsFromDocument_Params;
// RenderViewTest-based tests crash on Android
// http://crbug.com/187500
#if defined(OS_ANDROID)
-#define MAYBE_PrintWebViewHelperTest DISABLED_PrintWebViewHelperTest
-#define MAYBE_PrintWebViewHelperPreviewTest \
- DISABLED_PrintWebViewHelperPreviewTest
+#define MAYBE_PrintRenderFrameHelperTest DISABLED_PrintRenderFrameHelperTest
+#define MAYBE_PrintRenderFrameHelperPreviewTest \
+ DISABLED_PrintRenderFrameHelperPreviewTest
#else
-#define MAYBE_PrintWebViewHelperTest PrintWebViewHelperTest
-#define MAYBE_PrintWebViewHelperPreviewTest PrintWebViewHelperPreviewTest
+#define MAYBE_PrintRenderFrameHelperTest PrintRenderFrameHelperTest
+#define MAYBE_PrintRenderFrameHelperPreviewTest \
+ PrintRenderFrameHelperPreviewTest
#endif // defined(OS_ANDROID)
namespace base {
@@ -55,7 +56,10 @@ class PrepareFrameAndViewForPrint;
// Stores reference to frame using WebVew and unique name.
// Workaround to modal dialog issue on Linux. crbug.com/236147.
-// If WebFrame someday supports WeakPtr, we should use it here.
+// TODO(dcheng): Try to get rid of this class. However, it's a bit tricky due to
+// PrepareFrameAndViewForPrint sometimes pointing to a WebLocalFrame associated
+// with a RenderFrame and sometimes pointing to an internally allocated
+// WebLocalFrame...
class FrameReference {
public:
explicit FrameReference(blink::WebLocalFrame* frame);
@@ -74,12 +78,12 @@ class FrameReference {
DISALLOW_COPY_AND_ASSIGN(FrameReference);
};
-// PrintWebViewHelper handles most of the printing grunt work for RenderView.
-// We plan on making print asynchronous and that will require copying the DOM
-// of the document and creating a new WebView with the contents.
-class PrintWebViewHelper
+// PrintRenderFrameHelper handles most of the printing grunt work for
+// RenderView. We plan on making print asynchronous and that will require
+// copying the DOM of the document and creating a new WebView with the contents.
+class PrintRenderFrameHelper
: public content::RenderFrameObserver,
- public content::RenderFrameObserverTracker<PrintWebViewHelper> {
+ public content::RenderFrameObserverTracker<PrintRenderFrameHelper> {
public:
class Delegate {
public:
@@ -117,9 +121,9 @@ class PrintWebViewHelper
#endif
};
- PrintWebViewHelper(content::RenderFrame* render_frame,
- std::unique_ptr<Delegate> delegate);
- ~PrintWebViewHelper() override;
+ PrintRenderFrameHelper(content::RenderFrame* render_frame,
+ std::unique_ptr<Delegate> delegate);
+ ~PrintRenderFrameHelper() override;
// Minimum valid value for scaling. Since scaling is originally an integer
// representing a percentage, it should never be less than this if it is
@@ -135,17 +139,17 @@ class PrintWebViewHelper
void PrintNode(const blink::WebNode& node);
private:
- friend class PrintWebViewHelperTestBase;
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperPreviewTest,
+ friend class PrintRenderFrameHelperTestBase;
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperPreviewTest,
BlockScriptInitiatedPrinting);
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperTest, OnPrintPages);
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperTest,
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest, OnPrintPages);
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest,
BlockScriptInitiatedPrinting);
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperTest,
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest,
BlockScriptInitiatedPrintingFromPopup);
#if defined(OS_WIN) || defined(OS_MACOSX)
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperTest, PrintLayoutTest);
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintWebViewHelperTest, PrintWithIframe);
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest, PrintLayoutTest);
+ FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest, PrintWithIframe);
#endif // defined(OS_WIN) || defined(OS_MACOSX)
enum PrintingResult {
@@ -179,7 +183,8 @@ class PrintWebViewHelper
// RenderFrameObserver implementation.
void OnDestruct() override;
- void DidStartProvisionalLoad(blink::WebDataSource* data_source) override;
+ void DidStartProvisionalLoad(
+ blink::WebDocumentLoader* document_loader) override;
void DidFailProvisionalLoad(const blink::WebURLError& error) override;
void DidFinishLoad() override;
void ScriptedPrint(bool user_initiated) override;
@@ -270,12 +275,11 @@ class PrintWebViewHelper
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
// Get final print settings from the user.
// WARNING: |this| may be gone after this method returns.
- void GetPrintSettingsFromUser(
- blink::WebLocalFrame* frame,
- const blink::WebNode& node,
- int expected_pages_count,
- bool is_scripted,
- PrintMsg_PrintPages_Params* print_settings);
+ void GetPrintSettingsFromUser(blink::WebLocalFrame* frame,
+ const blink::WebNode& node,
+ int expected_pages_count,
+ bool is_scripted,
+ PrintMsg_PrintPages_Params* print_settings);
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// Page Printing / Rendering ------------------------------------------------
@@ -349,8 +353,11 @@ class PrintWebViewHelper
const PrintMsg_PrintPages_Params& params,
int page_count);
- // Given the |canvas| to draw on, prints the appropriate headers and footers
- // to |canvas| using information from the remaining parameters.
+ // Helper function to find document type.
+ static SkiaDocumentType GetDocType(const PrintMsg_Print_Params& params);
+
+ // Given the |device| and |canvas| to draw on, prints the appropriate headers
+ // and footers using strings from |header_footer_info| on to the canvas.
static void PrintHeaderAndFooter(blink::WebCanvas* canvas,
int page_number,
int total_pages,
@@ -427,9 +434,10 @@ class PrintWebViewHelper
void OnPrintPreview();
// Create the print preview document. |pages| is empty to print all pages.
- // Takes ownership of |prepared_frame|.
- bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame,
- const std::vector<int>& pages);
+ bool CreatePreviewDocument(
+ std::unique_ptr<PrepareFrameAndViewForPrint> prepared_frame,
+ const std::vector<int>& pages,
+ SkiaDocumentType doc_type);
// Called after a page gets rendered. |page_time| is how long the
// rendering took.
@@ -557,11 +565,11 @@ class PrintWebViewHelper
// parameters so that it can be invoked after DidStopLoading.
base::Closure on_stop_loading_closure_;
- base::WeakPtrFactory<PrintWebViewHelper> weak_ptr_factory_;
+ base::WeakPtrFactory<PrintRenderFrameHelper> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper);
+ DISALLOW_COPY_AND_ASSIGN(PrintRenderFrameHelper);
};
} // namespace printing
-#endif // COMPONENTS_PRINTING_RENDERER_PRINT_WEB_VIEW_HELPER_H_
+#endif // COMPONENTS_PRINTING_RENDERER_PRINT_RENDER_FRAME_HELPER_H_
diff --git a/chromium/components/printing/renderer/print_web_view_helper_android.cc b/chromium/components/printing/renderer/print_render_frame_helper_android.cc
index c5e4e4a68cf..93c43822921 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_android.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper_android.cc
@@ -2,6 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// All the necessary logic already lives in print_web_view_helper_linux.cc.
+// All the necessary logic already lives in print_render_frame_helper_linux.cc.
// We need a separate file for Android due to build/filename_rules.gypi rules.
-#include "components/printing/renderer/print_web_view_helper_linux.cc"
+#include "components/printing/renderer/print_render_frame_helper_linux.cc"
diff --git a/chromium/components/printing/renderer/print_web_view_helper_linux.cc b/chromium/components/printing/renderer/print_render_frame_helper_linux.cc
index 024ff6a1755..f5ae4cdcfe3 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper_linux.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/printing/renderer/print_web_view_helper.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
#include <stddef.h>
@@ -44,12 +44,13 @@ bool SaveToFD(const printing::Metafile& metafile,
namespace printing {
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
- int page_count) {
- PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
+bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
+ int page_count) {
+ const PrintMsg_PrintPages_Params& params = *print_pages_params_;
+ const PrintMsg_Print_Params& print_params = params.params;
+ PdfMetafileSkia metafile(print_params.printed_doc_type);
CHECK(metafile.Init());
- const PrintMsg_PrintPages_Params& params = *print_pages_params_;
std::vector<int> printed_pages = GetPrintedPages(params, page_count);
if (printed_pages.empty())
return false;
@@ -69,8 +70,7 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
base::FileDescriptor fd;
// Ask the browser to open a file for us.
- Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(),
- &fd,
+ Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(), &fd,
&sequence_number));
if (!SaveToFD(metafile, fd))
return false;
@@ -82,8 +82,8 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
#else
PrintHostMsg_DidPrintPage_Params printed_page_params;
- if (!CopyMetafileDataToSharedMem(
- metafile, &printed_page_params.metafile_data_handle)) {
+ if (!CopyMetafileDataToSharedMem(metafile,
+ &printed_page_params.metafile_data_handle)) {
return false;
}
diff --git a/chromium/components/printing/renderer/print_web_view_helper_mac.mm b/chromium/components/printing/renderer/print_render_frame_helper_mac.mm
index a00cfa0a95f..42149955ee2 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_mac.mm
+++ b/chromium/components/printing/renderer/print_render_frame_helper_mac.mm
@@ -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/printing/renderer/print_web_view_helper.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
#import <AppKit/AppKit.h>
@@ -19,8 +19,8 @@
namespace printing {
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
- int page_count) {
+bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
+ int page_count) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
@@ -40,12 +40,12 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
}
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
-void PrintWebViewHelper::PrintPagesInternal(
+void PrintRenderFrameHelper::PrintPagesInternal(
const PrintMsg_Print_Params& params,
const std::vector<int>& printed_pages,
int page_count,
blink::WebLocalFrame* frame) {
- PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
+ PdfMetafileSkia metafile(params.printed_doc_type);
CHECK(metafile.Init());
gfx::Size page_size_in_dpi;
@@ -64,7 +64,7 @@ void PrintWebViewHelper::PrintPagesInternal(
// Ask the browser to create the shared memory for us.
if (!CopyMetafileDataToSharedMem(metafile,
- &(page_params.metafile_data_handle))) {
+ &page_params.metafile_data_handle)) {
// TODO(thestig): Fail and return false instead.
page_params.data_size = 0;
}
@@ -77,30 +77,30 @@ void PrintWebViewHelper::PrintPagesInternal(
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-bool PrintWebViewHelper::RenderPreviewPage(
+bool PrintRenderFrameHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
- PrintMsg_Print_Params printParams = print_params;
std::unique_ptr<PdfMetafileSkia> draft_metafile;
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
- bool render_to_draft = print_preview_context_.IsModifiable() &&
- is_print_ready_metafile_sent_;
+ bool render_to_draft =
+ print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_;
if (render_to_draft) {
- draft_metafile.reset(new PdfMetafileSkia(PDF_SKIA_DOCUMENT_TYPE));
+ draft_metafile =
+ base::MakeUnique<PdfMetafileSkia>(print_params.printed_doc_type);
CHECK(draft_metafile->Init());
initial_render_metafile = draft_metafile.get();
}
base::TimeTicks begin_time = base::TimeTicks::Now();
gfx::Size page_size;
- RenderPage(printParams, page_number,
+ RenderPage(print_params, page_number,
print_preview_context_.total_page_count(),
print_preview_context_.prepared_frame(), true,
initial_render_metafile, &page_size, NULL);
- print_preview_context_.RenderedPreviewPage(
- base::TimeTicks::Now() - begin_time);
+ print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
+ begin_time);
if (draft_metafile.get()) {
draft_metafile->FinishDocument();
@@ -110,21 +110,21 @@ bool PrintWebViewHelper::RenderPreviewPage(
DCHECK(!draft_metafile.get());
draft_metafile =
print_preview_context_.metafile()->GetMetafileForCurrentPage(
- PDF_SKIA_DOCUMENT_TYPE);
+ print_params.printed_doc_type);
}
}
return PreviewPageRendered(page_number, draft_metafile.get());
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
-void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params,
- int page_number,
- int page_count,
- blink::WebLocalFrame* frame,
- bool is_preview,
- PdfMetafileSkia* metafile,
- gfx::Size* page_size,
- gfx::Rect* content_rect) {
+void PrintRenderFrameHelper::RenderPage(const PrintMsg_Print_Params& params,
+ int page_number,
+ int page_count,
+ blink::WebLocalFrame* frame,
+ bool is_preview,
+ PdfMetafileSkia* metafile,
+ gfx::Size* page_size,
+ gfx::Rect* content_rect) {
double scale_factor =
params.scale_factor >= kEpsilon ? params.scale_factor : 1.0f;
double webkit_shrink_factor = frame->GetPrintPageShrink(page_number);
diff --git a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc b/chromium/components/printing/renderer/print_render_frame_helper_pdf_win.cc
index d32141d81f5..a746fd9e97f 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper_pdf_win.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/printing/renderer/print_web_view_helper.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
#include <stddef.h>
@@ -15,8 +15,8 @@
namespace printing {
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
- int page_count) {
+bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
+ int page_count) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
std::vector<int> printed_pages = GetPrintedPages(params, page_count);
if (printed_pages.empty())
@@ -26,7 +26,7 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
std::vector<gfx::Rect> content_area_in_dpi(printed_pages.size());
std::vector<gfx::Rect> printable_area_in_dpi(printed_pages.size());
- PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
+ PdfMetafileSkia metafile(params.params.printed_doc_type);
CHECK(metafile.Init());
for (size_t i = 0; i < printed_pages.size(); ++i) {
@@ -41,8 +41,8 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
metafile.FinishDocument();
PrintHostMsg_DidPrintPage_Params printed_page_params;
- if (!CopyMetafileDataToSharedMem(
- metafile, &printed_page_params.metafile_data_handle)) {
+ if (!CopyMetafileDataToSharedMem(metafile,
+ &printed_page_params.metafile_data_handle)) {
return false;
}
diff --git a/chromium/components/printing/service/BUILD.gn b/chromium/components/printing/service/BUILD.gn
index 077ee2813b0..f28f1440fc0 100644
--- a/chromium/components/printing/service/BUILD.gn
+++ b/chromium/components/printing/service/BUILD.gn
@@ -4,6 +4,7 @@
import("//services/service_manager/public/cpp/service.gni")
import("//services/service_manager/public/service_manifest.gni")
+import("//services/service_manager/public/tools/test/service_test.gni")
static_library("service") {
sources = [
@@ -33,3 +34,49 @@ service_manifest("pdf_compositor_manifest") {
name = "pdf_compositor"
source = "pdf_compositor_manifest.json"
}
+
+service("pdf_compositor_test_service") {
+ testonly = true
+
+ sources = [
+ "test_service_main.cc",
+ ]
+
+ deps = [
+ ":service",
+ "//base",
+ "//base/test:test_support",
+ ]
+}
+
+service_test("pdf_compositor_service_unittest") {
+ testonly = true
+
+ sources = [
+ "pdf_compositor_service_unittest.cc",
+ ]
+
+ catalog = ":pdf_compositor_service_unittest_catalog"
+
+ include_dirs = [ "testing/gmock/include" ]
+ deps = [
+ ":pdf_compositor_test_service",
+ "//base",
+ "//components/printing/service/public/interfaces",
+ "//mojo/common",
+ "//services/service_manager/public/cpp:service_test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+service_manifest("pdf_compositor_service_unittest_manifest") {
+ name = "pdf_compositor_service_unittest"
+ source = "pdf_compositor_service_unittest_manifest.json"
+}
+
+catalog("pdf_compositor_service_unittest_catalog") {
+ testonly = true
+ embedded_services = [ ":pdf_compositor_service_unittest_manifest" ]
+ standalone_services = [ ":pdf_compositor_manifest" ]
+}
diff --git a/chromium/components/printing/service/DEPS b/chromium/components/printing/service/DEPS
index 839127983cb..e5308e2dc39 100644
--- a/chromium/components/printing/service/DEPS
+++ b/chromium/components/printing/service/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+components/discardable_memory/client",
- "+content/public/common",
"+content/public/utility",
"+mojo/public/cpp",
"+printing/common",
@@ -8,3 +7,9 @@ include_rules = [
"+skia",
"+third_party/skia",
]
+
+specific_include_rules = {
+ "test_service_main\.cc": [
+ "+services/service_manager/public/c",
+ ]
+}
diff --git a/chromium/components/printing/service/OWNERS b/chromium/components/printing/service/OWNERS
new file mode 100644
index 00000000000..c44174f6ef4
--- /dev/null
+++ b/chromium/components/printing/service/OWNERS
@@ -0,0 +1,5 @@
+per-file pdf_compositor_manifest.json=set noparent
+per-file pdf_compositor_manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file pdf_compositor_service_unittest_manifest.json=set noparent
+per-file pdf_compositor_service_unittest_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/printing/service/pdf_compositor_impl.cc b/chromium/components/printing/service/pdf_compositor_impl.cc
index c27e466ddd8..c22998a7bc9 100644
--- a/chromium/components/printing/service/pdf_compositor_impl.cc
+++ b/chromium/components/printing/service/pdf_compositor_impl.cc
@@ -43,7 +43,8 @@ void PdfCompositorImpl::CompositePdf(
base::MakeUnique<base::SharedMemory>(memory_handle, true);
if (!shm->Map(memory_size)) {
DLOG(ERROR) << "CompositePdf: Shared memory map failed.";
- std::move(callback).Run(mojo::ScopedSharedBufferHandle());
+ std::move(callback).Run(mojom::PdfCompositor::Status::HANDLE_MAP_ERROR,
+ mojo::ScopedSharedBufferHandle());
return;
}
@@ -51,14 +52,16 @@ void PdfCompositorImpl::CompositePdf(
int page_count = SkMultiPictureDocumentReadPageCount(&stream);
if (!page_count) {
DLOG(ERROR) << "CompositePdf: No page is read.";
- std::move(callback).Run(mojo::ScopedSharedBufferHandle());
+ std::move(callback).Run(mojom::PdfCompositor::Status::CONTENT_FORMAT_ERROR,
+ mojo::ScopedSharedBufferHandle());
return;
}
std::vector<SkDocumentPage> pages(page_count);
if (!SkMultiPictureDocumentRead(&stream, pages.data(), page_count)) {
DLOG(ERROR) << "CompositePdf: Page reading failed.";
- std::move(callback).Run(mojo::ScopedSharedBufferHandle());
+ std::move(callback).Run(mojom::PdfCompositor::Status::CONTENT_FORMAT_ERROR,
+ mojo::ScopedSharedBufferHandle());
return;
}
@@ -80,7 +83,8 @@ void PdfCompositorImpl::CompositePdf(
DCHECK(mapping);
wstream.copyToAndReset(mapping.get());
- std::move(callback).Run(std::move(buffer));
+ std::move(callback).Run(mojom::PdfCompositor::Status::SUCCESS,
+ std::move(buffer));
}
} // namespace printing
diff --git a/chromium/components/printing/service/pdf_compositor_manifest.json b/chromium/components/printing/service/pdf_compositor_manifest.json
index 9e9b05929d8..d7914f4c8e2 100644
--- a/chromium/components/printing/service/pdf_compositor_manifest.json
+++ b/chromium/components/printing/service/pdf_compositor_manifest.json
@@ -7,8 +7,8 @@
"composite": [ "printing::mojom::PdfCompositor" ]
},
"requires": {
- "service_manager": [ "service_manager:all_users" ],
- "content_browser": [ "utility" ]
+ "*": [ "app" ],
+ "service_manager": [ "service_manager:all_users" ]
}
}
}
diff --git a/chromium/components/printing/service/pdf_compositor_service.cc b/chromium/components/printing/service/pdf_compositor_service.cc
index 40456fe47aa..d656c6d6c7a 100644
--- a/chromium/components/printing/service/pdf_compositor_service.cc
+++ b/chromium/components/printing/service/pdf_compositor_service.cc
@@ -42,7 +42,7 @@ std::unique_ptr<service_manager::Service> PdfCompositorService::Create(
return base::MakeUnique<printing::PdfCompositorService>(creator);
}
-void PdfCompositorService::OnStart() {
+void PdfCompositorService::PrepareToStart() {
// Set up discardable memory manager.
discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr;
context()->connector()->BindInterface(content::mojom::kBrowserServiceName,
@@ -53,6 +53,10 @@ void PdfCompositorService::OnStart() {
DCHECK(discardable_shared_memory_manager_);
base::DiscardableMemoryAllocator::SetInstance(
discardable_shared_memory_manager_.get());
+}
+
+void PdfCompositorService::OnStart() {
+ PrepareToStart();
ref_factory_ = base::MakeUnique<service_manager::ServiceContextRefFactory>(
base::Bind(&service_manager::ServiceContext::RequestQuit,
diff --git a/chromium/components/printing/service/pdf_compositor_service.h b/chromium/components/printing/service/pdf_compositor_service.h
index 6f7bdb8c2c9..4c1bb5dae00 100644
--- a/chromium/components/printing/service/pdf_compositor_service.h
+++ b/chromium/components/printing/service/pdf_compositor_service.h
@@ -33,6 +33,8 @@ class PdfCompositorService : public service_manager::Service {
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
+ virtual void PrepareToStart();
+
private:
// The creator of this service.
// Currently contains the service creator's user agent string if given,
diff --git a/chromium/components/printing/service/pdf_compositor_service_unittest.cc b/chromium/components/printing/service/pdf_compositor_service_unittest.cc
new file mode 100644
index 00000000000..b005a7031ae
--- /dev/null
+++ b/chromium/components/printing/service/pdf_compositor_service_unittest.cc
@@ -0,0 +1,136 @@
+// 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 <memory>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/shared_memory.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+class PdfCompositorServiceTest : public service_manager::test::ServiceTest {
+ public:
+ PdfCompositorServiceTest() : ServiceTest("pdf_compositor_service_unittest") {}
+ ~PdfCompositorServiceTest() override {}
+
+ MOCK_METHOD1(CallbackOnSuccess, void(mojo::SharedBufferHandle));
+ MOCK_METHOD1(CallbackOnError, void(mojom::PdfCompositor::Status));
+ void OnCallback(mojom::PdfCompositor::Status status,
+ mojo::ScopedSharedBufferHandle handle) {
+ if (status == mojom::PdfCompositor::Status::SUCCESS)
+ CallbackOnSuccess(handle.get());
+ else
+ CallbackOnError(status);
+ run_loop_->Quit();
+ }
+
+ MOCK_METHOD0(ConnectionClosed, void());
+
+ protected:
+ // service_manager::test::ServiceTest:
+ void SetUp() override {
+ ServiceTest::SetUp();
+
+ ASSERT_FALSE(compositor_);
+ connector()->BindInterface(mojom::kServiceName, &compositor_);
+ ASSERT_TRUE(compositor_);
+
+ run_loop_ = base::MakeUnique<base::RunLoop>();
+ }
+
+ void TearDown() override {
+ // Clean up
+ compositor_.reset();
+ }
+
+ base::SharedMemoryHandle LoadFileInSharedMemory() {
+ base::FilePath path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::FilePath test_file =
+ path.AppendASCII("components/test/data/printing/google.mskp");
+ std::string content;
+ base::SharedMemoryHandle invalid_handle;
+ if (!base::ReadFileToString(test_file, &content))
+ return invalid_handle;
+ size_t len = content.size();
+ base::SharedMemoryCreateOptions options;
+ options.size = len;
+ options.share_read_only = true;
+ base::SharedMemory shared_memory;
+ if (shared_memory.Create(options) && shared_memory.Map(len)) {
+ memcpy(shared_memory.memory(), content.data(), len);
+ base::SharedMemoryHandle handle = shared_memory.handle();
+ if (len == handle.GetSize())
+ return base::SharedMemory::DuplicateHandle(handle);
+ }
+ return invalid_handle;
+ }
+
+ void CallCompositorWithSuccess(mojom::PdfCompositorPtr ptr) {
+ auto handle = LoadFileInSharedMemory();
+ ASSERT_TRUE(handle.IsValid());
+ mojo::ScopedSharedBufferHandle buffer_handle =
+ mojo::WrapSharedMemoryHandle(handle, handle.GetSize(), true);
+ ASSERT_TRUE(buffer_handle->is_valid());
+ EXPECT_CALL(*this, CallbackOnSuccess(testing::_)).Times(1);
+ ptr->CompositePdf(std::move(buffer_handle),
+ base::BindOnce(&PdfCompositorServiceTest::OnCallback,
+ base::Unretained(this)));
+ run_loop_->Run();
+ }
+
+ std::unique_ptr<base::RunLoop> run_loop_;
+ mojom::PdfCompositorPtr compositor_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PdfCompositorServiceTest);
+};
+
+// Test callback is called on error conditions in service.
+TEST_F(PdfCompositorServiceTest, InvokeCallbackOnContentError) {
+ auto handle = LoadFileInSharedMemory();
+ ASSERT_TRUE(handle.IsValid());
+ mojo::ScopedSharedBufferHandle buffer_handle =
+ mojo::WrapSharedMemoryHandle(handle, 10, true);
+ // The size of mapped area is not equal to the original buffer,
+ // so the content is invalid.
+ ASSERT_LT(10u, handle.GetSize());
+ ASSERT_TRUE(buffer_handle->is_valid());
+ EXPECT_CALL(*this, CallbackOnError(
+ mojom::PdfCompositor::Status::CONTENT_FORMAT_ERROR))
+ .Times(1);
+ compositor_->CompositePdf(
+ std::move(buffer_handle),
+ base::BindOnce(&PdfCompositorServiceTest::OnCallback,
+ base::Unretained(this)));
+ run_loop_->Run();
+}
+
+TEST_F(PdfCompositorServiceTest, InvokeCallbackOnSuccess) {
+ CallCompositorWithSuccess(std::move(compositor_));
+}
+
+TEST_F(PdfCompositorServiceTest, ServiceInstances) {
+ // One service can bind multiple interfaces.
+ mojom::PdfCompositorPtr another_compositor;
+ ASSERT_FALSE(another_compositor);
+ connector()->BindInterface(mojom::kServiceName, &another_compositor);
+ ASSERT_TRUE(another_compositor);
+ ASSERT_NE(compositor_.get(), another_compositor.get());
+
+ // Terminating one interface won't affect another.
+ compositor_.reset();
+ CallCompositorWithSuccess(std::move(another_compositor));
+}
+
+} // namespace printing
diff --git a/chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json b/chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json
new file mode 100644
index 00000000000..262a00fe57b
--- /dev/null
+++ b/chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json
@@ -0,0 +1,17 @@
+{
+ "name": "pdf_compositor_service_unittest",
+ "display_name": "Pdf Compositor Service Unittest",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "service_manager:service_factory": [
+ "service_manager::mojom::ServiceFactory"
+ ]
+ },
+ "requires": {
+ "pdf_compositor": [ "composite" ],
+ "service_manager": [ "service_manager:service_manager" ]
+ }
+ }
+ }
+}
diff --git a/chromium/components/printing/service/public/cpp/pdf_compositor_client.cc b/chromium/components/printing/service/public/cpp/pdf_compositor_client.cc
index 51aaa560bc6..e88eb4b772f 100644
--- a/chromium/components/printing/service/public/cpp/pdf_compositor_client.cc
+++ b/chromium/components/printing/service/public/cpp/pdf_compositor_client.cc
@@ -19,8 +19,9 @@ void OnCompositePdf(
printing::mojom::PdfCompositorPtr compositor,
printing::mojom::PdfCompositor::CompositePdfCallback callback,
scoped_refptr<base::SequencedTaskRunner> task_runner,
+ mojom::PdfCompositor::Status status,
mojo::ScopedSharedBufferHandle pdf_handle) {
- task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback),
+ task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), status,
base::Passed(&pdf_handle)));
}
diff --git a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc b/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
index f832f860313..555394c93a2 100644
--- a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
+++ b/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
@@ -16,7 +16,7 @@ std::unique_ptr<service_manager::Service> CreatePdfCompositorService(
content::UtilityThread::Get()->EnsureBlinkInitialized();
// Hook up blink's codecs so skia can call them.
SkGraphics::SetImageGeneratorFromEncodedDataFactory(
- blink::WebImageGenerator::Create);
+ blink::WebImageGenerator::CreateAsSkImageGenerator);
return printing::PdfCompositorService::Create(creator);
}
diff --git a/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom b/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom
index 67f9448d947..ad8b5549902 100644
--- a/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom
+++ b/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom
@@ -8,9 +8,18 @@ const string kServiceName = "pdf_compositor";
// TODO(weili): Add support for printing frames from different processes.
interface PdfCompositor {
+ // The status of CompositePdf execution.
+ enum Status {
+ SUCCESS,
+ HANDLE_MAP_ERROR,
+ CONTENT_FORMAT_ERROR,
+ COMPOSTING_FAILURE,
+ };
+
// Currently directly convert passed in page data to a PDF file.
// |sk_handle| points to a buffer of a Skia MultiPictureDocument.
- // |pdf_handle| points to the generated PDF file buffer.
+ // |status| records the function execution status.
+ // |pdf_handle| points to the generated PDF file buffer upon success.
CompositePdf(handle<shared_buffer> sk_handle)
- => (handle<shared_buffer> pdf_handle);
+ => (Status status, handle<shared_buffer>? pdf_handle);
};
diff --git a/chromium/components/printing/service/test_service_main.cc b/chromium/components/printing/service/test_service_main.cc
new file mode 100644
index 00000000000..dd8b2c464c3
--- /dev/null
+++ b/chromium/components/printing/service/test_service_main.cc
@@ -0,0 +1,33 @@
+// 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 "base/test/test_discardable_memory_allocator.h"
+#include "components/printing/service/pdf_compositor_service.h"
+#include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/service_runner.h"
+
+// In order to test PdfCompositorService, this class overrides and
+// uses a test discardable memory allocator.
+class PdfCompositorTestService : public printing::PdfCompositorService {
+ public:
+ explicit PdfCompositorTestService(const std::string& creator)
+ : PdfCompositorService(creator) {}
+ ~PdfCompositorTestService() override {}
+
+ // PdfCompositorService:
+ void PrepareToStart() override;
+
+ private:
+ base::TestDiscardableMemoryAllocator mem_allocator_;
+};
+
+void PdfCompositorTestService::PrepareToStart() {
+ base::DiscardableMemoryAllocator::SetInstance(&mem_allocator_);
+}
+
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+ service_manager::ServiceRunner runner(
+ new PdfCompositorTestService("pdf_compositor_service_unittest"));
+ return runner.Run(service_request_handle);
+}
diff --git a/chromium/components/rappor/log_uploader.cc b/chromium/components/rappor/log_uploader.cc
index bfc3bb8fa57..1530148869f 100644
--- a/chromium/components/rappor/log_uploader.cc
+++ b/chromium/components/rappor/log_uploader.cc
@@ -127,7 +127,7 @@ void LogUploader::StartScheduledUpload() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature by stopping "
"'Automatically send usage statistics and crash reports to Google'"
diff --git a/chromium/components/reading_list/core/reading_list_model_impl.cc b/chromium/components/reading_list/core/reading_list_model_impl.cc
index 8a0b440c025..632fa6ede7c 100644
--- a/chromium/components/reading_list/core/reading_list_model_impl.cc
+++ b/chromium/components/reading_list/core/reading_list_model_impl.cc
@@ -327,7 +327,12 @@ const ReadingListEntry& ReadingListModelImpl::AddEntry(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(loaded());
DCHECK(url.SchemeIsHTTPOrHTTPS());
- RemoveEntryByURL(url);
+ std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
+ scoped_model_batch_updates = nullptr;
+ if (GetEntryByURL(url)) {
+ scoped_model_batch_updates = BeginBatchUpdates();
+ RemoveEntryByURL(url);
+ }
std::string trimmed_title = base::CollapseWhitespaceASCII(title, false);
diff --git a/chromium/components/reading_list/core/reading_list_model_unittest.cc b/chromium/components/reading_list/core/reading_list_model_unittest.cc
index c71c731eed4..50c53e8b95b 100644
--- a/chromium/components/reading_list/core/reading_list_model_unittest.cc
+++ b/chromium/components/reading_list/core/reading_list_model_unittest.cc
@@ -373,6 +373,35 @@ TEST_F(ReadingListModelTest, AddEntry) {
EXPECT_EQ("sample Test", other_entry->Title());
}
+// Tests adding an entry that already exists.
+TEST_F(ReadingListModelTest, AddExistingEntry) {
+ auto clock = base::MakeUnique<base::SimpleTestClock>();
+ auto storage = base::MakeUnique<TestReadingListStorage>(this, clock.get());
+ SetStorage(std::move(storage), std::move(clock));
+ GURL url = GURL("http://example.com");
+ std::string title = "\n \tsample Test ";
+ model_->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
+ ClearCounts();
+
+ const ReadingListEntry& entry =
+ model_->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
+ EXPECT_EQ(GURL("http://example.com"), entry.URL());
+ EXPECT_EQ("sample Test", entry.Title());
+
+ AssertObserverCount(0, 1, 1, 0, 1, 0, 1, 0, 2);
+ AssertStorageCount(1, 1);
+ EXPECT_EQ(1ul, UnreadSize());
+ EXPECT_EQ(0ul, ReadSize());
+ EXPECT_TRUE(model_->GetLocalUnseenFlag());
+
+ const ReadingListEntry* other_entry =
+ model_->GetEntryByURL(GURL("http://example.com"));
+ EXPECT_NE(other_entry, nullptr);
+ EXPECT_FALSE(other_entry->IsRead());
+ EXPECT_EQ(GURL("http://example.com"), other_entry->URL());
+ EXPECT_EQ("sample Test", other_entry->Title());
+}
+
// Tests addin entry from sync.
TEST_F(ReadingListModelTest, SyncAddEntry) {
auto clock = base::MakeUnique<base::SimpleTestClock>();
diff --git a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
index dde8f6ca942..f334d1b7adb 100644
--- a/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
+++ b/chromium/components/reading_list/ios/reading_list_model_bridge_observer.h
@@ -76,7 +76,6 @@ class ReadingListModelBridge : public ReadingListModelObserver {
__unsafe_unretained id<ReadingListModelBridgeObserver> observer_;
- // TODO(crbug.com/729015): Refactor to remove the naked pointer.
ReadingListModel* model_; // weak
DISALLOW_COPY_AND_ASSIGN(ReadingListModelBridge);
diff --git a/chromium/components/resources/OWNERS b/chromium/components/resources/OWNERS
index eed6b23f6bd..511b189b471 100644
--- a/chromium/components/resources/OWNERS
+++ b/chromium/components/resources/OWNERS
@@ -18,6 +18,7 @@ per-file gcm_driver_resources.grdp=zea@chromium.org
per-file neterror*=juliatuttle@chromium.org
per-file neterror*=mmenke@chromium.org
per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
+per-file offline_pages_resources.grdp=file://components/offline_pages/OWNERS
per-file proximity_auth*=tengs@chromium.org
per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
per-file supervised_user_error_page_resources.grdp=file://components/supervised_user_error_page/OWNERS
diff --git a/chromium/components/resources/components_resources.grd b/chromium/components/resources/components_resources.grd
index ec0dffdd4bd..1dea8d0d02e 100644
--- a/chromium/components/resources/components_resources.grd
+++ b/chromium/components/resources/components_resources.grd
@@ -16,6 +16,7 @@
<part file="net_log_resources.grdp" />
<part file="neterror_resources.grdp" />
<part file="ntp_tiles_resources.grdp" />
+ <part file="offline_pages_resources.grdp" />
<part file="physical_web_ui_resources.grdp" />
<part file="printing_resources.grdp" />
<part file="proximity_auth_resources.grdp" />
diff --git a/chromium/components/resources/default_100_percent/autofill/cc-generic.png b/chromium/components/resources/default_100_percent/autofill/cc-generic.png
index 4b699dbd5bf..1ee634bedfa 100644
--- a/chromium/components/resources/default_100_percent/autofill/cc-generic.png
+++ b/chromium/components/resources/default_100_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/cc-generic.png b/chromium/components/resources/default_200_percent/autofill/cc-generic.png
index c0af2dd66ca..5eadeec29d5 100644
--- a/chromium/components/resources/default_200_percent/autofill/cc-generic.png
+++ b/chromium/components/resources/default_200_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/amex.png b/chromium/components/resources/default_300_percent/autofill/amex.png
new file mode 100644
index 00000000000..995841180dc
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/amex.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/cc-generic.png b/chromium/components/resources/default_300_percent/autofill/cc-generic.png
new file mode 100644
index 00000000000..1a556d04572
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/diners.png b/chromium/components/resources/default_300_percent/autofill/diners.png
new file mode 100644
index 00000000000..b3eaa4e4389
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/diners.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/discover.png b/chromium/components/resources/default_300_percent/autofill/discover.png
new file mode 100644
index 00000000000..9ba9a63f338
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/discover.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/jcb.png b/chromium/components/resources/default_300_percent/autofill/jcb.png
new file mode 100644
index 00000000000..5a924a2ae07
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/jcb.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/mastercard.png b/chromium/components/resources/default_300_percent/autofill/mastercard.png
new file mode 100644
index 00000000000..47695176487
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/mastercard.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/mir.png b/chromium/components/resources/default_300_percent/autofill/mir.png
new file mode 100644
index 00000000000..41b8cc5b407
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/mir.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/unionpay.png b/chromium/components/resources/default_300_percent/autofill/unionpay.png
new file mode 100644
index 00000000000..98cc3a7a5a4
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/unionpay.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/visa.png b/chromium/components/resources/default_300_percent/autofill/visa.png
new file mode 100644
index 00000000000..189d94eda0b
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/visa.png
Binary files differ
diff --git a/chromium/components/resources/offline_pages_resources.grdp b/chromium/components/resources/offline_pages_resources.grdp
new file mode 100644
index 00000000000..28388eec6d2
--- /dev/null
+++ b/chromium/components/resources/offline_pages_resources.grdp
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <include name="IDR_OFFLINE_PAGES_RENOVATIONS_JS" file="../offline_pages/resources/renovations.js" type="BINDATA" />
+</grit-part>
diff --git a/chromium/components/resources/sync_driver_resources.grdp b/chromium/components/resources/sync_driver_resources.grdp
index bb00a51651d..a12e0991648 100644
--- a/chromium/components/resources/sync_driver_resources.grdp
+++ b/chromium/components/resources/sync_driver_resources.grdp
@@ -12,4 +12,5 @@
<include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS" file="../sync/driver/resources/events.js" type="BINDATA" />
<include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS" file="../sync/driver/resources/search.js" type="BINDATA" />
<include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_USER_EVENTS_JS" file="../sync/driver/resources/user_events.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_TRAFFIC_LOG_JS" file="../sync/driver/resources/traffic_log.js" type="BINDATA" />
</grit-part>
diff --git a/chromium/components/safe_browsing/BUILD.gn b/chromium/components/safe_browsing/BUILD.gn
index f09e7c62cff..f2cb4a1ae2e 100644
--- a/chromium/components/safe_browsing/BUILD.gn
+++ b/chromium/components/safe_browsing/BUILD.gn
@@ -6,7 +6,13 @@ import("//third_party/protobuf/proto_library.gni")
proto_library("csd_proto") {
sources = [
- "csd.proto",
+ "proto/csd.proto",
+ ]
+}
+
+proto_library("webui_proto") {
+ sources = [
+ "proto/webui.proto",
]
}
@@ -18,6 +24,8 @@ source_set("safe_browsing") {
"base_resource_throttle.h",
"base_ui_manager.cc",
"base_ui_manager.h",
+ "net_event_logger.cc",
+ "net_event_logger.h",
]
public_deps = [
"//components/security_interstitials/content:security_interstitial_page",
@@ -27,6 +35,7 @@ source_set("safe_browsing") {
":features",
"//base:base",
"//base:i18n",
+ "//components/safe_browsing/common:common",
"//components/safe_browsing/common:safe_browsing_prefs",
"//components/safe_browsing/web_ui:constants",
"//components/safe_browsing_db:database_manager",
diff --git a/chromium/components/safe_browsing_db/android/BUILD.gn b/chromium/components/safe_browsing/android/BUILD.gn
index 32b2ff2f402..32b905249c0 100644
--- a/chromium/components/safe_browsing_db/android/BUILD.gn
+++ b/chromium/components/safe_browsing/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
+
android_library("safe_browsing_java") {
deps = [
"//base:base_java",
@@ -19,5 +20,5 @@ generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/safe_browsing/SafeBrowsingApiBridge.java",
]
- jni_package = "components/safe_browsing_db/android"
+ jni_package = "components/safe_browsing/android"
}
diff --git a/chromium/components/safe_browsing/android/DEPS b/chromium/components/safe_browsing/android/DEPS
new file mode 100644
index 00000000000..1129c7b690d
--- /dev/null
+++ b/chromium/components/safe_browsing/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+jni",
+] \ No newline at end of file
diff --git a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
index 3acd9a4153a..613f2dbe9ba 100644
--- a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.cc
+++ b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/safe_browsing_db/android/safe_browsing_api_handler_bridge.h"
+#include "components/safe_browsing/android/safe_browsing_api_handler_bridge.h"
#include <memory>
#include <string>
-#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/containers/flat_set.h"
#include "base/metrics/histogram_macros.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler_util.h"
+#include "components/safe_browsing/db/safe_browsing_api_handler_util.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "content/public/browser/browser_thread.h"
#include "jni/SafeBrowsingApiBridge_jni.h"
@@ -73,10 +72,6 @@ ScopedJavaLocalRef<jintArray> SBThreatTypeSetToJavaArray(
} // namespace
-bool RegisterSafeBrowsingApiBridge(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
// Java->Native call, invoked when a check is done.
// |callback_id| is an int form of pointer to a URLCheckCallbackMeta
// that will be called and then deleted here.
diff --git a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.h b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
index 40eda4d2149..7161c8fd17e 100644
--- a/chromium/components/safe_browsing_db/android/safe_browsing_api_handler_bridge.h
+++ b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
@@ -4,8 +4,8 @@
//
// Glue to pass Safe Browsing API requests between Chrome and GMSCore
-#ifndef COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
-#define COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
+#ifndef COMPONENTS_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
+#define COMPONENTS_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
#include <jni.h>
@@ -14,13 +14,11 @@
#include "base/android/jni_android.h"
#include "base/macros.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler.h"
+#include "components/safe_browsing/db/safe_browsing_api_handler.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "url/gurl.h"
namespace safe_browsing {
-bool RegisterSafeBrowsingApiBridge(JNIEnv* env);
-
class SafeBrowsingApiHandlerBridge : public SafeBrowsingApiHandler {
public:
SafeBrowsingApiHandlerBridge();
@@ -46,4 +44,4 @@ class SafeBrowsingApiHandlerBridge : public SafeBrowsingApiHandler {
};
} // namespace safe_browsing
-#endif // COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
+#endif // COMPONENTS_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_BRIDGE_H_
diff --git a/chromium/components/safe_browsing/base_ping_manager.cc b/chromium/components/safe_browsing/base_ping_manager.cc
index cc89412fd98..bb37fcd7d92 100644
--- a/chromium/components/safe_browsing/base_ping_manager.cc
+++ b/chromium/components/safe_browsing/base_ping_manager.cc
@@ -58,7 +58,8 @@ std::unique_ptr<base::Value> NetLogPingEndCallback(
}
net::NetworkTrafficAnnotationTag kTrafficAnnotation =
- net::DefineNetworkTrafficAnnotation("safe_browsing_extended_reporting", R"(
+ net::DefineNetworkTrafficAnnotation("safe_browsing_extended_reporting",
+ R"(
semantics {
sender: "Safe Browsing Extended Reporting"
description:
@@ -79,7 +80,7 @@ net::NetworkTrafficAnnotationTag kTrafficAnnotation =
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "Safe Browsing Cookie Store"
setting:
"Users can control this feature via the 'Automatically report "
diff --git a/chromium/components/safe_browsing/base_resource_throttle.cc b/chromium/components/safe_browsing/base_resource_throttle.cc
index 8de25547cfe..e511d3faf6c 100644
--- a/chromium/components/safe_browsing/base_resource_throttle.cc
+++ b/chromium/components/safe_browsing/base_resource_throttle.cc
@@ -8,8 +8,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
-#include "base/values.h"
#include "components/safe_browsing/base_ui_manager.h"
+#include "components/safe_browsing/common/utils.h"
#include "components/safe_browsing/web_ui/constants.h"
#include "components/safe_browsing_db/util.h"
#include "components/security_interstitials/content/unsafe_resource.h"
@@ -17,14 +17,11 @@
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "net/base/load_flags.h"
-#include "net/log/net_log_capture_mode.h"
-#include "net/log/net_log_source.h"
-#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_event_type.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request.h"
using net::NetLogEventType;
-using net::NetLogSourceType;
namespace safe_browsing {
@@ -35,35 +32,6 @@ namespace {
// aborted, and the URL will be treated as if it were safe.
const int kCheckUrlTimeoutMs = 5000;
-// Return a dictionary with "url"=|url-spec| and optionally
-// |name|=|value| (if not null), for netlogging.
-// This will also add a reference to the original request's net_log ID.
-std::unique_ptr<base::Value> NetLogUrlCallback(
- const net::URLRequest* request,
- const GURL& url,
- const char* name,
- const char* value,
- net::NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> event_params(
- new base::DictionaryValue());
- event_params->SetString("url", url.spec());
- if (name && value)
- event_params->SetString(name, value);
- request->net_log().source().AddToEventParameters(event_params.get());
- return std::move(event_params);
-}
-
-// Return a dictionary with |name|=|value|, for netlogging.
-std::unique_ptr<base::Value> NetLogStringCallback(const char* name,
- const char* value,
- net::NetLogCaptureMode) {
- std::unique_ptr<base::DictionaryValue> event_params(
- new base::DictionaryValue());
- if (name && value)
- event_params->SetString(name, value);
- return std::move(event_params);
-}
-
} // namespace
// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
@@ -83,44 +51,22 @@ BaseResourceThrottle::BaseResourceThrottle(
state_(STATE_NONE),
defer_state_(DEFERRED_NONE),
resource_type_(resource_type),
- net_log_with_source_(
- net::NetLogWithSource::Make(request->net_log().net_log(),
- NetLogSourceType::SAFE_BROWSING)) {}
+ net_event_logger_(&request->net_log()) {}
BaseResourceThrottle::~BaseResourceThrottle() {
if (defer_state_ != DEFERRED_NONE) {
- EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr);
+ net_event_logger_.EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
+ nullptr, nullptr);
}
if (state_ == STATE_CHECKING_URL) {
database_manager_->CancelCheck(this);
- EndNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
- "request_canceled");
+ net_event_logger_.EndNetLogEvent(
+ NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
+ "request_canceled");
}
}
-// Note on net_log calls: SAFE_BROWSING_DEFERRED events must be wholly
-// nested within SAFE_BROWSING_CHECKING_URL events. Synchronous checks
-// are not logged at all.
-void BaseResourceThrottle::BeginNetLogEvent(NetLogEventType type,
- const GURL& url,
- const char* name,
- const char* value) {
- net_log_with_source_.BeginEvent(
- type, base::Bind(&NetLogUrlCallback, request_, url, name, value));
- request_->net_log().AddEvent(
- type, net_log_with_source_.source().ToEventParametersCallback());
-}
-
-void BaseResourceThrottle::EndNetLogEvent(NetLogEventType type,
- const char* name,
- const char* value) {
- net_log_with_source_.EndEvent(type,
- base::Bind(&NetLogStringCallback, name, value));
- request_->net_log().AddEvent(
- type, net_log_with_source_.source().ToEventParametersCallback());
-}
-
void BaseResourceThrottle::WillStartRequest(bool* defer) {
// We need to check the new URL before starting the request.
if (CheckUrl(request_->url()))
@@ -137,8 +83,9 @@ void BaseResourceThrottle::WillStartRequest(bool* defer) {
defer_state_ = DEFERRED_START;
defer_start_time_ = base::TimeTicks::Now();
*defer = true;
- BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(),
- "defer_reason", "at_start");
+ net_event_logger_.BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
+ request_->url(), "defer_reason",
+ "at_start");
}
void BaseResourceThrottle::WillProcessResponse(bool* defer) {
@@ -152,8 +99,9 @@ void BaseResourceThrottle::WillProcessResponse(bool* defer) {
defer_state_ = DEFERRED_PROCESSING;
defer_start_time_ = base::TimeTicks::Now();
*defer = true;
- BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(),
- "defer_reason", "at_response");
+ net_event_logger_.BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
+ request_->url(), "defer_reason",
+ "at_response");
}
}
@@ -200,7 +148,7 @@ void BaseResourceThrottle::WillRedirectRequest(
defer_start_time_ = base::TimeTicks::Now();
*defer = true;
- BeginNetLogEvent(
+ net_event_logger_.BeginNetLogEvent(
NetLogEventType::SAFE_BROWSING_DEFERRED, redirect_info.new_url,
"defer_reason",
defer_state_ == DEFERRED_REDIRECT ? "redirect" : "unchecked_redirect");
@@ -229,19 +177,20 @@ void BaseResourceThrottle::OnCheckBrowseUrlResult(
state_ = STATE_NONE;
if (defer_state_ != DEFERRED_NONE) {
- EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr);
+ net_event_logger_.EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
+ nullptr, nullptr);
}
- EndNetLogEvent(
+ net_event_logger_.EndNetLogEvent(
NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
threat_type_ == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe");
if (threat_type == SB_THREAT_TYPE_SAFE) {
if (defer_state_ != DEFERRED_NONE) {
// Log how much time the safe browsing check cost us.
- ui_manager_->LogPauseDelay(base::TimeTicks::Now() - defer_start_time_);
+ LogDelay(base::TimeTicks::Now() - defer_start_time_);
ResumeRequest();
} else {
- ui_manager_->LogPauseDelay(base::TimeDelta());
+ LogDelay(base::TimeDelta());
}
return;
}
@@ -284,31 +233,6 @@ void BaseResourceThrottle::OnCheckBrowseUrlResult(
StartDisplayingBlockingPageHelper(resource);
}
-void BaseResourceThrottle::StartDisplayingBlockingPageHelper(
- security_interstitials::UnsafeResource resource) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::Bind(&BaseResourceThrottle::StartDisplayingBlockingPage,
- AsWeakPtr(), ui_manager_, resource));
-}
-
-// Static
-void BaseResourceThrottle::StartDisplayingBlockingPage(
- const base::WeakPtr<BaseResourceThrottle>& throttle,
- scoped_refptr<BaseUIManager> ui_manager,
- const security_interstitials::UnsafeResource& resource) {
- content::WebContents* web_contents = resource.web_contents_getter.Run();
- if (web_contents) {
- ui_manager->DisplayBlockingPage(resource);
- return;
- }
-
- // Tab is gone or it's being prerendered.
- content::BrowserThread::PostTask(
- content::BrowserThread::IO, FROM_HERE,
- base::Bind(&BaseResourceThrottle::Cancel, throttle));
-}
-
void BaseResourceThrottle::OnBlockingPageComplete(bool proceed) {
CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE);
state_ = STATE_NONE;
@@ -356,14 +280,15 @@ bool BaseResourceThrottle::CheckUrl(const GURL& url) {
if (database_manager_->CheckBrowseUrl(url, threat_types_, this)) {
threat_type_ = SB_THREAT_TYPE_SAFE;
- ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay.
+ LogDelay(base::TimeDelta()); // No delay.
return true;
}
state_ = STATE_CHECKING_URL;
url_being_checked_ = url;
- BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr,
- nullptr);
+ // Note on net_log calls: Synchronous checks are not logged at all.
+ net_event_logger_.BeginNetLogEvent(
+ NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr, nullptr);
// Start a timer to abort the check if it takes too long.
// TODO(nparker): Set this only when we defer, based on remaining time,
@@ -417,9 +342,9 @@ void BaseResourceThrottle::ResumeRequest() {
// We're now waiting for the unchecked_redirect_url_.
defer_state_ = DEFERRED_REDIRECT;
resume = false;
- BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
- unchecked_redirect_url_, "defer_reason",
- "resumed_redirect");
+ net_event_logger_.BeginNetLogEvent(
+ NetLogEventType::SAFE_BROWSING_DEFERRED, unchecked_redirect_url_,
+ "defer_reason", "resumed_redirect");
}
}
diff --git a/chromium/components/safe_browsing/base_resource_throttle.h b/chromium/components/safe_browsing/base_resource_throttle.h
index 38de36f5d28..78d5dcc26a1 100644
--- a/chromium/components/safe_browsing/base_resource_throttle.h
+++ b/chromium/components/safe_browsing/base_resource_throttle.h
@@ -12,13 +12,12 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/safe_browsing/base_ui_manager.h"
+#include "components/safe_browsing/net_event_logger.h"
#include "components/safe_browsing_db/database_manager.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/security_interstitials/content/unsafe_resource.h"
#include "content/public/browser/resource_throttle.h"
#include "content/public/common/resource_type.h"
-#include "net/log/net_log_event_type.h"
-#include "net/log/net_log_with_source.h"
#include "url/gurl.h"
namespace content {
@@ -93,20 +92,13 @@ class BaseResourceThrottle
// Posts a task for StartDisplayingBlockingPage
virtual void StartDisplayingBlockingPageHelper(
- security_interstitials::UnsafeResource resource);
+ security_interstitials::UnsafeResource resource) = 0;
// Called by OnBlockingPageComplete when proceed == false. This removes the
// blocking page. This calls ResourceThrottle::Cancel() to show the previous
// page, but may be overridden in a subclass.
virtual void CancelResourceLoad();
- // Starts displaying the safe browsing interstitial page. Called on the UI
- // thread.
- static void StartDisplayingBlockingPage(
- const base::WeakPtr<BaseResourceThrottle>& throttle,
- scoped_refptr<BaseUIManager> ui_manager,
- const security_interstitials::UnsafeResource& resource);
-
// Starts running |url| through the safe browsing check. Returns true if the
// URL is safe to visit. Otherwise returns false and will call
// OnBrowseUrlResult() when the check has completed.
@@ -147,15 +139,6 @@ class BaseResourceThrottle
void ResumeRequest();
- // For marking network events. |name| and |value| can be null.
- void BeginNetLogEvent(net::NetLogEventType type,
- const GURL& url,
- const char* name,
- const char* value);
- void EndNetLogEvent(net::NetLogEventType type,
- const char* name,
- const char* value);
-
// The result of the most recent safe browsing check. Only valid to read this
// when state_ != STATE_CHECKING_URL.
safe_browsing::SBThreatType threat_type_;
@@ -182,7 +165,7 @@ class BaseResourceThrottle
DeferState defer_state_;
const content::ResourceType resource_type_;
- net::NetLogWithSource net_log_with_source_;
+ NetEventLogger net_event_logger_;
DISALLOW_COPY_AND_ASSIGN(BaseResourceThrottle);
};
diff --git a/chromium/components/safe_browsing/base_ui_manager.cc b/chromium/components/safe_browsing/base_ui_manager.cc
index 5a63b615871..084dd71ee18 100644
--- a/chromium/components/safe_browsing/base_ui_manager.cc
+++ b/chromium/components/safe_browsing/base_ui_manager.cc
@@ -8,7 +8,6 @@
#include "base/callback.h"
#include "base/i18n/rtl.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
#include "base/supports_user_data.h"
#include "components/safe_browsing/base_blocking_page.h"
#include "content/public/browser/browser_thread.h"
@@ -43,6 +42,7 @@ class WhitelistUrlSet : public base::SupportsUserData::Data {
return true;
}
void RemovePending(const GURL& url) { pending_.erase(url); }
+ void Remove(const GURL& url) { map_.erase(url); }
void Insert(const GURL url, SBThreatType threat_type) {
if (Contains(url, nullptr))
return;
@@ -166,7 +166,8 @@ void BaseUIManager::OnBlockingPageDone(
resource.threat_type);
} else if (web_contents) {
// |web_contents| doesn't exist if the tab has been closed.
- RemoveFromPendingWhitelistUrlSet(whitelist_url, web_contents);
+ RemoveWhitelistUrlSet(whitelist_url, web_contents,
+ true /* from_pending_only */);
}
}
}
@@ -232,11 +233,6 @@ void BaseUIManager::EnsureWhitelistCreated(
GetOrCreateWhitelist(web_contents);
}
-void BaseUIManager::LogPauseDelay(base::TimeDelta time) {
- UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
- return;
-}
-
void BaseUIManager::CreateAndSendHitReport(const UnsafeResource& resource) {}
void BaseUIManager::ShowBlockingPageForResource(
@@ -310,9 +306,9 @@ const GURL BaseUIManager::default_safe_page() const {
return GURL(url::kAboutBlankURL);
}
-void BaseUIManager::RemoveFromPendingWhitelistUrlSet(
- const GURL& whitelist_url,
- WebContents* web_contents) {
+void BaseUIManager::RemoveWhitelistUrlSet(const GURL& whitelist_url,
+ WebContents* web_contents,
+ bool from_pending_only) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// A WebContents might not exist if the tab has been closed.
@@ -343,6 +339,11 @@ void BaseUIManager::RemoveFromPendingWhitelistUrlSet(
if (site_list && site_list->ContainsPending(whitelist_url, nullptr))
site_list->RemovePending(whitelist_url);
+ if (!from_pending_only && site_list &&
+ site_list->Contains(whitelist_url, nullptr)) {
+ site_list->Remove(whitelist_url);
+ }
+
// Notify security UI that security state has changed.
web_contents->DidChangeVisibleSecurityState();
}
diff --git a/chromium/components/safe_browsing/base_ui_manager.h b/chromium/components/safe_browsing/base_ui_manager.h
index f20e0d938c0..85de4149067 100644
--- a/chromium/components/safe_browsing/base_ui_manager.h
+++ b/chromium/components/safe_browsing/base_ui_manager.h
@@ -11,7 +11,6 @@
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
#include "components/security_interstitials/content/unsafe_resource.h"
class GURL;
@@ -48,12 +47,6 @@ class BaseUIManager
// chain). Otherwise, |original_url| = |url|.
virtual void DisplayBlockingPage(const UnsafeResource& resource);
- // Log the user perceived delay caused by SafeBrowsing. This delay is the time
- // delta starting from when we would have started reading data from the
- // network, and ending when the SafeBrowsing check completes indicating that
- // the current page is 'safe'.
- virtual void LogPauseDelay(base::TimeDelta time);
-
// This is a no-op in the base class, but should be overridden to send threat
// details. Called on the IO thread by the ThreatDetails with the serialized
// protocol buffer.
@@ -112,6 +105,7 @@ class BaseUIManager
virtual const GURL default_safe_page() const;
protected:
+ friend class ChromePasswordProtectionService;
virtual ~BaseUIManager();
// Updates the whitelist URL set for |web_contents|. Called on the UI thread.
@@ -125,10 +119,11 @@ class BaseUIManager
virtual void ReportSafeBrowsingHitOnIOThread(
const safe_browsing::HitReport& hit_report);
- // Removes |whitelist_url| from the pending whitelist for
- // |web_contents|. Called on the UI thread.
- void RemoveFromPendingWhitelistUrlSet(const GURL& whitelist_url,
- content::WebContents* web_contents);
+ // Removes |whitelist_url| from the whitelist for |web_contents|.
+ // Called on the UI thread.
+ void RemoveWhitelistUrlSet(const GURL& whitelist_url,
+ content::WebContents* web_contents,
+ bool from_pending_only);
// Ensures that |web_contents| has its whitelist set in its userdata
static void EnsureWhitelistCreated(content::WebContents* web_contents);
diff --git a/chromium/components/safe_browsing/browser/BUILD.gn b/chromium/components/safe_browsing/browser/BUILD.gn
index 1ad4965da44..6999f32d9da 100644
--- a/chromium/components/safe_browsing/browser/BUILD.gn
+++ b/chromium/components/safe_browsing/browser/BUILD.gn
@@ -6,6 +6,8 @@ import("//build/config/features.gni")
source_set("browser") {
sources = [
+ "base_parallel_resource_throttle.cc",
+ "base_parallel_resource_throttle.h",
"browser_url_loader_throttle.cc",
"browser_url_loader_throttle.h",
"mojo_safe_browsing_impl.cc",
@@ -29,6 +31,7 @@ source_set("browser") {
"//components/safe_browsing:csd_proto",
"//components/safe_browsing:safe_browsing",
"//components/safe_browsing/common:common",
+ "//components/safe_browsing/web_ui:constants",
"//components/safe_browsing_db:database_manager",
"//components/security_interstitials/content:security_interstitial_page",
"//content/public/browser:browser",
diff --git a/chromium/components/safe_browsing/browser/DEPS b/chromium/components/safe_browsing/browser/DEPS
index d98a2a4dfa1..b219d834aa1 100644
--- a/chromium/components/safe_browsing/browser/DEPS
+++ b/chromium/components/safe_browsing/browser/DEPS
@@ -1,6 +1,6 @@
include_rules = [
"+components/history/core/browser",
- "+components/safe_browsing/csd.pb.h",
+ "+components/safe_browsing/proto/csd.pb.h",
"+content/public/browser",
"+ipc/ipc_message.h",
"+net/cookies",
diff --git a/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.cc b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.cc
new file mode 100644
index 00000000000..a59be63c9a3
--- /dev/null
+++ b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.cc
@@ -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.
+
+#include "components/safe_browsing/browser/base_parallel_resource_throttle.h"
+
+#include <utility>
+
+#include "components/safe_browsing/browser/browser_url_loader_throttle.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/resource_request.h"
+#include "net/http/http_request_headers.h"
+#include "net/log/net_log_with_source.h"
+#include "net/url_request/url_request.h"
+
+namespace safe_browsing {
+
+void BaseParallelResourceThrottle::URLLoaderThrottleDelegateImpl::
+ CancelWithError(int error_code) {
+ owner_->CancelResourceLoad();
+}
+
+void BaseParallelResourceThrottle::URLLoaderThrottleDelegateImpl::Resume() {
+ owner_->Resume();
+}
+
+BaseParallelResourceThrottle::BaseParallelResourceThrottle(
+ const net::URLRequest* request,
+ content::ResourceType resource_type,
+ scoped_refptr<UrlCheckerDelegate> url_checker_delegate)
+ : request_(request),
+ resource_type_(resource_type),
+ url_loader_throttle_delegate_(this),
+ net_event_logger_(&request->net_log()) {
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request_);
+ url_loader_throttle_ = BrowserURLLoaderThrottle::MaybeCreate(
+ std::move(url_checker_delegate), info->GetWebContentsGetterForRequest());
+ url_loader_throttle_->set_delegate(&url_loader_throttle_delegate_);
+ url_loader_throttle_->set_net_event_logger(&net_event_logger_);
+}
+
+BaseParallelResourceThrottle::~BaseParallelResourceThrottle() = default;
+
+void BaseParallelResourceThrottle::WillStartRequest(bool* defer) {
+ content::ResourceRequest resource_request;
+
+ net::HttpRequestHeaders full_headers;
+ resource_request.headers = request_->GetFullRequestHeaders(&full_headers)
+ ? full_headers.ToString()
+ : request_->extra_request_headers().ToString();
+
+ resource_request.load_flags = request_->load_flags();
+ resource_request.resource_type = resource_type_;
+
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request_);
+ resource_request.has_user_gesture = info && info->HasUserGesture();
+
+ resource_request.url = request_->url();
+ resource_request.method = request_->method();
+
+ url_loader_throttle_->WillStartRequest(resource_request, defer);
+ DCHECK(!*defer);
+}
+
+void BaseParallelResourceThrottle::WillRedirectRequest(
+ const net::RedirectInfo& redirect_info,
+ bool* defer) {
+ url_loader_throttle_->WillRedirectRequest(redirect_info, defer);
+ DCHECK(!*defer);
+}
+
+void BaseParallelResourceThrottle::WillProcessResponse(bool* defer) {
+ url_loader_throttle_->WillProcessResponse(defer);
+}
+
+const char* BaseParallelResourceThrottle::GetNameForLogging() const {
+ return "BaseParallelResourceThrottle";
+}
+
+void BaseParallelResourceThrottle::CancelResourceLoad() {
+ Cancel();
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.h b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.h
new file mode 100644
index 00000000000..26d64ab46c4
--- /dev/null
+++ b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle.h
@@ -0,0 +1,77 @@
+// 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_SAFE_BROWSING_BROWSER_BASE_PARALLEL_RESOURCE_THROTTLE_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_BASE_PARALLEL_RESOURCE_THROTTLE_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/safe_browsing/net_event_logger.h"
+#include "content/public/browser/resource_throttle.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/common/url_loader_throttle.h"
+
+namespace net {
+class URLRequest;
+}
+
+namespace safe_browsing {
+
+class BrowserURLLoaderThrottle;
+class UrlCheckerDelegate;
+
+// A thin wrapper around BrowserURLLoaderThrottle to adapt to the
+// content::ResourceThrottle interface.
+// Used when --enable-features=S13nSafeBrowsingParallelUrlCheck is in effect.
+class BaseParallelResourceThrottle : public content::ResourceThrottle {
+ protected:
+ BaseParallelResourceThrottle(
+ const net::URLRequest* request,
+ content::ResourceType resource_type,
+ scoped_refptr<UrlCheckerDelegate> url_checker_delegate);
+
+ ~BaseParallelResourceThrottle() override;
+
+ // content::ResourceThrottle implementation:
+ void WillStartRequest(bool* defer) override;
+ void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+ bool* defer) override;
+ void WillProcessResponse(bool* defer) override;
+ const char* GetNameForLogging() const override;
+
+ virtual void CancelResourceLoad();
+
+ private:
+ class URLLoaderThrottleDelegateImpl
+ : public content::URLLoaderThrottle::Delegate {
+ public:
+ explicit URLLoaderThrottleDelegateImpl(BaseParallelResourceThrottle* owner)
+ : owner_(owner) {}
+ ~URLLoaderThrottleDelegateImpl() override = default;
+
+ // content::URLLoaderThrottle::Delegate implementation:
+ void CancelWithError(int error_code) override;
+ void Resume() override;
+
+ private:
+ BaseParallelResourceThrottle* const owner_;
+ DISALLOW_COPY_AND_ASSIGN(URLLoaderThrottleDelegateImpl);
+ };
+
+ const net::URLRequest* const request_;
+ const content::ResourceType resource_type_;
+
+ // The following two members need to outlive |url_loader_throttle_| which
+ // holds raw pointers to them.
+ URLLoaderThrottleDelegateImpl url_loader_throttle_delegate_;
+ NetEventLogger net_event_logger_;
+
+ std::unique_ptr<BrowserURLLoaderThrottle> url_loader_throttle_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseParallelResourceThrottle);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_BROWSER_BASE_PARALLEL_RESOURCE_THROTTLE_H_
diff --git a/chromium/components/safe_browsing/browser/browser_url_loader_throttle.cc b/chromium/components/safe_browsing/browser/browser_url_loader_throttle.cc
index f841da38bc5..de7a14e1ee9 100644
--- a/chromium/components/safe_browsing/browser/browser_url_loader_throttle.cc
+++ b/chromium/components/safe_browsing/browser/browser_url_loader_throttle.cc
@@ -7,6 +7,10 @@
#include "base/logging.h"
#include "components/safe_browsing/browser/safe_browsing_url_checker_impl.h"
#include "components/safe_browsing/browser/url_checker_delegate.h"
+#include "components/safe_browsing/common/utils.h"
+#include "components/safe_browsing/net_event_logger.h"
+#include "content/public/common/resource_request.h"
+#include "net/log/net_log_event_type.h"
#include "net/url_request/redirect_info.h"
namespace safe_browsing {
@@ -31,12 +35,15 @@ BrowserURLLoaderThrottle::BrowserURLLoaderThrottle(
: url_checker_delegate_(std::move(url_checker_delegate)),
web_contents_getter_(web_contents_getter) {}
-BrowserURLLoaderThrottle::~BrowserURLLoaderThrottle() = default;
+BrowserURLLoaderThrottle::~BrowserURLLoaderThrottle() {
+ if (deferred_ && net_event_logger_) {
+ net_event_logger_->EndNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr);
+ }
+}
void BrowserURLLoaderThrottle::WillStartRequest(
- const GURL& url,
- int load_flags,
- content::ResourceType resource_type,
+ const content::ResourceRequest& request,
bool* defer) {
DCHECK_EQ(0u, pending_checks_);
DCHECK(!blocked_);
@@ -44,11 +51,16 @@ void BrowserURLLoaderThrottle::WillStartRequest(
pending_checks_++;
url_checker_ = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
- load_flags, resource_type, std::move(url_checker_delegate_),
+ request.headers, request.load_flags, request.resource_type,
+ request.has_user_gesture, std::move(url_checker_delegate_),
web_contents_getter_);
+ if (net_event_logger_)
+ url_checker_->set_net_event_logger(net_event_logger_);
+
url_checker_->CheckUrl(
- url, base::BindOnce(&BrowserURLLoaderThrottle::OnCheckUrlResult,
- base::Unretained(this)));
+ request.url, request.method,
+ base::BindOnce(&BrowserURLLoaderThrottle::OnCheckUrlResult,
+ base::Unretained(this)));
}
void BrowserURLLoaderThrottle::WillRedirectRequest(
@@ -60,7 +72,7 @@ void BrowserURLLoaderThrottle::WillRedirectRequest(
pending_checks_++;
url_checker_->CheckUrl(
- redirect_info.new_url,
+ redirect_info.new_url, redirect_info.new_method,
base::BindOnce(&BrowserURLLoaderThrottle::OnCheckUrlResult,
base::Unretained(this)));
}
@@ -70,21 +82,46 @@ void BrowserURLLoaderThrottle::WillProcessResponse(bool* defer) {
// shouldn't be such a notification.
DCHECK(!blocked_);
- if (pending_checks_ > 0)
- *defer = true;
+ if (pending_checks_ == 0) {
+ LogDelay(base::TimeDelta());
+ return;
+ }
+
+ DCHECK(!deferred_);
+ deferred_ = true;
+ defer_start_time_ = base::TimeTicks::Now();
+ *defer = true;
+ if (net_event_logger_) {
+ net_event_logger_->BeginNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_DEFERRED,
+ url_checker_->GetCurrentlyCheckingUrl(), "defer_reason", "at_response");
+ }
+}
+
+void BrowserURLLoaderThrottle::set_net_event_logger(
+ NetEventLogger* net_event_logger) {
+ net_event_logger_ = net_event_logger;
+ if (url_checker_)
+ url_checker_->set_net_event_logger(net_event_logger);
}
-void BrowserURLLoaderThrottle::OnCheckUrlResult(bool safe) {
+void BrowserURLLoaderThrottle::OnCheckUrlResult(bool proceed,
+ bool showed_interstitial) {
if (blocked_)
return;
DCHECK_LT(0u, pending_checks_);
pending_checks_--;
- if (safe) {
- if (pending_checks_ == 0) {
- // The resource load is not necessarily deferred, in that case Resume() is
- // a no-op.
+ if (proceed) {
+ if (pending_checks_ == 0 && deferred_) {
+ LogDelay(base::TimeTicks::Now() - defer_start_time_);
+ deferred_ = false;
+ if (net_event_logger_) {
+ net_event_logger_->EndNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr);
+ }
+
delegate_->Resume();
}
} else {
diff --git a/chromium/components/safe_browsing/browser/browser_url_loader_throttle.h b/chromium/components/safe_browsing/browser/browser_url_loader_throttle.h
index f57ce492fd6..7a017f0e5ff 100644
--- a/chromium/components/safe_browsing/browser/browser_url_loader_throttle.h
+++ b/chromium/components/safe_browsing/browser/browser_url_loader_throttle.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "content/public/common/url_loader_throttle.h"
namespace content {
@@ -18,14 +19,14 @@ class WebContents;
namespace safe_browsing {
-class UrlCheckerDelegate;
+class NetEventLogger;
class SafeBrowsingUrlCheckerImpl;
+class UrlCheckerDelegate;
// BrowserURLLoaderThrottle is used in the browser process to query
// SafeBrowsing to determine whether a URL and also its redirect URLs are safe
// to load. It defers response processing until all URL checks are completed;
// cancels the load if any URLs turn out to be bad.
-// Used when --enable-network-service is in effect.
class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
public:
static std::unique_ptr<BrowserURLLoaderThrottle> MaybeCreate(
@@ -35,14 +36,14 @@ class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
~BrowserURLLoaderThrottle() override;
// content::URLLoaderThrottle implementation.
- void WillStartRequest(const GURL& url,
- int load_flags,
- content::ResourceType resource_type,
+ void WillStartRequest(const content::ResourceRequest& request,
bool* defer) override;
void WillRedirectRequest(const net::RedirectInfo& redirect_info,
bool* defer) override;
void WillProcessResponse(bool* defer) override;
+ void set_net_event_logger(NetEventLogger* net_event_logger);
+
private:
// |web_contents_getter| is used for displaying SafeBrowsing UI when
// necessary.
@@ -50,7 +51,7 @@ class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
const base::Callback<content::WebContents*()>& web_contents_getter);
- void OnCheckUrlResult(bool safe);
+ void OnCheckUrlResult(bool proceed, bool showed_interstitial);
// The following member stays valid until |url_checker_| is created.
scoped_refptr<UrlCheckerDelegate> url_checker_delegate_;
@@ -62,6 +63,12 @@ class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
size_t pending_checks_ = 0;
bool blocked_ = false;
+ // The time when we started deferring the request.
+ base::TimeTicks defer_start_time_;
+ bool deferred_ = false;
+
+ NetEventLogger* net_event_logger_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(BrowserURLLoaderThrottle);
};
diff --git a/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.cc b/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.cc
index 19195203517..c613b93a191 100644
--- a/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.cc
+++ b/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.cc
@@ -29,23 +29,25 @@ content::WebContents* GetWebContentsFromID(int render_process_id,
return content::WebContents::FromRenderFrameHost(render_frame_host);
}
-// This class wraps a base::OnceCallback<void(bool)> and runs it on destruction,
+// This class wraps a callback for checking URL, and runs it on destruction,
// if it hasn't been run yet.
-class BooleanCallbackWrapper {
+class CheckUrlCallbackWrapper {
public:
- using BooleanCallback = base::OnceCallback<void(bool)>;
+ using Callback = base::OnceCallback<void(bool, bool)>;
- explicit BooleanCallbackWrapper(BooleanCallback callback)
+ explicit CheckUrlCallbackWrapper(Callback callback)
: callback_(std::move(callback)) {}
- ~BooleanCallbackWrapper() {
+ ~CheckUrlCallbackWrapper() {
if (callback_)
- Run(false);
+ Run(true, false);
}
- void Run(bool value) { std::move(callback_).Run(value); }
+ void Run(bool proceed, bool showed_interstitial) {
+ std::move(callback_).Run(proceed, showed_interstitial);
+ }
private:
- BooleanCallback callback_;
+ Callback callback_;
};
} // namespace
@@ -80,19 +82,24 @@ void MojoSafeBrowsingImpl::CreateCheckerAndCheck(
int32_t render_frame_id,
mojom::SafeBrowsingUrlCheckerRequest request,
const GURL& url,
+ const std::string& method,
+ const std::string& headers,
int32_t load_flags,
content::ResourceType resource_type,
+ bool has_user_gesture,
CreateCheckerAndCheckCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
- static_cast<int>(load_flags), resource_type, delegate_,
+ headers, static_cast<int>(load_flags), resource_type, has_user_gesture,
+ delegate_,
base::Bind(&GetWebContentsFromID, render_process_id_,
static_cast<int>(render_frame_id)));
checker_impl->CheckUrl(
- url, base::BindOnce(
- &BooleanCallbackWrapper::Run,
- base::Owned(new BooleanCallbackWrapper(std::move(callback)))));
+ url, method,
+ base::BindOnce(
+ &CheckUrlCallbackWrapper::Run,
+ base::Owned(new CheckUrlCallbackWrapper(std::move(callback)))));
mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
}
diff --git a/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.h b/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.h
index fb0416a009c..8e423f5ffd7 100644
--- a/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.h
+++ b/chromium/components/safe_browsing/browser/mojo_safe_browsing_impl.h
@@ -32,8 +32,11 @@ class MojoSafeBrowsingImpl : public mojom::SafeBrowsing {
void CreateCheckerAndCheck(int32_t render_frame_id,
mojom::SafeBrowsingUrlCheckerRequest request,
const GURL& url,
+ const std::string& method,
+ const std::string& headers,
int32_t load_flags,
content::ResourceType resource_type,
+ bool has_user_gesture,
CreateCheckerAndCheckCallback callback) override;
scoped_refptr<UrlCheckerDelegate> delegate_;
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
index 174e75e939b..35387807cd9 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
+++ b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
@@ -4,11 +4,17 @@
#include "components/safe_browsing/browser/safe_browsing_url_checker_impl.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
#include "components/safe_browsing/browser/url_checker_delegate.h"
+#include "components/safe_browsing/net_event_logger.h"
+#include "components/safe_browsing/web_ui/constants.h"
#include "components/security_interstitials/content/unsafe_resource.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/log/net_log_event_type.h"
namespace safe_browsing {
namespace {
@@ -21,13 +27,26 @@ const int kCheckUrlTimeoutMs = 5000;
} // namespace
+SafeBrowsingUrlCheckerImpl::UrlInfo::UrlInfo(const GURL& in_url,
+ const std::string& in_method,
+ CheckUrlCallback in_callback)
+ : url(in_url), method(in_method), callback(std::move(in_callback)) {}
+
+SafeBrowsingUrlCheckerImpl::UrlInfo::UrlInfo(UrlInfo&& other) = default;
+
+SafeBrowsingUrlCheckerImpl::UrlInfo::~UrlInfo() = default;
+
SafeBrowsingUrlCheckerImpl::SafeBrowsingUrlCheckerImpl(
+ const std::string& headers,
int load_flags,
content::ResourceType resource_type,
+ bool has_user_gesture,
scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
const base::Callback<content::WebContents*()>& web_contents_getter)
- : load_flags_(load_flags),
+ : headers_(headers),
+ load_flags_(load_flags),
resource_type_(resource_type),
+ has_user_gesture_(has_user_gesture),
web_contents_getter_(web_contents_getter),
url_checker_delegate_(std::move(url_checker_delegate)),
database_manager_(url_checker_delegate_->GetDatabaseManager()),
@@ -36,52 +55,81 @@ SafeBrowsingUrlCheckerImpl::SafeBrowsingUrlCheckerImpl(
SafeBrowsingUrlCheckerImpl::~SafeBrowsingUrlCheckerImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (state_ == STATE_CHECKING_URL)
+ if (state_ == STATE_CHECKING_URL) {
database_manager_->CancelCheck(this);
+ if (net_event_logger_) {
+ net_event_logger_->EndNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
+ "request_canceled");
+ }
+ }
}
void SafeBrowsingUrlCheckerImpl::CheckUrl(const GURL& url,
+ const std::string& method,
CheckUrlCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
- urls_.push_back(url);
- callbacks_.push_back(std::move(callback));
+ urls_.emplace_back(url, method, std::move(callback));
ProcessUrls();
}
+const GURL& SafeBrowsingUrlCheckerImpl::GetCurrentlyCheckingUrl() const {
+ return next_index_ < urls_.size() ? urls_[next_index_].url
+ : GURL::EmptyGURL();
+}
+
void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult(
const GURL& url,
SBThreatType threat_type,
const ThreatMetadata& metadata) {
DCHECK_EQ(STATE_CHECKING_URL, state_);
DCHECK_LT(next_index_, urls_.size());
- DCHECK_EQ(urls_[next_index_], url);
+ DCHECK_EQ(urls_[next_index_].url, url);
timer_.Stop();
+
+ if (net_event_logger_) {
+ net_event_logger_->EndNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
+ threat_type == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe");
+ }
+
if (threat_type == SB_THREAT_TYPE_SAFE) {
state_ = STATE_NONE;
- std::move(callbacks_[next_index_]).Run(true);
- next_index_++;
+
+ if (!RunNextCallback(true, false))
+ return;
+
ProcessUrls();
return;
}
if (load_flags_ & net::LOAD_PREFETCH) {
// Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
- if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME)
+ if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME) {
url_checker_delegate_->MaybeDestroyPrerenderContents(
web_contents_getter_);
- BlockAndProcessUrls();
+ }
+ UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.UnsafePrefetchCanceled",
+ resource_type_, content::RESOURCE_TYPE_LAST_TYPE);
+ BlockAndProcessUrls(false);
return;
}
+ UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_,
+ content::RESOURCE_TYPE_LAST_TYPE);
+
security_interstitials::UnsafeResource resource;
resource.url = url;
- resource.original_url = urls_[0];
- if (urls_.size() > 1)
- resource.redirect_urls = std::vector<GURL>(urls_.begin() + 1, urls_.end());
+ resource.original_url = urls_[0].url;
+ if (urls_.size() > 1) {
+ resource.redirect_urls.reserve(urls_.size() - 1);
+ for (size_t i = 1; i < urls_.size(); ++i)
+ resource.redirect_urls.push_back(urls_[i].url);
+ }
resource.is_subresource = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME;
resource.is_subframe = resource_type_ == content::RESOURCE_TYPE_SUB_FRAME;
resource.threat_type = threat_type;
@@ -94,15 +142,20 @@ void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult(
resource.web_contents_getter = web_contents_getter_;
resource.threat_source = database_manager_->GetThreatSource();
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(headers_);
+
state_ = STATE_DISPLAYING_BLOCKING_PAGE;
- url_checker_delegate_->StartDisplayingBlockingPageHelper(resource);
+ url_checker_delegate_->StartDisplayingBlockingPageHelper(
+ resource, urls_[next_index_].method, headers,
+ resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME, has_user_gesture_);
}
void SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout() {
database_manager_->CancelCheck(this);
- OnCheckBrowseUrlResult(urls_[next_index_], safe_browsing::SB_THREAT_TYPE_SAFE,
- ThreatMetadata());
+ OnCheckBrowseUrlResult(urls_[next_index_].url,
+ safe_browsing::SB_THREAT_TYPE_SAFE, ThreatMetadata());
}
void SafeBrowsingUrlCheckerImpl::ProcessUrls() {
@@ -115,19 +168,72 @@ void SafeBrowsingUrlCheckerImpl::ProcessUrls() {
while (next_index_ < urls_.size()) {
DCHECK_EQ(STATE_NONE, state_);
+
+ const GURL& url = urls_[next_index_].url;
+
+ TRACE_EVENT1("loader", "SafeBrowsingUrlCheckerImpl::ProcessUrls", "url",
+ url.spec());
+
+ if (url_checker_delegate_->IsUrlWhitelisted(url)) {
+ if (!RunNextCallback(true, false))
+ return;
+
+ continue;
+ }
+
// TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
// side. That would save some IPCs. It requires a method on the
// SafeBrowsing mojo interface to query all supported resource types.
- if (!database_manager_->CanCheckResourceType(resource_type_) ||
- database_manager_->CheckBrowseUrl(
- urls_[next_index_], url_checker_delegate_->GetThreatTypes(),
- this)) {
- std::move(callbacks_[next_index_]).Run(true);
- next_index_++;
+ if (!database_manager_->CanCheckResourceType(resource_type_)) {
+ // TODO(vakh): Consider changing this metric to
+ // SafeBrowsing.V4ResourceType to be consistent with the other PVer4
+ // metrics.
+ UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Skipped", resource_type_,
+ content::RESOURCE_TYPE_LAST_TYPE);
+
+ if (!RunNextCallback(true, false))
+ return;
+
+ continue;
+ }
+
+ // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType
+ // to be consistent with the other PVer4 metrics.
+ UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Checked", resource_type_,
+ content::RESOURCE_TYPE_LAST_TYPE);
+
+ SBThreatType threat_type = CheckWebUIUrls(url);
+ if (threat_type != safe_browsing::SB_THREAT_TYPE_SAFE) {
+ state_ = STATE_CHECKING_URL;
+ if (net_event_logger_) {
+ net_event_logger_->BeginNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr,
+ nullptr);
+ }
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult,
+ weak_factory_.GetWeakPtr(), url, threat_type,
+ ThreatMetadata()));
+ break;
+ }
+
+ if (database_manager_->CheckBrowseUrl(
+ url, url_checker_delegate_->GetThreatTypes(), this)) {
+ if (!RunNextCallback(true, false))
+ return;
+
continue;
}
state_ = STATE_CHECKING_URL;
+ if (net_event_logger_) {
+ net_event_logger_->BeginNetLogEvent(
+ net::NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr,
+ nullptr);
+ }
+
// Start a timer to abort the check if it takes too long.
timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
@@ -137,14 +243,17 @@ void SafeBrowsingUrlCheckerImpl::ProcessUrls() {
}
}
-void SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls() {
- DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
+void SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls(bool showed_interstitial) {
+ DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: "
+ << urls_[next_index_].url;
state_ = STATE_BLOCKED;
// If user decided to not proceed through a warning, mark all the remaining
// redirects as "bad".
- for (; next_index_ < callbacks_.size(); ++next_index_)
- std::move(callbacks_[next_index_]).Run(false);
+ for (; next_index_ < urls_.size(); ++next_index_) {
+ if (!RunNextCallback(false, showed_interstitial))
+ return;
+ }
}
void SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete(bool proceed) {
@@ -152,12 +261,35 @@ void SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete(bool proceed) {
if (proceed) {
state_ = STATE_NONE;
- std::move(callbacks_[next_index_]).Run(true);
- next_index_++;
+ if (!RunNextCallback(true, true))
+ return;
ProcessUrls();
} else {
- BlockAndProcessUrls();
+ BlockAndProcessUrls(true);
}
}
+SBThreatType SafeBrowsingUrlCheckerImpl::CheckWebUIUrls(const GURL& url) {
+ // TODO(yzshen): This duplicates the logic in
+ // safe_browsing::BaseResourceThrottle::CheckWebUIUrls(), which eventually
+ // will go away. crbug.com/715673
+ if (url == kChromeUISafeBrowsingMatchMalwareUrl)
+ return safe_browsing::SB_THREAT_TYPE_URL_MALWARE;
+ if (url == kChromeUISafeBrowsingMatchPhishingUrl)
+ return safe_browsing::SB_THREAT_TYPE_URL_PHISHING;
+ if (url == kChromeUISafeBrowsingMatchUnwantedUrl)
+ return safe_browsing::SB_THREAT_TYPE_URL_UNWANTED;
+
+ return safe_browsing::SB_THREAT_TYPE_SAFE;
+}
+
+bool SafeBrowsingUrlCheckerImpl::RunNextCallback(bool proceed,
+ bool showed_interstitial) {
+ DCHECK_LT(next_index_, urls_.size());
+
+ auto weak_self = weak_factory_.GetWeakPtr();
+ std::move(urls_[next_index_++].callback).Run(proceed, showed_interstitial);
+ return !!weak_self;
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.h b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
index b037d8dcfd0..83328e6980e 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
+++ b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
@@ -22,6 +22,7 @@ class WebContents;
namespace safe_browsing {
+class NetEventLogger;
class UrlCheckerDelegate;
// A SafeBrowsingUrlCheckerImpl instance is used to perform SafeBrowsing check
@@ -29,22 +30,31 @@ class UrlCheckerDelegate;
// be used to handle queries from renderers. But it is also used to handle
// queries from the browser. In that case, the public methods are called
// directly instead of through Mojo.
-// Used when --enable-network-service is in effect.
-//
-// TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
public SafeBrowsingDatabaseManager::Client {
public:
SafeBrowsingUrlCheckerImpl(
+ const std::string& headers,
int load_flags,
content::ResourceType resource_type,
+ bool has_user_gesture,
scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
const base::Callback<content::WebContents*()>& web_contents_getter);
~SafeBrowsingUrlCheckerImpl() override;
// mojom::SafeBrowsingUrlChecker implementation.
- void CheckUrl(const GURL& url, CheckUrlCallback callback) override;
+ // NOTE: |callback| could be run synchronously before this method returns. Be
+ // careful if |callback| could destroy this object.
+ void CheckUrl(const GURL& url,
+ const std::string& method,
+ CheckUrlCallback callback) override;
+
+ const GURL& GetCurrentlyCheckingUrl() const;
+
+ void set_net_event_logger(NetEventLogger* net_event_logger) {
+ net_event_logger_ = net_event_logger;
+ }
private:
// SafeBrowsingDatabaseManager::Client implementation:
@@ -54,12 +64,20 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
void OnCheckUrlTimeout();
+ // NOTE: this method runs callbacks which could destroy this object.
void ProcessUrls();
- void BlockAndProcessUrls();
+ // NOTE: this method runs callbacks which could destroy this object.
+ void BlockAndProcessUrls(bool showed_interstitial);
void OnBlockingPageComplete(bool proceed);
+ SBThreatType CheckWebUIUrls(const GURL& url);
+
+ // Returns false if this object has been destroyed by the callback. In that
+ // case none of the members of this object should be touched again.
+ bool RunNextCallback(bool proceed, bool showed_interstitial);
+
enum State {
// Haven't started checking or checking is complete.
STATE_NONE,
@@ -71,18 +89,30 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
STATE_BLOCKED
};
+ struct UrlInfo {
+ UrlInfo(const GURL& url,
+ const std::string& method,
+ CheckUrlCallback callback);
+ UrlInfo(UrlInfo&& other);
+
+ ~UrlInfo();
+
+ GURL url;
+ std::string method;
+ CheckUrlCallback callback;
+ };
+
+ const std::string headers_;
const int load_flags_;
const content::ResourceType resource_type_;
+ const bool has_user_gesture_;
base::Callback<content::WebContents*()> web_contents_getter_;
scoped_refptr<UrlCheckerDelegate> url_checker_delegate_;
scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
// The redirect chain for this resource, including the original URL and
// subsequent redirect URLs.
- std::vector<GURL> urls_;
- // Callbacks corresponding to |urls_| to report check results. |urls_| and
- // |callbacks_| are always of the same size.
- std::vector<CheckUrlCallback> callbacks_;
+ std::vector<UrlInfo> urls_;
// |urls_| before |next_index_| have been checked. If |next_index_| is smaller
// than the size of |urls_|, the URL at |next_index_| is being processed.
size_t next_index_ = 0;
@@ -92,6 +122,8 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
// Timer to abort the SafeBrowsing check if it takes too long.
base::OneShotTimer timer_;
+ NetEventLogger* net_event_logger_ = nullptr;
+
base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_url_request_context_getter.cc b/chromium/components/safe_browsing/browser/safe_browsing_url_request_context_getter.cc
index 7c5ce4a4073..102567c9a09 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_url_request_context_getter.cc
+++ b/chromium/components/safe_browsing/browser/safe_browsing_url_request_context_getter.cc
@@ -61,7 +61,7 @@ SafeBrowsingURLRequestContextGetter::GetURLRequestContext() {
// Set up the CookieStore
content::CookieStoreConfig cookie_config(
CookieFilePath(), content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
- nullptr, nullptr);
+ nullptr);
cookie_config.channel_id_service = channel_id_service_.get();
cookie_config.background_task_runner = background_task_runner;
safe_browsing_cookie_store_ = content::CreateCookieStore(cookie_config);
diff --git a/chromium/components/safe_browsing/browser/threat_details.cc b/chromium/components/safe_browsing/browser/threat_details.cc
index b1fe8d6ee44..d7d5df569c6 100644
--- a/chromium/components/safe_browsing/browser/threat_details.cc
+++ b/chromium/components/safe_browsing/browser/threat_details.cc
@@ -8,6 +8,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <unordered_set>
+#include <vector>
#include "base/bind.h"
#include "base/lazy_instance.h"
@@ -43,6 +45,9 @@ ThreatDetailsFactory* ThreatDetails::factory_ = NULL;
namespace {
+// An element ID indicating that an HTML Element has no parent.
+const int kElementIdNoParent = -1;
+
typedef std::unordered_set<std::string> StringSet;
// A set of HTTPS headers that are allowed to be collected. Contains both
// request and response headers. All entries in this list should be lower-case
@@ -79,6 +84,8 @@ ClientSafeBrowsingReportRequest::ReportType GetReportTypeFromSBThreatType(
return ClientSafeBrowsingReportRequest::URL_CLIENT_SIDE_MALWARE;
case SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
return ClientSafeBrowsingReportRequest::URL_PASSWORD_PROTECTION_PHISHING;
+ case SB_THREAT_TYPE_AD_SAMPLE:
+ return ClientSafeBrowsingReportRequest::AD_SAMPLE;
default: // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails.
NOTREACHED() << "We should not send report for threat type "
<< threat_type;
@@ -151,6 +158,103 @@ CSBRR::SafeBrowsingUrlApiType GetUrlApiTypeForThreatSource(
}
return CSBRR::SAFE_BROWSING_URL_API_TYPE_UNSPECIFIED;
}
+
+void TrimElements(const std::set<int> target_ids,
+ ElementMap* elements,
+ ResourceMap* resources) {
+ if (target_ids.empty()) {
+ elements->clear();
+ resources->clear();
+ return;
+ }
+
+ // First, scan over the elements and create a list ordered by element ID as
+ // well as a reverse mapping from element ID to its parent ID.
+ std::vector<HTMLElement*> elements_by_id(elements->size());
+
+ // The parent vector is initialized with |kElementIdNoParent| so we can
+ // identify elements that have no parent.
+ std::vector<int> element_id_to_parent_id(elements->size(),
+ kElementIdNoParent);
+ for (const auto& element_pair : *elements) {
+ HTMLElement* element = element_pair.second.get();
+ elements_by_id[element->id()] = element;
+
+ for (int child_id : element->child_ids()) {
+ element_id_to_parent_id[child_id] = element->id();
+ }
+ }
+
+ // Create a similar map for resources, ordered by resource ID.
+ std::vector<std::string> resource_id_to_url(resources->size());
+ for (const auto& resource_pair : *resources) {
+ const std::string& url = resource_pair.first;
+ ClientSafeBrowsingReportRequest::Resource* resource =
+ resource_pair.second.get();
+ resource_id_to_url[resource->id()] = url;
+ }
+
+ // Take a second pass and determine which element IDs to keep. We want to keep
+ // both siblings and children of the target ids. We start by identifying the
+ // siblings by finding the common parent of each target element, and keeping
+ // all of its children (ie: the siblings of the target elements).
+ std::vector<int> ids_to_keep;
+ // Keep track of ids that were kept to avoid duplicated. We still need the
+ // vector above for handling the children where it is used like a queue.
+ std::unordered_set<int> kept_ids;
+ for (int target_id : target_ids) {
+ const int parent_id = element_id_to_parent_id[target_id];
+ if (parent_id == kElementIdNoParent) {
+ // If one of the target elements has no parent then we skip trimming the
+ // report further. Since we collect all siblings of this element, it will
+ // effectively span the whole report, so no trimming necessary.
+ return;
+ }
+
+ const HTMLElement* parent_element = elements_by_id[parent_id];
+ for (int sibling_id : parent_element->child_ids()) {
+ if (kept_ids.count(sibling_id) == 0) {
+ ids_to_keep.push_back(sibling_id);
+ kept_ids.insert(sibling_id);
+ }
+ }
+ }
+
+ // Walk through |ids_to_keep| and append the children of each of element to
+ // |ids_to_keep|. This is effectively a breadth-first traversal of the tree.
+ // The list will stop growing when we reach the leaf nodes that have no more
+ // children.
+ for (size_t index = 0; index < ids_to_keep.size(); ++index) {
+ int cur_element_id = ids_to_keep[index];
+ const HTMLElement& element = *(elements_by_id[cur_element_id]);
+ for (int child_id : element.child_ids()) {
+ ids_to_keep.push_back(child_id);
+ }
+ }
+ // Sort the list for easier lookup below.
+ std::sort(ids_to_keep.begin(), ids_to_keep.end());
+
+ // Now we know which elements we want to keep, scan through |elements| and
+ // erase anything that we aren't keeping. If an erased element refers to a
+ // resource then remove it from |resources| as well.
+ for (auto element_iter = elements->begin();
+ element_iter != elements->end();) {
+ const HTMLElement& element = *element_iter->second;
+
+ // Delete any elements that we do not want to keep.
+ if (std::find(ids_to_keep.begin(), ids_to_keep.end(), element.id()) ==
+ ids_to_keep.end()) {
+ if (element.has_resource_id()) {
+ const std::string& resource_url =
+ resource_id_to_url[element.resource_id()];
+ resources->erase(resource_url);
+ }
+ element_iter = elements->erase(element_iter);
+ } else {
+ ++element_iter;
+ }
+ }
+}
} // namespace
// The default ThreatDetailsFactory. Global, made a singleton so we
@@ -162,9 +266,11 @@ class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
WebContents* web_contents,
const security_interstitials::UnsafeResource& unsafe_resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service) override {
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags) override {
return new ThreatDetails(ui_manager, web_contents, unsafe_resource,
- request_context_getter, history_service);
+ request_context_getter, history_service,
+ trim_to_ad_tags);
}
private:
@@ -185,13 +291,15 @@ ThreatDetails* ThreatDetails::NewThreatDetails(
WebContents* web_contents,
const UnsafeResource& resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service) {
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags) {
// Set up the factory if this has not been done already (tests do that
// before this method is called).
if (!factory_)
factory_ = g_threat_details_factory_impl.Pointer();
return factory_->CreateThreatDetails(ui_manager, web_contents, resource,
- request_context_getter, history_service);
+ request_context_getter, history_service,
+ trim_to_ad_tags);
}
// Create a ThreatDetails for the given tab. Runs in the UI thread.
@@ -200,7 +308,8 @@ ThreatDetails::ThreatDetails(
content::WebContents* web_contents,
const UnsafeResource& resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service)
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags)
: content::WebContentsObserver(web_contents),
request_context_getter_(request_context_getter),
ui_manager_(ui_manager),
@@ -209,6 +318,7 @@ ThreatDetails::ThreatDetails(
did_proceed_(false),
num_visits_(0),
ambiguous_dom_(false),
+ trim_to_ad_tags_(trim_to_ad_tags),
cache_collector_(new ThreatDetailsCacheCollector) {
redirects_collector_ = new ThreatDetailsRedirectsCollector(
history_service ? history_service->AsWeakPtr()
@@ -216,11 +326,14 @@ ThreatDetails::ThreatDetails(
StartCollection();
}
+// TODO(lpz): Consider making this constructor delegate to the parameterized one
+// above.
ThreatDetails::ThreatDetails()
: cache_result_(false),
did_proceed_(false),
num_visits_(0),
- ambiguous_dom_(false) {}
+ ambiguous_dom_(false),
+ trim_to_ad_tags_(false) {}
ThreatDetails::~ThreatDetails() {}
@@ -336,6 +449,12 @@ void ThreatDetails::AddDomElement(
HTMLElement::Attribute* attribute_pb = cur_element->add_attribute();
attribute_pb->set_name(attribute.first);
attribute_pb->set_value(attribute.second);
+
+ // Remember which the IDs of elements that represent ads so we can trim the
+ // report down to just those parts later.
+ if (trim_to_ad_tags_ && attribute_pb->name() == "data-google-query-id") {
+ trimmed_dom_element_ids_.insert(cur_element->id());
+ }
}
if (resource) {
@@ -544,6 +663,11 @@ void ThreatDetails::FinishCollection(bool did_proceed, int num_visit) {
}
}
}
+
+ if (trim_to_ad_tags_) {
+ TrimElements(trimmed_dom_element_ids_, &elements_, &resources_);
+ }
+
did_proceed_ = did_proceed;
num_visits_ = num_visit;
std::vector<GURL> urls;
diff --git a/chromium/components/safe_browsing/browser/threat_details.h b/chromium/components/safe_browsing/browser/threat_details.h
index adbda2996a7..b633bca77c9 100644
--- a/chromium/components/safe_browsing/browser/threat_details.h
+++ b/chromium/components/safe_browsing/browser/threat_details.h
@@ -21,7 +21,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/safe_browsing/common/safebrowsing_types.h"
-#include "components/safe_browsing/csd.pb.h"
+#include "components/safe_browsing/proto/csd.pb.h"
#include "components/security_interstitials/content/unsafe_resource.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents_observer.h"
@@ -77,7 +77,8 @@ class ThreatDetails : public base::RefCountedThreadSafe<
content::WebContents* web_contents,
const UnsafeResource& resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service);
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags);
// Makes the passed |factory| the factory used to instantiate
// SafeBrowsingBlockingPage objects. Useful for tests.
@@ -109,7 +110,8 @@ class ThreatDetails : public base::RefCountedThreadSafe<
content::WebContents* web_contents,
const UnsafeResource& resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service);
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags);
// Default constructor for testing only.
ThreatDetails();
@@ -218,6 +220,15 @@ class ThreatDetails : public base::RefCountedThreadSafe<
// associated with a parent Element in the parent frame.
bool ambiguous_dom_;
+ // Whether this report should be trimmed down to only ad tags, not the entire
+ // page contents. Used for sampling ads.
+ bool trim_to_ad_tags_;
+
+ // A vector containing the IDs of the DOM Elements to trim to. If an element
+ // ID is in this list, then its siblings and its children should be included
+ // in the report. Only populated if this report will be trimmed.
+ std::set<int> trimmed_dom_element_ids_;
+
// The factory used to instantiate SafeBrowsingBlockingPage objects.
// Useful for tests, so they can provide their own implementation of
// SafeBrowsingBlockingPage.
@@ -235,6 +246,7 @@ class ThreatDetails : public base::RefCountedThreadSafe<
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HTTPCache);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames);
+ FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails);
DISALLOW_COPY_AND_ASSIGN(ThreatDetails);
@@ -250,7 +262,8 @@ class ThreatDetailsFactory {
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& unsafe_resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service) = 0;
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags) = 0;
};
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/browser/threat_details_cache.cc b/chromium/components/safe_browsing/browser/threat_details_cache.cc
index 8604cb0d012..419cb89f9a0 100644
--- a/chromium/components/safe_browsing/browser/threat_details_cache.cc
+++ b/chromium/components/safe_browsing/browser/threat_details_cache.cc
@@ -94,7 +94,7 @@ void ThreatDetailsCacheCollector::OpenEntry() {
destination: OTHER
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature by stopping sending "
"security incident reports to Google via disabling 'Automatically "
diff --git a/chromium/components/safe_browsing/browser/url_checker_delegate.h b/chromium/components/safe_browsing/browser/url_checker_delegate.h
index 02f442e0405..3a375af817d 100644
--- a/chromium/components/safe_browsing/browser/url_checker_delegate.h
+++ b/chromium/components/safe_browsing/browser/url_checker_delegate.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_SAFE_BROWSING_BROWSER_URL_CHECKER_DELEGATE_H_
#define COMPONENTS_SAFE_BROWSING_BROWSER_URL_CHECKER_DELEGATE_H_
+#include <string>
+
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
@@ -13,6 +15,10 @@ namespace content {
class WebContents;
}
+namespace net {
+class HttpRequestHeaders;
+}
+
namespace security_interstitials {
struct UnsafeResource;
}
@@ -22,9 +28,10 @@ namespace safe_browsing {
class BaseUIManager;
class SafeBrowsingDatabaseManager;
-// Delegate interface for SafeBrowsingUrlCheckerImpl. SafeBrowsingUrlCheckerImpl
-// is embedder-independent. It delegates to this interface those operations that
-// different embedders (Chrome and Android WebView) handle differently.
+// Delegate interface for SafeBrowsingUrlCheckerImpl and SafeBrowsing's
+// content::ResourceThrottle subclasses. They delegate to this interface those
+// operations that different embedders (Chrome and Android WebView) handle
+// differently.
//
// All methods should only be called from the IO thread.
class UrlCheckerDelegate
@@ -36,7 +43,15 @@ class UrlCheckerDelegate
// Starts displaying the SafeBrowsing interstitial page.
virtual void StartDisplayingBlockingPageHelper(
- const security_interstitials::UnsafeResource& resource) = 0;
+ const security_interstitials::UnsafeResource& resource,
+ const std::string& method,
+ const net::HttpRequestHeaders& headers,
+ bool is_main_frame,
+ bool has_user_gesture) = 0;
+
+ // A whitelisted URL is considered safe and therefore won't be checked with
+ // the SafeBrowsing database.
+ virtual bool IsUrlWhitelisted(const GURL& url) = 0;
virtual const SBThreatTypeSet& GetThreatTypes() = 0;
virtual SafeBrowsingDatabaseManager* GetDatabaseManager() = 0;
diff --git a/chromium/components/safe_browsing/common/safe_browsing.mojom b/chromium/components/safe_browsing/common/safe_browsing.mojom
index 5b7ae9544c7..ee79cb2e9c8 100644
--- a/chromium/components/safe_browsing/common/safe_browsing.mojom
+++ b/chromium/components/safe_browsing/common/safe_browsing.mojom
@@ -7,25 +7,38 @@ module safe_browsing.mojom;
import "content/public/common/resource_type.mojom";
import "url/mojo/url.mojom";
+// Provided by the browser and used by renderers to perform SafeBrowsing URL
+// checks.
interface SafeBrowsing {
// Queries SafeBrowsing whether |url| is safe to load, and creates a
// SafeBrowsingUrlChecker interface.
- // This checker interface should be used (and only used) for subsequent checks
- // of redirects, so that the server side could keep track of the redirect
- // chain. Disconnecting the checker interface cancels on-going URL checks.
- // Please note that in that case if the check started by this method hasn't
- // completed yet, it will also be canceled and return true as if the URL is
- // safe.
+ //
// The check and (subsequent checks performed using SafeBrowsingUrlChecker)
// checks against SafeBrowsing's Malware, Phishing, and UwS blacklists.
+ //
+ // The SafeBrowsingUrlChecker interface should be used (and only used) for
+ // subsequent checks of redirects, so that the server side could keep track of
+ // the redirect chain. Disconnecting the checker interface cancels on-going
+ // URL checks. Please note that in that case if the check started by this
+ // method hasn't completed yet, it will also be canceled and the callback is
+ // ran with |proceed == true| and |showed_interstitial == false| as if the URL
+ // is safe.
+ //
+ // |proceed| indicates whether it is okay to proceed with loading the URL.
+ // |showed_interstitial| indicates whether the SafeBrowsing interstitial page
+ // has been shown to the user.
CreateCheckerAndCheck(
int32 render_frame_id,
SafeBrowsingUrlChecker& request,
url.mojom.Url url,
+ string method,
+ string headers,
int32 load_flags,
- content.mojom.ResourceType resource_type) => (bool safe);
+ content.mojom.ResourceType resource_type,
+ bool has_user_gesture) => (bool proceed, bool showed_interstitial);
};
interface SafeBrowsingUrlChecker {
- CheckUrl(url.mojom.Url url) => (bool safe);
+ CheckUrl(url.mojom.Url url, string method)
+ => (bool proceed, bool showed_interstitial);
};
diff --git a/chromium/components/safe_browsing/common/safe_browsing_prefs.cc b/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
index 6747a0d50dc..2ebf20d05ee 100644
--- a/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -141,6 +141,8 @@ void RecordExtendedReportingPrefChanged(
} // namespace
namespace prefs {
+const char kSafeBrowsingChangePasswordInSettingsEnabled[] =
+ "safebrowsing.change_password_enabled";
const char kSafeBrowsingEnabled[] = "safebrowsing.enabled";
const char kSafeBrowsingExtendedReportingEnabled[] =
"safebrowsing.extended_reporting_enabled";
@@ -358,6 +360,8 @@ void RecordExtendedReportingMetrics(const PrefService& prefs) {
}
void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref(
+ prefs::kSafeBrowsingChangePasswordInSettingsEnabled, false);
registry->RegisterBooleanPref(prefs::kSafeBrowsingExtendedReportingEnabled,
false);
registry->RegisterBooleanPref(prefs::kSafeBrowsingScoutReportingEnabled,
diff --git a/chromium/components/safe_browsing/common/safe_browsing_prefs.h b/chromium/components/safe_browsing/common/safe_browsing_prefs.h
index 76c7913b02f..460588869b4 100644
--- a/chromium/components/safe_browsing/common/safe_browsing_prefs.h
+++ b/chromium/components/safe_browsing/common/safe_browsing_prefs.h
@@ -14,6 +14,10 @@ class PrefRegistrySimple;
class PrefService;
namespace prefs {
+// Boolean that is true when Chrome settings page should show change password
+// warning.
+extern const char kSafeBrowsingChangePasswordInSettingsEnabled[];
+
// Boolean that is true when SafeBrowsing is enabled.
extern const char kSafeBrowsingEnabled[];
@@ -85,7 +89,7 @@ enum ExtendedReportingLevel {
// These values are written to logs. New enum values can be added, but
// existing enums must never be renumbered or deleted and reused.
enum ExtendedReportingOptInLocation {
- // The chrome://settings UI (also shared with chrome://md-settings).
+ // The chrome://settings UI.
SBER_OPTIN_SITE_CHROME_SETTINGS = 0,
// The Android settings UI.
SBER_OPTIN_SITE_ANDROID_SETTINGS = 1,
diff --git a/chromium/components/safe_browsing/common/utils.cc b/chromium/components/safe_browsing/common/utils.cc
index 67baa8c13cc..52a75fea9f1 100644
--- a/chromium/components/safe_browsing/common/utils.cc
+++ b/chromium/components/safe_browsing/common/utils.cc
@@ -4,6 +4,7 @@
#include "components/safe_browsing/common/utils.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "crypto/sha2.h"
@@ -22,4 +23,8 @@ std::string ShortURLForReporting(const GURL& url) {
return spec;
}
+void LogDelay(base::TimeDelta time) {
+ UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/common/utils.h b/chromium/components/safe_browsing/common/utils.h
index fa3b8a771d0..9a0965da886 100644
--- a/chromium/components/safe_browsing/common/utils.h
+++ b/chromium/components/safe_browsing/common/utils.h
@@ -1,4 +1,4 @@
-// Copyrights 2017 The Chromium Authors. All rights reserved.
+// 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.
//
@@ -7,6 +7,7 @@
#ifndef COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
#define COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
+#include "base/time/time.h"
#include "url/gurl.h"
namespace safe_browsing {
@@ -15,6 +16,13 @@ namespace safe_browsing {
// scheme.
std::string ShortURLForReporting(const GURL& url);
+// UMA histogram helper for logging "SB2.Delay".
+// Logs the user perceived delay caused by SafeBrowsing. This delay is the time
+// delta starting from when we would have started reading data from the network,
+// and ending when the SafeBrowsing check completes indicating that the current
+// page is 'safe'.
+void LogDelay(base::TimeDelta time);
+
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
diff --git a/chromium/components/safe_browsing/db/BUILD.gn b/chromium/components/safe_browsing/db/BUILD.gn
new file mode 100644
index 00000000000..9c30f2654b8
--- /dev/null
+++ b/chromium/components/safe_browsing/db/BUILD.gn
@@ -0,0 +1,91 @@
+# 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.
+
+# This target is for the mobile version.
+group("safe_browsing_mobile") {
+ deps = [
+ ":remote_database_manager",
+ ":safe_browsing_api_handler",
+ ":safe_browsing_api_handler_util",
+ "//components/safe_browsing_db:safe_browsing_db_shared",
+ ]
+}
+
+static_library("remote_database_manager") {
+ sources = [
+ "remote_database_manager.cc",
+ "remote_database_manager.h",
+ ]
+ deps = [
+ ":safe_browsing_api_handler",
+ "//base:base",
+ "//components/safe_browsing_db:database_manager",
+ "//components/safe_browsing_db:v4_get_hash_protocol_manager",
+ "//components/safe_browsing_db:v4_protocol_manager_util",
+ "//components/variations",
+ "//content/public/browser",
+ "//net",
+ "//url",
+ ]
+}
+
+static_library("safe_browsing_api_handler_util") {
+ sources = [
+ "safe_browsing_api_handler_util.cc",
+ "safe_browsing_api_handler_util.h",
+ ]
+ deps = [
+ "//base",
+ "//components/safe_browsing_db:metadata_proto",
+ "//components/safe_browsing_db:util",
+ ]
+}
+
+source_set("safe_browsing_api_handler") {
+ sources = [
+ "safe_browsing_api_handler.cc",
+ "safe_browsing_api_handler.h",
+ ]
+ deps = [
+ ":safe_browsing_api_handler_util",
+ "//base",
+ "//components/safe_browsing_db:util",
+ "//content/public/browser:browser",
+ "//url",
+ ]
+
+ if (is_android) {
+ deps += [ "//components/safe_browsing/android:jni_headers" ]
+ sources += [
+ "//components/safe_browsing/android/safe_browsing_api_handler_bridge.cc",
+ "//components/safe_browsing/android/safe_browsing_api_handler_bridge.h",
+ ]
+ }
+}
+
+source_set("unit_tests_mobile") {
+ testonly = true
+ sources = [
+ "remote_database_manager_unittest.cc",
+ "safe_browsing_api_handler_unittest.cc",
+ ]
+ deps = [
+ ":remote_database_manager",
+ ":safe_browsing_api_handler",
+ ":safe_browsing_api_handler_util",
+ "//base",
+ "//components/safe_browsing_db:metadata_proto",
+ "//components/safe_browsing_db:unit_tests_shared",
+ "//components/safe_browsing_db:util",
+ "//components/safe_browsing_db:v4_test_util",
+ "//components/variations",
+ "//content/test:test_support",
+ "//testing/gtest",
+ "//url",
+ ]
+ if (is_win) {
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ cflags = [ "/wd4267" ] # Conversion from size_t to 'type'.
+ }
+}
diff --git a/chromium/components/safe_browsing/db/DEPS b/chromium/components/safe_browsing/db/DEPS
new file mode 100644
index 00000000000..a9774be7966
--- /dev/null
+++ b/chromium/components/safe_browsing/db/DEPS
@@ -0,0 +1,10 @@
+include_rules = [
+ "+base",
+ "+components/safe_browsing_db",
+ "+components/variations",
+ "+content/public/test",
+ "+net",
+ "+testing/gtest",
+ "+url",
+
+]
diff --git a/chromium/components/safe_browsing_db/remote_database_manager.cc b/chromium/components/safe_browsing/db/remote_database_manager.cc
index 5762d41831c..7a3d04b91dc 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager.cc
+++ b/chromium/components/safe_browsing/db/remote_database_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/safe_browsing_db/remote_database_manager.h"
+#include "components/safe_browsing/db/remote_database_manager.h"
#include <memory>
#include <vector>
@@ -11,7 +11,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/timer/elapsed_timer.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler.h"
+#include "components/safe_browsing/db/safe_browsing_api_handler.h"
#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/variations/variations_associated_data.h"
@@ -38,7 +38,6 @@ void LogPendingChecks(size_t current_requests_size) {
} // namespace
-
//
// RemoteSafeBrowsingDatabaseManager::ClientRequest methods
//
@@ -329,8 +328,8 @@ bool RemoteSafeBrowsingDatabaseManager::IsSupported() const {
}
void RemoteSafeBrowsingDatabaseManager::StartOnIOThread(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) {
+ net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config) {
VLOG(1) << "RemoteSafeBrowsingDatabaseManager starting";
SafeBrowsingDatabaseManager::StartOnIOThread(request_context_getter, config);
enabled_ = true;
diff --git a/chromium/components/safe_browsing_db/remote_database_manager.h b/chromium/components/safe_browsing/db/remote_database_manager.h
index c2a30ff2016..c2a30ff2016 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager.h
+++ b/chromium/components/safe_browsing/db/remote_database_manager.h
diff --git a/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc b/chromium/components/safe_browsing/db/remote_database_manager_unittest.cc
index 4a2b49a99d7..32ae5c554b8 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing/db/remote_database_manager_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_db/remote_database_manager.h"
+#include "components/safe_browsing/db/remote_database_manager.h"
#include <memory>
@@ -11,7 +11,7 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler.h"
+#include "components/safe_browsing/db/safe_browsing_api_handler.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/safe_browsing_db/safe_browsing_api_handler.cc b/chromium/components/safe_browsing/db/safe_browsing_api_handler.cc
index 528dccbf8cb..49cb58cf5ca 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_api_handler.cc
+++ b/chromium/components/safe_browsing/db/safe_browsing_api_handler.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/safe_browsing/db/safe_browsing_api_handler.h"
#include "base/bind.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler.h"
namespace safe_browsing {
diff --git a/chromium/components/safe_browsing_db/safe_browsing_api_handler.h b/chromium/components/safe_browsing/db/safe_browsing_api_handler.h
index f2e7abaf63c..e83e19a8fe9 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_api_handler.h
+++ b/chromium/components/safe_browsing/db/safe_browsing_api_handler.h
@@ -42,4 +42,4 @@ class SafeBrowsingApiHandler {
} // namespace safe_browsing
-#endif // COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_API_HANDLER_H_
+#endif // COMPONENTS_SAFE_BROWSING_SAFE_BROWSING_API_HANDLER_H_
diff --git a/chromium/components/safe_browsing_db/safe_browsing_api_handler_unittest.cc b/chromium/components/safe_browsing/db/safe_browsing_api_handler_unittest.cc
index c466dd99021..2ee2e4fe8f6 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_api_handler_unittest.cc
+++ b/chromium/components/safe_browsing/db/safe_browsing_api_handler_unittest.cc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/safe_browsing/db/safe_browsing_api_handler_util.h"
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
#include "components/safe_browsing_db/metadata.pb.h"
-#include "components/safe_browsing_db/safe_browsing_api_handler_util.h"
#include "components/safe_browsing_db/util.h"
#include "components/safe_browsing_db/v4_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +25,6 @@ class SafeBrowsingApiHandlerUtilTest : public ::testing::Test {
meta_ = ThreatMetadata();
return ParseJsonFromGMSCore(json, &threat_, &meta_);
}
-
};
TEST_F(SafeBrowsingApiHandlerUtilTest, BadJson) {
@@ -149,7 +152,7 @@ TEST_F(SafeBrowsingApiHandlerUtilTest, PopulationId) {
EXPECT_NE(empty_meta_, meta_);
}
-TEST_F(SafeBrowsingApiHandlerUtilTest, SubresourceFilterSubTypes) {
+TEST_F(SafeBrowsingApiHandlerUtilTest, NoSubresourceFilterSubTypes) {
ThreatMetadata expected;
EXPECT_EQ(UMA_STATUS_MATCH,
@@ -157,6 +160,42 @@ TEST_F(SafeBrowsingApiHandlerUtilTest, SubresourceFilterSubTypes) {
EXPECT_EQ(SB_THREAT_TYPE_SUBRESOURCE_FILTER, threat_);
expected.threat_pattern_type = ThreatPatternType::NONE;
EXPECT_EQ(expected, meta_);
+
+ EXPECT_EQ(UMA_STATUS_MATCH,
+ ResetAndParseJson("{\"matches\":[{\"threat_type\":\"13\", "
+ "\"se_pattern_type\":\"junk\"}]}"));
+ EXPECT_EQ(SB_THREAT_TYPE_SUBRESOURCE_FILTER, threat_);
+ expected.threat_pattern_type = ThreatPatternType::NONE;
+ EXPECT_EQ(expected, meta_);
+}
+
+TEST_F(SafeBrowsingApiHandlerUtilTest, SubresourceFilterSubTypes) {
+ const struct {
+ const char* pattern_type;
+ const char* experimental;
+ ThreatPatternType expected_pattern_type;
+ bool expected_experimental;
+ } test_cases[] = {
+ {"BETTER_ADS", "true", ThreatPatternType::SUBRESOURCE_FILTER_BETTER_ADS,
+ true},
+ {"ALL_ADS", "asdf", ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS, false},
+ {"ABUSIVE_ADS", "false",
+ ThreatPatternType::SUBRESOURCE_FILTER_ABUSIVE_ADS, false},
+ {"", "false", ThreatPatternType::NONE, false},
+ };
+ for (const auto& test_case : test_cases) {
+ std::string json = base::StringPrintf(
+ "{\"matches\":[{\"threat_type\":\"13\", "
+ "\"sf_pattern_type\":\"%s\", \"experimental\":\"%s\"}]}",
+ test_case.pattern_type, test_case.experimental);
+ ASSERT_EQ(UMA_STATUS_MATCH, ResetAndParseJson(json));
+ EXPECT_EQ(SB_THREAT_TYPE_SUBRESOURCE_FILTER, threat_);
+
+ ThreatMetadata expected;
+ expected.threat_pattern_type = test_case.expected_pattern_type;
+ expected.experimental = test_case.expected_experimental;
+ EXPECT_EQ(expected, meta_);
+ }
}
TEST_F(SafeBrowsingApiHandlerUtilTest, NoUnwantedSoftwareSubTypes) {
diff --git a/chromium/components/safe_browsing_db/safe_browsing_api_handler_util.cc b/chromium/components/safe_browsing/db/safe_browsing_api_handler_util.cc
index 04b8070cd9d..d0755501294 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_api_handler_util.cc
+++ b/chromium/components/safe_browsing/db/safe_browsing_api_handler_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/safe_browsing_db/safe_browsing_api_handler_util.h"
+#include "components/safe_browsing/db/safe_browsing_api_handler_util.h"
#include <stddef.h>
@@ -33,6 +33,9 @@ enum UmaThreatSubType {
UMA_THREAT_SUB_TYPE_SOCIAL_ENGINEERING_ADS = 4,
UMA_THREAT_SUB_TYPE_SOCIAL_ENGINEERING_LANDING = 5,
UMA_THREAT_SUB_TYPE_PHISHING = 6,
+ UMA_THREAT_SUB_TYPE_BETTER_ADS = 7,
+ UMA_THREAT_SUB_TYPE_ABUSIVE_ADS = 8,
+ UMA_THREAT_SUB_TYPE_ALL_ADS = 9,
UMA_THREAT_SUB_TYPE_MAX_VALUE
};
@@ -50,20 +53,25 @@ void ReportUmaThreatSubType(SBThreatType threat_type,
// Parse the appropriate "*_pattern_type" key from the metadata.
// Returns NONE if no pattern type was found.
-ThreatPatternType ParseThreatSubType(
- const base::DictionaryValue* match,
- SBThreatType threat_type) {
- if (threat_type == SB_THREAT_TYPE_SUBRESOURCE_FILTER ||
- threat_type == SB_THREAT_TYPE_URL_UNWANTED) {
+ThreatPatternType ParseThreatSubType(const base::DictionaryValue* match,
+ SBThreatType threat_type) {
+ if (threat_type == SB_THREAT_TYPE_URL_UNWANTED)
return ThreatPatternType::NONE;
- }
std::string pattern_key;
- if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
- pattern_key = "pha_pattern_type";
- } else {
- DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING);
- pattern_key = "se_pattern_type";
+ switch (threat_type) {
+ case SB_THREAT_TYPE_SUBRESOURCE_FILTER:
+ pattern_key = "sf_pattern_type";
+ break;
+ case SB_THREAT_TYPE_URL_MALWARE:
+ pattern_key = "pha_pattern_type";
+ break;
+ case SB_THREAT_TYPE_URL_PHISHING:
+ pattern_key = "se_pattern_type";
+ break;
+ default:
+ NOTREACHED();
+ break;
}
std::string pattern_type;
@@ -72,7 +80,21 @@ ThreatPatternType ParseThreatSubType(
return ThreatPatternType::NONE;
}
- if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
+ if (threat_type == SB_THREAT_TYPE_SUBRESOURCE_FILTER) {
+ if (pattern_type == "BETTER_ADS") {
+ ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_BETTER_ADS);
+ return ThreatPatternType::SUBRESOURCE_FILTER_BETTER_ADS;
+ } else if (pattern_type == "ABUSIVE_ADS") {
+ ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_ABUSIVE_ADS);
+ return ThreatPatternType::SUBRESOURCE_FILTER_ABUSIVE_ADS;
+ } else if (pattern_type == "ALL_ADS") {
+ ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_ALL_ADS);
+ return ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS;
+ } else {
+ ReportUmaThreatSubType(threat_type, UMA_THREAT_SUB_TYPE_UNKNOWN);
+ return ThreatPatternType::NONE;
+ }
+ } else if (threat_type == SB_THREAT_TYPE_URL_MALWARE) {
if (pattern_type == "LANDING") {
ReportUmaThreatSubType(
threat_type, UMA_THREAT_SUB_TYPE_POTENTIALLY_HALMFUL_APP_LANDING);
@@ -116,6 +138,12 @@ std::string ParseUserPopulation(const base::DictionaryValue* match) {
return population_id;
}
+bool ParseExperimental(const base::DictionaryValue* match) {
+ bool experimental = false;
+ match->GetBoolean("experimental", &experimental);
+ return experimental;
+}
+
// Returns the severity level for a given SafeBrowsing list. The lowest value is
// 0, which represents the most severe list.
int GetThreatSeverity(JavaThreatTypes threat_type) {
@@ -164,7 +192,7 @@ UmaRemoteCallResult ParseJsonFromGMSCore(const std::string& metadata_str,
SBThreatType* worst_sb_threat_type,
ThreatMetadata* metadata) {
*worst_sb_threat_type = SB_THREAT_TYPE_SAFE; // Default to safe.
- *metadata = ThreatMetadata(); // Default values.
+ *metadata = ThreatMetadata(); // Default values.
if (metadata_str.empty())
return UMA_STATUS_JSON_EMPTY;
@@ -212,6 +240,7 @@ UmaRemoteCallResult ParseJsonFromGMSCore(const std::string& metadata_str,
metadata->threat_pattern_type =
ParseThreatSubType(worst_match, *worst_sb_threat_type);
metadata->population_id = ParseUserPopulation(worst_match);
+ metadata->experimental = ParseExperimental(worst_match);
return UMA_STATUS_MATCH; // success
}
diff --git a/chromium/components/safe_browsing_db/safe_browsing_api_handler_util.h b/chromium/components/safe_browsing/db/safe_browsing_api_handler_util.h
index f3724808f6c..f3724808f6c 100644
--- a/chromium/components/safe_browsing_db/safe_browsing_api_handler_util.h
+++ b/chromium/components/safe_browsing/db/safe_browsing_api_handler_util.h
diff --git a/chromium/components/safe_browsing/features.cc b/chromium/components/safe_browsing/features.cc
index 0e5c74c858b..f929d01ca39 100644
--- a/chromium/components/safe_browsing/features.cc
+++ b/chromium/components/safe_browsing/features.cc
@@ -22,19 +22,42 @@ namespace safe_browsing {
const base::Feature kAdSamplerTriggerFeature{"SafeBrowsingAdSamplerTrigger",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kGaiaPasswordReuseReporting{
+ "SyncPasswordReuseEvent", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kGoogleBrandedPhishingWarning{
+ "PasswordProtectionGoogleBrandedPhishingWarning",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kLocalDatabaseManagerEnabled{
"SafeBrowsingV4LocalDatabaseManagerEnabled",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Specifies which non-resource HTML Elements to collect based on their tag and
-// attributes. It's a single param containing a comma-separated list of pairs.
-// For example: "tag1,id,tag1,height,tag2,foo" - this will collect elements with
-// tag "tag1" that have attribute "id" or "height" set, and elements of tag
-// "tag2" if they have attribute "foo" set. All tag names and attributes should
-// be lower case.
+// If enabled, SafeBrowsing URL checks don't defer starting requests or
+// following redirects, no matter on desktop or mobile. Instead they only defer
+// response processing.
+// Please note that when --enable-features=NetworkService is in effect,
+// SafeBrowsing URL checks never block starting requests or following redirects.
+// S13nSafeBrowsingParallelUrlCheck is ignored in that case.
+const base::Feature kParallelUrlCheck{"S13nSafeBrowsingParallelUrlCheck",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kPasswordFieldOnFocusPinging{
+ "PasswordFieldOnFocusPinging", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kPasswordProtectionInterstitial{
+ "PasswordProtectionInterstitial", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kProtectedPasswordEntryPinging{
+ "ProtectedPasswordEntryPinging", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kThreatDomDetailsTagAndAttributeFeature{
"ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTriggerThrottlerDailyQuotaFeature{
+ "SafeBrowsingTriggerThrottlerDailyQuota",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kV4OnlyEnabled{"SafeBrowsingV4OnlyEnabled",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -48,8 +71,15 @@ constexpr struct {
bool probabilistically_enabled;
} kExperimentalFeatures[]{
{&kAdSamplerTriggerFeature, false},
+ {&kGaiaPasswordReuseReporting, true},
+ {&kGoogleBrandedPhishingWarning, false},
{&kLocalDatabaseManagerEnabled, true},
+ {&kParallelUrlCheck, true},
+ {&kPasswordFieldOnFocusPinging, true},
+ {&kPasswordProtectionInterstitial, false},
+ {&kProtectedPasswordEntryPinging, true},
{&kThreatDomDetailsTagAndAttributeFeature, false},
+ {&kTriggerThrottlerDailyQuotaFeature, false},
{&kV4OnlyEnabled, true},
};
diff --git a/chromium/components/safe_browsing/features.h b/chromium/components/safe_browsing/features.h
index baa6763d675..f4c0bbc3e48 100644
--- a/chromium/components/safe_browsing/features.h
+++ b/chromium/components/safe_browsing/features.h
@@ -20,8 +20,29 @@ class ListValue;
namespace safe_browsing {
// Features list
extern const base::Feature kAdSamplerTriggerFeature;
+// Gates logging of GaiaPasswordReuse user events.
+extern const base::Feature kGaiaPasswordReuseReporting;
+extern const base::Feature kGoogleBrandedPhishingWarning;
extern const base::Feature kLocalDatabaseManagerEnabled;
+extern const base::Feature kParallelUrlCheck;
+extern const base::Feature kPasswordFieldOnFocusPinging;
+extern const base::Feature kPasswordProtectionInterstitial;
+extern const base::Feature kProtectedPasswordEntryPinging;
+
+// Specifies which non-resource HTML Elements to collect based on their tag and
+// attributes. It's a single param containing a comma-separated list of pairs.
+// For example: "tag1,id,tag1,height,tag2,foo" - this will collect elements with
+// tag "tag1" that have attribute "id" or "height" set, and elements of tag
+// "tag2" if they have attribute "foo" set. All tag names and attributes should
+// be lower case.
extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
+
+// Controls the daily quota for data collection triggers. It's a single param
+// containing a comma-separated list of pairs. The format of the param is
+// "T1,Q1,T2,Q2,...Tn,Qn", where Tx is a TriggerType and Qx is how many reports
+// that trigger is allowed to send per day.
+extern const base::Feature kTriggerThrottlerDailyQuotaFeature;
+
extern const base::Feature kV4OnlyEnabled;
base::ListValue GetFeatureStatusList();
diff --git a/chromium/components/safe_browsing/net_event_logger.cc b/chromium/components/safe_browsing/net_event_logger.cc
new file mode 100644
index 00000000000..82b38c1b8ce
--- /dev/null
+++ b/chromium/components/safe_browsing/net_event_logger.cc
@@ -0,0 +1,75 @@
+// 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/safe_browsing/net_event_logger.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+namespace {
+
+// Return a dictionary with "url"=|url-spec| and optionally
+// |name|=|value| (if not null), for netlogging.
+// This will also add a reference to the original request's net_log ID.
+std::unique_ptr<base::Value> NetLogUrlCallback(
+ const net::NetLogWithSource* net_log,
+ const GURL& url,
+ const char* name,
+ const char* value,
+ net::NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> event_params(
+ new base::DictionaryValue());
+ event_params->SetString("url", url.spec());
+ if (name && value)
+ event_params->SetString(name, value);
+ net_log->source().AddToEventParameters(event_params.get());
+ return std::move(event_params);
+}
+
+// Return a dictionary with |name|=|value|, for netlogging.
+std::unique_ptr<base::Value> NetLogStringCallback(const char* name,
+ const char* value,
+ net::NetLogCaptureMode) {
+ std::unique_ptr<base::DictionaryValue> event_params(
+ new base::DictionaryValue());
+ if (name && value)
+ event_params->SetString(name, value);
+ return std::move(event_params);
+}
+
+} // namespace
+
+NetEventLogger::NetEventLogger(const net::NetLogWithSource* net_log)
+ : net_log_(net_log),
+ net_log_with_sb_source_(
+ net::NetLogWithSource::Make(net_log_->net_log(),
+ net::NetLogSourceType::SAFE_BROWSING)) {}
+
+void NetEventLogger::BeginNetLogEvent(net::NetLogEventType type,
+ const GURL& url,
+ const char* name,
+ const char* value) {
+ net_log_with_sb_source_.BeginEvent(
+ type, base::Bind(&NetLogUrlCallback, net_log_, url, name, value));
+ net_log_->AddEvent(
+ type, net_log_with_sb_source_.source().ToEventParametersCallback());
+}
+
+void NetEventLogger::EndNetLogEvent(net::NetLogEventType type,
+ const char* name,
+ const char* value) {
+ net_log_with_sb_source_.EndEvent(
+ type, base::Bind(&NetLogStringCallback, name, value));
+ net_log_->AddEvent(
+ type, net_log_with_sb_source_.source().ToEventParametersCallback());
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/net_event_logger.h b/chromium/components/safe_browsing/net_event_logger.h
new file mode 100644
index 00000000000..7da40970a29
--- /dev/null
+++ b/chromium/components/safe_browsing/net_event_logger.h
@@ -0,0 +1,40 @@
+// 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_SAFE_BROWSING_NET_EVENT_LOGGER_H_
+#define COMPONENTS_SAFE_BROWSING_NET_EVENT_LOGGER_H_
+
+#include "base/macros.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
+
+class GURL;
+
+namespace safe_browsing {
+
+// A helper class to log network events for SafeBrowsing.
+class NetEventLogger {
+ public:
+ // |net_log| must outlive this class.
+ explicit NetEventLogger(const net::NetLogWithSource* net_log);
+
+ // For marking network events. |name| and |value| can be null.
+ void BeginNetLogEvent(net::NetLogEventType type,
+ const GURL& url,
+ const char* name,
+ const char* value);
+ void EndNetLogEvent(net::NetLogEventType type,
+ const char* name,
+ const char* value);
+
+ private:
+ const net::NetLogWithSource* net_log_;
+ net::NetLogWithSource net_log_with_sb_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetEventLogger);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_NET_EVENT_LOGGER_H_
diff --git a/chromium/components/safe_browsing/password_protection/BUILD.gn b/chromium/components/safe_browsing/password_protection/BUILD.gn
index f2e9509917b..125f4b2b81f 100644
--- a/chromium/components/safe_browsing/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/password_protection/BUILD.gn
@@ -22,6 +22,7 @@ source_set("password_protection") {
"//components/history/core/browser:browser",
"//components/password_manager/core/browser:browser",
"//components/safe_browsing:csd_proto",
+ "//components/safe_browsing:features",
"//components/safe_browsing_db:database_manager",
"//components/safe_browsing_db:v4_protocol_manager_util",
"//components/safe_browsing_db:whitelist_checker_client",
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
index 3c5ac791456..7e42c119841 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
@@ -23,12 +23,30 @@ using content::WebContents;
namespace safe_browsing {
+namespace {
+
+// Cap on how many reused domains can be included in a report, to limit
+// the size of the report. UMA suggests 99.9% will have < 200 domains.
+const int kMaxReusedDomains = 200;
+
+} // namespace
+
+const char kPasswordOnFocusVerdictHistogram[] =
+ "PasswordProtection.Verdict.PasswordFieldOnFocus";
+const char kAnyPasswordEntryVerdictHistogram[] =
+ "PasswordProtection.Verdict.AnyPasswordEntry";
+const char kSyncPasswordEntryVerdictHistogram[] =
+ "PasswordProtection.Verdict.SyncPasswordEntry";
+const char kProtectedPasswordEntryVerdictHistogram[] =
+ "PasswordProtection.Verdict.ProtectedPasswordEntry";
+
PasswordProtectionRequest::PasswordProtectionRequest(
WebContents* web_contents,
const GURL& main_frame_url,
const GURL& password_form_action,
const GURL& password_form_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
LoginReputationClientRequest::TriggerType type,
bool password_field_exists,
PasswordProtectionService* pps,
@@ -37,15 +55,20 @@ PasswordProtectionRequest::PasswordProtectionRequest(
main_frame_url_(main_frame_url),
password_form_action_(password_form_action),
password_form_frame_url_(password_form_frame_url),
- saved_domain_(saved_domain),
+ matches_sync_password_(matches_sync_password),
+ matching_domains_(matching_domains),
trigger_type_(type),
password_field_exists_(password_field_exists),
password_protection_service_(pps),
request_timeout_in_ms_(request_timeout_in_ms),
+ request_proto_(base::MakeUnique<LoginReputationClientRequest>()),
weakptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
DCHECK(trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE ||
trigger_type_ == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
+ DCHECK(trigger_type_ != LoginReputationClientRequest::PASSWORD_REUSE_EVENT ||
+ matches_sync_password_ || matching_domains_.size() > 0);
}
PasswordProtectionRequest::~PasswordProtectionRequest() {
@@ -109,7 +132,6 @@ void PasswordProtectionRequest::CheckCachedVerdicts() {
}
void PasswordProtectionRequest::FillRequestProto() {
- request_proto_ = base::MakeUnique<LoginReputationClientRequest>();
request_proto_->set_page_url(main_frame_url_.spec());
request_proto_->set_trigger_type(trigger_type_);
password_protection_service_->FillUserPopulation(trigger_type_,
@@ -146,9 +168,8 @@ void PasswordProtectionRequest::FillRequestProto() {
main_frame->set_has_password_field(password_field_exists_);
LoginReputationClientRequest::PasswordReuseEvent* reuse_event =
request_proto_->mutable_password_reuse_event();
- reuse_event->set_is_chrome_signin_password(
- saved_domain_ == std::string(password_manager::kSyncPasswordDomain));
- if (reuse_event->is_chrome_signin_password()) {
+ reuse_event->set_is_chrome_signin_password(matches_sync_password_);
+ if (matches_sync_password_) {
reuse_event->set_sync_account_type(
password_protection_service_->GetSyncAccountType());
UMA_HISTOGRAM_ENUMERATION(
@@ -158,6 +179,15 @@ void PasswordProtectionRequest::FillRequestProto() {
SyncAccountType_MAX +
1);
}
+ if (password_protection_service_->IsExtendedReporting() &&
+ !password_protection_service_->IsIncognito()) {
+ for (const auto& domain : matching_domains_) {
+ reuse_event->add_domains_matching_password(domain);
+ if (reuse_event->domains_matching_password_size() >=
+ kMaxReusedDomains)
+ break;
+ }
+ }
break;
}
default:
@@ -195,7 +225,7 @@ void PasswordProtectionRequest::SendRequest() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "Safe Browsing Cookie Store"
setting:
"Users can control this feature via 'Protect you and your device "
@@ -271,37 +301,36 @@ void PasswordProtectionRequest::Finish(
std::unique_ptr<LoginReputationClientResponse> response) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
tracker_.TryCancelAll();
- bool is_sync_password =
- saved_domain_ == std::string(password_manager::kSyncPasswordDomain);
if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
- UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName,
- outcome, PasswordProtectionService::MAX_OUTCOME);
- } else if (is_sync_password) {
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordEntryRequestOutcomeHistogramName,
- outcome, PasswordProtectionService::MAX_OUTCOME);
+ UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogram, outcome,
+ PasswordProtectionService::MAX_OUTCOME);
} else {
- UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName,
- outcome, PasswordProtectionService::MAX_OUTCOME);
+ PasswordProtectionService::LogPasswordEntryRequestOutcome(
+ outcome, matches_sync_password_);
+ if (matches_sync_password_) {
+ password_protection_service_->MaybeLogPasswordReuseLookupEvent(
+ web_contents_, outcome, response.get());
+ }
}
if (outcome == PasswordProtectionService::SUCCEEDED && response) {
switch (trigger_type_) {
case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE:
UMA_HISTOGRAM_ENUMERATION(
- "PasswordProtection.Verdict.PasswordFieldOnFocus",
- response->verdict_type(),
+ kPasswordOnFocusVerdictHistogram, response->verdict_type(),
LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
break;
case LoginReputationClientRequest::PASSWORD_REUSE_EVENT:
- if (is_sync_password) {
+ UMA_HISTOGRAM_ENUMERATION(
+ kAnyPasswordEntryVerdictHistogram, response->verdict_type(),
+ LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
+ if (matches_sync_password_) {
UMA_HISTOGRAM_ENUMERATION(
- "PasswordProtection.Verdict.SyncProtectedPasswordEntry",
- response->verdict_type(),
+ kSyncPasswordEntryVerdictHistogram, response->verdict_type(),
LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
} else {
UMA_HISTOGRAM_ENUMERATION(
- "PasswordProtection.Verdict.ProtectedPasswordEntry",
- response->verdict_type(),
+ kProtectedPasswordEntryVerdictHistogram, response->verdict_type(),
LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
}
break;
@@ -310,7 +339,6 @@ void PasswordProtectionRequest::Finish(
}
}
- DCHECK(password_protection_service_);
password_protection_service_->RequestFinished(
this, outcome == PasswordProtectionService::RESPONSE_ALREADY_CACHED,
std::move(response));
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.h b/chromium/components/safe_browsing/password_protection/password_protection_request.h
index 7593ca74027..267fa301a0e 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_request.h
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.h
@@ -14,10 +14,18 @@
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_status.h"
+#include <vector>
+
class GURL;
namespace safe_browsing {
+// UMA metrics
+extern const char kPasswordOnFocusVerdictHistogram[];
+extern const char kAnyPasswordEntryVerdictHistogram[];
+extern const char kSyncPasswordEntryVerdictHistogram[];
+extern const char kProtectedPasswordEntryVerdictHistogram[];
+
// A request for checking if an unfamiliar login form or a password reuse event
// is safe. PasswordProtectionRequest objects are owned by
// PasswordProtectionService indicated by |password_protection_service_|.
@@ -44,7 +52,8 @@ class PasswordProtectionRequest : public base::RefCountedThreadSafe<
const GURL& main_frame_url,
const GURL& password_form_action,
const GURL& password_form_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_origins,
LoginReputationClientRequest::TriggerType type,
bool password_field_exists,
PasswordProtectionService* pps,
@@ -125,8 +134,13 @@ class PasswordProtectionRequest : public base::RefCountedThreadSafe<
// Frame url of the detected password form.
const GURL password_form_frame_url_;
- // Domain on which a password is saved and gets reused.
- const std::string saved_domain_;
+ // True if the password is the sync/Google password.
+ const bool matches_sync_password_;
+
+ // Domains from the Password Manager that match this password.
+ // Should be non-empty if |matches_sync_password_| == false. Otherwise,
+ // may or may not be empty.
+ const std::vector<std::string> matching_domains_;
// If this request is for unfamiliar login page or for a password reuse event.
const LoginReputationClientRequest::TriggerType trigger_type_;
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
index 646c1762f19..91b105515be 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -19,6 +20,7 @@
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/history/core/browser/history_service.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
+#include "components/safe_browsing/features.h"
#include "components/safe_browsing/password_protection/password_protection_request.h"
#include "components/safe_browsing_db/database_manager.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
@@ -74,21 +76,23 @@ GURL GetHostNameWithHTTPScheme(const GURL& url) {
} // namespace
-const base::Feature kPasswordFieldOnFocusPinging{
- "PasswordFieldOnFocusPinging", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kProtectedPasswordEntryPinging{
- "ProtectedPasswordEntryPinging", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kPasswordProtectionInterstitial{
- "PasswordProtectionInterstitial", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const char kPasswordOnFocusRequestOutcomeHistogramName[] =
+const char kPasswordOnFocusRequestOutcomeHistogram[] =
"PasswordProtection.RequestOutcome.PasswordFieldOnFocus";
-const char kPasswordEntryRequestOutcomeHistogramName[] =
- "PasswordProtection.RequestOutcome.ProtectedPasswordEntry";
-const char kSyncPasswordEntryRequestOutcomeHistogramName[] =
+// Matches sync and/or saved password
+const char kAnyPasswordEntryRequestOutcomeHistogram[] =
+ "PasswordProtection.RequestOutcome.AnyPasswordEntry";
+// Matches sync and maybe also saved password
+const char kSyncPasswordEntryRequestOutcomeHistogram[] =
"PasswordProtection.RequestOutcome.SyncPasswordEntry";
+// Matches saved but NOT sync password
+const char kProtectedPasswordEntryRequestOutcomeHistogram[] =
+ "PasswordProtection.RequestOutcome.ProtectedPasswordEntry";
+const char kSyncPasswordWarningDialogHistogram[] =
+ "PasswordProtection.ModalWarningDialogAction.SyncPasswordEntry";
+const char kSyncPasswordPageInfoHistogram[] =
+ "PasswordProtection.PageInfoAction.SyncPasswordEntry";
+const char kSyncPasswordChromeSettingsHistogram[] =
+ "PasswordProtection.ChromeSettingsAction.SyncPasswordEntry";
PasswordProtectionService::PasswordProtectionService(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
@@ -123,6 +127,57 @@ bool PasswordProtectionService::CanGetReputationOfURL(const GURL& url) {
hostname.find('.') != std::string::npos;
}
+void PasswordProtectionService::RecordWarningAction(WarningUIType ui_type,
+ WarningAction action) {
+ switch (ui_type) {
+ case PAGE_INFO:
+ UMA_HISTOGRAM_ENUMERATION(kSyncPasswordPageInfoHistogram, action,
+ MAX_ACTION);
+ break;
+ case MODAL_DIALOG:
+ UMA_HISTOGRAM_ENUMERATION(kSyncPasswordWarningDialogHistogram, action,
+ MAX_ACTION);
+ break;
+ case CHROME_SETTINGS:
+ UMA_HISTOGRAM_ENUMERATION(kSyncPasswordChromeSettingsHistogram, action,
+ MAX_ACTION);
+ break;
+ case NOT_USED:
+ case MAX_UI_TYPE:
+ NOTREACHED();
+ break;
+ }
+}
+
+void PasswordProtectionService::OnWarningDone(
+ content::WebContents* web_contents,
+ WarningUIType ui_type,
+ WarningAction action) {
+ RecordWarningAction(ui_type, action);
+ // TODO(jialiul): Need to send post-warning report, trigger event logger and
+ // other tasks.
+ if (ui_type == MODAL_DIALOG)
+ web_contents_to_proto_map_.erase(web_contents);
+
+ if (action == MARK_AS_LEGITIMATE) {
+ DCHECK_EQ(PAGE_INFO, ui_type);
+ UpdateSecurityState(SB_THREAT_TYPE_SAFE, web_contents);
+ // TODO(jialiul): Close page info bubble.
+ }
+}
+
+void PasswordProtectionService::OnWarningShown(
+ content::WebContents* web_contents,
+ WarningUIType ui_type) {
+ RecordWarningAction(ui_type, SHOWN);
+ // TODO(jialiul): Trigger event logger here.
+}
+
+bool PasswordProtectionService::ShouldShowSofterWarning() {
+ return base::GetFieldTrialParamByFeatureAsBool(kGoogleBrandedPhishingWarning,
+ "softer_warning", false);
+}
+
// We cache both types of pings under the same content settings type (
// CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION). Since UNFAMILIAR_LOGING_PAGE
// verdicts are only enabled on extended reporting users, we cache them one
@@ -314,17 +369,17 @@ void PasswordProtectionService::StartRequest(
const GURL& main_frame_url,
const GURL& password_form_action,
const GURL& password_form_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
TriggerType trigger_type,
bool password_field_exists) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<PasswordProtectionRequest> request(
new PasswordProtectionRequest(
web_contents, main_frame_url, password_form_action,
- password_form_frame_url, saved_domain, trigger_type,
- password_field_exists, this, GetRequestTimeoutInMS()));
+ password_form_frame_url, matches_sync_password, matching_domains,
+ trigger_type, password_field_exists, this, GetRequestTimeoutInMS()));
- DCHECK(request);
request->Start();
requests_.insert(std::move(request));
}
@@ -338,7 +393,8 @@ void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest(
if (CanSendPing(kPasswordFieldOnFocusPinging, main_frame_url, false)) {
StartRequest(web_contents, main_frame_url, password_form_action,
password_form_frame_url,
- std::string(), /* saved_domain: not used for this type */
+ false, /* matches_sync_password: not used for this type */
+ {}, /* matching_domains: not used for this type */
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
}
}
@@ -346,13 +402,14 @@ void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest(
void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
WebContents* web_contents,
const GURL& main_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
bool password_field_exists) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (CanSendPing(
- kProtectedPasswordEntryPinging, main_frame_url,
- saved_domain == std::string(password_manager::kSyncPasswordDomain))) {
- StartRequest(web_contents, main_frame_url, GURL(), GURL(), saved_domain,
+ if (CanSendPing(kProtectedPasswordEntryPinging, main_frame_url,
+ matches_sync_password)) {
+ StartRequest(web_contents, main_frame_url, GURL(), GURL(),
+ matches_sync_password, matching_domains,
LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
password_field_exists);
}
@@ -360,13 +417,13 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
bool PasswordProtectionService::CanSendPing(const base::Feature& feature,
const GURL& main_frame_url,
- bool is_sync_password) {
+ bool matches_sync_password) {
RequestOutcome request_outcome = URL_NOT_VALID_FOR_REPUTATION_COMPUTING;
if (IsPingingEnabled(feature, &request_outcome) &&
CanGetReputationOfURL(main_frame_url)) {
return true;
}
- RecordNoPingingReason(feature, request_outcome, is_sync_password);
+ RecordNoPingingReason(feature, request_outcome, matches_sync_password);
return false;
}
@@ -661,11 +718,8 @@ bool PasswordProtectionService::ParseVerdictEntry(
bool PasswordProtectionService::PathVariantsMatchCacheExpression(
const std::vector<std::string>& generated_paths,
const std::string& cache_expression_path) {
- for (const auto& path : generated_paths) {
- if (cache_expression_path == path)
- return true;
- }
- return false;
+ return std::find(generated_paths.begin(), generated_paths.end(),
+ cache_expression_path) != generated_paths.end();
}
bool PasswordProtectionService::IsCacheExpired(int cache_creation_time,
@@ -727,23 +781,30 @@ PasswordProtectionService::CreateDictionaryFromVerdict(
void PasswordProtectionService::RecordNoPingingReason(
const base::Feature& feature,
RequestOutcome reason,
- bool is_sync_password) {
+ bool matches_sync_password) {
DCHECK(feature.name == kProtectedPasswordEntryPinging.name ||
feature.name == kPasswordFieldOnFocusPinging.name);
- bool is_password_entry_ping =
- feature.name == kProtectedPasswordEntryPinging.name;
+ if (feature.name == kPasswordFieldOnFocusPinging.name) {
+ UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogram, reason,
+ MAX_OUTCOME);
+ return;
+ }
- if (is_password_entry_ping) {
- if (is_sync_password) {
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordEntryRequestOutcomeHistogramName,
- reason, MAX_OUTCOME);
- } else {
- UMA_HISTOGRAM_ENUMERATION(kPasswordEntryRequestOutcomeHistogramName,
- reason, MAX_OUTCOME);
- }
+ LogPasswordEntryRequestOutcome(reason, matches_sync_password);
+}
+
+// static
+void PasswordProtectionService::LogPasswordEntryRequestOutcome(
+ RequestOutcome reason,
+ bool matches_sync_password) {
+ UMA_HISTOGRAM_ENUMERATION(kAnyPasswordEntryRequestOutcomeHistogram, reason,
+ MAX_OUTCOME);
+ if (matches_sync_password) {
+ UMA_HISTOGRAM_ENUMERATION(kSyncPasswordEntryRequestOutcomeHistogram, reason,
+ MAX_OUTCOME);
} else {
- UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogramName,
+ UMA_HISTOGRAM_ENUMERATION(kProtectedPasswordEntryRequestOutcomeHistogram,
reason, MAX_OUTCOME);
}
}
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.h b/chromium/components/safe_browsing/password_protection/password_protection_service.h
index a5b24bf1744..2b99a48c218 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_PASSWORD_PROTECTION_SERVICE_H_
#include <set>
+#include <unordered_map>
#include "base/callback.h"
#include "base/feature_list.h"
@@ -17,7 +18,8 @@
#include "base/task/cancelable_task_tracker.h"
#include "base/values.h"
#include "components/history/core/browser/history_service_observer.h"
-#include "components/safe_browsing/csd.pb.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "net/url_request/url_request_context_getter.h"
#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
@@ -37,12 +39,14 @@ namespace safe_browsing {
class SafeBrowsingDatabaseManager;
class PasswordProtectionRequest;
-extern const base::Feature kPasswordFieldOnFocusPinging;
-extern const base::Feature kProtectedPasswordEntryPinging;
-extern const base::Feature kPasswordProtectionInterstitial;
-extern const char kPasswordOnFocusRequestOutcomeHistogramName[];
-extern const char kPasswordEntryRequestOutcomeHistogramName[];
-extern const char kSyncPasswordEntryRequestOutcomeHistogramName[];
+// UMA metrics
+extern const char kPasswordOnFocusRequestOutcomeHistogram[];
+extern const char kAnyPasswordEntryRequestOutcomeHistogram[];
+extern const char kSyncPasswordEntryRequestOutcomeHistogram[];
+extern const char kProtectedPasswordEntryRequestOutcomeHistogram[];
+extern const char kSyncPasswordWarningDialogHistogram[];
+extern const char kSyncPasswordPageInfoHistogram[];
+extern const char kSyncPasswordChromeSettingsHistogram[];
// Manage password protection pings and verdicts. There is one instance of this
// class per profile. Therefore, every PasswordProtectionService instance is
@@ -53,6 +57,9 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
using TriggerType = LoginReputationClientRequest::TriggerType;
using SyncAccountType =
LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType;
+ using WebContentsToProtoMap = std::unordered_map<
+ content::WebContents*,
+ std::pair<LoginReputationClientRequest, LoginReputationClientResponse>>;
// The outcome of the request. These values are used for UMA.
// DO NOT CHANGE THE ORDERING OF THESE VALUES.
@@ -75,6 +82,37 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
MAX_OUTCOME
};
+ // Enum values indicates if a password protection warning is shown or
+ // represents user's action on warnings. These values are used for UMA.
+ // DO NOT CHANGE THE ORDERING OF THESE VALUES.
+ enum WarningAction {
+ // Warning shows up.
+ SHOWN = 0,
+
+ // User clicks on "Change Password" button.
+ CHANGE_PASSWORD = 1,
+
+ // User clicks on "Ignore" button.
+ IGNORE_WARNING = 2,
+
+ // User navigates page away or hit "ESC" to close dialog.
+ CLOSE = 3,
+
+ // User explicitly mark the site as legitimate.
+ MARK_AS_LEGITIMATE = 4,
+
+ MAX_ACTION
+ };
+
+ // Type of password protection warning UI.
+ enum WarningUIType {
+ NOT_USED = 0,
+ PAGE_INFO = 1,
+ MODAL_DIALOG = 2,
+ CHROME_SETTINGS = 3,
+ MAX_UI_TYPE
+ };
+
PasswordProtectionService(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
@@ -112,7 +150,8 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
const GURL& main_frame_url,
const GURL& password_form_action,
const GURL& password_form_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
TriggerType trigger_type,
bool password_field_exists);
@@ -125,9 +164,14 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
virtual void MaybeStartProtectedPasswordEntryRequest(
content::WebContents* web_contents,
const GURL& main_frame_url,
- const std::string& saved_domain,
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
bool password_field_exists);
+ // Records a Chrome Sync event that sync password reuse was detected.
+ virtual void MaybeLogPasswordReuseDetectedEvent(
+ content::WebContents* web_contents) = 0;
+
scoped_refptr<SafeBrowsingDatabaseManager> database_manager();
// Safe Browsing backend cannot get a reliable reputation of a URL if
@@ -139,16 +183,47 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// (6) Its hostname is a dotless domain.
static bool CanGetReputationOfURL(const GURL& url);
+ // Records user action to corresponding UMA histograms.
+ void RecordWarningAction(WarningUIType ui_type, WarningAction action);
+
+ // Called when user close warning UI or navigate away.
+ void OnWarningDone(content::WebContents* web_contents,
+ WarningUIType ui_type,
+ WarningAction action);
+
+ // Shows modal warning dialog on the current |web_contents| and store request
+ // and response protos in |web_contents_to_proto_map_|.
+ virtual void ShowModalWarning(
+ content::WebContents* web_contents,
+ const LoginReputationClientRequest* request_proto,
+ const LoginReputationClientResponse* response_proto) {}
+
+ // Record UMA stats and trigger event logger when warning UI is shown.
+ virtual void OnWarningShown(content::WebContents* web_contents,
+ WarningUIType ui_type);
+
+ // If we want to show softer warnings based on Finch parameters.
+ static bool ShouldShowSofterWarning();
+
+ virtual void UpdateSecurityState(safe_browsing::SBThreatType threat_type,
+ content::WebContents* web_contents) {}
+
+ // Log the |reason| to several UMA metrics, depending on the value
+ // of |matches_sync_password|.
+ static void LogPasswordEntryRequestOutcome(RequestOutcome reason,
+ bool matches_sync_password);
+
protected:
friend class PasswordProtectionRequest;
FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest, VerifyCanSendPing);
+
// Chrome can send password protection ping if it is allowed by Finch config
// and if Safe Browsing can compute reputation of |main_frame_url| (e.g.
// Safe Browsing is not able to compute reputation of a private IP or
- // a local host). |is_sync_password| is used for UMA metric recording.
+ // a local host). |matches_sync_password| is used for UMA metric recording.
bool CanSendPing(const base::Feature& feature,
const GURL& main_frame_url,
- bool is_sync_password);
+ bool matches_sync_password);
// Called by a PasswordProtectionRequest instance when it finishes to remove
// itself from |requests_|.
@@ -202,10 +277,21 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// |NOT_SIGNED_IN|.
virtual SyncAccountType GetSyncAccountType() = 0;
+ // Records a Chrome Sync event for the result of the URL reputation lookup
+ // if the user enters their sync password on a website.
+ virtual void MaybeLogPasswordReuseLookupEvent(
+ content::WebContents* web_contents,
+ PasswordProtectionService::RequestOutcome,
+ const LoginReputationClientResponse*) = 0;
+
void CheckCsdWhitelistOnIOThread(const GURL& url, bool* check_result);
HostContentSettingsMap* content_settings() const { return content_settings_; }
+ WebContentsToProtoMap web_contents_to_proto_map() const {
+ return web_contents_to_proto_map_;
+ }
+
private:
friend class PasswordProtectionServiceTest;
friend class TestPasswordProtectionService;
@@ -266,7 +352,7 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
static void RecordNoPingingReason(const base::Feature& feature,
RequestOutcome reason,
- bool is_sync_password);
+ bool matches_sync_password);
// Number of verdict stored for this profile for password on focus pings.
int stored_verdict_count_password_on_focus_;
@@ -294,6 +380,8 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// we need CancelableTaskTracker to cancel tasks posted to IO thread.
base::CancelableTaskTracker tracker_;
+ WebContentsToProtoMap web_contents_to_proto_map_;
+
base::WeakPtrFactory<PasswordProtectionService> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PasswordProtectionService);
};
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index eb9a5971ddc..c1e80ae0833 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -29,6 +29,7 @@ namespace {
const char kFormActionUrl[] = "https://form_action.com/";
const char kPasswordFrameUrl[] = "https://password_frame.com/";
const char kSavedDomain[] = "saved_domain.com";
+const char kSavedDomain2[] = "saved_domain2.com";
const char kTargetUrl[] = "http://foo.com/";
} // namespace
@@ -106,12 +107,20 @@ class TestPasswordProtectionService : public PasswordProtectionService {
void set_incognito(bool enabled) { is_incognito_ = enabled; }
+ void MaybeLogPasswordReuseDetectedEvent(
+ content::WebContents* web_contents) override {}
+
bool IsPingingEnabled(const base::Feature& feature,
RequestOutcome* reason) override {
checked_feature_name_ = feature.name;
return true;
}
+ void MaybeLogPasswordReuseLookupEvent(
+ content::WebContents* web_contents,
+ PasswordProtectionService::RequestOutcome,
+ const LoginReputationClientResponse*) override {}
+
void ShowPhishingInterstitial(const GURL& phishing_url,
const std::string& token,
content::WebContents* web_contents) override {}
@@ -146,7 +155,8 @@ class TestPasswordProtectionService : public PasswordProtectionService {
DISALLOW_COPY_AND_ASSIGN(TestPasswordProtectionService);
};
-class PasswordProtectionServiceTest : public testing::Test {
+class PasswordProtectionServiceTest
+ : public ::testing::TestWithParam<std::vector<bool>> {
public:
PasswordProtectionServiceTest(){};
@@ -172,6 +182,10 @@ class PasswordProtectionServiceTest : public testing::Test {
base::MakeUnique<TestPasswordProtectionService>(
database_manager_, dummy_request_context_getter_,
content_setting_map_);
+
+ ASSERT_EQ(2ul, GetParam().size());
+ password_protection_service_->set_extended_reporting(GetParam()[0]);
+ password_protection_service_->set_incognito(GetParam()[1]);
}
void TearDown() override { content_setting_map_->ShutdownOnUIThread(); }
@@ -186,23 +200,26 @@ class PasswordProtectionServiceTest : public testing::Test {
request_ = new PasswordProtectionRequest(
nullptr, target_url, GURL(kFormActionUrl), GURL(kPasswordFrameUrl),
- std::string(), LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
- true, password_protection_service_.get(), timeout_in_ms);
+ false /* matches_sync_password */, {},
+ LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true,
+ password_protection_service_.get(), timeout_in_ms);
request_->Start();
}
- void InitializeAndStartPasswordEntryRequest(const std::string& saved_domain,
- bool match_whitelist,
- int timeout_in_ms) {
+ void InitializeAndStartPasswordEntryRequest(
+ bool matches_sync_password,
+ const std::vector<std::string>& matching_domains,
+ bool match_whitelist,
+ int timeout_in_ms) {
GURL target_url(kTargetUrl);
EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url, _))
.WillRepeatedly(
Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
request_ = new PasswordProtectionRequest(
- nullptr, target_url, GURL(), GURL(), saved_domain,
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT, true,
- password_protection_service_.get(), timeout_in_ms);
+ nullptr, target_url, GURL(), GURL(), matches_sync_password,
+ matching_domains, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ true, password_protection_service_.get(), timeout_in_ms);
request_->Start();
}
@@ -265,7 +282,7 @@ class PasswordProtectionServiceTest : public testing::Test {
base::HistogramTester histograms_;
};
-TEST_F(PasswordProtectionServiceTest, TestParseInvalidVerdictEntry) {
+TEST_P(PasswordProtectionServiceTest, TestParseInvalidVerdictEntry) {
std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
base::MakeUnique<base::DictionaryValue>();
invalid_verdict_entry->SetString("cache_creation_time", "invalid_time");
@@ -281,7 +298,7 @@ TEST_F(PasswordProtectionServiceTest, TestParseInvalidVerdictEntry) {
invalid_verdict_entry.get(), &cache_creation_time, &response));
}
-TEST_F(PasswordProtectionServiceTest, TestParseValidVerdictEntry) {
+TEST_P(PasswordProtectionServiceTest, TestParseValidVerdictEntry) {
base::Time expected_creation_time = base::Time::Now();
LoginReputationClientResponse expected_verdict(CreateVerdictProto(
LoginReputationClientResponse::SAFE, 10 * 60, "test.com/foo"));
@@ -303,7 +320,7 @@ TEST_F(PasswordProtectionServiceTest, TestParseValidVerdictEntry) {
actual_verdict.cache_expression());
}
-TEST_F(PasswordProtectionServiceTest, TestPathVariantsMatchCacheExpression) {
+TEST_P(PasswordProtectionServiceTest, TestPathVariantsMatchCacheExpression) {
// Cache expression without path.
std::string cache_expression("google.com");
std::string cache_expression_with_slash("google.com/");
@@ -341,7 +358,7 @@ TEST_F(PasswordProtectionServiceTest, TestPathVariantsMatchCacheExpression) {
GURL("http://evil.com/worse/index.html"), cache_expression_with_slash));
}
-TEST_F(PasswordProtectionServiceTest, TestCachePasswordReuseVerdicts) {
+TEST_P(PasswordProtectionServiceTest, TestCachePasswordReuseVerdicts) {
ASSERT_EQ(0U, GetStoredVerdictCount(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
@@ -392,7 +409,7 @@ TEST_F(PasswordProtectionServiceTest, TestCachePasswordReuseVerdicts) {
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
}
-TEST_F(PasswordProtectionServiceTest, TestCacheUnfamiliarLoginVerdicts) {
+TEST_P(PasswordProtectionServiceTest, TestCacheUnfamiliarLoginVerdicts) {
ASSERT_EQ(0U, GetStoredVerdictCount(
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
@@ -428,7 +445,7 @@ TEST_F(PasswordProtectionServiceTest, TestCacheUnfamiliarLoginVerdicts) {
LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
}
-TEST_F(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
+TEST_P(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
ASSERT_EQ(0U, GetStoredVerdictCount(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
ASSERT_EQ(0U, GetStoredVerdictCount(
@@ -479,7 +496,7 @@ TEST_F(PasswordProtectionServiceTest, TestGetCachedVerdicts) {
LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &actual_verdict));
}
-TEST_F(PasswordProtectionServiceTest, TestRemoveCachedVerdictOnURLsDeleted) {
+TEST_P(PasswordProtectionServiceTest, TestRemoveCachedVerdictOnURLsDeleted) {
ASSERT_EQ(0U, GetStoredVerdictCount(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
ASSERT_EQ(0U, GetStoredVerdictCount(
@@ -547,7 +564,7 @@ TEST_F(PasswordProtectionServiceTest, TestRemoveCachedVerdictOnURLsDeleted) {
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
}
-TEST_F(PasswordProtectionServiceTest, VerifyCanGetReputationOfURL) {
+TEST_P(PasswordProtectionServiceTest, VerifyCanGetReputationOfURL) {
// Invalid main frame URL.
EXPECT_FALSE(PasswordProtectionService::CanGetReputationOfURL(GURL()));
@@ -585,19 +602,19 @@ TEST_F(PasswordProtectionServiceTest, VerifyCanGetReputationOfURL) {
GURL("http://www.chromium.org")));
}
-TEST_F(PasswordProtectionServiceTest, TestNoRequestSentForWhitelistedURL) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestNoRequestSentForWhitelistedURL) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
InitializeAndStartPasswordOnFocusRequest(true /* match whitelist */,
10000 /* timeout in ms*/);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, password_protection_service_->latest_response());
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(4 /* MATCHED_WHITELIST */, 1)));
}
-TEST_F(PasswordProtectionServiceTest, TestNoRequestSentIfVerdictAlreadyCached) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestNoRequestSentIfVerdictAlreadyCached) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
CacheVerdict(GURL(kTargetUrl),
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
LoginReputationClientResponse::LOW_REPUTATION, 600,
@@ -606,14 +623,14 @@ TEST_F(PasswordProtectionServiceTest, TestNoRequestSentIfVerdictAlreadyCached) {
10000 /* timeout in ms*/);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(5 /* RESPONSE_ALREADY_CACHED */, 1)));
EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
password_protection_service_->latest_response()->verdict_type());
}
-TEST_F(PasswordProtectionServiceTest, TestResponseFetchFailed) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestResponseFetchFailed) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
net::TestURLFetcher failed_fetcher(0, GURL("http://bar.com"), nullptr);
// Set up failed response.
failed_fetcher.set_status(
@@ -625,12 +642,12 @@ TEST_F(PasswordProtectionServiceTest, TestResponseFetchFailed) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, password_protection_service_->latest_response());
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(9 /* FETCH_FAILED */, 1)));
}
-TEST_F(PasswordProtectionServiceTest, TestMalformedResponse) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestMalformedResponse) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
// Set up malformed response.
net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
fetcher.set_status(
@@ -644,24 +661,24 @@ TEST_F(PasswordProtectionServiceTest, TestMalformedResponse) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, password_protection_service_->latest_response());
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(10 /* RESPONSE_MALFORMED */, 1)));
}
-TEST_F(PasswordProtectionServiceTest, TestRequestTimedout) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestRequestTimedout) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
InitializeAndStartPasswordOnFocusRequest(false /* match whitelist */,
0 /* timeout immediately */);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, password_protection_service_->latest_response());
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(3 /* TIMEDOUT */, 1)));
}
-TEST_F(PasswordProtectionServiceTest,
+TEST_P(PasswordProtectionServiceTest,
TestPasswordOnFocusRequestAndResponseSuccessfull) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
// Set up valid response.
net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
fetcher.set_status(
@@ -676,10 +693,9 @@ TEST_F(PasswordProtectionServiceTest,
request_->OnURLFetchComplete(&fetcher);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
- EXPECT_THAT(histograms_.GetAllSamples(
- "PasswordProtection.Verdict.PasswordFieldOnFocus"),
+ EXPECT_THAT(histograms_.GetAllSamples(kPasswordOnFocusVerdictHistogram),
ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
LoginReputationClientResponse* actual_response =
password_protection_service_->latest_response();
@@ -690,10 +706,11 @@ TEST_F(PasswordProtectionServiceTest,
actual_response->cache_duration_sec());
}
-TEST_F(PasswordProtectionServiceTest,
- TestPasswordEntryRequestAndResponseSuccessfull) {
- histograms_.ExpectTotalCount(kPasswordEntryRequestOutcomeHistogramName, 0);
- histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogramName,
+TEST_P(PasswordProtectionServiceTest,
+ TestProtectedPasswordEntryRequestAndResponseSuccessfull) {
+ histograms_.ExpectTotalCount(kAnyPasswordEntryRequestOutcomeHistogram, 0);
+ histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
+ histograms_.ExpectTotalCount(kProtectedPasswordEntryRequestOutcomeHistogram,
0);
// Set up valid response.
net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
@@ -704,48 +721,82 @@ TEST_F(PasswordProtectionServiceTest,
LoginReputationClientResponse::PHISHING, 600, GURL(kTargetUrl).host());
fetcher.SetResponseString(expected_response.SerializeAsString());
- // Initiate a saved password entry request.
+ // Initiate a saved password entry request (w/ no sync password).
InitializeAndStartPasswordEntryRequest(
- "example.com", false /* match whitelist */, 10000 /* timeout in ms*/);
+ false /* matches_sync_password */, {"example.com"},
+ false /* match whitelist */, 10000 /* timeout in ms*/);
request_->OnURLFetchComplete(&fetcher);
base::RunLoop().RunUntilIdle();
+
+ // UMA: request outcomes
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kAnyPasswordEntryRequestOutcomeHistogram),
+ ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
+ histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordEntryRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kProtectedPasswordEntryRequestOutcomeHistogram),
ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
- EXPECT_THAT(histograms_.GetAllSamples(
- "PasswordProtection.Verdict.ProtectedPasswordEntry"),
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kProtectedPasswordEntryVerdictHistogram),
+ ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
+
+ // UMA: verdicts
+ EXPECT_THAT(histograms_.GetAllSamples(kAnyPasswordEntryVerdictHistogram),
ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
- histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogramName,
+ histograms_.ExpectTotalCount(kSyncPasswordEntryVerdictHistogram, 0);
+ EXPECT_THAT(
+ histograms_.GetAllSamples(kProtectedPasswordEntryVerdictHistogram),
+ ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
+}
+
+TEST_P(PasswordProtectionServiceTest,
+ TestSyncPasswordEntryRequestAndResponseSuccessfull) {
+ histograms_.ExpectTotalCount(kAnyPasswordEntryRequestOutcomeHistogram, 0);
+ histograms_.ExpectTotalCount(kSyncPasswordEntryRequestOutcomeHistogram, 0);
+ histograms_.ExpectTotalCount(kProtectedPasswordEntryRequestOutcomeHistogram,
0);
+ // Set up valid response.
+ net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
+ fetcher.set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ fetcher.set_response_code(200);
+ LoginReputationClientResponse expected_response = CreateVerdictProto(
+ LoginReputationClientResponse::PHISHING, 600, GURL(kTargetUrl).host());
+ fetcher.SetResponseString(expected_response.SerializeAsString());
- // Initiate a sync password entry request.
- InitializeAndStartPasswordEntryRequest(password_manager::kSyncPasswordDomain,
+ // Initiate a sync password entry request (w/ no saved password).
+ InitializeAndStartPasswordEntryRequest(true /* matches_sync_password */, {},
false /* match whitelist */,
10000 /* timeout in ms*/);
request_->OnURLFetchComplete(&fetcher);
base::RunLoop().RunUntilIdle();
+
+ // UMA: request outcomes
EXPECT_THAT(
- histograms_.GetAllSamples(kSyncPasswordEntryRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kAnyPasswordEntryRequestOutcomeHistogram),
ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordEntryRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kSyncPasswordEntryRequestOutcomeHistogram),
ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
- EXPECT_THAT(histograms_.GetAllSamples(
- "PasswordProtection.Verdict.SyncProtectedPasswordEntry"),
+ histograms_.ExpectTotalCount(kProtectedPasswordEntryRequestOutcomeHistogram,
+ 0);
+
+ // UMA: verdicts
+ EXPECT_THAT(histograms_.GetAllSamples(kAnyPasswordEntryVerdictHistogram),
ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
- EXPECT_THAT(histograms_.GetAllSamples(
- "PasswordProtection.Verdict.ProtectedPasswordEntry"),
+ EXPECT_THAT(histograms_.GetAllSamples(kSyncPasswordEntryVerdictHistogram),
ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
+ histograms_.ExpectTotalCount(kProtectedPasswordEntryVerdictHistogram, 0);
}
-TEST_F(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
- histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogramName, 0);
+TEST_P(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
+ histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
GURL target_url(kTargetUrl);
EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url, _))
.WillRepeatedly(Return(AsyncMatch::NO_MATCH));
password_protection_service_->StartRequest(
nullptr, target_url, GURL("http://foo.com/submit"),
- GURL("http://foo.com/frame"), std::string(),
+ GURL("http://foo.com/frame"), false, {},
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
// Destroy password_protection_service_ while there is one request pending.
@@ -753,11 +804,11 @@ TEST_F(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
base::RunLoop().RunUntilIdle();
EXPECT_THAT(
- histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogramName),
+ histograms_.GetAllSamples(kPasswordOnFocusRequestOutcomeHistogram),
ElementsAre(base::Bucket(2 /* CANCELED */, 1)));
}
-TEST_F(PasswordProtectionServiceTest, TestCleanUpExpiredVerdict) {
+TEST_P(PasswordProtectionServiceTest, TestCleanUpExpiredVerdict) {
// Prepare 4 verdicts for PASSWORD_REUSE_EVENT:
// (1) "foo.com/abc" valid
// (2) "foo.com/def" expired
@@ -841,7 +892,7 @@ TEST_F(PasswordProtectionServiceTest, TestCleanUpExpiredVerdict) {
&actual_verdict));
}
-TEST_F(PasswordProtectionServiceTest,
+TEST_P(PasswordProtectionServiceTest,
TestCleanUpExpiredVerdictWithInvalidEntry) {
CacheInvalidVerdict();
ContentSettingsForOneType password_protection_settings;
@@ -858,7 +909,7 @@ TEST_F(PasswordProtectionServiceTest,
EXPECT_TRUE(password_protection_settings.empty());
}
-TEST_F(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
+TEST_P(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
// Set up valid response.
net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
fetcher.set_status(
@@ -887,7 +938,8 @@ TEST_F(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
EXPECT_EQ(kFormActionUrl, actual_request->frames(1).forms(0).action_url());
}
-TEST_F(PasswordProtectionServiceTest, VerifyPasswordProtectionRequestProto) {
+TEST_P(PasswordProtectionServiceTest,
+ VerifySyncPasswordProtectionRequestProto) {
// Set up valid response.
net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
fetcher.set_status(
@@ -896,10 +948,11 @@ TEST_F(PasswordProtectionServiceTest, VerifyPasswordProtectionRequestProto) {
LoginReputationClientResponse expected_response = CreateVerdictProto(
LoginReputationClientResponse::PHISHING, 600, GURL(kTargetUrl).host());
fetcher.SetResponseString(expected_response.SerializeAsString());
+
// Initialize request triggered by chrome sync password reuse.
- InitializeAndStartPasswordEntryRequest(
- std::string(password_manager::kSyncPasswordDomain),
- false /* match whitelist */, 100000 /* timeout in ms*/);
+ InitializeAndStartPasswordEntryRequest(true /* matches_sync_password */, {},
+ false /* match whitelist */,
+ 100000 /* timeout in ms*/);
base::RunLoop().RunUntilIdle();
request_->OnURLFetchComplete(&fetcher);
base::RunLoop().RunUntilIdle();
@@ -913,24 +966,46 @@ TEST_F(PasswordProtectionServiceTest, VerifyPasswordProtectionRequestProto) {
EXPECT_EQ(kTargetUrl, actual_request->frames(0).url());
EXPECT_TRUE(actual_request->frames(0).has_password_field());
ASSERT_TRUE(actual_request->has_password_reuse_event());
- ASSERT_TRUE(
- actual_request->password_reuse_event().is_chrome_signin_password());
+ const auto& reuse_event = actual_request->password_reuse_event();
+ EXPECT_TRUE(reuse_event.is_chrome_signin_password());
+ EXPECT_EQ(0, reuse_event.domains_matching_password_size());
+}
+
+TEST_P(PasswordProtectionServiceTest,
+ VerifyNonSyncPasswordProtectionRequestProto) {
+ // Set up valid response.
+ net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
+ fetcher.set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ fetcher.set_response_code(200);
+ LoginReputationClientResponse expected_response = CreateVerdictProto(
+ LoginReputationClientResponse::PHISHING, 600, GURL(kTargetUrl).host());
+ fetcher.SetResponseString(expected_response.SerializeAsString());
// Initialize request triggered by saved password reuse.
- InitializeAndStartPasswordEntryRequest(std::string(kSavedDomain),
- false /* match whitelist */,
- 100000 /* timeout in ms*/);
+ InitializeAndStartPasswordEntryRequest(
+ false /* matches_sync_password */, {kSavedDomain, kSavedDomain2},
+ false /* match whitelist */, 100000 /* timeout in ms*/);
base::RunLoop().RunUntilIdle();
request_->OnURLFetchComplete(&fetcher);
base::RunLoop().RunUntilIdle();
- actual_request = password_protection_service_->GetLatestRequestProto();
+ const LoginReputationClientRequest* actual_request =
+ password_protection_service_->GetLatestRequestProto();
ASSERT_TRUE(actual_request->has_password_reuse_event());
- ASSERT_FALSE(
- actual_request->password_reuse_event().is_chrome_signin_password());
+ const auto& reuse_event = actual_request->password_reuse_event();
+ EXPECT_FALSE(reuse_event.is_chrome_signin_password());
+
+ if (password_protection_service_->IsExtendedReporting() &&
+ !password_protection_service_->IsIncognito()) {
+ ASSERT_EQ(2, reuse_event.domains_matching_password_size());
+ EXPECT_EQ(kSavedDomain, reuse_event.domains_matching_password(0));
+ EXPECT_EQ(kSavedDomain2, reuse_event.domains_matching_password(1));
+ } else {
+ EXPECT_EQ(0, reuse_event.domains_matching_password_size());
+ }
}
-
-TEST_F(PasswordProtectionServiceTest, VerifyCanSendPing) {
+TEST_P(PasswordProtectionServiceTest, VerifyCanSendPing) {
GURL suspicious_url("http://phishing.com");
EXPECT_TRUE(password_protection_service_->CanSendPing(
kProtectedPasswordEntryPinging, suspicious_url,
@@ -945,4 +1020,12 @@ TEST_F(PasswordProtectionServiceTest, VerifyCanSendPing) {
password_protection_service_->checked_feature_name());
}
+INSTANTIATE_TEST_CASE_P(
+ InstSBERIncog,
+ PasswordProtectionServiceTest,
+ ::testing::Values(std::vector<bool>({false, false}), // SBER, incog.
+ std::vector<bool>({false, true}),
+ std::vector<bool>({true, false}),
+ std::vector<bool>({true, true})));
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/csd.proto b/chromium/components/safe_browsing/proto/csd.proto
index 088d7b5bde3..f712ff0edda 100644
--- a/chromium/components/safe_browsing/csd.proto
+++ b/chromium/components/safe_browsing/proto/csd.proto
@@ -209,7 +209,11 @@ message LoginReputationClientRequest {
// The message contains fields needed for a password reuse event.
// Next tag: 4
message PasswordReuseEvent {
- reserved 1;
+ // Domains from the Chrome password manager DB that are associated with
+ // the same password as the one triggering this event. The field is filled
+ // in only when TriggerType is PASSWORD_REUSE_EVENT, and only for users
+ // opted in to extended reporting.
+ repeated string domains_matching_password = 1;
// The frame that the password reuse is detected.
optional int32 frame_id = 2;
@@ -911,7 +915,7 @@ message DownloadMetadata {
// A Detailed Safebrowsing Report from clients. Chrome safebrowsing reports are
// only sent by Chrome users who have opted into extended Safe Browsing.
// This proto is replacing ClientMalwareReportRequest.
-// Next tag: 17
+// Next tag: 19
message ClientSafeBrowsingReportRequest {
// Note: A lot of the "optional" fields would make sense to be
// "required" instead. However, having them as optional allows the
@@ -929,6 +933,8 @@ message ClientSafeBrowsingReportRequest {
DANGEROUS_DOWNLOAD_WARNING = 7;
DANGEROUS_DOWNLOAD_BY_API = 10;
URL_PASSWORD_PROTECTION_PHISHING = 12;
+ DANGEROUS_DOWNLOAD_OPENED = 13;
+ AD_SAMPLE = 14;
}
message HTTPHeader {
@@ -1011,8 +1017,8 @@ message ClientSafeBrowsingReportRequest {
// The same token in ClientDownloadResponse or LoginReputationClientResponse.
// This field is only set if its report type is DANGEROUS_DOWNLOAD_RECOVERY,
- // DANGEROUS_DOWNLOAD_WARNING, DANGEROUS_DOWNLOAD_BY_API or
- // PASSWORD_PROTECTION_PHISHING_URL.
+ // DANGEROUS_DOWNLOAD_WARNING, DANGEROUS_DOWNLOAD_BY_API,
+ // URL_PASSWORD_PROTECTION_PHISHING, or DANGEROUS_DOWNLOAD_OPENED.
optional bytes token = 15;
enum SafeBrowsingUrlApiType {
@@ -1037,6 +1043,12 @@ message ClientSafeBrowsingReportRequest {
optional SafeBrowsingUrlApiType url_api_type = 4;
}
optional SafeBrowsingClientProperties client_properties = 17;
+
+ // Only set if report type is DANGEROUS_DOWNLOAD_EXECUTION.
+ // True means user opened the folder where this download is in via browser.
+ // False means user directly executed this download via download shelf or
+ // other download UIs.
+ optional bool show_download_in_folder = 18;
}
// An HTML Element on the page (eg: iframe, div, script, etc).
diff --git a/chromium/components/safe_browsing/proto/webui.proto b/chromium/components/safe_browsing/proto/webui.proto
new file mode 100644
index 00000000000..c495460f0a1
--- /dev/null
+++ b/chromium/components/safe_browsing/proto/webui.proto
@@ -0,0 +1,106 @@
+// 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.
+
+// This file includes Safe Browsing WebUI protocol buffer.
+
+syntax = "proto2";
+
+package safe_browsing;
+
+option optimize_for = LITE_RUNTIME;
+
+// Describes the state of the database manager.
+message DatabaseManagerInfo {
+ // Describes the status of the last update request sent to SafeBrowsing.
+ message UpdateInfo {
+ // Network status code for the last update request sent to SafeBrowsing.
+ optional int32 network_status_code = 1;
+
+ // The time, since epoch, when the last update request was sent to
+ // SafeBrowsing.
+ optional uint64 last_update_time_millis = 2;
+ }
+
+ optional UpdateInfo update_info = 1;
+
+ // Describes the state of the database.
+ message DatabaseInfo {
+ // Was the last update applied successfully?
+ optional bool update_successful = 1;
+
+ // Sum of the store sizes in the database.
+ optional uint64 database_size_bytes = 2;
+
+ // Describes the state of a store in the database.
+ message StoreInfo {
+ // The store file name.
+ optional string file_name = 1;
+
+ // The store file size.
+ optional int64 file_size_bytes = 2;
+
+ // The status of applying the updates fetched from the server to the
+ // store. The values of update_status corresponds to the enum
+ // ApplyUpdateResult in V4Store.
+ optional int32 update_status = 3;
+
+ // The time, since epoch, of applying the updates to the store.
+ optional uint64 last_apply_update_time_millis = 4;
+
+ // The number of times the store has been queried for a prefix.
+ optional uint32 checks_attempted = 5;
+ }
+
+ // Information about each of the stores managed by the database.
+ repeated StoreInfo store_info = 3;
+ }
+
+ optional DatabaseInfo database_info = 2;
+}
+
+// The information about the list of prefixes for which the full hashes have
+// been stored in the cache.
+message FullHashCacheInfo {
+ // Records number of cache hits since the beginning of the session.
+ optional int32 number_of_hits = 1;
+ // Cached full hashes received from the server for the corresponding hash
+ // prefixes.
+ message FullHashCache {
+ // The hash prefix for which the full hashes are stored in the cache.
+ optional string hash_prefix = 1;
+ // The information about a hash prefix stored in the cache.
+ message CachedHashPrefixInfo {
+ // The negative ttl for the hash prefix.
+ optional int64 negative_expiry = 1;
+ // The information about a particular full hash.
+ message FullHashInfo {
+ // The expiration time of the full hash for a particular store.
+ optional int64 positive_expiry = 1;
+ // A variable-length SHA256 hash with size between 4 and 32 bytes
+ // inclusive.
+ optional string full_hash = 2;
+ // The list for which this full hash is applicable.
+ message ListIdentifier {
+ // Types of platforms. The value of platform_type corresponds to the
+ // PlatformType enum in safebrowsing_proto.
+ optional int32 platform_type = 1;
+ // Types of entries that pose threats. The value of threat_entry_type
+ // corresponds to the ThreatEntryType enum in safebrowsing_proto.
+ optional int32 threat_entry_type = 2;
+ // Types of threats. The value of threat_type corresponds to the
+ // ThreatType enum in safebrowsing_proto.
+ optional int32 threat_type = 3;
+ }
+ optional ListIdentifier list_identifier = 3;
+ }
+ // The list of all full hashes (and related info) that start with a
+ // particular hash prefix and are known to be unsafe.
+ repeated FullHashInfo full_hash_info = 2;
+ }
+ // Information about the cached hash prefix for each hash prefix in the
+ // cache.
+ optional CachedHashPrefixInfo cached_hash_prefix_info = 2;
+ }
+ repeated FullHashCache full_hash_cache = 2;
+}
diff --git a/chromium/components/safe_browsing/renderer/BUILD.gn b/chromium/components/safe_browsing/renderer/BUILD.gn
index 02239b48b2f..271efd9fb9c 100644
--- a/chromium/components/safe_browsing/renderer/BUILD.gn
+++ b/chromium/components/safe_browsing/renderer/BUILD.gn
@@ -22,18 +22,22 @@ source_set("renderer") {
}
}
-source_set("websocket_sb_handshake_throttle") {
+source_set("throttles") {
sources = [
+ "renderer_url_loader_throttle.cc",
+ "renderer_url_loader_throttle.h",
"websocket_sb_handshake_throttle.cc",
"websocket_sb_handshake_throttle.h",
]
deps = [
"//base:base",
+ "//components/safe_browsing/common:common",
"//components/safe_browsing/common:interfaces",
"//content/public/common:common",
"//content/public/renderer:renderer",
"//ipc",
+ "//net",
"//services/service_manager/public/cpp:cpp",
"//third_party/WebKit/public:blink",
"//url:url",
@@ -47,7 +51,7 @@ source_set("websocket_sb_handshake_throttle_unittest") {
]
deps = [
- ":websocket_sb_handshake_throttle",
+ ":throttles",
"//base:base",
"//base/test:test_support",
"//components/safe_browsing/common:interfaces",
diff --git a/chromium/components/safe_browsing/renderer/DEPS b/chromium/components/safe_browsing/renderer/DEPS
index 15dc39ee340..60654785bdc 100644
--- a/chromium/components/safe_browsing/renderer/DEPS
+++ b/chromium/components/safe_browsing/renderer/DEPS
@@ -1,8 +1,9 @@
include_rules = [
"+content/public/renderer",
- "+components/safe_browsing",
+ "+components/safe_browsing",
"+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web",
"+ipc",
"+mojo/public/cpp",
+ "+net/http/redirect_info.h",
]
diff --git a/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.cc b/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.cc
new file mode 100644
index 00000000000..32af062814b
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.cc
@@ -0,0 +1,117 @@
+// 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/safe_browsing/renderer/renderer_url_loader_throttle.h"
+
+#include "base/logging.h"
+#include "components/safe_browsing/common/utils.h"
+#include "content/public/common/resource_request.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/url_request/redirect_info.h"
+
+namespace safe_browsing {
+
+RendererURLLoaderThrottle::RendererURLLoaderThrottle(
+ mojom::SafeBrowsing* safe_browsing,
+ int render_frame_id)
+ : safe_browsing_(safe_browsing),
+ render_frame_id_(render_frame_id),
+ weak_factory_(this) {}
+
+RendererURLLoaderThrottle::~RendererURLLoaderThrottle() = default;
+
+void RendererURLLoaderThrottle::WillStartRequest(
+ const content::ResourceRequest& request,
+ bool* defer) {
+ DCHECK_EQ(0u, pending_checks_);
+ DCHECK(!blocked_);
+ DCHECK(!url_checker_);
+
+ pending_checks_++;
+ // Use a weak pointer to self because |safe_browsing_| is not owned by this
+ // object.
+ safe_browsing_->CreateCheckerAndCheck(
+ render_frame_id_, mojo::MakeRequest(&url_checker_), request.url,
+ request.method, request.headers, request.load_flags,
+ request.resource_type, request.has_user_gesture,
+ base::BindOnce(&RendererURLLoaderThrottle::OnCheckUrlResult,
+ weak_factory_.GetWeakPtr()));
+ safe_browsing_ = nullptr;
+
+ url_checker_.set_connection_error_handler(base::BindOnce(
+ &RendererURLLoaderThrottle::OnConnectionError, base::Unretained(this)));
+}
+
+void RendererURLLoaderThrottle::WillRedirectRequest(
+ const net::RedirectInfo& redirect_info,
+ bool* defer) {
+ // If |blocked_| is true, the resource load has been canceled and there
+ // shouldn't be such a notification.
+ DCHECK(!blocked_);
+
+ if (!url_checker_) {
+ DCHECK_EQ(0u, pending_checks_);
+ return;
+ }
+
+ pending_checks_++;
+ url_checker_->CheckUrl(
+ redirect_info.new_url, redirect_info.new_method,
+ base::BindOnce(&RendererURLLoaderThrottle::OnCheckUrlResult,
+ base::Unretained(this)));
+}
+
+void RendererURLLoaderThrottle::WillProcessResponse(bool* defer) {
+ // If |blocked_| is true, the resource load has been canceled and there
+ // shouldn't be such a notification.
+ DCHECK(!blocked_);
+
+ if (pending_checks_ == 0) {
+ LogDelay(base::TimeDelta());
+ return;
+ }
+
+ DCHECK(!deferred_);
+ deferred_ = true;
+ defer_start_time_ = base::TimeTicks::Now();
+ *defer = true;
+}
+
+void RendererURLLoaderThrottle::OnCheckUrlResult(bool proceed,
+ bool showed_interstitial) {
+ if (blocked_ || !url_checker_)
+ return;
+
+ DCHECK_LT(0u, pending_checks_);
+ pending_checks_--;
+
+ if (proceed) {
+ if (pending_checks_ == 0 && deferred_) {
+ LogDelay(base::TimeTicks::Now() - defer_start_time_);
+ deferred_ = false;
+ delegate_->Resume();
+ }
+ } else {
+ url_checker_.reset();
+ blocked_ = true;
+ pending_checks_ = 0;
+ delegate_->CancelWithError(net::ERR_ABORTED);
+ }
+}
+
+void RendererURLLoaderThrottle::OnConnectionError() {
+ DCHECK(!blocked_);
+
+ // If a service-side disconnect happens, treat all URLs as if they are safe.
+ url_checker_.reset();
+ pending_checks_ = 0;
+
+ if (deferred_) {
+ deferred_ = false;
+ LogDelay(base::TimeTicks::Now() - defer_start_time_);
+ delegate_->Resume();
+ }
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.h b/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.h
new file mode 100644
index 00000000000..9f64297d211
--- /dev/null
+++ b/chromium/components/safe_browsing/renderer/renderer_url_loader_throttle.h
@@ -0,0 +1,56 @@
+// 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_SAFE_BROWSING_RENDERER_RENDERER_URL_LOADER_THROTTLE_H_
+#define COMPONENTS_SAFE_BROWSING_RENDERER_RENDERER_URL_LOADER_THROTTLE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/safe_browsing/common/safe_browsing.mojom.h"
+#include "content/public/common/url_loader_throttle.h"
+
+namespace safe_browsing {
+
+// RendererURLLoaderThrottle is used in renderer processes to query
+// SafeBrowsing and determine whether a URL and its redirect URLs are safe to
+// load. It defers response processing until all URL checks are completed;
+// cancels the load if any URLs turn out to be bad.
+class RendererURLLoaderThrottle : public content::URLLoaderThrottle {
+ public:
+ // |safe_browsing| must stay alive until WillStartRequest() (if it is called)
+ // or the end of this object.
+ // |render_frame_id| is used for displaying SafeBrowsing UI when necessary.
+ RendererURLLoaderThrottle(mojom::SafeBrowsing* safe_browsing,
+ int render_frame_id);
+ ~RendererURLLoaderThrottle() override;
+
+ // content::URLLoaderThrottle implementation.
+ void WillStartRequest(const content::ResourceRequest& request,
+ bool* defer) override;
+ void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+ bool* defer) override;
+ void WillProcessResponse(bool* defer) override;
+
+ private:
+ void OnCheckUrlResult(bool proceed, bool showed_interstitial);
+
+ void OnConnectionError();
+
+ mojom::SafeBrowsing* safe_browsing_;
+ const int render_frame_id_;
+
+ mojom::SafeBrowsingUrlCheckerPtr url_checker_;
+
+ size_t pending_checks_ = 0;
+ bool blocked_ = false;
+
+ // The time when we started deferring the request.
+ base::TimeTicks defer_start_time_;
+ bool deferred_ = false;
+
+ base::WeakPtrFactory<RendererURLLoaderThrottle> weak_factory_;
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_RENDERER_RENDERER_URL_LOADER_THROTTLE_H_
diff --git a/chromium/components/safe_browsing/renderer/threat_dom_details.cc b/chromium/components/safe_browsing/renderer/threat_dom_details.cc
index 823b36a2c92..eee6d491039 100644
--- a/chromium/components/safe_browsing/renderer/threat_dom_details.cc
+++ b/chromium/components/safe_browsing/renderer/threat_dom_details.cc
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
@@ -309,17 +310,20 @@ void ThreatDOMDetails::ExtractResources(
ElementToNodeMap element_to_node_map;
blink::WebElementCollection elements = document.All();
blink::WebElement element = elements.FirstItem();
+ bool max_nodes_exceeded = false;
for (; !element.IsNull(); element = elements.NextItem()) {
if (ShouldHandleElement(element, tag_and_attributes_list_)) {
HandleElement(element, tag_and_attributes_list_, &details_node, resources,
&element_to_node_map);
if (resources->size() >= kMaxNodes) {
// We have reached kMaxNodes, exit early.
- resources->push_back(details_node);
- return;
+ max_nodes_exceeded = true;
+ break;
}
}
}
+ UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.ThreatReport.MaxNodesExceededInFrame",
+ max_nodes_exceeded);
resources->push_back(details_node);
}
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
index 7e7bfefcbf2..5eb84dcc189 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
@@ -51,22 +52,30 @@ void WebSocketSBHandshakeThrottle::ThrottleHandshake(
url_ = url;
int render_frame_id = MSG_ROUTING_NONE;
if (web_local_frame) {
- render_frame_id =
- content::RenderFrame::FromWebFrame(web_local_frame)->GetRoutingID();
+ auto* render_frame = content::RenderFrame::FromWebFrame(web_local_frame);
+ if (render_frame)
+ render_frame_id = render_frame->GetRoutingID();
}
int load_flags = 0;
start_time_ = base::TimeTicks::Now();
safe_browsing_->CreateCheckerAndCheck(
- render_frame_id, mojo::MakeRequest(&url_checker_), url, load_flags,
- content::RESOURCE_TYPE_SUB_RESOURCE,
+ render_frame_id, mojo::MakeRequest(&url_checker_), url, "GET",
+ std::string(), load_flags, content::RESOURCE_TYPE_SUB_RESOURCE, false,
base::BindOnce(&WebSocketSBHandshakeThrottle::OnCheckResult,
weak_factory_.GetWeakPtr()));
+
+ // This use of base::Unretained() is safe because the handler will not be
+ // called after |url_checker_| is destroyed, and it is owned by this object.
+ url_checker_.set_connection_error_handler(
+ base::BindOnce(&WebSocketSBHandshakeThrottle::OnConnectionError,
+ base::Unretained(this)));
}
-void WebSocketSBHandshakeThrottle::OnCheckResult(bool safe) {
+void WebSocketSBHandshakeThrottle::OnCheckResult(bool proceed,
+ bool showed_interstitial) {
DCHECK(!start_time_.is_null());
base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
- if (safe) {
+ if (proceed) {
result_ = Result::SAFE;
UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Safe", elapsed);
callbacks_->OnSuccess();
@@ -82,4 +91,15 @@ void WebSocketSBHandshakeThrottle::OnCheckResult(bool safe) {
// |this| is destroyed here.
}
+void WebSocketSBHandshakeThrottle::OnConnectionError() {
+ DCHECK_EQ(result_, Result::UNKNOWN);
+
+ url_checker_.reset();
+ // Make the destructor record NOT_SUPPORTED in the result histogram.
+ result_ = Result::NOT_SUPPORTED;
+ // Don't record the time elapsed because it's unlikely to be meaningful.
+ callbacks_->OnSuccess();
+ // |this| is destroyed here.
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
index 71a2c73832c..291f7cfda49 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
@@ -37,9 +37,11 @@ class WebSocketSBHandshakeThrottle : public blink::WebSocketHandshakeThrottle {
SAFE = 1,
BLOCKED = 2,
ABANDONED = 3,
+ NOT_SUPPORTED = 4,
RESULT_COUNT
};
- void OnCheckResult(bool safe);
+ void OnCheckResult(bool proceed, bool showed_interstitial);
+ void OnConnectionError();
GURL url_;
blink::WebCallbacks<void, const blink::WebString&>* callbacks_;
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
index 806768d3c7e..6a760bb8efe 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
@@ -27,19 +27,29 @@ constexpr char kTestUrl[] = "wss://test/";
class FakeSafeBrowsing : public mojom::SafeBrowsing {
public:
- FakeSafeBrowsing() : render_frame_id_(), load_flags_(-1), resource_type_() {}
+ FakeSafeBrowsing()
+ : render_frame_id_(),
+ load_flags_(-1),
+ resource_type_(),
+ has_user_gesture_(false) {}
void CreateCheckerAndCheck(int32_t render_frame_id,
mojom::SafeBrowsingUrlCheckerRequest request,
const GURL& url,
+ const std::string& method,
+ const std::string& headers,
int32_t load_flags,
content::ResourceType resource_type,
+ bool has_user_gesture,
CreateCheckerAndCheckCallback callback) override {
render_frame_id_ = render_frame_id;
request_ = std::move(request);
url_ = url;
+ method_ = method;
+ headers_ = headers;
load_flags_ = load_flags;
resource_type_ = resource_type;
+ has_user_gesture_ = has_user_gesture;
callback_ = std::move(callback);
run_loop_.Quit();
}
@@ -49,8 +59,11 @@ class FakeSafeBrowsing : public mojom::SafeBrowsing {
int32_t render_frame_id_;
mojom::SafeBrowsingUrlCheckerRequest request_;
GURL url_;
+ std::string method_;
+ std::string headers_;
int32_t load_flags_;
content::ResourceType resource_type_;
+ bool has_user_gesture_;
CreateCheckerAndCheckCallback callback_;
base::RunLoop run_loop_;
};
@@ -105,15 +118,18 @@ TEST_F(WebSocketSBHandshakeThrottleTest, CheckArguments) {
// the code that looks up the render_frame_id can be tested.
EXPECT_EQ(MSG_ROUTING_NONE, safe_browsing_.render_frame_id_);
EXPECT_EQ(GURL(kTestUrl), safe_browsing_.url_);
+ EXPECT_EQ("GET", safe_browsing_.method_);
+ EXPECT_TRUE(safe_browsing_.headers_.empty());
EXPECT_EQ(0, safe_browsing_.load_flags_);
EXPECT_EQ(content::RESOURCE_TYPE_SUB_RESOURCE, safe_browsing_.resource_type_);
+ EXPECT_FALSE(safe_browsing_.has_user_gesture_);
EXPECT_TRUE(safe_browsing_.callback_);
}
TEST_F(WebSocketSBHandshakeThrottleTest, Safe) {
throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
safe_browsing_.RunUntilCalled();
- std::move(safe_browsing_.callback_).Run(true);
+ std::move(safe_browsing_.callback_).Run(true, false);
fake_callbacks_.RunUntilCalled();
EXPECT_EQ(FakeWebCallbacks::RESULT_SUCCESS, fake_callbacks_.result_);
}
@@ -121,7 +137,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, Safe) {
TEST_F(WebSocketSBHandshakeThrottleTest, Unsafe) {
throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
safe_browsing_.RunUntilCalled();
- std::move(safe_browsing_.callback_).Run(false);
+ std::move(safe_browsing_.callback_).Run(false, false);
fake_callbacks_.RunUntilCalled();
EXPECT_EQ(FakeWebCallbacks::RESULT_ERROR, fake_callbacks_.result_);
EXPECT_EQ(
@@ -130,6 +146,13 @@ TEST_F(WebSocketSBHandshakeThrottleTest, Unsafe) {
fake_callbacks_.message_);
}
+TEST_F(WebSocketSBHandshakeThrottleTest, MojoServiceNotThere) {
+ mojo_binding_.Close();
+ throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ fake_callbacks_.RunUntilCalled();
+ EXPECT_EQ(FakeWebCallbacks::RESULT_SUCCESS, fake_callbacks_.result_);
+}
+
} // namespace
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/triggers/BUILD.gn b/chromium/components/safe_browsing/triggers/BUILD.gn
index 32721f0838d..c591384e0c4 100644
--- a/chromium/components/safe_browsing/triggers/BUILD.gn
+++ b/chromium/components/safe_browsing/triggers/BUILD.gn
@@ -20,6 +20,7 @@ source_set("triggers") {
"//components/prefs:prefs",
"//components/safe_browsing:safe_browsing",
"//components/safe_browsing/browser:browser",
+ "//net:net",
]
}
@@ -30,6 +31,7 @@ source_set("trigger_throttler") {
]
deps = [
"//base:base",
+ "//components/safe_browsing:features",
]
}
@@ -39,6 +41,8 @@ source_set("ad_sampler_trigger") {
"ad_sampler_trigger.h",
]
deps = [
+ ":trigger_throttler",
+ ":triggers",
"//base:base",
"//components/safe_browsing:features",
"//content/public/browser",
@@ -48,17 +52,21 @@ source_set("ad_sampler_trigger") {
source_set("unit_tests") {
testonly = true
sources = [
+ "ad_sampler_trigger_unittest.cc",
"trigger_manager_unittest.cc",
"trigger_throttler_unittest.cc",
]
deps = [
+ ":ad_sampler_trigger",
":trigger_throttler",
":triggers",
"//base",
- "//chrome/test:test_support",
+ "//base/test:test_support",
"//components/prefs:test_support",
+ "//components/safe_browsing:features",
"//components/safe_browsing/browser:browser",
"//content/test:test_support",
+ "//testing/gmock",
"//testing/gtest",
]
}
diff --git a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
index 8ca19eaa080..29ae219b1cf 100644
--- a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
+++ b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
@@ -9,8 +9,12 @@
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "components/safe_browsing/features.h"
+#include "components/safe_browsing/triggers/trigger_manager.h"
+#include "components/safe_browsing/triggers/trigger_throttler.h"
+#include "components/security_interstitials/content/unsafe_resource.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(safe_browsing::AdSamplerTrigger);
@@ -24,6 +28,10 @@ const char kAdSamplerFrequencyDenominatorParam[] =
// A frequency denominator with this value indicates sampling is disabled.
const size_t kSamplerFrequencyDisabled = 0;
+// Number of milliseconds to allow data collection to run before sending a
+// report (since this trigger runs in the background).
+const int64_t kAdSampleCollectionPeriodMilliseconds = 5000;
+
namespace {
size_t GetSamplerFrequencyDenominator() {
@@ -77,19 +85,73 @@ bool ShouldCheckForAd(const size_t frequency_denominator) {
} // namespace
-AdSamplerTrigger::AdSamplerTrigger(content::WebContents* web_contents)
+AdSamplerTrigger::AdSamplerTrigger(
+ content::WebContents* web_contents,
+ TriggerManager* trigger_manager,
+ PrefService* prefs,
+ net::URLRequestContextGetter* request_context,
+ history::HistoryService* history_service)
: content::WebContentsObserver(web_contents),
- sampler_frequency_denominator_(GetSamplerFrequencyDenominator()) {}
+ sampler_frequency_denominator_(GetSamplerFrequencyDenominator()),
+ trigger_manager_(trigger_manager),
+ prefs_(prefs),
+ request_context_(request_context),
+ history_service_(history_service) {}
AdSamplerTrigger::~AdSamplerTrigger() {}
+// static
+void AdSamplerTrigger::CreateForWebContents(
+ content::WebContents* web_contents,
+ TriggerManager* trigger_manager,
+ PrefService* prefs,
+ net::URLRequestContextGetter* request_context,
+ history::HistoryService* history_service) {
+ DCHECK(web_contents);
+ if (!FromWebContents(web_contents)) {
+ web_contents->SetUserData(UserDataKey(),
+ base::WrapUnique(new AdSamplerTrigger(
+ web_contents, trigger_manager, prefs,
+ request_context, history_service)));
+ }
+}
+
+// TODO(lpz): In some cases, this event may be too early for ads to finish
+// loading on the page. Investigate later events or possible timer delays.
void AdSamplerTrigger::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
// TODO(lpz): Add UMA metrics for how often we skip checking, find nothing, or
// take a sample.
if (ShouldCheckForAd(sampler_frequency_denominator_) &&
DetectGoogleAd(navigation_handle)) {
- // TODO(lpz): Call into TriggerManager to sample the ad.
+ SBErrorOptions error_options =
+ TriggerManager::GetSBErrorDisplayOptions(*prefs_, *web_contents());
+
+ security_interstitials::UnsafeResource resource;
+ resource.threat_type = SB_THREAT_TYPE_AD_SAMPLE;
+ resource.url = web_contents()->GetURL();
+ resource.web_contents_getter = resource.GetWebContentsGetter(
+ web_contents()->GetRenderProcessHost()->GetID(),
+ web_contents()->GetMainFrame()->GetRoutingID());
+
+ if (!trigger_manager_->StartCollectingThreatDetails(
+ TriggerType::AD_SAMPLE, web_contents(), resource, request_context_,
+ history_service_, error_options)) {
+ return;
+ }
+
+ // Immediately call FinishCollection but include a short delay to allow data
+ // collection to happen.
+ // TODO(lpz): This is suboptimal because we can send duplicate reports if
+ // there are multiple ads on the page. To improve this, the delay should be
+ // before calling into trigger_manager_, which requires TriggerManager to be
+ // Bind-able.
+ trigger_manager_->FinishCollectingThreatDetails(
+ TriggerType::AD_SAMPLE, web_contents(),
+ base::TimeDelta::FromMilliseconds(
+ kAdSampleCollectionPeriodMilliseconds),
+ /*did_proceed=*/false,
+ /*num_visits=*/0, error_options);
}
}
diff --git a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.h b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.h
index ab4c87c2595..5a2d3f1fe38 100644
--- a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.h
+++ b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.h
@@ -7,14 +7,24 @@
#include "base/macros.h"
#include "content/public/browser/web_contents_observer.h"
-
#include "content/public/browser/web_contents_user_data.h"
+class PrefService;
+
namespace content {
class NavigationHandle;
}
+namespace history {
+class HistoryService;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
namespace safe_browsing {
+class TriggerManager;
// Param name of the denominator for controlling sampling frequency.
extern const char kAdSamplerFrequencyDenominatorParam[];
@@ -29,18 +39,41 @@ class AdSamplerTrigger : public content::WebContentsObserver,
public:
~AdSamplerTrigger() override;
+ static void CreateForWebContents(
+ content::WebContents* web_contents,
+ TriggerManager* trigger_manager,
+ PrefService* prefs,
+ net::URLRequestContextGetter* request_context,
+ history::HistoryService* history_service);
+
// content::WebContentsObserver implementation.
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
private:
- explicit AdSamplerTrigger(content::WebContents* contents);
+ friend class AdSamplerTriggerTest;
friend class content::WebContentsUserData<AdSamplerTrigger>;
+ FRIEND_TEST_ALL_PREFIXES(AdSamplerTriggerTestFinch,
+ FrequencyDenominatorFeature);
+
+ AdSamplerTrigger(content::WebContents* web_contents,
+ TriggerManager* trigger_manager,
+ PrefService* prefs,
+ net::URLRequestContextGetter* request_context,
+ history::HistoryService* history_service);
// Ad samples will be collected with frequency
// 1/|sampler_frequency_denominator_|
size_t sampler_frequency_denominator_;
+ // TriggerManager gets called if this trigger detects an ad and wants to
+ // collect some data about it. Not owned.
+ TriggerManager* trigger_manager_;
+
+ PrefService* prefs_;
+ net::URLRequestContextGetter* request_context_;
+ history::HistoryService* history_service_;
+
DISALLOW_COPY_AND_ASSIGN(AdSamplerTrigger);
};
diff --git a/chromium/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc b/chromium/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc
new file mode 100644
index 00000000000..035bdf0d9e5
--- /dev/null
+++ b/chromium/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc
@@ -0,0 +1,193 @@
+// 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/safe_browsing/triggers/ad_sampler_trigger.h"
+
+#include "base/metrics/field_trial_params.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/safe_browsing/features.h"
+#include "components/safe_browsing/triggers/trigger_manager.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::NavigationSimulator;
+using content::RenderFrameHost;
+using content::RenderFrameHostTester;
+
+using testing::_;
+using testing::Return;
+
+namespace safe_browsing {
+
+namespace {
+const char kAdUrl[] = "https://tpc.googlesyndication.com/safeframe/1";
+const char kNonAdUrl[] = "https://foo.com/";
+const char kAdName[] = "google_ads_iframe_1";
+const char kNonAdName[] = "foo";
+} // namespace
+
+class MockTriggerManager : public TriggerManager {
+ public:
+ MockTriggerManager() : TriggerManager(nullptr) {}
+
+ MOCK_METHOD6(StartCollectingThreatDetails,
+ bool(TriggerType trigger_type,
+ content::WebContents* web_contents,
+ const security_interstitials::UnsafeResource& resource,
+ net::URLRequestContextGetter* request_context_getter,
+ history::HistoryService* history_service,
+ const SBErrorOptions& error_display_options));
+
+ MOCK_METHOD6(FinishCollectingThreatDetails,
+ bool(TriggerType trigger_type,
+ content::WebContents* web_contents,
+ const base::TimeDelta& delay,
+ bool did_proceed,
+ int num_visits,
+ const SBErrorOptions& error_display_options));
+};
+
+class AdSamplerTriggerTest : public content::RenderViewHostTestHarness {
+ public:
+ AdSamplerTriggerTest() {}
+ ~AdSamplerTriggerTest() override {}
+
+ void SetUp() override {
+ content::RenderViewHostTestHarness::SetUp();
+
+ // Enable any prefs required for the trigger to run.
+ safe_browsing::RegisterProfilePrefs(prefs_.registry());
+ prefs_.SetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
+ prefs_.SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, true);
+ prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true);
+ }
+
+ void CreateTriggerWithFrequency(const size_t denominator) {
+ safe_browsing::AdSamplerTrigger::CreateForWebContents(
+ web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr);
+ safe_browsing::AdSamplerTrigger::FromWebContents(web_contents())
+ ->sampler_frequency_denominator_ = denominator;
+ }
+
+ // Returns the final RenderFrameHost after navigation commits.
+ RenderFrameHost* NavigateFrame(const std::string& url,
+ RenderFrameHost* frame) {
+ auto navigation_simulator =
+ NavigationSimulator::CreateRendererInitiated(GURL(url), frame);
+ navigation_simulator->Commit();
+ return navigation_simulator->GetFinalRenderFrameHost();
+ }
+
+ // Returns the final RenderFrameHost after navigation commits.
+ RenderFrameHost* NavigateMainFrame(const std::string& url) {
+ return NavigateFrame(url, web_contents()->GetMainFrame());
+ }
+ // Returns the final RenderFrameHost after navigation commits.
+ RenderFrameHost* CreateAndNavigateSubFrame(const std::string& url,
+ const std::string& frame_name,
+ RenderFrameHost* parent) {
+ RenderFrameHost* subframe =
+ RenderFrameHostTester::For(parent)->AppendChild(frame_name);
+ auto navigation_simulator =
+ NavigationSimulator::CreateRendererInitiated(GURL(url), subframe);
+ navigation_simulator->Commit();
+ return navigation_simulator->GetFinalRenderFrameHost();
+ }
+
+ MockTriggerManager* get_trigger_manager() { return &trigger_manager_; }
+
+ private:
+ TestingPrefServiceSimple prefs_;
+ MockTriggerManager trigger_manager_;
+};
+
+TEST_F(AdSamplerTriggerTest, TriggerDisabledBySamplingFrequency) {
+ // Make sure the trigger doesn't fire when the samlping frequency is set to
+ // zero, which disables the trigger.
+ CreateTriggerWithFrequency(kSamplerFrequencyDisabled);
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ // This page contains two ads - one identifiable by its URL, the other by the
+ // name of the frame.
+ RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
+ CreateAndNavigateSubFrame(kAdUrl, kNonAdName, main_frame);
+ CreateAndNavigateSubFrame(kNonAdUrl, kAdName, main_frame);
+}
+
+TEST_F(AdSamplerTriggerTest, PageWithNoAds) {
+ // Make sure the trigger doesn't fire when there are no ads on the page.
+ CreateTriggerWithFrequency(/*denominator=*/1);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
+ CreateAndNavigateSubFrame(kNonAdUrl, kNonAdName, main_frame);
+ CreateAndNavigateSubFrame(kNonAdUrl, kNonAdName, main_frame);
+}
+
+TEST_F(AdSamplerTriggerTest, PageWithMultipleAds) {
+ // Make sure the trigger fires when there are ads on the page. We expect
+ // one call for each ad detected.
+ CreateTriggerWithFrequency(/*denominator=*/1);
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents(), _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents(), _, _, _, _))
+ .Times(2);
+
+ // This page contains two ads - one identifiable by its URL, the other by the
+ // name of the frame.
+ RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
+ CreateAndNavigateSubFrame(kAdUrl, kNonAdName, main_frame);
+ CreateAndNavigateSubFrame(kNonAdUrl, kAdName, main_frame);
+}
+
+TEST(AdSamplerTriggerTestFinch, FrequencyDenominatorFeature) {
+ // Make sure that setting the frequency denominator via Finch params works as
+ // expected.
+ const size_t kDenominatorInt = 12345;
+ base::FieldTrialList field_trial_list(nullptr);
+
+ base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
+ safe_browsing::kAdSamplerTriggerFeature.name, "Group");
+ std::map<std::string, std::string> feature_params;
+ feature_params[std::string(
+ safe_browsing::kAdSamplerFrequencyDenominatorParam)] =
+ base::IntToString(kDenominatorInt);
+ base::AssociateFieldTrialParams(safe_browsing::kAdSamplerTriggerFeature.name,
+ "Group", feature_params);
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(
+ safe_browsing::kAdSamplerTriggerFeature.name, std::string());
+ feature_list->AssociateReportingFieldTrial(
+ safe_browsing::kAdSamplerTriggerFeature.name,
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ AdSamplerTrigger trigger(nullptr, nullptr, nullptr, nullptr, nullptr);
+ EXPECT_EQ(kDenominatorInt, trigger.sampler_frequency_denominator_);
+}
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager.cc b/chromium/components/safe_browsing/triggers/trigger_manager.cc
index eeec916a499..9514994d915 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_manager.cc
@@ -17,25 +17,46 @@ namespace safe_browsing {
namespace {
-bool CanStartDataCollection(const SBErrorOptions& error_display_options,
- const TriggerThrottler& throttler,
- const TriggerType trigger_type) {
- // We start data collection as long as user is not incognito and is able to
- // change the Extended Reporting opt-in, and the |trigger_type| has available
- // quota. We don't require users to be opted-in to SBER to begin collecting
- // data, since they may be able to change the setting while data collection is
- // running (eg: on a security interstitial).
- return !error_display_options.is_off_the_record &&
- error_display_options.is_extended_reporting_opt_in_allowed &&
- throttler.TriggerCanFire(trigger_type);
+bool TriggerNeedsScout(const TriggerType trigger_type) {
+ switch (trigger_type) {
+ case TriggerType::SECURITY_INTERSTITIAL:
+ // Security interstitials only need legacy SBER opt-in.
+ return false;
+ case TriggerType::AD_SAMPLE:
+ // Ad samples need Scout-level opt-in.
+ return true;
+ }
+ // By default, require Scout so we are more restrictive on data collection.
+ return true;
}
-bool CanSendReport(const SBErrorOptions& error_display_options) {
+bool TriggerNeedsOptInForCollection(const TriggerType trigger_type) {
+ switch (trigger_type) {
+ case TriggerType::SECURITY_INTERSTITIAL:
+ // For security interstitials, users can change the opt-in while the
+ // trigger runs, so collection can begin without opt-in.
+ return false;
+ case TriggerType::AD_SAMPLE:
+ // Ad samples happen in the background so the user must already be opted
+ // in before the trigger is allowed to run.
+ return true;
+ }
+ // By default, require opt-in for all triggers.
+ return true;
+}
+
+bool CanSendReport(const SBErrorOptions& error_display_options,
+ const TriggerType trigger_type) {
+ // Some triggers require that users are eligible for elevated Scout data
+ // collection in order to run.
+ bool scout_check_ok = !TriggerNeedsScout(trigger_type) ||
+ error_display_options.is_scout_reporting_enabled;
+
// Reports are only sent for non-incoginito users who are allowed to modify
// the Extended Reporting setting and have opted-in to Extended Reporting.
return !error_display_options.is_off_the_record &&
error_display_options.is_extended_reporting_opt_in_allowed &&
- error_display_options.is_extended_reporting_enabled;
+ error_display_options.is_extended_reporting_enabled && scout_check_ok;
}
} // namespace
@@ -44,10 +65,14 @@ DataCollectorsContainer::DataCollectorsContainer() {}
DataCollectorsContainer::~DataCollectorsContainer() {}
TriggerManager::TriggerManager(BaseUIManager* ui_manager)
- : ui_manager_(ui_manager) {}
+ : ui_manager_(ui_manager), trigger_throttler_(new TriggerThrottler()) {}
TriggerManager::~TriggerManager() {}
+void TriggerManager::set_trigger_throttler(TriggerThrottler* throttler) {
+ trigger_throttler_.reset(throttler);
+}
+
// static
SBErrorOptions TriggerManager::GetSBErrorDisplayOptions(
const PrefService& pref_service,
@@ -56,12 +81,37 @@ SBErrorOptions TriggerManager::GetSBErrorDisplayOptions(
IsExtendedReportingOptInAllowed(pref_service),
web_contents.GetBrowserContext()->IsOffTheRecord(),
IsExtendedReportingEnabled(pref_service),
- /*is_scout_reporting_enabled=*/false,
+ IsScout(pref_service),
/*is_proceed_anyway_disabled=*/false,
/*should_open_links_in_new_tab=*/false,
/*help_center_article_link=*/std::string());
}
+bool TriggerManager::CanStartDataCollection(
+ const SBErrorOptions& error_display_options,
+ const TriggerType trigger_type) {
+ // Some triggers require that the user be opted-in to extended reporting in
+ // order to run, while others can run without opt-in (eg: because users are
+ // prompted for opt-in as part of the trigger).
+ bool optin_required_check_ok =
+ !TriggerNeedsOptInForCollection(trigger_type) ||
+ error_display_options.is_extended_reporting_enabled;
+
+ // Some triggers require that users are eligible for elevated Scout data
+ // collection in order to run.
+ bool scout_check_ok = !TriggerNeedsScout(trigger_type) ||
+ error_display_options.is_scout_reporting_enabled;
+
+ // We start data collection as long as user is not incognito and is able to
+ // change the Extended Reporting opt-in, and the |trigger_type| has available
+ // quota. For some triggers we also require Scout or extended reporting opt-in
+ // in order to start data collection.
+ return !error_display_options.is_off_the_record &&
+ error_display_options.is_extended_reporting_opt_in_allowed &&
+ optin_required_check_ok && scout_check_ok &&
+ trigger_throttler_->TriggerCanFire(trigger_type);
+}
+
bool TriggerManager::StartCollectingThreatDetails(
const TriggerType trigger_type,
content::WebContents* web_contents,
@@ -70,9 +120,7 @@ bool TriggerManager::StartCollectingThreatDetails(
history::HistoryService* history_service,
const SBErrorOptions& error_display_options) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- if (!CanStartDataCollection(error_display_options, trigger_throttler_,
- trigger_type))
+ if (!CanStartDataCollection(error_display_options, trigger_type))
return false;
// Ensure we're not already collecting data on this tab.
@@ -83,9 +131,11 @@ bool TriggerManager::StartCollectingThreatDetails(
return false;
DataCollectorsContainer* collectors = &data_collectors_map_[web_contents];
- collectors->threat_details = scoped_refptr<ThreatDetails>(
- ThreatDetails::NewThreatDetails(ui_manager_, web_contents, resource,
- request_context_getter, history_service));
+ bool should_trim_threat_details = trigger_type == TriggerType::AD_SAMPLE;
+ collectors->threat_details =
+ scoped_refptr<ThreatDetails>(ThreatDetails::NewThreatDetails(
+ ui_manager_, web_contents, resource, request_context_getter,
+ history_service, should_trim_threat_details));
return true;
}
@@ -97,7 +147,6 @@ bool TriggerManager::FinishCollectingThreatDetails(
int num_visits,
const SBErrorOptions& error_display_options) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
// Make sure there's a data collector running on this tab.
// TODO(lpz): this check should be more specific to check that the right type
// of data collector is running on this tab (once additional data collectors
@@ -106,7 +155,7 @@ bool TriggerManager::FinishCollectingThreatDetails(
return false;
// Determine whether a report should be sent.
- bool should_send_report = CanSendReport(error_display_options);
+ bool should_send_report = CanSendReport(error_display_options, trigger_type);
DataCollectorsContainer* collectors = &data_collectors_map_[web_contents];
// Find the data collector and tell it to finish collecting data, and then
@@ -122,7 +171,7 @@ bool TriggerManager::FinishCollectingThreatDetails(
delay);
// Record that this trigger fired and collected data.
- trigger_throttler_.TriggerFired(trigger_type);
+ trigger_throttler_->TriggerFired(trigger_type);
}
// Regardless of whether the report got sent, clean up the data collector on
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager.h b/chromium/components/safe_browsing/triggers/trigger_manager.h
index fcc0df62b06..2cd27eb15c7 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager.h
+++ b/chromium/components/safe_browsing/triggers/trigger_manager.h
@@ -64,7 +64,7 @@ using SBErrorOptions =
class TriggerManager {
public:
TriggerManager(BaseUIManager* ui_manager);
- ~TriggerManager();
+ virtual ~TriggerManager();
// Returns a SBErrorDisplayOptions struct containing user state that is
// relevant for TriggerManager to decide whether to start/finish data
@@ -74,6 +74,11 @@ class TriggerManager {
const PrefService& pref_service,
const content::WebContents& web_contents);
+ // Returns whether data collection can be started for the |trigger_type| based
+ // on the settings specified in |error_display_options| as well as quota.
+ bool CanStartDataCollection(const SBErrorOptions& error_display_options,
+ const TriggerType trigger_type);
+
// Begins collecting a ThreatDetails report on the specified |web_contents|.
// |resource| is the unsafe resource that cause the collection to occur.
// |request_context_getter| is used to retrieve data from the HTTP cache.
@@ -82,8 +87,8 @@ class TriggerManager {
// preferences. We use this object for interop with WebView, in Chrome it
// should be created by TriggerManager::GetSBErrorDisplayOptions().
// Returns true if the collection began, or false if it didn't.
- bool StartCollectingThreatDetails(
- const TriggerType trigger_type,
+ virtual bool StartCollectingThreatDetails(
+ TriggerType trigger_type,
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
net::URLRequestContextGetter* request_context_getter,
@@ -100,8 +105,8 @@ class TriggerManager {
// should be created by TriggerManager::GetSBErrorDisplayOptions().
// Returns true if the report was completed and sent, or false otherwise (eg:
// the user was not opted-in to extended reporting after collection began).
- bool FinishCollectingThreatDetails(
- const TriggerType trigger_type,
+ virtual bool FinishCollectingThreatDetails(
+ TriggerType trigger_type,
content::WebContents* web_contents,
const base::TimeDelta& delay,
bool did_proceed,
@@ -111,6 +116,9 @@ class TriggerManager {
private:
friend class TriggerManagerTest;
+ // For testing only - allows injecting a mock Throttler.
+ void set_trigger_throttler(TriggerThrottler* throttler);
+
// The UI manager is used to send reports to Google. Not owned.
// TODO(lpz): we may only need a the PingManager here.
BaseUIManager* ui_manager_;
@@ -119,7 +127,7 @@ class TriggerManager {
DataCollectorsMap data_collectors_map_;
// Keeps track of how often triggers fire and throttles them when needed.
- TriggerThrottler trigger_throttler_;
+ std::unique_ptr<TriggerThrottler> trigger_throttler_;
DISALLOW_COPY_AND_ASSIGN(TriggerManager);
};
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc b/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
index 662f446aff9..9038fd2a8f5 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -8,6 +8,7 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/safe_browsing/browser/threat_details.h"
+#include "components/safe_browsing/triggers/trigger_throttler.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_web_contents_factory.h"
@@ -16,6 +17,7 @@
using testing::_;
using testing::Key;
+using testing::Return;
using testing::UnorderedElementsAre;
namespace safe_browsing {
@@ -40,12 +42,18 @@ class MockThreatDetailsFactory : public ThreatDetailsFactory {
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& unsafe_resource,
net::URLRequestContextGetter* request_context_getter,
- history::HistoryService* history_service) override {
+ history::HistoryService* history_service,
+ bool trim_to_ad_tags) override {
MockThreatDetails* threat_details = new MockThreatDetails();
return threat_details;
}
};
+class MockTriggerThrottler : public TriggerThrottler {
+ public:
+ MOCK_CONST_METHOD1(TriggerCanFire, bool(TriggerType trigger_type));
+};
+
class TriggerManagerTest : public ::testing::Test {
public:
TriggerManagerTest() : trigger_manager_(/*ui_manager=*/nullptr) {}
@@ -60,12 +68,28 @@ class TriggerManagerTest : public ::testing::Test {
SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
SetPref(prefs::kSafeBrowsingScoutReportingEnabled, true);
SetPref(prefs::kSafeBrowsingScoutGroupSelected, true);
+
+ MockTriggerThrottler* mock_throttler = new MockTriggerThrottler();
+ ON_CALL(*mock_throttler, TriggerCanFire(_)).WillByDefault(Return(true));
+ // Trigger Manager takes ownership of the mock throttler.
+ trigger_manager_.set_trigger_throttler(mock_throttler);
}
void SetPref(const std::string& pref, bool value) {
pref_service_.SetBoolean(pref, value);
}
+ bool GetPref(const std::string& pref) {
+ return pref_service_.GetBoolean(pref);
+ }
+
+ void SetTriggerHasQuota(const TriggerType trigger_type, bool has_quota) {
+ MockTriggerThrottler* mock_throttler = static_cast<MockTriggerThrottler*>(
+ trigger_manager_.trigger_throttler_.get());
+ EXPECT_CALL(*mock_throttler, TriggerCanFire(trigger_type))
+ .WillOnce(Return(has_quota));
+ }
+
content::WebContents* CreateWebContents() {
DCHECK(!browser_context_.IsOffTheRecord())
<< "CreateWebContents() should not be called after "
@@ -78,15 +102,17 @@ class TriggerManagerTest : public ::testing::Test {
return web_contents_factory_.CreateWebContents(&browser_context_);
}
- bool StartCollectingThreatDetails(content::WebContents* web_contents) {
+ bool StartCollectingThreatDetails(const TriggerType trigger_type,
+ content::WebContents* web_contents) {
SBErrorOptions options =
TriggerManager::GetSBErrorDisplayOptions(pref_service_, *web_contents);
return trigger_manager_.StartCollectingThreatDetails(
- TriggerType::SECURITY_INTERSTITIAL, web_contents,
- security_interstitials::UnsafeResource(), nullptr, nullptr, options);
+ trigger_type, web_contents, security_interstitials::UnsafeResource(),
+ nullptr, nullptr, options);
}
- bool FinishCollectingThreatDetails(content::WebContents* web_contents,
+ bool FinishCollectingThreatDetails(const TriggerType trigger_type,
+ content::WebContents* web_contents,
bool expect_report_sent) {
if (expect_report_sent) {
MockThreatDetails* threat_details = static_cast<MockThreatDetails*>(
@@ -97,8 +123,7 @@ class TriggerManagerTest : public ::testing::Test {
SBErrorOptions options =
TriggerManager::GetSBErrorDisplayOptions(pref_service_, *web_contents);
return trigger_manager_.FinishCollectingThreatDetails(
- TriggerType::SECURITY_INTERSTITIAL, web_contents, base::TimeDelta(),
- false, 0, options);
+ trigger_type, web_contents, base::TimeDelta(), false, 0, options);
}
const DataCollectorsMap& data_collectors_map() {
@@ -120,49 +145,63 @@ TEST_F(TriggerManagerTest, StartAndFinishCollectingThreatDetails) {
// Basic workflow is to start and finish data collection with a single
// WebContents.
content::WebContents* web_contents1 = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents1));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents1)));
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents1, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1, true));
EXPECT_TRUE(data_collectors_map().empty());
// More complex scenarios can happen, where collection happens on two
// WebContents at the same time, possibly starting and completing in different
// order.
content::WebContents* web_contents2 = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents1));
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents2));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents2));
EXPECT_THAT(data_collectors_map(),
UnorderedElementsAre(Key(web_contents1), Key(web_contents2)));
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents2, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents2, true));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents1)));
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents1, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1, true));
EXPECT_TRUE(data_collectors_map().empty());
// Calling Start twice with the same WebContents is an error, and will return
// false the second time. But it can still be completed normally.
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents1));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents1)));
- EXPECT_FALSE(StartCollectingThreatDetails(web_contents1));
+ EXPECT_FALSE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents1)));
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents1, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1, true));
EXPECT_TRUE(data_collectors_map().empty());
// Calling Finish twice with the same WebContents is an error, and will return
// false the second time. It's basically a no-op.
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents1));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents1)));
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents1, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1, true));
EXPECT_TRUE(data_collectors_map().empty());
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents1, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents1, false));
EXPECT_TRUE(data_collectors_map().empty());
}
TEST_F(TriggerManagerTest, NoDataCollection_Incognito) {
// Data collection will not begin and no reports will be sent when incognito.
content::WebContents* web_contents = CreateIncognitoWebContents();
- EXPECT_FALSE(StartCollectingThreatDetails(web_contents));
+ EXPECT_FALSE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_TRUE(data_collectors_map().empty());
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -171,9 +210,11 @@ TEST_F(TriggerManagerTest, NoDataCollection_SBEROptInDisallowed) {
// not allowed to opt-in to SBER.
SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, false);
content::WebContents* web_contents = CreateWebContents();
- EXPECT_FALSE(StartCollectingThreatDetails(web_contents));
+ EXPECT_FALSE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_TRUE(data_collectors_map().empty());
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -182,9 +223,11 @@ TEST_F(TriggerManagerTest, NoDataCollection_IncognitoAndSBEROptInDisallowed) {
// not allowed to opt-in to SBER and is also incognito.
SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, false);
content::WebContents* web_contents = CreateIncognitoWebContents();
- EXPECT_FALSE(StartCollectingThreatDetails(web_contents));
+ EXPECT_FALSE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_TRUE(data_collectors_map().empty());
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -193,9 +236,11 @@ TEST_F(TriggerManagerTest, UserOptedOutOfSBER_DataCollected_NoReportSent) {
// report will be sent when data collection ends.
SetPref(prefs::kSafeBrowsingScoutReportingEnabled, false);
content::WebContents* web_contents = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -204,12 +249,14 @@ TEST_F(TriggerManagerTest, UserOptsOutOfSBER_DataCollected_NoReportSent) {
// then no report is sent. Note that the test fixture opts the user into
// Extended Reporting by default.
content::WebContents* web_contents = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
SetPref(prefs::kSafeBrowsingScoutReportingEnabled, false);
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -219,12 +266,14 @@ TEST_F(TriggerManagerTest, UserOptsInToSBER_DataCollected_ReportSent) {
// also be sent.
SetPref(prefs::kSafeBrowsingScoutReportingEnabled, false);
content::WebContents* web_contents = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
SetPref(prefs::kSafeBrowsingScoutReportingEnabled, true);
- EXPECT_TRUE(FinishCollectingThreatDetails(web_contents, true));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, true));
EXPECT_TRUE(data_collectors_map().empty());
}
@@ -233,13 +282,88 @@ TEST_F(TriggerManagerTest,
// If the user loses the ability to opt-in to SBER in the middle of data
// collection then the report will not be sent.
content::WebContents* web_contents = CreateWebContents();
- EXPECT_TRUE(StartCollectingThreatDetails(web_contents));
+ EXPECT_TRUE(StartCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents));
EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
// Remove the ability to opt-in to SBER.
SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, false);
- EXPECT_FALSE(FinishCollectingThreatDetails(web_contents, false));
+ EXPECT_FALSE(FinishCollectingThreatDetails(TriggerType::SECURITY_INTERSTITIAL,
+ web_contents, false));
+ EXPECT_TRUE(data_collectors_map().empty());
+}
+
+TEST_F(TriggerManagerTest, NoCollectionWhenOutOfQuota) {
+ // Triggers are not allowed to collect data when they're out of quota, even if
+ // all other conditions are as expected.
+ content::WebContents* web_contents = CreateWebContents();
+
+ // Turn on the AD_SAMPLE trigger inside the throttler and confirm that it can
+ // fire normally.
+ SetTriggerHasQuota(TriggerType::AD_SAMPLE, true);
+ EXPECT_TRUE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents, true));
+ EXPECT_TRUE(data_collectors_map().empty());
+
+ // Turn off the AD_SAMPLE trigger inside the throttler, the trigger should no
+ // longer be able to fire.
+ SetTriggerHasQuota(TriggerType::AD_SAMPLE, false);
+ EXPECT_FALSE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
EXPECT_TRUE(data_collectors_map().empty());
}
+
+TEST_F(TriggerManagerTest, AdSamplerTrigger) {
+ // Check the conditions required for the Ad Sampler trigger to fire. It needs
+ // opt-in to start collecting data, scout opt-in, and quota.
+ content::WebContents* web_contents = CreateWebContents();
+
+ // The default setup in this test makes the trigger fire (all prefs enabled,
+ // all triggers have quota).
+ EXPECT_TRUE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ EXPECT_THAT(data_collectors_map(), UnorderedElementsAre(Key(web_contents)));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents, true));
+ EXPECT_TRUE(data_collectors_map().empty());
+
+ // Disabling SBEROptInAllowed disables this trigger.
+ SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, false);
+ EXPECT_FALSE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ // Confirm it can fire when we re-enable SBEROptInAllowed
+ SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
+ EXPECT_TRUE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents, true));
+
+ // Disabling Scout disables this trigger even if the legacy SBER is enabled.
+ SetPref(prefs::kSafeBrowsingScoutReportingEnabled, false);
+ SetPref(prefs::kSafeBrowsingExtendedReportingEnabled, true);
+ EXPECT_FALSE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ // Confirm it can fire when we re-enable Scout and disable legacy SBER.
+ SetPref(prefs::kSafeBrowsingScoutReportingEnabled, true);
+ SetPref(prefs::kSafeBrowsingExtendedReportingEnabled, false);
+ EXPECT_TRUE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents, true));
+
+ // Finally, make sure the trigger can't fire if it has no quota.
+ SetTriggerHasQuota(TriggerType::AD_SAMPLE, false);
+ EXPECT_FALSE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ // Confirm it can fire again when quota is available.
+ SetTriggerHasQuota(TriggerType::AD_SAMPLE, true);
+ EXPECT_TRUE(
+ StartCollectingThreatDetails(TriggerType::AD_SAMPLE, web_contents));
+ EXPECT_TRUE(FinishCollectingThreatDetails(TriggerType::AD_SAMPLE,
+ web_contents, true));
+}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler.cc b/chromium/components/safe_browsing/triggers/trigger_throttler.cc
index cb00346e4c3..bc558545be8 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler.cc
@@ -4,33 +4,114 @@
#include "components/safe_browsing/triggers/trigger_throttler.h"
+#include "base/metrics/field_trial_params.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/time/default_clock.h"
#include "base/time/time.h"
+#include "components/safe_browsing/features.h"
namespace safe_browsing {
+const char kTriggerTypeAndQuotaParam[] = "trigger_type_and_quota_csv";
namespace {
const size_t kUnlimitedTriggerQuota = std::numeric_limits<size_t>::max();
constexpr base::TimeDelta kOneDayTimeDelta = base::TimeDelta::FromDays(1);
-size_t GetDailyQuotaForTrigger(const TriggerType trigger_type) {
+// Predicate used to search |trigger_type_and_quota_list_| by trigger type.
+class TriggerTypeIs {
+ public:
+ explicit TriggerTypeIs(const TriggerType type) : type_(type) {}
+ bool operator()(const TriggerTypeAndQuotaItem& trigger_type_and_quota) {
+ return type_ == trigger_type_and_quota.first;
+ }
+
+ private:
+ TriggerType type_;
+};
+
+void ParseTriggerTypeAndQuotaParam(
+ std::vector<TriggerTypeAndQuotaItem>* trigger_type_and_quota_list) {
+ DCHECK(trigger_type_and_quota_list);
+ // If the feature is disabled we just use the default list. Otherwise the list
+ // from the Finch param will be the one used.
+ if (!base::FeatureList::IsEnabled(kTriggerThrottlerDailyQuotaFeature)) {
+ return;
+ }
+
+ trigger_type_and_quota_list->clear();
+ const std::string& trigger_and_quota_csv_param =
+ base::GetFieldTrialParamValueByFeature(kTriggerThrottlerDailyQuotaFeature,
+ kTriggerTypeAndQuotaParam);
+ if (trigger_and_quota_csv_param.empty()) {
+ return;
+ }
+
+ std::vector<std::string> split =
+ base::SplitString(trigger_and_quota_csv_param, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ // If we don't have the right number of pairs in the csv then don't bother
+ // parsing further.
+ if (split.size() % 2 != 0) {
+ return;
+ }
+ for (size_t i = 0; i < split.size(); i += 2) {
+ // Make sure both the trigger type and quota are integers. Skip them if not.
+ int trigger_type_int = -1;
+ int quota_int = -1;
+ if (!base::StringToInt(split[i], &trigger_type_int) ||
+ !base::StringToInt(split[i + 1], &quota_int)) {
+ continue;
+ }
+ trigger_type_and_quota_list->push_back(
+ std::make_pair(static_cast<TriggerType>(trigger_type_int), quota_int));
+ }
+
+ std::sort(trigger_type_and_quota_list->begin(),
+ trigger_type_and_quota_list->end(),
+ [](const TriggerTypeAndQuotaItem& a,
+ const TriggerTypeAndQuotaItem& b) { return a.first < b.first; });
+}
+
+size_t GetDailyQuotaForTrigger(
+ const TriggerType trigger_type,
+ const std::vector<TriggerTypeAndQuotaItem>& trigger_quota_list) {
switch (trigger_type) {
case TriggerType::SECURITY_INTERSTITIAL:
return kUnlimitedTriggerQuota;
+ case TriggerType::AD_SAMPLE:
+ // These triggers have quota configured via Finch, lookup the value in
+ // |trigger_quota_list|.
+ const auto& trigger_quota_iter =
+ std::find_if(trigger_quota_list.begin(), trigger_quota_list.end(),
+ TriggerTypeIs(trigger_type));
+ if (trigger_quota_iter != trigger_quota_list.end())
+ return trigger_quota_iter->second;
+
+ break;
}
- // By default, unhandled trigger types have no quota.
+ // By default, unhandled or unconfigured trigger types have no quota.
return 0;
}
} // namespace
-TriggerThrottler::TriggerThrottler() {}
+TriggerThrottler::TriggerThrottler() : clock_(new base::DefaultClock()) {
+ ParseTriggerTypeAndQuotaParam(&trigger_type_and_quota_list_);
+}
TriggerThrottler::~TriggerThrottler() {}
+void TriggerThrottler::SetClockForTesting(
+ std::unique_ptr<base::Clock> test_clock) {
+ clock_ = std::move(test_clock);
+}
+
bool TriggerThrottler::TriggerCanFire(const TriggerType trigger_type) const {
// Lookup how many times this trigger is allowed to fire each day.
- const size_t trigger_quota = GetDailyQuotaForTrigger(trigger_type);
+ const size_t trigger_quota =
+ GetDailyQuotaForTrigger(trigger_type, trigger_type_and_quota_list_);
// Some basic corner cases for triggers that always fire, or disabled
// triggers that never fire.
@@ -49,18 +130,19 @@ bool TriggerThrottler::TriggerCanFire(const TriggerType trigger_type) const {
if (trigger_quota > timestamps.size())
return true;
- // Otherwise, we have more events than quota, check which day they occured on.
- // Newest events are at the end of vector so we can simply look at the
+ // Otherwise, we have more events than quota, check which day they occurred
+ // on. Newest events are at the end of vector so we can simply look at the
// Nth-from-last entry (where N is the quota) to see if it happened within
// the current day or earlier.
- base::Time min_timestamp = base::Time::Now() - kOneDayTimeDelta;
+ base::Time min_timestamp = clock_->Now() - kOneDayTimeDelta;
const size_t pos = timestamps.size() - trigger_quota + 1;
return timestamps[pos] < min_timestamp.ToTimeT();
}
void TriggerThrottler::TriggerFired(const TriggerType trigger_type) {
// Lookup how many times this trigger is allowed to fire each day.
- const size_t trigger_quota = GetDailyQuotaForTrigger(trigger_type);
+ const size_t trigger_quota =
+ GetDailyQuotaForTrigger(trigger_type, trigger_type_and_quota_list_);
// For triggers that always fire, don't bother tracking quota.
if (trigger_quota == kUnlimitedTriggerQuota)
@@ -68,7 +150,7 @@ void TriggerThrottler::TriggerFired(const TriggerType trigger_type) {
// Otherwise, record that the trigger fired.
std::vector<time_t>* timestamps = &trigger_events_[trigger_type];
- timestamps->push_back(base::Time::Now().ToTimeT());
+ timestamps->push_back(clock_->Now().ToTimeT());
// Clean up the trigger events map.
CleanupOldEvents();
@@ -77,7 +159,8 @@ void TriggerThrottler::TriggerFired(const TriggerType trigger_type) {
void TriggerThrottler::CleanupOldEvents() {
for (const auto& map_iter : trigger_events_) {
const TriggerType trigger_type = map_iter.first;
- const size_t trigger_quota = GetDailyQuotaForTrigger(trigger_type);
+ const size_t trigger_quota =
+ GetDailyQuotaForTrigger(trigger_type, trigger_type_and_quota_list_);
const std::vector<time_t>& trigger_times = map_iter.second;
// Skip the cleanup if we have quota room, quotas should generally be small.
@@ -85,7 +168,7 @@ void TriggerThrottler::CleanupOldEvents() {
return;
std::vector<time_t> tmp_trigger_times;
- base::Time min_timestamp = base::Time::Now() - kOneDayTimeDelta;
+ base::Time min_timestamp = clock_->Now() - kOneDayTimeDelta;
// Go over the event times for this trigger and keep timestamps which are
// newer than |min_timestamp|. We put timestamps in a temp vector that will
// get swapped into the map in place of the existing vector.
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler.h b/chromium/components/safe_browsing/triggers/trigger_throttler.h
index 33b588a2983..f4746d7d4ae 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler.h
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler.h
@@ -5,16 +5,22 @@
#ifndef COMPONENTS_SAFE_BROWSING_TRIGGERS_TRIGGER_THROTTLER_H_
#define COMPONENTS_SAFE_BROWSING_TRIGGERS_TRIGGER_THROTTLER_H_
+#include <memory>
#include <unordered_map>
#include <vector>
#include "base/macros.h"
-#include "base/time/time.h"
+#include "base/time/clock.h"
namespace safe_browsing {
+// Param name of the finch param containing the comma-separated list of trigger
+// types and daily quotas.
+extern const char kTriggerTypeAndQuotaParam[];
+
enum class TriggerType {
SECURITY_INTERSTITIAL = 1,
+ AD_SAMPLE = 2,
};
struct TriggerTypeHash {
@@ -27,6 +33,9 @@ struct TriggerTypeHash {
using TriggerTimestampMap =
std::unordered_map<TriggerType, std::vector<time_t>, TriggerTypeHash>;
+// A pair containing a TriggerType and its associated daily report quota.
+using TriggerTypeAndQuotaItem = std::pair<TriggerType, int>;
+
// TriggerThrottler keeps track of how often each type of trigger gets fired
// and throttles them if they fire too often.
class TriggerThrottler {
@@ -36,20 +45,32 @@ class TriggerThrottler {
// Check if the the specified |trigger_type| has quota available and is
// allowed to fire at this time.
- bool TriggerCanFire(const TriggerType trigger_type) const;
+ virtual bool TriggerCanFire(TriggerType trigger_type) const;
// Called to notify the throttler that a trigger has just fired and quota
// should be updated.
- void TriggerFired(const TriggerType trigger_type);
+ void TriggerFired(TriggerType trigger_type);
+
+ protected:
+ void SetClockForTesting(std::unique_ptr<base::Clock> test_clock);
private:
+ friend class TriggerThrottlerTest;
+
// Called to periodically clean-up the list of event timestamps.
void CleanupOldEvents();
+ // Can be set for testing.
+ std::unique_ptr<base::Clock> clock_;
+
// Stores each trigger type that fired along with the timestamps of when it
// fired.
TriggerTimestampMap trigger_events_;
+ // List of trigger types and their quotas, controlled by Finch feature
+ // |kTriggerThrottlerDailyQuotaFeature|.
+ std::vector<TriggerTypeAndQuotaItem> trigger_type_and_quota_list_;
+
DISALLOW_COPY_AND_ASSIGN(TriggerThrottler);
};
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc b/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
index 1b01e7295d4..b489bb19211 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
@@ -4,19 +4,154 @@
#include "components/safe_browsing/triggers/trigger_throttler.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
+#include "components/safe_browsing/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::ElementsAre;
+
namespace safe_browsing {
-namespace {
-TEST(TriggerThrottler, SecurityInterstitialsHaveUnlimitedQuota) {
+class TriggerThrottlerTest : public ::testing::Test {
+ public:
+ void SetQuotaForTriggerType(TriggerType trigger_type, size_t max_quota) {
+ trigger_throttler_.trigger_type_and_quota_list_.push_back(
+ std::make_pair(trigger_type, max_quota));
+ }
+
+ TriggerThrottler* throttler() { return &trigger_throttler_; }
+
+ void SetTestClock(base::Clock* clock) {
+ trigger_throttler_.SetClockForTesting(base::WrapUnique(clock));
+ }
+
+ std::vector<time_t> GetEventTimestampsForTriggerType(
+ TriggerType trigger_type) {
+ return trigger_throttler_.trigger_events_[trigger_type];
+ }
+
+ private:
+ TriggerThrottler trigger_throttler_;
+};
+
+TEST_F(TriggerThrottlerTest, SecurityInterstitialsHaveUnlimitedQuota) {
// Make sure that security interstitials never run out of quota.
- TriggerThrottler throttler;
for (int i = 0; i < 1000; ++i) {
- throttler.TriggerFired(TriggerType::SECURITY_INTERSTITIAL);
- EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::SECURITY_INTERSTITIAL));
+ throttler()->TriggerFired(TriggerType::SECURITY_INTERSTITIAL);
+ EXPECT_TRUE(
+ throttler()->TriggerCanFire(TriggerType::SECURITY_INTERSTITIAL));
+ }
+}
+
+TEST_F(TriggerThrottlerTest, SecurityInterstitialQuotaCanNotBeOverwritten) {
+ // Make sure that security interstitials never run out of quota, even if we
+ // try to configure quota for this trigger type.
+ SetQuotaForTriggerType(TriggerType::SECURITY_INTERSTITIAL, 3);
+ for (int i = 0; i < 1000; ++i) {
+ throttler()->TriggerFired(TriggerType::SECURITY_INTERSTITIAL);
+ EXPECT_TRUE(
+ throttler()->TriggerCanFire(TriggerType::SECURITY_INTERSTITIAL));
}
}
-} // namespace
+TEST_F(TriggerThrottlerTest, TriggerExceedsQuota) {
+ // Ensure that a trigger can't fire more than its quota allows.
+ SetQuotaForTriggerType(TriggerType::AD_SAMPLE, 2);
+
+ // First two triggers should work
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+
+ // Third attempt will fail since we're out of quota.
+ EXPECT_FALSE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+}
+
+TEST_F(TriggerThrottlerTest, TriggerQuotaResetsAfterOneDay) {
+ // Ensure that trigger events older than a day are cleaned up and triggers can
+ // resume firing.
+
+ // We initialize the test clock to several days ago and fire some events to
+ // use up quota. We then advance the clock by a day and ensure quota is
+ // available again.
+ base::SimpleTestClock* test_clock(new base::SimpleTestClock);
+ test_clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(10));
+ time_t base_ts = test_clock->Now().ToTimeT();
+
+ SetTestClock(test_clock);
+ SetQuotaForTriggerType(TriggerType::AD_SAMPLE, 2);
+
+ // First two triggers should work
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+
+ // Third attempt will fail since we're out of quota.
+ EXPECT_FALSE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+
+ // Also confirm that the throttler contains two event timestamps for the above
+ // two events - since we use a test clock, it doesn't move unless we tell it
+ // to.
+ EXPECT_THAT(GetEventTimestampsForTriggerType(TriggerType::AD_SAMPLE),
+ ElementsAre(base_ts, base_ts));
+
+ // Move the clock forward by 1 day (and a bit) and try the trigger again,
+ // quota should be available now.
+ test_clock->Advance(base::TimeDelta::FromDays(1) +
+ base::TimeDelta::FromSeconds(1));
+ time_t advanced_ts = test_clock->Now().ToTimeT();
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+
+ // The previous time stamps should remain in the throttler.
+ EXPECT_THAT(GetEventTimestampsForTriggerType(TriggerType::AD_SAMPLE),
+ ElementsAre(base_ts, base_ts));
+
+ // Firing the trigger will clean up the expired timestamps and insert the new
+ // timestamp.
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ EXPECT_THAT(GetEventTimestampsForTriggerType(TriggerType::AD_SAMPLE),
+ ElementsAre(advanced_ts));
+}
+
+TEST(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) {
+ // Make sure that setting the quota param via Finch params works as expected.
+ base::FieldTrialList field_trial_list(nullptr);
+ base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
+ safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, "Group");
+ std::map<std::string, std::string> feature_params;
+ feature_params[std::string(safe_browsing::kTriggerTypeAndQuotaParam)] =
+ base::StringPrintf("%d,%d", TriggerType::AD_SAMPLE, 3);
+ base::AssociateFieldTrialParams(
+ safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, "Group",
+ feature_params);
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(
+ safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, std::string());
+ feature_list->AssociateReportingFieldTrial(
+ safe_browsing::kTriggerThrottlerDailyQuotaFeature.name,
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ // The throttler has been configured (above) to allow ad samples to fire three
+ // times per day.
+ TriggerThrottler throttler;
+
+ // First three triggers should work
+ EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler.TriggerFired(TriggerType::AD_SAMPLE);
+ EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler.TriggerFired(TriggerType::AD_SAMPLE);
+ EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
+ throttler.TriggerFired(TriggerType::AD_SAMPLE);
+
+ // Fourth attempt will fail since we're out of quota.
+ EXPECT_FALSE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
+}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/web_ui/BUILD.gn b/chromium/components/safe_browsing/web_ui/BUILD.gn
index d695729c39b..7bd2a139242 100644
--- a/chromium/components/safe_browsing/web_ui/BUILD.gn
+++ b/chromium/components/safe_browsing/web_ui/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("//third_party/protobuf/proto_library.gni")
+
static_library("web_ui") {
sources = [
"safe_browsing_ui.cc",
@@ -14,7 +16,9 @@ static_library("web_ui") {
"//components/resources:components_resources_grit",
"//components/resources:components_scaled_resources_grit",
"//components/safe_browsing:features",
+ "//components/safe_browsing:webui_proto",
"//components/safe_browsing/common:safe_browsing_prefs",
+ "//components/safe_browsing_db:v4_local_database_manager",
"//components/strings:components_strings_grit",
"//components/user_prefs:user_prefs",
"//content/public/browser",
diff --git a/chromium/components/safe_browsing/web_ui/DEPS b/chromium/components/safe_browsing/web_ui/DEPS
index 09eb5158069..1403bfc83db 100644
--- a/chromium/components/safe_browsing/web_ui/DEPS
+++ b/chromium/components/safe_browsing/web_ui/DEPS
@@ -2,5 +2,6 @@ include_rules = [
"+components/grit/components_resources.h",
"+components/user_prefs",
"+components/strings/grit/components_strings.h",
- "+components/grit/components_scaled_resources.h"
+ "+components/grit/components_scaled_resources.h",
+ "+components/safe_browsing_db",
]
diff --git a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.css b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.css
index 6f8f80b504d..5fe64a5f6bb 100644
--- a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.css
+++ b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.css
@@ -9,18 +9,18 @@ body {
p {
white-space: pre-wrap;
}
-.sbPageContent {
+.content {
background-color: #fbfbfb;
border: 1px solid #cecece;
border-radius: 3px;
padding: 19px;
line-height: 1.5;
}
-#sbTitle {
+#sb-title {
font-size: 2em;
margin-bottom: 0.8em;
}
h1, h2, h3, p {
font-weight: normal;
- line-height: 1;
+ line-height: 1.5;
}
diff --git a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.html b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.html
index bf5863f70e4..fe60658a331 100644
--- a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.html
+++ b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.html
@@ -13,16 +13,24 @@
</head>
<body>
<div id="header">
- <h1 id="sbTitle">Safe Browsing</h1>
+ <h1 id="sb-title">Safe Browsing</h1>
</div>
<p>$i18n{sbUnderConstruction}</p>
<h2>Experiments</h2>
- <div class="sbPageContent">
- <p id="experimentsList"></p>
+ <div class="content">
+ <p id="experiments-list"></p>
</div>
<h2>Preferences</h2>
- <div class="sbPageContent">
- <p id="preferencesList"></p>
+ <div class="content">
+ <p id="preferences-list"></p>
+ </div>
+ <h2>Database Manager</h2>
+ <div class="content">
+ <p id="database-info-list"></p>
+ </div>
+ <h2>Full Hash Cache</h2>
+ <div class="content">
+ <p id="full-hash-cache-info"></p>
</div>
<script src="chrome://resources/js/i18n_template.js"></script>
</body>
diff --git a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.js b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.js
index f7ed029e3c9..8c203f7adfd 100644
--- a/chromium/components/safe_browsing/web_ui/resources/safe_browsing.js
+++ b/chromium/components/safe_browsing/web_ui/resources/safe_browsing.js
@@ -13,10 +13,14 @@ cr.define('safe_browsing', function() {
function initialize() {
cr.sendWithPromise('getExperiments', []).then((experiments) =>
addExperiments(experiments));
- cr.sendWithPromise('getPrefs', []).then(
- prefs=>addPrefs(prefs));
- }
-
+ cr.sendWithPromise('getPrefs', []).then((prefs) => addPrefs(prefs));
+ cr.sendWithPromise('getDatabaseManagerInfo', []).then(
+ function(databaseState) {
+ var fullHashCacheState = databaseState.splice(-1,1);
+ addDatabaseManagerInfo(databaseState);
+ addFullHashCacheInfo(fullHashCacheState);
+ });
+}
function addExperiments(result) {
var resLength = result.length;
var experimentsListFormatted = "";
@@ -25,8 +29,7 @@ cr.define('safe_browsing', function() {
experimentsListFormatted += "<div><b>" + result[i + 1] +
"</b>: " + result[i] + "</div>";
}
-
- $('experimentsList').innerHTML = experimentsListFormatted;
+ $('experiments-list').innerHTML = experimentsListFormatted;
}
function addPrefs(result) {
@@ -37,7 +40,22 @@ cr.define('safe_browsing', function() {
preferencesListFormatted += "<div><b>" + result[i + 1] + "</b>: " +
result[i] + "</div>";
}
- $('preferencesList').innerHTML = preferencesListFormatted;
+ $('preferences-list').innerHTML = preferencesListFormatted;
+ }
+
+ function addDatabaseManagerInfo(result) {
+ var resLength = result.length;
+ var preferencesListFormatted = "";
+
+ for (var i = 0; i < resLength; i += 2) {
+ preferencesListFormatted += "<div><b>" + result[i] + "</b>: " +
+ result[i+1] + "</div>";
+ }
+ $('database-info-list').innerHTML = preferencesListFormatted;
+ }
+
+ function addFullHashCacheInfo(result) {
+ $('full-hash-cache-info').innerHTML = result;
}
return {
diff --git a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
index dcc522f6ecd..2cc2964b9be 100644
--- a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -4,6 +4,16 @@
#include "components/safe_browsing/web_ui/safe_browsing_ui.h"
+#include <stddef.h>
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/base64url.h"
+#include "base/i18n/time_formatting.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "components/grit/components_resources.h"
#include "components/grit/components_scaled_resources.h"
@@ -14,7 +24,179 @@
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
+#if SAFE_BROWSING_DB_LOCAL
+#include "components/safe_browsing_db/v4_local_database_manager.h"
+#endif
+
+using base::Time;
+
namespace safe_browsing {
+namespace {
+#if SAFE_BROWSING_DB_LOCAL
+
+base::Value UserReadableTimeFromMillisSinceEpoch(int64_t time_in_milliseconds) {
+ base::Time time = base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds(time_in_milliseconds);
+ return base::Value(
+ base::UTF16ToASCII(base::TimeFormatShortDateAndTime(time)));
+}
+
+void AddStoreInfo(const DatabaseManagerInfo::DatabaseInfo::StoreInfo store_info,
+ base::ListValue* database_info_list) {
+ if (store_info.has_file_size_bytes() && store_info.has_file_name()) {
+ database_info_list->GetList().push_back(
+ base::Value(store_info.file_name()));
+ database_info_list->GetList().push_back(
+ base::Value(static_cast<double>(store_info.file_size_bytes())));
+ }
+ if (store_info.has_update_status()) {
+ database_info_list->GetList().push_back(base::Value("Store update status"));
+ database_info_list->GetList().push_back(
+ base::Value(store_info.update_status()));
+ }
+ if (store_info.has_last_apply_update_time_millis()) {
+ database_info_list->GetList().push_back(base::Value("Last update time"));
+ database_info_list->GetList().push_back(
+ UserReadableTimeFromMillisSinceEpoch(
+ store_info.last_apply_update_time_millis()));
+ }
+ if (store_info.has_checks_attempted()) {
+ database_info_list->GetList().push_back(
+ base::Value("Number of database checks"));
+ database_info_list->GetList().push_back(
+ base::Value(static_cast<int>(store_info.checks_attempted())));
+ }
+}
+
+void AddDatabaseInfo(const DatabaseManagerInfo::DatabaseInfo database_info,
+ base::ListValue* database_info_list) {
+ if (database_info.has_database_size_bytes()) {
+ database_info_list->GetList().push_back(
+ base::Value("Database size in bytes"));
+ database_info_list->GetList().push_back(
+ base::Value(static_cast<double>(database_info.database_size_bytes())));
+ }
+
+ // Add the information specific to each store.
+ for (int i = 0; i < database_info.store_info_size(); i++) {
+ AddStoreInfo(database_info.store_info(i), database_info_list);
+ }
+}
+
+void AddUpdateInfo(const DatabaseManagerInfo::UpdateInfo update_info,
+ base::ListValue* database_info_list) {
+ if (update_info.has_network_status_code()) {
+ // Network status of the last GetUpdate().
+ database_info_list->GetList().push_back(
+ base::Value("Last update network status code"));
+ database_info_list->GetList().push_back(
+ base::Value(update_info.network_status_code()));
+ }
+ if (update_info.has_last_update_time_millis()) {
+ database_info_list->GetList().push_back(base::Value("Last update time"));
+ database_info_list->GetList().push_back(
+ UserReadableTimeFromMillisSinceEpoch(
+ update_info.last_update_time_millis()));
+ }
+}
+
+void ParseFullHashInfo(
+ const FullHashCacheInfo::FullHashCache::CachedHashPrefixInfo::FullHashInfo
+ full_hash_info,
+ base::DictionaryValue* full_hash_info_dict) {
+ if (full_hash_info.has_positive_expiry()) {
+ full_hash_info_dict->SetString(
+ "Positive expiry",
+ UserReadableTimeFromMillisSinceEpoch(full_hash_info.positive_expiry())
+ .GetString());
+ }
+ if (full_hash_info.has_full_hash()) {
+ std::string full_hash;
+ base::Base64UrlEncode(full_hash_info.full_hash(),
+ base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &full_hash);
+ full_hash_info_dict->SetString("Full hash (base64)", full_hash);
+ }
+ if (full_hash_info.list_identifier().has_platform_type()) {
+ full_hash_info_dict->SetInteger(
+ "platform_type", full_hash_info.list_identifier().platform_type());
+ }
+ if (full_hash_info.list_identifier().has_threat_entry_type()) {
+ full_hash_info_dict->SetInteger(
+ "threat_entry_type",
+ full_hash_info.list_identifier().threat_entry_type());
+ }
+ if (full_hash_info.list_identifier().has_threat_type()) {
+ full_hash_info_dict->SetInteger(
+ "threat_type", full_hash_info.list_identifier().threat_type());
+ }
+}
+
+void ParseFullHashCache(const FullHashCacheInfo::FullHashCache full_hash_cache,
+ base::ListValue* full_hash_cache_list) {
+ base::DictionaryValue full_hash_cache_parsed;
+
+ if (full_hash_cache.has_hash_prefix()) {
+ std::string hash_prefix;
+ base::Base64UrlEncode(full_hash_cache.hash_prefix(),
+ base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &hash_prefix);
+ full_hash_cache_parsed.SetString("Hash prefix (base64)", hash_prefix);
+ }
+ if (full_hash_cache.cached_hash_prefix_info().has_negative_expiry()) {
+ full_hash_cache_parsed.SetString(
+ "Negative expiry",
+ UserReadableTimeFromMillisSinceEpoch(
+ full_hash_cache.cached_hash_prefix_info().negative_expiry())
+ .GetString());
+ }
+
+ full_hash_cache_list->GetList().push_back(std::move(full_hash_cache_parsed));
+
+ for (auto full_hash_info_it :
+ full_hash_cache.cached_hash_prefix_info().full_hash_info()) {
+ base::DictionaryValue full_hash_info_dict;
+ ParseFullHashInfo(full_hash_info_it, &full_hash_info_dict);
+ full_hash_cache_list->GetList().push_back(std::move(full_hash_info_dict));
+ }
+}
+
+void ParseFullHashCacheInfo(const FullHashCacheInfo full_hash_cache_info_proto,
+ base::ListValue* full_hash_cache_info) {
+ if (full_hash_cache_info_proto.has_number_of_hits()) {
+ base::DictionaryValue number_of_hits;
+ number_of_hits.SetInteger("Number of cache hits",
+ full_hash_cache_info_proto.number_of_hits());
+ full_hash_cache_info->GetList().push_back(std::move(number_of_hits));
+ }
+
+ // Record FullHashCache list.
+ for (auto full_hash_cache_it : full_hash_cache_info_proto.full_hash_cache()) {
+ base::ListValue full_hash_cache_list;
+ ParseFullHashCache(full_hash_cache_it, &full_hash_cache_list);
+ full_hash_cache_info->GetList().push_back(std::move(full_hash_cache_list));
+ }
+}
+
+std::string AddFullHashCacheInfo(
+ const FullHashCacheInfo full_hash_cache_info_proto) {
+ std::string full_hash_cache_parsed;
+
+ base::ListValue full_hash_cache;
+ ParseFullHashCacheInfo(full_hash_cache_info_proto, &full_hash_cache);
+
+ base::Value* full_hash_cache_tree = &full_hash_cache;
+
+ JSONStringValueSerializer serializer(&full_hash_cache_parsed);
+ serializer.set_pretty_print(true);
+ serializer.Serialize(*full_hash_cache_tree);
+
+ return full_hash_cache_parsed;
+}
+
+#endif
+
+} // namespace
SafeBrowsingUI::SafeBrowsingUI(content::WebUI* web_ui)
: content::WebUIController(web_ui) {
@@ -48,6 +230,8 @@ SafeBrowsingUI::~SafeBrowsingUI() {}
SafeBrowsingUIHandler::SafeBrowsingUIHandler(content::BrowserContext* context)
: browser_context_(context) {}
+SafeBrowsingUIHandler::~SafeBrowsingUIHandler() = default;
+
void SafeBrowsingUIHandler::GetExperiments(const base::ListValue* args) {
AllowJavascript();
std::string callback_id;
@@ -63,7 +247,41 @@ void SafeBrowsingUIHandler::GetPrefs(const base::ListValue* args) {
safe_browsing::GetSafeBrowsingPreferencesList(
user_prefs::UserPrefs::Get(browser_context_)));
}
-SafeBrowsingUIHandler::~SafeBrowsingUIHandler() {}
+
+void SafeBrowsingUIHandler::GetDatabaseManagerInfo(
+ const base::ListValue* args) {
+ base::ListValue database_manager_info;
+
+#if SAFE_BROWSING_DB_LOCAL
+ const V4LocalDatabaseManager* local_database_manager_instance =
+ V4LocalDatabaseManager::current_local_database_manager();
+ if (local_database_manager_instance) {
+ DatabaseManagerInfo database_manager_info_proto;
+ FullHashCacheInfo full_hash_cache_info_proto;
+
+ local_database_manager_instance->CollectDatabaseManagerInfo(
+ &database_manager_info_proto, &full_hash_cache_info_proto);
+
+ if (database_manager_info_proto.has_update_info()) {
+ AddUpdateInfo(database_manager_info_proto.update_info(),
+ &database_manager_info);
+ }
+ if (database_manager_info_proto.has_database_info()) {
+ AddDatabaseInfo(database_manager_info_proto.database_info(),
+ &database_manager_info);
+ }
+
+ database_manager_info.GetList().push_back(
+ base::Value(AddFullHashCacheInfo(full_hash_cache_info_proto)));
+ }
+#endif
+
+ AllowJavascript();
+ std::string callback_id;
+ args->GetString(0, &callback_id);
+
+ ResolveJavascriptCallback(base::Value(callback_id), database_manager_info);
+}
void SafeBrowsingUIHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
@@ -72,6 +290,10 @@ void SafeBrowsingUIHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"getPrefs",
base::Bind(&SafeBrowsingUIHandler::GetPrefs, base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "getDatabaseManagerInfo",
+ base::Bind(&SafeBrowsingUIHandler::GetDatabaseManagerInfo,
+ base::Unretained(this)));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.h b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.h
index 632b82dc1cd..54fef1ec6e8 100644
--- a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.h
+++ b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SAFE_BROWSING_WEBUI_SAFE_BROWSING_UI_H_
#include "base/macros.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
@@ -20,8 +21,11 @@ class SafeBrowsingUIHandler : public content::WebUIMessageHandler {
public:
SafeBrowsingUIHandler(content::BrowserContext*);
~SafeBrowsingUIHandler() override;
+
void GetExperiments(const base::ListValue* args);
void GetPrefs(const base::ListValue* args);
+ void GetDatabaseManagerInfo(const base::ListValue* args);
+
void RegisterMessages() override;
private:
diff --git a/chromium/components/safe_browsing_db/BUILD.gn b/chromium/components/safe_browsing_db/BUILD.gn
index c3f376dcbeb..bf1ea05d921 100644
--- a/chromium/components/safe_browsing_db/BUILD.gn
+++ b/chromium/components/safe_browsing_db/BUILD.gn
@@ -46,16 +46,6 @@ group("safe_browsing_db") {
]
}
-# This target is for the mobile version.
-group("safe_browsing_db_mobile") {
- deps = [
- ":remote_database_manager",
- ":safe_browsing_api_handler",
- ":safe_browsing_api_handler_util",
- ":safe_browsing_db_shared",
- ]
-}
-
static_library("database_manager") {
sources = [
"database_manager.cc",
@@ -104,60 +94,6 @@ static_library("prefix_set") {
]
}
-static_library("remote_database_manager") {
- sources = [
- "remote_database_manager.cc",
- "remote_database_manager.h",
- ]
- deps = [
- ":database_manager",
- ":safe_browsing_api_handler",
- ":v4_get_hash_protocol_manager",
- ":v4_protocol_manager_util",
- "//base:base",
- "//components/variations",
- "//content/public/browser",
- "//net",
- "//url",
- ]
-}
-
-source_set("safe_browsing_api_handler") {
- sources = [
- "android/jni_registrar.cc",
- "android/jni_registrar.h",
- "safe_browsing_api_handler.cc",
- "safe_browsing_api_handler.h",
- ]
- deps = [
- ":safe_browsing_api_handler_util",
- ":util",
- "//base",
- "//content/public/browser:browser",
- "//url",
- ]
-
- if (is_android) {
- deps += [ "//components/safe_browsing_db/android:jni_headers" ]
- sources += [
- "android/safe_browsing_api_handler_bridge.cc",
- "android/safe_browsing_api_handler_bridge.h",
- ]
- }
-}
-
-static_library("safe_browsing_api_handler_util") {
- sources = [
- "safe_browsing_api_handler_util.cc",
- "safe_browsing_api_handler_util.h",
- ]
- deps = [
- ":metadata_proto",
- ":util",
- "//base",
- ]
-}
-
static_library("test_database_manager") {
sources = [
"test_database_manager.cc",
@@ -206,6 +142,7 @@ static_library("v4_database") {
":v4_protocol_manager_util",
":v4_store",
"//base",
+ "//components/safe_browsing:webui_proto",
"//content/public/browser",
]
}
@@ -234,6 +171,7 @@ static_library("v4_get_hash_protocol_manager") {
":v4_protocol_manager_util",
"//base",
"//components/data_use_measurement/core",
+ "//components/safe_browsing:webui_proto",
"//content/public/browser",
"//net",
"//url",
@@ -255,6 +193,7 @@ static_library("v4_local_database_manager") {
":v4_protocol_manager_util",
":v4_update_protocol_manager",
"//base",
+ "//components/safe_browsing:webui_proto",
"//content/public/browser",
"//net",
"//url",
@@ -309,6 +248,7 @@ source_set("v4_store") {
":v4_protocol_manager_util",
":v4_rice",
"//base",
+ "//components/safe_browsing:webui_proto",
"//crypto",
]
}
@@ -336,6 +276,7 @@ static_library("v4_update_protocol_manager") {
":v4_protocol_manager_util",
"//base",
"//components/data_use_measurement/core",
+ "//components/safe_browsing:webui_proto",
"//components/safe_browsing/common:safe_browsing_prefs",
"//net",
"//url",
@@ -484,32 +425,6 @@ source_set("unit_tests_desktop") {
}
}
-source_set("unit_tests_mobile") {
- testonly = true
- sources = [
- "remote_database_manager_unittest.cc",
- "safe_browsing_api_handler_unittest.cc",
- ]
- deps = [
- ":metadata_proto",
- ":remote_database_manager",
- ":safe_browsing_api_handler",
- ":safe_browsing_api_handler_util",
- ":unit_tests_shared",
- ":util",
- ":v4_test_util",
- "//base",
- "//components/variations",
- "//content/test:test_support",
- "//testing/gtest",
- "//url",
- ]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # Conversion from size_t to 'type'.
- }
-}
-
static_library("whitelist_checker_client") {
sources = [
"whitelist_checker_client.cc",
diff --git a/chromium/components/safe_browsing_db/DEPS b/chromium/components/safe_browsing_db/DEPS
index 341bbf0b8ca..ce3c7b9ff0e 100644
--- a/chromium/components/safe_browsing_db/DEPS
+++ b/chromium/components/safe_browsing_db/DEPS
@@ -1,7 +1,10 @@
include_rules = [
"+components/data_use_measurement/core",
"+components/safe_browsing/common/safe_browsing_prefs.h",
+ "+components/safe_browsing/db/safe_browsing_api_handler.h",
"+components/safe_browsing/features.h",
+ "+components/safe_browsing/proto/webui.pb.h",
+ "+components/safe_browsing/web_ui/webui.pb.h",
"+components/variations",
"+components/version_info",
"+content/public/browser",
@@ -9,7 +12,6 @@ include_rules = [
"+content/public/test",
"+crypto",
"+google_apis/google_api_keys.h",
- "+jni",
"+third_party/protobuf/src/google",
"+net",
]
diff --git a/chromium/components/safe_browsing_db/metadata.proto b/chromium/components/safe_browsing_db/metadata.proto
index 786bb9ed4cf..f17e2f54411 100644
--- a/chromium/components/safe_browsing_db/metadata.proto
+++ b/chromium/components/safe_browsing_db/metadata.proto
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This proto is deprecated, and is only used for PVer3.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
diff --git a/chromium/components/safe_browsing_db/notification_types.h b/chromium/components/safe_browsing_db/notification_types.h
new file mode 100644
index 00000000000..14826033224
--- /dev/null
+++ b/chromium/components/safe_browsing_db/notification_types.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
+#define COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
+
+// Lists of Safe Browsing related notifications, used with NotificationService.
+namespace safe_browsing {
+
+enum NotificationType {
+ NOTIFICATION_SAFE_BROWSING_START = 0,
+
+ // General -----------------------------------------------------------------
+
+ // Special signal value to represent an interest in all notifications.
+ // Not valid when posting a notification.
+ NOTIFICATION_ALL = NOTIFICATION_SAFE_BROWSING_START,
+
+ // A safe browsing database update completed. Source is the
+ // SafeBrowsingDatabaseManager and the details are none. It is posted on the
+ // UI thread.
+ NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
+
+ NOTIFICATION_SAFE_BROWSING_END
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
diff --git a/chromium/components/safe_browsing_db/util.h b/chromium/components/safe_browsing_db/util.h
index ff47d837205..43f4d24d411 100644
--- a/chromium/components/safe_browsing_db/util.h
+++ b/chromium/components/safe_browsing_db/util.h
@@ -32,6 +32,15 @@ enum class ThreatPatternType : int {
SOCIAL_ENGINEERING_LANDING = 4, // The match is a social engineering landing
// page
PHISHING = 5, // The match is a phishing page
+
+ // The match is a better ads standard violating page
+ SUBRESOURCE_FILTER_BETTER_ADS = 6,
+
+ // The match is an abusive ads violating page
+ SUBRESOURCE_FILTER_ABUSIVE_ADS = 7,
+
+ // The match violates both better ads standard and abusive policies
+ SUBRESOURCE_FILTER_ALL_ADS = 8,
THREAT_PATTERN_TYPE_MAX_VALUE
};
@@ -57,6 +66,10 @@ struct ThreatMetadata {
// Opaque base64 string used for user-population experiments in pver4.
// This will be empty if it wasn't present in the response.
std::string population_id;
+
+ // Used with threat type SUBRESOURCE_FILTER. Indicates that the site is only a
+ // match for experimental configurations.
+ bool experimental = false;
};
// A truncated hash's type.
diff --git a/chromium/components/safe_browsing_db/v4_database.cc b/chromium/components/safe_browsing_db/v4_database.cc
index fc23c9b68d2..f380624db9c 100644
--- a/chromium/components/safe_browsing_db/v4_database.cc
+++ b/chromium/components/safe_browsing_db/v4_database.cc
@@ -11,6 +11,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/v4_database.h"
#include "content/public/browser/browser_thread.h"
@@ -307,6 +308,21 @@ void V4Database::RecordFileSizeHistograms() {
UMA_HISTOGRAM_COUNTS(kV4DatabaseSizeMetric, db_size_kilobytes);
}
+void V4Database::CollectDatabaseInfo(
+ DatabaseManagerInfo::DatabaseInfo* database_info) {
+ // Records the database size in bytes.
+ int64_t db_size = 0;
+
+ for (const auto& store_map_iter : *store_map_) {
+ DatabaseManagerInfo::DatabaseInfo::StoreInfo* store_info =
+ database_info->add_store_info();
+ store_map_iter.second->CollectStoreInfo(store_info, kV4DatabaseSizeMetric);
+ db_size += store_info->file_size_bytes();
+ }
+
+ database_info->set_database_size_bytes(db_size);
+}
+
ListInfo::ListInfo(const bool fetch_updates,
const std::string& filename,
const ListIdentifier& list_id,
diff --git a/chromium/components/safe_browsing_db/v4_database.h b/chromium/components/safe_browsing_db/v4_database.h
index 0146830f08c..aea51b051a8 100644
--- a/chromium/components/safe_browsing_db/v4_database.h
+++ b/chromium/components/safe_browsing_db/v4_database.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/safe_browsing_db/v4_store.h"
@@ -163,6 +164,9 @@ class V4Database {
// with the combined size of all the stores.
void RecordFileSizeHistograms();
+ // Populates the DatabaseInfo message of the safe_browsing_page proto.
+ void CollectDatabaseInfo(DatabaseManagerInfo::DatabaseInfo* database_info);
+
protected:
V4Database(const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
std::unique_ptr<StoreMap> store_map);
diff --git a/chromium/components/safe_browsing_db/v4_feature_list.cc b/chromium/components/safe_browsing_db/v4_feature_list.cc
index 8185e6fc16d..1ae33462658 100644
--- a/chromium/components/safe_browsing_db/v4_feature_list.cc
+++ b/chromium/components/safe_browsing_db/v4_feature_list.cc
@@ -11,25 +11,12 @@ namespace safe_browsing {
namespace V4FeatureList {
-bool IsV4OnlyEnabled() {
- return base::FeatureList::IsEnabled(kV4OnlyEnabled);
-}
-
-bool IsLocalDatabaseManagerEnabled() {
- return base::FeatureList::IsEnabled(kLocalDatabaseManagerEnabled) ||
- IsV4OnlyEnabled();
-}
-
V4UsageStatus GetV4UsageStatus() {
- V4UsageStatus v4_usage_status;
- if (safe_browsing::V4FeatureList::IsV4OnlyEnabled()) {
- v4_usage_status = V4UsageStatus::V4_ONLY;
- } else if (safe_browsing::V4FeatureList::IsLocalDatabaseManagerEnabled()) {
- v4_usage_status = V4UsageStatus::V4_INSTANTIATED;
- } else {
- v4_usage_status = V4UsageStatus::V4_DISABLED;
- }
- return v4_usage_status;
+#if defined(SAFE_BROWSING_DB_LOCAL)
+ return V4UsageStatus::V4_ONLY;
+#else
+ return V4UsageStatus::V4_DISABLED;
+#endif
}
} // namespace V4FeatureList
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
index 9cfd8ffa13e..22368b1bc62 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
@@ -124,11 +124,16 @@ const char kPermission[] = "permission";
const char kPhaPatternType[] = "pha_pattern_type";
const char kMalwareThreatType[] = "malware_threat_type";
const char kSePatternType[] = "se_pattern_type";
+const char kSfPatternType[] = "sf_pattern_type";
+const char kExperimentalKey[] = "experimental";
const char kLanding[] = "LANDING";
const char kDistribution[] = "DISTRIBUTION";
const char kSocialEngineeringAds[] = "SOCIAL_ENGINEERING_ADS";
const char kSocialEngineeringLanding[] = "SOCIAL_ENGINEERING_LANDING";
const char kPhishing[] = "PHISHING";
+const char kSubresourceFilterBetterAds[] = "BETTER_ADS";
+const char kSubresourceFilterAbusiveAds[] = "ABUSIVE_ADS";
+const char kSubresourceFilterAll[] = "ALL_ADS";
} // namespace
@@ -323,7 +328,7 @@ void V4GetHashProtocolManager::GetFullHashes(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "Safe Browsing cookie store"
setting:
"Users can disable Safe Browsing by unchecking 'Protect you and "
@@ -381,7 +386,7 @@ void V4GetHashProtocolManager::GetFullHashCachedResults(
full_hash_to_store_and_hash_prefixes,
const Time& now,
std::vector<HashPrefix>* prefixes_to_request,
- std::vector<FullHashInfo>* cached_full_hash_infos) const {
+ std::vector<FullHashInfo>* cached_full_hash_infos) {
DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
DCHECK(prefixes_to_request->empty());
DCHECK(cached_full_hash_infos->empty());
@@ -433,6 +438,7 @@ void V4GetHashProtocolManager::GetFullHashCachedResults(
full_hash_info.list_id == list_id) {
// Case a.
found_full_hash = true;
+ number_of_hits_++;
if (full_hash_info.positive_expiry > now) {
// Case i.
cached_full_hash_infos->push_back(full_hash_info);
@@ -664,6 +670,24 @@ void V4GetHashProtocolManager::ParseMetadata(const ThreatMatch& match,
}
}
}
+ } else if (match.threat_type() == SUBRESOURCE_FILTER) {
+ for (const ThreatEntryMetadata::MetadataEntry& m :
+ match.threat_entry_metadata().entries()) {
+ if (m.key() == kSfPatternType) {
+ if (m.value() == kSubresourceFilterBetterAds) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::SUBRESOURCE_FILTER_BETTER_ADS;
+ } else if (m.value() == kSubresourceFilterAbusiveAds) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::SUBRESOURCE_FILTER_ABUSIVE_ADS;
+ } else if (m.value() == kSubresourceFilterAll) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS;
+ }
+ } else if (m.key() == kExperimentalKey) {
+ metadata->experimental = m.value() == "true";
+ }
+ }
} else if (match.has_threat_entry_metadata() &&
match.threat_entry_metadata().entries_size() > 1) {
RecordParseGetHashResult(UNEXPECTED_THREAT_TYPE_ERROR);
@@ -788,6 +812,35 @@ void V4GetHashProtocolManager::OnURLFetchComplete(
pending_hash_requests_.erase(it);
}
+void V4GetHashProtocolManager::CollectFullHashCacheInfo(
+ FullHashCacheInfo* full_hash_cache_info) {
+ full_hash_cache_info->set_number_of_hits(number_of_hits_);
+
+ for (const auto& it : full_hash_cache_) {
+ FullHashCacheInfo::FullHashCache* full_hash_cache =
+ full_hash_cache_info->add_full_hash_cache();
+ full_hash_cache->set_hash_prefix(it.first);
+ full_hash_cache->mutable_cached_hash_prefix_info()->set_negative_expiry(
+ it.second.negative_expiry.ToJavaTime());
+
+ for (const auto& full_hash_infos_it : it.second.full_hash_infos) {
+ FullHashCacheInfo::FullHashCache::CachedHashPrefixInfo::FullHashInfo*
+ full_hash_info = full_hash_cache->mutable_cached_hash_prefix_info()
+ ->add_full_hash_info();
+ full_hash_info->set_positive_expiry(
+ full_hash_infos_it.positive_expiry.ToJavaTime());
+ full_hash_info->set_full_hash(full_hash_infos_it.full_hash);
+
+ full_hash_info->mutable_list_identifier()->set_platform_type(
+ static_cast<int>(full_hash_infos_it.list_id.platform_type()));
+ full_hash_info->mutable_list_identifier()->set_threat_entry_type(
+ static_cast<int>(full_hash_infos_it.list_id.threat_entry_type()));
+ full_hash_info->mutable_list_identifier()->set_threat_type(
+ static_cast<int>(full_hash_infos_it.list_id.threat_type()));
+ }
+ }
+}
+
#ifndef DEBUG
std::ostream& operator<<(std::ostream& os, const FullHashInfo& fhi) {
os << "{full_hash: " << fhi.full_hash << "; list_id: " << fhi.list_id
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
index 6e43e8897c9..967c0ef3f60 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
@@ -24,6 +24,7 @@
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "components/safe_browsing_db/util.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
@@ -187,6 +188,9 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate {
// net::URLFetcherDelegate interface.
void OnURLFetchComplete(const net::URLFetcher* source) override;
+ // Populates the protobuf with the FullHashCache data.
+ void CollectFullHashCacheInfo(FullHashCacheInfo* full_hash_cache_info);
+
protected:
// Constructs a V4GetHashProtocolManager that issues network requests using
// |request_context_getter|.
@@ -202,6 +206,8 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate {
FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashThreatPatternType);
FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
+ TestParseSubresourceFilterMetadata);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashResponseNonPermissionMetadata);
FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashResponseInconsistentThreatTypes);
@@ -231,7 +237,7 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate {
full_hash_to_store_and_hash_prefixes,
const base::Time& now,
std::vector<HashPrefix>* prefixes_to_request,
- std::vector<FullHashInfo>* cached_full_hash_infos) const;
+ std::vector<FullHashInfo>* cached_full_hash_infos);
// Fills a FindFullHashesRequest protocol buffer for a request.
// Returns the serialized and base 64 encoded request as a string.
@@ -327,6 +333,9 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate {
// The context we use to issue network requests.
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ // Records number of cache hits since the beginning of this session.
+ int number_of_hits_ = 0;
+
// ID for URLFetchers for testing.
int url_fetcher_id_;
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
index 85a42c16c65..a0305740c99 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
@@ -71,8 +71,8 @@ class V4GetHashProtocolManagerTest : public PlatformTest {
StoresToCheck stores_to_check(
{GetUrlMalwareId(), GetChromeUrlApiId(),
ListIdentifier(CHROME_PLATFORM, URL, SOCIAL_ENGINEERING_PUBLIC),
- ListIdentifier(CHROME_PLATFORM, URL,
- POTENTIALLY_HARMFUL_APPLICATION)});
+ ListIdentifier(CHROME_PLATFORM, URL, POTENTIALLY_HARMFUL_APPLICATION),
+ ListIdentifier(CHROME_PLATFORM, URL, SUBRESOURCE_FILTER)});
return V4GetHashProtocolManager::Create(NULL, stores_to_check,
GetTestV4ProtocolConfig());
}
@@ -285,9 +285,9 @@ TEST_F(V4GetHashProtocolManagerTest, TestGetHashRequest) {
info->add_threat_entry_types(URL);
- for (const ThreatType& tt :
- std::set<ThreatType>{MALWARE_THREAT, SOCIAL_ENGINEERING_PUBLIC,
- POTENTIALLY_HARMFUL_APPLICATION, API_ABUSE}) {
+ for (const ThreatType& tt : std::set<ThreatType>{
+ MALWARE_THREAT, SOCIAL_ENGINEERING_PUBLIC,
+ POTENTIALLY_HARMFUL_APPLICATION, API_ABUSE, SUBRESOURCE_FILTER}) {
info->add_threat_types(tt);
}
@@ -495,6 +495,49 @@ TEST_F(V4GetHashProtocolManagerTest, TestParseHashThreatPatternType) {
}
}
+TEST_F(V4GetHashProtocolManagerTest, TestParseSubresourceFilterMetadata) {
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+
+ base::Time now = base::Time::UnixEpoch();
+ SetTestClock(now, pm.get());
+ FindFullHashesResponse sf_res;
+ sf_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* sf = sf_res.add_matches();
+ sf->set_threat_type(SUBRESOURCE_FILTER);
+ sf->set_platform_type(CHROME_PLATFORM);
+ sf->set_threat_entry_type(URL);
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ sf->mutable_threat()->set_hash(full_hash);
+
+ // sf_pattern_type
+ ThreatEntryMetadata::MetadataEntry* sf_pattern_meta =
+ sf->mutable_threat_entry_metadata()->add_entries();
+ sf_pattern_meta->set_key("sf_pattern_type");
+ sf_pattern_meta->set_value("ALL_ADS");
+ // experimental
+ ThreatEntryMetadata::MetadataEntry* sf_experimental_meta =
+ sf->mutable_threat_entry_metadata()->add_entries();
+ sf_experimental_meta->set_key("experimental");
+ sf_experimental_meta->set_value("true");
+
+ std::string sf_data;
+ sf_res.SerializeToString(&sf_data);
+
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_TRUE(pm->ParseHashResponse(sf_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
+
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ const ListIdentifier list_id(CHROME_PLATFORM, URL, SUBRESOURCE_FILTER);
+ EXPECT_EQ(list_id, fhi.list_id);
+ EXPECT_EQ(ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS,
+ fhi.metadata.threat_pattern_type);
+ EXPECT_TRUE(fhi.metadata.experimental);
+}
+
// Adds metadata with a key value that is not "permission".
TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseNonPermissionMetadata) {
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager.cc b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
index 326ed5b0fdb..879e4e77d19 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
@@ -17,9 +17,11 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/task_scheduler/post_task.h"
+#include "components/safe_browsing_db/notification_types.h"
#include "components/safe_browsing_db/v4_feature_list.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
#include "crypto/sha2.h"
using content::BrowserThread;
@@ -173,21 +175,46 @@ V4LocalDatabaseManager::PendingCheck::PendingCheck(
V4LocalDatabaseManager::PendingCheck::~PendingCheck() {}
// static
+const V4LocalDatabaseManager*
+ V4LocalDatabaseManager::current_local_database_manager_;
+
+// static
scoped_refptr<V4LocalDatabaseManager> V4LocalDatabaseManager::Create(
const base::FilePath& base_path,
ExtendedReportingLevelCallback extended_reporting_level_callback) {
- return make_scoped_refptr(
- new V4LocalDatabaseManager(base_path, extended_reporting_level_callback));
+ return make_scoped_refptr(new V4LocalDatabaseManager(
+ base_path, extended_reporting_level_callback, nullptr));
+}
+
+void V4LocalDatabaseManager::CollectDatabaseManagerInfo(
+ DatabaseManagerInfo* database_manager_info,
+ FullHashCacheInfo* full_hash_cache_info) const {
+ if (v4_update_protocol_manager_) {
+ v4_update_protocol_manager_->CollectUpdateInfo(
+ database_manager_info->mutable_update_info());
+ }
+ if (v4_database_) {
+ v4_database_->CollectDatabaseInfo(
+ database_manager_info->mutable_database_info());
+ }
+ if (v4_get_hash_protocol_manager_) {
+ v4_get_hash_protocol_manager_->CollectFullHashCacheInfo(
+ full_hash_cache_info);
+ }
}
V4LocalDatabaseManager::V4LocalDatabaseManager(
const base::FilePath& base_path,
- ExtendedReportingLevelCallback extended_reporting_level_callback)
+ ExtendedReportingLevelCallback extended_reporting_level_callback,
+ scoped_refptr<base::SequencedTaskRunner> task_runner_for_tests)
: base_path_(base_path),
extended_reporting_level_callback_(extended_reporting_level_callback),
list_infos_(GetListInfos()),
- task_runner_(base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
+ task_runner_(task_runner_for_tests
+ ? task_runner_for_tests
+ : base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
weak_factory_(this) {
DCHECK(!base_path_.empty());
DCHECK(!list_infos_.empty());
@@ -465,6 +492,8 @@ void V4LocalDatabaseManager::StartOnIOThread(
SetupDatabase();
enabled_ = true;
+
+ current_local_database_manager_ = this;
}
void V4LocalDatabaseManager::StopOnIOThread(bool shutdown) {
@@ -472,6 +501,8 @@ void V4LocalDatabaseManager::StopOnIOThread(bool shutdown) {
enabled_ = false;
+ current_local_database_manager_ = NULL;
+
pending_checks_.clear();
RespondSafeToQueuedChecks();
@@ -536,9 +567,26 @@ void V4LocalDatabaseManager::DatabaseUpdated() {
v4_database_->RecordFileSizeHistograms();
v4_update_protocol_manager_->ScheduleNextUpdate(
v4_database_->GetStoreStateMap());
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&V4LocalDatabaseManager::PostUpdateNotificationOnUIThread,
+ content::Source<SafeBrowsingDatabaseManager>(this)));
}
}
+// static
+void V4LocalDatabaseManager::PostUpdateNotificationOnUIThread(
+ const content::NotificationSource& source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // The notification needs to be posted on the UI thread because the extension
+ // checker is observing UI thread's notification service.
+ content::NotificationService::current()->Notify(
+ NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, source,
+ content::NotificationService::NoDetails());
+}
+
void V4LocalDatabaseManager::DeleteUnusedStoreFiles() {
for (auto* const store_filename_to_delete : kStoreFileNamesToDelete) {
// Is the file marked for deletion also being used for a valid V4Store?
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager.h b/chromium/components/safe_browsing_db/v4_local_database_manager.h
index c35296e0f18..90e62e97fb9 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager.h
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager.h
@@ -12,12 +12,14 @@
#include <unordered_set>
#include "base/memory/weak_ptr.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/database_manager.h"
#include "components/safe_browsing_db/hit_report.h"
#include "components/safe_browsing_db/v4_database.h"
#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/safe_browsing_db/v4_update_protocol_manager.h"
+#include "content/public/browser/notification_service.h"
#include "url/gurl.h"
namespace safe_browsing {
@@ -34,6 +36,16 @@ class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
const base::FilePath& base_path,
ExtendedReportingLevelCallback extended_reporting_level_callback);
+ // Populates the protobuf with the database data.
+ void CollectDatabaseManagerInfo(
+ DatabaseManagerInfo* v4_database_info,
+ FullHashCacheInfo* full_hash_cache_info) const;
+
+ // Return an instance of the V4LocalDatabaseManager object
+ static const V4LocalDatabaseManager* current_local_database_manager() {
+ return current_local_database_manager_;
+ }
+
//
// SafeBrowsingDatabaseManager implementation
//
@@ -80,15 +92,11 @@ class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
// Must be initialized by calling StartOnIOThread() before using.
V4LocalDatabaseManager(
const base::FilePath& base_path,
- ExtendedReportingLevelCallback extended_reporting_level_callback);
+ ExtendedReportingLevelCallback extended_reporting_level_callback,
+ scoped_refptr<base::SequencedTaskRunner> task_runner_for_tests);
~V4LocalDatabaseManager() override;
- void SetTaskRunnerForTest(
- const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
- task_runner_ = task_runner;
- }
-
enum class ClientCallbackType {
// This represents the case when we're trying to determine if a URL is
// unsafe from the following perspectives: Malware, Phishing, UwS.
@@ -183,6 +191,7 @@ class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
friend class V4LocalDatabaseManagerTest;
FRIEND_TEST_ALL_PREFIXES(V4LocalDatabaseManagerTest,
TestGetSeverestThreatTypeAndMetadata);
+ FRIEND_TEST_ALL_PREFIXES(V4LocalDatabaseManagerTest, NotificationOnUpdate);
// The checks awaiting a full hash response from SafeBrowsing service.
typedef std::unordered_set<const PendingCheck*> PendingChecks;
@@ -264,6 +273,12 @@ class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
const FullHashToStoreAndHashPrefixesMap&
full_hash_to_store_and_hash_prefixes);
+ // Post a notification about the completion of database update process.
+ // This is currently used by the extension blacklist checker to disable any
+ // installed extensions that have been blacklisted since.
+ static void PostUpdateNotificationOnUIThread(
+ const content::NotificationSource& source);
+
// When the database is ready to use, process the checks that were queued
// while the database was loading from disk.
void ProcessQueuedChecks();
@@ -301,6 +316,9 @@ class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
// The base directory under which to create the files that contain hashes.
const base::FilePath base_path_;
+ // Instance of the V4LocalDatabaseManager object
+ static const V4LocalDatabaseManager* current_local_database_manager_;
+
// Called when the V4Database has finished applying the latest update and is
// ready to process next update.
DatabaseUpdatedCallback db_updated_callback_;
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index f40d3410470..3bcdcfe9544 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -11,10 +11,12 @@
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/safe_browsing_db/notification_types.h"
#include "components/safe_browsing_db/v4_database.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/safe_browsing_db/v4_test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
#include "crypto/sha2.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/platform_test.h"
@@ -246,8 +248,11 @@ class FakeV4LocalDatabaseManager : public V4LocalDatabaseManager {
public:
FakeV4LocalDatabaseManager(
const base::FilePath& base_path,
- ExtendedReportingLevelCallback extended_reporting_level_callback)
- : V4LocalDatabaseManager(base_path, extended_reporting_level_callback),
+ ExtendedReportingLevelCallback extended_reporting_level_callback,
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : V4LocalDatabaseManager(base_path,
+ extended_reporting_level_callback,
+ task_runner),
perform_full_hash_check_called_(false) {}
// V4LocalDatabaseManager impl:
@@ -285,9 +290,8 @@ class V4LocalDatabaseManagerTest : public PlatformTest {
base::Bind(&V4LocalDatabaseManagerTest::GetExtendedReportingLevel,
base::Unretained(this));
- v4_local_database_manager_ = make_scoped_refptr(
- new V4LocalDatabaseManager(base_dir_.GetPath(), erl_callback_));
- SetTaskRunnerForTest();
+ v4_local_database_manager_ = make_scoped_refptr(new V4LocalDatabaseManager(
+ base_dir_.GetPath(), erl_callback_, task_runner_));
StartLocalDatabaseManager();
}
@@ -338,9 +342,8 @@ class V4LocalDatabaseManagerTest : public PlatformTest {
void ResetLocalDatabaseManager() {
StopLocalDatabaseManager();
- v4_local_database_manager_ = make_scoped_refptr(
- new V4LocalDatabaseManager(base_dir_.GetPath(), erl_callback_));
- SetTaskRunnerForTest();
+ v4_local_database_manager_ = make_scoped_refptr(new V4LocalDatabaseManager(
+ base_dir_.GetPath(), erl_callback_, task_runner_));
StartLocalDatabaseManager();
}
@@ -348,10 +351,6 @@ class V4LocalDatabaseManagerTest : public PlatformTest {
V4Database::Destroy(std::move(v4_local_database_manager_->v4_database_));
}
- void SetTaskRunnerForTest() {
- v4_local_database_manager_->SetTaskRunnerForTest(task_runner_);
- }
-
void StartLocalDatabaseManager() {
v4_local_database_manager_->StartOnIOThread(NULL,
GetTestV4ProtocolConfig());
@@ -378,9 +377,9 @@ class V4LocalDatabaseManagerTest : public PlatformTest {
// StopLocalDatabaseManager before resetting it because that's what
// ~V4LocalDatabaseManager expects.
StopLocalDatabaseManager();
- v4_local_database_manager_ = make_scoped_refptr(
- new FakeV4LocalDatabaseManager(base_dir_.GetPath(), erl_callback_));
- SetTaskRunnerForTest();
+ v4_local_database_manager_ =
+ make_scoped_refptr(new FakeV4LocalDatabaseManager(
+ base_dir_.GetPath(), erl_callback_, task_runner_));
StartLocalDatabaseManager();
WaitForTasksOnTaskRunner();
}
@@ -1157,4 +1156,20 @@ TEST_F(V4LocalDatabaseManagerTest, DeleteUnusedStoreFileRandomFileNotDeleted) {
base::DeleteFile(random_store_file_path, false /* recursive */);
}
+TEST_F(V4LocalDatabaseManagerTest, NotificationOnUpdate) {
+ content::WindowedNotificationObserver observer(
+ NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
+ content::Source<SafeBrowsingDatabaseManager>(
+ v4_local_database_manager_.get()));
+
+ // Creates and associates a V4Database instance.
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ ReplaceV4Database(store_and_hash_prefixes);
+
+ v4_local_database_manager_->DatabaseUpdated();
+
+ // This observer waits until it receives the notification.
+ observer.Wait();
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
index 9c083542bdd..3192e149c91 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -125,6 +125,12 @@ enum SBThreatType {
// Url detected by password protection service.
SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING,
+
+ // Password reuse detected on low reputation page,
+ SB_THREAT_TYPE_PASSWORD_REUSE,
+
+ // A sample of an ad was collected
+ SB_THREAT_TYPE_AD_SAMPLE,
};
using SBThreatTypeSet = base::flat_set<SBThreatType>;
diff --git a/chromium/components/safe_browsing_db/v4_store.cc b/chromium/components/safe_browsing_db/v4_store.cc
index a1bc3070143..2d51d61c766 100644
--- a/chromium/components/safe_browsing_db/v4_store.cc
+++ b/chromium/components/safe_browsing_db/v4_store.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/safe_browsing_db/v4_store.h"
+
#include "base/base64.h"
#include "base/bind.h"
#include "base/files/file_util.h"
@@ -10,8 +12,8 @@
#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/v4_rice.h"
-#include "components/safe_browsing_db/v4_store.h"
#include "components/safe_browsing_db/v4_store.pb.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
@@ -372,6 +374,9 @@ void V4Store::ApplyUpdate(
if (apply_update_result == APPLY_UPDATE_SUCCESS) {
new_store->has_valid_data_ = true;
+ new_store->last_apply_update_result_ = apply_update_result;
+ new_store->last_apply_update_time_millis_ = base::Time::Now();
+ new_store->checks_attempted_ = checks_attempted_;
RecordApplyUpdateTime(metric, TimeTicks::Now() - before, store_path_);
} else {
new_store.reset();
@@ -379,6 +384,9 @@ void V4Store::ApplyUpdate(
<< "; store: " << *this;
}
+ // Record the state of the update to be shown in the Safe Browsing page.
+ last_apply_update_result_ = apply_update_result;
+
RecordApplyUpdateResult(metric, apply_update_result, store_path_);
// Posting the task should be the last thing to do in this function.
@@ -703,6 +711,7 @@ StoreReadResult V4Store::ReadFromDisk() {
ApplyUpdateResult apply_update_result = ProcessFullUpdate(
kReadFromDisk, response, true /* delay_checksum check */);
RecordApplyUpdateResult(kReadFromDisk, apply_update_result, store_path_);
+ last_apply_update_result_ = apply_update_result;
if (apply_update_result != APPLY_UPDATE_SUCCESS) {
hash_prefix_map_.clear();
return HASH_PREFIX_MAP_GENERATION_FAILURE;
@@ -760,6 +769,7 @@ HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) {
// full hash. However, if that happens, this method returns any one of them.
// It does not guarantee which one of those will be returned.
DCHECK(full_hash.size() == 32u || full_hash.size() == 21u);
+ checks_attempted_++;
for (const auto& pair : hash_prefix_map_) {
const PrefixSize& prefix_size = pair.first;
const HashPrefixes& hash_prefixes = pair.second;
@@ -862,4 +872,17 @@ int64_t V4Store::RecordAndReturnFileSize(const std::string& base_metric) {
return file_size_;
}
+void V4Store::CollectStoreInfo(
+ DatabaseManagerInfo::DatabaseInfo::StoreInfo* store_info,
+ const std::string& base_metric) {
+ store_info->set_file_name(base_metric + GetUmaSuffixForStore(store_path_));
+ store_info->set_file_size_bytes(file_size_);
+ store_info->set_update_status(static_cast<int>(last_apply_update_result_));
+ store_info->set_checks_attempted(checks_attempted_);
+ if (last_apply_update_time_millis_.ToJavaTime()) {
+ store_info->set_last_apply_update_time_millis(
+ last_apply_update_time_millis_.ToJavaTime());
+ }
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_store.h b/chromium/components/safe_browsing_db/v4_store.h
index 3fb74edf5f9..392d841c9cd 100644
--- a/chromium/components/safe_browsing_db/v4_store.h
+++ b/chromium/components/safe_browsing_db/v4_store.h
@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
namespace safe_browsing {
@@ -215,6 +216,11 @@ class V4Store {
// which blocks resource loads.
bool VerifyChecksum();
+ // Populates the DatabaseInfo message.
+ void CollectStoreInfo(
+ DatabaseManagerInfo::DatabaseInfo::StoreInfo* store_info,
+ const std::string& base_metric);
+
protected:
HashPrefixMap hash_prefix_map_;
@@ -400,6 +406,12 @@ class V4Store {
// |checksum| is used to set the |checksum| field in the final proto.
StoreWriteResult WriteToDisk(const Checksum& checksum);
+ // Records the status of the update being applied to the database.
+ ApplyUpdateResult last_apply_update_result_ = APPLY_UPDATE_RESULT_MAX;
+
+ // Records the time when the store was last updated.
+ base::Time last_apply_update_time_millis_;
+
// The checksum value as read from the disk, until it is verified. Once
// verified, it is cleared.
std::string expected_checksum_;
@@ -411,6 +423,9 @@ class V4Store {
// a full update.
bool has_valid_data_;
+ // Records the number of times we have looked up the store.
+ size_t checks_attempted_ = 0;
+
// The state of the store as returned by the PVer4 server in the last applied
// update response.
std::string state_;
diff --git a/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc b/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
index ddd08f588b6..d1ed6fd4b94 100644
--- a/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
@@ -72,7 +72,7 @@ static const int kV4TimerStartIntervalSecMin = 60;
static const int kV4TimerStartIntervalSecMax = 300;
// Maximum time, in seconds, to wait for a response to an update request.
-static const int kV4TimerUpdateWaitSecMax = 30;
+static const int kV4TimerUpdateWaitSecMax = 15 * 60; // 15 minutes
ChromeClientInfo::SafeBrowsingReportingPopulation GetReportingLevelProtoValue(
ExtendedReportingLevel reporting_level) {
@@ -329,7 +329,7 @@ void V4UpdateProtocolManager::IssueUpdateRequest() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "Safe Browsing cookie store"
setting:
"Users can disable Safe Browsing by unchecking 'Protect you and "
@@ -376,17 +376,17 @@ void V4UpdateProtocolManager::OnURLFetchComplete(
timeout_timer_.Stop();
- int response_code = source->GetResponseCode();
+ last_response_code_ = source->GetResponseCode();
net::URLRequestStatus status = source->GetStatus();
V4ProtocolManagerUtil::RecordHttpResponseOrErrorCode(
- "SafeBrowsing.V4Update.Network.Result", status, response_code);
+ "SafeBrowsing.V4Update.Network.Result", status, last_response_code_);
UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.V4Update.TimedOut", false);
last_response_time_ = Time::Now();
std::unique_ptr<ParsedServerResponse> parsed_server_response(
new ParsedServerResponse);
- if (status.is_success() && response_code == net::HTTP_OK) {
+ if (status.is_success() && last_response_code_ == net::HTTP_OK) {
RecordUpdateResult(V4OperationResult::STATUS_200);
ResetUpdateErrors();
std::string data;
@@ -407,7 +407,7 @@ void V4UpdateProtocolManager::OnURLFetchComplete(
} else {
DVLOG(1) << "SafeBrowsing GetEncodedUpdates request for: "
<< source->GetURL() << " failed with error: " << status.error()
- << " and response code: " << response_code;
+ << " and response code: " << last_response_code_;
if (status.status() == net::URLRequestStatus::FAILED) {
RecordUpdateResult(V4OperationResult::NETWORK_ERROR);
@@ -430,4 +430,13 @@ void V4UpdateProtocolManager::GetUpdateUrlAndHeaders(
req_base64, "threatListUpdates:fetch", config_, gurl, headers);
}
+void V4UpdateProtocolManager::CollectUpdateInfo(
+ DatabaseManagerInfo::UpdateInfo* update_info) {
+ if (last_response_code_)
+ update_info->set_network_status_code(last_response_code_);
+
+ if (last_response_time_.ToJavaTime())
+ update_info->set_last_update_time_millis(last_response_time_.ToJavaTime());
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_update_protocol_manager.h b/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
index 706c7d4c331..73f076f68d0 100644
--- a/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
+++ b/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
@@ -22,6 +22,7 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/proto/webui.pb.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "components/safe_browsing_db/util.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
@@ -70,6 +71,9 @@ class V4UpdateProtocolManager : public net::URLFetcherDelegate {
// Schedule the next update without backoff.
void ScheduleNextUpdate(std::unique_ptr<StoreStateMap> store_state_map);
+ // Populates the UpdateInfo message.
+ void CollectUpdateInfo(DatabaseManagerInfo::UpdateInfo* database_info);
+
protected:
// Constructs a V4UpdateProtocolManager that issues network requests using
// |request_context_getter|. It schedules updates to get the hash prefixes for
@@ -102,6 +106,9 @@ class V4UpdateProtocolManager : public net::URLFetcherDelegate {
// Returns the serialized and base64 URL encoded request as a string.
std::string GetBase64SerializedUpdateRequestProto();
+ // Records the network response code of the last update
+ int last_response_code_ = 0;
+
// The method to populate |gurl| with the URL to be sent to the server.
// |request_base64| is the base64 encoded form of an instance of the protobuf
// FetchThreatListUpdatesRequest. Also sets the appropriate header values for
diff --git a/chromium/components/safe_json/json_sanitizer_android.cc b/chromium/components/safe_json/json_sanitizer_android.cc
index f79ea7f5e99..82d95069008 100644
--- a/chromium/components/safe_json/json_sanitizer_android.cc
+++ b/chromium/components/safe_json/json_sanitizer_android.cc
@@ -51,20 +51,13 @@ class JsonSanitizerAndroid : public JsonSanitizer {
StringCallback success_callback_;
StringCallback error_callback_;
- // Runs the callbacks. Stored as a member because grabbing it when posting
- // the callbacks (being called from Java) fails under certain circumstances
- // (https://crbug.com/739510).
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
DISALLOW_COPY_AND_ASSIGN(JsonSanitizerAndroid);
};
JsonSanitizerAndroid::JsonSanitizerAndroid(
const StringCallback& success_callback,
const StringCallback& error_callback)
- : success_callback_(success_callback),
- error_callback_(error_callback),
- task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+ : success_callback_(success_callback), error_callback_(error_callback) {}
void JsonSanitizerAndroid::Sanitize(const std::string& unsafe_json) {
// The JSON parser only accepts wellformed UTF-8.
@@ -83,11 +76,13 @@ void JsonSanitizerAndroid::Sanitize(const std::string& unsafe_json) {
}
void JsonSanitizerAndroid::OnSuccess(const std::string& json) {
- task_runner_->PostTask(FROM_HERE, base::Bind(success_callback_, json));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(success_callback_, json));
}
void JsonSanitizerAndroid::OnError(const std::string& error) {
- task_runner_->PostTask(FROM_HERE, base::Bind(error_callback_, error));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(error_callback_, error));
}
} // namespace
diff --git a/chromium/components/search/OWNERS b/chromium/components/search/OWNERS
index 5b1b249b4b5..9d7d94a9956 100644
--- a/chromium/components/search/OWNERS
+++ b/chromium/components/search/OWNERS
@@ -1,6 +1,5 @@
treib@chromium.org
# Original implementors of most of the code, but not active in Chromium anymore
-kmadhusu@chromium.org
jered@chromium.org
samarth@chromium.org
diff --git a/chromium/components/search/search.cc b/chromium/components/search/search.cc
index 41d9fc96b3c..69ea1c1ae97 100644
--- a/chromium/components/search/search.cc
+++ b/chromium/components/search/search.cc
@@ -4,51 +4,12 @@
#include "components/search/search.h"
-#include <stddef.h>
-
-#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/google/core/browser/google_util.h"
-#include "components/search_engines/template_url.h"
-#include "url/gurl.h"
namespace search {
-namespace {
-
-// Configuration options for Embedded Search.
-// EmbeddedSearch field trials are named in such a way that we can parse out
-// the experiment configuration from the trial's group name in order to give
-// us maximum flexability in running experiments.
-// Field trial groups should be named things like "Group7 espv:2 instant:1".
-// The first token is always GroupN for some integer N, followed by a
-// space-delimited list of key:value pairs which correspond to these flags:
-const char kEmbeddedPageVersionFlagName[] = "espv";
-
-#if defined(OS_IOS) || defined(OS_ANDROID)
-const uint64_t kEmbeddedPageVersionDefault = 1;
-#else
-const uint64_t kEmbeddedPageVersionDefault = 2;
-#endif
-
-// Constants for the field trial name and group prefix.
-// Note in M30 and below this field trial was named "InstantExtended" and in
-// M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
-// can't easilly sync up Finch configs with the pushing of this change to
-// Dev & Canary, for now the code accepts both names.
-// TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
-// channel.
-const char kInstantExtendedFieldTrialName[] = "InstantExtended";
-const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
-
-// If the field trial's group name ends with this string its configuration will
-// be ignored and Instant Extended will not be enabled by default.
-const char kDisablingSuffix[] = "DISABLED";
-
-} // namespace
-
bool IsInstantExtendedAPIEnabled() {
#if defined(OS_IOS) || defined(OS_ANDROID)
return false;
@@ -57,62 +18,12 @@ bool IsInstantExtendedAPIEnabled() {
#endif
}
-// Determine what embedded search page version to request from the user's
-// default search provider. If 0, the embedded search UI should not be enabled.
uint64_t EmbeddedSearchPageVersion() {
- FieldTrialFlags flags;
- if (GetFieldTrialInfo(&flags)) {
- return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
- kEmbeddedPageVersionDefault,
- flags);
- }
- return kEmbeddedPageVersionDefault;
-}
-
-bool GetFieldTrialInfo(FieldTrialFlags* flags) {
- // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
- // the older InstantExtended name.
- std::string group_name = base::FieldTrialList::FindFullName(
- kEmbeddedSearchFieldTrialName);
- if (group_name.empty()) {
- group_name = base::FieldTrialList::FindFullName(
- kInstantExtendedFieldTrialName);
- }
-
- if (base::EndsWith(group_name, kDisablingSuffix,
- base::CompareCase::SENSITIVE))
- return false;
-
- // We have a valid trial that isn't disabled. Extract the flags.
- std::string group_prefix(group_name);
- size_t first_space = group_name.find(" ");
- if (first_space != std::string::npos) {
- // There is a flags section of the group name. Split that out and parse it.
- group_prefix = group_name.substr(0, first_space);
- if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
- ':', ' ', flags)) {
- // Failed to parse the flags section. Assume the whole group name is
- // invalid.
- return false;
- }
- }
- return true;
-}
-
-// Given a FieldTrialFlags object, returns the uint64_t value of the provided
-// flag.
-uint64_t GetUInt64ValueForFlagWithDefault(const std::string& flag,
- uint64_t default_value,
- const FieldTrialFlags& flags) {
- for (const std::pair<std::string, std::string>& flag_and_value : flags) {
- if (flag_and_value.first == flag) {
- const std::string& str_value = flag_and_value.second;
- uint64_t value;
- if (base::StringToUint64(str_value, &value))
- return value;
- }
- }
- return default_value;
+#if defined(OS_IOS) || defined(OS_ANDROID)
+ return 1;
+#else
+ return 2;
+#endif
}
std::string InstantExtendedEnabledParam() {
diff --git a/chromium/components/search/search.h b/chromium/components/search/search.h
index 9320e8fa55f..fd3d1f24c8d 100644
--- a/chromium/components/search/search.h
+++ b/chromium/components/search/search.h
@@ -5,42 +5,14 @@
#ifndef COMPONENTS_SEARCH_SEARCH_H_
#define COMPONENTS_SEARCH_SEARCH_H_
-#include <stdint.h>
-
#include <string>
-#include "base/strings/string_split.h"
-
namespace search {
// Returns whether the Instant Extended API is enabled. This is always true on
// desktop and false on mobile.
bool IsInstantExtendedAPIEnabled();
-// Returns the value to pass to the &espv CGI parameter when loading the
-// embedded search page from the user's default search provider. Returns 0 if
-// the Instant Extended API is not enabled.
-uint64_t EmbeddedSearchPageVersion();
-
-// Type for a collection of experiment configuration parameters.
-typedef base::StringPairs FieldTrialFlags;
-
-// Finds the active field trial group name and parses out the configuration
-// flags. On success, |flags| will be filled with the field trial flags. |flags|
-// must not be NULL. Returns true iff the active field trial is successfully
-// parsed and not disabled.
-// Note that |flags| may be successfully populated in some cases when false is
-// returned - in these cases it should not be used.
-// Exposed for testing only.
-bool GetFieldTrialInfo(FieldTrialFlags* flags);
-
-// Given a FieldTrialFlags object, returns the uint64_t value of the provided
-// flag.
-// Exposed for testing only.
-uint64_t GetUInt64ValueForFlagWithDefault(const std::string& flag,
- uint64_t default_value,
- const FieldTrialFlags& flags);
-
// Returns a string indicating whether InstantExtended is enabled, suitable
// for adding as a query string param to the homepage or search requests.
std::string InstantExtendedEnabledParam();
diff --git a/chromium/components/search/search_android_unittest.cc b/chromium/components/search/search_android_unittest.cc
index 08fd73ce0d2..8bbc75a00dc 100644
--- a/chromium/components/search/search_android_unittest.cc
+++ b/chromium/components/search/search_android_unittest.cc
@@ -4,8 +4,6 @@
#include "components/search/search.h"
-#include "base/command_line.h"
-#include "components/search/search.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace search {
@@ -13,7 +11,6 @@ namespace search {
namespace {
TEST(SearchTest, EmbeddedSearchAPIEnabled) {
- EXPECT_EQ(1ul, EmbeddedSearchPageVersion());
EXPECT_FALSE(IsInstantExtendedAPIEnabled());
}
diff --git a/chromium/components/search/search_unittest.cc b/chromium/components/search/search_unittest.cc
index b9f637d160c..6c86c76dc9c 100644
--- a/chromium/components/search/search_unittest.cc
+++ b/chromium/components/search/search_unittest.cc
@@ -4,160 +4,23 @@
#include "components/search/search.h"
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/statistics_recorder.h"
#include "build/build_config.h"
-#include "components/variations/entropy_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace search {
-class EmbeddedSearchFieldTrialTest : public testing::Test {
- protected:
- void SetUp() override {
- field_trial_list_.reset(new base::FieldTrialList(
- base::MakeUnique<metrics::SHA1EntropyProvider>("42")));
- base::StatisticsRecorder::Initialize();
- }
-
- private:
- std::unique_ptr<base::FieldTrialList> field_trial_list_;
-};
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoEmptyAndValid) {
- FieldTrialFlags flags;
-
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoInvalidNumber) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77.2"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoInvalidName) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Invalid77"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoValidGroup) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoValidFlag) {
- FieldTrialFlags flags;
-
- EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77 foo:6"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(1ul, flags.size());
- EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoNewName) {
- FieldTrialFlags flags;
-
- EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77 foo:6"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(1ul, flags.size());
- EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoNewNameOverridesOld) {
- FieldTrialFlags flags;
-
- EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group77 foo:6"));
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
- "Group78 foo:5"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(1ul, flags.size());
- EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoLotsOfFlags) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group77 baz:7 cat:dogs"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(2ul, flags.size());
- EXPECT_EQ(7ul, GetUInt64ValueForFlagWithDefault("baz", 0, flags));
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoDisabled) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group77 bar:1 baz:7 cat:dogs DISABLED"));
- EXPECT_FALSE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(0ul, flags.size());
-}
-
-TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoControlFlags) {
- FieldTrialFlags flags;
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Control77 bar:1 baz:7 cat:dogs"));
- EXPECT_TRUE(GetFieldTrialInfo(&flags));
- EXPECT_EQ(3ul, flags.size());
-}
-
#if !defined(OS_IOS) && !defined(OS_ANDROID)
-typedef EmbeddedSearchFieldTrialTest SearchTest;
-TEST_F(SearchTest, ShouldPrefetchSearchResults_InstantExtendedAPIEnabled) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group1 espv:2"));
- EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
+TEST(SearchTest, InstantExtendedAPIEnabled) {
EXPECT_TRUE(IsInstantExtendedAPIEnabled());
}
-TEST_F(SearchTest, ForceInstantResultsParam) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group1 espv:2"));
- EXPECT_TRUE(IsInstantExtendedAPIEnabled());
+TEST(SearchTest, ForceInstantResultsParam) {
EXPECT_EQ("ion=1&", ForceInstantResultsParam(true));
EXPECT_EQ(std::string(), ForceInstantResultsParam(false));
}
-typedef EmbeddedSearchFieldTrialTest InstantExtendedEnabledParamTest;
-
-TEST_F(InstantExtendedEnabledParamTest, QueryExtractionDisabled) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group1 espv:12"));
- EXPECT_EQ("espv=12&", InstantExtendedEnabledParam());
-}
-
-TEST_F(InstantExtendedEnabledParamTest, UseDefaultEmbeddedSearchPageVersion) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:-1"));
+TEST(SearchTest, InstantExtendedEnabledParam) {
EXPECT_EQ("espv=2&", InstantExtendedEnabledParam());
}
diff --git a/chromium/components/search_engines/default_search_manager.cc b/chromium/components/search_engines/default_search_manager.cc
index ebe9a875aaa..d1ab96ccb94 100644
--- a/chromium/components/search_engines/default_search_manager.cc
+++ b/chromium/components/search_engines/default_search_manager.cc
@@ -54,6 +54,7 @@ const char DefaultSearchManager::kContextualSearchURL[] =
"contextual_search_url";
const char DefaultSearchManager::kFaviconURL[] = "favicon_url";
const char DefaultSearchManager::kLogoURL[] = "logo_url";
+const char DefaultSearchManager::kDoodleURL[] = "doodle_url";
const char DefaultSearchManager::kOriginatingURL[] = "originating_url";
const char DefaultSearchManager::kSearchURLPostParams[] =
diff --git a/chromium/components/search_engines/default_search_manager.h b/chromium/components/search_engines/default_search_manager.h
index 7f0853ad898..083268a2893 100644
--- a/chromium/components/search_engines/default_search_manager.h
+++ b/chromium/components/search_engines/default_search_manager.h
@@ -43,6 +43,7 @@ class DefaultSearchManager {
static const char kContextualSearchURL[];
static const char kFaviconURL[];
static const char kLogoURL[];
+ static const char kDoodleURL[];
static const char kOriginatingURL[];
static const char kSearchURLPostParams[];
diff --git a/chromium/components/search_engines/default_search_manager_unittest.cc b/chromium/components/search_engines/default_search_manager_unittest.cc
index 8b2c54b42c4..b2620b6d840 100644
--- a/chromium/components/search_engines/default_search_manager_unittest.cc
+++ b/chromium/components/search_engines/default_search_manager_unittest.cc
@@ -55,7 +55,7 @@ void SetOverrides(sync_preferences::TestingPrefServiceSyncable* prefs,
entry->SetString("name", update ? "new_bar" : "bar");
entry->SetString("keyword", update ? "new_bark" : "bark");
entry->SetString("encoding", std::string());
- overrides->Append(base::MakeUnique<base::Value>(*entry));
+ overrides->Append(base::MakeUnique<base::Value>(entry->Clone()));
entry->SetInteger("id", 1003);
entry->SetString("name", "baz");
entry->SetString("keyword", "bazk");
diff --git a/chromium/components/search_engines/default_search_policy_handler.cc b/chromium/components/search_engines/default_search_policy_handler.cc
index 295334d2d0f..3b9ee6f0fcd 100644
--- a/chromium/components/search_engines/default_search_policy_handler.cc
+++ b/chromium/components/search_engines/default_search_policy_handler.cc
@@ -36,8 +36,9 @@ void SetListInPref(const PolicyMap& policies,
bool is_list = policy_value->GetAsList(&policy_list);
DCHECK(is_list);
}
- dict->Set(key, policy_list ? base::MakeUnique<base::ListValue>(*policy_list)
- : base::MakeUnique<base::ListValue>());
+ dict->Set(key, policy_list
+ ? base::MakeUnique<base::Value>(policy_list->Clone())
+ : base::MakeUnique<base::Value>(base::Value::Type::LIST));
}
// Extracts a string from a policy value and adds it to a pref dictionary.
diff --git a/chromium/components/search_engines/keyword_web_data_service.cc b/chromium/components/search_engines/keyword_web_data_service.cc
index 47bfafcf8f6..c1ab4071379 100644
--- a/chromium/components/search_engines/keyword_web_data_service.cc
+++ b/chromium/components/search_engines/keyword_web_data_service.cc
@@ -37,10 +37,10 @@ KeywordWebDataService::BatchModeScoper::~BatchModeScoper() {
KeywordWebDataService::KeywordWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const ProfileErrorCallback& callback)
- : WebDataServiceBase(wdbs, callback, ui_thread), batch_mode_level_(0) {
-}
+ : WebDataServiceBase(wdbs, callback, ui_task_runner),
+ batch_mode_level_(0) {}
void KeywordWebDataService::AddKeyword(const TemplateURLData& data) {
if (batch_mode_level_) {
diff --git a/chromium/components/search_engines/keyword_web_data_service.h b/chromium/components/search_engines/keyword_web_data_service.h
index 12ede63818d..f97f03638db 100644
--- a/chromium/components/search_engines/keyword_web_data_service.h
+++ b/chromium/components/search_engines/keyword_web_data_service.h
@@ -61,12 +61,13 @@ class KeywordWebDataService : public WebDataServiceBase {
DISALLOW_COPY_AND_ASSIGN(BatchModeScoper);
};
- KeywordWebDataService(scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- const ProfileErrorCallback& callback);
+ KeywordWebDataService(
+ scoped_refptr<WebDatabaseService> wdbs,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const ProfileErrorCallback& callback);
- // As the database processes requests at a later date, all deletion is
- // done on the background thread.
+ // As the database processes requests at a later date, all deletion is done on
+ // the background sequence.
//
// Many of the keyword related methods do not return a handle. This is because
// the caller (TemplateURLService) does not need to know when the request is
@@ -95,7 +96,7 @@ class KeywordWebDataService : public WebDataServiceBase {
//////////////////////////////////////////////////////////////////////////////
//
- // The following methods are only invoked on the DB thread.
+ // The following methods are only invoked on the DB sequence.
//
//////////////////////////////////////////////////////////////////////////////
WebDatabase::State PerformKeywordOperationsImpl(
diff --git a/chromium/components/search_engines/prepopulated_engines.json b/chromium/components/search_engines/prepopulated_engines.json
index 02999b593bc..212a8167d93 100644
--- a/chromium/components/search_engines/prepopulated_engines.json
+++ b/chromium/components/search_engines/prepopulated_engines.json
@@ -146,7 +146,7 @@
"name": "@MAIL.RU",
"keyword": "mail.ru",
"favicon_url": "https://go.imgsmail.ru/favicon.ico",
- "search_url": "https://go.mail.ru/search?q={searchTerms}",
+ "search_url": "https://go.mail.ru/search?q={searchTerms}&{mailru:referralID}",
"encoding": "windows-1251",
"suggest_url": "https://suggests.go.mail.ru/chrome?q={searchTerms}",
"type": "SEARCH_ENGINE_MAILRU",
diff --git a/chromium/components/search_engines/prepopulated_engines_schema.json b/chromium/components/search_engines/prepopulated_engines_schema.json
index b27caf2bd38..02757abefbc 100644
--- a/chromium/components/search_engines/prepopulated_engines_schema.json
+++ b/chromium/components/search_engines/prepopulated_engines_schema.json
@@ -32,7 +32,11 @@
{ "field": "new_tab_url", "type": "string", "optional": true },
// If omitted, this engine does not support contextual search.
{ "field": "contextual_search_url", "type": "string", "optional": true },
+ // If omitted, this engine does not support a static logo.
{ "field": "logo_url", "type": "string", "optional": true },
+ // If omitted, this engine does not support doodles. Note: Only at most one
+ // of "doodle_url" and "logo_url" should be set.
+ { "field": "doodle_url", "type": "string", "optional": true },
// The followings are post parameters for the corresponding search URL.
// If omitted, a GET request will be sent when using the corresponding
// search URL. Otherwise, a POST request will be sent.
diff --git a/chromium/components/search_engines/search_terms_data.cc b/chromium/components/search_engines/search_terms_data.cc
index d532ae61c8c..a976227e890 100644
--- a/chromium/components/search_engines/search_terms_data.cc
+++ b/chromium/components/search_engines/search_terms_data.cc
@@ -70,3 +70,7 @@ std::string SearchTermsData::GoogleImageSearchSource() const {
std::string SearchTermsData::GetYandexReferralID() const {
return std::string();
}
+
+std::string SearchTermsData::GetMailRUReferralID() 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 c72b99222f4..302c906f831 100644
--- a/chromium/components/search_engines/search_terms_data.h
+++ b/chromium/components/search_engines/search_terms_data.h
@@ -65,6 +65,10 @@ class SearchTermsData {
// the omnibox (returns the empty string if not supported/applicable).
virtual std::string GetYandexReferralID() const;
+ // Returns the optional referral ID to be passed to @MAIL.RU when searching
+ // from the omnibox (returns the empty string if not supported/applicable).
+ virtual std::string GetMailRUReferralID() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(SearchTermsData);
};
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index 1478d897802..0316dd8734b 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -659,6 +659,8 @@ bool TemplateURLRef::ParseParameter(size_t start,
replacements->push_back(Replacement(GOOGLE_UNESCAPED_SEARCH_TERMS, start));
} else if (parameter == "yandex:referralID") {
replacements->push_back(Replacement(YANDEX_REFERRAL_ID, start));
+ } else if (parameter == "mailru:referralID") {
+ replacements->push_back(Replacement(MAIL_RU_REFERRAL_ID, start));
} else if (parameter == "yandex:searchPath") {
switch (ui::GetDeviceFormFactor()) {
case ui::DEVICE_FORM_FACTOR_DESKTOP:
@@ -1141,6 +1143,13 @@ std::string TemplateURLRef::HandleReplacements(
break;
}
+ case MAIL_RU_REFERRAL_ID: {
+ std::string referral_id = search_terms_data.GetMailRUReferralID();
+ if (!referral_id.empty())
+ HandleReplacement("gp", referral_id, *i, &url);
+ break;
+ }
+
default:
NOTREACHED();
break;
diff --git a/chromium/components/search_engines/template_url.h b/chromium/components/search_engines/template_url.h
index 7fd245b1e67..e5cb8df5642 100644
--- a/chromium/components/search_engines/template_url.h
+++ b/chromium/components/search_engines/template_url.h
@@ -110,7 +110,7 @@ class TemplateURLRef {
base::string16 original_query;
// The type the original input query was identified as.
- metrics::OmniboxInputType::Type input_type;
+ metrics::OmniboxInputType input_type;
// The optional assisted query stats, aka AQS, used for logging purposes.
// This string contains impressions of all autocomplete matches shown
@@ -326,6 +326,7 @@ class TemplateURLRef {
GOOGLE_SUGGEST_REQUEST_ID,
GOOGLE_UNESCAPED_SEARCH_TERMS,
LANGUAGE,
+ MAIL_RU_REFERRAL_ID,
SEARCH_TERMS,
YANDEX_REFERRAL_ID,
};
@@ -570,6 +571,8 @@ class TemplateURL {
const GURL& logo_url() const { return data_.logo_url; }
+ const GURL& doodle_url() const { return data_.doodle_url; }
+
const GURL& originating_url() const { return data_.originating_url; }
bool safe_for_autoreplace() const { return data_.safe_for_autoreplace; }
diff --git a/chromium/components/search_engines/template_url_data.cc b/chromium/components/search_engines/template_url_data.cc
index 84adb1aa87d..1f9c5d5a212 100644
--- a/chromium/components/search_engines/template_url_data.cc
+++ b/chromium/components/search_engines/template_url_data.cc
@@ -35,6 +35,7 @@ TemplateURLData::TemplateURLData(const base::string16& name,
base::StringPiece new_tab_url,
base::StringPiece contextual_search_url,
base::StringPiece logo_url,
+ base::StringPiece doodle_url,
base::StringPiece search_url_post_params,
base::StringPiece suggest_url_post_params,
base::StringPiece instant_url_post_params,
@@ -44,17 +45,18 @@ TemplateURLData::TemplateURLData(const base::string16& name,
const base::ListValue& alternate_urls_list,
base::StringPiece search_terms_replacement_key,
int prepopulate_id)
- : suggestions_url(suggest_url.as_string()),
- instant_url(instant_url.as_string()),
- image_url(image_url.as_string()),
- new_tab_url(new_tab_url.as_string()),
- contextual_search_url(contextual_search_url.as_string()),
- logo_url(GURL(logo_url)),
- search_url_post_params(search_url_post_params.as_string()),
- suggestions_url_post_params(suggest_url_post_params.as_string()),
- instant_url_post_params(instant_url_post_params.as_string()),
- image_url_post_params(image_url_post_params.as_string()),
- favicon_url(GURL(favicon_url)),
+ : suggestions_url(suggest_url),
+ instant_url(instant_url),
+ image_url(image_url),
+ new_tab_url(new_tab_url),
+ contextual_search_url(contextual_search_url),
+ logo_url(logo_url),
+ doodle_url(doodle_url),
+ search_url_post_params(search_url_post_params),
+ suggestions_url_post_params(suggest_url_post_params),
+ instant_url_post_params(instant_url_post_params),
+ image_url_post_params(image_url_post_params),
+ favicon_url(favicon_url),
safe_for_autoreplace(true),
id(0),
date_created(base::Time()),
@@ -63,7 +65,7 @@ TemplateURLData::TemplateURLData(const base::string16& name,
usage_count(0),
prepopulate_id(prepopulate_id),
sync_guid(base::GenerateGUID()),
- search_terms_replacement_key(search_terms_replacement_key.as_string()) {
+ search_terms_replacement_key(search_terms_replacement_key) {
SetShortName(name);
SetKeyword(keyword);
SetURL(search_url.as_string());
diff --git a/chromium/components/search_engines/template_url_data.h b/chromium/components/search_engines/template_url_data.h
index 6ad8be2817d..f970bd5e178 100644
--- a/chromium/components/search_engines/template_url_data.h
+++ b/chromium/components/search_engines/template_url_data.h
@@ -38,6 +38,7 @@ struct TemplateURLData {
base::StringPiece new_tab_url,
base::StringPiece contextual_search_url,
base::StringPiece logo_url,
+ base::StringPiece doodle_url,
base::StringPiece search_url_post_params,
base::StringPiece suggest_url_post_params,
base::StringPiece instant_url_post_params,
@@ -75,6 +76,9 @@ struct TemplateURLData {
// Optional URL for the logo.
GURL logo_url;
+ // Optional URL for the Doodle.
+ GURL doodle_url;
+
// The following post_params are comma-separated lists used to specify the
// post parameters for the corresponding URL.
std::string search_url_post_params;
diff --git a/chromium/components/search_engines/template_url_data_util.cc b/chromium/components/search_engines/template_url_data_util.cc
index 8712307e23e..1e427b9498f 100644
--- a/chromium/components/search_engines/template_url_data_util.cc
+++ b/chromium/components/search_engines/template_url_data_util.cc
@@ -50,12 +50,15 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
std::string favicon_url;
std::string originating_url;
std::string logo_url;
+ std::string doodle_url;
dict.GetString(DefaultSearchManager::kFaviconURL, &favicon_url);
dict.GetString(DefaultSearchManager::kOriginatingURL, &originating_url);
dict.GetString(DefaultSearchManager::kLogoURL, &logo_url);
+ dict.GetString(DefaultSearchManager::kDoodleURL, &doodle_url);
result->favicon_url = GURL(favicon_url);
result->originating_url = GURL(originating_url);
result->logo_url = GURL(logo_url);
+ result->doodle_url = GURL(doodle_url);
dict.GetString(DefaultSearchManager::kSearchURLPostParams,
&result->search_url_post_params);
@@ -137,6 +140,7 @@ std::unique_ptr<base::DictionaryValue> TemplateURLDataToDictionary(
url_dict->SetString(DefaultSearchManager::kOriginatingURL,
data.originating_url.spec());
url_dict->SetString(DefaultSearchManager::kLogoURL, data.logo_url.spec());
+ url_dict->SetString(DefaultSearchManager::kDoodleURL, data.doodle_url.spec());
url_dict->SetString(DefaultSearchManager::kSearchURLPostParams,
data.search_url_post_params);
@@ -191,7 +195,7 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromPrepopulatedEngine(
base::WideToUTF16(engine.name), base::WideToUTF16(engine.keyword),
engine.search_url, engine.suggest_url, engine.instant_url,
engine.image_url, engine.new_tab_url, engine.contextual_search_url,
- engine.logo_url, engine.search_url_post_params,
+ engine.logo_url, engine.doodle_url, engine.search_url_post_params,
engine.suggest_url_post_params, engine.instant_url_post_params,
engine.image_url_post_params, engine.favicon_url, engine.encoding,
alternate_urls, engine.search_terms_replacement_key, engine.id);
@@ -219,6 +223,7 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromOverrideDictionary(
std::string new_tab_url;
std::string contextual_search_url;
std::string logo_url;
+ std::string doodle_url;
std::string search_url_post_params;
std::string suggest_url_post_params;
std::string instant_url_post_params;
@@ -232,6 +237,7 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromOverrideDictionary(
engine.GetString("new_tab_url", &new_tab_url);
engine.GetString("contextual_search_url", &contextual_search_url);
engine.GetString("logo_url", &logo_url);
+ engine.GetString("doodle_url", &doodle_url);
engine.GetString("search_url_post_params", &search_url_post_params);
engine.GetString("suggest_url_post_params", &suggest_url_post_params);
engine.GetString("instant_url_post_params", &instant_url_post_params);
@@ -241,10 +247,10 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromOverrideDictionary(
&search_terms_replacement_key);
return base::MakeUnique<TemplateURLData>(
name, keyword, search_url, suggest_url, instant_url, image_url,
- new_tab_url, contextual_search_url, logo_url, search_url_post_params,
- suggest_url_post_params, instant_url_post_params, image_url_post_params,
- favicon_url, encoding, *alternate_urls, search_terms_replacement_key,
- id);
+ new_tab_url, contextual_search_url, logo_url, doodle_url,
+ search_url_post_params, suggest_url_post_params,
+ instant_url_post_params, image_url_post_params, favicon_url, encoding,
+ *alternate_urls, search_terms_replacement_key, id);
}
return std::unique_ptr<TemplateURLData>();
}
diff --git a/chromium/components/search_engines/template_url_fetcher.cc b/chromium/components/search_engines/template_url_fetcher.cc
index eb9e90af07e..bd8e084b1ae 100644
--- a/chromium/components/search_engines/template_url_fetcher.cc
+++ b/chromium/components/search_engines/template_url_fetcher.cc
@@ -37,7 +37,7 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
destination: WEBSITE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification:
"Not implemented, considered not useful as this feature does not "
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.cc b/chromium/components/search_engines/template_url_prepopulate_data.cc
index b361e6ea087..4a6eb92dedf 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data.cc
@@ -49,461 +49,563 @@ namespace {
// first. The default will be the first engine.
// Default (for countries with no better engine set)
-const PrepopulatedEngine* engines_default[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_default[] = {
+ &google, &bing, &yahoo,
+};
// United Arab Emirates
-const PrepopulatedEngine* engines_AE[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_AE[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Albania
-const PrepopulatedEngine* engines_AL[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_AL[] = {
+ &google, &yahoo, &bing,
+};
// Argentina
-const PrepopulatedEngine* engines_AR[] =
- { &google, &bing, &yahoo_ar, };
+const PrepopulatedEngine* const engines_AR[] = {
+ &google, &bing, &yahoo_ar,
+};
// Austria
-const PrepopulatedEngine* engines_AT[] =
- { &google, &bing, &yahoo_at, };
+const PrepopulatedEngine* const engines_AT[] = {
+ &google, &bing, &yahoo_at,
+};
// Australia
-const PrepopulatedEngine* engines_AU[] =
- { &google, &bing, &yahoo_au, };
+const PrepopulatedEngine* const engines_AU[] = {
+ &google, &bing, &yahoo_au,
+};
// Bosnia and Herzegovina
-const PrepopulatedEngine* engines_BA[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_BA[] = {
+ &google, &yahoo, &bing,
+};
// Belgium
-const PrepopulatedEngine* engines_BE[] =
- { &google, &bing, &yahoo, &yahoo_fr, };
+const PrepopulatedEngine* const engines_BE[] = {
+ &google, &bing, &yahoo, &yahoo_fr,
+};
// Bulgaria
-const PrepopulatedEngine* engines_BG[] =
- { &google, &bing, &ask, };
+const PrepopulatedEngine* const engines_BG[] = {
+ &google, &bing, &ask,
+};
// Bahrain
-const PrepopulatedEngine* engines_BH[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_BH[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Burundi
-const PrepopulatedEngine* engines_BI[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_BI[] = {
+ &google, &yahoo, &bing,
+};
// Brunei
-const PrepopulatedEngine* engines_BN[] =
- { &google, &yahoo_my, &bing, };
+const PrepopulatedEngine* const engines_BN[] = {
+ &google, &yahoo_my, &bing,
+};
// Bolivia
-const PrepopulatedEngine* engines_BO[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_BO[] = {
+ &google, &bing, &yahoo,
+};
// Brazil
-const PrepopulatedEngine* engines_BR[] =
- { &google, &ask_br, &bing, &yahoo_br, };
+const PrepopulatedEngine* const engines_BR[] = {
+ &google, &ask_br, &bing, &yahoo_br,
+};
// Belarus
-const PrepopulatedEngine* engines_BY[] =
- { &google, &yandex_by, &mail_ru, };
+const PrepopulatedEngine* const engines_BY[] = {
+ &google, &yandex_by, &mail_ru,
+};
// Belize
-const PrepopulatedEngine* engines_BZ[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_BZ[] = {
+ &google, &yahoo, &bing,
+};
// Canada
-const PrepopulatedEngine* engines_CA[] =
- { &google, &bing, &ask, &yahoo_ca, &yahoo_qc, };
+const PrepopulatedEngine* const engines_CA[] = {
+ &google, &bing, &ask, &yahoo_ca, &yahoo_qc,
+};
// Switzerland
-const PrepopulatedEngine* engines_CH[] =
- { &google, &bing, &yahoo_ch, };
+const PrepopulatedEngine* const engines_CH[] = {
+ &google, &bing, &yahoo_ch,
+};
// Chile
-const PrepopulatedEngine* engines_CL[] =
- { &google, &bing, &yahoo_cl, };
+const PrepopulatedEngine* const engines_CL[] = {
+ &google, &bing, &yahoo_cl,
+};
// China
-const PrepopulatedEngine* engines_CN[] =
- { &google, &baidu, &sogou, &so_360};
+const PrepopulatedEngine* const engines_CN[] = {
+ &google, &baidu, &sogou, &so_360,
+};
// Colombia
-const PrepopulatedEngine* engines_CO[] =
- { &google, &bing, &yahoo_co, };
+const PrepopulatedEngine* const engines_CO[] = {
+ &google, &bing, &yahoo_co,
+};
// Costa Rica
-const PrepopulatedEngine* engines_CR[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_CR[] = {
+ &google, &yahoo, &bing,
+};
// Czech Republic
-const PrepopulatedEngine* engines_CZ[] =
- { &google, &seznam, &bing, };
+const PrepopulatedEngine* const engines_CZ[] = {
+ &google, &seznam, &bing,
+};
// Germany
-const PrepopulatedEngine* engines_DE[] =
- { &google, &bing, &yahoo_de };
+const PrepopulatedEngine* const engines_DE[] = {
+ &google, &bing, &yahoo_de,
+};
// Denmark
-const PrepopulatedEngine* engines_DK[] =
- { &google, &bing, &yahoo_dk, };
+const PrepopulatedEngine* const engines_DK[] = {
+ &google, &bing, &yahoo_dk,
+};
// Dominican Republic
-const PrepopulatedEngine* engines_DO[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_DO[] = {
+ &google, &yahoo, &bing,
+};
// Algeria
-const PrepopulatedEngine* engines_DZ[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_DZ[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// Ecuador
-const PrepopulatedEngine* engines_EC[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_EC[] = {
+ &google, &bing, &yahoo,
+};
// Estonia
-const PrepopulatedEngine* engines_EE[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_EE[] = {
+ &google, &bing, &yahoo,
+};
// Egypt
-const PrepopulatedEngine* engines_EG[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_EG[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Spain
-const PrepopulatedEngine* engines_ES[] =
- { &google, &bing, &yahoo_es, };
+const PrepopulatedEngine* const engines_ES[] = {
+ &google, &bing, &yahoo_es,
+};
// Faroe Islands
-const PrepopulatedEngine* engines_FO[] =
- { &google, &bing, &ask, };
+const PrepopulatedEngine* const engines_FO[] = {
+ &google, &bing, &ask,
+};
// Finland
-const PrepopulatedEngine* engines_FI[] =
- { &google, &bing, &yahoo_fi, };
+const PrepopulatedEngine* const engines_FI[] = {
+ &google, &bing, &yahoo_fi,
+};
// France
-const PrepopulatedEngine* engines_FR[] =
- { &google, &bing, &yahoo_fr, };
+const PrepopulatedEngine* const engines_FR[] = {
+ &google, &bing, &yahoo_fr,
+};
// United Kingdom
-const PrepopulatedEngine* engines_GB[] =
- { &google, &bing, &yahoo_uk, &ask_uk, };
+const PrepopulatedEngine* const engines_GB[] = {
+ &google, &bing, &yahoo_uk, &ask_uk,
+};
// Greece
-const PrepopulatedEngine* engines_GR[] =
- { &google, &bing, &yahoo_gr, };
+const PrepopulatedEngine* const engines_GR[] = {
+ &google, &bing, &yahoo_gr,
+};
// Guatemala
-const PrepopulatedEngine* engines_GT[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_GT[] = {
+ &google, &yahoo, &bing,
+};
// Hong Kong
-const PrepopulatedEngine* engines_HK[] =
- { &google, &yahoo_hk, &baidu, &bing, };
+const PrepopulatedEngine* const engines_HK[] = {
+ &google, &yahoo_hk, &baidu, &bing,
+};
// Honduras
-const PrepopulatedEngine* engines_HN[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_HN[] = {
+ &google, &yahoo, &bing,
+};
// Croatia
-const PrepopulatedEngine* engines_HR[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_HR[] = {
+ &google, &bing, &yahoo,
+};
// Hungary
-const PrepopulatedEngine* engines_HU[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_HU[] = {
+ &google, &bing, &yahoo,
+};
// Indonesia
-const PrepopulatedEngine* engines_ID[] =
- { &google, &yahoo_id, &bing, };
+const PrepopulatedEngine* const engines_ID[] = {
+ &google, &yahoo_id, &bing,
+};
// Ireland
-const PrepopulatedEngine* engines_IE[] =
- { &google, &bing, &yahoo_uk, };
+const PrepopulatedEngine* const engines_IE[] = {
+ &google, &bing, &yahoo_uk,
+};
// Israel
-const PrepopulatedEngine* engines_IL[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_IL[] = {
+ &google, &yahoo, &bing,
+};
// India
-const PrepopulatedEngine* engines_IN[] =
- { &google, &bing, &yahoo_in, };
+const PrepopulatedEngine* const engines_IN[] = {
+ &google, &bing, &yahoo_in,
+};
// Iraq
-const PrepopulatedEngine* engines_IQ[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_IQ[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Iran
-const PrepopulatedEngine* engines_IR[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_IR[] = {
+ &google, &yahoo, &bing,
+};
// Iceland
-const PrepopulatedEngine* engines_IS[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_IS[] = {
+ &google, &bing, &yahoo,
+};
// Italy
-const PrepopulatedEngine* engines_IT[] =
- { &google, &virgilio, &bing, };
+const PrepopulatedEngine* const engines_IT[] = {
+ &google, &virgilio, &bing,
+};
// Jamaica
-const PrepopulatedEngine* engines_JM[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_JM[] = {
+ &google, &yahoo, &bing,
+};
// Jordan
-const PrepopulatedEngine* engines_JO[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_JO[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Japan
-const PrepopulatedEngine* engines_JP[] =
- { &google, &yahoo_jp, &bing, };
+const PrepopulatedEngine* const engines_JP[] = {
+ &google, &yahoo_jp, &bing,
+};
// Kenya
-const PrepopulatedEngine* engines_KE[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_KE[] = {
+ &google, &yahoo, &bing,
+};
// Kuwait
-const PrepopulatedEngine* engines_KW[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_KW[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// South Korea
-const PrepopulatedEngine* engines_KR[] =
- { &google, &naver, &daum, };
+const PrepopulatedEngine* const engines_KR[] = {
+ &google, &naver, &daum,
+};
// Kazakhstan
-const PrepopulatedEngine* engines_KZ[] =
- { &google, &mail_ru, &yandex_kz, };
+const PrepopulatedEngine* const engines_KZ[] = {
+ &google, &mail_ru, &yandex_kz,
+};
// Lebanon
-const PrepopulatedEngine* engines_LB[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_LB[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Liechtenstein
-const PrepopulatedEngine* engines_LI[] =
- { &google, &bing, &yahoo_de, };
+const PrepopulatedEngine* const engines_LI[] = {
+ &google, &bing, &yahoo_de,
+};
// Lithuania
-const PrepopulatedEngine* engines_LT[] =
- { &google, &bing, &yandex_ru, };
+const PrepopulatedEngine* const engines_LT[] = {
+ &google, &bing, &yandex_ru,
+};
// Luxembourg
-const PrepopulatedEngine* engines_LU[] =
- { &google, &bing, &yahoo_fr, };
+const PrepopulatedEngine* const engines_LU[] = {
+ &google, &bing, &yahoo_fr,
+};
// Latvia
-const PrepopulatedEngine* engines_LV[] =
- { &google, &yandex_ru, &bing, };
+const PrepopulatedEngine* const engines_LV[] = {
+ &google, &yandex_ru, &bing,
+};
// Libya
-const PrepopulatedEngine* engines_LY[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_LY[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Morocco
-const PrepopulatedEngine* engines_MA[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_MA[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// Monaco
-const PrepopulatedEngine* engines_MC[] =
- { &google, &yahoo_fr, &bing, };
+const PrepopulatedEngine* const engines_MC[] = {
+ &google, &yahoo_fr, &bing,
+};
// Moldova
-const PrepopulatedEngine* engines_MD[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_MD[] = {
+ &google, &bing, &yahoo,
+};
// Montenegro
-const PrepopulatedEngine* engines_ME[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_ME[] = {
+ &google, &bing, &yahoo,
+};
// Macedonia
-const PrepopulatedEngine* engines_MK[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_MK[] = {
+ &google, &yahoo, &bing,
+};
// Mexico
-const PrepopulatedEngine* engines_MX[] =
- { &google, &bing, &yahoo_mx, };
+const PrepopulatedEngine* const engines_MX[] = {
+ &google, &bing, &yahoo_mx,
+};
// Malaysia
-const PrepopulatedEngine* engines_MY[] =
- { &google, &yahoo_my, &bing, };
+const PrepopulatedEngine* const engines_MY[] = {
+ &google, &yahoo_my, &bing,
+};
// Nicaragua
-const PrepopulatedEngine* engines_NI[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_NI[] = {
+ &google, &yahoo, &bing,
+};
// Netherlands
-const PrepopulatedEngine* engines_NL[] =
- { &google, &yahoo_nl, &vinden, };
+const PrepopulatedEngine* const engines_NL[] = {
+ &google, &yahoo_nl, &vinden,
+};
// Norway
-const PrepopulatedEngine* engines_NO[] =
- { &google, &bing, &kvasir, };
+const PrepopulatedEngine* const engines_NO[] = {
+ &google, &bing, &kvasir,
+};
// New Zealand
-const PrepopulatedEngine* engines_NZ[] =
- { &google, &bing, &yahoo_nz, };
+const PrepopulatedEngine* const engines_NZ[] = {
+ &google, &bing, &yahoo_nz,
+};
// Oman
-const PrepopulatedEngine* engines_OM[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_OM[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// Panama
-const PrepopulatedEngine* engines_PA[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_PA[] = {
+ &google, &yahoo, &bing,
+};
// Peru
-const PrepopulatedEngine* engines_PE[] =
- { &google, &bing, &yahoo_pe, };
+const PrepopulatedEngine* const engines_PE[] = {
+ &google, &bing, &yahoo_pe,
+};
// Philippines
-const PrepopulatedEngine* engines_PH[] =
- { &google, &yahoo_ph, &bing, };
+const PrepopulatedEngine* const engines_PH[] = {
+ &google, &yahoo_ph, &bing,
+};
// Pakistan
-const PrepopulatedEngine* engines_PK[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_PK[] = {
+ &google, &yahoo, &bing,
+};
// Puerto Rico
-const PrepopulatedEngine* engines_PR[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_PR[] = {
+ &google, &yahoo, &bing,
+};
// Poland
-const PrepopulatedEngine* engines_PL[] =
- { &google, &onet, &bing, };
+const PrepopulatedEngine* const engines_PL[] = {
+ &google, &onet, &bing,
+};
// Portugal
-const PrepopulatedEngine* engines_PT[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_PT[] = {
+ &google, &bing, &yahoo,
+};
// Paraguay
-const PrepopulatedEngine* engines_PY[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_PY[] = {
+ &google, &bing, &yahoo,
+};
// Qatar
-const PrepopulatedEngine* engines_QA[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_QA[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Romania
-const PrepopulatedEngine* engines_RO[] =
- { &google, &yahoo_ro, &bing, };
+const PrepopulatedEngine* const engines_RO[] = {
+ &google, &yahoo_ro, &bing,
+};
// Serbia
-const PrepopulatedEngine* engines_RS[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_RS[] = {
+ &google, &bing, &yahoo,
+};
// Russia
-const PrepopulatedEngine* engines_RU[] =
- { &google, &yandex_ru, &mail_ru, };
+const PrepopulatedEngine* const engines_RU[] = {
+ &google, &yandex_ru, &mail_ru,
+};
// Rwanda
-const PrepopulatedEngine* engines_RW[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_RW[] = {
+ &google, &bing, &yahoo,
+};
// Saudi Arabia
-const PrepopulatedEngine* engines_SA[] =
- { &google, &yahoo_maktoob, &bing, };
+const PrepopulatedEngine* const engines_SA[] = {
+ &google, &yahoo_maktoob, &bing,
+};
// Sweden
-const PrepopulatedEngine* engines_SE[] =
- { &google, &bing, &yahoo_se, };
+const PrepopulatedEngine* const engines_SE[] = {
+ &google, &bing, &yahoo_se,
+};
// Singapore
-const PrepopulatedEngine* engines_SG[] =
- { &google, &yahoo_sg, &bing, };
+const PrepopulatedEngine* const engines_SG[] = {
+ &google, &yahoo_sg, &bing,
+};
// Slovenia
-const PrepopulatedEngine* engines_SI[] =
- { &google, &najdi, &ask, };
+const PrepopulatedEngine* const engines_SI[] = {
+ &google, &najdi, &ask,
+};
// Slovakia
-const PrepopulatedEngine* engines_SK[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_SK[] = {
+ &google, &bing, &yahoo,
+};
// El Salvador
-const PrepopulatedEngine* engines_SV[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_SV[] = {
+ &google, &yahoo, &bing,
+};
// Syria
-const PrepopulatedEngine* engines_SY[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_SY[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// Thailand
-const PrepopulatedEngine* engines_TH[] =
- { &google, &yahoo_th, &bing, };
+const PrepopulatedEngine* const engines_TH[] = {
+ &google, &yahoo_th, &bing,
+};
// Tunisia
-const PrepopulatedEngine* engines_TN[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_TN[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// Turkey
-const PrepopulatedEngine* engines_TR[] =
- { &google, &bing, &yahoo_tr, &yandex_tr, };
+const PrepopulatedEngine* const engines_TR[] = {
+ &google, &bing, &yahoo_tr, &yandex_tr,
+};
// Trinidad and Tobago
-const PrepopulatedEngine* engines_TT[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_TT[] = {
+ &google, &bing, &yahoo,
+};
// Taiwan
-const PrepopulatedEngine* engines_TW[] =
- { &google, &yahoo_tw, &bing, };
+const PrepopulatedEngine* const engines_TW[] = {
+ &google, &yahoo_tw, &bing,
+};
// Tanzania
-const PrepopulatedEngine* engines_TZ[] =
- { &google, &yahoo, &bing, };
+const PrepopulatedEngine* const engines_TZ[] = {
+ &google, &yahoo, &bing,
+};
// Ukraine
-const PrepopulatedEngine* engines_UA[] =
- { &google, &yandex_ua, &bing, };
+const PrepopulatedEngine* const engines_UA[] = {
+ &google, &yandex_ua, &bing,
+};
// United States
-const PrepopulatedEngine* engines_US[] =
- { &google, &bing, &yahoo, &aol, &ask, };
+const PrepopulatedEngine* const engines_US[] = {
+ &google, &bing, &yahoo, &aol, &ask,
+};
// Uruguay
-const PrepopulatedEngine* engines_UY[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_UY[] = {
+ &google, &bing, &yahoo,
+};
// Venezuela
-const PrepopulatedEngine* engines_VE[] =
- { &google, &bing, &yahoo_ve, };
+const PrepopulatedEngine* const engines_VE[] = {
+ &google, &bing, &yahoo_ve,
+};
// Vietnam
-const PrepopulatedEngine* engines_VN[] =
- { &google, &yahoo_vn, &bing, };
+const PrepopulatedEngine* const engines_VN[] = {
+ &google, &yahoo_vn, &bing,
+};
// Yemen
-const PrepopulatedEngine* engines_YE[] =
- { &google, &bing, &yahoo_maktoob, };
+const PrepopulatedEngine* const engines_YE[] = {
+ &google, &bing, &yahoo_maktoob,
+};
// South Africa
-const PrepopulatedEngine* engines_ZA[] =
- { &google, &bing, &yahoo, };
+const PrepopulatedEngine* const engines_ZA[] = {
+ &google, &bing, &yahoo,
+};
// Zimbabwe
-const PrepopulatedEngine* engines_ZW[] =
- { &google, &bing, &yahoo, &ask, };
+const PrepopulatedEngine* const engines_ZW[] = {
+ &google, &bing, &yahoo, &ask,
+};
// A list of all the engines that we know about.
-const PrepopulatedEngine* kAllEngines[] = {
- // Prepopulated engines:
- &aol, &ask, &ask_br, &ask_uk, &baidu,
- &bing, &daum, &google, &kvasir, &mail_ru,
- &najdi, &naver, &onet, &seznam, &sogou,
- &vinden, &virgilio, &yahoo, &yahoo_ar, &yahoo_at,
- &yahoo_au, &yahoo_br, &yahoo_ca, &yahoo_ch, &yahoo_cl,
- &yahoo_co, &yahoo_de, &yahoo_dk, &yahoo_es, &yahoo_fi,
- &yahoo_fr, &yahoo_gr, &yahoo_hk, &yahoo_id, &yahoo_in,
- &yahoo_jp, &yahoo_maktoob,&yahoo_mx, &yahoo_my, &yahoo_nl,
- &yahoo_nz, &yahoo_pe, &yahoo_ph, &yahoo_qc, &yahoo_ro,
- &yahoo_se, &yahoo_sg, &yahoo_th, &yahoo_tr, &yahoo_tw,
- &yahoo_uk, &yahoo_ve, &yahoo_vn, &yandex_by, &yandex_kz,
- &yandex_ru, &yandex_tr, &yandex_ua,
-
- // UMA-only engines:
- &atlas_cz, &atlas_sk, &avg, &babylon, &conduit,
- &delfi_lt, &delfi_lv, &delta, &funmoods, &goo,
- &imesh, &iminent, &in, &incredibar, &libero,
- &neti, &nigma, &ok, &rambler, &sapo,
- &search_results, &searchnu, &snapdo, &softonic, &sweetim,
- &terra_ar, &terra_es, &tut, &walla, &wp,
- &zoznam,
+const PrepopulatedEngine* const kAllEngines[] = {
+ // Prepopulated engines:
+ &aol, &ask, &ask_br, &ask_uk, &baidu, &bing, &daum, &google, &kvasir,
+ &mail_ru, &najdi, &naver, &onet, &seznam, &sogou, &vinden, &virgilio,
+ &yahoo, &yahoo_ar, &yahoo_at, &yahoo_au, &yahoo_br, &yahoo_ca, &yahoo_ch,
+ &yahoo_cl, &yahoo_co, &yahoo_de, &yahoo_dk, &yahoo_es, &yahoo_fi, &yahoo_fr,
+ &yahoo_gr, &yahoo_hk, &yahoo_id, &yahoo_in, &yahoo_jp, &yahoo_maktoob,
+ &yahoo_mx, &yahoo_my, &yahoo_nl, &yahoo_nz, &yahoo_pe, &yahoo_ph, &yahoo_qc,
+ &yahoo_ro, &yahoo_se, &yahoo_sg, &yahoo_th, &yahoo_tr, &yahoo_tw, &yahoo_uk,
+ &yahoo_ve, &yahoo_vn, &yandex_by, &yandex_kz, &yandex_ru, &yandex_tr,
+ &yandex_ua,
+
+ // UMA-only engines:
+ &atlas_cz, &atlas_sk, &avg, &babylon, &conduit, &delfi_lt, &delfi_lv,
+ &delta, &funmoods, &goo, &imesh, &iminent, &in, &incredibar, &libero, &neti,
+ &nigma, &ok, &rambler, &sapo, &search_results, &searchnu, &snapdo,
+ &softonic, &sweetim, &terra_ar, &terra_es, &tut, &walla, &wp, &zoznam,
};
// Please refer to ISO 3166-1 for information about the two-character country
@@ -622,7 +724,7 @@ int GetCountryIDFromPrefs(PrefService* prefs) {
std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulationSetFromCountryID(
int country_id) {
- const PrepopulatedEngine** engines;
+ const PrepopulatedEngine* const* engines;
size_t num_engines;
// If you add a new country make sure to update the unit test for coverage.
switch (country_id) {
diff --git a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
index 77e1c585963..51669712583 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
@@ -408,6 +408,12 @@ TEST_F(TemplateURLPrepopulateDataTest, HttpsUrls) {
GURL logo_url = data->logo_url;
EXPECT_TRUE(logo_url.is_empty() || logo_url.SchemeIsCryptographic())
<< logo_url;
+ GURL doodle_url = data->doodle_url;
+ EXPECT_TRUE(doodle_url.is_empty() || doodle_url.SchemeIsCryptographic())
+ << doodle_url;
+ EXPECT_TRUE(logo_url.is_empty() || doodle_url.is_empty())
+ << "Only one of logo_url or doodle_url should be set.";
+
GURL favicon_url = data->favicon_url;
EXPECT_TRUE(favicon_url.is_empty() || favicon_url.SchemeIsCryptographic())
<< favicon_url;
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index 9433205bea4..e64736ae1ed 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -1335,19 +1335,6 @@ TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
// Revert these fields to the built-in values.
UpdateTemplateURLIfPrepopulated(turl.get(), prefs);
- // We used to sync keywords associated with omnibox extensions, but no longer
- // want to. Delete them from the server.
- // TODO(vasilii): After a few Chrome versions, delete this code together with
- // IsOmniboxExtensionURL().
- DCHECK(client);
- if (client->IsOmniboxExtensionURL(turl->url())) {
- change_list->push_back(
- syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_DELETE,
- sync_data));
- return nullptr;
- }
-
DCHECK_EQ(TemplateURL::NORMAL, turl->type());
if (reset_keyword || deduped) {
if (reset_keyword)
diff --git a/chromium/components/search_engines/template_url_service_client.h b/chromium/components/search_engines/template_url_service_client.h
index 77a22d26706..21a1f2400a8 100644
--- a/chromium/components/search_engines/template_url_service_client.h
+++ b/chromium/components/search_engines/template_url_service_client.h
@@ -9,7 +9,6 @@
#include "components/search_engines/template_url_id.h"
class GURL;
-class TemplateURL;
class TemplateURLService;
// This interface provides history related functionality required by
@@ -36,10 +35,6 @@ class TemplateURLServiceClient {
// Adds the given URL to history as a keyword generated visit.
virtual void AddKeywordGeneratedVisit(const GURL& url) = 0;
-
- // Given the main search |url| for a TemplateURL, returns whether the
- // TemplateURL is from an omnibox extension.
- virtual bool IsOmniboxExtensionURL(const std::string& url) = 0;
};
#endif // COMPONENTS_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_CLIENT_H_
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index f269e0f2254..211be3d7eab 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -637,18 +637,16 @@ TEST_F(TemplateURLTest, ReplaceCursorPosition) {
TEST_F(TemplateURLTest, ReplaceInputType) {
struct TestData {
const base::string16 search_term;
- metrics::OmniboxInputType::Type input_type;
+ metrics::OmniboxInputType input_type;
const std::string url;
const std::string expected_result;
} test_data[] = {
- { ASCIIToUTF16("foo"),
- metrics::OmniboxInputType::UNKNOWN,
- "{google:baseURL}?{searchTerms}&{google:inputType}",
- "http://www.google.com/?foo&oit=1&" },
- { ASCIIToUTF16("foo"),
- metrics::OmniboxInputType::URL,
- "{google:baseURL}?{searchTerms}&{google:inputType}",
- "http://www.google.com/?foo&oit=3&" },
+ {ASCIIToUTF16("foo"), metrics::OmniboxInputType::UNKNOWN,
+ "{google:baseURL}?{searchTerms}&{google:inputType}",
+ "http://www.google.com/?foo&oit=1&"},
+ {ASCIIToUTF16("foo"), metrics::OmniboxInputType::URL,
+ "{google:baseURL}?{searchTerms}&{google:inputType}",
+ "http://www.google.com/?foo&oit=3&"},
};
TemplateURLData data;
data.input_encodings.push_back("UTF-8");
diff --git a/chromium/components/search_provider_logos/BUILD.gn b/chromium/components/search_provider_logos/BUILD.gn
index 7b9909e15c6..2f46978884f 100644
--- a/chromium/components/search_provider_logos/BUILD.gn
+++ b/chromium/components/search_provider_logos/BUILD.gn
@@ -14,6 +14,8 @@ static_library("search_provider_logos") {
"logo_cache.h",
"logo_common.cc",
"logo_common.h",
+ "logo_service.cc",
+ "logo_service.h",
"logo_tracker.cc",
"logo_tracker.h",
"switches.cc",
@@ -27,12 +29,56 @@ static_library("search_provider_logos") {
deps = [
"//components/data_use_measurement/core",
+ "//components/image_fetcher/core",
+ "//components/keyed_service/core",
+ "//components/search_engines",
"//net",
"//ui/gfx",
"//url",
]
}
+bundle_data("unit_tests_bundle_data") {
+ visibility = [ ":unit_tests" ]
+ testonly = true
+ sources = [
+ "//components/test/data/search_provider_logos/ddljson_android0.json",
+ "//components/test/data/search_provider_logos/ddljson_android0_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_android1.json",
+ "//components/test/data/search_provider_logos/ddljson_android1_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_android2.json",
+ "//components/test/data/search_provider_logos/ddljson_android2_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_android3.json",
+ "//components/test/data/search_provider_logos/ddljson_android3_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_android4.json",
+ "//components/test/data/search_provider_logos/ddljson_android4_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop0.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop0_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop1.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop1_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop2.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop2_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop3.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop3_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop4.json",
+ "//components/test/data/search_provider_logos/ddljson_desktop4_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_ios0.json",
+ "//components/test/data/search_provider_logos/ddljson_ios0_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_ios1.json",
+ "//components/test/data/search_provider_logos/ddljson_ios1_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_ios2.json",
+ "//components/test/data/search_provider_logos/ddljson_ios2_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_ios3.json",
+ "//components/test/data/search_provider_logos/ddljson_ios3_fp.json",
+ "//components/test/data/search_provider_logos/ddljson_ios4.json",
+ "//components/test/data/search_provider_logos/ddljson_ios4_fp.json",
+ ]
+ outputs = [
+ "{{bundle_resources_dir}}/" +
+ "{{source_root_relative_dir}}/{{source_file_part}}",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
sources = [
@@ -42,6 +88,7 @@ source_set("unit_tests") {
]
deps = [
":search_provider_logos",
+ ":unit_tests_bundle_data",
"//base/test:test_support",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/search_provider_logos/DEPS b/chromium/components/search_provider_logos/DEPS
index 7f085f8d3ba..e5c2279becf 100644
--- a/chromium/components/search_provider_logos/DEPS
+++ b/chromium/components/search_provider_logos/DEPS
@@ -1,5 +1,8 @@
include_rules = [
"+components/data_use_measurement/core",
+ "+components/image_fetcher/core",
+ "+components/keyed_service/core",
+ "+components/search_engines",
"+net",
"+third_party/skia/include/core/SkBitmap.h",
"+ui/gfx/image",
diff --git a/chromium/components/search_provider_logos/OWNERS b/chromium/components/search_provider_logos/OWNERS
index db0aa591a2c..0acaad40b97 100644
--- a/chromium/components/search_provider_logos/OWNERS
+++ b/chromium/components/search_provider_logos/OWNERS
@@ -1,3 +1,5 @@
bauerb@chromium.org
justincohen@chromium.org
treib@chromium.org
+
+# COMPONENT: UI>Browser>NewTabPage
diff --git a/chromium/components/search_provider_logos/features.cc b/chromium/components/search_provider_logos/features.cc
index 1326c7f639a..a5529bade17 100644
--- a/chromium/components/search_provider_logos/features.cc
+++ b/chromium/components/search_provider_logos/features.cc
@@ -10,5 +10,13 @@ namespace features {
const base::Feature kUseDdljsonApi{"UseDdljsonApi",
base::FEATURE_DISABLED_BY_DEFAULT};
+const char kDdljsonOverrideUrlParam[] = "ddljson-override-url";
+
+const base::Feature kThirdPartyDoodles{"ThirdPartyDoodles",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kThirdPartyDoodlesOverrideUrlParam[] =
+ "third-party-doodles-override-url";
+
} // namespace features
} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/features.h b/chromium/components/search_provider_logos/features.h
index 05c46e5e65c..0628b2cf870 100644
--- a/chromium/components/search_provider_logos/features.h
+++ b/chromium/components/search_provider_logos/features.h
@@ -10,8 +10,22 @@
namespace search_provider_logos {
namespace features {
+// If enabled, Google Doodles are fetched from the newer /ddljson API instead of
+// the /newtab_mobile API.
extern const base::Feature kUseDdljsonApi;
+// This parameter can be used to override the URL of the /ddljson API. Useful
+// for testing.
+extern const char kDdljsonOverrideUrlParam[];
+
+// If enabled, Doodles are fetched for third-party search engines that specify
+// a doodle_url in prepopulated_engines.json.
+extern const base::Feature kThirdPartyDoodles;
+
+// This parameter can be used to override the URL of the doodle API for
+// third-party search engines. Useful for testing.
+extern const char kThirdPartyDoodlesOverrideUrlParam[];
+
} // namespace features
} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/google_logo_api.cc b/chromium/components/search_provider_logos/google_logo_api.cc
index 2750c90df8d..467b3c0b7be 100644
--- a/chromium/components/search_provider_logos/google_logo_api.cc
+++ b/chromium/components/search_provider_logos/google_logo_api.cc
@@ -16,6 +16,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/metrics/field_trial_params.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/values.h"
@@ -25,10 +26,21 @@
namespace search_provider_logos {
GURL GetGoogleDoodleURL(const GURL& google_base_url) {
+ std::string override_url = base::GetFieldTrialParamValueByFeature(
+ features::kUseDdljsonApi, features::kDdljsonOverrideUrlParam);
+ if (!override_url.empty()) {
+ return GURL(override_url);
+ }
+ bool use_ddljson_api = base::FeatureList::IsEnabled(features::kUseDdljsonApi);
GURL::Replacements replacements;
- replacements.SetPathStr(base::FeatureList::IsEnabled(features::kUseDdljsonApi)
- ? "async/ddljson"
- : "async/newtab_mobile");
+ replacements.SetPathStr(use_ddljson_api ? "async/ddljson"
+ : "async/newtab_mobile");
+ // Make sure we use https rather than http (except for .cn).
+ if (use_ddljson_api && google_base_url.SchemeIs(url::kHttpScheme) &&
+ !base::EndsWith(google_base_url.host_piece(), ".cn",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ replacements.SetSchemeStr(url::kHttpsScheme);
+ }
return google_base_url.ReplaceComponents(replacements);
}
@@ -152,13 +164,17 @@ std::unique_ptr<EncodedLogo> GoogleLegacyParseLogoResponse(
}
// Don't check return values since these fields are optional.
- logo_dict->GetString("target", &logo->metadata.on_click_url);
+ std::string on_click_url;
+ logo_dict->GetString("target", &on_click_url);
+ logo->metadata.on_click_url = GURL(on_click_url);
logo_dict->GetString("fingerprint", &logo->metadata.fingerprint);
logo_dict->GetString("alt", &logo->metadata.alt_text);
// Existance of url indicates |data| is a call to action image for an
// animated doodle. |url| points to that animated doodle.
- logo_dict->GetString("url", &logo->metadata.animated_url);
+ std::string animated_url;
+ logo_dict->GetString("url", &animated_url);
+ logo->metadata.animated_url = GURL(animated_url);
base::TimeDelta time_to_live;
int time_to_live_ms;
@@ -190,7 +206,7 @@ GURL GoogleNewAppendQueryparamsToLogoURL(bool gray_background,
query += "async=";
- std::vector<base::StringPiece> params;
+ std::vector<std::string> params;
params.push_back("ntp:1");
if (gray_background) {
params.push_back("graybg:1");
@@ -264,14 +280,13 @@ std::unique_ptr<EncodedLogo> GoogleNewParseLogoResponse(
bool is_animated = false;
const base::DictionaryValue* image = nullptr;
if (ddljson->GetDictionary("large_image", &image)) {
- image->GetBoolean("is_animated", &is_animated);
+ image->GetBoolean("is_animated_gif", &is_animated);
// If animated, get the URL for the animated image.
if (is_animated) {
- GURL animated_url = ParseUrl(*image, "url", base_url);
- if (!animated_url.is_valid())
+ logo->metadata.animated_url = ParseUrl(*image, "url", base_url);
+ if (!logo->metadata.animated_url.is_valid())
return nullptr;
- logo->metadata.animated_url = animated_url.spec();
}
}
@@ -309,8 +324,7 @@ std::unique_ptr<EncodedLogo> GoogleNewParseLogoResponse(
return nullptr;
}
- logo->metadata.on_click_url =
- ParseUrl(*ddljson, "target_url", base_url).spec();
+ logo->metadata.on_click_url = ParseUrl(*ddljson, "target_url", base_url);
ddljson->GetString("alt_text", &logo->metadata.alt_text);
ddljson->GetString("fingerprint", &logo->metadata.fingerprint);
diff --git a/chromium/components/search_provider_logos/google_logo_api.h b/chromium/components/search_provider_logos/google_logo_api.h
index 3c3929eba4e..c8274594403 100644
--- a/chromium/components/search_provider_logos/google_logo_api.h
+++ b/chromium/components/search_provider_logos/google_logo_api.h
@@ -39,13 +39,13 @@ std::unique_ptr<EncodedLogo> GoogleLegacyParseLogoResponse(
bool* parsing_failed);
// Implements AppendQueryparamsToLogoURL, defined in logo_tracker.h, for Google
-// doodles (new ddljson API).
+// or third-party doodles (new ddljson API).
GURL GoogleNewAppendQueryparamsToLogoURL(bool gray_background,
const GURL& logo_url,
const std::string& fingerprint);
-// Implements ParseLogoResponse, defined in logo_tracker.h, for Google doodles
-// (new ddljson API).
+// Implements ParseLogoResponse, defined in logo_tracker.h, for Google or
+// third-party doodles (new ddljson API).
std::unique_ptr<EncodedLogo> GoogleNewParseLogoResponse(
const GURL& base_url,
std::unique_ptr<std::string> response,
diff --git a/chromium/components/search_provider_logos/google_logo_api_unittest.cc b/chromium/components/search_provider_logos/google_logo_api_unittest.cc
index 221ee31afe1..5fcbd9b7676 100644
--- a/chromium/components/search_provider_logos/google_logo_api_unittest.cc
+++ b/chromium/components/search_provider_logos/google_logo_api_unittest.cc
@@ -7,15 +7,60 @@
#include <memory>
#include <string>
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/search_provider_logos/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-using testing::Eq;
-
namespace search_provider_logos {
+TEST(GoogleNewLogoApiTest, UsesHttps) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kUseDdljsonApi);
+
+ // "https://" remains in place, even for .cn.
+ EXPECT_EQ(GURL("https://www.google.com/async/ddljson"),
+ GetGoogleDoodleURL(GURL("https://www.google.com")));
+ EXPECT_EQ(GURL("https://www.google.de/async/ddljson"),
+ GetGoogleDoodleURL(GURL("https://www.google.de")));
+ EXPECT_EQ(GURL("https://www.google.cn/async/ddljson"),
+ GetGoogleDoodleURL(GURL("https://www.google.cn")));
+ EXPECT_EQ(GURL("https://www.google.com.cn/async/ddljson"),
+ GetGoogleDoodleURL(GURL("https://www.google.com.cn")));
+
+ // But "http://" gets replaced by "https://".
+ EXPECT_EQ(GURL("https://www.google.com/async/ddljson"),
+ GetGoogleDoodleURL(GURL("http://www.google.com")));
+ EXPECT_EQ(GURL("https://www.google.de/async/ddljson"),
+ GetGoogleDoodleURL(GURL("http://www.google.de")));
+ // ...except for .cn, which is allowed to keep "http://".
+ EXPECT_EQ(GURL("http://www.google.cn/async/ddljson"),
+ GetGoogleDoodleURL(GURL("http://www.google.cn")));
+ EXPECT_EQ(GURL("http://www.google.com.cn/async/ddljson"),
+ GetGoogleDoodleURL(GURL("http://www.google.com.cn")));
+}
+
+TEST(GoogleNewLogoApiTest, AppendsQueryParams) {
+ const GURL logo_url("https://base.doo/target");
+
+ EXPECT_EQ(
+ GURL("https://base.doo/target?async=ntp:1"),
+ GoogleNewAppendQueryparamsToLogoURL(false, logo_url, std::string()));
+ EXPECT_EQ(GURL("https://base.doo/target?async=ntp:1,graybg:1"),
+ GoogleNewAppendQueryparamsToLogoURL(true, logo_url, std::string()));
+ EXPECT_EQ(
+ GURL("https://base.doo/target?async=ntp:1,es_dfp:fingerprint"),
+ GoogleNewAppendQueryparamsToLogoURL(false, logo_url, "fingerprint"));
+ EXPECT_EQ(
+ GURL("https://base.doo/target?async=ntp:1,graybg:1,es_dfp:fingerprint"),
+ GoogleNewAppendQueryparamsToLogoURL(true, logo_url, "fingerprint"));
+}
+
TEST(GoogleNewLogoApiTest, ResolvesRelativeUrl) {
const GURL base_url("https://base.doo/");
const std::string json = R"json()]}'
@@ -31,7 +76,7 @@ TEST(GoogleNewLogoApiTest, ResolvesRelativeUrl) {
ASSERT_FALSE(failed);
ASSERT_TRUE(logo);
- EXPECT_EQ("https://base.doo/target", logo->metadata.on_click_url);
+ EXPECT_EQ(GURL("https://base.doo/target"), logo->metadata.on_click_url);
}
TEST(GoogleNewLogoApiTest, DoesNotResolveAbsoluteUrl) {
@@ -49,7 +94,7 @@ TEST(GoogleNewLogoApiTest, DoesNotResolveAbsoluteUrl) {
ASSERT_FALSE(failed);
ASSERT_TRUE(logo);
- EXPECT_EQ("https://www.doodle.com/target", logo->metadata.on_click_url);
+ EXPECT_EQ(GURL("https://www.doodle.com/target"), logo->metadata.on_click_url);
}
TEST(GoogleNewLogoApiTest, ParsesStaticImage) {
@@ -80,7 +125,7 @@ TEST(GoogleNewLogoApiTest, ParsesAnimatedImage) {
"ddljson": {
"target_url": "/target",
"large_image": {
- "is_animated": true,
+ "is_animated_gif": true,
"url": "https://www.doodle.com/image.gif"
},
"cta_data_uri": "data:image/png;base64,YWJj"
@@ -93,8 +138,57 @@ TEST(GoogleNewLogoApiTest, ParsesAnimatedImage) {
ASSERT_FALSE(failed);
ASSERT_TRUE(logo);
- EXPECT_EQ("https://www.doodle.com/image.gif", logo->metadata.animated_url);
+ EXPECT_EQ(GURL("https://www.doodle.com/image.gif"),
+ logo->metadata.animated_url);
EXPECT_EQ("abc", logo->encoded_image->data());
}
+TEST(GoogleNewLogoApiTest, ParsesCapturedApiResult) {
+ const GURL base_url("https://base.doo/");
+
+ base::FilePath test_data_dir;
+ ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+ test_data_dir = test_data_dir.AppendASCII("components")
+ .AppendASCII("test")
+ .AppendASCII("data")
+ .AppendASCII("search_provider_logos");
+
+ const struct TestCase {
+ const char* file;
+ bool has_image_data;
+ } test_cases[] = {
+ {"ddljson_android0.json", true}, {"ddljson_android0_fp.json", false},
+ {"ddljson_android1.json", true}, {"ddljson_android1_fp.json", false},
+ {"ddljson_android2.json", true}, {"ddljson_android2_fp.json", false},
+ {"ddljson_android3.json", true}, {"ddljson_android3_fp.json", false},
+ {"ddljson_android4.json", true}, {"ddljson_android4_fp.json", false},
+ {"ddljson_desktop0.json", true}, {"ddljson_desktop0_fp.json", false},
+ {"ddljson_desktop1.json", true}, {"ddljson_desktop1_fp.json", false},
+ {"ddljson_desktop2.json", true}, {"ddljson_desktop2_fp.json", false},
+ {"ddljson_desktop3.json", true}, {"ddljson_desktop3_fp.json", false},
+ {"ddljson_desktop4.json", true}, {"ddljson_desktop4_fp.json", false},
+ {"ddljson_ios0.json", true}, {"ddljson_ios0_fp.json", false},
+ {"ddljson_ios1.json", true}, {"ddljson_ios1_fp.json", false},
+ {"ddljson_ios2.json", true}, {"ddljson_ios2_fp.json", false},
+ {"ddljson_ios3.json", true}, {"ddljson_ios3_fp.json", false},
+ {"ddljson_ios4.json", true}, {"ddljson_ios4_fp.json", false},
+ };
+
+ for (const TestCase& test_case : test_cases) {
+ std::string json;
+ ASSERT_TRUE(base::ReadFileToString(
+ test_data_dir.AppendASCII(test_case.file), &json))
+ << test_case.file;
+
+ bool failed = false;
+ std::unique_ptr<EncodedLogo> logo = GoogleNewParseLogoResponse(
+ base_url, base::MakeUnique<std::string>(json), base::Time(), &failed);
+
+ EXPECT_FALSE(failed) << test_case.file;
+ EXPECT_TRUE(logo) << test_case.file;
+ bool has_image_data = logo && logo->encoded_image.get();
+ EXPECT_EQ(has_image_data, test_case.has_image_data) << test_case.file;
+ }
+}
+
} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/logo_cache.cc b/chromium/components/search_provider_logos/logo_cache.cc
index 3c4b2728eb9..e9724038360 100644
--- a/chromium/components/search_provider_logos/logo_cache.cc
+++ b/chromium/components/search_provider_logos/logo_cache.cc
@@ -128,11 +128,14 @@ std::unique_ptr<LogoMetadata> LogoCache::LogoMetadataFromString(
return nullptr;
std::unique_ptr<LogoMetadata> metadata(new LogoMetadata());
- if (!dict->GetString(kSourceUrlKey, &metadata->source_url) ||
+ std::string source_url;
+ std::string on_click_url;
+ std::string animated_url;
+ if (!dict->GetString(kSourceUrlKey, &source_url) ||
!dict->GetString(kFingerprintKey, &metadata->fingerprint) ||
- !dict->GetString(kOnClickURLKey, &metadata->on_click_url) ||
+ !dict->GetString(kOnClickURLKey, &on_click_url) ||
!dict->GetString(kAltTextKey, &metadata->alt_text) ||
- !dict->GetString(kAnimatedUrlKey, &metadata->animated_url) ||
+ !dict->GetString(kAnimatedUrlKey, &animated_url) ||
!dict->GetString(kMimeTypeKey, &metadata->mime_type) ||
!dict->GetBoolean(kCanShowAfterExpirationKey,
&metadata->can_show_after_expiration) ||
@@ -140,6 +143,9 @@ std::unique_ptr<LogoMetadata> LogoCache::LogoMetadataFromString(
!GetTimeValue(*dict, kExpirationTimeKey, &metadata->expiration_time)) {
return nullptr;
}
+ metadata->source_url = GURL(source_url);
+ metadata->on_click_url = GURL(on_click_url);
+ metadata->animated_url = GURL(animated_url);
return metadata;
}
@@ -149,11 +155,11 @@ void LogoCache::LogoMetadataToString(const LogoMetadata& metadata,
int num_bytes,
std::string* str) {
base::DictionaryValue dict;
- dict.SetString(kSourceUrlKey, metadata.source_url);
+ dict.SetString(kSourceUrlKey, metadata.source_url.spec());
dict.SetString(kFingerprintKey, metadata.fingerprint);
- dict.SetString(kOnClickURLKey, metadata.on_click_url);
+ dict.SetString(kOnClickURLKey, metadata.on_click_url.spec());
dict.SetString(kAltTextKey, metadata.alt_text);
- dict.SetString(kAnimatedUrlKey, metadata.animated_url);
+ dict.SetString(kAnimatedUrlKey, metadata.animated_url.spec());
dict.SetString(kMimeTypeKey, metadata.mime_type);
dict.SetBoolean(kCanShowAfterExpirationKey,
metadata.can_show_after_expiration);
diff --git a/chromium/components/search_provider_logos/logo_cache_unittest.cc b/chromium/components/search_provider_logos/logo_cache_unittest.cc
index 2e0ca57f949..2060a27100f 100644
--- a/chromium/components/search_provider_logos/logo_cache_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_cache_unittest.cc
@@ -22,13 +22,13 @@ namespace search_provider_logos {
LogoMetadata GetExampleMetadata() {
LogoMetadata metadata;
- metadata.source_url = "http://google.com/mylogo";
+ metadata.source_url = GURL("http://google.com/mylogo");
metadata.fingerprint = "LC4JVIZ5HVITQFKH0V70";
EXPECT_TRUE(base::Time::FromString("98-05-05 05:05:06 GMT",
&metadata.expiration_time));
metadata.can_show_after_expiration = true;
- metadata.on_click_url = "https://www.google.com/search?q=chicken";
- metadata.animated_url = "http://www.google.com/logos/doodle.png";
+ metadata.on_click_url = GURL("https://www.google.com/search?q=chicken");
+ metadata.animated_url = GURL("http://www.google.com/logos/doodle.png");
metadata.alt_text = "A logo about chickens";
metadata.mime_type = "image/jpeg";
return metadata;
@@ -36,12 +36,12 @@ LogoMetadata GetExampleMetadata() {
LogoMetadata GetExampleMetadata2() {
LogoMetadata metadata;
- metadata.source_url = "https://www.example.com/thebestlogo?size=large";
+ metadata.source_url = GURL("https://www.example.com/thebestlogo?size=large");
metadata.fingerprint = "bh4PLHdnEaQAPxNGRyMao1rOmVFTXuOdVhdrMmPV";
EXPECT_TRUE(base::Time::FromString("17-04-04 07:10:58 GMT",
&metadata.expiration_time));
metadata.can_show_after_expiration = false;
- metadata.on_click_url = "http://www.example.co.uk/welcome.php#top";
+ metadata.on_click_url = GURL("http://www.example.co.uk/welcome.php#top");
metadata.alt_text = "This is a logo";
metadata.mime_type = "image/png";
return metadata;
@@ -180,7 +180,7 @@ TEST_F(LogoCacheTest, StoreAndRetrieveMetadata) {
ExpectMetadata(&metadata);
// Update metadata.
- metadata.on_click_url = "http://anotherwebsite.com";
+ metadata.on_click_url = GURL("http://anotherwebsite.com");
cache_->UpdateCachedLogoMetadata(metadata);
ExpectMetadata(&metadata);
diff --git a/chromium/components/search_provider_logos/logo_common.h b/chromium/components/search_provider_logos/logo_common.h
index fbb3a9c64a0..7c901061da0 100644
--- a/chromium/components/search_provider_logos/logo_common.h
+++ b/chromium/components/search_provider_logos/logo_common.h
@@ -15,8 +15,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkBitmap.h"
-
-class GURL;
+#include "url/gurl.h"
namespace search_provider_logos {
@@ -31,7 +30,7 @@ struct LogoMetadata {
// For use by the client ----------------------------------------------------
// The URL to load when the logo is clicked.
- std::string on_click_url;
+ GURL on_click_url;
// The accessibility text for the logo.
std::string alt_text;
// The mime type of the logo image.
@@ -39,12 +38,12 @@ struct LogoMetadata {
// The URL for an animated image to display when the call to action logo is
// clicked. If |animated_url| is not empty, |encoded_image| refers to a call
// to action image.
- std::string animated_url;
+ GURL animated_url;
// For use by LogoTracker ---------------------------------------------------
// The URL from which the logo was downloaded (without the fingerprint param).
- std::string source_url;
+ GURL source_url;
// A fingerprint (i.e. hash) identifying the logo. Used when revalidating the
// logo with the server.
std::string fingerprint;
diff --git a/chromium/components/search_provider_logos/logo_service.cc b/chromium/components/search_provider_logos/logo_service.cc
new file mode 100644
index 00000000000..aab9569f590
--- /dev/null
+++ b/chromium/components/search_provider_logos/logo_service.cc
@@ -0,0 +1,207 @@
+// 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/search_provider_logos/logo_service.h"
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/search_engines/search_terms_data.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/search_provider_logos/features.h"
+#include "components/search_provider_logos/fixed_logo_api.h"
+#include "components/search_provider_logos/google_logo_api.h"
+#include "components/search_provider_logos/logo_tracker.h"
+#include "components/search_provider_logos/switches.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "ui/gfx/image/image.h"
+
+using search_provider_logos::LogoDelegate;
+using search_provider_logos::LogoTracker;
+
+namespace search_provider_logos {
+namespace {
+
+const int kDecodeLogoTimeoutSeconds = 30;
+
+// Implements a callback for image_fetcher::ImageDecoder. If Run() is called on
+// a callback returned by GetCallback() within 30 seconds, forwards the decoded
+// image to the wrapped callback. If not, sends an empty image to the wrapped
+// callback instead. Either way, deletes the object and prevents further calls.
+//
+// TODO(sfiera): find a more idiomatic way of setting a deadline on the
+// callback. This is implemented as a self-deleting object in part because it
+// needed to when it used to be a delegate and in part because I couldn't figure
+// out a better way, now that it isn't.
+class ImageDecodedHandlerWithTimeout {
+ public:
+ static base::Callback<void(const gfx::Image&)> Wrap(
+ const base::Callback<void(const SkBitmap&)>& image_decoded_callback) {
+ auto* handler = new ImageDecodedHandlerWithTimeout(image_decoded_callback);
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ImageDecodedHandlerWithTimeout::OnImageDecoded,
+ handler->weak_ptr_factory_.GetWeakPtr(), gfx::Image()),
+ base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds));
+ return base::Bind(&ImageDecodedHandlerWithTimeout::OnImageDecoded,
+ handler->weak_ptr_factory_.GetWeakPtr());
+ }
+
+ private:
+ explicit ImageDecodedHandlerWithTimeout(
+ const base::Callback<void(const SkBitmap&)>& image_decoded_callback)
+ : image_decoded_callback_(image_decoded_callback),
+ weak_ptr_factory_(this) {}
+
+ void OnImageDecoded(const gfx::Image& decoded_image) {
+ image_decoded_callback_.Run(decoded_image.AsBitmap());
+ delete this;
+ }
+
+ base::Callback<void(const SkBitmap&)> image_decoded_callback_;
+ base::WeakPtrFactory<ImageDecodedHandlerWithTimeout> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDecodedHandlerWithTimeout);
+};
+
+class LogoDelegateImpl : public search_provider_logos::LogoDelegate {
+ public:
+ explicit LogoDelegateImpl(
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder)
+ : image_decoder_(std::move(image_decoder)) {}
+
+ ~LogoDelegateImpl() override = default;
+
+ // search_provider_logos::LogoDelegate:
+ void DecodeUntrustedImage(
+ const scoped_refptr<base::RefCountedString>& encoded_image,
+ base::Callback<void(const SkBitmap&)> image_decoded_callback) override {
+ image_decoder_->DecodeImage(
+ encoded_image->data(),
+ gfx::Size(), // No particular size desired.
+ ImageDecodedHandlerWithTimeout::Wrap(image_decoded_callback));
+ }
+
+ private:
+ const std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogoDelegateImpl);
+};
+
+} // namespace
+
+LogoService::LogoService(
+ const base::FilePath& cache_directory,
+ TemplateURLService* template_url_service,
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ bool use_gray_background)
+ : cache_directory_(cache_directory),
+ template_url_service_(template_url_service),
+ request_context_getter_(request_context_getter),
+ use_gray_background_(use_gray_background),
+ image_decoder_(std::move(image_decoder)) {}
+
+LogoService::~LogoService() = default;
+
+void LogoService::GetLogo(search_provider_logos::LogoObserver* observer) {
+ if (!template_url_service_) {
+ observer->OnObserverRemoved();
+ return;
+ }
+
+ const TemplateURL* template_url =
+ template_url_service_->GetDefaultSearchProvider();
+ if (!template_url) {
+ observer->OnObserverRemoved();
+ return;
+ }
+
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ GURL logo_url;
+ if (command_line->HasSwitch(switches::kSearchProviderLogoURL)) {
+ logo_url = GURL(
+ command_line->GetSwitchValueASCII(switches::kSearchProviderLogoURL));
+ } else {
+#if defined(OS_ANDROID)
+ // Non-Google default search engine logos are currently enabled only on
+ // Android (https://crbug.com/737283).
+ logo_url = template_url->logo_url();
+#endif
+ }
+
+ GURL base_url;
+ GURL doodle_url;
+ const bool is_google = template_url->url_ref().HasGoogleBaseURLs(
+ template_url_service_->search_terms_data());
+ if (is_google) {
+ // TODO(treib): After features::kUseDdljsonApi has launched, put the Google
+ // doodle URL into prepopulated_engines.json.
+ base_url =
+ GURL(template_url_service_->search_terms_data().GoogleBaseURLValue());
+ doodle_url = search_provider_logos::GetGoogleDoodleURL(base_url);
+ } else if (base::FeatureList::IsEnabled(features::kThirdPartyDoodles)) {
+ // First try to get the Doodle URL from the command line, then from a
+ // feature param, and finally the "real" one from TemplateURL.
+ if (command_line->HasSwitch(switches::kThirdPartyDoodleURL)) {
+ doodle_url = GURL(
+ command_line->GetSwitchValueASCII(switches::kThirdPartyDoodleURL));
+ } else {
+ std::string override_url = base::GetFieldTrialParamValueByFeature(
+ features::kThirdPartyDoodles,
+ features::kThirdPartyDoodlesOverrideUrlParam);
+ if (!override_url.empty()) {
+ doodle_url = GURL(override_url);
+ } else {
+ doodle_url = template_url->doodle_url();
+ }
+ }
+ base_url = doodle_url.GetOrigin();
+ }
+
+ if (!logo_url.is_valid() && !doodle_url.is_valid()) {
+ observer->OnObserverRemoved();
+ return;
+ }
+
+ const bool use_fixed_logo = !doodle_url.is_valid();
+
+ if (!logo_tracker_) {
+ logo_tracker_ = base::MakeUnique<LogoTracker>(
+ cache_directory_, request_context_getter_,
+ base::MakeUnique<LogoDelegateImpl>(std::move(image_decoder_)));
+ }
+
+ if (use_fixed_logo) {
+ logo_tracker_->SetServerAPI(
+ logo_url, base::Bind(&search_provider_logos::ParseFixedLogoResponse),
+ base::Bind(&search_provider_logos::UseFixedLogoUrl));
+ } else if (is_google) {
+ // TODO(treib): Get rid of this Google special case after
+ // features::kUseDdljsonApi has launched.
+ logo_tracker_->SetServerAPI(
+ doodle_url,
+ search_provider_logos::GetGoogleParseLogoResponseCallback(base_url),
+ search_provider_logos::GetGoogleAppendQueryparamsCallback(
+ use_gray_background_));
+ } else {
+ logo_tracker_->SetServerAPI(
+ doodle_url,
+ base::Bind(&search_provider_logos::GoogleNewParseLogoResponse,
+ base_url),
+ base::Bind(&search_provider_logos::GoogleNewAppendQueryparamsToLogoURL,
+ use_gray_background_));
+ }
+
+ logo_tracker_->GetLogo(observer);
+}
+
+} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/logo_service.h b/chromium/components/search_provider_logos/logo_service.h
new file mode 100644
index 00000000000..d7b738dde54
--- /dev/null
+++ b/chromium/components/search_provider_logos/logo_service.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_ANDROID_LOGO_SERVICE_H_
+#define COMPONENTS_SEARCH_PROVIDER_LOGOS_ANDROID_LOGO_SERVICE_H_
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class TemplateURLService;
+
+namespace image_fetcher {
+class ImageDecoder;
+} // namespace image_fetcher
+
+namespace net {
+class URLRequestContextGetter;
+} // namespace net
+
+namespace search_provider_logos {
+
+class LogoTracker;
+class LogoObserver;
+
+// Provides the logo for a profile's default search provider.
+//
+// Example usage:
+// LogoService* logo_service = LogoServiceFactory::GetForProfile(profile);
+// logo_service->GetLogo(...);
+//
+class LogoService : public KeyedService {
+ public:
+ LogoService(
+ const base::FilePath& cache_directory,
+ TemplateURLService* template_url_service,
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ bool use_gray_background);
+ ~LogoService() override;
+
+ // Gets the logo for the default search provider and notifies |observer|
+ // with the results.
+ void GetLogo(search_provider_logos::LogoObserver* observer);
+
+ private:
+ // Constructor arguments.
+ const base::FilePath cache_directory_;
+ TemplateURLService* const template_url_service_;
+ const scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ const bool use_gray_background_;
+
+ // logo_tracker_ takes ownership if/when it is initialized.
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
+
+ // Lazily initialized on first call to GetLogo().
+ std::unique_ptr<search_provider_logos::LogoTracker> logo_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogoService);
+};
+
+} // namespace search_provider_logos
+
+#endif // COMPONENTS_SEARCH_PROVIDER_LOGOS_ANDROID_LOGO_SERVICE_H_
diff --git a/chromium/components/search_provider_logos/logo_tracker.cc b/chromium/components/search_provider_logos/logo_tracker.cc
index 021e52e2ba9..9f0193bae69 100644
--- a/chromium/components/search_provider_logos/logo_tracker.cc
+++ b/chromium/components/search_provider_logos/logo_tracker.cc
@@ -37,10 +37,8 @@ bool IsLogoOkToShow(const LogoMetadata& metadata, base::Time now) {
base::TimeDelta offset =
base::TimeDelta::FromMilliseconds(kMaxTimeToLiveMS * 3 / 2);
base::Time distant_past = now - offset;
- base::Time distant_future = now + offset;
// Sanity check so logos aren't accidentally cached forever.
- if (metadata.expiration_time < distant_past ||
- metadata.expiration_time > distant_future) {
+ if (metadata.expiration_time < distant_past) {
return false;
}
return metadata.can_show_after_expiration || metadata.expiration_time >= now;
@@ -55,8 +53,7 @@ std::unique_ptr<EncodedLogo> GetLogoFromCacheOnFileThread(LogoCache* logo_cache,
if (!metadata)
return nullptr;
- if (metadata->source_url != logo_url.spec() ||
- !IsLogoOkToShow(*metadata, now)) {
+ if (metadata->source_url != logo_url || !IsLogoOkToShow(*metadata, now)) {
logo_cache->SetCachedLogo(NULL);
return nullptr;
}
@@ -135,7 +132,8 @@ void LogoTracker::SetClockForTests(std::unique_ptr<base::Clock> clock) {
void LogoTracker::ReturnToIdle(int outcome) {
if (outcome != kDownloadOutcomeNotTracked) {
- UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoDownloadOutcome", outcome,
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoDownloadOutcome",
+ static_cast<LogoDownloadOutcome>(outcome),
DOWNLOAD_OUTCOME_COUNT);
}
// Cancel the current asynchronous operation, if any.
@@ -227,7 +225,7 @@ void LogoTracker::FetchLogo() {
destination: OTHER
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store: "user"
setting:
"Choosing a non-Google search engine in Chromium settings under "
@@ -252,7 +250,7 @@ void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
DCHECK(!is_idle_);
if (logo)
- logo->metadata.source_url = logo_url_.spec();
+ logo->metadata.source_url = logo_url_;
if (!logo || !logo->encoded_image.get()) {
OnFreshLogoAvailable(std::move(logo), *parsing_failed, from_http_cache,
diff --git a/chromium/components/search_provider_logos/logo_tracker_unittest.cc b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
index 1b634c396cc..23afb2667c3 100644
--- a/chromium/components/search_provider_logos/logo_tracker_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
@@ -26,6 +26,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "components/search_provider_logos/google_logo_api.h"
#include "net/base/url_util.h"
#include "net/http/http_response_headers.h"
@@ -101,10 +102,10 @@ Logo GetSampleLogo(const GURL& logo_url, base::Time response_time) {
logo.metadata.expiration_time =
response_time + base::TimeDelta::FromHours(19);
logo.metadata.fingerprint = "8bc33a80";
- logo.metadata.source_url = logo_url.spec();
- logo.metadata.on_click_url = "http://www.google.com/search?q=potato";
+ logo.metadata.source_url = logo_url;
+ logo.metadata.on_click_url = GURL("http://www.google.com/search?q=potato");
logo.metadata.alt_text = "A logo about potatoes";
- logo.metadata.animated_url = "http://www.google.com/logos/doodle.png";
+ logo.metadata.animated_url = GURL("http://www.google.com/logos/doodle.png");
logo.metadata.mime_type = "image/png";
return logo;
}
@@ -115,8 +116,8 @@ Logo GetSampleLogo2(const GURL& logo_url, base::Time response_time) {
logo.metadata.can_show_after_expiration = true;
logo.metadata.expiration_time = base::Time();
logo.metadata.fingerprint = "71082741021409127";
- logo.metadata.source_url = logo_url.spec();
- logo.metadata.on_click_url = "http://example.com/page25";
+ logo.metadata.source_url = logo_url;
+ logo.metadata.on_click_url = GURL("http://example.com/page25");
logo.metadata.alt_text = "The logo for example.com";
logo.metadata.mime_type = "image/jpeg";
return logo;
@@ -151,13 +152,10 @@ std::string MakeServerResponse(
}
std::string MakeServerResponse(const Logo& logo, base::TimeDelta time_to_live) {
- return MakeServerResponse(logo.image,
- logo.metadata.on_click_url,
- logo.metadata.alt_text,
- logo.metadata.animated_url,
- logo.metadata.mime_type,
- logo.metadata.fingerprint,
- time_to_live);
+ return MakeServerResponse(
+ logo.image, logo.metadata.on_click_url.spec(), logo.metadata.alt_text,
+ logo.metadata.animated_url.spec(), logo.metadata.mime_type,
+ logo.metadata.fingerprint, time_to_live);
}
void ExpectLogosEqual(const Logo* expected_logo,
@@ -457,7 +455,7 @@ TEST_F(LogoTrackerTest, EmptyCacheAndFailedDownload) {
TEST_F(LogoTrackerTest, AcceptMinimalLogoResponse) {
Logo logo;
logo.image = MakeBitmap(1, 2);
- logo.metadata.source_url = logo_url_.spec();
+ logo.metadata.source_url = logo_url_;
logo.metadata.can_show_after_expiration = true;
logo.metadata.mime_type = "image/png";
@@ -524,9 +522,9 @@ TEST_F(LogoTrackerTest, UpdateCachedLogoMetadata) {
Logo fresh_logo = cached_logo;
fresh_logo.image.reset();
fresh_logo.metadata.mime_type.clear();
- fresh_logo.metadata.on_click_url = "http://new.onclick.url";
+ fresh_logo.metadata.on_click_url = GURL("http://new.onclick.url");
fresh_logo.metadata.alt_text = "new alt text";
- fresh_logo.metadata.animated_url = "http://new.animated.url";
+ fresh_logo.metadata.animated_url = GURL("http://new.animated.url");
fresh_logo.metadata.expiration_time =
test_clock_->Now() + base::TimeDelta::FromDays(8);
SetServerResponseWhenFingerprint(fresh_logo.metadata.fingerprint,
@@ -700,7 +698,14 @@ void EnqueueObservers(
base::ConstRef(observers), start_index + 1));
}
-TEST_F(LogoTrackerTest, SupportOverlappingLogoRequests) {
+#if defined(THREAD_SANITIZER)
+// Flakes on Linux TSan: http://crbug/754599 (data race).
+#define MAYBE_SupportOverlappingLogoRequests \
+ DISABLED_SupportOverlappingLogoRequests
+#else
+#define MAYBE_SupportOverlappingLogoRequests SupportOverlappingLogoRequests
+#endif
+TEST_F(LogoTrackerTest, MAYBE_SupportOverlappingLogoRequests) {
Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
logo_cache_->EncodeAndSetCachedLogo(cached_logo);
ON_CALL(*logo_cache_, SetCachedLogo(_)).WillByDefault(Return());
diff --git a/chromium/components/search_provider_logos/switches.cc b/chromium/components/search_provider_logos/switches.cc
index 32679db4c64..cbb86d84212 100644
--- a/chromium/components/search_provider_logos/switches.cc
+++ b/chromium/components/search_provider_logos/switches.cc
@@ -8,7 +8,15 @@ namespace search_provider_logos {
namespace switches {
// Overrides the URL used to fetch the current Google Doodle.
+// Example: https://www.google.com/async/ddljson
const char kGoogleDoodleUrl[] = "google-doodle-url";
+// Use a static URL for the logo of the default search engine.
+// Example: https://www.google.com/branding/logo.png
+const char kSearchProviderLogoURL[] = "search-provider-logo-url";
+
+// Overrides the Doodle URL to use for third-party search engines.
+const char kThirdPartyDoodleURL[] = "third-party-doodle-url";
+
} // namespace switches
} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/switches.h b/chromium/components/search_provider_logos/switches.h
index 385690fe445..a177df5c46f 100644
--- a/chromium/components/search_provider_logos/switches.h
+++ b/chromium/components/search_provider_logos/switches.h
@@ -9,6 +9,9 @@ namespace search_provider_logos {
namespace switches {
extern const char kGoogleDoodleUrl[];
+extern const char kSearchProviderLogoURL[];
+
+extern const char kThirdPartyDoodleURL[];
} // namespace switches
} // namespace search_provider_logos
diff --git a/chromium/components/security_interstitials/content/unsafe_resource.cc b/chromium/components/security_interstitials/content/unsafe_resource.cc
index 410c3c7e46a..2b77bd6663c 100644
--- a/chromium/components/security_interstitials/content/unsafe_resource.cc
+++ b/chromium/components/security_interstitials/content/unsafe_resource.cc
@@ -40,14 +40,19 @@ bool UnsafeResource::IsMainPageLoadBlocked() const {
if (is_subresource)
return false;
- // Client-side phishing/malware detection and password protection phishing
- // interstitials never block the main frame load, since they happen after the
- // page is finished loading.
- if (threat_type == safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING ||
- threat_type == safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE ||
- threat_type ==
- safe_browsing::SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING) {
- return false;
+ switch (threat_type) {
+ // Client-side phishing/malware detection and password protection phishing
+ // interstitials never block the main frame load, since they happen after
+ // the page is finished loading.
+ case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING:
+ case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE:
+ case safe_browsing::SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
+ // Ad sampling happens in the background.
+ case safe_browsing::SB_THREAT_TYPE_AD_SAMPLE:
+ return false;
+
+ default:
+ break;
}
return true;
diff --git a/chromium/components/security_interstitials/core/BUILD.gn b/chromium/components/security_interstitials/core/BUILD.gn
index ec859cf01d4..f1a6a910522 100644
--- a/chromium/components/security_interstitials/core/BUILD.gn
+++ b/chromium/components/security_interstitials/core/BUILD.gn
@@ -14,6 +14,8 @@ static_library("core") {
"controller_client.h",
"metrics_helper.cc",
"metrics_helper.h",
+ "mitm_software_ui.cc",
+ "mitm_software_ui.h",
"safe_browsing_loud_error_ui.cc",
"safe_browsing_loud_error_ui.h",
"safe_browsing_quiet_error_ui.cc",
@@ -26,6 +28,13 @@ static_library("core") {
"urls.h",
]
+ if (is_ios) {
+ sources -= [
+ "mitm_software_ui.cc",
+ "mitm_software_ui.h",
+ ]
+ }
+
deps = [
"//base",
"//base:i18n",
diff --git a/chromium/components/security_interstitials/core/base_safe_browsing_error_ui.h b/chromium/components/security_interstitials/core/base_safe_browsing_error_ui.h
index ccbf9f90429..b4af3936cdc 100644
--- a/chromium/components/security_interstitials/core/base_safe_browsing_error_ui.h
+++ b/chromium/components/security_interstitials/core/base_safe_browsing_error_ui.h
@@ -46,10 +46,16 @@ class BaseSafeBrowsingErrorUI {
// Indicates if user is in incognito mode.
bool is_off_the_record;
- // Indicates if user opted in for SB extended reporting.
+ // Indicates if user opted in for SB extended reporting. This contains only
+ // the value of the pref that is currently active for the user (either the
+ // legacy SBER pref, or the Scout pref). Use |is_scout_reporting_enabled| to
+ // determine which of the prefs is being used.
bool is_extended_reporting_enabled;
- // Indicates if user opted in for Scout extended reporting.
+ // Indicates if extended reporting is controlled by Scout or the legacy SBER
+ // setting. This does NOT indicate whether the user is opted-in to extended
+ // reporting, just the level of reporting that's available to the user. Use
+ // |is_extended_reporting_enabled| to see if the user is opted-in.
bool is_scout_reporting_enabled;
// Indicates if kSafeBrowsingProceedAnywayDisabled preference is set.
diff --git a/chromium/components/security_interstitials/core/browser/resources/list_of_interstitials.html b/chromium/components/security_interstitials/core/browser/resources/list_of_interstitials.html
index d9a13f8bf35..639d6769f94 100644
--- a/chromium/components/security_interstitials/core/browser/resources/list_of_interstitials.html
+++ b/chromium/components/security_interstitials/core/browser/resources/list_of_interstitials.html
@@ -46,6 +46,12 @@
<li>
<a href="superfish-ssl">Superfish</a>
</li>
+ <li>
+ <a href="mitm-software-ssl?enterprise=0">MITM software</a>
+ </li>
+ <li>
+ <a href="mitm-software-ssl?enterprise=1">MITM software on an enterprise-managed machine</a>
+ </li>
</ul>
<h3>SafeBrowsing</h3>
<h4>Loud</h4>
diff --git a/chromium/components/security_interstitials/core/mitm_software_ui.cc b/chromium/components/security_interstitials/core/mitm_software_ui.cc
new file mode 100644
index 00000000000..f15cf8aa72a
--- /dev/null
+++ b/chromium/components/security_interstitials/core/mitm_software_ui.cc
@@ -0,0 +1,137 @@
+// 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/security_interstitials/core/mitm_software_ui.h"
+
+#include "base/i18n/time_formatting.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/security_interstitials/core/common_string_util.h"
+#include "components/security_interstitials/core/metrics_helper.h"
+#include "components/ssl_errors/error_info.h"
+#include "components/strings/grit/components_strings.h"
+#include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace security_interstitials {
+
+MITMSoftwareUI::MITMSoftwareUI(const GURL& request_url,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const std::string& mitm_software_name,
+ bool is_enterprise_managed,
+ ControllerClient* controller)
+ : request_url_(request_url),
+ cert_error_(cert_error),
+ ssl_info_(ssl_info),
+ mitm_software_name_(mitm_software_name),
+ is_enterprise_managed_(is_enterprise_managed),
+ controller_(controller) {
+ controller_->metrics_helper()->RecordUserInteraction(
+ security_interstitials::MetricsHelper::TOTAL_VISITS);
+}
+
+MITMSoftwareUI::~MITMSoftwareUI() {
+ controller_->metrics_helper()->RecordShutdownMetrics();
+}
+
+void MITMSoftwareUI::PopulateStringsForHTML(
+ base::DictionaryValue* load_time_data) {
+ CHECK(load_time_data);
+
+ // Shared with other SSL errors.
+ common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
+ common_string_util::PopulateSSLDebuggingStrings(
+ ssl_info_, base::Time::NowFromSystemTime(), load_time_data);
+
+ // Set display booleans.
+ load_time_data->SetBoolean("overridable", false);
+ load_time_data->SetBoolean("hide_primary_button", true);
+ load_time_data->SetBoolean("bad_clock", false);
+
+ // Set strings that are shared between enterprise and non-enterprise
+ // interstitials.
+ load_time_data->SetString("tabTitle",
+ l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
+ load_time_data->SetString(
+ "heading", l10n_util::GetStringUTF16(IDS_MITM_SOFTWARE_HEADING));
+ load_time_data->SetString("primaryButtonText", std::string());
+ load_time_data->SetString("finalParagraph", std::string());
+
+ if (is_enterprise_managed_) {
+ MITMSoftwareUI::PopulateEnterpriseUserStringsForHTML(load_time_data);
+ return;
+ }
+
+ MITMSoftwareUI::PopulateAtHomeUserStringsForHTML(load_time_data);
+}
+
+void MITMSoftwareUI::HandleCommand(SecurityInterstitialCommands command) {
+ switch (command) {
+ case CMD_DO_REPORT:
+ controller_->SetReportingPreference(true);
+ break;
+ case CMD_DONT_REPORT:
+ controller_->SetReportingPreference(false);
+ break;
+ case CMD_SHOW_MORE_SECTION:
+ controller_->metrics_helper()->RecordUserInteraction(
+ security_interstitials::MetricsHelper::SHOW_ADVANCED);
+ break;
+ case CMD_OPEN_REPORTING_PRIVACY:
+ controller_->OpenExtendedReportingPrivacyPolicy(true);
+ break;
+ case CMD_OPEN_WHITEPAPER:
+ controller_->OpenExtendedReportingWhitepaper(true);
+ break;
+ case CMD_DONT_PROCEED:
+ case CMD_OPEN_HELP_CENTER:
+ case CMD_RELOAD:
+ case CMD_PROCEED:
+ case CMD_OPEN_DATE_SETTINGS:
+ case CMD_OPEN_DIAGNOSTIC:
+ case CMD_OPEN_LOGIN:
+ case CMD_REPORT_PHISHING_ERROR:
+ // Not supported by the SSL error page.
+ NOTREACHED() << "Unsupported command: " << command;
+ case CMD_ERROR:
+ case CMD_TEXT_FOUND:
+ case CMD_TEXT_NOT_FOUND:
+ // Commands are for testing.
+ break;
+ }
+}
+
+void MITMSoftwareUI::PopulateEnterpriseUserStringsForHTML(
+ base::DictionaryValue* load_time_data) {
+ load_time_data->SetString(
+ "primaryParagraph",
+ l10n_util::GetStringFUTF16(
+ IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_ENTERPRISE,
+ net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_))));
+ load_time_data->SetString(
+ "explanationParagraph",
+ l10n_util::GetStringFUTF16(
+ IDS_MITM_SOFTWARE_EXPLANATION_ENTERPRISE,
+ net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_)),
+ l10n_util::GetStringUTF16(IDS_MITM_SOFTWARE_EXPLANATION)));
+}
+
+void MITMSoftwareUI::PopulateAtHomeUserStringsForHTML(
+ base::DictionaryValue* load_time_data) {
+ load_time_data->SetString(
+ "primaryParagraph",
+ l10n_util::GetStringFUTF16(
+ IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_NONENTERPRISE,
+ net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_))));
+ load_time_data->SetString(
+ "explanationParagraph",
+ l10n_util::GetStringFUTF16(
+ IDS_MITM_SOFTWARE_EXPLANATION_NONENTERPRISE,
+ net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_)),
+ l10n_util::GetStringUTF16(IDS_MITM_SOFTWARE_EXPLANATION)));
+}
+
+} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/mitm_software_ui.h b/chromium/components/security_interstitials/core/mitm_software_ui.h
new file mode 100644
index 00000000000..bc862f92bc4
--- /dev/null
+++ b/chromium/components/security_interstitials/core/mitm_software_ui.h
@@ -0,0 +1,49 @@
+// 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_SECURITY_INTERSTITIALS_CORE_MITM_SOFTWARE_UI_H_
+#define COMPONENTS_SECURITY_INTERSTITIALS_CORE_MITM_SOFTWARE_UI_H_
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "components/security_interstitials/core/controller_client.h"
+#include "components/ssl_errors/error_classification.h"
+#include "net/ssl/ssl_info.h"
+#include "url/gurl.h"
+
+namespace security_interstitials {
+
+// Provides UI for SSL errors caused by MITM software misconfigurations.
+class MITMSoftwareUI {
+ public:
+ MITMSoftwareUI(const GURL& request_url,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const std::string& mitm_software_name,
+ bool is_enterprise_managed,
+ ControllerClient* controller_);
+ ~MITMSoftwareUI();
+
+ void PopulateStringsForHTML(base::DictionaryValue* load_time_data);
+ void HandleCommand(SecurityInterstitialCommands command);
+
+ protected:
+ void PopulateEnterpriseUserStringsForHTML(
+ base::DictionaryValue* load_time_data);
+ void PopulateAtHomeUserStringsForHTML(base::DictionaryValue* load_time_data);
+
+ private:
+ const GURL request_url_;
+ const int cert_error_;
+ const net::SSLInfo ssl_info_;
+ const std::string mitm_software_name_;
+ const bool is_enterprise_managed_;
+ ControllerClient* controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MITMSoftwareUI);
+};
+
+} // namespace security_interstitials
+
+#endif // COMPONENTS_SECURITY_INTERSTITIALS_CORE_MITM_SOFTWARE_UI_H
diff --git a/chromium/components/security_interstitials_strings.grdp b/chromium/components/security_interstitials_strings.grdp
index 8d44d5de458..14fe3931c10 100644
--- a/chromium/components/security_interstitials_strings.grdp
+++ b/chromium/components/security_interstitials_strings.grdp
@@ -8,6 +8,62 @@
Hide advanced
</message>
+ <!-- Captive portal interstitial -->
+ <message name="IDS_CAPTIVE_PORTAL_AUTHORIZATION_DIALOG_NAME" desc="Name of the modal Web dialog (displayed in the title) displaying captive portal login page on Chrome OS.">
+ Captive Portal Authorization
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_HEADING_WIRED" desc="Heading in the error page when a secure request is blocked because a captive portal is manipulating a wired connection (e.g. ethernet)">
+ Connect to network
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_HEADING_WIFI" desc="Heading in the error page when a secure request is blocked because a captive portal is manipulating a Wi-Fi connection">
+ Connect to Wi-Fi
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIRED" desc="The primary explanatory paragraph for the captive portal error page for wired network connections.">
+ The network you are using may require you to visit <ph name="BEGIN_BOLD">&lt;strong&gt;</ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD">&lt;/strong&gt;</ph>.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections.">
+ The Wi-Fi you are using may require you to visit <ph name="BEGIN_BOLD">&lt;strong&gt;</ph><ph name="LOGIN_URL">$1<ex>example.com</ex></ph><ph name="END_BOLD">&lt;/strong&gt;</ph>.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI_SSID" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections, displaying the Wi-Fi name.">
+ The Wi-Fi you are using (<ph name="WIFI_NAME">$1<ex>Google Guest</ex></ph>) may require you to visit <ph name="BEGIN_BOLD">&lt;strong&gt;</ph><ph name="LOGIN_URL">$2<ex>example.com</ex></ph><ph name="END_BOLD">&lt;/strong&gt;</ph>.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIRED" desc="The primary explanatory paragraph for the captive portal error page for network connections when the captive portal login url isn't available.">
+ The network you are using may require you to visit its login page.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections when the captive portal login url isn't available.">
+ The Wi-Fi you are using may require you to visit its login page.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI_SSID" desc="The primary explanatory paragraph for the captive portal error page for Wi-Fi connections when the captive portal login url isn't available.">
+ The Wi-Fi you are using (<ph name="WIFI_NAME">$1<ex>Google Guest</ex></ph>) may require you to visit its login page.
+ </message>
+ <message name="IDS_CAPTIVE_PORTAL_BUTTON_OPEN_LOGIN_PAGE" desc="Text for the open login page button">
+ Connect
+ </message>
+
+ <!-- MITM software interstitial -->
+ <message name="IDS_MITM_SOFTWARE_HEADING" desc="Header of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error.">
+ An application is stopping Chrome from safely connecting to this site
+ </message>
+ <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_ENTERPRISE" desc="Main body of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. There is a title above and a button below that exposes more information. ‘IT administrator’ here refers to the information technology expert at the user’s school or company. Placeholder text is the name of a computer program.">
+ &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; wasn’t installed properly on your computer or network. Ask your IT administrator to resolve this issue.
+ </message>
+ <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_NONENTERPRISE" desc="Main body of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. There is a title above and a button below that exposes more information. Placeholder text is the name of a computer program.">
+ &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; wasn’t installed properly on your computer or the network:
+ &lt;ul&gt;
+ &lt;li&gt;Try uninstalling or disabling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot;&lt;/li&gt;
+ &lt;li&gt;Try connecting to another network&lt;/li&gt;
+ &lt;/ul&gt;
+ </message>
+ <message name="IDS_MITM_SOFTWARE_EXPLANATION_ENTERPRISE" desc="Extended description for an error page hidden behind an 'Advanced' button. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title reads 'An application is stopping Chrome from safely connection to this site' and there is a shorter description of the error shown above. First placeholder text is the name of a computer program. Second placeholder text is some further explanation.">
+ A root certificate for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; is required but isn’t installed. Your IT administrator should look at configuration instructions for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; to fix this problem. <ph name="FURTHER_EXPLANATION">$2<ex>Further explanation goes here.</ex></ph>
+ </message>
+ <message name="IDS_MITM_SOFTWARE_EXPLANATION_NONENTERPRISE" desc="Extended description for an error page hidden behind an 'Advanced' button. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title reads 'An application is stopping Chrome from safely connection to this site' and there is a shorter description of the error shown above. First placeholder text is the name of a computer program. Second placeholder text is some further explanation.">
+ &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; isn’t configured correctly. Uninstalling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; usually fixes the problem. <ph name="FURTHER_EXPLANATION">$2<ex>Further explanation goes here.</ex></ph>
+ </message>
+ <message name="IDS_MITM_SOFTWARE_EXPLANATION" desc="Part of an extended description hidden behind an 'Advanced' button on an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title and additional description of the error are shown above. 'Antivirus software' is software that finds and deletes viruses on a user's computer. 'Firewall software' is software typically used on a company network that keeps unwanted people from accessing the network. 'Proxy software' is software on a network that blocks the user from viewing certain websites. Proxies may be used to keep school children from viewing inappropriate websites for example. 'Web-filtering software' is a synonym for proxy software, so it can be excluded in translation.">
+ Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.
+ </message>
+
<!-- Clock errors -->
<message name="IDS_CLOCK_ERROR_TITLE" desc="Tab title. Context: the browser can't load a page because the device's clock is wrong.">
Clock error
@@ -61,9 +117,16 @@
</message>
<!-- SSL error page: Superfish-specific -->
- <message name="IDS_SSL_SUPERFISH_HEADING" desc="The large heading at the top of the Superfish-specific SSL interstitial.">
- Software on your computer is stopping Chrome from safely connecting to the web
- </message>
+ <if expr="_google_chrome">
+ <message name="IDS_SSL_SUPERFISH_HEADING" desc="The large heading at the top of the Superfish-specific SSL interstitial.">
+ Software on your computer is stopping Chrome from safely connecting to the web
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_SSL_SUPERFISH_HEADING" desc="The large heading at the top of the Superfish-specific SSL interstitial.">
+ Software on your computer is stopping Chromium from safely connecting to the web
+ </message>
+ </if>
<message name="IDS_SSL_SUPERFISH_PRIMARY_PARAGRAPH" desc="The primary explanatory paragraph for the Superfish-specific SSL interstitial.">
<ph name="BEGIN_PARAGRAPH">&lt;p&gt;</ph>Follow these steps to temporarily disable the software so you can get on the web. You'll need administrator privileges.<ph name="END_PARAGRAPH">&lt;/p&gt;</ph>
diff --git a/chromium/components/security_state/content/BUILD.gn b/chromium/components/security_state/content/BUILD.gn
index 7d3f5038b01..ce49f5987ab 100644
--- a/chromium/components/security_state/content/BUILD.gn
+++ b/chromium/components/security_state/content/BUILD.gn
@@ -6,6 +6,8 @@ static_library("content") {
sources = [
"content_utils.cc",
"content_utils.h",
+ "ssl_status_input_event_data.cc",
+ "ssl_status_input_event_data.h",
]
public_deps = [
@@ -34,6 +36,7 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//components/security_state/core",
+ "//components/strings",
"//content/public/browser",
"//content/test:test_support",
"//net",
diff --git a/chromium/components/security_state/content/content_utils.cc b/chromium/components/security_state/content/content_utils.cc
index 2832bf0c95f..d7608b4a204 100644
--- a/chromium/components/security_state/content/content_utils.cc
+++ b/chromium/components/security_state/content/content_utils.cc
@@ -11,6 +11,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/security_state/content/ssl_status_input_event_data.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_chromium_strings.h"
#include "components/strings/grit/components_strings.h"
@@ -39,9 +40,7 @@ blink::WebSecurityStyle SecurityLevelToSecurityStyle(
case security_state::NONE:
case security_state::HTTP_SHOW_WARNING:
return blink::kWebSecurityStyleNeutral;
- case security_state::SECURITY_WARNING:
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
- return blink::kWebSecurityStyleWarning;
case security_state::EV_SECURE:
case security_state::SECURE:
return blink::kWebSecurityStyleSecure;
@@ -56,21 +55,27 @@ blink::WebSecurityStyle SecurityLevelToSecurityStyle(
void ExplainHTTPSecurity(
const security_state::SecurityInfo& security_info,
content::SecurityStyleExplanations* security_style_explanations) {
- if (security_info.security_level == security_state::HTTP_SHOW_WARNING) {
- if (security_info.displayed_password_field_on_http ||
- security_info.displayed_credit_card_field_on_http) {
- security_style_explanations->neutral_explanations.push_back(
- content::SecurityStyleExplanation(
- l10n_util::GetStringUTF8(IDS_PRIVATE_USER_DATA_INPUT),
- l10n_util::GetStringUTF8(
- IDS_PRIVATE_USER_DATA_INPUT_DESCRIPTION)));
- }
- if (security_info.incognito_downgraded_security_level) {
- security_style_explanations->neutral_explanations.push_back(
- content::SecurityStyleExplanation(
- l10n_util::GetStringUTF8(IDS_INCOGNITO_NONSECURE),
- l10n_util::GetStringUTF8(IDS_INCOGNITO_NONSECURE_DESCRIPTION)));
- }
+ if (security_info.security_level != security_state::HTTP_SHOW_WARNING)
+ return;
+
+ if (security_info.field_edit_downgraded_security_level) {
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_EDITED_NONSECURE),
+ l10n_util::GetStringUTF8(IDS_EDITED_NONSECURE_DESCRIPTION)));
+ }
+ if (security_info.displayed_password_field_on_http ||
+ security_info.displayed_credit_card_field_on_http) {
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_PRIVATE_USER_DATA_INPUT),
+ l10n_util::GetStringUTF8(IDS_PRIVATE_USER_DATA_INPUT_DESCRIPTION)));
+ }
+ if (security_info.incognito_downgraded_security_level) {
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_INCOGNITO_NONSECURE),
+ l10n_util::GetStringUTF8(IDS_INCOGNITO_NONSECURE_DESCRIPTION)));
}
}
@@ -92,7 +97,7 @@ void ExplainCertificateSecurity(
content::SecurityStyleExplanation(
l10n_util::GetStringUTF8(IDS_SHA1),
l10n_util::GetStringUTF8(IDS_SHA1_DESCRIPTION),
- !!security_info.certificate,
+ security_info.certificate,
blink::WebMixedContentContextType::kNotMixedContent));
}
@@ -101,7 +106,7 @@ void ExplainCertificateSecurity(
content::SecurityStyleExplanation(
l10n_util::GetStringUTF8(IDS_SUBJECT_ALT_NAME_MISSING),
l10n_util::GetStringUTF8(IDS_SUBJECT_ALT_NAME_MISSING_DESCRIPTION),
- !!security_info.certificate,
+ security_info.certificate,
blink::WebMixedContentContextType::kNotMixedContent));
}
@@ -117,7 +122,7 @@ void ExplainCertificateSecurity(
l10n_util::GetStringUTF8(IDS_CERTIFICATE_CHAIN_ERROR),
l10n_util::GetStringFUTF8(
IDS_CERTIFICATE_CHAIN_ERROR_DESCRIPTION_FORMAT, error_string),
- !!security_info.certificate,
+ security_info.certificate,
blink::WebMixedContentContextType::kNotMixedContent);
if (is_cert_status_minor_error) {
@@ -148,7 +153,7 @@ void ExplainCertificateSecurity(
l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE),
l10n_util::GetStringFUTF8(
IDS_VALID_SERVER_CERTIFICATE_DESCRIPTION, issuer_name),
- !!security_info.certificate,
+ security_info.certificate,
blink::WebMixedContentContextType::kNotMixedContent));
}
}
@@ -254,21 +259,46 @@ void ExplainContentSecurity(
SecurityLevelToSecurityStyle(
security_state::kDisplayedInsecureContentLevel);
- // Record the presence of mixed content (HTTP subresources on an HTTPS
- // page).
+ // Add the secure explanation unless there is an issue.
+ bool add_secure_explanation = true;
+
security_style_explanations->ran_mixed_content =
security_info.mixed_content_status ==
security_state::CONTENT_STATUS_RAN ||
security_info.mixed_content_status ==
security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ if (security_style_explanations->ran_mixed_content) {
+ add_secure_explanation = false;
+ security_style_explanations->insecure_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_SUMMARY),
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_DESCRIPTION),
+ nullptr, blink::WebMixedContentContextType::kBlockable));
+ }
+
security_style_explanations->displayed_mixed_content =
security_info.mixed_content_status ==
security_state::CONTENT_STATUS_DISPLAYED ||
security_info.mixed_content_status ==
security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ if (security_style_explanations->displayed_mixed_content) {
+ add_secure_explanation = false;
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_SUMMARY),
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_DESCRIPTION),
+ nullptr, blink::WebMixedContentContextType::kOptionallyBlockable));
+ }
security_style_explanations->contained_mixed_form =
security_info.contained_mixed_form;
+ if (security_style_explanations->contained_mixed_form) {
+ add_secure_explanation = false;
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_NON_SECURE_FORM_SUMMARY),
+ l10n_util::GetStringUTF8(IDS_NON_SECURE_FORM_DESCRIPTION)));
+ }
// If the main resource was loaded with no certificate errors or only minor
// certificate errors, then record the presence of subresources with
@@ -285,11 +315,36 @@ void ExplainContentSecurity(
security_state::CONTENT_STATUS_RAN ||
security_info.content_with_cert_errors_status ==
security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ if (security_style_explanations->ran_content_with_cert_errors) {
+ add_secure_explanation = false;
+ security_style_explanations->insecure_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY),
+ l10n_util::GetStringUTF8(
+ IDS_CERT_ERROR_ACTIVE_CONTENT_DESCRIPTION)));
+ }
+
security_style_explanations->displayed_content_with_cert_errors =
security_info.content_with_cert_errors_status ==
security_state::CONTENT_STATUS_DISPLAYED ||
security_info.content_with_cert_errors_status ==
security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ if (security_style_explanations->displayed_content_with_cert_errors) {
+ add_secure_explanation = false;
+ security_style_explanations->neutral_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY),
+ l10n_util::GetStringUTF8(
+ IDS_CERT_ERROR_PASSIVE_CONTENT_DESCRIPTION)));
+ }
+ }
+
+ if (add_secure_explanation) {
+ DCHECK(security_info.scheme_is_cryptographic);
+ security_style_explanations->secure_explanations.push_back(
+ content::SecurityStyleExplanation(
+ l10n_util::GetStringUTF8(IDS_SECURE_RESOURCES_SUMMARY),
+ l10n_util::GetStringUTF8(IDS_SECURE_RESOURCES_DESCRIPTION)));
}
}
@@ -332,6 +387,12 @@ std::unique_ptr<security_state::VisibleSecurityState> GetVisibleSecurityState(
!!(ssl.content_status &
content::SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP);
+ SSLStatusInputEventData* input_events =
+ static_cast<SSLStatusInputEventData*>(ssl.user_data.get());
+
+ if (input_events)
+ state->insecure_input_events = *input_events->input_events();
+
return state;
}
diff --git a/chromium/components/security_state/content/content_utils_browsertest.cc b/chromium/components/security_state/content/content_utils_browsertest.cc
index 5e4dedbaad6..bc697a1f338 100644
--- a/chromium/components/security_state/content/content_utils_browsertest.cc
+++ b/chromium/components/security_state/content/content_utils_browsertest.cc
@@ -8,6 +8,8 @@
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "components/security_state/content/ssl_status_input_event_data.h"
+#include "components/security_state/core/insecure_input_event_data.h"
#include "components/security_state/core/security_state.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
@@ -25,6 +27,8 @@ namespace {
using content::NavigateToURL;
using security_state::GetVisibleSecurityState;
+using security_state::InsecureInputEventData;
+using security_state::SSLStatusInputEventData;
const base::FilePath::CharType kDocRoot[] =
FILE_PATH_LITERAL("components/security_state/content/testdata");
@@ -85,4 +89,41 @@ IN_PROC_BROWSER_TEST_F(SecurityStateContentUtilsBrowserTest,
->displayed_credit_card_field_on_http);
}
+// Tests that the flags for nonsecure editing are set correctly.
+IN_PROC_BROWSER_TEST_F(SecurityStateContentUtilsBrowserTest,
+ VisibleSecurityStateInsecureFieldEdit) {
+ ASSERT_TRUE(https_server_.Start());
+ EXPECT_TRUE(NavigateToURL(shell(), https_server_.GetURL("/hello.html")));
+
+ content::WebContents* contents = shell()->web_contents();
+ ASSERT_TRUE(contents);
+
+ // First, ensure the flag is not set prematurely.
+ content::SSLStatus& ssl_status =
+ contents->GetController().GetVisibleEntry()->GetSSL();
+ SSLStatusInputEventData* ssl_status_input_events =
+ static_cast<SSLStatusInputEventData*>(ssl_status.user_data.get());
+ InsecureInputEventData events;
+ if (ssl_status_input_events)
+ events = *ssl_status_input_events->input_events();
+ EXPECT_FALSE(events.insecure_field_edited);
+
+ std::unique_ptr<security_state::VisibleSecurityState> visible_state =
+ GetVisibleSecurityState(contents);
+ EXPECT_FALSE(visible_state->insecure_input_events.insecure_field_edited);
+
+ // Simulate a field edit and update the SSLStatus' |user_data|.
+ events.insecure_field_edited = true;
+ ssl_status.user_data =
+ base::MakeUnique<security_state::SSLStatusInputEventData>(events);
+
+ // Verify the field edit was recorded properly in the |user_data|.
+ ssl_status_input_events =
+ static_cast<SSLStatusInputEventData*>(ssl_status.user_data.get());
+ EXPECT_TRUE(ssl_status_input_events->input_events()->insecure_field_edited);
+ // Verify the field edit was propagated to the VisibleSecurityState.
+ visible_state = GetVisibleSecurityState(contents);
+ EXPECT_TRUE(visible_state->insecure_input_events.insecure_field_edited);
+}
+
} // namespace
diff --git a/chromium/components/security_state/content/content_utils_unittest.cc b/chromium/components/security_state/content/content_utils_unittest.cc
index e031970a874..d4e30e8397f 100644
--- a/chromium/components/security_state/content/content_utils_unittest.cc
+++ b/chromium/components/security_state/content/content_utils_unittest.cc
@@ -4,12 +4,14 @@
#include "components/security_state/content/content_utils.h"
+#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/test/histogram_tester.h"
#include "components/security_state/core/security_state.h"
#include "components/security_state/core/switches.h"
+#include "components/strings/grit/components_strings.h"
#include "content/public/browser/security_style_explanation.h"
#include "content/public/browser/security_style_explanations.h"
#include "net/cert/cert_status_flags.h"
@@ -19,6 +21,7 @@
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
+#include "ui/base/l10n/l10n_util.h"
namespace {
@@ -151,9 +154,26 @@ TEST(SecurityStateContentUtilsTest, GetSecurityStyleForMixedContent) {
EXPECT_TRUE(explanations.displayed_mixed_content);
}
+// Tests that malicious safe browsing data in SecurityInfo triggers an
+// appropriate summary in SecurityStyleExplanations.
+TEST(SecurityStateContentUtilsTest, GetSecurityStyleForSafeBrowsing) {
+ content::SecurityStyleExplanations explanations;
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = 0;
+ security_info.scheme_is_cryptographic = true;
+ security_info.malicious_content_status =
+ security_state::MALICIOUS_CONTENT_STATUS_MALWARE;
+
+ security_info.content_with_cert_errors_status =
+ security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ GetSecurityStyle(security_info, &explanations);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFEBROWSING_WARNING),
+ explanations.summary);
+}
+
bool FindSecurityStyleExplanation(
const std::vector<content::SecurityStyleExplanation>& explanations,
- const char* summary,
+ const std::string& summary,
content::SecurityStyleExplanation* explanation) {
for (const auto& entry : explanations) {
if (entry.summary == summary) {
@@ -257,6 +277,218 @@ TEST(SecurityStateContentUtilsTest, ObsoleteConnectionExplanation) {
}
}
+// Test that a secure content explanation is added as expected.
+TEST(SecurityStateContentUtilsTest, SecureContentExplanation) {
+ // Test a modern configuration with a key exchange group.
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ security_info.scheme_is_cryptographic = true;
+ net::SSLConnectionStatusSetCipherSuite(
+ 0xcca8 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */,
+ &security_info.connection_status);
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &security_info.connection_status);
+ security_info.key_exchange_group = 29; // X25519
+
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.secure_explanations,
+ l10n_util::GetStringUTF8(IDS_SECURE_RESOURCES_SUMMARY), &explanation));
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SECURE_RESOURCES_DESCRIPTION),
+ explanation.description);
+ }
+}
+
+// Test that mixed content explanations are added as expected.
+TEST(SecurityStateContentUtilsTest, MixedContentExplanations) {
+ // Test a modern configuration with a key exchange group.
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ security_info.scheme_is_cryptographic = true;
+ net::SSLConnectionStatusSetCipherSuite(
+ 0xcca8 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */,
+ &security_info.connection_status);
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &security_info.connection_status);
+ security_info.key_exchange_group = 29; // X25519
+
+ security_info.mixed_content_status =
+ security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_DESCRIPTION),
+ explanation.description);
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_DESCRIPTION),
+ explanation.description);
+ }
+
+ security_info.mixed_content_status = security_state::CONTENT_STATUS_DISPLAYED;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_FALSE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ }
+
+ security_info.mixed_content_status = security_state::CONTENT_STATUS_RAN;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_FALSE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ }
+
+ security_info.contained_mixed_form = true;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_NON_SECURE_FORM_SUMMARY), &explanation));
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_NON_SECURE_FORM_DESCRIPTION),
+ explanation.description);
+ }
+}
+
+// Test that cert error explanations are formatted as expected.
+TEST(SecurityStateContentUtilsTest, CertErrorContentExplanations) {
+ // Test a modern configuration with a key exchange group.
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ security_info.scheme_is_cryptographic = true;
+ net::SSLConnectionStatusSetCipherSuite(
+ 0xcca8 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */,
+ &security_info.connection_status);
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &security_info.connection_status);
+ security_info.key_exchange_group = 29; // X25519
+
+ security_info.content_with_cert_errors_status =
+ security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_EQ(
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_DESCRIPTION),
+ explanation.description);
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_EQ(
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_DESCRIPTION),
+ explanation.description);
+ }
+
+ security_info.content_with_cert_errors_status =
+ security_state::CONTENT_STATUS_DISPLAYED;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ ASSERT_FALSE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ }
+
+ security_info.content_with_cert_errors_status =
+ security_state::CONTENT_STATUS_RAN;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ ASSERT_FALSE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_EQ(
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_DESCRIPTION),
+ explanation.description);
+ }
+}
+
+// Test that all mixed content explanations can appear together.
+TEST(SecurityStateContentUtilsTest, MixedContentAndCertErrorExplanations) {
+ // Test a modern configuration with a key exchange group.
+ security_state::SecurityInfo security_info;
+ security_info.cert_status = net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ security_info.scheme_is_cryptographic = true;
+ net::SSLConnectionStatusSetCipherSuite(
+ 0xcca8 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */,
+ &security_info.connection_status);
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+ &security_info.connection_status);
+ security_info.key_exchange_group = 29; // X25519
+
+ security_info.mixed_content_status =
+ security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ security_info.content_with_cert_errors_status =
+ security_state::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ {
+ content::SecurityStyleExplanations explanations;
+ GetSecurityStyle(security_info, &explanations);
+ content::SecurityStyleExplanation explanation;
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_MIXED_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.neutral_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY),
+ &explanation));
+ EXPECT_TRUE(FindSecurityStyleExplanation(
+ explanations.insecure_explanations,
+ l10n_util::GetStringUTF8(IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY),
+ &explanation));
+ }
+}
+
// Tests that a security level of HTTP_SHOW_WARNING produces
// blink::WebSecurityStyleNeutral and an explanation if appropriate.
TEST(SecurityStateContentUtilsTest, HTTPWarning) {
@@ -290,10 +522,33 @@ TEST(SecurityStateContentUtilsTest, HTTPWarning) {
// FormNotSecure flags are both set.
explanations.neutral_explanations.clear();
security_info.displayed_credit_card_field_on_http = true;
+ security_info.displayed_password_field_on_http = false;
security_info.incognito_downgraded_security_level = true;
security_style = GetSecurityStyle(security_info, &explanations);
EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
EXPECT_EQ(2u, explanations.neutral_explanations.size());
+
+ // Verify that three explanations are shown when the Incognito, FormNotSecure,
+ // and Insecure Field Edit flags are all set.
+ explanations.neutral_explanations.clear();
+ security_info.displayed_credit_card_field_on_http = true;
+ security_info.displayed_password_field_on_http = false;
+ security_info.incognito_downgraded_security_level = true;
+ security_info.field_edit_downgraded_security_level = true;
+ security_style = GetSecurityStyle(security_info, &explanations);
+ EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
+ EXPECT_EQ(3u, explanations.neutral_explanations.size());
+
+ // Verify that one explanation is shown when the Insecure Field Edit flags
+ // alone is set.
+ explanations.neutral_explanations.clear();
+ security_info.displayed_credit_card_field_on_http = false;
+ security_info.displayed_password_field_on_http = false;
+ security_info.incognito_downgraded_security_level = false;
+ security_info.field_edit_downgraded_security_level = true;
+ security_style = GetSecurityStyle(security_info, &explanations);
+ EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
+ EXPECT_EQ(1u, explanations.neutral_explanations.size());
}
// Tests that an explanation is provided if a certificate is missing a
@@ -325,7 +580,7 @@ TEST(SecurityStateContentUtilsTest, SubjectAltNameWarning) {
TEST(SecurityStateContentUtilsTest, DefaultSecurityStyleExplanation) {
content::SecurityStyleExplanation explanation("summary", "description");
- EXPECT_EQ(false, explanation.has_certificate);
+ EXPECT_EQ(false, !!explanation.certificate);
EXPECT_EQ(blink::WebMixedContentContextType::kNotMixedContent,
explanation.mixed_content_type);
}
diff --git a/chromium/components/security_state/content/ssl_status_input_event_data.cc b/chromium/components/security_state/content/ssl_status_input_event_data.cc
new file mode 100644
index 00000000000..cfb66fff8b2
--- /dev/null
+++ b/chromium/components/security_state/content/ssl_status_input_event_data.cc
@@ -0,0 +1,29 @@
+// 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/security_state/content/ssl_status_input_event_data.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+
+namespace security_state {
+
+SSLStatusInputEventData::SSLStatusInputEventData() {}
+SSLStatusInputEventData::SSLStatusInputEventData(
+ const InsecureInputEventData& initial_data)
+ : data_(initial_data) {}
+
+SSLStatusInputEventData::~SSLStatusInputEventData() {}
+
+InsecureInputEventData* SSLStatusInputEventData::input_events() {
+ return &data_;
+}
+
+std::unique_ptr<SSLStatus::UserData> SSLStatusInputEventData::Clone() {
+ return base::MakeUnique<SSLStatusInputEventData>(data_);
+}
+
+} // namespace security_state
diff --git a/chromium/components/security_state/content/ssl_status_input_event_data.h b/chromium/components/security_state/content/ssl_status_input_event_data.h
new file mode 100644
index 00000000000..44ac585b3f0
--- /dev/null
+++ b/chromium/components/security_state/content/ssl_status_input_event_data.h
@@ -0,0 +1,38 @@
+// 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_SECURITY_STATE_CONTENT_SSL_STATUS_INPUT_EVENT_DATA_H_
+#define COMPONENTS_SECURITY_STATE_CONTENT_SSL_STATUS_INPUT_EVENT_DATA_H_
+
+#include <memory>
+
+#include "components/security_state/core/insecure_input_event_data.h"
+#include "content/public/browser/ssl_status.h"
+
+namespace security_state {
+
+using content::SSLStatus;
+
+// Stores flags about Input Events in the SSLStatus UserData to
+// influence the Security Level of the page.
+class SSLStatusInputEventData : public SSLStatus::UserData {
+ public:
+ SSLStatusInputEventData();
+ explicit SSLStatusInputEventData(const InsecureInputEventData& initial_data);
+ ~SSLStatusInputEventData() override;
+
+ InsecureInputEventData* input_events();
+
+ // SSLStatus::UserData:
+ std::unique_ptr<SSLStatus::UserData> Clone() override;
+
+ private:
+ InsecureInputEventData data_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLStatusInputEventData);
+};
+
+} // namespace security_state
+
+#endif // COMPONENTS_SECURITY_STATE_CONTENT_SSL_STATUS_INPUT_EVENT_DATA_H_
diff --git a/chromium/components/security_state/core/BUILD.gn b/chromium/components/security_state/core/BUILD.gn
index 091df2041ad..27648f6014f 100644
--- a/chromium/components/security_state/core/BUILD.gn
+++ b/chromium/components/security_state/core/BUILD.gn
@@ -9,6 +9,7 @@ if (is_android) {
static_library("core") {
sources = [
+ "insecure_input_event_data.h",
"security_state.cc",
"security_state.h",
"security_state_ui.cc",
diff --git a/chromium/components/security_state/core/insecure_input_event_data.h b/chromium/components/security_state/core/insecure_input_event_data.h
new file mode 100644
index 00000000000..e6b9c913f1b
--- /dev/null
+++ b/chromium/components/security_state/core/insecure_input_event_data.h
@@ -0,0 +1,22 @@
+// 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_SECURITY_STATE_CORE_INSECURE_INPUT_EVENT_DATA_H_
+#define COMPONENTS_SECURITY_STATE_CORE_INSECURE_INPUT_EVENT_DATA_H_
+
+namespace security_state {
+
+// Stores flags about Input Events in the page that may influence
+// its security level.
+struct InsecureInputEventData {
+ InsecureInputEventData() : insecure_field_edited(false) {}
+ ~InsecureInputEventData() {}
+
+ // True if the user edited a field on a non-secure page.
+ bool insecure_field_edited;
+};
+
+} // namespace security_state
+
+#endif // COMPONENTS_SECURITY_STATE_CORE_INSECURE_INPUT_EVENT_DATA_H_
diff --git a/chromium/components/security_state/core/security_state.cc b/chromium/components/security_state/core/security_state.cc
index c7d40bf2b11..2dcd0d36d8c 100644
--- a/chromium/components/security_state/core/security_state.cc
+++ b/chromium/components/security_state/core/security_state.cc
@@ -37,11 +37,12 @@ bool GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
std::string switch_or_field_trial_group,
bool displayed_sensitive_input_on_http,
bool is_incognito,
+ const InsecureInputEventData* input_events,
SecurityLevel* level,
- MarkHttpStatus* histogram_status) {
+ MarkHttpStatus* mark_http_as) {
if (switch_or_field_trial_group ==
switches::kMarkHttpAsNonSecureWhileIncognito) {
- *histogram_status = NON_SECURE_WHILE_INCOGNITO;
+ *mark_http_as = NON_SECURE_WHILE_INCOGNITO;
*level = (is_incognito || displayed_sensitive_input_on_http)
? security_state::HTTP_SHOW_WARNING
: NONE;
@@ -49,14 +50,24 @@ bool GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
}
if (switch_or_field_trial_group ==
switches::kMarkHttpAsNonSecureWhileIncognitoOrEditing) {
- *histogram_status = NON_SECURE_WHILE_INCOGNITO_OR_EDITING;
- *level = (is_incognito || displayed_sensitive_input_on_http)
+ *mark_http_as = NON_SECURE_WHILE_INCOGNITO_OR_EDITING;
+ *level = (is_incognito || displayed_sensitive_input_on_http ||
+ (input_events && input_events->insecure_field_edited))
+ ? security_state::HTTP_SHOW_WARNING
+ : NONE;
+ return true;
+ }
+ if (switch_or_field_trial_group ==
+ switches::kMarkHttpAsNonSecureAfterEditing) {
+ *mark_http_as = NON_SECURE_AFTER_EDITING;
+ *level = (displayed_sensitive_input_on_http ||
+ (input_events && input_events->insecure_field_edited))
? security_state::HTTP_SHOW_WARNING
: NONE;
return true;
}
if (switch_or_field_trial_group == switches::kMarkHttpAsDangerous) {
- *histogram_status = NON_SECURE;
+ *mark_http_as = NON_SECURE;
*level = DANGEROUS;
return true;
}
@@ -66,7 +77,9 @@ bool GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
SecurityLevel GetSecurityLevelForNonSecureFieldTrial(
bool displayed_sensitive_input_on_http,
- bool is_incognito) {
+ bool is_incognito,
+ const InsecureInputEventData* input_events,
+ MarkHttpStatus* mark_http_as) {
std::string choice =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kMarkHttpAs);
@@ -75,24 +88,23 @@ SecurityLevel GetSecurityLevelForNonSecureFieldTrial(
const char kEnumeration[] = "SSL.MarkHttpAsStatus";
SecurityLevel level = NONE;
- MarkHttpStatus status;
// If the command-line switch is set, then it takes precedence over
// the field trial group.
if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
- choice, displayed_sensitive_input_on_http, is_incognito, &level,
- &status)) {
+ choice, displayed_sensitive_input_on_http, is_incognito, input_events,
+ &level, mark_http_as)) {
if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
- group, displayed_sensitive_input_on_http, is_incognito, &level,
- &status)) {
- status = HTTP_SHOW_WARNING_ON_SENSITIVE_FIELDS;
+ group, displayed_sensitive_input_on_http, is_incognito,
+ input_events, &level, mark_http_as)) {
+ *mark_http_as = HTTP_SHOW_WARNING_ON_SENSITIVE_FIELDS;
level = displayed_sensitive_input_on_http
? security_state::HTTP_SHOW_WARNING
: NONE;
}
}
- UMA_HISTOGRAM_ENUMERATION(kEnumeration, status, LAST_STATUS);
+ UMA_HISTOGRAM_ENUMERATION(kEnumeration, *mark_http_as, LAST_STATUS);
return level;
}
@@ -112,7 +124,8 @@ SecurityLevel GetSecurityLevelForRequest(
const IsOriginSecureCallback& is_origin_secure_callback,
bool sha1_in_chain,
ContentStatus mixed_content_status,
- ContentStatus content_with_cert_errors_status) {
+ ContentStatus content_with_cert_errors_status,
+ MarkHttpStatus* mark_http_as) {
DCHECK(visible_security_state.connection_info_initialized ||
visible_security_state.malicious_content_status !=
MALICIOUS_CONTENT_STATUS_NONE);
@@ -152,7 +165,8 @@ SecurityLevel GetSecurityLevelForRequest(
return GetSecurityLevelForNonSecureFieldTrial(
visible_security_state.displayed_password_field_on_http ||
visible_security_state.displayed_credit_card_field_on_http,
- visible_security_state.is_incognito);
+ visible_security_state.is_incognito,
+ &visible_security_state.insecure_input_events, mark_http_as);
}
return NONE;
}
@@ -207,6 +221,11 @@ void SecurityInfoForRequest(
bool used_policy_installed_certificate,
const IsOriginSecureCallback& is_origin_secure_callback,
SecurityInfo* security_info) {
+ // |mark_http_as| will be updated to the value specified by the
+ // field trial or command-line in |GetSecurityLevelForNonSecureFieldTrial|
+ // if that function is reached.
+ MarkHttpStatus mark_http_as = HTTP_SHOW_WARNING_ON_SENSITIVE_FIELDS;
+
if (!visible_security_state.connection_info_initialized) {
*security_info = SecurityInfo();
security_info->malicious_content_status =
@@ -216,7 +235,7 @@ void SecurityInfoForRequest(
security_info->security_level = GetSecurityLevelForRequest(
visible_security_state, used_policy_installed_certificate,
is_origin_secure_callback, false, CONTENT_STATUS_UNKNOWN,
- CONTENT_STATUS_UNKNOWN);
+ CONTENT_STATUS_UNKNOWN, &mark_http_as);
}
return;
}
@@ -259,38 +278,26 @@ void SecurityInfoForRequest(
visible_security_state, used_policy_installed_certificate,
is_origin_secure_callback, security_info->sha1_in_chain,
security_info->mixed_content_status,
- security_info->content_with_cert_errors_status);
+ security_info->content_with_cert_errors_status, &mark_http_as);
security_info->incognito_downgraded_security_level =
(visible_security_state.is_incognito &&
security_info->security_level == HTTP_SHOW_WARNING &&
- security_state::IsHttpWarningForIncognitoEnabled());
-}
+ (mark_http_as == NON_SECURE_WHILE_INCOGNITO ||
+ mark_http_as == NON_SECURE_WHILE_INCOGNITO_OR_EDITING));
-} // namespace
+ security_info->field_edit_downgraded_security_level =
+ (security_info->security_level == HTTP_SHOW_WARNING &&
+ visible_security_state.insecure_input_events.insecure_field_edited &&
+ (mark_http_as == NON_SECURE_AFTER_EDITING ||
+ mark_http_as == NON_SECURE_WHILE_INCOGNITO_OR_EDITING));
-bool IsHttpWarningForIncognitoEnabled() {
- std::string choice =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kMarkHttpAs);
- std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs");
- SecurityLevel level = NONE;
- MarkHttpStatus status;
-
- // If the command-line switch is set, then it takes precedence over
- // the field trial group.
- if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
- choice, false, true, &level, &status)) {
- if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
- group, false, true, &level, &status)) {
- return false;
- }
- }
-
- return (status == NON_SECURE_WHILE_INCOGNITO ||
- status == NON_SECURE_WHILE_INCOGNITO_OR_EDITING);
+ security_info->insecure_input_events =
+ visible_security_state.insecure_input_events;
}
+} // namespace
+
const base::Feature kHttpFormWarningFeature{"HttpFormWarning",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -311,7 +318,8 @@ SecurityInfo::SecurityInfo()
displayed_credit_card_field_on_http(false),
contained_mixed_form(false),
cert_missing_subject_alt_name(false),
- incognito_downgraded_security_level(false) {}
+ incognito_downgraded_security_level(false),
+ field_edit_downgraded_security_level(false) {}
SecurityInfo::~SecurityInfo() {}
@@ -348,26 +356,4 @@ VisibleSecurityState::VisibleSecurityState()
VisibleSecurityState::~VisibleSecurityState() {}
-bool VisibleSecurityState::operator==(const VisibleSecurityState& other) const {
- return (url == other.url &&
- malicious_content_status == other.malicious_content_status &&
- !!certificate == !!other.certificate &&
- (certificate ? certificate->Equals(other.certificate.get()) : true) &&
- connection_status == other.connection_status &&
- key_exchange_group == other.key_exchange_group &&
- security_bits == other.security_bits &&
- displayed_mixed_content == other.displayed_mixed_content &&
- ran_mixed_content == other.ran_mixed_content &&
- displayed_content_with_cert_errors ==
- other.displayed_content_with_cert_errors &&
- ran_content_with_cert_errors == other.ran_content_with_cert_errors &&
- pkp_bypassed == other.pkp_bypassed &&
- displayed_password_field_on_http ==
- other.displayed_password_field_on_http &&
- displayed_credit_card_field_on_http ==
- other.displayed_credit_card_field_on_http &&
- contained_mixed_form == other.contained_mixed_form &&
- is_incognito == other.is_incognito);
-}
-
} // namespace security_state
diff --git a/chromium/components/security_state/core/security_state.h b/chromium/components/security_state/core/security_state.h
index 0e737f9d2ce..dab5dd88bda 100644
--- a/chromium/components/security_state/core/security_state.h
+++ b/chromium/components/security_state/core/security_state.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/macros.h"
+#include "components/security_state/core/insecure_input_event_data.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/sct_status_flags.h"
#include "net/cert/x509_certificate.h"
@@ -31,8 +32,8 @@ extern const base::Feature kHttpFormWarningFeature;
// Describes the overall security state of the page.
//
-// If you reorder, add, or delete values from this enum, you must also
-// update the UI icons in ToolbarModelImpl::GetIconForSecurityLevel.
+// If you change this enum, you may need to update the UI icons in
+// ToolbarModelImpl::GetVectorIcon and GetIconForSecurityState.
//
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.security_state
@@ -55,11 +56,10 @@ enum SecurityLevel {
// HTTPS (non-EV) with valid cert.
SECURE,
- // HTTPS, but with an outdated protocol version.
- SECURITY_WARNING,
-
// HTTPS, but the certificate verification chain is anchored on a
// certificate that was installed by the system administrator.
+ //
+ // Currently used only on ChromeOS.
SECURE_WITH_POLICY_INSTALLED_CERT,
// Attempted HTTPS and failed, page not authenticated, HTTPS with
@@ -87,6 +87,7 @@ enum MaliciousContentStatus {
MALICIOUS_CONTENT_STATUS_MALWARE,
MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE,
MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING,
+ MALICIOUS_CONTENT_STATUS_PASSWORD_REUSE,
};
// Describes the security status of a page or request. This is the
@@ -144,6 +145,12 @@ struct SecurityInfo {
// True if the |security_level| was downgraded to HTTP_SHOW_WARNING because
// the page was loaded while Incognito.
bool incognito_downgraded_security_level;
+ // True if the |security_level| was downgraded to HTTP_SHOW_WARNING because
+ // of a field edit recorded in |insecure_input_events|.
+ bool field_edit_downgraded_security_level;
+ // Contains information about input events that may impact the security
+ // level of the page.
+ InsecureInputEventData insecure_input_events;
};
// Contains the security state relevant to computing the SecurityInfo
@@ -186,6 +193,9 @@ struct VisibleSecurityState {
bool displayed_credit_card_field_on_http;
// True if the page was displayed in an Incognito context.
bool is_incognito;
+ // Contains information about input events that may impact the security
+ // level of the page.
+ InsecureInputEventData insecure_input_events;
};
// These security levels describe the treatment given to pages that
@@ -214,10 +224,6 @@ void GetSecurityInfo(
// |kHttpFormWarningFeature| feature.
bool IsHttpWarningInFormEnabled();
-// Returns true if the MarkHttpAs setting indicates that a warning
-// should be shown for HTTP pages loaded while in Incognito mode.
-bool IsHttpWarningForIncognitoEnabled();
-
} // namespace security_state
#endif // COMPONENTS_SECURITY_STATE_CORE_SECURITY_STATE_H_
diff --git a/chromium/components/security_state/core/security_state_ui.cc b/chromium/components/security_state/core/security_state_ui.cc
index 31aff663361..91b53ea8430 100644
--- a/chromium/components/security_state/core/security_state_ui.cc
+++ b/chromium/components/security_state/core/security_state_ui.cc
@@ -15,7 +15,6 @@ bool ShouldAlwaysShowIcon(SecurityLevel security_level) {
case HTTP_SHOW_WARNING:
case EV_SECURE:
case SECURE:
- case SECURITY_WARNING:
case SECURE_WITH_POLICY_INSTALLED_CERT:
case DANGEROUS:
return true;
diff --git a/chromium/components/security_state/core/security_state_unittest.cc b/chromium/components/security_state/core/security_state_unittest.cc
index 85df06e2560..89a76497f9e 100644
--- a/chromium/components/security_state/core/security_state_unittest.cc
+++ b/chromium/components/security_state/core/security_state_unittest.cc
@@ -12,6 +12,7 @@
#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_command_line.h"
+#include "components/security_state/core/insecure_input_event_data.h"
#include "components/security_state/core/switches.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cipher_suite_names.h"
@@ -91,6 +92,10 @@ class TestSecurityStateHelper {
}
void set_is_incognito(bool is_incognito) { is_incognito_ = is_incognito; }
+ void set_insecure_field_edit(bool insecure_field_edit) {
+ insecure_input_events_.insecure_field_edited = insecure_field_edit;
+ }
+
void SetUrl(const GURL& url) { url_ = url; }
std::unique_ptr<VisibleSecurityState> GetVisibleSecurityState() const {
@@ -109,6 +114,7 @@ class TestSecurityStateHelper {
state->displayed_credit_card_field_on_http =
displayed_credit_card_field_on_http_;
state->is_incognito = is_incognito_;
+ state->insecure_input_events = insecure_input_events_;
return state;
}
@@ -131,6 +137,7 @@ class TestSecurityStateHelper {
bool displayed_password_field_on_http_;
bool displayed_credit_card_field_on_http_;
bool is_incognito_;
+ InsecureInputEventData insecure_input_events_;
};
} // namespace
@@ -455,12 +462,66 @@ TEST(SecurityStateTest, MarkHttpAsStatusHistogram) {
histograms.ExpectUniqueSample(
kHistogramName, 5 /* NON_SECURE_WHILE_INCOGNITO_OR_EDITING */, 1);
- // Ensure histogram recorded correctly even without the Incognito flag.
+ // Ensure histogram recorded correctly when the Insecure Field Edit flag
+ // is set.
helper.set_is_incognito(false);
+ helper.set_insecure_field_edit(true);
helper.GetSecurityInfo(&security_info);
EXPECT_FALSE(security_info.incognito_downgraded_security_level);
histograms.ExpectUniqueSample(
kHistogramName, 5 /* NON_SECURE_WHILE_INCOGNITO_OR_EDITING */, 2);
+
+ // Ensure histogram recorded correctly even when neither flag is set.
+ helper.set_is_incognito(false);
+ helper.set_insecure_field_edit(false);
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_FALSE(security_info.incognito_downgraded_security_level);
+ histograms.ExpectUniqueSample(
+ kHistogramName, 5 /* NON_SECURE_WHILE_INCOGNITO_OR_EDITING */, 3);
+ }
+
+ {
+ // Test the "non-secure-after-editing" configuration.
+ base::test::ScopedCommandLine scoped_command_line;
+ scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+ security_state::switches::kMarkHttpAs,
+ security_state::switches::kMarkHttpAsNonSecureAfterEditing);
+
+ base::HistogramTester histograms;
+ TestSecurityStateHelper helper;
+ helper.SetUrl(GURL(kHttpUrl));
+
+ // Ensure histogram recorded correctly when the editing flag is present.
+ helper.set_insecure_field_edit(true);
+ SecurityInfo security_info;
+ histograms.ExpectTotalCount(kHistogramName, 0);
+ helper.GetSecurityInfo(&security_info);
+ histograms.ExpectUniqueSample(kHistogramName,
+ 3 /* NON_SECURE_AFTER_EDITING */, 1);
+
+ // Ensure histogram recorded correctly even without the editing flag.
+ helper.set_insecure_field_edit(false);
+ helper.GetSecurityInfo(&security_info);
+ histograms.ExpectUniqueSample(kHistogramName,
+ 3 /* NON_SECURE_AFTER_EDITING */, 2);
+ }
+
+ {
+ // Test the "dangerous" configuration.
+ base::test::ScopedCommandLine scoped_command_line;
+ scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+ security_state::switches::kMarkHttpAs,
+ security_state::switches::kMarkHttpAsDangerous);
+
+ base::HistogramTester histograms;
+ TestSecurityStateHelper helper;
+ helper.SetUrl(GURL(kHttpUrl));
+
+ // Ensure histogram recorded correctly.
+ SecurityInfo security_info;
+ histograms.ExpectTotalCount(kHistogramName, 0);
+ helper.GetSecurityInfo(&security_info);
+ histograms.ExpectUniqueSample(kHistogramName, 1 /* NON_SECURE */, 1);
}
}
@@ -509,4 +570,55 @@ TEST(SecurityStateTest, MixedForm) {
EXPECT_EQ(DANGEROUS, mixed_form_and_active_security_info.security_level);
}
+// Tests that a field edit is reflected in the SecurityInfo.
+TEST(SecurityStateTest, FieldEdit) {
+ TestSecurityStateHelper helper;
+ helper.SetUrl(GURL(kHttpUrl));
+
+ SecurityInfo no_field_edit_security_info;
+ helper.GetSecurityInfo(&no_field_edit_security_info);
+ EXPECT_FALSE(
+ no_field_edit_security_info.insecure_input_events.insecure_field_edited);
+
+ helper.set_insecure_field_edit(true);
+
+ SecurityInfo security_info;
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_TRUE(security_info.insecure_input_events.insecure_field_edited);
+
+ {
+ // Test that no warning is raised in the "non-secure-while-incognito"
+ // configuration.
+ base::test::ScopedCommandLine scoped_command_line;
+ scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+ security_state::switches::kMarkHttpAs,
+ security_state::switches::kMarkHttpAsNonSecureWhileIncognito);
+
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_EQ(NONE, security_info.security_level);
+ }
+
+ {
+ // Test the "non-secure-after-editing" configuration.
+ base::test::ScopedCommandLine scoped_command_line;
+ scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+ security_state::switches::kMarkHttpAs,
+ security_state::switches::kMarkHttpAsNonSecureAfterEditing);
+
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
+ }
+
+ {
+ // Test the "non-secure-while-incognito-or-editing" configuration.
+ base::test::ScopedCommandLine scoped_command_line;
+ scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+ security_state::switches::kMarkHttpAs,
+ security_state::switches::kMarkHttpAsNonSecureWhileIncognitoOrEditing);
+
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
+ }
+}
+
} // namespace security_state
diff --git a/chromium/components/security_state_strings.grdp b/chromium/components/security_state_strings.grdp
index 6094c157812..d38b26d9d86 100644
--- a/chromium/components/security_state_strings.grdp
+++ b/chromium/components/security_state_strings.grdp
@@ -13,6 +13,12 @@
<message name="IDS_INCOGNITO_NONSECURE_DESCRIPTION" desc="Description of a security problem where the site is non-secure (HTTP) and the user is browsing Incognito, which results in an omnibox warning." translateable="false">
This page was loaded non-securely in an incognito window. A warning has been added to the URL bar.
</message>
+ <message name="IDS_EDITED_NONSECURE" desc="Summary phrase for a security problem where the site is non-secure (HTTP) and user has entered data in a form field." translateable="false">
+ Form field edited on a non-secure page
+ </message>
+ <message name="IDS_EDITED_NONSECURE_DESCRIPTION" desc="Description of a security problem where the site is non-secure (HTTP) and user has entered data in a form field." translateable="false">
+ Data was entered in a text field on a non-secure page. A warning has been added to the URL bar.
+ </message>
<message name="IDS_SAFEBROWSING_WARNING" desc="Summary phrase for a security problem where the site is deemed unsafe by the SafeBrowsing service." translateable="false">
This page is dangerous (flagged by Google Safe Browsing).
</message>
@@ -82,4 +88,42 @@
<message name="IDS_SSL_KEY_EXCHANGE_WITH_GROUP" desc="A phrase to describe an SSL/TLS ECDHE-based key exchange with a group." translateable="false">
<ph name="A_KEY_EXCHANGE">$1<ex>ECDHE_RSA</ex></ph> with <ph name="A_GROUP">$2<ex>X25519</ex></ph>
</message>
+
+ <!-- Mixed Content -->
+ <message name="IDS_SECURE_RESOURCES_SUMMARY" desc="" translateable="false">
+ Secure resources
+ </message>
+ <message name="IDS_SECURE_RESOURCES_DESCRIPTION" desc="" translateable="false">
+ All resources on this page are served securely.
+ </message>
+ <message name="IDS_MIXED_PASSIVE_CONTENT_SUMMARY" desc="" translateable="false">
+ Mixed content
+ </message>
+ <message name="IDS_MIXED_PASSIVE_CONTENT_DESCRIPTION" desc="" translateable="false">
+ This page includes HTTP resources.
+ </message>
+ <message name="IDS_MIXED_ACTIVE_CONTENT_SUMMARY" desc="" translateable="false">
+ Active mixed content
+ </message>
+ <message name="IDS_MIXED_ACTIVE_CONTENT_DESCRIPTION" desc="" translateable="false">
+ You have recently allowed non-secure content (such as scripts or iframes) to run on this site.
+ </message>
+ <message name="IDS_CERT_ERROR_PASSIVE_CONTENT_SUMMARY" desc="" translateable="false">
+ Content with certificate errors
+ </message>
+ <message name="IDS_CERT_ERROR_PASSIVE_CONTENT_DESCRIPTION" desc="" translateable="false">
+ This page includes resources that were loaded with certificate errors.
+ </message>
+ <message name="IDS_CERT_ERROR_ACTIVE_CONTENT_SUMMARY" desc="" translateable="false">
+ Active content with certificate errors
+ </message>
+ <message name="IDS_CERT_ERROR_ACTIVE_CONTENT_DESCRIPTION" desc="" translateable="false">
+ You have recently allowed content loaded with certificate errors (such as scripts or iframes) to run on this site.
+ </message>
+ <message name="IDS_NON_SECURE_FORM_SUMMARY" desc="" translateable="false">
+ Non-secure form
+ </message>
+ <message name="IDS_NON_SECURE_FORM_DESCRIPTION" desc="" translateable="false">
+ This page includes a form with a non-secure "action" attribute.
+ </message>
</grit-part>
diff --git a/chromium/components/session_manager/session_manager_types.h b/chromium/components/session_manager/session_manager_types.h
index 5a88b4e7d89..f38650a9bec 100644
--- a/chromium/components/session_manager/session_manager_types.h
+++ b/chromium/components/session_manager/session_manager_types.h
@@ -48,8 +48,10 @@ struct Session {
AccountId user_account_id;
};
-// Limits the number of logged in users to 10 due to memory constraints.
-constexpr int kMaxmiumNumberOfUserSessions = 10;
+// Limits the number of logged in users to 5. User-switcher UI was not designed
+// around a large number of users. This also helps on memory-constrained
+// devices. See b/64593342 for some additional context.
+constexpr int kMaximumNumberOfUserSessions = 5;
} // namespace session_manager
diff --git a/chromium/components/sessions/core/base_session_service.cc b/chromium/components/sessions/core/base_session_service.cc
index e40809f472a..770c7d9f037 100644
--- a/chromium/components/sessions/core/base_session_service.cc
+++ b/chromium/components/sessions/core/base_session_service.cc
@@ -8,7 +8,8 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/sessions/core/base_session_service_delegate.h"
@@ -48,14 +49,14 @@ void PostOrRunInternalGetCommandsCallback(
// backend.
static const int kSaveDelayMS = 2500;
-BaseSessionService::BaseSessionService(
- SessionType type,
- const base::FilePath& path,
- BaseSessionServiceDelegate* delegate)
+BaseSessionService::BaseSessionService(SessionType type,
+ const base::FilePath& path,
+ BaseSessionServiceDelegate* delegate)
: pending_reset_(false),
commands_since_reset_(0),
delegate_(delegate),
- sequence_token_(delegate_->GetBlockingPool()->GetSequenceToken()),
+ backend_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
weak_factory_(this) {
backend_ = new SessionBackend(type, path);
DCHECK(backend_.get());
@@ -66,14 +67,14 @@ BaseSessionService::~BaseSessionService() {}
void BaseSessionService::MoveCurrentSessionToLastSession() {
Save();
RunTaskOnBackendThread(
- FROM_HERE, base::Bind(&SessionBackend::MoveCurrentSessionToLastSession,
- backend_));
+ FROM_HERE,
+ base::BindOnce(&SessionBackend::MoveCurrentSessionToLastSession,
+ backend_));
}
void BaseSessionService::DeleteLastSession() {
RunTaskOnBackendThread(
- FROM_HERE,
- base::Bind(&SessionBackend::DeleteLastSession, backend_));
+ FROM_HERE, base::BindOnce(&SessionBackend::DeleteLastSession, backend_));
}
void BaseSessionService::ScheduleCommand(
@@ -139,16 +140,13 @@ void BaseSessionService::Save() {
// current commands. This will also clear the current list.
RunTaskOnBackendThread(
FROM_HERE,
- base::Bind(&SessionBackend::AppendCommands, backend_,
- base::Passed(&pending_commands_),
- pending_reset_));
+ base::BindOnce(&SessionBackend::AppendCommands, backend_,
+ base::Passed(&pending_commands_), pending_reset_));
if (pending_reset_) {
commands_since_reset_ = 0;
pending_reset_ = false;
}
-
- delegate_->OnSavedCommands();
}
base::CancelableTaskTracker::TaskId
@@ -168,24 +166,15 @@ BaseSessionService::ScheduleGetLastSessionCommands(
run_if_not_canceled);
RunTaskOnBackendThread(
- FROM_HERE,
- base::Bind(&SessionBackend::ReadLastSessionCommands, backend_,
- is_canceled, callback_runner));
+ FROM_HERE, base::BindOnce(&SessionBackend::ReadLastSessionCommands,
+ backend_, is_canceled, callback_runner));
return id;
}
void BaseSessionService::RunTaskOnBackendThread(
const tracked_objects::Location& from_here,
- const base::Closure& task) {
- base::SequencedWorkerPool* pool = delegate_->GetBlockingPool();
- if (!pool->IsShutdownInProgress()) {
- pool->PostSequencedWorkerTask(sequence_token_, from_here, task);
- } else {
- // Fall back to executing on the main thread if the sequence
- // worker pool has been requested to shutdown (around shutdown
- // time).
- task.Run();
- }
+ base::OnceClosure task) {
+ backend_task_runner_->PostNonNestableTask(from_here, std::move(task));
}
} // namespace sessions
diff --git a/chromium/components/sessions/core/base_session_service.h b/chromium/components/sessions/core/base_session_service.h
index 385948b8898..20dae1f8808 100644
--- a/chromium/components/sessions/core/base_session_service.h
+++ b/chromium/components/sessions/core/base_session_service.h
@@ -10,12 +10,14 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "components/sessions/core/sessions_export.h"
-#include "url/gurl.h"
+namespace base {
+class SequencedTaskRunner;
+}
namespace sessions {
class BaseSessionServiceDelegate;
@@ -103,10 +105,9 @@ class SESSIONS_EXPORT BaseSessionService {
private:
friend class BaseSessionServiceTestHelper;
- // This posts the task to the SequencedWorkerPool, or run immediately
- // if the SequencedWorkerPool has been shutdown.
+ // This posts the task to the TaskRunner.
void RunTaskOnBackendThread(const tracked_objects::Location& from_here,
- const base::Closure& task);
+ base::OnceClosure task);
// The backend object which reads and saves commands.
scoped_refptr<SessionBackend> backend_;
@@ -123,8 +124,9 @@ class SESSIONS_EXPORT BaseSessionService {
BaseSessionServiceDelegate* delegate_;
- // A token to make sure that all tasks will be serialized.
- base::SequencedWorkerPool::SequenceToken sequence_token_;
+ // TaskRunner all backend tasks are run on. This is a SequencedTaskRunner as
+ // all tasks *must* be processed in the order they are scheduled.
+ scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
// Used to invoke Save.
base::WeakPtrFactory<BaseSessionService> weak_factory_;
diff --git a/chromium/components/sessions/core/base_session_service_delegate.h b/chromium/components/sessions/core/base_session_service_delegate.h
index 8a226878655..1a2c245611c 100644
--- a/chromium/components/sessions/core/base_session_service_delegate.h
+++ b/chromium/components/sessions/core/base_session_service_delegate.h
@@ -5,10 +5,6 @@
#ifndef COMPONENTS_SESSIONS_CORE_BASE_SESSION_SERVICE_DELEGATE_H_
#define COMPONENTS_SESSIONS_CORE_BASE_SESSION_SERVICE_DELEGATE_H_
-namespace base {
-class SequencedWorkerPool;
-}
-
namespace sessions {
// The BaseSessionServiceDelegate decouples the BaseSessionService from
@@ -17,10 +13,6 @@ class BaseSessionServiceDelegate {
public:
BaseSessionServiceDelegate() {}
- // Get the sequenced worker pool for running tasks on the backend thread as
- // long as the system is not shutting down.
- virtual base::SequencedWorkerPool* GetBlockingPool() = 0;
-
// Returns true if save operations can be performed as a delayed task - which
// is usually only used by unit tests.
virtual bool ShouldUseDelayedSave() = 0;
@@ -28,9 +20,6 @@ class BaseSessionServiceDelegate {
// Called when commands are about to be written to disc.
virtual void OnWillSaveCommands() {}
- // Called when commands were saved to disc.
- virtual void OnSavedCommands() {}
-
protected:
virtual ~BaseSessionServiceDelegate() {}
};
diff --git a/chromium/components/sessions/core/live_tab_context.h b/chromium/components/sessions/core/live_tab_context.h
index 03615b0c31a..0efb779e20c 100644
--- a/chromium/components/sessions/core/live_tab_context.h
+++ b/chromium/components/sessions/core/live_tab_context.h
@@ -10,6 +10,11 @@
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/sessions_export.h"
+#include "ui/base/ui_base_types.h"
+
+namespace gfx {
+class Rect;
+}
namespace sessions {
@@ -31,6 +36,9 @@ class SESSIONS_EXPORT LiveTabContext {
virtual LiveTab* GetLiveTabAt(int index) const = 0;
virtual LiveTab* GetActiveLiveTab() const = 0;
virtual bool IsTabPinned(int index) const = 0;
+ virtual const gfx::Rect GetRestoredBounds() const = 0;
+ virtual ui::WindowShowState GetRestoredState() const = 0;
+ virtual std::string GetWorkspace() const = 0;
// Note: |tab_platform_data| may be null (e.g., if |from_last_session| is
// true, as this data is not persisted, or if the platform does not provide
diff --git a/chromium/components/sessions/core/persistent_tab_restore_service.cc b/chromium/components/sessions/core/persistent_tab_restore_service.cc
index d9016ee0369..c70d39d51ac 100644
--- a/chromium/components/sessions/core/persistent_tab_restore_service.cc
+++ b/chromium/components/sessions/core/persistent_tab_restore_service.cc
@@ -45,15 +45,16 @@ struct SelectedNavigationInTabPayload {
// Payload used for the start of a window close. This is the old struct that is
// used for backwards compat when it comes to reading the session files. This
// struct must be POD, because we memset the contents.
-struct WindowPayload {
+struct WindowPayloadObsolete {
SessionID::id_type window_id;
int32_t selected_tab_index;
int32_t num_tabs;
};
-// Payload used for the start of a window close. This struct must be POD,
-// because we memset the contents.
-struct WindowPayload2 : WindowPayload {
+// Payload used for the start of a window close. This struct must be POD,
+// because we memset the contents. This is an older version of the struct that
+// is used for backwards compat when it comes to reading the session files.
+struct WindowPayloadObsolete2 : WindowPayloadObsolete {
int64_t timestamp;
};
@@ -96,12 +97,13 @@ enum LoadState {
// is written.
const SessionCommand::id_type kCommandUpdateTabNavigation = 1;
const SessionCommand::id_type kCommandRestoredEntry = 2;
-const SessionCommand::id_type kCommandWindow = 3;
+const SessionCommand::id_type kCommandWindowDeprecated = 3;
const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
const SessionCommand::id_type kCommandPinnedState = 5;
const SessionCommand::id_type kCommandSetExtensionAppID = 6;
const SessionCommand::id_type kCommandSetWindowAppName = 7;
const SessionCommand::id_type kCommandSetTabUserAgentOverride = 8;
+const SessionCommand::id_type kCommandWindow = 9;
// Number of entries (not commands) before we clobber the file and write
// everything.
@@ -135,6 +137,202 @@ void RemoveEntryByID(
}
}
+// An enum that corresponds to ui::WindowShowStates. This needs to be kept in
+// sync with that enum. Moreover, the integer values corresponding to each show
+// state need to be stable in this enum (which is not necessarily true about the
+// ui::WindowShowStates enum).
+enum SerializedWindowShowState : int {
+ kSerializedShowStateInvalid = -1,
+ kSerializedShowStateDefault = 0,
+ kSerializedShowStateNormal = 1,
+ kSerializedShowStateMinimized = 2,
+ kSerializedShowStateMaximized = 3,
+ kSerializedShowStateInactive = 4,
+ kSerializedShowStateFullscreen = 5,
+};
+
+// Converts a window show state to an integer. This function needs to be kept
+// up to date with the SerializedWindowShowState enum.
+int SerializeWindowShowState(ui::WindowShowState show_state) {
+ switch (show_state) {
+ case ui::SHOW_STATE_DEFAULT:
+ return kSerializedShowStateDefault;
+ case ui::SHOW_STATE_NORMAL:
+ return kSerializedShowStateNormal;
+ case ui::SHOW_STATE_MINIMIZED:
+ return kSerializedShowStateMinimized;
+ case ui::SHOW_STATE_MAXIMIZED:
+ return kSerializedShowStateMaximized;
+ case ui::SHOW_STATE_INACTIVE:
+ return kSerializedShowStateInactive;
+ case ui::SHOW_STATE_FULLSCREEN:
+ return kSerializedShowStateFullscreen;
+ case ui::SHOW_STATE_END:
+ // This should never happen.
+ NOTREACHED();
+ }
+ return kSerializedShowStateInvalid;
+}
+
+// Converts an integer to a window show state. Returns true on success, false
+// otherwise. This function needs to be kept up to date with the
+// SerializedWindowShowState enum.
+bool DeserializeWindowShowState(int show_state_int,
+ ui::WindowShowState* show_state) {
+ switch (static_cast<SerializedWindowShowState>(show_state_int)) {
+ case kSerializedShowStateDefault:
+ *show_state = ui::SHOW_STATE_DEFAULT;
+ return true;
+ case kSerializedShowStateNormal:
+ *show_state = ui::SHOW_STATE_NORMAL;
+ return true;
+ case kSerializedShowStateMinimized:
+ *show_state = ui::SHOW_STATE_MINIMIZED;
+ return true;
+ case kSerializedShowStateMaximized:
+ *show_state = ui::SHOW_STATE_MAXIMIZED;
+ return true;
+ case kSerializedShowStateInactive:
+ *show_state = ui::SHOW_STATE_INACTIVE;
+ return true;
+ case kSerializedShowStateFullscreen:
+ *show_state = ui::SHOW_STATE_FULLSCREEN;
+ return true;
+ case kSerializedShowStateInvalid:
+ default:
+ // Ignore unknown values. This could happen if the data is corrupt.
+ break;
+ }
+ return false;
+}
+
+// Superset of WindowPayloadObsolete/WindowPayloadObsolete2 and the other fields
+// that can appear in the Pickle version of a Window command. This is used as a
+// convenient destination for parsing the various fields in a WindowCommand.
+struct WindowCommandFields {
+ // Fields in WindowPayloadObsolete/WindowPayloadObsolete2/Pickle:
+ int window_id = 0;
+ int selected_tab_index = 0;
+ int num_tabs = 0;
+
+ // Fields in WindowPayloadObsolete2/Pickle:
+ int64_t timestamp = 0;
+
+ // Fields in Pickle:
+ // Completely zeroed position/dimensions indicates that defaults should be
+ // used.
+ int window_x = 0;
+ int window_y = 0;
+ int window_width = 0;
+ int window_height = 0;
+ int window_show_state = 0;
+ std::string workspace;
+};
+
+std::unique_ptr<sessions::TabRestoreService::Window>
+CreateWindowEntryFromCommand(const SessionCommand* command,
+ SessionID::id_type* window_id,
+ int32_t* num_tabs) {
+ WindowCommandFields fields;
+ ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
+
+ if (command->id() == kCommandWindow) {
+ std::unique_ptr<base::Pickle> pickle(command->PayloadAsPickle());
+ if (!pickle.get())
+ return nullptr;
+
+ base::PickleIterator it(*pickle);
+ WindowCommandFields parsed_fields;
+
+ // The first version of the pickle contains all of the following fields, so
+ // they should all successfully parse if the command is in fact a pickle.
+ if (!it.ReadInt(&parsed_fields.window_id) ||
+ !it.ReadInt(&parsed_fields.selected_tab_index) ||
+ !it.ReadInt(&parsed_fields.num_tabs) ||
+ !it.ReadInt64(&parsed_fields.timestamp) ||
+ !it.ReadInt(&parsed_fields.window_x) ||
+ !it.ReadInt(&parsed_fields.window_y) ||
+ !it.ReadInt(&parsed_fields.window_width) ||
+ !it.ReadInt(&parsed_fields.window_height) ||
+ !it.ReadInt(&parsed_fields.window_show_state) ||
+ !it.ReadString(&parsed_fields.workspace)) {
+ return nullptr;
+ }
+
+ // Validate the parameters. If the entire pickles parses but any of the
+ // validation fails assume corruption.
+ if (parsed_fields.window_width < 0 || parsed_fields.window_height < 0)
+ return nullptr;
+
+ // Deserialize the show state, validating it at the same time.
+ if (!DeserializeWindowShowState(parsed_fields.window_show_state,
+ &show_state)) {
+ return nullptr;
+ }
+
+ // New fields added to the pickle in later versions would be parsed and
+ // validated here.
+
+ // Copy the parsed data.
+ fields = parsed_fields;
+ } else if (command->id() == kCommandWindowDeprecated) {
+ // Old window commands can be in either of 2 formats. Try the newest first.
+ // These have distinct sizes so are easily distinguished.
+ bool parsed = false;
+
+ // Try to parse the command as a WindowPayloadObsolete2.
+ WindowPayloadObsolete2 payload2;
+ if (command->GetPayload(&payload2, sizeof(payload2))) {
+ fields.window_id = payload2.window_id;
+ fields.selected_tab_index = payload2.selected_tab_index;
+ fields.num_tabs = payload2.num_tabs;
+ fields.timestamp = payload2.timestamp;
+ parsed = true;
+ }
+
+ // Finally, try the oldest WindowPayloadObsolete type.
+ if (!parsed) {
+ WindowPayloadObsolete payload;
+ if (command->GetPayload(&payload, sizeof(payload))) {
+ fields.window_id = payload.window_id;
+ fields.selected_tab_index = payload.selected_tab_index;
+ fields.num_tabs = payload.num_tabs;
+ parsed = true;
+ }
+ }
+
+ // Fail if the old command wasn't able to be parsed in either of the
+ // deprecated formats.
+ if (!parsed)
+ return nullptr;
+ } else {
+ // This should never be called with anything other than a known window
+ // command ID.
+ NOTREACHED();
+ }
+
+ // Create the Window entry.
+ std::unique_ptr<sessions::TabRestoreService::Window> window =
+ base::MakeUnique<sessions::TabRestoreService::Window>();
+ window->selected_tab_index = fields.selected_tab_index;
+ window->timestamp = base::Time::FromInternalValue(fields.timestamp);
+ *window_id = static_cast<SessionID::id_type>(fields.window_id);
+ *num_tabs = fields.num_tabs;
+
+ // Set the bounds, show state and workspace if valid ones have been provided.
+ if (!(fields.window_x == 0 && fields.window_y == 0 &&
+ fields.window_width == 0 && fields.window_height == 0)) {
+ window->bounds.SetRect(fields.window_x, fields.window_y,
+ fields.window_width, fields.window_height);
+ // |show_state| was converted from window->show_state earlier during
+ // validation.
+ window->show_state = show_state;
+ window->workspace = std::move(fields.workspace);
+ }
+
+ return window;
+}
+
} // namespace
// PersistentTabRestoreService::Delegate ---------------------------------------
@@ -150,7 +348,6 @@ class PersistentTabRestoreService::Delegate
~Delegate() override;
// BaseSessionServiceDelegate:
- base::SequencedWorkerPool* GetBlockingPool() override;
bool ShouldUseDelayedSave() override;
void OnWillSaveCommands() override;
@@ -187,9 +384,12 @@ class PersistentTabRestoreService::Delegate
// Creates a window close command.
static std::unique_ptr<SessionCommand> CreateWindowCommand(
- SessionID::id_type id,
+ SessionID::id_type window_id,
int selected_tab_index,
int num_tabs,
+ const gfx::Rect& bounds,
+ ui::WindowShowState show_state,
+ const std::string& workspace,
base::Time timestamp);
// Creates a tab close command.
@@ -282,11 +482,6 @@ PersistentTabRestoreService::Delegate::Delegate(TabRestoreServiceClient* client)
PersistentTabRestoreService::Delegate::~Delegate() {}
-base::SequencedWorkerPool*
-PersistentTabRestoreService::Delegate::GetBlockingPool() {
- return client_->GetBlockingPool();
-}
-
bool PersistentTabRestoreService::Delegate::ShouldUseDelayedSave() {
return true;
}
@@ -435,7 +630,8 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow(
base_session_service_->ScheduleCommand(CreateWindowCommand(
window.id, std::min(real_selected_tab, valid_tab_count - 1),
- valid_tab_count, window.timestamp));
+ valid_tab_count, window.bounds, window.show_state, window.workspace,
+ window.timestamp));
if (!window.app_name.empty()) {
base_session_service_->ScheduleCommand(CreateSetWindowAppNameCommand(
@@ -504,22 +700,38 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForTab(
// static
std::unique_ptr<SessionCommand>
PersistentTabRestoreService::Delegate::CreateWindowCommand(
- SessionID::id_type id,
+ SessionID::id_type window_id,
int selected_tab_index,
int num_tabs,
+ const gfx::Rect& bounds,
+ ui::WindowShowState show_state,
+ const std::string& workspace,
base::Time timestamp) {
- WindowPayload2 payload;
- // |timestamp| is aligned on a 16 byte boundary, leaving 4 bytes of
- // uninitialized memory in the struct.
- memset(&payload, 0, sizeof(payload));
- payload.window_id = id;
- payload.selected_tab_index = selected_tab_index;
- payload.num_tabs = num_tabs;
- payload.timestamp = timestamp.ToInternalValue();
+ static_assert(sizeof(SessionID::id_type) == sizeof(int),
+ "SessionID::id_type has changed size.");
+
+ // Use a pickle to handle marshaling as this command contains variable-length
+ // content.
+ base::Pickle pickle;
+ pickle.WriteInt(static_cast<int>(window_id));
+ pickle.WriteInt(selected_tab_index);
+ pickle.WriteInt(num_tabs);
+ pickle.WriteInt64(timestamp.ToInternalValue());
+ pickle.WriteInt(bounds.x());
+ pickle.WriteInt(bounds.y());
+ pickle.WriteInt(bounds.width());
+ pickle.WriteInt(bounds.height());
+ pickle.WriteInt(SerializeWindowShowState(show_state));
+
+ // Enforce a maximum length on workspace names. A common size is 32 bytes for
+ // GUIDs.
+ if (workspace.size() <= 128)
+ pickle.WriteString(workspace);
+ else
+ pickle.WriteString(std::string());
std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandWindow, sizeof(payload)));
- memcpy(command->contents(), &payload, sizeof(payload));
+ new SessionCommand(kCommandWindow, pickle));
return command;
}
@@ -624,43 +836,29 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
break;
}
+ case kCommandWindowDeprecated:
case kCommandWindow: {
- WindowPayload2 payload;
- if (pending_window_tabs > 0) {
- // Should never receive a window command while waiting for all the
- // tabs in a window.
+ // Should never receive a window command while waiting for all the
+ // tabs in a window.
+ if (pending_window_tabs > 0)
return;
- }
- // Try the new payload first
- if (!command.GetPayload(&payload, sizeof(payload))) {
- // then the old payload
- WindowPayload old_payload;
- if (!command.GetPayload(&old_payload, sizeof(old_payload)))
- return;
-
- // Copy the old payload data to the new payload.
- payload.window_id = old_payload.window_id;
- payload.selected_tab_index = old_payload.selected_tab_index;
- payload.num_tabs = old_payload.num_tabs;
- // Since we don't have a time use time 0 which is used to mark as an
- // unknown timestamp.
- payload.timestamp = 0;
- }
-
- pending_window_tabs = payload.num_tabs;
- if (pending_window_tabs <= 0) {
- // Should always have at least 1 tab. Likely indicates corruption.
+ // Try to parse the command, and silently skip if it fails.
+ int32_t num_tabs = 0;
+ SessionID::id_type window_id = 0;
+ std::unique_ptr<Window> window =
+ CreateWindowEntryFromCommand(&command, &window_id, &num_tabs);
+ if (!window)
return;
- }
- RemoveEntryByID(payload.window_id, &entries);
+ // Should always have at least 1 tab. Likely indicates corruption.
+ pending_window_tabs = num_tabs;
+ if (pending_window_tabs <= 0)
+ return;
- entries.push_back(base::MakeUnique<Window>());
- current_window = static_cast<Window*>(entries.back().get());
- current_window->selected_tab_index = payload.selected_tab_index;
- current_window->timestamp =
- base::Time::FromInternalValue(payload.timestamp);
+ RemoveEntryByID(window_id, &entries);
+ current_window = window.get();
+ entries.push_back(std::move(window));
break;
}
@@ -780,7 +978,6 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
// If there was corruption some of the entries won't be valid.
ValidateAndDeleteEmptyEntries(&entries);
-
loaded_entries->swap(entries);
}
@@ -833,6 +1030,9 @@ bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow(
std::min(session_window->selected_tab_index,
static_cast<int>(window->tabs.size() - 1));
window->timestamp = base::Time();
+ window->bounds = session_window->bounds;
+ window->show_state = session_window->show_state;
+ window->workspace = session_window->workspace;
return true;
}
diff --git a/chromium/components/sessions/core/tab_restore_service.h b/chromium/components/sessions/core/tab_restore_service.h
index 2746da2e6e8..47bd4048c33 100644
--- a/chromium/components/sessions/core/tab_restore_service.h
+++ b/chromium/components/sessions/core/tab_restore_service.h
@@ -16,7 +16,9 @@
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
#include "components/sessions/core/sessions_export.h"
+#include "ui/base/ui_base_types.h"
#include "ui/base/window_open_disposition.h"
+#include "ui/gfx/geometry/rect.h"
namespace sessions {
@@ -133,6 +135,11 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
// If an application window, the name of the app.
std::string app_name;
+
+ // Where and how the window is displayed.
+ gfx::Rect bounds;
+ ui::WindowShowState show_state;
+ std::string workspace;
};
typedef std::list<std::unique_ptr<Entry>> Entries;
diff --git a/chromium/components/sessions/core/tab_restore_service_client.h b/chromium/components/sessions/core/tab_restore_service_client.h
index b5d3b97671f..60cdc1eaf32 100644
--- a/chromium/components/sessions/core/tab_restore_service_client.h
+++ b/chromium/components/sessions/core/tab_restore_service_client.h
@@ -11,12 +11,16 @@
#include "base/files/file_path.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/sessions_export.h"
+#include "ui/base/ui_base_types.h"
class GURL;
namespace base {
class CancelableTaskTracker;
-class SequencedWorkerPool;
+}
+
+namespace gfx {
+class Rect;
}
namespace sessions {
@@ -40,7 +44,11 @@ class SESSIONS_EXPORT TabRestoreServiceClient {
// Creates a LiveTabContext instance that is associated with |app_name|. May
// return nullptr (e.g., if the embedder does not support LiveTabContext
// functionality).
- virtual LiveTabContext* CreateLiveTabContext(const std::string& app_name) = 0;
+ virtual LiveTabContext* CreateLiveTabContext(
+ const std::string& app_name,
+ const gfx::Rect& bounds,
+ ui::WindowShowState show_state,
+ const std::string& workspace) = 0;
// Returns the LiveTabContext instance that is associated with
// |tab|, or null if there is no such instance.
@@ -59,10 +67,6 @@ class SESSIONS_EXPORT TabRestoreServiceClient {
// embedder).
virtual std::string GetExtensionAppIDForTab(LiveTab* tab) = 0;
- // Get the sequenced worker pool for running tasks on the backend thread as
- // long as the system is not shutting down.
- virtual base::SequencedWorkerPool* GetBlockingPool() = 0;
-
// Returns the path of the directory to save state into.
virtual base::FilePath GetPathToSaveTo() = 0;
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.cc b/chromium/components/sessions/core/tab_restore_service_helper.cc
index e792dd6b67f..01a089a5e49 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.cc
+++ b/chromium/components/sessions/core/tab_restore_service_helper.cc
@@ -82,6 +82,9 @@ void TabRestoreServiceHelper::CreateHistoricalTab(LiveTab* live_tab,
if (restoring_)
return;
+ // If an entire window is being closed than all of the tabs have already
+ // been persisted via "BrowserClosing". Ignore the subsequent tab closing
+ // notifications.
LiveTabContext* context = client_->FindLiveTabContextForTab(live_tab);
if (closing_contexts_.find(context) != closing_contexts_.end())
return;
@@ -101,6 +104,9 @@ void TabRestoreServiceHelper::BrowserClosing(LiveTabContext* context) {
window->selected_tab_index = context->GetSelectedIndex();
window->timestamp = TimeNow();
window->app_name = context->GetAppName();
+ window->bounds = context->GetRestoredBounds();
+ window->show_state = context->GetRestoredState();
+ window->workspace = context->GetWorkspace();
for (int tab_index = 0; tab_index < context->GetTabCount(); ++tab_index) {
auto tab = base::MakeUnique<Tab>();
@@ -111,6 +117,7 @@ void TabRestoreServiceHelper::BrowserClosing(LiveTabContext* context) {
window->tabs.push_back(std::move(tab));
}
}
+
if (window->tabs.size() == 1 && window->app_name.empty()) {
// Short-circuit creating a Window if only 1 tab was present. This fixes
// http://crbug.com/56744.
@@ -199,7 +206,9 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
// single tab within it. If the entry's ID matches the one to restore,
// then the entire window will be restored.
if (!restoring_tab_in_window) {
- context = client_->CreateLiveTabContext(window.app_name);
+ context =
+ client_->CreateLiveTabContext(window.app_name, window.bounds,
+ window.show_state, window.workspace);
for (size_t tab_i = 0; tab_i < window.tabs.size(); ++tab_i) {
const Tab& tab = *window.tabs[tab_i];
LiveTab* restored_tab = context->AddRestoredTab(
@@ -220,8 +229,7 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
}
} else {
// Restore a single tab from the window. Find the tab that matches the
- // ID
- // in the window and restore it.
+ // ID in the window and restore it.
for (auto tab_i = window.tabs.begin(); tab_i != window.tabs.end();
++tab_i) {
SessionID::id_type restored_tab_browser_id;
@@ -445,7 +453,7 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
tab.navigations, tab.current_navigation_index, tab.from_last_session,
tab.extension_app_id, tab.platform_data.get(), tab.user_agent_override);
} else {
- // We only respsect the tab's original browser if there's no disposition.
+ // We only respect the tab's original browser if there's no disposition.
if (disposition == WindowOpenDisposition::UNKNOWN && tab.browser_id) {
context = client_->FindLiveTabContextWithID(tab.browser_id);
}
@@ -458,7 +466,8 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
if (context && disposition != WindowOpenDisposition::NEW_WINDOW) {
tab_index = tab.tabstrip_index;
} else {
- context = client_->CreateLiveTabContext(std::string());
+ context = client_->CreateLiveTabContext(
+ std::string(), gfx::Rect(), ui::SHOW_STATE_NORMAL, std::string());
if (tab.browser_id)
UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id());
}
@@ -492,14 +501,12 @@ bool TabRestoreServiceHelper::ValidateTab(const Tab& tab) {
}
bool TabRestoreServiceHelper::ValidateWindow(const Window& window) {
- if (static_cast<size_t>(window.selected_tab_index) >= window.tabs.size()) {
+ if (static_cast<size_t>(window.selected_tab_index) >= window.tabs.size())
return false;
- }
for (const auto& tab : window.tabs) {
- if (!ValidateTab(*tab)) {
+ if (!ValidateTab(*tab))
return false;
- }
}
return true;
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index b900638e0cf..28c5cada8b0 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -152,10 +152,16 @@ static_library("test_support") {
"fake_profile_oauth2_token_service.h",
"fake_signin_manager.cc",
"fake_signin_manager.h",
+ "scoped_account_consistency.cc",
+ "scoped_account_consistency.h",
"test_signin_client.cc",
"test_signin_client.h",
]
+ deps = [
+ "//base/test:test_support",
+ ]
+
public_deps = [
":browser",
"//base",
@@ -175,6 +181,7 @@ source_set("unit_tests") {
"account_investigator_unittest.cc",
"account_tracker_service_unittest.cc",
"gaia_cookie_manager_service_unittest.cc",
+ "profile_management_switches_unittest.cc",
"refresh_token_annotation_request_unittest.cc",
"signin_error_controller_unittest.cc",
"signin_header_helper_unittest.cc",
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index fca6fbe2507..757a42fc059 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -6,8 +6,10 @@
#include <stddef.h>
+#include <algorithm>
#include <tuple>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/hash.h"
@@ -131,7 +133,7 @@ std::string SigninStatusFieldToLabel(TimedSigninStatusField field) {
NOTREACHED();
return "Error";
}
-#endif // !defined (OS_CHROMEOS)
+#endif // !defined (OS_CHROMEOS)
void SetPref(PrefService* prefs,
TimedSigninStatusField field,
@@ -534,7 +536,7 @@ AboutSigninInternals::SigninStatus::ToValue(
AddSectionEntry(basic_info, "Chrome Version", product_version);
AddSectionEntry(
basic_info, "Account Consistency?",
- switches::IsAccountConsistencyMirrorEnabled() == true ? "On" : "Off");
+ signin::IsAccountConsistencyMirrorEnabled() == true ? "On" : "Off");
AddSectionEntry(basic_info, "Signin Status",
signin_manager->IsAuthenticated() ? "Signed In" : "Not Signed In");
OAuth2TokenServiceDelegate::LoadCredentialsState load_tokens_state =
@@ -632,7 +634,7 @@ AboutSigninInternals::SigninStatus::ToValue(
"");
}
-#endif // !defined(OS_CHROMEOS)
+#endif // !defined(OS_CHROMEOS)
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
// fixed.
@@ -689,5 +691,14 @@ AboutSigninInternals::SigninStatus::ToValue(
}
signin_status->Set("accountInfo", std::move(account_info));
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ if (signin::IsAccountConsistencyDiceEnabled()) {
+ auto dice_info = base::MakeUnique<base::DictionaryValue>();
+ dice_info->SetBoolean("isSignedIn", signin_manager->IsAuthenticated());
+ signin_status->Set("dice", std::move(dice_info));
+ }
+#endif
+
return signin_status;
}
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 3393ef7333e..3d02ebb2af5 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -240,7 +240,7 @@ void AccountReconcilor::GoogleSignedOut(const std::string& account_id,
}
void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
- if (!switches::IsAccountConsistencyMirrorEnabled()) {
+ if (!signin::IsAccountConsistencyMirrorEnabled()) {
MarkAccountAsAddedToCookie(account_id);
return;
}
@@ -249,7 +249,7 @@ void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
}
void AccountReconcilor::PerformLogoutAllAccountsAction() {
- if (!switches::IsAccountConsistencyMirrorEnabled())
+ if (!signin::IsAccountConsistencyMirrorEnabled())
return;
VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
cookie_manager_service_->LogOutAllAccounts(kSource);
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index d7d0c958299..57e1962642b 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -13,21 +13,26 @@ generate_jni("jni_headers") {
android_library("java") {
deps = [
+ "$google_play_services_package:google_play_services_auth_base_java",
+ "$google_play_services_package:google_play_services_base_java",
+ "$google_play_services_package:google_play_services_basement_java",
"//base:base_java",
"//net/android:net_java",
"//third_party/android_tools:android_support_annotations_java",
- google_play_services_library,
]
java_files = [
"java/src/org/chromium/components/signin/AccountManagerDelegate.java",
+ "java/src/org/chromium/components/signin/AccountManagerDelegateException.java",
"java/src/org/chromium/components/signin/AccountManagerFacade.java",
- "java/src/org/chromium/components/signin/AccountManagerHelper.java",
+ "java/src/org/chromium/components/signin/AccountManagerResult.java",
"java/src/org/chromium/components/signin/AccountsChangeObserver.java",
"java/src/org/chromium/components/signin/AuthException.java",
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
"java/src/org/chromium/components/signin/ChromeSigninController.java",
- "java/src/org/chromium/components/signin/AccountManagerDelegateException.java",
+ "java/src/org/chromium/components/signin/GmsAvailabilityException.java",
+ "java/src/org/chromium/components/signin/GmsJustUpdatedException.java",
+ "java/src/org/chromium/components/signin/ProfileDataSource.java",
"java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
]
}
@@ -40,6 +45,7 @@ android_library("javatests") {
"//base:base_java",
"//base:base_java_test_support",
"//third_party/android_support_test_runner:runner_java",
+ "//third_party/junit",
]
java_files = [ "javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java" ]
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
index 2fbdd2a0076..05c2602bc3e 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
@@ -47,7 +47,7 @@ ChildAccountInfoFetcherAndroid::ChildAccountInfoFetcherAndroid(
ChildAccountInfoFetcherAndroid::~ChildAccountInfoFetcherAndroid() {
Java_ChildAccountInfoFetcher_destroy(base::android::AttachCurrentThread(),
- j_child_account_info_fetcher_.obj());
+ j_child_account_info_fetcher_);
}
void SetIsChildAccount(JNIEnv* env,
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 12486b67317..dde5fb6d274 100644
--- a/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -131,8 +131,7 @@ bool ChromeConnectedHeaderHelper::IsUrlEligibleForRequestHeader(
return false;
GURL origin(url.GetOrigin());
- bool is_enable_account_consistency =
- switches::IsAccountConsistencyMirrorEnabled();
+ bool is_enable_account_consistency = IsAccountConsistencyMirrorEnabled();
bool is_google_url = is_enable_account_consistency &&
(google_util::IsGoogleDomainUrl(
url, google_util::ALLOW_SUBDOMAIN,
@@ -163,7 +162,7 @@ std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
base::IntToString(profile_mode_mask).c_str()));
parts.push_back(base::StringPrintf(
"%s=%s", kEnableAccountConsistencyAttrName,
- switches::IsAccountConsistencyMirrorEnabled() ? "true" : "false"));
+ IsAccountConsistencyMirrorEnabled() ? "true" : "false"));
return base::JoinString(parts, is_header_request ? "," : ":");
}
diff --git a/chromium/components/signin/core/browser/dice_header_helper.cc b/chromium/components/signin/core/browser/dice_header_helper.cc
index 4d8aade04f2..c0bf31e26f6 100644
--- a/chromium/components/signin/core/browser/dice_header_helper.cc
+++ b/chromium/components/signin/core/browser/dice_header_helper.cc
@@ -37,6 +37,9 @@ DiceAction GetDiceActionFromHeader(const std::string& value) {
} // namespace
+DiceHeaderHelper::DiceHeaderHelper(bool signed_in_with_auth_error)
+ : signed_in_with_auth_error_(signed_in_with_auth_error) {}
+
// static
DiceResponseParams DiceHeaderHelper::BuildDiceSigninResponseParams(
const std::string& header_value) {
@@ -127,10 +130,17 @@ DiceResponseParams DiceHeaderHelper::BuildDiceSignoutResponseParams(
}
bool DiceHeaderHelper::IsUrlEligibleForRequestHeader(const GURL& url) {
- if (switches::GetAccountConsistencyMethod() !=
- switches::AccountConsistencyMethod::kDice) {
+ if (!IsDiceFixAuthErrorsEnabled())
+ return false;
+
+ // With kDiceFixAuthError, only set the request header if the user is signed
+ // in and has an authentication error.
+ if (!signed_in_with_auth_error_ &&
+ (GetAccountConsistencyMethod() ==
+ AccountConsistencyMethod::kDiceFixAuthErrors)) {
return false;
}
+
return gaia::IsGaiaSignonRealm(url.GetOrigin());
}
diff --git a/chromium/components/signin/core/browser/dice_header_helper.h b/chromium/components/signin/core/browser/dice_header_helper.h
index d83fa037693..bece6b77d65 100644
--- a/chromium/components/signin/core/browser/dice_header_helper.h
+++ b/chromium/components/signin/core/browser/dice_header_helper.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/macros.h"
#include "components/signin/core/browser/signin_header_helper.h"
class GURL;
@@ -16,7 +17,7 @@ namespace signin {
// SigninHeaderHelper implementation managing the Dice header.
class DiceHeaderHelper : public SigninHeaderHelper {
public:
- DiceHeaderHelper() {}
+ explicit DiceHeaderHelper(bool signed_in_with_auth_error);
~DiceHeaderHelper() override {}
// Returns the parameters contained in the X-Chrome-ID-Consistency-Response
@@ -37,6 +38,10 @@ class DiceHeaderHelper : public SigninHeaderHelper {
private:
// SigninHeaderHelper implementation:
bool IsUrlEligibleForRequestHeader(const GURL& url) override;
+
+ bool signed_in_with_auth_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiceHeaderHelper);
};
} // namespace signin
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
index 0e664641579..85e7d283991 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -65,7 +65,7 @@ const int kMaxFetcherRetries = 8;
// Name of the GAIA cookie that is being observed to detect when available
// accounts have changed in the content-area.
-const char* kGaiaCookieName = "APISID";
+const char* const kGaiaCookieName = "APISID";
enum GaiaCookieRequestType {
ADD_ACCOUNT,
@@ -144,11 +144,9 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::Start() {
helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
// Some fetches may timeout. Start a timer to decide when the result fetcher
- // has waited long enough.
- // TODO(rogerta): I have no idea how long to wait before timing out.
- // Gaia folks say this should take no more than 2 second even in mobile.
- // This will need to be tweaked.
- timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), this,
+ // has waited long enough. See https://crbug.com/750316#c36 for details on
+ // exact timeout duration.
+ timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(7), this,
&GaiaCookieManagerService::ExternalCcResultFetcher::Timeout);
}
@@ -234,7 +232,7 @@ GaiaCookieManagerService::ExternalCcResultFetcher::CreateFetcher(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification:
"Not implemented. Disabling GaiaCookieManager would break "
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
index 30d0562f6b0..b9a25211e69 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -5,13 +5,13 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
-#include <deque>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
@@ -308,7 +308,7 @@ class GaiaCookieManagerService : public KeyedService,
// A worklist for this class. Stores any pending requests that couldn't be
// executed right away, since this class only permits one request to be
// executed at a time.
- std::deque<GaiaCookieRequest> requests_;
+ base::circular_deque<GaiaCookieRequest> requests_;
// List of observers to notify when merge session completes.
// Makes sure list is empty on destruction.
diff --git a/chromium/components/signin/core/browser/profile_management_switches_unittest.cc b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
new file mode 100644
index 00000000000..8119b0b009e
--- /dev/null
+++ b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
@@ -0,0 +1,59 @@
+// 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/signin/core/common/profile_management_switches.h"
+
+#include "base/macros.h"
+#include "components/signin/core/browser/scoped_account_consistency.h"
+#include "components/signin/core/common/signin_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace signin {
+
+#if BUILDFLAG(ENABLE_MIRROR)
+TEST(ProfileManagementSwitchesTest, GetAccountConsistencyMethodMirror) {
+ // Mirror is enabled by default on some platforms.
+ EXPECT_EQ(AccountConsistencyMethod::kMirror, GetAccountConsistencyMethod());
+ EXPECT_TRUE(IsAccountConsistencyMirrorEnabled());
+ EXPECT_FALSE(IsAccountConsistencyDiceEnabled());
+ EXPECT_FALSE(IsDiceFixAuthErrorsEnabled());
+}
+#else
+TEST(ProfileManagementSwitchesTest, GetAccountConsistencyMethod) {
+ // By default account consistency is disabled.
+ EXPECT_EQ(AccountConsistencyMethod::kDisabled, GetAccountConsistencyMethod());
+ EXPECT_FALSE(IsAccountConsistencyMirrorEnabled());
+ EXPECT_FALSE(IsAccountConsistencyDiceEnabled());
+ EXPECT_FALSE(IsDiceFixAuthErrorsEnabled());
+
+ // Check that feature flags work.
+ struct TestCase {
+ AccountConsistencyMethod method;
+ bool expect_mirror_enabled;
+ bool expect_dice_fix_auth_errors;
+ bool expect_dice_enabled;
+ };
+
+ TestCase test_cases[] = {
+ {AccountConsistencyMethod::kDisabled, false, false, false},
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ {AccountConsistencyMethod::kDiceFixAuthErrors, false, true, false},
+ {AccountConsistencyMethod::kDice, false, true, true},
+#endif
+ {AccountConsistencyMethod::kMirror, true, false, false}
+ };
+
+ for (TestCase test_case : test_cases) {
+ ScopedAccountConsistency scoped_method(test_case.method);
+ EXPECT_EQ(test_case.method, GetAccountConsistencyMethod());
+ EXPECT_EQ(test_case.expect_mirror_enabled,
+ IsAccountConsistencyMirrorEnabled());
+ EXPECT_EQ(test_case.expect_dice_fix_auth_errors,
+ IsDiceFixAuthErrorsEnabled());
+ EXPECT_EQ(test_case.expect_dice_enabled, IsAccountConsistencyDiceEnabled());
+ }
+}
+#endif // BUILDFLAG(ENABLE_MIRROR)
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/resources/signin_index.css b/chromium/components/signin/core/browser/resources/signin_index.css
index ebcc78732f1..34531a7ceac 100644
--- a/chromium/components/signin/core/browser/resources/signin_index.css
+++ b/chromium/components/signin/core/browser/resources/signin_index.css
@@ -76,3 +76,13 @@ tr[highlighted]:nth-child(odd) {
-webkit-animation-name: highlight2;
-webkit-animation-timing-function: linear;
}
+
+paper-button.dice-primary-action {
+ --paper-button-flat-keyboard-focus: {
+ background: rgb(58, 117, 215);
+ font-weight: 500;
+ margin-top: 20;
+ };
+ background: var(--google-blue-500);
+ color: white;
+}
diff --git a/chromium/components/signin/core/browser/resources/signin_index.html b/chromium/components/signin/core/browser/resources/signin_index.html
index 513a934658d..2b300d38b12 100644
--- a/chromium/components/signin/core/browser/resources/signin_index.html
+++ b/chromium/components/signin/core/browser/resources/signin_index.html
@@ -2,6 +2,9 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <link rel="import" href="chrome://resources/html/polymer.html">
+ <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+ <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<title>Signin Internals</title>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/util.js"></script>
@@ -86,6 +89,17 @@
</table>
</div>
</div>
+ <div id="diceSection" hidden="true">
+ <h2>Desktop Identity Consistency</h2>
+ <div class="action-container">
+ <paper-button class="dice-primary-action" id="enableSyncButton">
+ Enable Sync
+ </paper-button>
+ <paper-button class="dice-primary-action" id="disableSyncButton">
+ Disable Sync
+ </paper-button>
+ </div>
+ </div>
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="chrome://signin-internals/signin_internals.js"></script>
diff --git a/chromium/components/signin/core/browser/resources/signin_internals.js b/chromium/components/signin/core/browser/resources/signin_internals.js
index 5ac1b25eeb8..fb0f47c275e 100644
--- a/chromium/components/signin/core/browser/resources/signin_internals.js
+++ b/chromium/components/signin/core/browser/resources/signin_internals.js
@@ -161,6 +161,39 @@ for (var i = 0; i < signinFunctions.length; ++i) {
chrome.signin[signinFunction] = makeSigninFunction(signinFunction);
}
+cr.define('chrome.signin.dice', function() {
+ 'use strict';
+
+ function initialize() {
+ $('enableSyncButton').addEventListener('click', function(e) {
+ chrome.send("enableSync");
+ });
+ }
+
+ function refreshUI(signinInfo) {
+ var diceInfo = signinInfo.dice;
+
+ if (diceInfo == undefined) {
+ $('diceSection').hidden = true;
+ return;
+ }
+
+ $('diceSection').hidden = false;
+ if (diceInfo.isSignedIn) {
+ $('enableSyncButton').hidden = true;
+ $('disableSyncButton').hidden = false;
+ } else {
+ $('disableSyncButton').hidden = true;
+ $('enableSyncButton').hidden = false;
+ }
+ }
+
+ return {
+ initialize: initialize,
+ refreshUI: refreshUI,
+ };
+});
+
chrome.signin.internalsInfo = {};
// Replace the displayed values with the latest fetched ones.
@@ -169,6 +202,9 @@ function refreshSigninInfo(signinInfo) {
jstProcess(new JsEvalContext(signinInfo), $('signin-info'));
jstProcess(new JsEvalContext(signinInfo), $('token-info'));
jstProcess(new JsEvalContext(signinInfo), $('account-info'));
+
+ // Refresh the DICE section if needed.
+ chrome.signin.dice.refreshUI(signinInfo);
}
// Replace the cookie information with the fetched values.
@@ -183,6 +219,7 @@ function onLoad() {
chrome.signin.onSigninInfoChanged.addListener(refreshSigninInfo);
chrome.signin.onCookieAccountsFetched.addListener(updateCookieAccounts);
+ chrome.signin.dice.initialize();
}
document.addEventListener('DOMContentLoaded', onLoad, false);
diff --git a/chromium/components/signin/core/browser/scoped_account_consistency.cc b/chromium/components/signin/core/browser/scoped_account_consistency.cc
new file mode 100644
index 00000000000..fbf910f9d8e
--- /dev/null
+++ b/chromium/components/signin/core/browser/scoped_account_consistency.cc
@@ -0,0 +1,63 @@
+// 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/signin/core/browser/scoped_account_consistency.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/signin/core/common/signin_features.h"
+
+namespace signin {
+
+ScopedAccountConsistency::ScopedAccountConsistency(
+ AccountConsistencyMethod method) {
+#if !BUILDFLAG(ENABLE_DICE_SUPPORT)
+ DCHECK_NE(AccountConsistencyMethod::kDice, method);
+ DCHECK_NE(AccountConsistencyMethod::kDiceFixAuthErrors, method);
+#endif
+
+#if BUILDFLAG(ENABLE_MIRROR)
+ DCHECK_EQ(AccountConsistencyMethod::kMirror, method);
+ return;
+#endif
+
+ if (method == AccountConsistencyMethod::kDisabled) {
+ scoped_feature_list_.InitAndDisableFeature(kAccountConsistencyFeature);
+ DCHECK_EQ(method, GetAccountConsistencyMethod());
+ return;
+ }
+
+ // Set up the account consistency method.
+ std::string feature_value;
+ switch (method) {
+ case AccountConsistencyMethod::kDisabled:
+ NOTREACHED();
+ break;
+ case AccountConsistencyMethod::kMirror:
+ feature_value = kAccountConsistencyFeatureMethodMirror;
+ break;
+ case AccountConsistencyMethod::kDiceFixAuthErrors:
+ feature_value = kAccountConsistencyFeatureMethodDiceFixAuthErrors;
+ break;
+ case AccountConsistencyMethod::kDice:
+ feature_value = kAccountConsistencyFeatureMethodDice;
+ break;
+ }
+
+ std::map<std::string, std::string> feature_params;
+ feature_params[kAccountConsistencyFeatureMethodParameter] = feature_value;
+
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ kAccountConsistencyFeature, feature_params);
+ DCHECK_EQ(method, GetAccountConsistencyMethod());
+}
+
+ScopedAccountConsistency::~ScopedAccountConsistency() {}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/scoped_account_consistency.h b/chromium/components/signin/core/browser/scoped_account_consistency.h
new file mode 100644
index 00000000000..0c4938d2314
--- /dev/null
+++ b/chromium/components/signin/core/browser/scoped_account_consistency.h
@@ -0,0 +1,56 @@
+// 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_SIGNIN_CORE_BROWSER_SCOPED_ACCOUNT_CONSISTENCY_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_SCOPED_ACCOUNT_CONSISTENCY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/signin/core/common/profile_management_switches.h"
+
+namespace signin {
+
+// Changes the account consistency method while it is in scope. Useful for
+// tests.
+class ScopedAccountConsistency {
+ public:
+ explicit ScopedAccountConsistency(AccountConsistencyMethod method);
+ ~ScopedAccountConsistency();
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAccountConsistency);
+};
+
+// Specialized helper classes for each account consistency method:
+// ScopedAccountConsistencyDice, ScopedAccountConsistencyMirror, ...
+
+#define SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(method) \
+ class ScopedAccountConsistency##method { \
+ public: \
+ ScopedAccountConsistency##method() \
+ : scoped_consistency_(AccountConsistencyMethod::k##method) {} \
+ \
+ private: \
+ ScopedAccountConsistency scoped_consistency_; \
+ DISALLOW_COPY_AND_ASSIGN(ScopedAccountConsistency##method); \
+ }
+
+// ScopedAccountConsistencyDisabled:
+SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(Disabled);
+// ScopedAccountConsistencyMirror:
+SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(Mirror);
+// ScopedAccountConsistencyDiceFixAuthErrors:
+SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(DiceFixAuthErrors);
+// ScopedAccountConsistencyDice:
+SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION(Dice);
+
+#undef SCOPED_ACCOUNT_CONSISTENCY_SPECIALIZATION
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_SCOPED_ACCOUNT_CONSISTENCY_H_
diff --git a/chromium/components/signin/core/browser/signin_header_helper.cc b/chromium/components/signin/core/browser/signin_header_helper.cc
index 0a326c1f807..ef836c4158f 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper.cc
@@ -24,8 +24,9 @@
namespace signin {
-extern const char kChromeConnectedHeader[] = "X-Chrome-Connected";
-extern const char kDiceRequestHeader[] = "X-Chrome-ID-Consistency-Request";
+const char kChromeConnectedHeader[] = "X-Chrome-Connected";
+const char kDiceRequestHeader[] = "X-Chrome-ID-Consistency-Request";
+const char kDiceResponseHeader[] = "X-Chrome-ID-Consistency-Response";
ManageAccountsParams::ManageAccountsParams()
: service_type(GAIA_SERVICE_TYPE_NONE),
@@ -125,16 +126,17 @@ bool SigninHeaderHelper::ShouldBuildRequestHeader(
return true;
}
-void AppendOrRemoveAccountConsistentyRequestHeader(
+void AppendOrRemoveAccountConsistencyRequestHeader(
net::URLRequest* request,
const GURL& redirect_url,
const std::string& account_id,
bool sync_enabled,
+ bool sync_has_auth_error,
const content_settings::CookieSettings* cookie_settings,
int profile_mode_mask) {
const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
- DiceHeaderHelper dice_helper;
+ DiceHeaderHelper dice_helper(!account_id.empty() && sync_has_auth_error);
std::string dice_header_value;
if (dice_helper.ShouldBuildRequestHeader(url, cookie_settings)) {
dice_header_value =
diff --git a/chromium/components/signin/core/browser/signin_header_helper.h b/chromium/components/signin/core/browser/signin_header_helper.h
index 06b72cb3ad6..1e43ebb975f 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.h
+++ b/chromium/components/signin/core/browser/signin_header_helper.h
@@ -33,6 +33,7 @@ enum ProfileMode {
extern const char kChromeConnectedHeader[];
extern const char kDiceRequestHeader[];
+extern const char kDiceResponseHeader[];
// The ServiceType specified by Gaia in the response header accompanying the 204
// response. This indicates the action Chrome is supposed to lead the user to
@@ -159,11 +160,12 @@ std::string BuildMirrorRequestCookieIfPossible(
// Adds account consistency header to all Gaia requests from a connected
// profile, with the exception of requests from gaia webview.
// Removes the header in case it should not be transfered to a redirected url.
-void AppendOrRemoveAccountConsistentyRequestHeader(
+void AppendOrRemoveAccountConsistencyRequestHeader(
net::URLRequest* request,
const GURL& redirect_url,
const std::string& account_id,
bool sync_enabled,
+ bool sync_has_auth_error,
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 bade766e6fb..e6965ea651f 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -12,6 +12,7 @@
#include "base/strings/stringprintf.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/signin/core/browser/chrome_connected_header_helper.h"
+#include "components/signin/core/browser/scoped_account_consistency.h"
#include "components/signin/core/common/profile_management_switches.h"
#include "components/signin/core/common/signin_features.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
@@ -51,15 +52,15 @@ class SigninHeaderHelperTest : public testing::Test {
expected_request);
}
- std::unique_ptr<net::URLRequest> CreateRequest(const GURL& url,
- const std::string& account_id,
- bool sync_enabled) {
+ std::unique_ptr<net::URLRequest> CreateRequest(
+ const GURL& url,
+ const std::string& account_id) {
std::unique_ptr<net::URLRequest> url_request =
url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
TRAFFIC_ANNOTATION_FOR_TESTS);
- AppendOrRemoveAccountConsistentyRequestHeader(
- url_request.get(), GURL(), account_id, sync_enabled,
- cookie_settings_.get(), PROFILE_MODE_DEFAULT);
+ AppendOrRemoveAccountConsistencyRequestHeader(
+ url_request.get(), GURL(), account_id, sync_enabled_,
+ sync_has_auth_error_, cookie_settings_.get(), PROFILE_MODE_DEFAULT);
return url_request;
}
@@ -71,7 +72,8 @@ class SigninHeaderHelperTest : public testing::Test {
std::string request;
EXPECT_EQ(
url_request->extra_request_headers().GetHeader(header_name, &request),
- expected_result);
+ expected_result)
+ << header_name << ": " << request;
if (expected_result) {
EXPECT_EQ(expected_request, request);
}
@@ -81,7 +83,7 @@ class SigninHeaderHelperTest : public testing::Test {
const std::string& account_id,
const std::string& expected_request) {
std::unique_ptr<net::URLRequest> url_request =
- CreateRequest(url, account_id, false /* sync_enabled */);
+ CreateRequest(url, account_id);
CheckAccountConsistencyHeaderRequest(
url_request.get(), kChromeConnectedHeader, expected_request);
}
@@ -89,11 +91,10 @@ class SigninHeaderHelperTest : public testing::Test {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void CheckDiceHeaderRequest(const GURL& url,
const std::string& account_id,
- bool sync_enabled,
const std::string& expected_mirror_request,
const std::string& expected_dice_request) {
std::unique_ptr<net::URLRequest> url_request =
- CreateRequest(url, account_id, sync_enabled);
+ CreateRequest(url, account_id);
CheckAccountConsistencyHeaderRequest(
url_request.get(), kChromeConnectedHeader, expected_mirror_request);
CheckAccountConsistencyHeaderRequest(url_request.get(), kDiceRequestHeader,
@@ -103,6 +104,9 @@ class SigninHeaderHelperTest : public testing::Test {
base::MessageLoop loop_;
+ bool sync_enabled_ = false;
+ bool sync_has_auth_error_ = false;
+
sync_preferences::TestingPrefServiceSyncable prefs_;
net::TestURLRequestContext url_request_context_;
@@ -113,8 +117,7 @@ class SigninHeaderHelperTest : public testing::Test {
// Tests that no Mirror request is returned when the user is not signed in (no
// account id).
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "", "");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "", "");
}
@@ -122,8 +125,7 @@ TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
// Tests that no Mirror request is returned when the cookies aren't allowed to
// be set.
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestCookieSettingBlocked) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "0123456789", "");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "0123456789", "");
@@ -131,8 +133,7 @@ TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestCookieSettingBlocked) {
// Tests that no Mirror request is returned when the target is a non-Google URL.
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestExternalURL) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckMirrorHeaderRequest(GURL("https://foo.com"), "0123456789", "");
CheckMirrorCookieRequest(GURL("https://foo.com"), "0123456789", "");
}
@@ -140,8 +141,7 @@ TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestExternalURL) {
// Tests that the Mirror request is returned without the GAIA Id when the target
// is a google TLD domain.
TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckMirrorHeaderRequest(GURL("https://google.fr"), "0123456789",
"mode=0,enable_account_consistency=true");
CheckMirrorCookieRequest(GURL("https://google.de"), "0123456789",
@@ -151,8 +151,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
// Tests that the Mirror request is returned when the target is the domain
// google.com, and that the GAIA Id is only attached for the cookie.
TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckMirrorHeaderRequest(GURL("https://www.google.com"), "0123456789",
"mode=0,enable_account_consistency=true");
CheckMirrorCookieRequest(
@@ -167,7 +166,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
// Tests that the Mirror request is returned when the target is a Gaia URL, even
// if account consistency is disabled.
TEST_F(SigninHeaderHelperTest, TestMirrorRequestGaiaURL) {
- ASSERT_FALSE(switches::IsAccountConsistencyMirrorEnabled());
+ ASSERT_FALSE(IsAccountConsistencyMirrorEnabled());
CheckMirrorHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
"mode=0,enable_account_consistency=false");
CheckMirrorCookieRequest(
@@ -177,11 +176,10 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGaiaURL) {
// Tests Dice requests.
TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
- switches::EnableAccountConsistencyDiceForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyDice scoped_dice;
// ChromeConnected but no Dice for Docs URLs.
CheckDiceHeaderRequest(
- GURL("https://docs.google.com"), "0123456789", false /* sync_enabled */,
+ GURL("https://docs.google.com"), "0123456789",
"id=0123456789,mode=0,enable_account_consistency=false", "");
// ChromeConnected and Dice for Gaia URLs.
@@ -189,34 +187,48 @@ TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
ASSERT_FALSE(client_id.empty());
CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
- false /* sync_enabled */,
"mode=0,enable_account_consistency=false",
"client_id=" + client_id);
// Sync enabled: check that the Dice header has the Sync account ID and that
// the mirror header is not modified.
+ sync_enabled_ = true;
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
- true /* sync_enabled */, "mode=0,enable_account_consistency=false",
+ "mode=0,enable_account_consistency=false",
"client_id=" + client_id + ",sync_account_id=0123456789");
+ sync_enabled_ = false;
// No ChromeConnected and no Dice for other URLs.
- CheckDiceHeaderRequest(GURL("https://www.google.com"), "0123456789",
- false /* sync_enabled */, "", "");
+ CheckDiceHeaderRequest(GURL("https://www.google.com"), "0123456789", "", "");
}
// Tests that no Dice request is returned when Dice is not enabled.
TEST_F(SigninHeaderHelperTest, TestNoDiceRequestWhenDisabled) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
- false /* sync_enabled */,
"mode=0,enable_account_consistency=true", "");
}
+// Tests that a Dice request is returned only when there is an authentication
+// error if the method is kDiceFixAuthErrors.
+TEST_F(SigninHeaderHelperTest, TestDiceFixAuthError) {
+ ScopedAccountConsistencyDiceFixAuthErrors scoped_dice_fix_auth_errors;
+ // Without authentication error, no Dice request.
+ CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
+ "mode=0,enable_account_consistency=false", "");
+
+ // With authentication error, there is a Dice request.
+ sync_has_auth_error_ = true;
+ CheckDiceHeaderRequest(
+ GURL("https://accounts.google.com"), "0123456789",
+ "mode=0,enable_account_consistency=false",
+ "client_id=" + GaiaUrls::GetInstance()->oauth2_chrome_client_id());
+}
+
// Tests that the Mirror request is returned with the GAIA Id on Drive origin,
// even if account consistency is disabled.
TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
- ASSERT_FALSE(switches::IsAccountConsistencyMirrorEnabled());
+ ASSERT_FALSE(IsAccountConsistencyMirrorEnabled());
CheckMirrorHeaderRequest(
GURL("https://docs.google.com/document"), "0123456789",
"id=0123456789,mode=0,enable_account_consistency=false");
@@ -225,8 +237,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
"id=0123456789:mode=0:enable_account_consistency=false");
// Enable Account Consistency will override the disable.
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
CheckMirrorHeaderRequest(
GURL("https://docs.google.com/document"), "0123456789",
"id=0123456789,mode=0,enable_account_consistency=true");
@@ -329,17 +340,16 @@ TEST_F(SigninHeaderHelperTest, TestBuildDiceResponseParams) {
// Tests that the Mirror header request is returned normally when the redirect
// URL is eligible.
TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
const GURL url("https://docs.google.com/document");
const GURL redirect_url("https://www.google.com");
const std::string account_id = "0123456789";
std::unique_ptr<net::URLRequest> url_request =
url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
TRAFFIC_ANNOTATION_FOR_TESTS);
- AppendOrRemoveAccountConsistentyRequestHeader(
- url_request.get(), redirect_url, account_id, false /* sync_enabled */,
- cookie_settings_.get(), PROFILE_MODE_DEFAULT);
+ AppendOrRemoveAccountConsistencyRequestHeader(
+ url_request.get(), redirect_url, account_id, sync_enabled_,
+ sync_has_auth_error_, cookie_settings_.get(), PROFILE_MODE_DEFAULT);
EXPECT_TRUE(
url_request->extra_request_headers().HasHeader(kChromeConnectedHeader));
}
@@ -347,17 +357,16 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
// Tests that the Mirror header request is stripped when the redirect URL is not
// eligible.
TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
const GURL url("https://docs.google.com/document");
const GURL redirect_url("http://www.foo.com");
const std::string account_id = "0123456789";
std::unique_ptr<net::URLRequest> url_request =
url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
TRAFFIC_ANNOTATION_FOR_TESTS);
- AppendOrRemoveAccountConsistentyRequestHeader(
- url_request.get(), redirect_url, account_id, false /* sync_enabled */,
- cookie_settings_.get(), PROFILE_MODE_DEFAULT);
+ AppendOrRemoveAccountConsistencyRequestHeader(
+ url_request.get(), redirect_url, account_id, sync_enabled_,
+ sync_has_auth_error_, cookie_settings_.get(), PROFILE_MODE_DEFAULT);
EXPECT_FALSE(
url_request->extra_request_headers().HasHeader(kChromeConnectedHeader));
}
@@ -365,8 +374,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
// Tests that the Mirror header, whatever its value is, is untouched when both
// the current and the redirect URL are non-eligible.
TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
- switches::EnableAccountConsistencyMirrorForTesting(
- base::CommandLine::ForCurrentProcess());
+ ScopedAccountConsistencyMirror scoped_mirror;
const GURL url("https://www.bar.com");
const GURL redirect_url("http://www.foo.com");
const std::string account_id = "0123456789";
@@ -376,9 +384,9 @@ TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
TRAFFIC_ANNOTATION_FOR_TESTS);
url_request->SetExtraRequestHeaderByName(kChromeConnectedHeader, fake_header,
false);
- AppendOrRemoveAccountConsistentyRequestHeader(
- url_request.get(), redirect_url, account_id, false /* sync_enabled */,
- cookie_settings_.get(), PROFILE_MODE_DEFAULT);
+ AppendOrRemoveAccountConsistencyRequestHeader(
+ url_request.get(), redirect_url, account_id, sync_enabled_,
+ sync_has_auth_error_, cookie_settings_.get(), PROFILE_MODE_DEFAULT);
std::string header;
EXPECT_TRUE(url_request->extra_request_headers().GetHeader(
kChromeConnectedHeader, &header));
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index 5ced3207823..60f309fc6a4 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -376,8 +376,11 @@ void SigninManager::OnExternalSigninCompleted(const std::string& username) {
}
void SigninManager::OnSignedIn() {
+ bool reauth_in_progress = IsAuthenticated();
+
client_->GetPrefs()->SetInt64(prefs::kSignedInTime,
base::Time::Now().ToInternalValue());
+
SetAuthenticatedAccountInfo(possibly_invalid_gaia_id_,
possibly_invalid_email_);
const std::string gaia_id = possibly_invalid_gaia_id_;
@@ -387,14 +390,8 @@ void SigninManager::OnSignedIn() {
possibly_invalid_email_.clear();
signin_manager_signed_in_ = true;
- for (auto& observer : observer_list_) {
- observer.GoogleSigninSucceeded(GetAuthenticatedAccountId(),
- GetAuthenticatedAccountInfo().email);
-
- observer.GoogleSigninSucceededWithPassword(
- GetAuthenticatedAccountId(), GetAuthenticatedAccountInfo().email,
- password_);
- }
+ if (!reauth_in_progress)
+ FireGoogleSigninSucceeded();
client_->OnSignedIn(GetAuthenticatedAccountId(), gaia_id,
GetAuthenticatedAccountInfo().email, password_);
@@ -407,6 +404,15 @@ void SigninManager::OnSignedIn() {
PostSignedIn();
}
+void SigninManager::FireGoogleSigninSucceeded() {
+ std::string account_id = GetAuthenticatedAccountId();
+ std::string email = GetAuthenticatedAccountInfo().email;
+ for (auto& observer : observer_list_) {
+ observer.GoogleSigninSucceeded(account_id, email);
+ observer.GoogleSigninSucceededWithPassword(account_id, email, password_);
+ }
+}
+
void SigninManager::PostSignedIn() {
if (!signin_manager_signed_in_ || !user_info_fetched_by_account_tracker_)
return;
diff --git a/chromium/components/signin/core/browser/signin_manager.h b/chromium/components/signin/core/browser/signin_manager.h
index bae32cf78e4..7ec3c3f69cf 100644
--- a/chromium/components/signin/core/browser/signin_manager.h
+++ b/chromium/components/signin/core/browser/signin_manager.h
@@ -184,15 +184,18 @@ class SigninManager : public SigninManagerBase,
// a sign-in success notification.
void OnSignedIn();
+ // Send all observers |GoogleSigninSucceeded| notifications.
+ void FireGoogleSigninSucceeded();
+
// Waits for the AccountTrackerService, then sends GoogleSigninSucceeded to
// the client and clears the local password.
void PostSignedIn();
- // AccountTrackerService::Observer implementation.
+ // AccountTrackerService::Observer:
void OnAccountUpdated(const AccountInfo& info) override;
void OnAccountUpdateFailed(const std::string& account_id) override;
- // OAuth2TokenService::Observer
+ // OAuth2TokenService::Observer:
void OnRefreshTokensLoaded() override;
// Called when a new request to re-authenticate a user is in progress.
diff --git a/chromium/components/signin/core/browser/signin_manager_base.cc b/chromium/components/signin/core/browser/signin_manager_base.cc
index 14ad0380e7a..bb6331147f3 100644
--- a/chromium/components/signin/core/browser/signin_manager_base.cc
+++ b/chromium/components/signin/core/browser/signin_manager_base.cc
@@ -184,9 +184,9 @@ void SigninManagerBase::SetAuthenticatedAccountId(
const std::string& account_id) {
DCHECK(!account_id.empty());
if (!authenticated_account_id_.empty()) {
- DLOG_IF(ERROR, account_id != authenticated_account_id_)
- << "Tried to change the authenticated id to something different: "
- << "Current: " << authenticated_account_id_ << ", New: " << account_id;
+ DCHECK_EQ(account_id, authenticated_account_id_)
+ << "Changing the authenticated account while authenticated is not "
+ "allowed.";
return;
}
diff --git a/chromium/components/signin/core/browser/signin_manager_base.h b/chromium/components/signin/core/browser/signin_manager_base.h
index a7c08678e66..690c209591f 100644
--- a/chromium/components/signin/core/browser/signin_manager_base.h
+++ b/chromium/components/signin/core/browser/signin_manager_base.h
@@ -59,6 +59,7 @@ class SigninManagerBase : public KeyedService {
virtual void GoogleSigninFailed(const GoogleServiceAuthError& error) {}
// Called when a user signs into Google services such as sync.
+ // This method is not called during a reauth.
virtual void GoogleSigninSucceeded(const std::string& account_id,
const std::string& username) {}
@@ -81,6 +82,7 @@ class SigninManagerBase : public KeyedService {
// Called when a user signs into Google services such as sync. Also passes
// the password of the Google account that was used to sign in.
+ // This method is not called during a reauth.
//
// Observers should override |GoogleSigninSucceeded| if they are not
// interested in the password thas was used during the sign-in.
@@ -175,6 +177,10 @@ class SigninManagerBase : public KeyedService {
}
// Sets the authenticated user's account id.
+ // If the user is already authenticated with the same account id, then this
+ // method is a no-op.
+ // It is forbidden to call this method if the user is already authenticated
+ // with a different account (this method will DCHECK in that case).
void SetAuthenticatedAccountId(const std::string& account_id);
// Used by subclass to clear the authenticated user instead of using
diff --git a/chromium/components/signin/core/browser/signin_metrics.cc b/chromium/components/signin/core/browser/signin_metrics.cc
index d754cf87a30..7daf5965000 100644
--- a/chromium/components/signin/core/browser/signin_metrics.cc
+++ b/chromium/components/signin/core/browser/signin_metrics.cc
@@ -186,7 +186,7 @@ void LogAuthError(GoogleServiceAuthError::State auth_error) {
GoogleServiceAuthError::State::NUM_STATES);
}
-void LogSigninConfirmHistogramValue(int action) {
+void LogSigninConfirmHistogramValue(ConfirmationUsage action) {
UMA_HISTOGRAM_ENUMERATION("Signin.OneClickConfirmation", action,
signin_metrics::HISTOGRAM_CONFIRM_MAX);
}
diff --git a/chromium/components/signin/core/browser/signin_metrics.h b/chromium/components/signin/core/browser/signin_metrics.h
index cc6709e2958..bcaa972e98c 100644
--- a/chromium/components/signin/core/browser/signin_metrics.h
+++ b/chromium/components/signin/core/browser/signin_metrics.h
@@ -53,7 +53,7 @@ enum ProfileSignout {
};
// Enum values used for use with "AutoLogin.Reverse" histograms.
-enum {
+enum AccessPointAction {
// The infobar was shown to the user.
HISTOGRAM_SHOWN,
// The user pressed the accept button to perform the suggested action.
@@ -82,7 +82,7 @@ enum {
// Enum values used with the "Signin.OneClickConfirmation" histogram, which
// tracks the actions used in the OneClickConfirmation bubble.
-enum {
+enum ConfirmationUsage {
HISTOGRAM_CONFIRM_SHOWN,
HISTOGRAM_CONFIRM_OK,
HISTOGRAM_CONFIRM_RETURN,
@@ -353,7 +353,7 @@ void LogExternalCcResultFetches(
// Track when the current authentication error changed.
void LogAuthError(GoogleServiceAuthError::State auth_error);
-void LogSigninConfirmHistogramValue(int action);
+void LogSigninConfirmHistogramValue(ConfirmationUsage action);
void LogXDevicePromoEligible(CrossDevicePromoEligibility metric);
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 8ead61c4a97..1b499cd3411 100644
--- a/chromium/components/signin/core/browser/signin_status_metrics_provider.cc
+++ b/chromium/components/signin/core/browser/signin_status_metrics_provider.cc
@@ -35,7 +35,7 @@ SigninStatusMetricsProvider::SigninStatusMetricsProvider(
SigninStatusMetricsProvider::~SigninStatusMetricsProvider() {}
-void SigninStatusMetricsProvider::ProvideGeneralMetrics(
+void SigninStatusMetricsProvider::ProvideCurrentSessionData(
metrics::ChromeUserMetricsExtension* uma_proto) {
RecordSigninStatusHistogram(signin_status());
// After a histogram value is recorded, a new UMA session will be started, so
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 ee6f0adf6ba..73cd0a4d676 100644
--- a/chromium/components/signin/core/browser/signin_status_metrics_provider.h
+++ b/chromium/components/signin/core/browser/signin_status_metrics_provider.h
@@ -33,7 +33,7 @@ class SigninStatusMetricsProvider : public SigninStatusMetricsProviderBase,
~SigninStatusMetricsProvider() override;
// SigninStatusMetricsProviderBase:
- void ProvideGeneralMetrics(
+ void ProvideCurrentSessionData(
metrics::ChromeUserMetricsExtension* uma_proto) override;
// Factory method, creates a new instance of this class.
diff --git a/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc b/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
index 47391e47637..32d169a839a 100644
--- a/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
+++ b/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
@@ -21,7 +21,7 @@ class TokenServiceTableTest : public testing::Test {
protected:
void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
+ OSCryptMocker::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
diff --git a/chromium/components/signin/core/browser/webdata/token_web_data.cc b/chromium/components/signin/core/browser/webdata/token_web_data.cc
index d8c405f0605..cb53ca68c96 100644
--- a/chromium/components/signin/core/browser/webdata/token_web_data.cc
+++ b/chromium/components/signin/core/browser/webdata/token_web_data.cc
@@ -18,8 +18,9 @@ using base::Time;
class TokenWebDataBackend
: public base::RefCountedDeleteOnSequence<TokenWebDataBackend> {
public:
- TokenWebDataBackend(scoped_refptr<base::SingleThreadTaskRunner> db_thread)
- : base::RefCountedDeleteOnSequence<TokenWebDataBackend>(db_thread) {}
+ TokenWebDataBackend(
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner)
+ : base::RefCountedDeleteOnSequence<TokenWebDataBackend>(db_task_runner) {}
WebDatabase::State RemoveAllTokens(WebDatabase* db) {
if (TokenServiceTable::FromWebDatabase(db)->RemoveAllTokens()) {
@@ -69,12 +70,11 @@ TokenResult::~TokenResult(){};
TokenWebData::TokenWebData(
scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const ProfileErrorCallback& callback)
- : WebDataServiceBase(wdbs, callback, ui_thread),
- token_backend_(new TokenWebDataBackend(db_thread)) {
-}
+ : WebDataServiceBase(wdbs, callback, ui_task_runner),
+ token_backend_(new TokenWebDataBackend(db_task_runner)) {}
void TokenWebData::SetTokenForService(const std::string& service,
const std::string& token) {
@@ -102,11 +102,10 @@ WebDataServiceBase::Handle TokenWebData::GetAllTokens(
}
TokenWebData::TokenWebData(
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread)
- : WebDataServiceBase(NULL, ProfileErrorCallback(), ui_thread),
- token_backend_(new TokenWebDataBackend(db_thread)) {
-}
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner)
+ : WebDataServiceBase(NULL, ProfileErrorCallback(), ui_task_runner),
+ token_backend_(new TokenWebDataBackend(db_task_runner)) {}
TokenWebData::~TokenWebData() {
}
diff --git a/chromium/components/signin/core/browser/webdata/token_web_data.h b/chromium/components/signin/core/browser/webdata/token_web_data.h
index f47f371c252..39bb6af92a9 100644
--- a/chromium/components/signin/core/browser/webdata/token_web_data.h
+++ b/chromium/components/signin/core/browser/webdata/token_web_data.h
@@ -47,12 +47,12 @@ struct TokenResult {
class TokenWebData : public WebDataServiceBase {
public:
TokenWebData(scoped_refptr<WebDatabaseService> wdbs,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const ProfileErrorCallback& callback);
- TokenWebData(scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread);
+ TokenWebData(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner);
// Set a token to use for a specified service.
void SetTokenForService(const std::string& service,
diff --git a/chromium/components/signin/core/common/profile_management_switches.cc b/chromium/components/signin/core/common/profile_management_switches.cc
index 61dd356e6c0..b8ea88e432b 100644
--- a/chromium/components/signin/core/common/profile_management_switches.cc
+++ b/chromium/components/signin/core/common/profile_management_switches.cc
@@ -7,25 +7,40 @@
#include <string>
#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/metrics/field_trial.h"
+#include "base/logging.h"
+#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
+#include "components/signin/core/common/signin_features.h"
#include "components/signin/core/common/signin_switches.h"
-namespace switches {
+namespace signin {
+
+// base::Feature definitions.
+const base::Feature kAccountConsistencyFeature{
+ "AccountConsistency", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kAccountConsistencyFeatureMethodParameter[] = "method";
+const char kAccountConsistencyFeatureMethodMirror[] = "mirror";
+const char kAccountConsistencyFeatureMethodDiceFixAuthErrors[] =
+ "dice_fix_auth_errors";
+const char kAccountConsistencyFeatureMethodDice[] = "dice";
AccountConsistencyMethod GetAccountConsistencyMethod() {
#if BUILDFLAG(ENABLE_MIRROR)
- // Mirror is enabled on Android and iOS.
+ // Mirror is always enabled on Android and iOS.
return AccountConsistencyMethod::kMirror;
#else
- base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
- std::string method = cmd->GetSwitchValueASCII(switches::kAccountConsistency);
- if (method == switches::kAccountConsistencyMirror)
- return AccountConsistencyMethod::kMirror;
+ if (!base::FeatureList::IsEnabled(kAccountConsistencyFeature))
+ return AccountConsistencyMethod::kDisabled;
+ std::string method_value = base::GetFieldTrialParamValueByFeature(
+ kAccountConsistencyFeature, kAccountConsistencyFeatureMethodParameter);
+
+ if (method_value == kAccountConsistencyFeatureMethodMirror)
+ return AccountConsistencyMethod::kMirror;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
- if (method == switches::kAccountConsistencyDice)
+ else if (method_value == kAccountConsistencyFeatureMethodDiceFixAuthErrors)
+ return AccountConsistencyMethod::kDiceFixAuthErrors;
+ else if (method_value == kAccountConsistencyFeatureMethodDice)
return AccountConsistencyMethod::kDice;
#endif
@@ -38,7 +53,13 @@ bool IsAccountConsistencyMirrorEnabled() {
}
bool IsAccountConsistencyDiceEnabled() {
- return GetAccountConsistencyMethod() == AccountConsistencyMethod::kDice;
+ return (GetAccountConsistencyMethod() == AccountConsistencyMethod::kDice);
+}
+
+bool IsDiceFixAuthErrorsEnabled() {
+ AccountConsistencyMethod method = GetAccountConsistencyMethod();
+ return (method == AccountConsistencyMethod::kDiceFixAuthErrors) ||
+ (method == AccountConsistencyMethod::kDice);
}
bool IsExtensionsMultiAccount() {
@@ -53,18 +74,4 @@ bool IsExtensionsMultiAccount() {
GetAccountConsistencyMethod() == AccountConsistencyMethod::kMirror;
}
-void EnableAccountConsistencyMirrorForTesting(base::CommandLine* command_line) {
-#if !BUILDFLAG(ENABLE_MIRROR)
- command_line->AppendSwitchASCII(switches::kAccountConsistency,
- switches::kAccountConsistencyMirror);
-#endif
-}
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-void EnableAccountConsistencyDiceForTesting(base::CommandLine* command_line) {
- command_line->AppendSwitchASCII(switches::kAccountConsistency,
- switches::kAccountConsistencyDice);
-}
-#endif
-
-} // namespace switches
+} // namespace signin
diff --git a/chromium/components/signin/core/common/profile_management_switches.h b/chromium/components/signin/core/common/profile_management_switches.h
index 9642ef5b0ce..7b379269cd5 100644
--- a/chromium/components/signin/core/common/profile_management_switches.h
+++ b/chromium/components/signin/core/common/profile_management_switches.h
@@ -9,18 +9,28 @@
#ifndef COMPONENTS_SIGNIN_CORE_COMMON_PROFILE_MANAGEMENT_SWITCHES_H_
#define COMPONENTS_SIGNIN_CORE_COMMON_PROFILE_MANAGEMENT_SWITCHES_H_
-#include "components/signin/core/common/signin_features.h"
+#include "base/feature_list.h"
-namespace base {
-class CommandLine;
-}
+namespace signin {
-namespace switches {
+// Account consistency feature. Only used on platforms where Mirror is not
+// always enabled (ENABLE_MIRROR is false).
+extern const base::Feature kAccountConsistencyFeature;
+
+// The account consistency method parameter name.
+extern const char kAccountConsistencyFeatureMethodParameter[];
+
+// Account consistency method values.
+extern const char kAccountConsistencyFeatureMethodMirror[];
+extern const char kAccountConsistencyFeatureMethodDiceFixAuthErrors[];
+extern const char kAccountConsistencyFeatureMethodDice[];
enum class AccountConsistencyMethod {
- kDisabled, // No account consistency.
- kMirror, // Account management UI in the avatar bubble.
- kDice // Account management UI on Gaia webpages.
+ kDisabled, // No account consistency.
+ kMirror, // Account management UI in the avatar bubble.
+ kDiceFixAuthErrors, // No account consistency, but Dice fixes authentication
+ // errors.
+ kDice // Account management UI on Gaia webpages.
};
// Returns the account consistency method.
@@ -32,19 +42,17 @@ bool IsAccountConsistencyMirrorEnabled();
// Checks whether Dice account consistency is enabled. If enabled, then account
// management UI is available on the Gaia webpages.
+// Returns true when the account consistency method is kDice.
+// WARNING: returns false when the method is kDiceFixAuthErrors.
bool IsAccountConsistencyDiceEnabled();
+// Returns true if the account consistency method is kDiceFixAuthErrors or
+// kDice.
+bool IsDiceFixAuthErrorsEnabled();
+
// Whether the chrome.identity API should be multi-account.
bool IsExtensionsMultiAccount();
-// Called in tests to force enable Mirror account consistency.
-void EnableAccountConsistencyMirrorForTesting(base::CommandLine* command_line);
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-// Called in tests to force enable Dice account consistency.
-void EnableAccountConsistencyDiceForTesting(base::CommandLine* command_line);
-#endif
-
-} // namespace switches
+} // namespace signin
#endif // COMPONENTS_SIGNIN_CORE_COMMON_PROFILE_MANAGEMENT_SWITCHES_H_
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.h b/chromium/components/signin/ios/browser/account_consistency_service.h
index 8df4874f76b..e05b4c78228 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.h
+++ b/chromium/components/signin/ios/browser/account_consistency_service.h
@@ -5,12 +5,12 @@
#ifndef COMPONENTS_SIGNIN_IOS_BROWSER_ACCOUNT_CONSISTENCY_SERVICE_H_
#define COMPONENTS_SIGNIN_IOS_BROWSER_ACCOUNT_CONSISTENCY_SERVICE_H_
-#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
@@ -170,7 +170,7 @@ class AccountConsistencyService : public KeyedService,
// Whether a CHROME_CONNECTED cookie request is currently being applied.
bool applying_cookie_requests_;
// The queue of CHROME_CONNECTED cookie requests to be applied.
- std::deque<CookieRequest> cookie_requests_;
+ base::circular_deque<CookieRequest> cookie_requests_;
// The map between domains where a CHROME_CONNECTED cookie is present and
// the time when the cookie was last updated.
std::map<std::string, base::Time> last_cookie_update_map_;
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.mm b/chromium/components/signin/ios/browser/account_consistency_service.mm
index a56cc1b8626..cf4ab48e794 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service.mm
@@ -56,7 +56,8 @@ class AccountConsistencyHandler : public web::WebStatePolicyDecider {
private:
// web::WebStatePolicyDecider override
- bool ShouldAllowResponse(NSURLResponse* response) override;
+ bool ShouldAllowResponse(NSURLResponse* response,
+ bool for_main_frame) override;
void WebStateDestroyed() override;
AccountConsistencyService* account_consistency_service_; // Weak.
@@ -75,7 +76,8 @@ AccountConsistencyHandler::AccountConsistencyHandler(
account_reconcilor_(account_reconcilor),
delegate_(delegate) {}
-bool AccountConsistencyHandler::ShouldAllowResponse(NSURLResponse* response) {
+bool AccountConsistencyHandler::ShouldAllowResponse(NSURLResponse* response,
+ bool for_main_frame) {
NSHTTPURLResponse* http_response =
base::mac::ObjCCast<NSHTTPURLResponse>(response);
if (!http_response)
@@ -373,7 +375,7 @@ void AccountConsistencyService::FinishedApplyingCookieRequest(bool success) {
case ADD_CHROME_CONNECTED_COOKIE:
// Add request.domain to prefs, use |true| as a dummy value (that is
// never used), as the dictionary is used as a set.
- update->SetBooleanWithoutPathExpansion(request.domain, true);
+ update->SetKey(request.domain, base::Value(true));
break;
case REMOVE_CHROME_CONNECTED_COOKIE:
// Remove request.domain from prefs.
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 f61cebd655c..7b940c01592 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -103,8 +103,9 @@ class TestWebState : public web::TestWebState {
EXPECT_EQ(decider_, decider);
decider_ = nullptr;
}
- bool ShouldAllowResponse(NSURLResponse* response) {
- return decider_ ? decider_->ShouldAllowResponse(response) : true;
+ bool ShouldAllowResponse(NSURLResponse* response, bool for_main_frame) {
+ return decider_ ? decider_->ShouldAllowResponse(response, for_main_frame)
+ : true;
}
void WebStateDestroyed() {
if (!decider_)
@@ -244,7 +245,8 @@ TEST_F(AccountConsistencyServiceTest, SignInSignOut) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
- EXPECT_TRUE(web_state_.ShouldAllowResponse(response));
+ EXPECT_TRUE(
+ web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
web_state_.WebStateDestroyed();
// Check that all domains are removed.
@@ -300,7 +302,8 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNotOnGaia) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
- EXPECT_TRUE(web_state_.ShouldAllowResponse(response));
+ EXPECT_TRUE(
+ web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
web_state_.WebStateDestroyed();
EXPECT_OCMOCK_VERIFY(delegate);
@@ -319,7 +322,8 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNoHeader) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
- EXPECT_TRUE(web_state_.ShouldAllowResponse(response));
+ EXPECT_TRUE(
+ web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
web_state_.WebStateDestroyed();
EXPECT_OCMOCK_VERIFY(delegate);
@@ -346,7 +350,8 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsDefault) {
EXPECT_CALL(account_reconcilor_, OnReceivedManageAccountsResponse(
signin::GAIA_SERVICE_TYPE_DEFAULT))
.Times(1);
- EXPECT_FALSE(web_state_.ShouldAllowResponse(response));
+ EXPECT_FALSE(
+ web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
web_state_.WebStateDestroyed();
EXPECT_OCMOCK_VERIFY(delegate);
diff --git a/chromium/components/spellcheck/browser/BUILD.gn b/chromium/components/spellcheck/browser/BUILD.gn
index 90c0534c854..b8069c146ce 100644
--- a/chromium/components/spellcheck/browser/BUILD.gn
+++ b/chromium/components/spellcheck/browser/BUILD.gn
@@ -40,10 +40,6 @@ source_set("browser") {
]
if (is_android) {
- sources += [
- "android/component_jni_registrar.cc",
- "android/component_jni_registrar.h",
- ]
deps += [ "android:jni_headers" ]
}
}
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
index b77ddb28dc5..adace851ed7 100644
--- a/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
@@ -17,11 +17,6 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
-// For version specific disabled tests below (http://crbug.com/230534).
-#include "base/win/windows_version.h"
-#endif
-
class SpellcheckHostMetricsTest : public testing::Test {
public:
SpellcheckHostMetricsTest() {
@@ -58,12 +53,14 @@ TEST_F(SpellcheckHostMetricsTest, RecordEnabledStats) {
histogram_tester2.ExpectBucketCount(kMetricName, 1, 1);
}
-TEST_F(SpellcheckHostMetricsTest, CustomWordStats) {
#if defined(OS_WIN)
// Failing consistently on Win7. See crbug.com/230534.
- if (base::win::GetVersion() >= base::win::VERSION_VISTA)
- return;
+#define MAYBE_CustomWordStats DISABLED_CustomWordStats
+#else
+#define MAYBE_CustomWordStats CustomWordStats
#endif
+
+TEST_F(SpellcheckHostMetricsTest, MAYBE_CustomWordStats) {
SpellCheckHostMetrics::RecordCustomWordCountStats(123);
// Determine if test failures are due the statistics recorder not being
diff --git a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h
index 75e538838c8..430a7ba06d3 100644
--- a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h
+++ b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h
@@ -26,12 +26,14 @@ class SpellCheckMessageFilterPlatform : public content::BrowserMessageFilter {
content::BrowserThread::ID* thread) override;
bool OnMessageReceived(const IPC::Message& message) override;
+#if defined(OS_MACOSX)
// Adjusts remote_results by examining local_results. Any result that's both
// local and remote stays type SPELLING, all others are flagged GRAMMAR.
// (This is needed to force gray underline for remote-only results.)
static void CombineResults(
std::vector<SpellCheckResult>* remote_results,
const std::vector<SpellCheckResult>& local_results);
+#endif
private:
friend class TestingSpellCheckMessageFilter;
@@ -39,17 +41,10 @@ class SpellCheckMessageFilterPlatform : public content::BrowserMessageFilter {
~SpellCheckMessageFilterPlatform() override;
- void OnCheckSpelling(const base::string16& word, int route_id, bool* correct);
- void OnFillSuggestionList(const base::string16& word,
- std::vector<base::string16>* suggestions);
void OnRequestTextCheck(int route_id,
int identifier,
const base::string16& text);
- int ToDocumentTag(int route_id);
- void RetireDocumentTag(int route_id);
- std::map<int,int> tag_map_;
-
int render_process_id_;
#if defined(OS_ANDROID)
@@ -62,7 +57,17 @@ class SpellCheckMessageFilterPlatform : public content::BrowserMessageFilter {
// Android-specific object used to query the Android spellchecker.
std::unique_ptr<SpellCheckerSessionBridge> impl_;
-#else
+#endif
+
+#if defined(OS_MACOSX)
+ void OnCheckSpelling(const base::string16& word, int route_id, bool* correct);
+ void OnFillSuggestionList(const base::string16& word,
+ std::vector<base::string16>* suggestions);
+
+ int ToDocumentTag(int route_id);
+ void RetireDocumentTag(int route_id);
+ std::map<int, int> tag_map_;
+
// A JSON-RPC client that calls the Spelling service in the background.
std::unique_ptr<SpellingServiceClient> client_;
#endif
diff --git a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc
index f68a73d99da..ca3fade94ee 100644
--- a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc
@@ -40,28 +40,8 @@ bool SpellCheckMessageFilterPlatform::OnMessageReceived(
return handled;
}
-// static
-void SpellCheckMessageFilterPlatform::CombineResults(
- std::vector<SpellCheckResult>* remote_results,
- const std::vector<SpellCheckResult>& local_results) {
- NOTREACHED();
-}
-
SpellCheckMessageFilterPlatform::~SpellCheckMessageFilterPlatform() {}
-void SpellCheckMessageFilterPlatform::OnCheckSpelling(
- const base::string16& word,
- int route_id,
- bool* correct) {
- NOTREACHED();
-}
-
-void SpellCheckMessageFilterPlatform::OnFillSuggestionList(
- const base::string16& word,
- std::vector<base::string16>* suggestions) {
- NOTREACHED();
-}
-
void SpellCheckMessageFilterPlatform::OnRequestTextCheck(
int route_id,
int identifier,
@@ -72,15 +52,6 @@ void SpellCheckMessageFilterPlatform::OnRequestTextCheck(
impl_->RequestTextCheck(route_id, identifier, text);
}
-int SpellCheckMessageFilterPlatform::ToDocumentTag(int route_id) {
- NOTREACHED();
- return -1;
-}
-
-void SpellCheckMessageFilterPlatform::RetireDocumentTag(int route_id) {
- NOTREACHED();
-}
-
void SpellCheckMessageFilterPlatform::OnToggleSpellCheck(
bool enabled,
bool checked) {
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc
index 7f9d41821ae..466d25ba646 100644
--- a/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -36,7 +37,7 @@ class SpellcheckPlatformMacTest: public testing::Test {
private:
void QuitMessageLoop() {
CHECK(base::MessageLoop::current() == &message_loop_);
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
void CompletionCallback(const std::vector<SpellCheckResult>& results) {
diff --git a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
index 68d20a3d1fd..2b4ba92adea 100644
--- a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
+++ b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
@@ -37,11 +37,6 @@ SpellCheckerSessionBridge::~SpellCheckerSessionBridge() {
DisconnectSession();
}
-// static
-bool SpellCheckerSessionBridge::RegisterJNI(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
void SpellCheckerSessionBridge::RequestTextCheck(int route_id,
int identifier,
const base::string16& text) {
diff --git a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h
index a9118dcf417..0845133a577 100644
--- a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h
+++ b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h
@@ -21,7 +21,6 @@ class SpellCheckerSessionBridge {
public:
explicit SpellCheckerSessionBridge(int render_process_id);
~SpellCheckerSessionBridge();
- static bool RegisterJNI(JNIEnv* env);
// Receives text to be checked from the message filter and sends it to Java
// to be spellchecked.
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.cc b/chromium/components/spellcheck/browser/spelling_service_client.cc
index 86eda34d958..3fed159e673 100644
--- a/chromium/components/spellcheck/browser/spelling_service_client.cc
+++ b/chromium/components/spellcheck/browser/spelling_service_client.cc
@@ -124,7 +124,7 @@ bool SpellingServiceClient::RequestTextCheck(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can enable or disable this feature via 'Use a web service "
"to help resolve spelling errors.' in Chromium's settings under "
diff --git a/chromium/components/spellcheck/common/BUILD.gn b/chromium/components/spellcheck/common/BUILD.gn
index 6c7c548f802..cac33a0394f 100644
--- a/chromium/components/spellcheck/common/BUILD.gn
+++ b/chromium/components/spellcheck/common/BUILD.gn
@@ -16,6 +16,8 @@ source_set("common") {
"spellcheck_messages.h",
"spellcheck_result.cc",
"spellcheck_result.h",
+ "spellcheck_struct_traits.cc",
+ "spellcheck_struct_traits.h",
"spellcheck_switches.cc",
"spellcheck_switches.h",
]
diff --git a/chromium/components/spellcheck/common/OWNERS b/chromium/components/spellcheck/common/OWNERS
index ed454dad2fd..7f7ed5ec40d 100644
--- a/chromium/components/spellcheck/common/OWNERS
+++ b/chromium/components/spellcheck/common/OWNERS
@@ -2,5 +2,7 @@ per-file *_messages*.h=set noparent
per-file *_messages*.h=file://ipc/SECURITY_OWNERS
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/spellcheck/common/spellcheck.mojom b/chromium/components/spellcheck/common/spellcheck.mojom
index 33b818f7d26..2475c1c06dd 100644
--- a/chromium/components/spellcheck/common/spellcheck.mojom
+++ b/chromium/components/spellcheck/common/spellcheck.mojom
@@ -50,5 +50,14 @@ interface SpellCheckHost {
(bool success, array<SpellCheckResult> results);
};
-[Native]
-struct SpellCheckResult;
+enum Decoration {
+ kSpelling,
+ kGrammar,
+};
+
+struct SpellCheckResult {
+ Decoration decoration;
+ int32 location;
+ int32 length;
+ array<string> replacements;
+};
diff --git a/chromium/components/spellcheck/common/spellcheck.typemap b/chromium/components/spellcheck/common/spellcheck.typemap
index 468241ca106..f4aa4588936 100644
--- a/chromium/components/spellcheck/common/spellcheck.typemap
+++ b/chromium/components/spellcheck/common/spellcheck.typemap
@@ -6,10 +6,13 @@ mojom = "//components/spellcheck/common/spellcheck.mojom"
public_headers = [ "//components/spellcheck/common/spellcheck_result.h" ]
-traits_headers = [ "//components/spellcheck/common/spellcheck_messages.h" ]
+traits_headers = [ "//components/spellcheck/common/spellcheck_struct_traits.h" ]
deps = [
"//components/spellcheck:build_features",
]
-type_mappings = [ "spellcheck.mojom.SpellCheckResult=::SpellCheckResult" ]
+type_mappings = [
+ "spellcheck.mojom.Decoration=::SpellCheckResult::Decoration",
+ "spellcheck.mojom.SpellCheckResult=::SpellCheckResult",
+]
diff --git a/chromium/components/spellcheck/common/spellcheck_struct_traits.cc b/chromium/components/spellcheck/common/spellcheck_struct_traits.cc
new file mode 100644
index 00000000000..5b8e5042419
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_struct_traits.cc
@@ -0,0 +1,50 @@
+// 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/spellcheck/common/spellcheck_struct_traits.h"
+
+namespace mojo {
+
+spellcheck::mojom::Decoration
+EnumTraits<spellcheck::mojom::Decoration, SpellCheckResult::Decoration>::
+ ToMojom(SpellCheckResult::Decoration decoration) {
+ switch (decoration) {
+ case SpellCheckResult::SPELLING:
+ return spellcheck::mojom::Decoration::kSpelling;
+ case SpellCheckResult::GRAMMAR:
+ return spellcheck::mojom::Decoration::kGrammar;
+ }
+ NOTREACHED();
+ return spellcheck::mojom::Decoration::kSpelling;
+}
+
+bool EnumTraits<spellcheck::mojom::Decoration, SpellCheckResult::Decoration>::
+ FromMojom(spellcheck::mojom::Decoration input,
+ SpellCheckResult::Decoration* output) {
+ switch (input) {
+ case spellcheck::mojom::Decoration::kSpelling:
+ *output = SpellCheckResult::SPELLING;
+ return true;
+ case spellcheck::mojom::Decoration::kGrammar:
+ *output = SpellCheckResult::GRAMMAR;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool StructTraits<
+ spellcheck::mojom::SpellCheckResultDataView,
+ SpellCheckResult>::Read(spellcheck::mojom::SpellCheckResultDataView input,
+ SpellCheckResult* output) {
+ if (!input.ReadDecoration(&output->decoration))
+ return false;
+ output->location = input.location();
+ output->length = input.length();
+ if (!input.ReadReplacements(&output->replacements))
+ return false;
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/components/spellcheck/common/spellcheck_struct_traits.h b/chromium/components/spellcheck/common/spellcheck_struct_traits.h
new file mode 100644
index 00000000000..cfdaa9e6dc9
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_struct_traits.h
@@ -0,0 +1,47 @@
+// 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_SPELLCHECK_COMMON_SPELLCHECK_STRUCT_TRAITS_H
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_STRUCT_TRAITS_H
+
+#include "components/spellcheck/common/spellcheck.mojom.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<spellcheck::mojom::Decoration, SpellCheckResult::Decoration> {
+ static spellcheck::mojom::Decoration ToMojom(SpellCheckResult::Decoration);
+ static bool FromMojom(spellcheck::mojom::Decoration,
+ SpellCheckResult::Decoration*);
+};
+
+template <>
+struct StructTraits<spellcheck::mojom::SpellCheckResultDataView,
+ SpellCheckResult> {
+ static SpellCheckResult::Decoration decoration(
+ const SpellCheckResult& result) {
+ return result.decoration;
+ }
+
+ static int32_t location(const SpellCheckResult& result) {
+ return result.location;
+ }
+
+ static int32_t length(const SpellCheckResult& result) {
+ return result.length;
+ }
+
+ static const std::vector<base::string16>& replacements(
+ const SpellCheckResult& result) {
+ return result.replacements;
+ }
+
+ static bool Read(spellcheck::mojom::SpellCheckResultDataView,
+ SpellCheckResult*);
+};
+
+} // namespace mojo
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_STRUCT_TRAITS_H
diff --git a/chromium/components/spellcheck/renderer/spellcheck_panel.cc b/chromium/components/spellcheck/renderer/spellcheck_panel.cc
index 545f1cf52b8..f432c39b93f 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_panel.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_panel.cc
@@ -9,7 +9,6 @@
#include "content/public/common/service_names.mojom.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/connector.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
@@ -25,12 +24,13 @@ spellcheck::mojom::SpellCheckPanelHostPtr GetSpellCheckPanelHost() {
}
}
-SpellCheckPanel::SpellCheckPanel(content::RenderFrame* render_frame)
+SpellCheckPanel::SpellCheckPanel(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry)
: content::RenderFrameObserver(render_frame),
spelling_panel_visible_(false) {
DCHECK(render_frame);
- render_frame->GetInterfaceRegistry()->AddInterface(base::Bind(
- &SpellCheckPanel::SpellCheckPanelRequest, base::Unretained(this)));
+ registry->AddInterface(base::Bind(&SpellCheckPanel::SpellCheckPanelRequest,
+ base::Unretained(this)));
render_frame->GetWebFrame()->SetSpellCheckPanelHostClient(this);
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_panel.h b/chromium/components/spellcheck/renderer/spellcheck_panel.h
index 8b3f63f41fb..ad336e4c669 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_panel.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_panel.h
@@ -10,6 +10,7 @@
#include "components/spellcheck/spellcheck_build_features.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/WebKit/public/platform/WebSpellCheckPanelHostClient.h"
#if !BUILDFLAG(HAS_SPELLCHECK_PANEL)
@@ -20,7 +21,8 @@ class SpellCheckPanel : public content::RenderFrameObserver,
public blink::WebSpellCheckPanelHostClient,
public spellcheck::mojom::SpellCheckPanel {
public:
- explicit SpellCheckPanel(content::RenderFrame* render_frame);
+ SpellCheckPanel(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry);
~SpellCheckPanel() override;
private:
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
index d31e1107a0d..f457dd719fd 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -7,7 +7,7 @@
#include <vector>
-#include "base/id_map.h"
+#include "base/containers/id_map.h"
#include "base/macros.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/spellcheck_build_features.h"
@@ -30,7 +30,8 @@ class SpellCheckProvider
public content::RenderFrameObserverTracker<SpellCheckProvider>,
public blink::WebTextCheckClient {
public:
- using WebTextCheckCompletions = IDMap<blink::WebTextCheckingCompletion*>;
+ using WebTextCheckCompletions =
+ base::IDMap<blink::WebTextCheckingCompletion*>;
SpellCheckProvider(content::RenderFrame* render_frame,
SpellCheck* spellcheck);
diff --git a/chromium/components/storage_monitor/image_capture_device.mm b/chromium/components/storage_monitor/image_capture_device.mm
index 29285d938ca..bfafbd40750 100644
--- a/chromium/components/storage_monitor/image_capture_device.mm
+++ b/chromium/components/storage_monitor/image_capture_device.mm
@@ -5,6 +5,9 @@
#import "components/storage_monitor/image_capture_device.h"
#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_thread.h"
namespace storage_monitor {
@@ -13,7 +16,7 @@ namespace {
base::File::Error RenameFile(const base::FilePath& downloaded_filename,
const base::FilePath& desired_filename) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+ base::ThreadRestrictions::AssertIOAllowed();
bool success = base::ReplaceFile(downloaded_filename, desired_filename, NULL);
return success ? base::File::FILE_OK : base::File::FILE_ERROR_NOT_FOUND;
}
@@ -217,12 +220,15 @@ base::FilePath PathForCameraItem(ICCameraItem* item) {
base::FilePath saveAsPath = saveDir.Append(saveAsFilename);
base::FilePath savedPath = saveDir.Append(savedFilename);
// Shared result value from file-copy closure to tell-listener closure.
- content::BrowserThread::PostTaskAndReplyWithResult(
- content::BrowserThread::FILE,
+ // This is worth blocking shutdown, as otherwise a file that has been
+ // downloaded will be incorrectly named.
+ base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::Bind(&storage_monitor::RenameFile, savedPath, saveAsPath),
- base::Bind(
- &storage_monitor::ReturnRenameResultToListener, listener_, name));
+ base::Bind(&storage_monitor::ReturnRenameResultToListener, listener_,
+ name));
}
@end // ImageCaptureDevice
diff --git a/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm b/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
index 09dd75f50b5..9a10311f039 100644
--- a/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
@@ -11,7 +11,7 @@
#include "base/mac/foundation_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/memory/weak_ptr.h"
-#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "components/storage_monitor/image_capture_device.h"
#include "components/storage_monitor/image_capture_device_manager.h"
#include "components/storage_monitor/test_storage_monitor.h"
@@ -240,6 +240,10 @@ class TestCameraListener
class ImageCaptureDeviceManagerTest : public testing::Test {
public:
+ ImageCaptureDeviceManagerTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
void SetUp() override { monitor_ = TestStorageMonitor::CreateAndInstall(); }
void TearDown() override { TestStorageMonitor::Destroy(); }
@@ -263,7 +267,10 @@ class ImageCaptureDeviceManagerTest : public testing::Test {
moreGoing:NO];
}
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
content::TestBrowserThreadBundle thread_bundle_;
TestStorageMonitor* monitor_;
TestCameraListener listener_;
@@ -360,7 +367,7 @@ TEST_F(ImageCaptureDeviceManagerTest, DownloadFile) {
// return us a not-found error.
base::FilePath temp_file = temp_dir.GetPath().Append("tempfile");
[camera downloadFile:std::string("nonexistent") localPath:temp_file];
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_EQ(1U, listener_.downloads().size());
EXPECT_EQ("nonexistent", listener_.downloads()[0]);
EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, listener_.last_error());
@@ -371,7 +378,7 @@ TEST_F(ImageCaptureDeviceManagerTest, DownloadFile) {
// library behavior. Our code then renames the file onto the requested
// destination.
[camera downloadFile:kTestFileName localPath:temp_file];
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
ASSERT_EQ(2U, listener_.downloads().size());
EXPECT_EQ(kTestFileName, listener_.downloads()[1]);
@@ -408,7 +415,7 @@ TEST_F(ImageCaptureDeviceManagerTest, TestSubdirectories) {
base::FilePath temp_file = temp_dir.GetPath().Append("tempfile");
[camera downloadFile:("dir/" + kTestFileName) localPath:temp_file];
- base::RunLoop().RunUntilIdle();
+ RunUntilIdle();
char file_contents[5];
ASSERT_EQ(4, base::ReadFile(temp_file, file_contents,
diff --git a/chromium/components/storage_monitor/media_storage_util.cc b/chromium/components/storage_monitor/media_storage_util.cc
index 7841e4e294e..aab083b1edc 100644
--- a/chromium/components/storage_monitor/media_storage_util.cc
+++ b/chromium/components/storage_monitor/media_storage_util.cc
@@ -11,13 +11,14 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_monitor.h"
#include "content/public/browser/browser_thread.h"
-using content::BrowserThread;
-
namespace storage_monitor {
namespace {
@@ -41,8 +42,9 @@ base::FilePath::StringType FindRemovableStorageLocationById(
return base::FilePath::StringType();
}
-void FilterAttachedDevicesOnFileThread(MediaStorageUtil::DeviceIdSet* devices) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void FilterAttachedDevicesOnBackgroundSequence(
+ MediaStorageUtil::DeviceIdSet* devices) {
+ base::ThreadRestrictions::AssertIOAllowed();
MediaStorageUtil::DeviceIdSet missing_devices;
for (MediaStorageUtil::DeviceIdSet::const_iterator it = devices->begin();
@@ -79,8 +81,7 @@ void FilterAttachedDevicesOnFileThread(MediaStorageUtil::DeviceIdSet* devices) {
// static
bool MediaStorageUtil::HasDcim(const base::FilePath& mount_point) {
- DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
+ base::ThreadRestrictions::AssertIOAllowed();
base::FilePath::StringType dcim_dir(kDCIMDirectoryName);
if (!base::DirectoryExists(mount_point.Append(dcim_dir))) {
// Check for lowercase 'dcim' as well.
@@ -108,16 +109,12 @@ bool MediaStorageUtil::CanCreateFileSystem(const std::string& device_id,
// static
void MediaStorageUtil::FilterAttachedDevices(DeviceIdSet* devices,
const base::Closure& done) {
- if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- FilterAttachedDevicesOnFileThread(devices);
- done.Run();
- return;
- }
- BrowserThread::PostTaskAndReply(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&FilterAttachedDevicesOnFileThread,
- devices),
- done);
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ base::PostTaskWithTraitsAndReply(
+ FROM_HERE,
+ {base::TaskPriority::BACKGROUND, base::MayBlock(),
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+ base::Bind(&FilterAttachedDevicesOnBackgroundSequence, devices), done);
}
// TODO(kmadhusu) Write unit tests for GetDeviceInfoFromPath().
diff --git a/chromium/components/storage_monitor/media_storage_util_unittest.cc b/chromium/components/storage_monitor/media_storage_util_unittest.cc
index b478bf76d33..fc9f5b352ae 100644
--- a/chromium/components/storage_monitor/media_storage_util_unittest.cc
+++ b/chromium/components/storage_monitor/media_storage_util_unittest.cc
@@ -9,12 +9,12 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/test/scoped_task_environment.h"
#include "components/storage_monitor/media_storage_util.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_monitor.h"
#include "components/storage_monitor/test_storage_monitor.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,14 +24,13 @@ const char kImageCaptureDeviceId[] = "ic:xyz";
} // namespace
-using content::BrowserThread;
-
namespace storage_monitor {
class MediaStorageUtilTest : public testing::Test {
public:
MediaStorageUtilTest()
- : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {}
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
~MediaStorageUtilTest() override {}
// Verify mounted device type.
@@ -67,24 +66,14 @@ class MediaStorageUtilTest : public testing::Test {
}
void TearDown() override {
- WaitForFileThread();
TestStorageMonitor::Destroy();
}
- static void PostQuitToUIThread() {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::MessageLoop::QuitWhenIdleClosure());
- }
-
- static void WaitForFileThread() {
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&PostQuitToUIThread));
- base::RunLoop().Run();
- }
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
private:
- content::TestBrowserThreadBundle thread_bundle_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
TestStorageMonitor* monitor_;
base::ScopedTempDir scoped_temp_dir_;
};
@@ -95,11 +84,11 @@ TEST_F(MediaStorageUtilTest, MediaDeviceAttached) {
// Create a dummy mount point with DCIM Directory.
base::FilePath mount_point(CreateMountPoint(true));
ASSERT_FALSE(mount_point.empty());
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&MediaStorageUtilTest::CheckDCIMDeviceType,
- base::Unretained(this), mount_point));
- base::RunLoop().RunUntilIdle();
+ base::PostTaskWithTraits(
+ FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
+ base::BindOnce(&MediaStorageUtilTest::CheckDCIMDeviceType,
+ base::Unretained(this), mount_point));
+ RunUntilIdle();
}
// Test to verify that HasDcim() function returns false for a given non-media
@@ -108,11 +97,11 @@ TEST_F(MediaStorageUtilTest, NonMediaDeviceAttached) {
// Create a dummy mount point without DCIM Directory.
base::FilePath mount_point(CreateMountPoint(false));
ASSERT_FALSE(mount_point.empty());
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&MediaStorageUtilTest::CheckNonDCIMDeviceType,
- base::Unretained(this), mount_point));
- base::RunLoop().RunUntilIdle();
+ base::PostTaskWithTraits(
+ FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
+ base::BindOnce(&MediaStorageUtilTest::CheckNonDCIMDeviceType,
+ base::Unretained(this), mount_point));
+ RunUntilIdle();
}
TEST_F(MediaStorageUtilTest, CanCreateFileSystemForImageCapture) {
@@ -130,26 +119,16 @@ TEST_F(MediaStorageUtilTest, DetectDeviceFiltered) {
MediaStorageUtil::DeviceIdSet devices;
devices.insert(kImageCaptureDeviceId);
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::Closure signal_event =
- base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event));
-
- // We need signal_event to be executed on the FILE thread, as the test thread
- // is blocked. Therefore, we invoke FilterAttachedDevices on the FILE thread.
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&MediaStorageUtil::FilterAttachedDevices,
- base::Unretained(&devices), signal_event));
- event.Wait();
+ MediaStorageUtil::FilterAttachedDevices(&devices,
+ base::Bind(&base::DoNothing));
+ RunUntilIdle();
EXPECT_FALSE(devices.find(kImageCaptureDeviceId) != devices.end());
ProcessAttach(kImageCaptureDeviceId, FILE_PATH_LITERAL("/location"));
devices.insert(kImageCaptureDeviceId);
- event.Reset();
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&MediaStorageUtil::FilterAttachedDevices,
- base::Unretained(&devices), signal_event));
- event.Wait();
+ MediaStorageUtil::FilterAttachedDevices(&devices,
+ base::Bind(&base::DoNothing));
+ RunUntilIdle();
EXPECT_TRUE(devices.find(kImageCaptureDeviceId) != devices.end());
}
diff --git a/chromium/components/storage_monitor/portable_device_watcher_win.cc b/chromium/components/storage_monitor/portable_device_watcher_win.cc
index d6911e2c655..d4b197ae8f0 100644
--- a/chromium/components/storage_monitor/portable_device_watcher_win.cc
+++ b/chromium/components/storage_monitor/portable_device_watcher_win.cc
@@ -501,7 +501,7 @@ PortableDeviceWatcherWin::~PortableDeviceWatcherWin() {
void PortableDeviceWatcherWin::Init(HWND hwnd) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
notifications_ = RegisterPortableDeviceNotification(hwnd);
- media_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+ media_task_runner_ = base::CreateCOMSTATaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
EnumerateAttachedDevices();
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.cc b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
index edce2a560fd..366d97e8e87 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
@@ -12,6 +12,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/storage_monitor/media_storage_util.h"
#include "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
#include "components/storage_monitor/removable_device_constants.h"
@@ -72,17 +76,8 @@ bool GetDeviceInfo(const DiskMountManager::MountPointInfo& mount_info,
return true;
}
-// Returns whether the mount point in |mount_info| is a media device or not.
-bool CheckMountedPathOnFileThread(
- const DiskMountManager::MountPointInfo& mount_info) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
- return MediaStorageUtil::HasDcim(base::FilePath(mount_info.mount_path));
-}
-
} // namespace
-using content::BrowserThread;
-
StorageMonitorCros::StorageMonitorCros()
: weak_ptr_factory_(this) {
}
@@ -112,24 +107,31 @@ void StorageMonitorCros::Init() {
void StorageMonitorCros::CheckExistingMountPoints() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND});
+
const DiskMountManager::MountPointMap& mount_point_map =
DiskMountManager::GetInstance()->mount_points();
for (DiskMountManager::MountPointMap::const_iterator it =
mount_point_map.begin(); it != mount_point_map.end(); ++it) {
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&CheckMountedPathOnFileThread, it->second),
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner.get(), FROM_HERE,
+ base::Bind(&MediaStorageUtil::HasDcim,
+ base::FilePath(it->second.mount_path)),
base::Bind(&StorageMonitorCros::AddMountedPath,
weak_ptr_factory_.GetWeakPtr(), it->second));
}
- // Note: relies on scheduled tasks on the file thread being sequential. This
- // block needs to follow the for loop, so that the DoNothing call on the FILE
- // thread happens after the scheduled metadata retrievals, meaning that the
- // reply callback will then happen after all the AddNewMount calls.
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&base::DoNothing),
+ // Note: Relies on scheduled tasks on the |blocking_task_runner| being
+ // sequential. This block needs to follow the for loop, so that the DoNothing
+ // call on the |blocking_task_runner| happens after the scheduled metadata
+ // retrievals, meaning that the reply callback will then happen after all the
+ // AddMountedPath calls.
+
+ blocking_task_runner->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing),
base::Bind(&StorageMonitorCros::MarkInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -162,9 +164,10 @@ void StorageMonitorCros::OnMountEvent(
return;
}
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&CheckMountedPathOnFileThread, mount_info),
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ base::Bind(&MediaStorageUtil::HasDcim,
+ base::FilePath(mount_info.mount_path)),
base::Bind(&StorageMonitorCros::AddMountedPath,
weak_ptr_factory_.GetWeakPtr(), mount_info));
break;
@@ -184,6 +187,10 @@ void StorageMonitorCros::OnFormatEvent(DiskMountManager::FormatEvent event,
chromeos::FormatError error_code,
const std::string& device_path) {}
+void StorageMonitorCros::OnRenameEvent(DiskMountManager::RenameEvent event,
+ chromeos::RenameError error_code,
+ const std::string& device_path) {}
+
void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
device::MediaTransferProtocolManager* test_manager) {
DCHECK(!media_transfer_protocol_manager_);
@@ -276,9 +283,9 @@ void StorageMonitorCros::AddMountedPath(
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (base::ContainsKey(mount_map_, mount_info.mount_path)) {
- // CheckExistingMountPointsOnUIThread() added the mount point information
- // in the map before the device attached handler is called. Therefore, an
- // entry for the device already exists in the map.
+ // CheckExistingMountPoints() added the mount point information in the map
+ // before the device attached handler is called. Therefore, an entry for
+ // the device already exists in the map.
return;
}
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.h b/chromium/components/storage_monitor/storage_monitor_chromeos.h
index b427c220867..300349711c0 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.h
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.h
@@ -57,6 +57,9 @@ class StorageMonitorCros : public StorageMonitor,
void OnFormatEvent(chromeos::disks::DiskMountManager::FormatEvent event,
chromeos::FormatError error_code,
const std::string& device_path) override;
+ void OnRenameEvent(chromeos::disks::DiskMountManager::RenameEvent event,
+ chromeos::RenameError error_code,
+ const std::string& device_path) override;
// StorageMonitor implementation.
bool GetStorageInfoForPath(const base::FilePath& path,
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
index e644d2766ec..c4127fb20db 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -16,13 +16,13 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "chromeos/disks/mock_disk_mount_manager.h"
#include "components/storage_monitor/mock_removable_storage_observer.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_info.h"
#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
#include "components/storage_monitor/test_storage_monitor.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,7 +30,6 @@ namespace storage_monitor {
namespace {
-using content::BrowserThread;
using chromeos::disks::DiskMountManager;
using testing::_;
@@ -49,6 +48,7 @@ const char kProductName[] = "Z101";
const char kUniqueId1[] = "FFFF-FFFF";
const char kUniqueId2[] = "FFFF-FF0F";
const char kVendorName[] = "CompanyA";
+const char kFileSystemType[] = "exfat";
uint64_t kDevice1SizeInBytes = 113048;
uint64_t kDevice2SizeInBytes = 212312;
@@ -127,9 +127,6 @@ class StorageMonitorCrosTest : public testing::Test {
// path on failure.
base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir);
- static void PostQuitToUIThread();
- static void WaitForFileThread();
-
MockRemovableStorageObserver& observer() {
return *mock_storage_observer_;
}
@@ -142,6 +139,8 @@ class StorageMonitorCrosTest : public testing::Test {
StorageMonitor::EjectStatus status_;
private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
content::TestBrowserThreadBundle thread_bundle_;
// Temporary directory for created test data.
@@ -157,14 +156,13 @@ StorageMonitorCrosTest::StorageMonitorCrosTest()
: monitor_(NULL),
disk_mount_manager_mock_(NULL),
status_(StorageMonitor::EJECT_FAILURE),
- thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD) {
-}
+ scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
StorageMonitorCrosTest::~StorageMonitorCrosTest() {
}
void StorageMonitorCrosTest::SetUp() {
- ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
disk_mount_manager_mock_ = new chromeos::disks::MockDiskMountManager();
DiskMountManager::InitializeForTesting(disk_mount_manager_mock_);
@@ -188,7 +186,7 @@ void StorageMonitorCrosTest::TearDown() {
disk_mount_manager_mock_ = NULL;
DiskMountManager::Shutdown();
- WaitForFileThread();
+ scoped_task_environment_.RunUntilIdle();
}
void StorageMonitorCrosTest::MountDevice(
@@ -202,20 +200,13 @@ void StorageMonitorCrosTest::MountDevice(
uint64_t device_size_in_bytes) {
if (error_code == chromeos::MOUNT_ERROR_NONE) {
disk_mount_manager_mock_->CreateDiskEntryForMountDevice(
- mount_info,
- unique_id,
- device_label,
- vendor_name,
- product_name,
- device_type,
- device_size_in_bytes,
- false /* is_parent */,
- true /* has_media */,
- false /* on_boot_device */,
- true /* on_removable_device */);
+ mount_info, unique_id, device_label, vendor_name, product_name,
+ device_type, device_size_in_bytes, false /* is_parent */,
+ true /* has_media */, false /* on_boot_device */,
+ true /* on_removable_device */, kFileSystemType);
}
monitor_->OnMountEvent(DiskMountManager::MOUNTING, error_code, mount_info);
- WaitForFileThread();
+ scoped_task_environment_.RunUntilIdle();
}
void StorageMonitorCrosTest::UnmountDevice(
@@ -224,7 +215,7 @@ void StorageMonitorCrosTest::UnmountDevice(
monitor_->OnMountEvent(DiskMountManager::UNMOUNTING, error_code, mount_info);
if (error_code == chromeos::MOUNT_ERROR_NONE)
disk_mount_manager_mock_->RemoveDiskEntryForMountDevice(mount_info);
- WaitForFileThread();
+ scoped_task_environment_.RunUntilIdle();
}
uint64_t StorageMonitorCrosTest::GetDeviceStorageSize(
@@ -248,19 +239,6 @@ base::FilePath StorageMonitorCrosTest::CreateMountPoint(
return return_path;
}
-// static
-void StorageMonitorCrosTest::PostQuitToUIThread() {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::MessageLoop::QuitWhenIdleClosure());
-}
-
-// static
-void StorageMonitorCrosTest::WaitForFileThread() {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&PostQuitToUIThread));
- base::RunLoop().Run();
-}
-
void StorageMonitorCrosTest::EjectNotify(StorageMonitor::EjectStatus status) {
status_ = status;
}
diff --git a/chromium/components/storage_monitor/storage_monitor_mac.h b/chromium/components/storage_monitor/storage_monitor_mac.h
index cf690fec2ca..d2ecb268d76 100644
--- a/chromium/components/storage_monitor/storage_monitor_mac.h
+++ b/chromium/components/storage_monitor/storage_monitor_mac.h
@@ -37,9 +37,9 @@ class StorageMonitorMac : public StorageMonitor,
void Init() override;
- void UpdateDisk(const std::string& bsd_name,
- const StorageInfo& info,
- UpdateType update_type);
+ void UpdateDisk(UpdateType update_type,
+ std::string* bsd_name,
+ const StorageInfo& info);
bool GetStorageInfoForPath(const base::FilePath& path,
StorageInfo* device_info) const override;
diff --git a/chromium/components/storage_monitor/storage_monitor_mac.mm b/chromium/components/storage_monitor/storage_monitor_mac.mm
index a48b02493f3..4e158c7e853 100644
--- a/chromium/components/storage_monitor/storage_monitor_mac.mm
+++ b/chromium/components/storage_monitor/storage_monitor_mac.mm
@@ -10,6 +10,9 @@
#include "base/mac/mac_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_restrictions.h"
#include "components/storage_monitor/image_capture_device_manager.h"
#include "components/storage_monitor/media_storage_util.h"
#include "components/storage_monitor/storage_info.h"
@@ -49,7 +52,7 @@ StorageInfo::Type GetDeviceType(bool is_removable, bool has_dcim) {
StorageInfo BuildStorageInfo(
CFDictionaryRef dict, std::string* bsd_name) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+ base::ThreadRestrictions::AssertIOAllowed();
CFStringRef device_bsd_name = base::mac::GetValueFromDictionary<CFStringRef>(
dict, kDADiskDescriptionMediaBSDNameKey);
@@ -107,25 +110,6 @@ StorageInfo BuildStorageInfo(
size_in_bytes);
}
-void GetDiskInfoAndUpdateOnFileThread(
- const base::WeakPtr<StorageMonitorMac>& monitor,
- base::ScopedCFTypeRef<CFDictionaryRef> dict,
- StorageMonitorMac::UpdateType update_type) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-
- std::string bsd_name;
- StorageInfo info = BuildStorageInfo(dict, &bsd_name);
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(&StorageMonitorMac::UpdateDisk,
- monitor,
- bsd_name,
- info,
- update_type));
-}
-
struct EjectDiskOptions {
std::string bsd_name;
base::Callback<void(StorageMonitor::EjectStatus)> callback;
@@ -205,25 +189,25 @@ void StorageMonitorMac::Init() {
image_capture_device_manager_->SetNotifications(receiver());
}
-void StorageMonitorMac::UpdateDisk(
- const std::string& bsd_name,
- const StorageInfo& info,
- UpdateType update_type) {
+void StorageMonitorMac::UpdateDisk(UpdateType update_type,
+ std::string* bsd_name,
+ const StorageInfo& info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(bsd_name);
pending_disk_updates_--;
bool initialization_complete = false;
if (!IsInitialized() && pending_disk_updates_ == 0)
initialization_complete = true;
- if (info.device_id().empty() || bsd_name.empty()) {
+ if (info.device_id().empty() || bsd_name->empty()) {
if (initialization_complete)
MarkInitialized();
return;
}
std::map<std::string, StorageInfo>::iterator it =
- disk_info_map_.find(bsd_name);
+ disk_info_map_.find(*bsd_name);
if (it != disk_info_map_.end()) {
// If an attached notification was previously posted then post a detached
// notification now. This is used for devices that are being removed or
@@ -237,7 +221,7 @@ void StorageMonitorMac::UpdateDisk(
if (it != disk_info_map_.end())
disk_info_map_.erase(it);
} else {
- disk_info_map_[bsd_name] = info;
+ disk_info_map_[*bsd_name] = info;
if (ShouldPostNotificationForDisk(info))
receiver()->ProcessAttach(info);
}
@@ -351,11 +335,12 @@ void StorageMonitorMac::GetDiskInfoAndUpdate(
pending_disk_updates_++;
base::ScopedCFTypeRef<CFDictionaryRef> dict(DADiskCopyDescription(disk));
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE,
- FROM_HERE,
- base::Bind(GetDiskInfoAndUpdateOnFileThread,
- AsWeakPtr(), dict, update_type));
+ std::string* bsd_name = new std::string;
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ base::BindOnce(&BuildStorageInfo, dict, bsd_name),
+ base::BindOnce(&StorageMonitorMac::UpdateDisk, AsWeakPtr(), update_type,
+ base::Owned(bsd_name)));
}
diff --git a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
index 47c091a2d66..89564cb66ff 100644
--- a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
+++ b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
@@ -57,10 +57,11 @@ class StorageMonitorMacTest : public testing::Test {
}
void UpdateDisk(StorageInfo info, StorageMonitorMac::UpdateType update_type) {
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
base::Bind(&StorageMonitorMac::UpdateDisk,
- base::Unretained(monitor_.get()),
- "dummy_bsd_name", info, update_type));
+ base::Unretained(monitor_.get()), update_type,
+ base::Owned(new std::string("dummy_bsd_name")), info));
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb b/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
index f86987732ef..fa3c22a0850 100644
--- a/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
@@ -9,7 +9,7 @@
<translation id="3444832043240812445">Esta página mostra informações sobre falhas recentes apenas se <ph name="BEGIN_LINK" />ativar relatórios de falha<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Permita que o Chrome aceda à rede nas definições da sua firewall ou
do antívirus.</translation>
-<translation id="4010643444566880169">O SO Chrome não concluiu a configuração inicial.</translation>
+<translation id="4010643444566880169">O Chrome OS não concluiu a configuração inicial.</translation>
<translation id="4853578032408195113">Está a ver uma página segura do Google Chrome</translation>
<translation id="6011049234605203654">Aceda ao
menu Chrome &gt;
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index 1d4e6b9cffe..9696c4151fb 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">የዴስክቶፕ ዕልባቶች</translation>
<translation id="1074497978438210769">ደህንነቱ አልተጠበቀም</translation>
<translation id="1080116354587839789">ከስፋቱ ጋር አመጣጥን</translation>
+<translation id="1088860948719068836">በካርድ ላይ ስም ያክሉ</translation>
<translation id="1103523840287552314">ሁልጊዜ <ph name="LANGUAGE" />ን መተርጎም</translation>
+<translation id="1103778128462718200">ሁሉንም የተቀመጡ የይለፍ ቃላት አሳይ...</translation>
<translation id="1107591249535594099">ምልክት ከተደረገበት፣ Chrome ለተሻለ ፈጣን የቅጽ አሞላል የካርድዎን ቅጂ በዚህ መሣሪያ ላይ ያከማቻል።</translation>
<translation id="1111153019813902504">የቅርብ ጊዜ ዕልባቶች</translation>
<translation id="1113869188872983271">&amp;እንደገና ደርድርን ቀልብስ</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />፣ <ph name="TYPE_2" /> (ሰምሯል)</translation>
<translation id="1263231323834454256">የንባብ ዝርዝር</translation>
<translation id="1264126396475825575">በ<ph name="CRASH_TIME" /> ላይ የብልሽት ሪፖርት ተይዟል (እስካሁን አልተሰቀለም ወይም ችላ አልተባለም)</translation>
+<translation id="1270502636509132238">የመውሰጃ ስልት</translation>
<translation id="1281526147609854549">በ<ph name="ISSUER" /> የተሰጠ</translation>
<translation id="1285320974508926690">ይህን ጣቢያ በጭራሽ አትተርጉም</translation>
<translation id="129553762522093515">በቅርብ ጊዜ የተዘጉ</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">ግንኙነትን በመጠበቅ ላይ…</translation>
<translation id="153384715582417236">ለአሁን ያለው ይኸው ነው</translation>
<translation id="1549470594296187301">ይህን ባህሪ ለመጠቀም ጃቫስክሪፕት መንቃት አለበት።</translation>
-<translation id="1555130319947370107">ሰማያዊ</translation>
<translation id="1559528461873125649">እንደዚህ ያለ ፋይል ወይም አቃፊ የለም</translation>
<translation id="1583429793053364125">ይህን ድረ-ገጽ በማሳየት ላይ ሳለ የሆነ ችግር ተፈጥሯል።</translation>
<translation id="1592005682883173041">አካባቢያዊ የውሂብ መድረሻ</translation>
<translation id="1594030484168838125">ምረጥ</translation>
-<translation id="161042844686301425">ውሃ ሰማያዊ</translation>
<translation id="1620510694547887537">ካሜራ</translation>
<translation id="1629803312968146339">ይህን ካርድ Chrome እንዲያስቀምጥልዎት ይፈልጋሉ?</translation>
<translation id="1639239467298939599">በመጫን ላይ</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ስርዓተ ክወና</translation>
<translation id="1721312023322545264">ይህን ጣቢያ ለመጎብኘት ከ<ph name="NAME" /> ፈቃድ ያስፈልገዎታል</translation>
<translation id="1721424275792716183">* መስክ ያስፈልጋል</translation>
+<translation id="1727741090716970331">የሚሰራ የካርድ ቁጥር ያክሉ</translation>
<translation id="1728677426644403582">የአንድ ድረ-ገጽ ምንጭ እየተመለከቱ ነው</translation>
<translation id="173080396488393970">የዚህ ዓይነቱ ካርድ አይደገፍም</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">የመለያ ቁጥር መስጠት ላይ ስህተት</translation>
<translation id="1974060860693918893">የላቀ</translation>
<translation id="1978555033938440688">የጽኑ ትዕዛዝ ስሪት</translation>
-<translation id="1995859865337580572">እባክዎ የካርድ ማረጋገጫ ኮድዎን ያረጋግጡ</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{እና 1 ተጨማሪ}one{እና # ተጨማሪ}other{እና # ተጨማሪ}}</translation>
<translation id="2025186561304664664">ተኪ ወደ ራስ-ውቅር ተዋቅሯል።</translation>
<translation id="2030481566774242610"><ph name="LINK" />ን ማለትዎ ነው?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">ቀልብስ</translation>
<translation id="20817612488360358">የስርዓት ተኪ ቅንብሮች ስራ ላይ እንዲውሉ ተቀናብረዋል ግን ግልጽ የሆነ የተኪ ውቅርም ተገልጿል።</translation>
<translation id="2086652334978798447">በGoogle የሚጠቆም ግላዊነት የተላበሰ ይዘትን ለማግኘት በመለያ ወደ Chrome ይግቡ።</translation>
+<translation id="2091887806945687916">ድምፅ</translation>
<translation id="2094505752054353250">የጎራ አለመዛመድ</translation>
<translation id="2096368010154057602">ክፍል</translation>
<translation id="2108755909498034140">ኮምፒውተርዎን ዳግም ያስጀምሩት</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">በ<ph name="POLICY_NAME" /> ስለተሻረ ችላ ተብሏል።</translation>
<translation id="2138201775715568214">በአቅራቢያ ያሉ አካላዊ ድረ-ገጾችን በመፈለግ ላይ</translation>
<translation id="213826338245044447">የተንቀሳቃሽ ስልክ ዕልባቶች</translation>
+<translation id="214556005048008348">ክፍያን ሰርዝ</translation>
<translation id="2147827593068025794">የጀርባ ስምረት</translation>
+<translation id="2148613324460538318">ካርድ አክል</translation>
<translation id="2154054054215849342">ስምረት ለእርስዎ ጎራ አይገኝም</translation>
<translation id="2154484045852737596">ካርትን ያርትዑ</translation>
<translation id="2166049586286450108">ሙሉ የአስተዳደር መድረሻ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 አድራሻ}one{# አድራሻዎች}other{# አድራሻዎች}}</translation>
<translation id="2187317261103489799">አግኝ (ነባሪ)</translation>
<translation id="2202020181578195191">ትክክለኛ የአገልግሎት ማብቂያ ዓመት ያስገቡ</translation>
+<translation id="2209523182407020534">ይህን ስህተት ሊያስከትሉ የሚችሉ መተግበሪያዎች ጸረ-ቫይረስ፣ ኬላ እና ድር ማጣሪያ ወይም ተኪ ሶፍትዌር ሊሆኑ ይችላሉ።</translation>
<translation id="2212735316055980242">መመሪያ አልተገኘም</translation>
<translation id="2213606439339815911">ግቤቶችን በማምጣት ላይ...</translation>
<translation id="2218879909401188352">በ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ አሁን ያሉ አጥቂዎች የእርስዎን መሣሪያ የሚያበላሹ አደገኛ መተግበሪያዎችን ሊጭኑ፣ በእርስዎ ሞባይል ክፍያ መጠየቂያ ላይ የተደበቁ ክፍያ መጠየቂያዎችን ሊያክሉ ወይም የእርስዎን የግል መረጃ ሊሰርቁ ይችላሉ። <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">ወደ ኋላ ተመለስ</translation>
<translation id="2503184589641749290">ተቀባይነት ያላቸው የዴቢት እና የቅድመ-ክፍያ ካርዶች</translation>
<translation id="2515629240566999685">በእርስዎ አካባቢ ያለውን ሲግናል መፈተሽ</translation>
+<translation id="2524461107774643265">ተጨማሪ መረጃ ያክሉ</translation>
+<translation id="2536110899380797252">አድራሻ ያክሉ</translation>
<translation id="2539524384386349900">አግኝ</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ልክ ያልኾነ ምላሽ ልኳል።</translation>
<translation id="2556876185419854533">&amp;አርትዕን ቀልብስ</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium በዚህ ጊዜ የእርስዎን ካርድ ማረጋገጥ አልቻለም። እባክዎ ቆይተው እንደገና ይሞክሩ።</translation>
<translation id="2705137772291741111">የተቀመጠው (የተሸጎጠ) የዚህ ጣቢያ ቅጂ የሚነበብ አልነበረም።</translation>
<translation id="2709516037105925701">ራስ-ሙላ</translation>
+<translation id="2710942282213947212">በእርስዎ ኮምፒውተር ላይ ያለ ሶፍትዌር Chromium ደህንነቱ በተጠበቀ ሁኔታ ከድር ጋር እንዳይገናኝ እያስቆመው ነው</translation>
<translation id="2712173769900027643">ፍቃድ ጠይቅ</translation>
-<translation id="2713444072780614174">ነጭ</translation>
<translation id="2720342946869265578">በአቅራቢያ</translation>
<translation id="2721148159707890343">ጥያቄ ተሳክቷል</translation>
<translation id="2728127805433021124">የአገልጋዩ እውቅና ማረጋገጫ የተፈረመው በደካማ የፊርማ ስልተቀመር ነው።</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">የአውታረ መረብ ለውጥ ተገኝቷል።</translation>
<translation id="2916038427272391327">ሌሎች ፕሮግራሞችን ይዝጉ</translation>
<translation id="2922350208395188000">የአገልጋይ እውቅና ማረጋገጫ ሊረጋገጥ አልቻለም።</translation>
+<translation id="2925673989565098301">የማድረሻ ስልት</translation>
<translation id="2928905813689894207">ክፍያ የሚጠየቅበት አድራሻ</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ተጨማሪ}}</translation>
<translation id="2941952326391522266">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው በ<ph name="DOMAIN2" /> ነው የተሰጠው። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">የተሳሳተ የመምሪያ አይነት</translation>
<translation id="3032412215588512954">ይህን ጣቢያ ዳግም መጫን ይፈልጋሉ?</translation>
<translation id="3037605927509011580">ውይ፣ ተሰናከለ!</translation>
+<translation id="3039538478787849737">ካርድ ወደ Google ይቀመጥ?</translation>
<translation id="3041612393474885105">የሰርቲፊኬት መረጃ</translation>
<translation id="3063697135517575841">Chrome በዚህ ጊዜ የእርስዎን ካርድ ማረጋገጥ አልቻለም። እባክዎ ቆይተው እንደገና ይሞክሩ።</translation>
<translation id="3064966200440839136">በውጫዊ ማከማቻ በኩል ለማጫወት ማንነት ከማያሳውቅ ሁነታ በመውጣት ላይ። ይቀጥል?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">ጊዜያዊ የአገልጋይ ስህተት</translation>
<translation id="3154506275960390542">ይህ ገጽ ደህንነቱ አስተማማኝ ባልሆነ መንገድ ላይገባ የሚችል ቅጽ ያካትታል። እርስዎ የሚልኩት ውሂብ በሽግግር ላይ እያለ በሌሎች ሊታይ ወይም አገልጋዩ የሚቀበለውን ለመለወጥ በአጥቂ ሊቀየር ይችላል።</translation>
<translation id="3157931365184549694">እነበረበት መልስ</translation>
+<translation id="3162559335345991374">እየተጠቀሙ ያሉት Wi-Fi በመለያ መግቢያ ገጹን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="3167968892399408617">ማንነትን በማያሳውቅ ትሮች ውስጥ የሚያዩዋቸው ገጾች ሁሉንም ማንነት የማያሳውቁ ትሮችዎን ከዘጉ በኋላ በአሳሽዎ ታሪክ፣ የኩኪ ማከማቻ፣ ወይም የፍለጋ ታሪክ ውስጥ አይቀመጡም። ማንነት በማያስውቅ ሁነታ መሥራት የሌሎች ሰዎች፣ አገልጋዮች፣ ሶፍትዌሮች ወይም ከጀርባዎ የቆሙ የሌሎች ሰዎች ባህሪይ ላይ ለውጥ አያመጣም።</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">ደሴት</translation>
@@ -286,6 +296,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">ክፍያን ሰርዝ</translation>
<translation id="3207960819495026254">ዕልባት ተደርጎበታል</translation>
+<translation id="3211223744486044430">በሚቀጥለው ጊዜ በበለጠ ፍጥነት ለመክፈል ይህን ካርድ በGoogle መለያዎ እና በዚህ መሣሪያ ላይ ያስቀምጡ።</translation>
<translation id="3225919329040284222">አገልጋዩ አብረው የተሰሩ የሚጠበቁ ማሟያዎችን የማያሟላ የእውቅና ማረጋገጫ ነው ያቀረበው። እነዚህ የሚጠበቁ ማሟያዎች እርስዎን ለመጠበቅ ለተረጋገጡ ከፍተኛ ደህንነት ላላቸው ድር ጣቢያዎች ተካትተዋል።</translation>
<translation id="3226128629678568754">ገጹን ለመጫን የሚያስፈልገው ውሂብ ዳግም ለማስገባት የዳግም ጫን አዝራሩን ይጫኑ።</translation>
<translation id="3227137524299004712">ማይክሮፎን</translation>
@@ -300,7 +311,6 @@
<translation id="3303855915957856445">ምንም የፍለጋ ውጤቶች አልተገኙም</translation>
<translation id="3305707030755673451">የእርስዎ ውሂብ <ph name="TIME" /> ላይ በእርስዎ የስምረት የይለፍ ቃል ተመስጥሯል። ስምረትን ለመጀመር ያስገቡት።</translation>
<translation id="3320021301628644560">የመክፈያ አድራሻ አክል</translation>
-<translation id="3329013043687509092">የቀለም ሙሌት</translation>
<translation id="333371639341676808">ይህ ገጽ ተጨማሪ ማገናኛዎችን እንዳይፈጥር አግድ።</translation>
<translation id="3338095232262050444">ደህንነቱ የተጠበቀ ነው</translation>
<translation id="3340978935015468852">ቅንብሮች</translation>
@@ -319,6 +329,7 @@
<translation id="3380864720620200369">የደንበኛ መታወቂያ፦</translation>
<translation id="3391030046425686457">የመላኪያ አድራሻ</translation>
<translation id="3395827396354264108">የመውሰጃ ዘዴ</translation>
+<translation id="3399952811970034796">የመላኪያ አድራሻ</translation>
<translation id="3422248202833853650">የማህደረ ትውስታ ቦታን ለማስለቀቅ ከሌሎች ፕሮግራሞች ዘግተው ለመውጣት ይውጡ።</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> አሁን ላይ ሊደረስበት አይችልም።</translation>
<translation id="3427092606871434483">ፍቀድ (ነባሪ)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375">የብልሽት ሪፖርት <ph name="CRASH_TIME" /> ላይ ተይዟል፣ <ph name="UPLOAD_TIME" /> ላይ ተሰቅሏል</translation>
<translation id="3681007416295224113">የሰርቲፊኬት መረጃ</translation>
<translation id="3690164694835360974">መግቢያ ደህንነቱ የተጠበቀ አይደለም</translation>
+<translation id="3704162925118123524">እየተጠቀሙ ያሉት አውታረ መረብ በመለያ መግቢያ ገጹን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">በመጫን ላይ…</translation>
<translation id="3712624925041724820">ሁሉም ፍቃዶች ተሞክረዋል</translation>
<translation id="3714780639079136834">የሞባይል ውሂብ ወይም Wi-Fi ማብራት</translation>
+<translation id="3715597595485130451">ከWi-Fi ጋር ይገናኙ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ወኪሉን፣ ኬላውን እና የዲኤንኤስ ውቅረትን መፈተሽ<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">ደህንነትዎ ላይ የሚያመጣቸውን ስጋቶች ከተረዱ አደገኛ ፕሮግራሞቹ ከመወገዳቸው በፊት <ph name="BEGIN_LINK" />ይህን ደህንነቱ ያልተጠበቀ ጣቢያ ሊጎብኙ<ph name="END_LINK" /> ይችላሉ።</translation>
<translation id="3739623965217189342">እርስዎ የቀዱት አገናኝ</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;አክልን ቀልብስ</translation>
<translation id="404928562651467259">ማስጠንቀቂያ</translation>
<translation id="4058922952496707368">ቁልፍ «<ph name="SUBKEY" />»፦ <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">የሚሰራ አድራሻ ያስገቡ</translation>
<translation id="4072486802667267160">የእርስዎን ትዕዛዝ መሥራት ላይ የሆነ ስህተት ነበር። እባክዎ እንደገና ይሞክሩ።</translation>
<translation id="4075732493274867456">ደንበኛው እና አገልጋዩ የተለመደ የኤስኤስኤል ፕሮቶኮል ስሪት ወይም የስነ መሰውር ጥቅል አይደግፉም።</translation>
<translation id="4079302484614802869">የተኪ ውቅር ቋሚ አገልጋዮችን ሳይሆን የ.pac ስክሪፕት ዩአርኤል ለመጠቀም ነው የተዋቀረው።</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">የመሣሪያ መለያ ቁጥር ልክ ያልሆነ ነው</translation>
<translation id="410351446219883937">ራስ-አጫውት</translation>
<translation id="4103763322291513355">የተከለከሉ የዩ አር ኤሎች ዝርዝር እና ሌሎች በስርዓት አስተዳዳሪዎ አስገዳጅነት የተሰጣቸው መመሪያዎችን ለማየት &lt;strong&gt;chrome://policy&lt;/strong&gt;ን ይጎብኙ።</translation>
-<translation id="4115378294792113321">ሮዝ</translation>
<translation id="4116663294526079822">ሁልጊዜ በዚህ ጣቢያ ላይ ፍቀድ</translation>
<translation id="4117700440116928470">የመመሪያ ወሰን አይደገፍም።</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 ሌላ}one{# ሌሎች}other{# ሌሎች}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" />ን ለመድረስ ሞክረዋል፣ ነገር ግን አገልጋዩ ያቀረበው የእውቅና ማረጋገጫ በሰጪው ተሽሯል። ይህ ማለት አገልጋዩ ያቀረበው የደህንነት ምስክርነቶች ፈጽሞ ሊታመኑ አይገባም። ከአጥቂ ጋር እየተገናኙ ሊሆን ይችላል።</translation>
<translation id="4394049700291259645">አሰናክል</translation>
<translation id="4406896451731180161">የፍለጋ ውጤቶች</translation>
+<translation id="4415426530740016218">የመውሰጃ አድራሻ</translation>
<translation id="4424024547088906515">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው በChrome የሚታመን አይደለም። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> የመግቢያ እውቅና ማረጋገጫዎን አልተቀበለም፣ ወይም ገና አልተሰጠዎት ይሆናል።</translation>
<translation id="443673843213245140">የተኪ መጠቀም ተሰናክሏል ግን ግልጽ የሆነ የተኪ ውቅር ተገልጿል።</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">ብልጭታ</translation>
<translation id="4558551763791394412">ቅጥያዎችዎን አሰናክለው ይሞክሩ።</translation>
<translation id="457875822857220463">መላኪያ</translation>
+<translation id="4582800630050655161">የGoogle መለያዎን መዳረሻ ሊያጡ ወይም የማንነት ስርቆት ሊያጋጥመዎት ይችላሉ። Chromium የይለፍ ቃልዎን አሁን መቀየር ይመክራል።</translation>
<translation id="4587425331216688090">አድራሻ ከChrome ይወገድ?</translation>
<translation id="4592951414987517459">ወደ የእርስዎ <ph name="DOMAIN" /> ግንኙነት ዘመናዊ የምስጠራ ጥቅል በመጠቀም ተመስጥሯል።</translation>
<translation id="4594403342090139922">&amp;ሰርዝን ቀልብስ</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው ስህተቶች አሉበት። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
<translation id="4690462567478992370">ልክ ያልሆነ የእውቅና ማረጋገጫ መጠቀም አቁም</translation>
+<translation id="4690954380545377795">የGoogle መለያዎን መዳረሻ ሊያጡ ወይም የማንነት ስርቆት ሊያጋጥመዎት ይችላሉ። Chrome የይለፍ ቃልዎን አሁን መቀየር ይመክራል።</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">የእርስዎ ግንኙነት ተቋርጧል</translation>
<translation id="471880041731876836">ይህን ጣቢያ የመጎብኘት ፈቃድ የለዎትም</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />የWindows አውታረ መረብ መመርመሪያን በማሄድ ላይ<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">የእርስዎ ክፍያ</translation>
<translation id="4726672564094551039">መምሪያዎችን ዳግም ጫን</translation>
<translation id="4728558894243024398">የመሣሪያ ስርዓት</translation>
<translation id="4736825316280949806">Chromiumን ዳግም ያስጀምሩት</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">የመጠባበቂያ ማከማቻ በመጥፎ ሁኔታ ላይ</translation>
<translation id="5023310440958281426">የአስተዳዳሪዎ መመሪያዎችን ያረጋግጡ</translation>
<translation id="5029568752722684782">ቅጂን አጽዳ</translation>
+<translation id="503069730517007720">ለ«<ph name="SOFTWARE_NAME" />» ስር እውቅና ማረጋገጫ ያስፈልጋል፣ ነገር ግን አልተጫነም። የእርስዎ አይቲ አስተዳዳሪ ይህን ችግር ለመፍታት የ«<ph name="SOFTWARE_NAME" />» ውቅረት መመሪያዎችን መመልከት አለበት። <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">ስለ Google ትርጉም</translation>
<translation id="5039804452771397117">ፍቀድ</translation>
<translation id="5040262127954254034">ግላዊነት</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">ሙከራዎች</translation>
<translation id="5205222826937269299">ስም ያስፈልጋል</translation>
<translation id="5222812217790122047">ኢሜይል ያስፈልጋል</translation>
+<translation id="522700295135997067">ይህ ጣቢያ አሁን የይለፍ ቃልዎን ሰርቆት ሊሆን ይችላል</translation>
+<translation id="5230733896359313003">የሚላክበት አድራሻ</translation>
<translation id="5251803541071282808">ደመና</translation>
<translation id="5277279256032773186">በሥራ ላይ Chrome እየተጠቀሙ ነዎት? ንግድ ሥራዎች ለሠራተኞቻቸው የChrome ቅንብሮችን ማስተዳደር ይችላሉ። የበለጠ ይረዱ</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />እርስዎ ድር ላይ መሆን እንዲችሉ ሶፍትዌሩን በጊዜያዊነት ለማሰናከል የሚከተሉትን ደረጃዎች ይከተሉ። የአስተዳዳሪ ልዩ መብቶች ሊኖርዎት ይገባል።<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">ከዚህ ጣቢያ ጋር ያለዎት ግንኙነት ግላዊ አይደለም። ከምናባዊ ዕውነታ ሁነታ በማናቸውም ጊዜ ለመውጣት፣ የጆሮ ማዳመጫን ያስወግዱ እና ተመለስ የሚለውን ይጫኑ።</translation>
<translation id="5299298092464848405">መምሪያን መተንተን ላይ ስህተት</translation>
+<translation id="5308380583665731573">ይገናኙ</translation>
<translation id="5308689395849655368">የብልሽት ሪፖርት ማድረግ ተሰናክሏል።</translation>
<translation id="5317780077021120954">አስቀምጥ</translation>
<translation id="5327248766486351172">ስም</translation>
+<translation id="5332219387342487447">የመላኪያ መንገድ</translation>
<translation id="5355557959165512791">የዕውቅና ማረጋገጫው ስለተሻረ <ph name="SITE" />ን መጎብኘት አይችሉም። የአውታረ መረብ ስህተቶች እና ጥቃቶች አብዛኛው ጊዜ ጊዜያዊ ብቻ ናቸው፣ ስለዚህ ይህ ገጽ በኋላ ላይ ሊሠራ ይችላል።</translation>
<translation id="536296301121032821">የመምሪያ ቅንብሮችን ማከማቸት አልተሳካም</translation>
<translation id="5386426401304769735">የዚህ ጣቢያ የዕውቅና ማረጋገጫ ሰንሰለቱ SHA-1 በመጠቀም የተፈረመ የዕውቅና ማረጋገጫን ያካትታል።</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">በኩባንያ፣ በድርጅት ወይም በትምህርት ቤት ውስጠ መረብ ውስጥ ያለው ይህ ጣቢያ እንደ ውጫዊ የድር ጣቢያ ተመሳሳይ ዩአርኤል አለው።
<ph name="LINE_BREAK" />
የእርስዎን የስርዓት አስተዳዳሪ ለማነጋገር ይሞክሩ።</translation>
+<translation id="5499929369096410817">የ<ph name="CREDIT_CARD" /> ደህንነት ኮድ ያስገቡ። ይህ ኮድ አይቀመጥም።</translation>
<translation id="5509780412636533143">የተዳደሩ እልባቶች</translation>
<translation id="5510766032865166053">ተወስዶ ወይም ተሰርዞ ሊሆን ይችላል።</translation>
<translation id="5523118979700054094">የመምሪያ ስም</translation>
<translation id="552553974213252141">ጽሑፉ በትክክል ነው የወጣው?</translation>
<translation id="5540224163453853">የተጠየቀውን ጽሑፍ ማግኘት አልተቻለም።</translation>
+<translation id="5541546772353173584">ኢሜይል ያክሉ</translation>
<translation id="5544037170328430102"><ph name="SITE" /> ላይ የተካተተ ገጽ እንዲህ ይላል፦</translation>
+<translation id="5545756402275714221">ለእርስዎ የሚሆኑ ጽሑፎች</translation>
<translation id="5556459405103347317">ዳግም ጫን</translation>
<translation id="5560088892362098740">አገልግሎቱ የሚያበቃበት ቀን</translation>
<translation id="5565735124758917034">ገባሪ</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">ኢሜይል</translation>
<translation id="5669703222995421982">ግላዊነት የተላበሰ ይዘት ያግኙ</translation>
<translation id="5675650730144413517">ይህ ገጽ እየሠራ አይደለም</translation>
+<translation id="5689199277474810259">ወደ JSON ላክ</translation>
<translation id="5710435578057952990">የዚህ ድረ-ገጽ ማንነት አልተረጋገጠም።</translation>
<translation id="5719499550583120431">የቅድመ-ክፍያ ካርዶች ተቀባይነት አላቸው።</translation>
<translation id="5720705177508910913">የአሁኑ ተጠቃሚ</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065">ወደ <ph name="DOMAIN" /> ግንኙነትዎ ፍጹማዊ ስነ መሰውር ጥቅል በመጠቀም የተመሳጠረ ነው።</translation>
<translation id="5813119285467412249">&amp;አክልን ድገም</translation>
<translation id="5838278095973806738">በአጥቂዎች ሊሰረቅ ስለሚችል በዚህ ጣቢያ ላይ ማናቸውም አደጋን ሊያስከትል የሚችል መረጃ (ለምሳሌ፦ የይለፍ ቃሎች ወይም የክሬዲት ካርዶች) ማስገባት የለብዎትም።</translation>
+<translation id="5866257070973731571">ስልክ ቁጥር ያክሉ</translation>
<translation id="5869405914158311789">ይህ ጣቢያ ሊደረስበት አይችልም</translation>
<translation id="5869522115854928033">የተቀመጡ የይለፍ ቃሎች</translation>
<translation id="5872918882028971132">የወላጅ አስተያየት ጥቆማዎች</translation>
<translation id="5893752035575986141">ክሬዲት ካርዶች ተቀባይነት አላቸው።</translation>
-<translation id="5901630391730855834">ቢጫ</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ሰምሯል)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 ጥቅም ላይ ያለ}one{# ጥቅም ላይ ያለ}other{# ጥቅም ላይ}}</translation>
<translation id="5959728338436674663">አደገኛ መተግበሪያዎችን እና ጣቢያዎችን ማግኘት እንዲያግዝ አንዳንድ <ph name="BEGIN_WHITEPAPER_LINK" />የሥርዓት መረጃ እና የገጽ ይዘት<ph name="END_WHITEPAPER_LINK" />ን በራስ-ሰር ወደ Google ይላኩ። <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">የዕውቂያ መረጃን ያርትዑ</translation>
<translation id="5967867314010545767">ከታሪክ አስወግድ</translation>
<translation id="5975083100439434680">አሳንስ</translation>
+<translation id="597552863672748783">የደህነንት ኮድ ያረጋግጡ</translation>
<translation id="598637245381783098">የክፍያ መተግበሪያን መክፈት አይቻልም</translation>
<translation id="5989320800837274978">ቋሚ ተኪ አገልጋዮችም ሆኑ የ.pac ስክሪፕት ዩአርኤል አልተገለጹም።</translation>
<translation id="5990559369517809815">ወደ አገልጋዩ የተላኩ ጥያቄዎች በአንድ ቅጥያ ታግደዋል።</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ገጽ 1}one{ገጽ #}other{ገጽ #}}</translation>
-<translation id="6017514345406065928">አረንጓዴ</translation>
<translation id="6017850046339264347">በ<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="6025416945513303461"><ph name="TYPE_1" />፣ <ph name="TYPE_2" />፣ <ph name="TYPE_3" /> (ሰምሯል)</translation>
<translation id="6027201098523975773">ስም ያስገቡ</translation>
<translation id="6040143037577758943">ዝጋ</translation>
-<translation id="6042308850641462728">ተጨማሪ</translation>
<translation id="6047233362582046994">በእርስዎ ደህንነት ላይ የሚያመጣቸውን ስጋቶች ከተረዱ አደገኛ መተግበሪያዎቹ ከመወገዳቸው በፊት <ph name="BEGIN_LINK" />ይህን ጣቢያ መጎብኘት<ph name="END_LINK" /> ይችላሉ።</translation>
<translation id="6047927260846328439">ይህ ይዘት ሶፍትዌር እንዲጭኑ ወይም የግል መረጃ ገልጸው እንዲያሳዩ እርስዎን ለማሳሳት ሊሞክር ይችል ይሆናል። <ph name="BEGIN_LINK" />የሆነው ሆኖ አሳይ<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> የዕውቅና ማረጋገጫ ሚስማር መሰካትን ስለሚጠቀም ድር ጣቢያውን አሁን መጎብኘት አይችሉም። የአውታረ መረብ ስህተቶች እና ጥቃቶች ብዙውን ጊዜ ጊዜያዊ ስለሆኑ ይህ ገጽ በኋላ ላይ ሊሠራ ይችላል።</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">የቅጥያ ገጽ እየተመለከቱ ነው</translation>
<translation id="6596325263575161958">የምስጠራ አማራጮች</translation>
<translation id="662080504995468778">ቆይ</translation>
+<translation id="6624427990725312378">የዕውቂያ መረጃ</translation>
<translation id="6626291197371920147">የሚሰራ የካርድ ቁጥር ያክሉ</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ፍለጋ</translation>
<translation id="6630809736994426279">አሁን <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ የሚገኙ አጥቂዎች የእርስዎን መረጃ (ለምሳሌ፦ ፎቶዎች፣ የይለፍ ቃላት፣ መልዕክቶች፣ እና ክሬዲት ካርዶች የመሳሰሉ) የሚሰርቁ ወይም የሚሰርዙ አደገኛ ፕሮግራሞችን በእርስዎ Mac ላይ ለመጫን እየሞከሩ ሊሆኑ ይችላሉ። <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">ቀዳሚ</translation>
<translation id="6710594484020273272">&lt;የፍለጋ ቃል ይተይቡ&gt;</translation>
<translation id="6711464428925977395">በተኪ አገልጋዩ ላይ የሆነ ችግር አለ ወይም አድራሻው ትክክል አይደለም።</translation>
-<translation id="6727102863431372879">አዘጋጅ</translation>
<translation id="674375294223700098">ያልታወቀ የአገልጋይ እውቅና ማረጋገጫ ስህተት።</translation>
<translation id="6753269504797312559">የመምሪያ እሴት</translation>
<translation id="6757797048963528358">የእርስዎ መሣሪያ ተኝቷል።</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">የመገለጫ ዱካ</translation>
<translation id="7424977062513257142">በዚህ ድረ-ገጽ ላይ ያለ የተካተተ ገጽ እንዲህ ይላል፦</translation>
+<translation id="7437289804838430631">የእውቂያ መረጃ አክል</translation>
<translation id="7441627299479586546">የተሳሳተ የመምሪያ ርዕሰ ጉዳይ</translation>
<translation id="7444046173054089907">ይህ ጣቢያ ታግዷል</translation>
<translation id="7445762425076701745">የተገናኙት የአገልጋይ ማንነት ሙሉ ለሙሉ ሊረጋገጥ አልቻለም። ስሙ በአውታረ መረብዎ ውስጥ ብቻ ልክ ከሆነ አገልጋይ ጋር ነው የተገናኙት፣ እና ባለቤትነቱ በውጫዊ የእውቅና ማረጋገጫ ሊረጋገጥ አይችልም። አንዳንድ የእውቅና ማረጋገጫ ባለስልጣናት ይሁን ብለው ለእነዚህ ስሞች የእውቅና ማረጋገጫዎች መስጠታቸው የማይቀር እንደመሆኑ መጠን፣ ከአጥቂ ሳይሆን ከታሰበው ድር ጣቢያ ጋር መገናኘትዎን የሚረጋገጥበት ምንም መንገድ የለም።</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">ወደ ፊት</translation>
<translation id="7485870689360869515">ምንም ውሂብ አልተገኘም።</translation>
<translation id="7508255263130623398">የተመላሽ መመሪያ መሣሪያ መታወቂያ ባዶ ነው ወይም ከአሁኑ የመሣሪያ መታወቂያ ጋር አይዛመድም</translation>
+<translation id="7511955381719512146">እየተጠቀሙበት ያለው Wi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="7514365320538308">አውርድ</translation>
<translation id="7518003948725431193">ለዚህ የድር አድራሻ ምንም ድረ-ገጽ አልተገኘም፦ <ph name="URL" /></translation>
<translation id="7521387064766892559">ጃቫስክሪፕት</translation>
<translation id="7526934274050461096">ከዚሃ ጣቢያ ጋር ያለዎት ግንኙነት የግል አይደለም</translation>
-<translation id="7535087603100972091">እሴት</translation>
<translation id="7537536606612762813">ግዴታ</translation>
<translation id="7542403920425041731">አንዴ ካረጋገጡ በኋላ የካርድ ዝርዝሮችዎ ለዚህ ጣቢያ ይጋራሉ።</translation>
<translation id="7542995811387359312">ይህ ቅጽ ደህንነቱ የተጠበቀ ግንኙነት ስለማይጠቀም የክሬዲት ካርድ ራስ-መሙላት ተሰናክሏል።</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው በተጭበረበረ ሁኔታ ተሰጥቶ ሊሆን ይችላል። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
<translation id="7568593326407688803">ይህ ገጽ በ<ph name="ORIGINAL_LANGUAGE" />ነው። መተርጎም ይፈልጋሉ?</translation>
<translation id="7569952961197462199">ክሬዲት ካርድ ከChrome ይወገድ?</translation>
-<translation id="7569983096843329377">ጥቁር</translation>
<translation id="7578104083680115302">Google ላይ ያስቀመጧቸውን ካርዶች በመጠቀም በሁሉም መሣሪያዎች ላይ በጣቢያዎችና መተግበሪያዎች ላይ በፍጥነት ይክፈሉ።</translation>
<translation id="7588950540487816470">አካላዊ ድር</translation>
<translation id="7592362899630581445">የአገልጋዩ እውቅና ማረጋገጫ አንዳንድ ገደቦችን ይጥሳል።</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">በዚህ ጣቢያ ላይ ያሉ አጥቂዎች እርስዎ የአሰሳ ተሞክሮዎን ሊጎዱ (ለምሳሌ፦ መነሻ ገጽዎን በመቀየር ወይም በሚጎበኟቸው ጣቢያዎች ላይ ተጨማሪ ማስታወቂያዎችን በማሳየት) የሚችሉ ፕሮግራሞችን እንዲጭኑ ለማታለል ሊሞክሩ ይችላሉ።</translation>
<translation id="7674629440242451245">አዲስ የሆኑ አሪፍ የChrome ባህሪያትን ይፈልጋሉ? በ chrome.com/dev ላይ ያለውን የdev ሰርጣችንን ይሞክሩት።</translation>
<translation id="7682287625158474539">ዕቃን የማጓጓዝ ስራ</translation>
+<translation id="7699293099605015246">ጽሑፎች አሁን አይገኙም</translation>
<translation id="7701040980221191251">ምንም</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ወደ <ph name="SITE" /> ቀጥል (ደህንነቱ ያልተጠበቀ)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">ሰርቲፊኬት</translation>
<translation id="7716147886133743102">በእርስዎ አስተዳዳሪ ታግዷል</translation>
<translation id="7716424297397655342">ይህ ጣቢያ ከመሸጎጫው ላይ ሊጫን አይችልም</translation>
+<translation id="7723047071702270851">ካርትን ያርትዑ</translation>
<translation id="774634243536837715">አደገኛ ይዘት ታግዷል።</translation>
<translation id="7752995774971033316">አይቀናበርም</translation>
<translation id="7755287808199759310">የእርስዎ ወላጅ እገዳውን ሊያነሱልዎ ይችላሉ</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">አድራሻ አክል</translation>
<translation id="777702478322588152">የፕሪፌክት ስልጣን</translation>
<translation id="7791543448312431591">አክል</translation>
+<translation id="7793553086574152071">በሚቀጥለው ጊዜ በበለጠ ፍጥነት ለመክፈል ይህን ካርድ በGoogle መለያዎ ላይ ያስቀምጡ።</translation>
<translation id="7793809570500803535"><ph name="SITE" /> ላይ ያለው ድረ-ገጽ ለጊዜው የማይሰራ ወይም እስከመጨረሻው ወደ አዲስ የድር አድራሻ ተዛውሮ ሊሆን ይችላል።</translation>
<translation id="7800304661137206267"><ph name="MAC" /> ለመልዕክት ማረጋገጥ እና ደግሞ <ph name="KX" /> ለቁልፍ መቀያየሪያ ስልቶች በማድረግ ግንኙነቱ <ph name="CIPHER" />ን በመጠቀም የተመሰጠረ ነው።</translation>
+<translation id="7802523362929240268">ጣቢያው ህጋዊ ነው</translation>
<translation id="780301667611848630">አይ፣ አመሰግናለሁ</translation>
<translation id="7805768142964895445">ሁኔታ</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">የአስተያየት ጥቆማ ከChrome ይወገድ?</translation>
<translation id="7815407501681723534">ለ«<ph name="SEARCH_STRING" />» <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ተገኝተዋል።</translation>
+<translation id="782886543891417279">እየተጠቀሙበት ያለው Wi-Fi (<ph name="WIFI_NAME" />) በመለያ መግቢያ ገጹን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="785549533363645510">ሆኖም ግን የማይታዩ አይደሉም። ማንነት የማያሳውቅ ሁነታ መጠቀም የእርስዎን አሰሳ፣ የበይነመረብ አገልግሎት አቅራቢ ወይም የሚጎበኟቸው ድር ጣቢያዎች ከአሰሪዎ አይደብቃቸውም።</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">የዴቢት እና የቅድመ-ክፍያ ካርዶች ተቀባይነት አላቸው።</translation>
+<translation id="7878562273885520351">የእርስዎ ይለፍ ቃል ተሰርቆ ሊሆን ይችላል</translation>
<translation id="7887683347370398519">የእርስዎን CVC ይፈትሹ እና እንደገና ይሞክሩ</translation>
<translation id="79338296614623784">የሚሰራ ስልክ ቁጥር ያስገቡ</translation>
<translation id="7935318582918952113">የDOM ማጣሪያ</translation>
<translation id="7938958445268990899">የአገልጋይ እውቅና ማረጋገጫ ገና አልጸናም።</translation>
-<translation id="7942349550061667556">ቀይ</translation>
<translation id="7947285636476623132">የእርስዎን የአገልግሎት ማብቂያ ዓመት ይመልከቱ እና እንደገና ይሞክሩ</translation>
<translation id="7951415247503192394">(32-ቢት)</translation>
<translation id="7956713633345437162">የተንቀሳቃሽ ስልክ ዕልባቶች</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">ጠይቅ (ነባሪ)</translation>
<translation id="8041089156583427627">ግብረ መልስ ላክ</translation>
<translation id="8041940743680923270">ሁለንተናዊ ነባሪውን ተጠቀሙ (ጠይቅ)</translation>
+<translation id="8057711352706143257">«<ph name="SOFTWARE_NAME" />» በአግባቡ አልተዋቀረም። «<ph name="SOFTWARE_NAME" />»ን ማራገፍ አብዛኛው ጊዜ ችግሩን ይፈታዋል። <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">ጽሑፉን ማየት አልተቻለም።</translation>
<translation id="8091372947890762290">ማግበር በአገልጋዩ ላይ በመጠባበቅ ላይ ነው</translation>
+<translation id="8094917007353911263">እየተጠቀሙበት ያለው አውታረ መረብ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
+<translation id="8103161714697287722">የክፍያ ስልት</translation>
<translation id="8118489163946903409">የመክፈያ ዘዴ</translation>
+<translation id="8127301229239896662">«<ph name="SOFTWARE_NAME" />» በእርስዎ ኮምፒውተር ወይም አውታረ መረብ ላይ በአግባቡ አልተጫነም። አስተዳዳሪዎ ይህን ችግር እንዲፈታ ይጠይቁ።</translation>
<translation id="8131740175452115882">አረጋግጥ</translation>
<translation id="8134994873729925007">የ<ph name="HOST_NAME" /> አገልጋይ <ph name="BEGIN_ABBR" />ዲኤንኤስ አድራሻ<ph name="END_ABBR" /> ሊገኝ አልተቻለም።</translation>
<translation id="8149426793427495338">የእርስዎ ኮምፒውተ ተኝቷል።</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">ይሄ ምን ማለት እንደሆነ እርግጠኛ ካልሆኑ የአውታረ መረብ አስተዳዳሪዎን ያግኙ።</translation>
<translation id="8293206222192510085">እልባት ያክሉ</translation>
<translation id="8294431847097064396">ምንጭ</translation>
+<translation id="8298115750975731693">እየተጠቀሙበት ያለው Wi-Fi (<ph name="WIFI_NAME" />) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="8306404619377842860">የእርስዎ መሣሪያ ቀን እና ሰዓት (<ph name="DATE_AND_TIME" />) ትክክል ስላልሆኑ ከ<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ጋር የግል ግንኙነት መመሥረት አይቻልም። <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">በአውታረመረብ ግንኙነት ችግር ምክንያት የትርጉም ስራው ተሰናክሏል።</translation>
<translation id="8332188693563227489">የ<ph name="HOST_NAME" /> መዳረሻ ተከልክሏል</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">በቅርብ ጊዜ የተዘጉ</translation>
<translation id="8874824191258364635">የሚሰራ የካርድ ቁጥር ያስገቡ</translation>
<translation id="8876793034577346603">የአውታረ መረብ ውቅር ሊተነተን አልቻለም።</translation>
-<translation id="8889402386540077796">ለይ ቀለም</translation>
<translation id="8891727572606052622">ልክ ያልሆነ የተኪ ሁነታ።</translation>
<translation id="889901481107108152">ይቅርታ፣ ይህ ሙከራ ለመሣሪያ ስርዓትዎ አይገኝም።</translation>
<translation id="8903921497873541725">አጉላ</translation>
<translation id="8931333241327730545">ይህን ካርድ በእርስዎ የGoogle መለያ ላይ ማስቀመጥ ይፈልጋሉ?</translation>
<translation id="8932102934695377596">የእርስዎ ሰዓት ወደ ኋላ ቀርቷል</translation>
+<translation id="893332455753468063">ስም ያክሉ</translation>
<translation id="8938939909778640821">ተቀባይነት ያላቸው የክሬዲት እና የቅድመ-ክፍያ ካርዶች</translation>
+<translation id="8957210676456822347">የተያዥ መግቢያ ፈቀዳ</translation>
<translation id="8971063699422889582">የአገልጋይ እውቅና ማረጋገጫ ጊዜው አልፎበታል።</translation>
-<translation id="8986494364107987395">የአጠቃቀም ስታስቲክስ እና የብልሽት ሪፖርቶች በራስ ሰር ወደ Google ይላኩ።</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">ቀጥሎ ያለው ጣቢያ ጎጂ ፕሮግራሙች አሉት</translation>
<translation id="8997023839087525404">አገልጋዩ የእውቅና ማረጋገጫ ግልጽነት መመሪያውን በመጠቀም በይፋ ያልተገለጸ የእውቅና ማረጋገጫን አቅርቧል። ይህ ለአንዳንድ የእውቅና ማረጋገጫዎች ሊታመኑ የሚችሉ መሆናቸውን ለማረጋገጥ እና ከአጥቂዎች ጥበቃ ለማድረግ እንዲቻል አስፈላጊ ነው።</translation>
<translation id="9001074447101275817">ተኪ <ph name="DOMAIN" /> የተጠቃሚ ስም እና የይለፍ ቃል ያስፈልገዋል።</translation>
<translation id="9005998258318286617">የፒዲኤፍ ሰነድ መጫን አልተሳካም።</translation>
+<translation id="9008201768610948239">ችላ በል</translation>
<translation id="901974403500617787">በመላው ስርዓት ላይ የሚተገበሩ ጥቆማዎች በባለቤቱ ብቻ ነው ሊዋቀሩ የሚችሉት፦ <ph name="OWNER_EMAIL" />።</translation>
<translation id="9020200922353704812">የካርድ ማስከፈያ አድራሻ ያስፈልጋል</translation>
<translation id="9020542370529661692">ይህ ገጽ ወደ <ph name="TARGET_LANGUAGE" /> ተተርጉሟል</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619"><ph name="DOMAIN" />ን ለመድረስ ሞክረው ነበር፣ ግን አገልጋዩ ልክ ያልሆነ የእውቅና ማረጋገጫ ነው ያሳየው።</translation>
<translation id="9050666287014529139">የይለፍ ሐረግ</translation>
<translation id="9065203028668620118">አርትዕ</translation>
-<translation id="9068849894565669697">ቀለም ይምረጡ</translation>
<translation id="9069693763241529744">በቅጥያ ታግዷል</translation>
<translation id="9076283476770535406">ለአዋቂ ብቻ የሚሆን ይዘት ሊኖረው ይችላል</translation>
<translation id="9078964945751709336">ተጨማሪ መረጃ ያስፈልጋል</translation>
+<translation id="9080712759204168376">የትዕዛዝ ማጠቃለያ</translation>
<translation id="9103872766612412690"><ph name="SITE" /> የእርስዎን መረጃ ለመጠበቅ በመደበኝነት ምስጠራን ይጠቀማል። Chromium አሁን ከ<ph name="SITE" /> ጋር ለመገናኘት ሲሞክር ድር ጣቢያው ያልተለመዱ እና ትክክል ያልሆኑ ምስክርነቶችን መልሷል። ይህ አንድ አጥቂ <ph name="SITE" />ን አስመስሎ ለመቅረብ ሲሞክር ነው ወይም አንድ የWi-Fi መግቢያ ገጽ ግንኙነቱን ሲቋረጥ ሊከሰት ይችላል። Chromium ማንኛውም የውሂብ ልውውጥ ከመካሄዱ በፊት ግንኙነቱን ስላቋረጠው አሁንም የእርስዎ መረጃ ደህንነት የተጠበቀ ነው።</translation>
+<translation id="9106062320799175032">የመክፈያ አድራሻ ያክሉ</translation>
+<translation id="910908805481542201">ይህን እንዳስተካክለው አግዘኝ</translation>
+<translation id="9128870381267983090">ከአውታረ መረብ ጋር ይገናኙ</translation>
<translation id="9137013805542155359">የመጀመሪያውን አሳይ</translation>
<translation id="9137248913990643158">ይህን መተግበሪያ ከመጠቀምዎ በፊት እባክዎ ይጀምሩና ወደ Chrome ይግቡ።</translation>
<translation id="9148507642005240123">&amp;አርትዕን ቀልብስ</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> የማይጠቀም ፕሮቶኮል ይጠቀማል።</translation>
<translation id="9205078245616868884">የእርስዎ ውሂብ በእርስዎ የስምረት የይለፍ ቃል ተመስጥሯል። ስምረትን ለመጀመር ያስገቡት።</translation>
<translation id="9207861905230894330">ጽሑፍ ማከል አልተቻለም።</translation>
+<translation id="9215416866750762878">አንድ መተግበሪያ Chrome ከዚህ ጣቢያ ጋር ደህንነቱ በተጠበቀ ሁኔታ እንዳይገናኝ እያቆመው ነው</translation>
<translation id="9219103736887031265">ምስሎች</translation>
<translation id="933612690413056017">ምንም የበይነመረብ ግንኙነት የለም</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{ምንም}=1{1 ንጥል}one{# ንጥሎች}other{# ንጥሎች}}</translation>
<translation id="981121421437150478">ከመስመር ውጪ</translation>
<translation id="988159990683914416">የገንቢዎች ግንባታ</translation>
+<translation id="989988560359834682">አድራሻ ያርትዑ</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">«<ph name="SOFTWARE_NAME" />» በእርስዎ ኮምፒውተር ወይም በአውታረ መረቡ ላይ በአግባቡ አልተጫነም፦
+ &lt;ul&gt;
+ &lt;li&gt;«<ph name="SOFTWARE_NAME" />»ን ለማራገፍ ወይም ለማሰናከል ይሞክሩ&lt;/li&gt;
+ &lt;li&gt;ከሌላ አውታረ መረብ ጋር ለመገናኘት ይሞክሩ&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index 618aa84fb12..4d979b7e797 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">الإشارات المرجعية على سطح المكتب</translation>
<translation id="1074497978438210769">غير آمن</translation>
<translation id="1080116354587839789">ملاءمة مع العرض</translation>
+<translation id="1088860948719068836">إضافة الاسم الوارد في البطاقة</translation>
<translation id="1103523840287552314">ترجمة اللغة <ph name="LANGUAGE" /> دائمًا</translation>
+<translation id="1103778128462718200">عرض جميع كلمات المرور المحفوظة...</translation>
<translation id="1107591249535594099">‏إذا تم وضع علامة على هذا الخيار، سيخزّن Chrome نسخة من هذه البطاقة على هذا الجهاز لتعبئة النماذج بشكل أسرع.</translation>
<translation id="1111153019813902504">الإشارات الجديدة</translation>
<translation id="1113869188872983271">تراجع عن إعادة الت&amp;رتيب</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />، <ph name="TYPE_2" /> (تمت المزامنة)</translation>
<translation id="1263231323834454256">قائمة القراءة</translation>
<translation id="1264126396475825575">تقرير الأعطال الذي تم الحصول عليه في <ph name="CRASH_TIME" /> (لم يتم تحميله بعد أو تجاهله)</translation>
+<translation id="1270502636509132238">طريقة الاستلام</translation>
<translation id="1281526147609854549">تم الإصدار بواسطة <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">عدم ترجمة هذا الموقع مطلقًا</translation>
<translation id="129553762522093515">المغلقة حديثًا</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">في انتظار الاتصال…</translation>
<translation id="153384715582417236">هذا كل شيء الآن</translation>
<translation id="1549470594296187301">‏يجب تمكين JavaScript لاستخدام هذه الميزة.</translation>
-<translation id="1555130319947370107">أزرق</translation>
<translation id="1559528461873125649">لا وجود لمثل هذا الملف أو الدليل</translation>
<translation id="1583429793053364125">حدث خطأ في شيء ما أثناء عرض صفحة الويب هذه.</translation>
<translation id="1592005682883173041">الوصول إلى البيانات المحلية</translation>
<translation id="1594030484168838125">اختيار</translation>
-<translation id="161042844686301425">سماوي</translation>
<translation id="1620510694547887537">الكاميرا</translation>
<translation id="1629803312968146339">‏هل تريد من Chrome حفظ هذه البطاقة؟</translation>
<translation id="1639239467298939599">جارٍ التحميل.</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">نظام التشغيل</translation>
<translation id="1721312023322545264">أنت بحاجة لإذن من <ph name="NAME" /> لزيارة هذا الموقع</translation>
<translation id="1721424275792716183">* هناك حقل مطلوب</translation>
+<translation id="1727741090716970331">إضافة رقم بطاقة صالح</translation>
<translation id="1728677426644403582">أنت تعرض مصدر صفحة ويب</translation>
<translation id="173080396488393970">لا يتم دعم هذا النوع من البطاقات</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">خطأ أثناء التسلسل</translation>
<translation id="1974060860693918893">إعدادات متقدمة</translation>
<translation id="1978555033938440688">إصدار البرامج الثابتة</translation>
-<translation id="1995859865337580572">‏يُرجى التحقق من رمز التحقق من البطاقة (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{وتطبيق آخر}zero{و# تطبيق آخر}two{وتطبيقان (#) آخران}few{و# تطبيقات أخرى}many{و# تطبيقًا آخر}other{و# تطبيق آخر}}</translation>
<translation id="2025186561304664664">تم تعيين الخادم الوكيل على التهيئة التلقائية.</translation>
<translation id="2030481566774242610">هل تقصد <ph name="LINK" />؟</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">تراجع</translation>
<translation id="20817612488360358">تم تعيين إعدادات الخادم الوكيل ليتم استخدامها وتم أيضًا تحديد تهيئة صريحة للخادم الوكيل.</translation>
<translation id="2086652334978798447">‏للحصول على محتوى مخصص اقترحته Google، سجِّلْ الدخول إلى Chrome.</translation>
+<translation id="2091887806945687916">الصوت</translation>
<translation id="2094505752054353250">النطاق غير متطابق</translation>
<translation id="2096368010154057602">الإدارة</translation>
<translation id="2108755909498034140">إعادة تشغيل جهاز الكمبيوتر</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">تم تجاهلها نظرًا لتجاوزها بواسطة <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">جارٍ البحث عن صفحات الشبكة المادية المجاورة</translation>
<translation id="213826338245044447">الإشارات المرجعية على الجوال</translation>
+<translation id="214556005048008348">إلغاء الدفع</translation>
<translation id="2147827593068025794">مزامنة الخلفية</translation>
+<translation id="2148613324460538318">إضافة بطاقة</translation>
<translation id="2154054054215849342">المزامنة غير متاحة لنطاقك</translation>
<translation id="2154484045852737596">تعديل البطاقة</translation>
<translation id="2166049586286450108">الوصول الكامل للمشرف</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{عنوان واحد}zero{# عنوان}two{عنوانان (#)}few{# عناوين}many{# عنوانًا}other{# عنوان}}</translation>
<translation id="2187317261103489799">اكتشاف (افتراضي)</translation>
<translation id="2202020181578195191">أدخِل سنة تاريخ انتهاء صلاحية صحيحة</translation>
+<translation id="2209523182407020534">تتضمن التطبيقات التي يمكنها التسبب في ذلك الخطأ برنامج مكافحة الفيروسات، والجدار الناري، وبرنامج تصفية الويب أو برنامج الخادم الوكيل.</translation>
<translation id="2212735316055980242">تعذر العثور على السياسة</translation>
<translation id="2213606439339815911">جارٍ جلب الإدخالات...</translation>
<translation id="2218879909401188352">يمكن حاليًا للمهاجمين على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت تطبيقات خطيرة تدمر الجهاز أو تضيف رسومًا إلى فاتورة الجوّال أو تسرق المعلومات الشخصية. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">الرجوع للخلف</translation>
<translation id="2503184589641749290">بطاقات السحب الآلي وبطاقات الدفع المسبق المقبولة</translation>
<translation id="2515629240566999685">التحقق من الإشارة في منطقتك</translation>
+<translation id="2524461107774643265">إضافة مزيد من المعلومات</translation>
+<translation id="2536110899380797252">إضافة عنوان</translation>
<translation id="2539524384386349900">اكتشاف</translation>
<translation id="255002559098805027">أرسل <ph name="HOST_NAME" /> استجابة غير صالحة.</translation>
<translation id="2556876185419854533">تراجع عن ا&amp;لتحرير</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">‏لم يتمكن Chromium من التأكد من بطاقتك في الوقت الحالي. يُرجى إعادة المحاولة في وقت لاحق.</translation>
<translation id="2705137772291741111">تعذر قراءة النسخة المحفوظة (المخزنة في ذاكرة التخزين المؤقت) لموقع الويب هذا.</translation>
<translation id="2709516037105925701">الملء التلقائي</translation>
+<translation id="2710942282213947212">‏تعمل البرامج على جهاز الكمبيوتر على منع اتصال Chromium بالويب بشكل آمن</translation>
<translation id="2712173769900027643">طلب إذن</translation>
-<translation id="2713444072780614174">أبيض</translation>
<translation id="2720342946869265578">المجاورة</translation>
<translation id="2721148159707890343">تم إرسال الطلب بنجاح</translation>
<translation id="2728127805433021124">شهادة الخادم موقّعة باستخدام خوارزمية توقيع ضعيفة.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">تم اكتشاف حدوث تغيير في الشبكة.</translation>
<translation id="2916038427272391327">إغلاق البرامج الأخرى</translation>
<translation id="2922350208395188000">لا يمكن التحقق من شهادة الخادم.</translation>
+<translation id="2925673989565098301">طريقة التسليم</translation>
<translation id="2928905813689894207">عنوان إرسال الفواتير</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> وعنوان <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> آخر}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> وعنوانان (<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />) آخران}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عناوين أخرى}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عنوانًا آخر}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> عنوان آخر}}</translation>
<translation id="2941952326391522266">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان من <ph name="DOMAIN2" />. وربما سبب ذلك خطأ في التكوين أو مهاجمًا يعترض اتصالك.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">نوع السياسة غير صحيح</translation>
<translation id="3032412215588512954">هل تريد إعادة تحميل هذا الموقع؟</translation>
<translation id="3037605927509011580">عذرًا!</translation>
+<translation id="3039538478787849737">‏هل تريد حفظ البطاقة في Google؟</translation>
<translation id="3041612393474885105">معلومات الشهادة</translation>
<translation id="3063697135517575841">‏لم يتمكن Chrome من التأكد من بطاقتك في الوقت الحالي. يُرجى إعادة المحاولة في وقت لاحق.</translation>
<translation id="3064966200440839136">ستتم مغادرة وضع التصفح المتخفي للدفع عبر تطبيق خارجي. هل تريد المتابعة؟</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">خطأ مؤقت في الخادم</translation>
<translation id="3154506275960390542">تتضمّن هذه الصفحة نموذجًا قد لا يتم إرساله بصورة آمنة، ويستطيع الآخرون مشاهدة البيانات التي ترسلها أثناء نقلها، كما يستطيع أي مهاجم تعديلها لتغيير ما يتلقاه الخادم.</translation>
<translation id="3157931365184549694">استعادة</translation>
+<translation id="3162559335345991374">‏قد يتطلب Wi-Fi الذي تستخدمه زيارة صفحة تسجيل الدخول.</translation>
<translation id="3167968892399408617">لن يتم تسجيل الصفحات التي تعرضها في علامات تبويب التصفح المتخفي في سجل المتصفح أو مخزن ملفات تعريف الارتباط أو سجل البحث بعد إغلاق جميع علامات التبويب في وضع التصفح المتخفي. ولكن سيتم الاحتفاظ بأي ملفات تنزلها أو إشارات مرجعية تنشئها.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">جزيرة</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">إلغاء الدفع</translation>
<translation id="3207960819495026254">محدد بعلامة متابعة القراءة</translation>
+<translation id="3211223744486044430">‏للدفع على نحو أسرع في المرة القادمة، احفظ هذه البطاقة في حسابك في Google وفي هذا الجهاز.</translation>
<translation id="3225919329040284222">قدم الخادم شهادة لا تتطابق مع التوقعات المضمّنة. تم تضمين هذه التوقعات للحصول على مواقع ويب موثوقة وآمنة جدًا لتوفير الحماية لك.</translation>
<translation id="3226128629678568754">اضغط على زر إعادة التحميل لإعادة إرسال البيانات المطلوبة لتحميل الصفحة.</translation>
<translation id="3227137524299004712">الميكروفون</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">لم يتم العثور على أي نتائج بحث</translation>
<translation id="3305707030755673451">تم تشفير بياناتك باستخدام عبارة مرور المزامنة في <ph name="TIME" />. أدخلها لبدء المزامنة.</translation>
<translation id="3320021301628644560">إضافة عنوان إرسال الفواتير</translation>
-<translation id="3329013043687509092">تشبع اللون</translation>
<translation id="333371639341676808">منع هذه الصفحة من إنشاء مربّعات حوار إضافية.</translation>
<translation id="3338095232262050444">آمن</translation>
<translation id="3340978935015468852">الإعدادات</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">معرِّف العميل:</translation>
<translation id="3391030046425686457">عنوان التسليم</translation>
<translation id="3395827396354264108">طريقة الاستلام</translation>
+<translation id="3399952811970034796">عنوان التسليم</translation>
<translation id="3422248202833853650">جرّب الخروج من البرامج الأخرى لتفريغ مساحة من الذاكرة.</translation>
<translation id="3422472998109090673">يتعذر الوصول إلى <ph name="HOST_NAME" /> حاليًا.</translation>
<translation id="3427092606871434483">السماح (افتراضي)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">تم تسجيل تقرير الأعطال في <ph name="CRASH_TIME" />، وتم تحميله في <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">معلومات الشهادة</translation>
<translation id="3690164694835360974">عملية تسجيل الدخول غير آمنة</translation>
+<translation id="3704162925118123524">قد تتطلب الشبكة التي تستخدمها زيارة صفحة تسجيل الدخول.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">جارٍ التحميل...</translation>
<translation id="3712624925041724820">التراخيص مستنفذة</translation>
<translation id="3714780639079136834">‏تشغيل بيانات شبكة الجوّال أو Wi-Fi</translation>
+<translation id="3715597595485130451">‏الاتصال بـ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />التحقق من تهيئة الخادم الوكيل والجدار الناري ونظام أسماء النطاقات<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">إذا كنت على دراية بالمخاطر على أمنك، يمكنك <ph name="BEGIN_LINK" />زيارة هذا الموقع غير الآمن<ph name="END_LINK" /> قبل أن تتم إزالة البرامج الخطيرة.</translation>
<translation id="3739623965217189342">الرابط الذي نسخته</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">تراجع عن الإ&amp;ضافة</translation>
<translation id="404928562651467259">تحذير</translation>
<translation id="4058922952496707368">المفتاح "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">إضافة عنوان صالح</translation>
<translation id="4072486802667267160">حدث خطأ أثناء معالجة طلبك. يُرجى إعادة المحاولة.</translation>
<translation id="4075732493274867456">لا يدعم كل من العميل والخادم مجموعة تشفير أو إصدار بروتوكول طبقة المقابس الآمنة الشائع.</translation>
<translation id="4079302484614802869">‏تم تعيين تهيئة الخادم الوكيل لاستخدام عنوان URL نص برمجي ‎.pac وليس الخوادم الوكيلة الثابتة.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">الرقم التسلسلي للجهاز غير صالح</translation>
<translation id="410351446219883937">تشغيل تلقائي</translation>
<translation id="4103763322291513355">‏انتقل إلى &lt;strong&gt;chrome://policy&lt;/strong&gt; لمشاهدة قائمة بعناوين URL المضافة إلى القائمة السوداء والسياسات الأخرى التي فرضها مشرف النظام.</translation>
-<translation id="4115378294792113321">أرجواني</translation>
<translation id="4116663294526079822">إلغاء الحظر دومًا على هذا الموقع</translation>
<translation id="4117700440116928470">نطاق السياسة غير متوافق.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{عنصر واحد آخر}zero{# عنصر آخر}two{عنصران آخران (#)}few{# عناصر أخرى}many{# عنصرًا آخر}other{# عنصر آخر}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">لقد حاولت الوصول إلى <ph name="DOMAIN" />، ولكن جهة إصدار الشهادة التي قدمها الخادم قد أبطلت الشهادة. وهذا يعني أن بيانات اعتماد الأمان التي قدمها الخادم يجب عدم الوثوق بها مطلقًا. فقد تكون على اتصال بأحد المهاجمين.</translation>
<translation id="4394049700291259645">تعطيل</translation>
<translation id="4406896451731180161">نتائج البحث</translation>
+<translation id="4415426530740016218">عنوان الاستلام</translation>
<translation id="4424024547088906515">‏هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان غير موثوقة من قبل Chrome. وربما يكون السبب في ذلك خطأ في التكوين أو مهاجمًا يعترض الاتصال.</translation>
<translation id="4432688616882109544">لم يقبل <ph name="HOST_NAME" /> شهادة تسجيل الدخول أو من المحتمل ألا يكون قد تم تقديم واحدة.</translation>
<translation id="443673843213245140">تم تعطيل استخدام الخادم الوكيل ولكن تم تحديد تهيئة صريحة للخادم الوكيل.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">الفلاش</translation>
<translation id="4558551763791394412">جرّب تعطيل الإضافات.</translation>
<translation id="457875822857220463">التسليم</translation>
+<translation id="4582800630050655161">‏من الممكن أن تفقد إمكانية الوصول إلى حسابك في Google أو تتعرض لسرقة هويتك. لذا يوصي Chromium بتغيير كلمة مرورك الآن.</translation>
<translation id="4587425331216688090">‏هل تريد إزالة العنوان من Chrome؟</translation>
<translation id="4592951414987517459">يتم ترميز اتصالك بالنطاق <ph name="DOMAIN" /> باستخدام مجموعة تشفير حديثة.</translation>
<translation id="4594403342090139922">تراجع عن الحذ&amp;ف</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">،</translation>
<translation id="467662567472608290">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان تحتوي على أخطاء. وربما يكون السبب في ذلك خطأ في التكوين أو مهاجمًا يعترض اتصالك.</translation>
<translation id="4690462567478992370">التوقف عن استخدام شهادة غير صالحة</translation>
+<translation id="4690954380545377795">‏من الممكن أن تفقد إمكانية الوصول إلى حسابك في Google أو تتعرض لسرقة هويتك. لذا يوصي Chrome بتغيير كلمة مرورك الآن.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" />‏ <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">تم قطع اتصالك</translation>
<translation id="471880041731876836">ليس لديك إذن لزيارة هذا الموقع</translation>
<translation id="4722547256916164131">‏<ph name="BEGIN_LINK" />تشغيل بيانات تشخيص شبكة Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">دفعتك</translation>
<translation id="4726672564094551039">إعادة تحميل السياسات</translation>
<translation id="4728558894243024398">النظام الأساسي</translation>
<translation id="4736825316280949806">‏إعادة تشغيل Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">التخزين المساعد في حالة سيئة</translation>
<translation id="5023310440958281426">التحقق من سياسات المشرف</translation>
<translation id="5029568752722684782">محو النسخة</translation>
+<translation id="503069730517007720">يلزم شهادة جذر لـ "<ph name="SOFTWARE_NAME" />" ولكن لم يتم تثبيتها. ينبغي على مشرف تقنية المعلومات أن يلقي نظرة على تعليمات التهيئة لـ "<ph name="SOFTWARE_NAME" />" لإصلاح تلك المشكلة. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">‏معلومات عن الترجمة من Google</translation>
<translation id="5039804452771397117">سماح</translation>
<translation id="5040262127954254034">الخصوصية</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">التجارب</translation>
<translation id="5205222826937269299">الاسم مطلوب</translation>
<translation id="5222812217790122047">البريد الإلكتروني مطلوب</translation>
+<translation id="522700295135997067">من المحتمل أن يكون موقع الويب هذا قد سرق كلمة مرورك للتو</translation>
+<translation id="5230733896359313003">عنوان الشحن</translation>
<translation id="5251803541071282808">السحاب</translation>
<translation id="5277279256032773186">‏هل تستخدم Chrome في العمل؟ يمكن للأنشطة التجارية إدارة إعدادات Chrome لموظفيها. تعرَّف على المزيد</translation>
<translation id="5281113152797308730">‏<ph name="BEGIN_PARAGRAPH" />اتبع هذه الخطوات لتعطيل البرامج مؤقتًا حتى يتسنى لك الوصول إلى الويب. سيلزمك الحصول على امتيازات المشرف.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">‏اتصالك بهذا الموقع ليس له خصوصية. للخروج من وضع الواقع الافتراضي (VR) في أي وقت، أزل سماعة الرأس واضغط على رجوع.</translation>
<translation id="5299298092464848405">خطأ في تحليل السياسة</translation>
+<translation id="5308380583665731573">اتصال</translation>
<translation id="5308689395849655368">ميزة الإبلاغ عن الأعطال معطلة.</translation>
<translation id="5317780077021120954">حفظ</translation>
<translation id="5327248766486351172">الاسم</translation>
+<translation id="5332219387342487447">طريقة الشحن</translation>
<translation id="5355557959165512791">لا يمكنك زيارة <ph name="SITE" /> الآن لأنه تم إبطال شهادته. أخطاء الشبكة والهجمات عليها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصفحة في وقت على الأرجح.</translation>
<translation id="536296301121032821">تعذّر تخزين إعدادات السياسة</translation>
<translation id="5386426401304769735">‏تتضمن سلسلة الشهادات لهذا الموقع شهادة موقعة باستخدام SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">‏يكون لموقع الويب هذا على الشبكة الداخلية للشركة أو المؤسسة أو المدرسة نفس عنوان URL لأحد مواقع الويب الخارجية.
<ph name="LINE_BREAK" />
حاول الاتصال بمشرف النظام.</translation>
+<translation id="5499929369096410817">أدخل رمز الأمان لبطاقة <ph name="CREDIT_CARD" />. لن يتم حفظ هذا الرمز.</translation>
<translation id="5509780412636533143">الإشارات المرجعية المُدارة</translation>
<translation id="5510766032865166053">ربما يكون تم نقله أو حذفه.</translation>
<translation id="5523118979700054094">اسم السياسة</translation>
<translation id="552553974213252141">هل تم استخراج النص بشكل صحيح؟</translation>
<translation id="5540224163453853">تعذر العثور على المقالة المطلوبة</translation>
+<translation id="5541546772353173584">إضافة البريد الإلكتروني</translation>
<translation id="5544037170328430102">صفحة مُضمنة في <ph name="SITE" /> تعرض:</translation>
+<translation id="5545756402275714221">مقالات لك</translation>
<translation id="5556459405103347317">إعادة تحميل</translation>
<translation id="5560088892362098740">تاريخ انتهاء الصلاحية</translation>
<translation id="5565735124758917034">نشط</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">البريد الإلكتروني</translation>
<translation id="5669703222995421982">الحصول على محتوى مخصص</translation>
<translation id="5675650730144413517">يتعذّر على هذه الصفحة العمل</translation>
+<translation id="5689199277474810259">‏تصدير إلى JSON</translation>
<translation id="5710435578057952990">لم يتمّ التحقق من هوية هذا الموقع.</translation>
<translation id="5719499550583120431">يتم قبول بطاقات الدفع المسبق.</translation>
<translation id="5720705177508910913">المستخدم الحالي</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">يتم ترميز اتصالك بالنطاق <ph name="DOMAIN" /> باستخدام مجموعة تشفير قديمة.</translation>
<translation id="5813119285467412249">إعا&amp;دة الإضافة</translation>
<translation id="5838278095973806738">يجب عدم إدخال معلومات حسّاسة على هذا الموقع (على سبيل المثال، كلمات المرور أو بطاقات الائتمان)، نظرًا لأنه قد تتم سرقتها من قِبل المهاجمين.</translation>
+<translation id="5866257070973731571">إضافة رقم الهاتف</translation>
<translation id="5869405914158311789">لا يمكن الوصول إلى موقع الويب هذا</translation>
<translation id="5869522115854928033">كلمات المرور المحفوظة</translation>
<translation id="5872918882028971132">اقتراحات الآباء</translation>
<translation id="5893752035575986141">يتم قبول بطاقات الائتمان.</translation>
-<translation id="5901630391730855834">أصفر</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (تمت المزامنة)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 قيد الاستخدام}zero{# قيد الاستخدام}two{# قيد الاستخدام}few{# قيد الاستخدام}many{# قيد الاستخدام}other{# قيد الاستخدام}}</translation>
<translation id="5959728338436674663">‏يمكنك إرسال بعض <ph name="BEGIN_WHITEPAPER_LINK" />معلومات النظام ومحتوى الصفحة<ph name="END_WHITEPAPER_LINK" /> إلى Google تلقائيًا للمساعدة في اكتشاف التطبيقات والمواقع الضارة. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">تعديل معلومات الاتصال</translation>
<translation id="5967867314010545767">إزالة من السجل</translation>
<translation id="5975083100439434680">تصغير</translation>
+<translation id="597552863672748783">تأكيد رمز الأمان</translation>
<translation id="598637245381783098">لا يمكن فتح تطبيق الدفع</translation>
<translation id="5989320800837274978">‏لم يتم تحديد أي من الخوادم الوكيلة الثابتة ولا عنوان URL للنص البرمجي pac.</translation>
<translation id="5990559369517809815">تم حظر الطلبات المقدمة إلى الخادم بواسطة إحدى الإضافات.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{صفحة 1}zero{صفحة #}two{صفحة #}few{صفحة #}many{صفحة #}other{صفحة #}}</translation>
-<translation id="6017514345406065928">أخضر</translation>
<translation id="6017850046339264347">يمكن للمهاجمين على <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="6025416945513303461"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /> (تمت المزامنة)</translation>
<translation id="6027201098523975773">أدخِل اسمًا</translation>
<translation id="6040143037577758943">إغلاق</translation>
-<translation id="6042308850641462728">المزيد</translation>
<translation id="6047233362582046994">إذا كنت على دراية بالمخاطر التي تهدد أمانك، يمكنك <ph name="BEGIN_LINK" />زيارة موقع الويب هذا<ph name="END_LINK" /> قبل أن تتم إزالة التطبيقات الضارة.</translation>
<translation id="6047927260846328439">قد يحاول هذا المحتوى خداعك لتثبيت برامج أو الكشف عن معلومات شخصية. <ph name="BEGIN_LINK" />عرض على أي حال<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">لا يمكنك زيارة <ph name="SITE" /> في الوقت الحالي لأن الموقع يستخدم أداة التحقق من صحة الشهادات. أخطاء الشبكة والهجمات عليها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصفحة في وقت لاحق على الأرجح.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">أنت تعرض صفحة إضافة</translation>
<translation id="6596325263575161958">خيارات التشفير</translation>
<translation id="662080504995468778">البقاء</translation>
+<translation id="6624427990725312378">معلومات الاتصال</translation>
<translation id="6626291197371920147">إضافة رقم بطاقة صالح</translation>
<translation id="6628463337424475685">بحث <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">‏قد يحاول المهاجمون حاليًا على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت برامج خطيرة على جهاز Mac تؤدي إلى سرقة أو حذف معلوماتك (على سبيل المثال، الصور، وكلمات المرور، والرسائل، وبطاقات الائتمان) <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">السابق</translation>
<translation id="6710594484020273272">&lt;إدخال عبارة البحث&gt;</translation>
<translation id="6711464428925977395">هناك خطأ ما في الخادم الوكيل، أو العنوان غير صحيح.</translation>
-<translation id="6727102863431372879">تعيين</translation>
<translation id="674375294223700098">حدث خطأ غير معروف في شهادة الخادم.</translation>
<translation id="6753269504797312559">قيمة السياسة</translation>
<translation id="6757797048963528358">خضع جهازك إلى وضع السكون.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">‏عنوان URL</translation>
<translation id="7419106976560586862">مسار الملف الشخصي</translation>
<translation id="7424977062513257142">صفحة مُضمنة في صفحة الويب هذه تعرض:</translation>
+<translation id="7437289804838430631">إضافة معلومات الاتصال</translation>
<translation id="7441627299479586546">موضوع السياسة غير صحيح</translation>
<translation id="7444046173054089907">تم حظر هذا الموقع</translation>
<translation id="7445762425076701745">لا يمكن التحقق بصورة كاملة من صحة هوية الخادم الذي تتصل به. فأنت متصل بخادم باستخدام اسم صالح فقط ضمن شبكتك، والذي لن يتمكن المرجع المصدق الخارجي من التحقق من ملكيته. وحيث إن بعض المراجع المصدقة تُصدر الشهادات لهذه الأسماء على أي حال، فليست هناك طريقة للتأكد من أنك متصل بموقع الويب المقصود وليس بأحد المهاجمين.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">إلى الأمام</translation>
<translation id="7485870689360869515">لم يتم العثور على بيانات.</translation>
<translation id="7508255263130623398">رقم تعريف الجهاز المعروض للسياسة فارغ أو لا يتطابق مع رقم تعريف الجهاز الحالي</translation>
+<translation id="7511955381719512146">‏قد يتتطلب Wi-Fi الذي تستخدمه زيارة <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">تنزيل</translation>
<translation id="7518003948725431193">لم يتم العثور على أي صفحة ويب لعنوان الويب:<ph name="URL" /></translation>
<translation id="7521387064766892559">جافا سكريبت</translation>
<translation id="7526934274050461096">اتصالك بموقع الويب هذا لا يتمتع بخصوصية</translation>
-<translation id="7535087603100972091">القيمة</translation>
<translation id="7537536606612762813">إلزامية</translation>
<translation id="7542403920425041731">بعد تأكيدك، ستتم مشاركة تفاصيل بطاقتك مع موقع الويب هذا.</translation>
<translation id="7542995811387359312">تم تعطيل الملء التلقائي لبطاقة الائتمان لأن هذا النموذج لا يستخدم اتصالاً آمنًا.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان تم إصدارها عن طريق الاحتيال. وربما يكون سبب ذلك خطأ في التكوين أو مهاجمًا يعترض اتصالك.</translation>
<translation id="7568593326407688803">تتوفر هذه الصفحة باللغة<ph name="ORIGINAL_LANGUAGE" />فهل تريد ترجمتها؟</translation>
<translation id="7569952961197462199">‏هل تريد إزالة بطاقة الائتمان من Chrome؟</translation>
-<translation id="7569983096843329377">أسود</translation>
<translation id="7578104083680115302">‏الدفع سريعًا على المواقع والتطبيقات عبر الأجهزة باستخدام البطاقات التي حفظتها في Google.</translation>
<translation id="7588950540487816470">الشبكة المادية</translation>
<translation id="7592362899630581445">تنتهك شهادة الخادم القيود المفروضة على الاسم.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">قد يحاول المهاجمون في هذا الموقع خداعك من خلال تثبيت برامج تضر بتجربة التصفح (على سبيل المثال، من خلال تغيير صفحتك الرئيسية أو عرض إعلانات إضافية على المواقع التي تزورها).</translation>
<translation id="7674629440242451245">‏إذا كنت مهتمًا بميزات Google الجديدة والرائعة، فيُمكنك تجربة قناة مطوري البرامج على chrome.com/dev.</translation>
<translation id="7682287625158474539">الشحن</translation>
+<translation id="7699293099605015246">المقالات غير متاحة الآن</translation>
<translation id="7701040980221191251">بلا</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />متابعة إلى <ph name="SITE" /> (غير آمن)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">شهادة</translation>
<translation id="7716147886133743102">تم الحظر من قبل المشرف</translation>
<translation id="7716424297397655342">لا يمكن تحميل موقع الويب هذا من ذاكرة التخزين المؤقت</translation>
+<translation id="7723047071702270851">تعديل البطاقة</translation>
<translation id="774634243536837715">تم حظر المحتوى الخطير.</translation>
<translation id="7752995774971033316">غير مُدار</translation>
<translation id="7755287808199759310">قد يلغي والداك الحظر لك</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">إضافة عنوان</translation>
<translation id="777702478322588152">الإدارة الأمنية</translation>
<translation id="7791543448312431591">إضافة</translation>
+<translation id="7793553086574152071">‏للدفع على نحو أسرع في المرة القادمة، احفظ هذه البطاقة في حسابك في Google.</translation>
<translation id="7793809570500803535">قد تكون صفحة الويب على العنوان <ph name="SITE" /> غير متاحة مؤقتًا أو تم نقلها نهائيًا إلى عنوان ويب جديد.</translation>
<translation id="7800304661137206267">تم تشفير الاتصال باستخدام <ph name="CIPHER" />، مع <ph name="MAC" /> لمصادقة الرسالة و<ph name="KX" /> كآلية التبادل الرئيسية.</translation>
+<translation id="7802523362929240268">موقع الويب مشروع</translation>
<translation id="780301667611848630">لا، شكرًا</translation>
<translation id="7805768142964895445">الحالة</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">‏هل تريد إزالة اقتراح النموذج من Chrome؟</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="785549533363645510">ومع ذلك، أنت غير مرئي. لا يخفي الانتقال إلى وضع التخفي التصفح من صاحب العمل أو مزود خدمة الإنترنت أو المواقع التي تزورها.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">يتم قبول بطاقات السحب الآلي وبطاقات الدفع المسبق.</translation>
+<translation id="7878562273885520351">من المحتمل أنه تم اختراق كلمة مرورك</translation>
<translation id="7887683347370398519">‏تحقق من رمز التحقق من البطاقة (CVC) ثم أعد المحاولة.</translation>
<translation id="79338296614623784">أدخِل رقم هاتف صحيحًا</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">شهادة الخادم ليست صالحة بعد.</translation>
-<translation id="7942349550061667556">أحمر</translation>
<translation id="7947285636476623132">تحقق من عام انتهاء الصلاحية وأعِد المحاولة مرة أخرى</translation>
<translation id="7951415247503192394">(32 بت)</translation>
<translation id="7956713633345437162">الإشارات المرجعية على الجوال</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">الطلب (افتراضي)</translation>
<translation id="8041089156583427627">إرسال تعليقات</translation>
<translation id="8041940743680923270">استخدام الإعداد الافتراضي العمومي (طلب)</translation>
+<translation id="8057711352706143257">لم تتم تهيئة "<ph name="SOFTWARE_NAME" />" بشكل صحيح. يؤدي عادةً إلغاء تثبيت "<ph name="SOFTWARE_NAME" />" إلى إصلاح المشكلة. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">تعذّر عرض المقالة.</translation>
<translation id="8091372947890762290">التنشيط قيد الانتظار في الخادم</translation>
+<translation id="8094917007353911263">قد تتطلب الشبكة التي تستخدمها زيارة <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">طريقة الدفع</translation>
<translation id="8118489163946903409">طريقة الدفع</translation>
+<translation id="8127301229239896662">لم يتم تثبيت "<ph name="SOFTWARE_NAME" />" بطريقة صحيحة على جهاز الكمبيوتر أو الشبكة. اطلب من مشرف تقنية المعلومات حل هذه المشكلة.</translation>
<translation id="8131740175452115882">التأكيد</translation>
<translation id="8134994873729925007">تعذر العثور على <ph name="BEGIN_ABBR" />عنوان نظام أسماء النطاقات<ph name="END_ABBR" /> للخادم <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">خضع جهاز الكمبيوتر إلى وضع السكون.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">اتصل بمشرف الشبكة إذا لم تكن متأكدًا مما يعنيه هذا.</translation>
<translation id="8293206222192510085">إضافة إشارة مرجعية</translation>
<translation id="8294431847097064396">المصدر</translation>
+<translation id="8298115750975731693">‏قد يتتطلب Wi-Fi الذي تستخدمه (<ph name="WIFI_NAME" />) زيارة <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن تاريخ ووقت جهازك (<ph name="DATE_AND_TIME" />) غير صحيحين. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">أخفقت الترجمة بسبب حدوث مشكلة في الاتصال بالشبكة.</translation>
<translation id="8332188693563227489">تم رفض الدخول إلى <ph name="HOST_NAME" />.</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">العناصر المغلقة مؤخرًا</translation>
<translation id="8874824191258364635">أدخِل رقم بطاقة صحيحًا</translation>
<translation id="8876793034577346603">تعذّر تحليل تهيئة الشبكة</translation>
-<translation id="8889402386540077796">تدرج اللون</translation>
<translation id="8891727572606052622">وضع الخادم الوكيل غير صالح.</translation>
<translation id="889901481107108152">عذرًا، هذه التجربة غير متاحة على نظامك الأساسي.</translation>
<translation id="8903921497873541725">تكبير</translation>
<translation id="8931333241327730545">‏هل تريد حفظ هذه البطاقة إلى حسابك في Google؟</translation>
<translation id="8932102934695377596">توقيت ساعتك متأخر عن الوقت الحالي</translation>
+<translation id="893332455753468063">إضافة اسم</translation>
<translation id="8938939909778640821">بطاقات الائتمان وبطاقات الدفع المسبق المقبولة</translation>
+<translation id="8957210676456822347">تفويض المدخل المقيد</translation>
<translation id="8971063699422889582">انتهت صلاحية شهادة الخادم.</translation>
-<translation id="8986494364107987395">‏إرسال إحصائيات الاستخدام وتقارير الأعطال إلى Google تلقائيًا</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" />‏ [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">تحتوي مقدمة الموقع على برامج ضارة</translation>
<translation id="8997023839087525404">قدم الخادم شهادة لم يتم الكشف عنها علنًا باستخدام سياسة شهادة الشفافية. وهذا ضروري لبعض الشهادات، لضمان أنها جديرة بالثقة ومحمية من المهاجمين.</translation>
<translation id="9001074447101275817">يتطلب الخادم الوكيل <ph name="DOMAIN" /> اسم مستخدم وكلمة مرور.</translation>
<translation id="9005998258318286617">‏فشل تحميل مستند PDF.</translation>
+<translation id="9008201768610948239">تجاهل</translation>
<translation id="901974403500617787">لا يمكن تعيين العلامات التي تسري عبر النظام إلا من قِبل المالك: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">عنوان إرسال الفواتير للبطاقة مطلوب</translation>
<translation id="9020542370529661692">تمت ترجمة هذه الصفحة إلى <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">لقد حاولت الوصول إلى <ph name="DOMAIN" />, ولكن الخادم قدّم شهادة غير صالحة.</translation>
<translation id="9050666287014529139">عبارة المرور</translation>
<translation id="9065203028668620118">تحرير</translation>
-<translation id="9068849894565669697">اختيار اللون</translation>
<translation id="9069693763241529744">تم الحظر بواسطة إحدى الإضافات</translation>
<translation id="9076283476770535406">قد يتضمن محتوى للبالغين</translation>
<translation id="9078964945751709336">مطلوب مزيد من المعلومات</translation>
+<translation id="9080712759204168376">ملخص الطلبات</translation>
<translation id="9103872766612412690">‏يستخدم <ph name="SITE" /> التشفير عادة لحماية معلوماتك. عندما حاول Chromium الاتصال بموقع <ph name="SITE" /> هذه المرة، أرجَع موقع الويب بيانات اعتماد غير عادية وغير صحيحة. وقد يحدث هذا عندما يحاول أحد المهاجمين التظاهر بأنه موقع <ph name="SITE" />، أو إذا قاطعت شاشة تسجيل دخول Wi-Fi الاتصال. ولكن لا تزال معلوماتك آمنة نظرًا لأن Chromium أوقَفَ الاتصال قبل تبادل أي بيانات.</translation>
+<translation id="9106062320799175032">إضافة عنوان إرسال الفواتير</translation>
+<translation id="910908805481542201">ساعدني لإصلاح ذلك</translation>
+<translation id="9128870381267983090">الاتصال بالشبكة</translation>
<translation id="9137013805542155359">إظهار الصفحة الأصلية</translation>
<translation id="9137248913990643158">‏يُرجى البدء وتسجيل الدخول إلى Chrome قبل استخدام هذا التطبيق.</translation>
<translation id="9148507642005240123">تراجع عن ا&amp;لتحرير</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419">يستخدم <ph name="HOST_NAME" /> بروتوكول غير مدعوم.</translation>
<translation id="9205078245616868884">يتم تشفير بياناتك باستخدام عبارة مرور المزامنة. أدخلها لبدء المزامنة.</translation>
<translation id="9207861905230894330">أخفقت إضافة مقالة.</translation>
+<translation id="9215416866750762878">‏يعمل أحد التطبيقات على منع اتصال Chrome بموقع الويب هذا على نحو آمن</translation>
<translation id="9219103736887031265">صور</translation>
<translation id="933612690413056017">لا يوجد اتصال بالإنترنت</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{بدون}=1{عنصر واحد}two{عنصران (#)}few{# عناصر}many{# عنصرًا}other{# عنصر}}</translation>
<translation id="981121421437150478">بلا اتصال</translation>
<translation id="988159990683914416">بنية المطوِّر</translation>
+<translation id="989988560359834682">تعديل العنوان</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">‏لم يتم تثبيت "<ph name="SOFTWARE_NAME" />" بطريقة صحيحة على جهاز الكمبيوتر أو الشبكة:
+ &lt;ul&gt;
+ &lt;li&gt;حاوِل إلغاء تثبيت "<ph name="SOFTWARE_NAME" />" أو تعطيل&lt;/li&gt;
+ &lt;li&gt;حاوِل الاتصال بشبكة أخرى&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index c8b2f8f687a..f2345009109 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Настолни отметки</translation>
<translation id="1074497978438210769">Няма защита</translation>
<translation id="1080116354587839789">Побиране на ширина</translation>
+<translation id="1088860948719068836">Добавяне на името на картодържателя</translation>
<translation id="1103523840287552314">Винаги да се превежда от <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Показване на всички запазени пароли...</translation>
<translation id="1107591249535594099">Ако поставите отметка, Chrome ще съхранява копие на картата ви на това устройство с цел по-бързо попълване на формуляри.</translation>
<translation id="1111153019813902504">Скорошни отметки</translation>
<translation id="1113869188872983271">&amp;Отмяна на пренареждането</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (синхронизирани)</translation>
<translation id="1263231323834454256">Списък за четене</translation>
<translation id="1264126396475825575">Сигнал за срив, записан в/ъв <ph name="CRASH_TIME" /> (още не е качен или пренебрегнат)</translation>
+<translation id="1270502636509132238">Начин на вземане</translation>
<translation id="1281526147609854549">Издадено от <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Този сайт да не се превежда никога</translation>
<translation id="129553762522093515">Наскоро затворени</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Изчаква се връзка…</translation>
<translation id="153384715582417236">Това е всичко засега</translation>
<translation id="1549470594296187301">Трябва да активирате JavaScript, за да използвате тази функция.</translation>
-<translation id="1555130319947370107">синьо</translation>
<translation id="1559528461873125649">Няма такъв файл или директория</translation>
<translation id="1583429793053364125">Възникна проблем при показването на тази уеб страница.</translation>
<translation id="1592005682883173041">Достъп до локални данни</translation>
<translation id="1594030484168838125">Избор</translation>
-<translation id="161042844686301425">синьозелено</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1629803312968146339">Искате ли Chrome да запази тази карта?</translation>
<translation id="1639239467298939599">Зарежда се</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Необходимо ви е разрешение от <ph name="NAME" />, за да посетите този сайт</translation>
<translation id="1721424275792716183">* Полето е задължително</translation>
+<translation id="1727741090716970331">Добавяне на валиден номер на карта</translation>
<translation id="1728677426644403582">Преглеждате изходния код на уеб страница</translation>
<translation id="173080396488393970">Този тип карта не се поддържа</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Грешка при сериализирането</translation>
<translation id="1974060860693918893">Разширени</translation>
<translation id="1978555033938440688">Версия на фърмуера</translation>
-<translation id="1995859865337580572">Моля, потвърдете кода си за проверка</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{и още 1}other{и още #}}</translation>
<translation id="2025186561304664664">За прокси сървъра е зададена автоматична конфигурация.</translation>
<translation id="2030481566774242610">Може би имахте предвид <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Отмяна</translation>
<translation id="20817612488360358">За използване са зададени системни настройки за прокси сървъра, но е посочена и изрична конфигурация.</translation>
<translation id="2086652334978798447">За да получавате персонализирано съдържание, предлагано от Google, влезте в Chrome.</translation>
+<translation id="2091887806945687916">Звук</translation>
<translation id="2094505752054353250">Несъответствие в домейна</translation>
<translation id="2096368010154057602">Департамент</translation>
<translation id="2108755909498034140">Рестартирайте компютъра си.</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Бе пренебрегнато, защото бе отменено от <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Търсят се намиращи се в близост страници във Физическата мрежа</translation>
<translation id="213826338245044447">Мобилни отметки</translation>
+<translation id="214556005048008348">Анулиране на плащането</translation>
<translation id="2147827593068025794">Синхронизиране на заден план</translation>
+<translation id="2148613324460538318">Добавяне на карта</translation>
<translation id="2154054054215849342">Синхронизирането не е налице за въведения от вас домейн</translation>
<translation id="2154484045852737596">Редактиране на картата</translation>
<translation id="2166049586286450108">Пълен администраторски достъп</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 адрес}other{# адреса}}</translation>
<translation id="2187317261103489799">Откриване (по подразбиране)</translation>
<translation id="2202020181578195191">Въведете валидна година на изтичане</translation>
+<translation id="2209523182407020534">Тази грешка може да се дължи например на антивирусна програма, защитна стена, прокси сървър или софтуер за филтриране в мрежата.</translation>
<translation id="2212735316055980242">Правилото не е намерено</translation>
<translation id="2213606439339815911">Записите се извличат...</translation>
<translation id="2218879909401188352">Понастоящем извършители на атака срещу <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могат да инсталират опасни приложения, които да повредят устройството ви, да добавят скрити такси към сметката ви за мобилни услуги или да откраднат личната ви информация. <ph name="BEGIN_LEARN_MORE_LINK" />Научете повече<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Назад</translation>
<translation id="2503184589641749290">Приемани дебитни и предплатени карти</translation>
<translation id="2515629240566999685">Проверете сигнала в района.</translation>
+<translation id="2524461107774643265">Добавяне на още информация</translation>
+<translation id="2536110899380797252">Добавяне на адрес</translation>
<translation id="2539524384386349900">Откриване</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> изпрати невалиден отговор.</translation>
<translation id="2556876185419854533">&amp;Отмяна на редактирането</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium не можа да потвърди картата ви. Моля, опитайте отново по-късно.</translation>
<translation id="2705137772291741111">Запазеното (кеширано) копие на този сайт не можа да се прочете.</translation>
<translation id="2709516037105925701">Автоматично попълване</translation>
+<translation id="2710942282213947212">Софтуер на компютъра ви пречи на Chromium да се свърже безопасно с мрежата</translation>
<translation id="2712173769900027643">Искане на разрешение</translation>
-<translation id="2713444072780614174">бяло</translation>
<translation id="2720342946869265578">В близост</translation>
<translation id="2721148159707890343">Заявката е успешна</translation>
<translation id="2728127805433021124">Сертификатът на сървъра е подписан със слаб алгоритъм.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Установена бе промяна в мрежата.</translation>
<translation id="2916038427272391327">Затворете другите програми.</translation>
<translation id="2922350208395188000">Сертификатът на сървъра не може да бъде проверен.</translation>
+<translation id="2925673989565098301">Начин на бърза доставка</translation>
<translation id="2928905813689894207">Адрес за фактуриране</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; сертификатът му за сигурност е от <ph name="DOMAIN2" />. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Грешен тип на правилото</translation>
<translation id="3032412215588512954">Искате ли да презаредите този сайт?</translation>
<translation id="3037605927509011580">Ужас!</translation>
+<translation id="3039538478787849737">Картата да се запази ли в Google?</translation>
<translation id="3041612393474885105">Информация за сертификата</translation>
<translation id="3063697135517575841">Chrome не можа да потвърди картата ви. Моля, опитайте отново по-късно.</translation>
<translation id="3064966200440839136">Ще напуснете режим „инкогнито“, за да платите във външно приложение. Искате ли да продължите?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Временна грешка в сървъра</translation>
<translation id="3154506275960390542">Тази страница включва формуляр, който не може да се изпрати по сигурен начин. Данните, които изпращате, могат да бъдат преглеждани от други хора, докато се прехвърлят, или модифицирани от извършител на атака, така че да се промени това, което сървърът получава.</translation>
<translation id="3157931365184549694">Възстановяване</translation>
+<translation id="3162559335345991374">Използваната от вас Wi-Fi мрежа може да изисква да посетите страницата й за вход.</translation>
<translation id="3167968892399408617">Страниците, които преглеждате в разделите в режим „инкогнито“, няма да останат в историята на браузъра, хранилището за „бисквитки“ или историята на търсенето, след като затворите всички раздели в този режим. Изтеглените от вас файлове или създадените от вас отметки обаче ще бъдат запазени.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Остров</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Анулиране на плащането</translation>
<translation id="3207960819495026254">С отметка</translation>
+<translation id="3211223744486044430">За да платите по-бързо следващия път, запазете тази карта в профила си в Google и на устройството.</translation>
<translation id="3225919329040284222">Сървърът предостави сертификат, който не съответства на вградените очаквания. Те са включени за определени уебсайтове с голяма степен на сигурност, за да ви предпазим.</translation>
<translation id="3226128629678568754">Натиснете бутона за презареждане, за да изпратите отново данните, необходими за отварянето на страницата.</translation>
<translation id="3227137524299004712">Микрофон</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Няма намерени резултати от търсенето</translation>
<translation id="3305707030755673451">На <ph name="TIME" /> данните ви бяха шифровани с пропуска ви за синхронизиране. Въведете го, за да стартирате синхронизирането.</translation>
<translation id="3320021301628644560">Добавяне на адреса за фактуриране</translation>
-<translation id="3329013043687509092">Насищане</translation>
<translation id="333371639341676808">Да не се показват допълнителни диалогови прозорци от тази страница.</translation>
<translation id="3338095232262050444">Има защита</translation>
<translation id="3340978935015468852">настройки</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Идент. № на клиентската програма:</translation>
<translation id="3391030046425686457">Адрес за бърза доставка</translation>
<translation id="3395827396354264108">Начин на вземане</translation>
+<translation id="3399952811970034796">Адрес за бърза доставка</translation>
<translation id="3422248202833853650">Затворете другите програми, за да освободите памет.</translation>
<translation id="3422472998109090673">Понастоящем няма достъп до <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Разрешаване (по подразбиране)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Сигналът за срив е записан в/ъв <ph name="CRASH_TIME" /> и качен в/ъв <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Информация за сертификата</translation>
<translation id="3690164694835360974">Страницата за вход не е защитена</translation>
+<translation id="3704162925118123524">Използваната от вас мрежа може да изисква да посетите страницата й за вход.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> „<ph name="TITLE" />“ <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Зарежда се...</translation>
<translation id="3712624925041724820">Лицензите са изчерпани</translation>
<translation id="3714780639079136834">Включете мобилните данни или Wi-Fi.</translation>
+<translation id="3715597595485130451">Свързване с Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Проверете конфигурацията на прокси сървъра, защитната стена и DNS<ph name="END_LINK" />.</translation>
<translation id="3736520371357197498">Ако разбирате рисковете за сигурността си, може <ph name="BEGIN_LINK" />да посетите този ненадежден сайт<ph name="END_LINK" /> преди премахването на опасните програми.</translation>
<translation id="3739623965217189342">Копирана от вас връзка</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Отмяна на добавянето</translation>
<translation id="404928562651467259">ПРЕДУПРЕЖДЕНИЕ</translation>
<translation id="4058922952496707368">Ключ „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">Добавяне на валиден адрес</translation>
<translation id="4072486802667267160">При обработването на поръчката ви възникна грешка. Моля, опитайте отново.</translation>
<translation id="4075732493274867456">Клиентът и сървърът не поддържат обща версия или пакет за шифроване за протокола SSL.</translation>
<translation id="4079302484614802869">За конфигурацията на прокси сървъра е зададено да използва URL адрес на скрипт във формат .pac, а не фиксирани прокси сървъри.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Серийният номер на устройството е невалиден</translation>
<translation id="410351446219883937">Автоматично възпроизвеждане</translation>
<translation id="4103763322291513355">Посетете &lt;strong&gt;chrome://policy&lt;/strong&gt;, за да видите изброени URL адресите в черния списък и другите правила, наложени от системния ви администратор.</translation>
-<translation id="4115378294792113321">пурпурно</translation>
<translation id="4116663294526079822">Разрешаване винаги на този сайт</translation>
<translation id="4117700440116928470">Обхватът на правилата не се поддържа.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{още 1 елемент}other{още # елемента}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Направихте опит да се свържете с/ъс <ph name="DOMAIN" />, но сървърът предoстави сертификат, анулиран от издателя си. Това означава, че в никакъв случай не трябва да се доверявате на представените от сървъра идентификационни данни за сигурност. Възможно е да сте се свързали с извършител на атака.</translation>
<translation id="4394049700291259645">Деактивиране</translation>
<translation id="4406896451731180161">резултата от търсенето</translation>
+<translation id="4415426530740016218">Адрес за вземане</translation>
<translation id="4424024547088906515">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; Chrome няма доверие на сертификата му за сигурност. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> не прие сертификата ви за вход или е възможно да не е предоставен такъв.</translation>
<translation id="443673843213245140">Използването на прокси сървър е деактивирано, но е посочена изрична негова конфигурация.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Опитайте да деактивирате разширенията.</translation>
<translation id="457875822857220463">Бърза доставка</translation>
+<translation id="4582800630050655161">Възможно е да загубите достъп до профила си в Google или самоличността ви да бъде открадната. Chromium препоръчва да промените паролата си сега.</translation>
<translation id="4587425331216688090">Адресът да се премахне ли от Chrome?</translation>
<translation id="4592951414987517459">Връзката ви с/ъс <ph name="DOMAIN" /> е шифрована със съвременен криптографски пакет.</translation>
<translation id="4594403342090139922">&amp;Отмяна на изтриването</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; сертификатът му за сигурност съдържа грешки. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="4690462567478992370">Спиране на използването на невалиден сертификат</translation>
+<translation id="4690954380545377795">Възможно е да загубите достъп до профила си в Google или самоличността ви да бъде открадната. Chrome препоръчва да промените паролата си сега.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Връзката ви бе прекъсната</translation>
<translation id="471880041731876836">Нямате разрешение да посетите този сайт</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Стартирайте мрежова диагностика в Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Вашето плащане</translation>
<translation id="4726672564094551039">Презареждане на правилата</translation>
<translation id="4728558894243024398">Платформа</translation>
<translation id="4736825316280949806">Рестартирайте Chromium.</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Допълнителното хранилище е в лошо състояние</translation>
<translation id="5023310440958281426">Проверете правилата на администратора</translation>
<translation id="5029568752722684782">Изчистване на копието</translation>
+<translation id="503069730517007720">За <ph name="SOFTWARE_NAME" /> се изисква основен сертификат, но такъв не е инсталиран. Системният ви администратор трябва да прегледа инструкциите за конфигуриране на <ph name="SOFTWARE_NAME" />, за да отстрани проблема. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Всичко за Google Преводач</translation>
<translation id="5039804452771397117">Разрешаване</translation>
<translation id="5040262127954254034">Поверителност</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Експерименти</translation>
<translation id="5205222826937269299">Името е задължително</translation>
<translation id="5222812217790122047">Имейл адресът е задължителен</translation>
+<translation id="522700295135997067">Възможно е този сайт току-що да е откраднал паролата ви</translation>
+<translation id="5230733896359313003">Адрес за доставка</translation>
<translation id="5251803541071282808">Облак</translation>
<translation id="5277279256032773186">Използвате Chrome на работното си място? Бизнесите могат да управляват настройките на браузъра за служителите си. Научете повече</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Изпълнете следните стъпки, за да деактивирате временно софтуера, така че да можете да се свържете с мрежата. Ще са ви необходими администраторски права.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Връзката ви с този сайт не е частна. За да излезете от режима на VR, премахнете очилата и натиснете бутона за назад.</translation>
<translation id="5299298092464848405">Грешка при синтактичния анализ на правилото</translation>
+<translation id="5308380583665731573">Свързване</translation>
<translation id="5308689395849655368">Изпращането на сигнали за сривове е деактивирано.</translation>
<translation id="5317780077021120954">Запазване</translation>
<translation id="5327248766486351172">Име</translation>
+<translation id="5332219387342487447">Начин за доставка</translation>
<translation id="5355557959165512791">В момента не можете да посетите сайта <ph name="SITE" />, защото сертификатът му е анулиран. Обикновено грешките в мрежата и атаките срещу нея са временни, така че тази страница вероятно ще работи по-късно.</translation>
<translation id="536296301121032821">Съхраняването на настройките за правилото не бе успешно</translation>
<translation id="5386426401304769735">Веригата от сертификати за този сайт съдържа сертификат, подписан с SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Този интранет сайт на фирмата, организацията или училището има същия URL адрес като на външен уебсайт.
<ph name="LINE_BREAK" />
Опитайте да се свържете със системния си администратор.</translation>
+<translation id="5499929369096410817">Въведете кода за сигурност за <ph name="CREDIT_CARD" />. Той няма да бъде запазен.</translation>
<translation id="5509780412636533143">Управлявани отметки</translation>
<translation id="5510766032865166053">Възможно е да е преместен или изтрит.</translation>
<translation id="5523118979700054094">Име на правилото</translation>
<translation id="552553974213252141">Текстът правилно ли бе извлечен?</translation>
<translation id="5540224163453853">Заявената статия не можа да бъде намерена.</translation>
+<translation id="5541546772353173584">Добавяне на имейл адрес</translation>
<translation id="5544037170328430102">Вградена страница на адрес <ph name="SITE" /> изпраща подкана:</translation>
+<translation id="5545756402275714221">Статии за вас</translation>
<translation id="5556459405103347317">Повторно зареждане</translation>
<translation id="5560088892362098740">Дата на изтичане</translation>
<translation id="5565735124758917034">Активно</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Имейл</translation>
<translation id="5669703222995421982">Получаване на персонализирано съдържание</translation>
<translation id="5675650730144413517">Тази страница не работи</translation>
+<translation id="5689199277474810259">Експортиране във формат JSON</translation>
<translation id="5710435578057952990">Самоличността на този уебсайт не е потвърдена.</translation>
<translation id="5719499550583120431">Приемат се предплатени карти.</translation>
<translation id="5720705177508910913">Текущият потребител</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Връзката ви с/ъс <ph name="DOMAIN" /> е шифрована с остарял криптографски пакет.</translation>
<translation id="5813119285467412249">&amp;Възстановяване на добавянето</translation>
<translation id="5838278095973806738">Не ви препоръчваме да въвеждате поверителна информация в този сайт (например пароли или номера на кредитни карти), тъй като може да бъде открадната от извършители на атаки.</translation>
+<translation id="5866257070973731571">Добавяне на телефонен номер</translation>
<translation id="5869405914158311789">Няма достъп до този сайт</translation>
<translation id="5869522115854928033">Запазени пароли</translation>
<translation id="5872918882028971132">Основни предложения</translation>
<translation id="5893752035575986141">Приемат се кредитни карти.</translation>
-<translation id="5901630391730855834">жълто</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (синхронизирано)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Използва се 1}other{Използват се #}}</translation>
<translation id="5959728338436674663">Автоматично изпращане до Google на <ph name="BEGIN_WHITEPAPER_LINK" />системна информация и част от съдържанието на страниците<ph name="END_WHITEPAPER_LINK" /> с цел по-лесно откриване на опасни приложения и сайтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Редактиране на информацията за връзка</translation>
<translation id="5967867314010545767">Премахване от историята</translation>
<translation id="5975083100439434680">Намаляване на мащаба</translation>
+<translation id="597552863672748783">Потвърдете кода за сигурност</translation>
<translation id="598637245381783098">Приложението за плащане не може да се отвори</translation>
<translation id="5989320800837274978">Не са посочени нито фиксирани прокси сървъри, нито URL адрес на скрипт във формат .pac.</translation>
<translation id="5990559369517809815">Заявките към сървъра са блокирани от разширение.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Страница 1}other{Страница #}}</translation>
-<translation id="6017514345406065928">зелено</translation>
<translation id="6017850046339264347">Извършители на атака срещу <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (синхронизирани)</translation>
<translation id="6027201098523975773">Въведете име</translation>
<translation id="6040143037577758943">Затваряне</translation>
-<translation id="6042308850641462728">Още</translation>
<translation id="6047233362582046994">Ако разбирате рисковете за сигурността си, може <ph name="BEGIN_LINK" />да посетите този сайт<ph name="END_LINK" /> преди премахването на опасните приложения.</translation>
<translation id="6047927260846328439">Въпросното съдържание може да се опита да ви подведе да инсталирате софтуер или да разкриете лична информация. <ph name="BEGIN_LINK" />Показване въпреки това<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">В момента не можете да посетите <ph name="SITE" />, защото уебсайтът използва метод за допълнително потвърждаване на сертификатите. Обикновено грешките в мрежата и атаките срещу нея са временни, така че тази страница вероятно ще работи по-късно.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Преглеждате страница на разширение</translation>
<translation id="6596325263575161958">Опции за шифроване</translation>
<translation id="662080504995468778">Оставане</translation>
+<translation id="6624427990725312378">Информация за връзка</translation>
<translation id="6626291197371920147">Добавяне на валиден номер на карта</translation>
<translation id="6628463337424475685">Търсене с/ъс <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Извършители на атака, понастоящем използващи <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, може да опитат да инсталират опасни програми на компютъра ви Mac, които крадат или изтриват информацията ви (например снимки, пароли, съобщения и номера на кредитни карти). <ph name="BEGIN_LEARN_MORE_LINK" />Научете повече<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Предишна</translation>
<translation id="6710594484020273272">&lt;Въведете дума за търсене&gt;</translation>
<translation id="6711464428925977395">Нещо не е наред с прокси сървъра или адресът е неправилен.</translation>
-<translation id="6727102863431372879">Задаване</translation>
<translation id="674375294223700098">Неизвестна грешка в сертификата на сървъра.</translation>
<translation id="6753269504797312559">Стойност за правилото</translation>
<translation id="6757797048963528358">Устройството ви премина в спящ режим.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL адрес</translation>
<translation id="7419106976560586862">Път на потребителския профил</translation>
<translation id="7424977062513257142">Страница, вградена в тази уеб страница, изпраща подкана:</translation>
+<translation id="7437289804838430631">Добавяне на информация за връзка</translation>
<translation id="7441627299479586546">Грешен предмет на правилото</translation>
<translation id="7444046173054089907">Този сайт е блокиран</translation>
<translation id="7445762425076701745">Идентичността на сървъра, към който сте свързани, не може да бъде потвърдена изцяло. Свързани сте към сървър чрез име, което е валидно само във вашата мрежа и чиято собственост няма начин да се потвърди от външен сертифициращ орган. Тъй като някои сертифициращи органи въпреки това издават сертификати за такива имена, не е възможно да се гарантира, че сте свързани към желания сайт, а не към атакуващ.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Препращане</translation>
<translation id="7485870689360869515">Няма намерени данни.</translation>
<translation id="7508255263130623398">Върнатият от правилата идентификационен номер на устройството е празен или не съответства на текущия</translation>
+<translation id="7511955381719512146">Използваната от вас Wi-Fi мрежа може да изисква да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Изтегляне</translation>
<translation id="7518003948725431193">Не е намерена уеб страница за уеб адреса: <ph name="URL" /></translation>
<translation id="7521387064766892559">Javascript</translation>
<translation id="7526934274050461096">Връзката ви с този сайт не е частна</translation>
-<translation id="7535087603100972091">Стойност</translation>
<translation id="7537536606612762813">Задължително</translation>
<translation id="7542403920425041731">След като потвърдите картата си, данните за нея ще бъдат споделени с този сайт.</translation>
<translation id="7542995811387359312">Автоматичното попълване на кредитната карта е деактивирано, защото този формуляр не използва защитена връзка.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; възможно е сертификатът му за сигурност да е издаден измамнически. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="7568593326407688803">Тази страница е на<ph name="ORIGINAL_LANGUAGE" />Искате ли да я преведете?</translation>
<translation id="7569952961197462199">Кредитната карта да се премахне ли от Chrome?</translation>
-<translation id="7569983096843329377">черно</translation>
<translation id="7578104083680115302">Извършвайте бързи плащания в сайтове и приложения от всякакви устройства посредством картите, които сте запазили в Google.</translation>
<translation id="7588950540487816470">Физическа мрежа</translation>
<translation id="7592362899630581445">Сертификатът на сървъра нарушава ограниченията за име.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Извършителите на атаки, използващи този сайт, може да опитат да ви подведат да инсталирате програми, които вредят на сърфирането ви (например, като променят началната ви страница или показват допълнителни реклами в посещаваните от вас сайтове).</translation>
<translation id="7674629440242451245">Търсите интересни нови функции на Chrome? Изпробвайте канала за програмисти на адрес chrome.com/dev.</translation>
<translation id="7682287625158474539">Адрес за доставка</translation>
+<translation id="7699293099605015246">В момента няма статии</translation>
<translation id="7701040980221191251">Няма</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Продължаване към <ph name="SITE" /> (опасно)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Сертификат</translation>
<translation id="7716147886133743102">Блокирано от администратора ви</translation>
<translation id="7716424297397655342">Този сайт не може да се зареди от кеш паметта</translation>
+<translation id="7723047071702270851">Редактиране на картата</translation>
<translation id="774634243536837715">Блокирахме опасно съдържание.</translation>
<translation id="7752995774971033316">Не се управлява</translation>
<translation id="7755287808199759310">Родителят ви може да го отблокира за вас</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Добавяне на адрес</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Добавяне</translation>
+<translation id="7793553086574152071">За да платите по-бързо следващия път, запазете тази карта в профила си в Google.</translation>
<translation id="7793809570500803535">До уеб страницата на адрес <ph name="SITE" /> може временно да няма достъп или да е преместена за постоянно на нов уеб адрес.</translation>
<translation id="7800304661137206267">Връзката е шифрована посредством <ph name="CIPHER" />, с/ъс <ph name="MAC" /> за удостоверяване за съобщения и <ph name="KX" /> като механизъм за обмен на ключове.</translation>
+<translation id="7802523362929240268">Сайтът е легитимен</translation>
<translation id="780301667611848630">Не, благодаря</translation>
<translation id="7805768142964895445">Състояние</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Предложението за формуляри да се премахне ли от Chrome?</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="785549533363645510">Сърфирането ви обаче не е невидимо. При преминаване в режим „инкогнито“ то не се скрива от работодателя ви и от доставчика ви на интернет услуги, нито от уебсайтовете, които посещавате.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Приемат се дебитни и предплатени карти.</translation>
+<translation id="7878562273885520351">Възможно е паролата ви да е компрометирана</translation>
<translation id="7887683347370398519">Прегледайте кода за проверка и опитайте отново</translation>
<translation id="79338296614623784">Въведете валиден телефонен номер</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификатът на сървъра още не е валиден.</translation>
-<translation id="7942349550061667556">червено</translation>
<translation id="7947285636476623132">Проверете годината на валидност и опитайте отново</translation>
<translation id="7951415247503192394">(32 бита)</translation>
<translation id="7956713633345437162">Мобилни отметки</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Извеждане на запитване (по подразбиране)</translation>
<translation id="8041089156583427627">Изпращане на отзивите</translation>
<translation id="8041940743680923270">Използване на глобалната стандартна стойност (запитване)</translation>
+<translation id="8057711352706143257">Софтуерът <ph name="SOFTWARE_NAME" /> не е конфигуриран правилно. Обикновено проблемът се отстранява с деинсталиране на <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Преглеждането на статията не бе успешно.</translation>
<translation id="8091372947890762290">В сървъра се изчаква активиране</translation>
+<translation id="8094917007353911263">Използваната от вас мрежа може да изисква да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Начин на плащане</translation>
<translation id="8118489163946903409">Начин на плащане</translation>
+<translation id="8127301229239896662"><ph name="SOFTWARE_NAME" /> не се инсталира правилно на компютъра ви или в мрежата. Помолете системния си администратор да реши този проблем.</translation>
<translation id="8131740175452115882">Потвърждаване</translation>
<translation id="8134994873729925007">Не можа да бъде намерен <ph name="BEGIN_ABBR" />DNS адресът<ph name="END_ABBR" /> на сървъра на <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Компютърът ви премина в спящ режим.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Свържете се със системния си администратор, ако не сте сигурни какво означава това.</translation>
<translation id="8293206222192510085">Добавяне на отметка</translation>
<translation id="8294431847097064396">Източник</translation>
+<translation id="8298115750975731693">Използваната от вас Wi-Fi мрежа (<ph name="WIFI_NAME" />) може да изисква да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Не може да се установи частна връзка със сайта <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, тъй като датата и часът на устройството ви (<ph name="DATE_AND_TIME" />) са неправилни. <ph name="BEGIN_LEARN_MORE_LINK" />Научете повече<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Преводът не бе успешен поради проблем с връзката към мрежата.</translation>
<translation id="8332188693563227489">Достъпът до <ph name="HOST_NAME" /> бе отказан</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Наскоро затворени</translation>
<translation id="8874824191258364635">Въведете валиден номер на карта</translation>
<translation id="8876793034577346603">Синтактичният анализ на конфигурацията на мрежата не бе успешен.</translation>
-<translation id="8889402386540077796">Цветови тон</translation>
<translation id="8891727572606052622">Невалиден режим на прокси сървъра.</translation>
<translation id="889901481107108152">За съжаление този експеримент не се предлага за платформата ви.</translation>
<translation id="8903921497873541725">Увеличаване на мащаба</translation>
<translation id="8931333241327730545">Искате ли да запазите тази карта в профила си в Google?</translation>
<translation id="8932102934695377596">Часовникът ви е назад</translation>
+<translation id="893332455753468063">Добавяне на име</translation>
<translation id="8938939909778640821">Приемани кредитни и предплатени карти</translation>
+<translation id="8957210676456822347">Упълномощаване в портал за удостоверяване</translation>
<translation id="8971063699422889582">Сертификатът на сървъра е с изтекла валидност.</translation>
-<translation id="8986494364107987395">Автоматично изпращане до Google на статистически данни за използването на Chrome и сигнали за сривове</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">На хоризонта се задава сайт с опасни програми</translation>
<translation id="8997023839087525404">Сървърът предостави сертификат, който не е разкрит публично чрез правило в Прозрачност на сертификатите. Това се изисква за някои сертификати с цел защита срещу хакери и за да е сигурно, че може да им се има доверие.</translation>
<translation id="9001074447101275817">Изискват се потребителско име и парола за прокси сървъра <ph name="DOMAIN" />.</translation>
<translation id="9005998258318286617">Зареждането на PDF документа не бе успешно.</translation>
+<translation id="9008201768610948239">Пренебрегване</translation>
<translation id="901974403500617787">Флаговете, които се прилагат за цялата система, могат да бъдат зададени само от собственика: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Свързаният с картата адрес за фактуриране е задължителен</translation>
<translation id="9020542370529661692">Тази страница е преведена на <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Опитахте да отворите <ph name="DOMAIN" />, но сървърът предостави невалиден сертификат.</translation>
<translation id="9050666287014529139">Парола</translation>
<translation id="9065203028668620118">Редактиране</translation>
-<translation id="9068849894565669697">Избор на цвят</translation>
<translation id="9069693763241529744">Блокирано от разширение</translation>
<translation id="9076283476770535406">Възможно е да има съдържание за пълнолетни</translation>
<translation id="9078964945751709336">Изисква се още информация</translation>
+<translation id="9080712759204168376">Обобщена информация за поръчката</translation>
<translation id="9103872766612412690">Обикновено <ph name="SITE" /> използва шифроване за защита на информацията ви. Когато Chromium опита да установи връзка с/ъс <ph name="SITE" /> този път, уебсайтът върна необичайни и неправилни идентификационни данни. Това може да се случи, когато извършител на атака пробва да се представи за <ph name="SITE" /> или връзката е прекъсната от екран за вход в Wi-Fi. Информацията ви продължава да е защитена, тъй като Chromium спря връзката, преди да бъдат обменени данни.</translation>
+<translation id="9106062320799175032">Добавяне на адрес за фактуриране</translation>
+<translation id="910908805481542201">Помогнете ми да отстраня този проблем</translation>
+<translation id="9128870381267983090">Свързване към мрежа</translation>
<translation id="9137013805542155359">Показване на оригинала</translation>
<translation id="9137248913990643158">Моля, стартирайте браузъра Chrome и влезте в него, преди да използвате това приложение.</translation>
<translation id="9148507642005240123">&amp;Отмяна на редактирането</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> използва неподдържан протокол.</translation>
<translation id="9205078245616868884">Данните ви са шифровани с пропуска ви за синхронизиране. Въведете го, за да стартирате синхронизирането.</translation>
<translation id="9207861905230894330">Добавянето на статията не бе успешно.</translation>
+<translation id="9215416866750762878">Приложение пречи на Chrome да се свърже безопасно с този сайт</translation>
<translation id="9219103736887031265">Изображения</translation>
<translation id="933612690413056017">Няма връзка с интернет</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Няма}=1{1 елемент}other{# елемента}}</translation>
<translation id="981121421437150478">Офлайн</translation>
<translation id="988159990683914416">Компилирана програма за програмисти</translation>
+<translation id="989988560359834682">Редактиране на адреса</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401"><ph name="SOFTWARE_NAME" /> не се инсталира правилно на компютъра ви или в мрежата:
+ &lt;ul&gt;
+ &lt;li&gt;Опитайте да деинсталирате или деактивирате <ph name="SOFTWARE_NAME" />.&lt;/li&gt;
+ &lt;li&gt;Опитайте да се свържете с друга мрежа.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index 19298eafd69..2111ab57aa7 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">ডেস্কটপ বুকমার্ক</translation>
<translation id="1074497978438210769">সুরক্ষিত নয়</translation>
<translation id="1080116354587839789">প্রস্থের মধ্যে আঁটান</translation>
+<translation id="1088860948719068836">কার্ডে নাম যোগ করুন</translation>
<translation id="1103523840287552314">সর্বদা অনুবাদ করুন <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">সেভ করা সমস্ত পাসওয়ার্ড দেখুন...</translation>
<translation id="1107591249535594099">যদি পরীক্ষা করা হয়, Chrome দ্রুত ফর্ম পূরণ করার জন্য এই ডিভাইসে থাকা আপনার কার্ডের একটি প্রতিলিপি সঞ্চয় করবে৷</translation>
<translation id="1111153019813902504">সাম্প্রতিক ঘুরে দেখা বুকমার্কগুলি</translation>
<translation id="1113869188872983271">&amp;পুনর্বিন্যাসকে পূর্বাবস্থায় ফেরান</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (সিঙ্ক হয়েছে)</translation>
<translation id="1263231323834454256">পড়ার তালিকা</translation>
<translation id="1264126396475825575">ক্র্যাশ প্রতিবেদন <ph name="CRASH_TIME" /> এ ক্যাপচার করা হয়েছে (এখনো আপলোড করা বা উপেক্ষা করা হয়নি)</translation>
+<translation id="1270502636509132238">পিক-আপের পদ্ধতি</translation>
<translation id="1281526147609854549">জারি করেছে <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">কখনই এই সাইটটিকে অনুবাদ করবেন না</translation>
<translation id="129553762522093515">সম্প্রতি বন্ধ হয়েছে</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">সংযোগের জন্য অপেক্ষা করা হচ্ছে...</translation>
<translation id="153384715582417236">এখন এই পর্যন্তই</translation>
<translation id="1549470594296187301">এই বৈশিষ্ট্যটি ব্যবহার করার জন্য JavaScript সক্ষম করা প্রয়োজন।</translation>
-<translation id="1555130319947370107">নীল</translation>
<translation id="1559528461873125649">এমন কোন ফাইল বা ডিরেক্টরি নেই</translation>
<translation id="1583429793053364125">এই ওয়েবপৃষ্ঠাটি দেখানোর সময় কোনো সমস্যা হয়েছে।</translation>
<translation id="1592005682883173041">স্থানীয় ডেটা অ্যাক্সেস</translation>
<translation id="1594030484168838125">বেছে নিন</translation>
-<translation id="161042844686301425">নীলাভ</translation>
<translation id="1620510694547887537">ক্যামেরা</translation>
<translation id="1629803312968146339">আপনি কি চান যে Chrome এই কার্ড সংরক্ষণ করুক?</translation>
<translation id="1639239467298939599">লোড হচ্ছে</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">এই সাইটে যেতে আপনাকে <ph name="NAME" /> এর কাছ থেকে অনুমতি নিতে হবে</translation>
<translation id="1721424275792716183">* এই ফিল্ডে কিছু লেখা প্রয়োজন</translation>
+<translation id="1727741090716970331">সঠিক কার্ড নম্বর যোগ করুন</translation>
<translation id="1728677426644403582">আপনি একটি ওয়েব পৃষ্ঠার উৎস কোড দেখছেন</translation>
<translation id="173080396488393970">এখানে এই ধরনের কার্ড কাজ করে না</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -115,7 +117,7 @@
<translation id="1826516787628120939">চেক করা হচ্ছে</translation>
<translation id="1834321415901700177">এই সাইটটিতে ক্ষতিকর প্রোগ্রাম রয়েছে</translation>
<translation id="1840414022444569775">এই কার্ডের নম্বরটি আগেই ব্যবহার করেছেন</translation>
-<translation id="1842969606798536927">অর্থ প্রদান করুন</translation>
+<translation id="1842969606798536927">পেমেন্ট করুন</translation>
<translation id="1871208020102129563">
প্রক্সি স্থির প্রক্সি সার্ভারগুলি ব্যবহার করতে সেট করা আছে কোনো .pac স্ক্রিপ্ট URL নয়৷</translation>
<translation id="1871284979644508959">আবশ্যক ক্ষেত্র</translation>
@@ -131,7 +133,6 @@
<translation id="1973335181906896915">ধারাবাহিকতাতে ত্রুটি</translation>
<translation id="1974060860693918893">উন্নত</translation>
<translation id="1978555033938440688">ফার্মওয়ের সংস্করণ</translation>
-<translation id="1995859865337580572">Please verify your CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{এবং আরও ১টি}one{এবং আরও #টি}other{এবং আরও #টি}}</translation>
<translation id="2025186561304664664">স্বতঃ কনফিগার করতে প্রক্সি সেট করা হয়৷</translation>
<translation id="2030481566774242610">আপনি কি <ph name="LINK" /> বোঝাতে চেয়েছিলেন?</translation>
@@ -142,6 +143,7 @@
<translation id="2079545284768500474">পূর্বাবস্থায় ফিরুন</translation>
<translation id="20817612488360358">সিস্টেম প্রক্সি সেটিংস ব্যবহার করার জন্য সেট আছে কিন্তু একটি সুনির্দিষ্ট প্রক্সি কনফিগারেশনও নির্দিষ্ট করা আছে৷</translation>
<translation id="2086652334978798447">Google দ্বারা প্রস্তাবিত ব্যক্তিগতকৃত সামগ্রী পেতে, Chrome এ সাইন ইন করুন।</translation>
+<translation id="2091887806945687916">আওয়াজ</translation>
<translation id="2094505752054353250">ডোমেন মেলেনি</translation>
<translation id="2096368010154057602">বিভাগ</translation>
<translation id="2108755909498034140">আপনার কম্পিউটার পুনরায় চালু করুন</translation>
@@ -149,7 +151,9 @@
<translation id="2114841414352855701">এড়িয়ে যাওয়া হয়েছে কারণ এটি <ph name="POLICY_NAME" />-দ্বারা ওভাররাইড করা হয়েছিল৷</translation>
<translation id="2138201775715568214">আশেপাশের বাস্তবিক ওয়েব পৃষ্ঠাগুলি খুঁজছে</translation>
<translation id="213826338245044447">মোবাইল বুকমার্ক</translation>
+<translation id="214556005048008348">পেমেন্ট বাতিল করুন</translation>
<translation id="2147827593068025794">পটভূমি সিঙ্ক</translation>
+<translation id="2148613324460538318">কার্ড যোগ করুন</translation>
<translation id="2154054054215849342">আপনার ডোমেনের জন্য সিঙ্ক উপলব্ধ নেই</translation>
<translation id="2154484045852737596">কার্ড সম্পাদনা করুন</translation>
<translation id="2166049586286450108">পূর্ণ প্রশাসক অ্যাক্সেস</translation>
@@ -158,6 +162,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{১টি ঠিকানা}one{ #টি ঠিকানা}other{ #টি ঠিকানা}}</translation>
<translation id="2187317261103489799">সনাক্ত করুন (ডিফল্ট)</translation>
<translation id="2202020181578195191">মেয়াদ শেষ হওয়ার বছরের সঠিক মান লিখুন</translation>
+<translation id="2209523182407020534">অ্যান্টিভাইরাস, ফায়ারওয়াল এবং ওয়েব-ফিল্টারিং বা প্রক্সি সফ্টওয়্যারের মতো অ্যাপ্লিকেশন এই ধরণের ত্রুটির কারণ হতে পারে।</translation>
<translation id="2212735316055980242">নীতি পাওয়া যায়নি</translation>
<translation id="2213606439339815911">এন্ট্রিগুলি আনা হচ্ছে...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> এ যে আক্রমণকারীরা এই মুহূর্তে সক্রিয় আছে, তারা এমন বিপজ্জনক অ্যাপ ইনস্টল করে দিতে পারে যেগুলি আপনার ডিভাইসের ক্ষতি করতে, আপনার মোবাইলের বিলে লুকানো চার্জ যোগ করতে, বা আপনার ব্যক্তিগত তথ্য চুরি করতে পারে৷ <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানুন<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -198,6 +203,8 @@
<translation id="2501278716633472235">ফিরে যান</translation>
<translation id="2503184589641749290">ডেবিট ও প্রিপেড কার্ড গ্রহণ করা হয়</translation>
<translation id="2515629240566999685">আপনার এলাকায় সংকেত পরীক্ষা করে দেখুন</translation>
+<translation id="2524461107774643265">আরও তথ্য যোগ করুন</translation>
+<translation id="2536110899380797252">ঠিকানা যোগ করুন</translation>
<translation id="2539524384386349900">সনাক্ত করুন</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> একটি অবৈধ প্রতিক্রিয়া পাঠিয়েছে।</translation>
<translation id="2556876185419854533">&amp;সম্পাদনাকে পূর্বাবস্থায় ফেরান</translation>
@@ -220,8 +227,8 @@
<translation id="2704951214193499422">Chromium এই মুহূর্তে আপনার কার্ড নিশ্চিত করতে অক্ষম হয়েছে৷ দয়া করে পরে আবার চেষ্টা করুন৷</translation>
<translation id="2705137772291741111">এই সাইটের সংরক্ষিত (সঞ্চিত) অনুলিপি পড়া সম্ভব হয়নি।</translation>
<translation id="2709516037105925701">স্বয়ংপূরণ</translation>
+<translation id="2710942282213947212">আপনার কম্পিউটারের সফ্টওয়্যার Chromium কে নিরাপদে ওয়েবে সংযোগ করতে বাধা দিচ্ছে</translation>
<translation id="2712173769900027643">অনুমতি নিন</translation>
-<translation id="2713444072780614174">সাদা</translation>
<translation id="2720342946869265578">আশেপাশে</translation>
<translation id="2721148159707890343">অনুরোধ সফল হয়েছে</translation>
<translation id="2728127805433021124">একটি দুর্বল স্বাক্ষর অ্যালগোরিদম ব্যবহার করে সার্ভারের শংসাপত্রে সাইন করা হয়েছে৷</translation>
@@ -244,6 +251,7 @@
<translation id="2909946352844186028">একটি নেটওয়ার্ক পরিবর্তন সনাক্ত হয়েছে৷</translation>
<translation id="2916038427272391327">অন্যান্য প্রোগ্রামগুলি বন্ধ করুন</translation>
<translation id="2922350208395188000">সার্ভারের শংসাপত্র চেক করা যাবে না৷</translation>
+<translation id="2925673989565098301">ডেলিভারির পদ্ধতি</translation>
<translation id="2928905813689894207">বিলিংয়ের ঠিকানা</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />টি}}</translation>
<translation id="2941952326391522266">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্র <ph name="DOMAIN2" /> থেকে পাওয়া। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
@@ -266,6 +274,7 @@
<translation id="3024663005179499861">নীতির ভুল প্রকার</translation>
<translation id="3032412215588512954">আপনি কি এই সাইটটি পুনরায় লোড করতে চান?</translation>
<translation id="3037605927509011580">ইস!</translation>
+<translation id="3039538478787849737">Google এ কার্ড সেভ করবেন?</translation>
<translation id="3041612393474885105">শংসাপত্র তথ্য</translation>
<translation id="3063697135517575841">Chrome এই মুহূর্তে আপনার কার্ড নিশ্চিত করতে পারছে না৷ অনুগ্রহ করে পরে আবার চেষ্টা করুন৷</translation>
<translation id="3064966200440839136">বহিরাগত অ্যাপ্লিকেশানের মাধ্যমে অর্থপ্রদান করার জন্য ছদ্মবেশী মোড থেকে বেরিয়ে যাচ্ছে। চালিয়ে যাবেন?</translation>
@@ -279,6 +288,7 @@
<translation id="3150653042067488994">সাময়িক সার্ভার ত্রুটি</translation>
<translation id="3154506275960390542">এই পৃষ্ঠাতে একটি ফর্ম আছে যেটি জমা দেওয়া নিরাপদ নাও হতে পারে। আপনার পাঠানো ডেটা সার্ভারে পৌঁছানোর আগে অন্যরা সেটি দেখতে পেতে পারেন, অথবা কেউ সেটি পরিবর্তন করে দিতে পারেন যাতে আপনার ডেটা সঠিকভাবে সার্ভারে না পৌঁছায়।</translation>
<translation id="3157931365184549694">পুনরুদ্ধার করুন</translation>
+<translation id="3162559335345991374">আপনি যে Wi-Fiটি ব্যবহার করছেন সেটির জন্য অপনাকে এটির লগ ইন পৃষ্ঠাতে যেতে হতে পরে৷</translation>
<translation id="3167968892399408617">ছদ্মবেশী ট্যাবগুলিতে আপনি যে পৃষ্ঠাগুলি দেখেন সেগুলি আপনার সব ছদ্মবেশী ট্যাব বন্ধ করে দেওয়ার পর ব্রাউজারের ইতিহাস, কুকি স্টোর বা অনুসন্ধান ইতিহাসে থাকবে না। আপনি ডাউনলোড করেছেন এমন ফাইল বা বুকমার্ক তৈরি করছেন এমন সবগুলি রেখে দেওয়া হবে।</translation>
<translation id="3169472444629675720">আবিষ্কার করুন</translation>
<translation id="3174168572213147020">দ্বীপ</translation>
@@ -288,6 +298,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">পেমেন্ট বাতিল করুন</translation>
<translation id="3207960819495026254">বুকমার্ক করা হয়েছে</translation>
+<translation id="3211223744486044430">পরের বার আরও দ্রুত পেমেন্ট করা জন্য এই কার্ডটি Google অ্যাকাউন্টে এবং এই ডিভাইসে সেভ করে রাখুন।</translation>
<translation id="3225919329040284222">সার্ভারটি এমন একটি শংসাপত্র উপস্থাপনা করেছে যা বিল্ট-ইন প্রত্যাশাগুলির সাথে মেলে না৷ এই প্রত্যাশাগুলি আপনাকে সুরক্ষিত করতে কিছু নিশ্চিত, উচ্চ সুরক্ষার ওয়েবসাইটের জন্য অন্তর্ভুক্ত৷</translation>
<translation id="3226128629678568754">পৃষ্ঠাটি লোড করতে প্রয়োজনীয় ডেটেটি আবার জমা দিতে আবার লোড করার বোতামটি টিপুন৷</translation>
<translation id="3227137524299004712">মাইক্রোফোন</translation>
@@ -302,7 +313,6 @@
<translation id="3303855915957856445">কোনো অনুসন্ধান ফলাফল পাওয়া যায়নি</translation>
<translation id="3305707030755673451">আপনার ডেটা আপনার সিঙ্ক পাসফ্রেজ দিয়ে <ph name="TIME" /> এ এনক্রিপ্ট করা হয়েছে। সিঙ্ক শুরু করার জন্য এটি লিখুন।</translation>
<translation id="3320021301628644560">বিলিংয়ের ঠিকানা যোগ করুন</translation>
-<translation id="3329013043687509092">পরিপৃক্তি</translation>
<translation id="333371639341676808">এই পৃষ্ঠাটিকে অতিরিক্ত কথোপকথন তৈরি করা থেকে আটকান৷</translation>
<translation id="3338095232262050444">সুরক্ষিত</translation>
<translation id="3340978935015468852">সেটিংস</translation>
@@ -321,6 +331,7 @@
<translation id="3380864720620200369">ক্লায়েন্ট ID:</translation>
<translation id="3391030046425686457">পৌঁছে দেওয়ার ঠিকানা</translation>
<translation id="3395827396354264108">পিকআপের পদ্ধতি</translation>
+<translation id="3399952811970034796">ডেলিভারির ঠিকানা</translation>
<translation id="3422248202833853650">মেমরি ফাঁকা করতে অন্যান্য প্রোগ্রাম থেকে বেরিয়ে যাওয়ার চেষ্টা করুন।</translation>
<translation id="3422472998109090673">বর্তমানে <ph name="HOST_NAME" /> পাওয়া যাচ্ছে না।</translation>
<translation id="3427092606871434483">মঞ্জুরি দিন (ডিফল্ট)</translation>
@@ -366,10 +377,12 @@
<translation id="3679803492151881375">ক্র্যাশ প্রতিবেদন <ph name="CRASH_TIME" /> এ ক্যাপচার করা হয়েছে, <ph name="UPLOAD_TIME" /> এ আপলোড করা হয়েছে</translation>
<translation id="3681007416295224113">শংসাপত্র তথ্য</translation>
<translation id="3690164694835360974">লগইন সুরক্ষিত নয়</translation>
+<translation id="3704162925118123524">আপনি যে নেটওয়ার্কটি ব্যবহার করছেন সেটির জন্য অপনাকে এটির লগ ইন পৃষ্ঠাতে যেতে হতে পরে৷</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">লোড হচ্ছে...</translation>
<translation id="3712624925041724820">লাইসেন্সগুলির মেয়াদ শেষ হয়ে গেছে</translation>
<translation id="3714780639079136834">মোবাইল ডেটা বা ওয়াই-ফাই চালু করে দেখুন</translation>
+<translation id="3715597595485130451">ওয়াই-ফাই তে সংযোগ স্থাপন করুন</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />প্রক্সি, ফায়ারওয়াল এবং DNS কনফিগারেশন পরীক্ষা করে দেখুন<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">আপনি যদি আপনার নিরাপত্তার ঝুঁকিগুলি বুঝতে পারেন, তাহলে ক্ষতিকারক প্রোগ্রাম সরানোর আগে আপনি <ph name="BEGIN_LINK" />অসুরক্ষিত সাইটে যেতে পারেন<ph name="END_LINK" />।</translation>
<translation id="3739623965217189342">আপনার অনুলিপি করা লিঙ্ক</translation>
@@ -404,6 +417,7 @@
<translation id="4030383055268325496">&amp;যোগ করাকে পূর্বাবস্থায় ফেরান</translation>
<translation id="404928562651467259">সতর্কতা</translation>
<translation id="4058922952496707368">কী "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">সঠিক ঠিকানা যোগ করুন</translation>
<translation id="4072486802667267160">আপনার অর্ডার প্রক্রিয়া করার সময় একটি সমস্যা হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।</translation>
<translation id="4075732493274867456">ক্লায়েন্ট ও সার্ভারটি কোনো অভিন্ন SSL প্রোটোকল সংস্করণ বা সাইফার স্যুট সমর্থন করে না।</translation>
<translation id="4079302484614802869">প্রক্সি কনফিগারেশনটি .pac স্ক্রিপ্ট URL-এ ব্যবহার করাতে সেট থাকে স্থির প্রক্সি সার্ভারগুলিতে নয়৷</translation>
@@ -411,7 +425,6 @@
<translation id="4103249731201008433">ডিভাইসের ক্রমিক সংখ্যা অবৈধ</translation>
<translation id="410351446219883937">স্বতঃচালানো</translation>
<translation id="4103763322291513355">নিবারিত URLগুলির তালিকা এবং আপনার সিস্টেম প্রশাসকের দ্বারা জারি করা অন্যান্য নীতিগুলি দেখার জন্য &lt;strong&gt;chrome://policy&lt;/strong&gt; এ যান৷</translation>
-<translation id="4115378294792113321">ম্যাজেন্টা</translation>
<translation id="4116663294526079822">এই সাইটে সর্বদা অনুমতি দিন</translation>
<translation id="4117700440116928470">নীতির সুযোগটি সমর্থিত নয়৷</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{আরও ১টি}one{অন্যান্য #টি}other{অন্যান্য #টি}}</translation>
@@ -449,6 +462,7 @@
<translation id="4377125064752653719">আপনি <ph name="DOMAIN" />-এ পৌঁছানোর প্রচেষ্টা করেছেন, তবে সার্ভারটি যে শংসাপত্রটি উপস্থাপন করেছে সেটির জারিকর্তা সেটিকে প্রত্যাহার করেছে৷ এর অর্থ হ'ল সার্ভারটি যে সুরক্ষা প্রমানপত্র উপস্থাপন করেছে তা কোনওমতেই বিশ্বাসযোগ্য নয়৷ হতে পারে আপনি একজন আক্রমণকারীর সাথে যোগাযোগ করছেন৷</translation>
<translation id="4394049700291259645">অক্ষম</translation>
<translation id="4406896451731180161">অনুসন্ধানের ফলাফলগুলি</translation>
+<translation id="4415426530740016218">পিক-আপের ঠিকানা</translation>
<translation id="4424024547088906515">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্র Chrome এর নিকট বিশ্বাসযোগ্য নয়। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> আপনার লগইন শংসাপত্রটি স্বীকার করেনি, অথবা কোনো শংসাপত্র দেওয়া হয়নি।</translation>
<translation id="443673843213245140">প্রক্সির ব্যবহার অক্ষম করা হয়েছে কিন্তু কোনো স্পষ্ট প্রক্সি কনফিগারেশান নির্দিষ্ট করা হয়েছে৷</translation>
@@ -461,6 +475,7 @@
<translation id="4552089082226364758">ফ্ল্যাশ</translation>
<translation id="4558551763791394412">আপনার এক্সটেনশানগুলি অক্ষম করে দেখুন।</translation>
<translation id="457875822857220463">পৌঁছে দেওয়া</translation>
+<translation id="4582800630050655161">আপনি নিজের Google অ্যাকাউন্টে অ্যাক্সেস হারাতে পারেন বা আপনার পরিচয় চুরি হতেই পারে। Chromium এখনই আপনার পাসওয়ার্ড পরিবর্তন করার আর্জি জানাচ্ছে।</translation>
<translation id="4587425331216688090">Chrome থেকে ঠিকানা সরাবেন?</translation>
<translation id="4592951414987517459">একটি আধুনিক সাইফার স্যুট ব্যবহার করে <ph name="DOMAIN" />-এ আপনার সংযোগ এনক্রিপ্ট করা হয়েছে।</translation>
<translation id="4594403342090139922">&amp;মুছে ফেলাকে পূর্বাবস্থায় ফেরান</translation>
@@ -469,10 +484,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্রে কিছু ত্রুটি আছে। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
<translation id="4690462567478992370">কোনো অবৈধ শংসাপত্র ব্যবহার করা বন্ধ করুন</translation>
+<translation id="4690954380545377795">আপনি নিজের Google অ্যাকাউন্টে অ্যাক্সেস হারাতে পারেন বা আপনার পরিচয় চুরি হতেই পারে। Chrome এখনই আপনার পাসওয়ার্ড পরিবর্তন করার আর্জি জানাচ্ছে।</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">আপনার সংযোগ বাধাপ্রাপ্ত হয়েছে</translation>
<translation id="471880041731876836">এই সাইট দেখার অনুমতি আপনার নেই</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows নেটওয়ার্ক ডায়গনিস্টিক্স চালান<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">আপনার অর্থপ্রদান</translation>
<translation id="4726672564094551039">নীতিগুলি পুনঃলোড করুন</translation>
<translation id="4728558894243024398">প্ল্যাটফর্ম</translation>
<translation id="4736825316280949806">Chromium পুনরায় চালু করুন</translation>
@@ -511,6 +528,7 @@
<translation id="5019198164206649151">ব্যাকিং স্টোরটি ত্রুটিপূর্ণ অবস্থায় আছে</translation>
<translation id="5023310440958281426">আপনার প্রশাসকের নীতিগুলি দেখুন</translation>
<translation id="5029568752722684782">প্রতিলিপি সাফ করুন</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" এর জন্য একটি রুট সার্টিফিকেট প্রয়োজন কিন্তু সেটি ইনস্টল করা নেই। এই সমস্যাটি সমাধান করতে আপনার IT প্রশাসককে "<ph name="SOFTWARE_NAME" />" এর কনফিগারেশন নির্দেশ ভাল করে দেখে নিতে হবে। <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google অনুবাদ সম্বন্ধে</translation>
<translation id="5039804452771397117">অনুমতি দিন</translation>
<translation id="5040262127954254034">গোপনীয়তা</translation>
@@ -534,6 +552,8 @@
<translation id="5199729219167945352">পরীক্ষাদি</translation>
<translation id="5205222826937269299">নাম প্রয়োজন</translation>
<translation id="5222812217790122047">ইমেল প্রয়োজন</translation>
+<translation id="522700295135997067">এই সাইট হয়ত আপনার পাসওয়ার্ড চুরি করেছে</translation>
+<translation id="5230733896359313003">শিপিংয়ের ঠিকানা</translation>
<translation id="5251803541071282808">ক্লাউড</translation>
<translation id="5277279256032773186">কর্মক্ষেত্রে Chrome ব্যবহার করছেন? ব্যবসাগুলো তাদের কর্মচারীদের জন্য Chrome সেটিংস পরিচালনা করতে পারে। আরও জানুন</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />সফ্টওয়্যারটি সাময়িকভাবে নিষ্ক্রিয় করার জন্য এই পদক্ষেপগুলি অনুসরণ করুন যাতে আপনি ওয়েবে যেতে পারেন। আপনার প্রশাসকের অধিকার প্রয়োজন হবে।<ph name="END_PARAGRAPH" />
@@ -548,9 +568,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">এই সাইটে আপনার সংযোগ ব্যক্তিগত নয়। যেকোনো সময় (ভিআর)VR মোড থেকে বেরিয়ে যাওয়ার জন্য, হেডসেট সরান এবং 'পিছনে' চাপুন।</translation>
<translation id="5299298092464848405">নীতি বিশ্লেষণ করার সময় ত্রুটি</translation>
+<translation id="5308380583665731573">সংযুক্ত করুন</translation>
<translation id="5308689395849655368">ক্র্যাশ প্রতিবেদন অক্ষম আছে৷</translation>
<translation id="5317780077021120954">সেভ করুন</translation>
<translation id="5327248766486351172">নাম</translation>
+<translation id="5332219387342487447">শিপিংয়ের মাধ্যম</translation>
<translation id="5355557959165512791">ওয়েবসাইটটির শংসাপত্র তুলে নেওয়ার কারণে আপনি এখন <ph name="SITE" /> এ যেতে পারবেন না। নেটওয়ার্ক ত্রুটি এবং আক্রমণ সাধারণত সাময়িকভাবে হয়, তাই এই পৃষ্ঠাটি সম্ভবত পরে কাজ করবে।</translation>
<translation id="536296301121032821">নীতি সেটিংস সংরক্ষণ করতে ব্যর্থ হয়েছে</translation>
<translation id="5386426401304769735">এই সাইটের শংসাপত্র শৃঙ্খলে SHA-1 ব্যবহার করে স্বাক্ষর করা একটি শংসাপত্র রয়েছে।</translation>
@@ -570,12 +592,15 @@
<translation id="5492298309214877701">কোম্পানী, সংস্থা বা স্কুল ইন্ট্রানেটে এই সাইটটির একটি বাহ্যিক ওয়েবসাইটের মতো একই URL আছে।
<ph name="LINE_BREAK" />
আপনার সিস্টেম প্রশাসকের সাথে যোগাযোগের চেষ্টা করুন।</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> এর নিরাপত্তা কোড লিখুন। এই কোডটি সেভ করা হবে না।</translation>
<translation id="5509780412636533143">পরিচালিত বুকমার্কগুলি</translation>
<translation id="5510766032865166053">এটি হয়ত সরানো বা মুছে ফেলা হয়েছে।</translation>
<translation id="5523118979700054094">নীতি নাম</translation>
<translation id="552553974213252141">পাঠ্য কি সঠিকভাবে প্রাপ্ত হয়েছে?</translation>
<translation id="5540224163453853">অনুরোধকৃত নিবন্ধ খুঁজে পাওয়া যায়নি৷</translation>
+<translation id="5541546772353173584">ইমেল যোগ করুন</translation>
<translation id="5544037170328430102"><ph name="SITE" /> এ একটি এম্বেডেড পৃষ্ঠা বলছে:</translation>
+<translation id="5545756402275714221">আপনার জন্য নিবন্ধ</translation>
<translation id="5556459405103347317">আবার লোড করুন</translation>
<translation id="5560088892362098740">মেয়াদ শেষের তারিখ</translation>
<translation id="5565735124758917034">সক্রিয়</translation>
@@ -597,6 +622,7 @@
<translation id="5659593005791499971">ইমেল</translation>
<translation id="5669703222995421982">ব্যক্তিগতকৃত সামগ্রী পান</translation>
<translation id="5675650730144413517">এই পৃষ্ঠাটি কাজ করছে না</translation>
+<translation id="5689199277474810259">JSON এ রপ্তানি করুন</translation>
<translation id="5710435578057952990">এই ওয়েবসাইটির পরিচয় যাচাই করা হয় নি৷</translation>
<translation id="5719499550583120431">প্রিপেড কার্ড গ্রহণ করা হয়।</translation>
<translation id="5720705177508910913">বর্তমান ব্যবহারকারী</translation>
@@ -611,27 +637,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" />-এ আপনার সংযোগ একটি অপ্রচলিত সাইফার স্যুট ব্যবহার করে এনক্রিপ্ট করা হয়েছে৷</translation>
<translation id="5813119285467412249">&amp;যোগ করাকে পুনরায় করুন</translation>
<translation id="5838278095973806738">এই সাইটে আপনার কোনো সংবেদনশীল তথ্য দেওয়া উচিত হবে না (উদাহরণস্বরূপ, পাসওয়ার্ড বা ক্রেডিট কার্ড) কারণ আক্রমণকারীরা এগুলি চুরি করতে পারে।</translation>
+<translation id="5866257070973731571">ফোন নম্বর যোগ করুন</translation>
<translation id="5869405914158311789">এই সাইটটিতে পৌছানো যাচ্ছে না</translation>
<translation id="5869522115854928033">সংরক্ষিত পাসওয়ার্ড</translation>
<translation id="5872918882028971132">মূল প্রস্তাবনাগুলি</translation>
<translation id="5893752035575986141">ক্রেডিট কার্ড গ্রহণ করা হয়।</translation>
-<translation id="5901630391730855834">হলুদ</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (সিঙ্ক হয়েছে)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{১টি ব্যবহৃত হচ্ছে}one{#টি ব্যবহৃত হচ্ছে}other{#টি ব্যবহৃত হচ্ছে}}</translation>
<translation id="5959728338436674663">বিপজ্জনক অ্যাপ্লিকেশান ও সাইটগুলি সনাক্ত করতে Google এর কাছে কিছু<ph name="BEGIN_WHITEPAPER_LINK" /> সিস্টেম তথ্য ও পৃষ্ঠার সামগ্রী<ph name="END_WHITEPAPER_LINK" /> স্বয়ংক্রিয়ভাবে পাঠান। <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">পরিচিতির তথ্য সম্পাদনা করুন</translation>
<translation id="5967867314010545767">ইতিহাস থেকে সরান</translation>
<translation id="5975083100439434680">জুম কমান</translation>
+<translation id="597552863672748783">নিরাপত্তা কোড নিশ্চিত করুন</translation>
<translation id="598637245381783098">পেমেন্ট অ্যাপ খোলা যাচ্ছে না</translation>
<translation id="5989320800837274978">কোনো নির্ধারিত প্রক্সি সার্ভার অথবা একটি.pac স্ক্রিপ্ট UR সুর্নিদিষ্টভাবে উল্লেখ করা হয়নি৷</translation>
<translation id="5990559369517809815">সার্ভারে অনুরোধগুলি একটি এক্সটেনশান দিয়ে অবরুদ্ধ করা আছে৷</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{পৃষ্ঠা ১}one{পৃষ্ঠা #}other{পৃষ্ঠা #}}</translation>
-<translation id="6017514345406065928">সবুজ</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (সিঙ্ক হয়েছে)</translation>
<translation id="6027201098523975773">একটি নাম লিখুন</translation>
<translation id="6040143037577758943">বন্ধ</translation>
-<translation id="6042308850641462728">আরও</translation>
<translation id="6047233362582046994">আপনি যদি আপনার নিরাপত্তার ঝুঁকিগুলি বুঝে নিয়ে থাকেন, তাহলে ক্ষতিকারক অ্যাপগুলি সরানোর আগে <ph name="BEGIN_LINK" />এই সাইটে যেতে পারেন<ph name="END_LINK" />৷</translation>
<translation id="6047927260846328439">এই কন্টেন্ট প্রতারণার মাধ্যমে আপনাকে দিয়ে কোনও সফ্টওয়্যার ইনস্টল করাতে অথবা আপনার ব্যক্তিগত তথ্য জেনে নেওয়ার চেষ্টা করতে পারে। <ph name="BEGIN_LINK" />তবুও এটি দেখতে চাই<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ওয়েবসাইটটি পিন করা শংসাপত্র ব্যবহার করার কারণে আপনি এখন <ph name="SITE" /> এ যেতে পারবেন না। নেটওয়ার্ক ত্রুটি এবং আক্রমণ সাধারণত সাময়িকভাবে হয়, তাই এই পৃষ্ঠাটি সম্ভবত পরে কাজ করবে।</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">আপনি একটি এক্সটেনশান পৃষ্ঠা দেখছেন</translation>
<translation id="6596325263575161958">এনক্রিপশন বিকল্পগুলি</translation>
<translation id="662080504995468778">থাকুন</translation>
+<translation id="6624427990725312378">পরিচিতির তথ্য</translation>
<translation id="6626291197371920147">বৈধ কার্ড নম্বর যোগ করুন</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> অনুসন্ধান</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> এ যে আক্রমণকারীরা এই মুহূর্তে সক্রিয় আছে, তারা আপনার Mac এ এমন বিপজ্জনক প্রোগ্রাম ইনস্টল করে দিতে পারে যেগুলি আপনার তথ্যের (যেমন ফটো, পাসওয়ার্ড, মেসেজ এবং ক্রেডিট কার্ড) ক্ষতি করতে বা সেগুলি চুরি করতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানুন<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">পূর্ববর্তী</translation>
<translation id="6710594484020273272">&lt;অনুসন্ধানের পদ লিখুন&gt;</translation>
<translation id="6711464428925977395">প্রক্সী সার্ভারের কোনো সমস্যা হয়েছে, অথবা ঠিকানাটি ভুল।</translation>
-<translation id="6727102863431372879">সেট</translation>
<translation id="674375294223700098">অজানা সার্ভার শংসাপত্র ত্রুটি৷</translation>
<translation id="6753269504797312559">নীতি মান</translation>
<translation id="6757797048963528358">আপনার ডিভাইস নিদ্রা মোডে গিয়েছে।</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">প্রোফাইল পথ</translation>
<translation id="7424977062513257142">এই ওয়েব পৃষ্ঠায় একটি এম্বেডেড পৃষ্ঠা বলছে:</translation>
+<translation id="7437289804838430631">পরিচিতির তথ্য যোগ করুন</translation>
<translation id="7441627299479586546">ভুল বিষয় বিশিষ্ট নীতি</translation>
<translation id="7444046173054089907">সাইটটি অবরুদ্ধ</translation>
<translation id="7445762425076701745">আপনি যে সার্ভারে সংযুক্ত রয়েছে সেটিকে সম্পূর্ণ যাচাই করতে পারা যায় না৷ আপনি নামগুলি দিয়ে এমন একটি সার্ভারে সংযুক্ত রয়েছেন যা আপনার নেটওয়ার্কে বৈধ, যেটি একটি বাহ্যিক শংসাকরণ কর্তৃপক্ষ যার এটির মালিকানা যাচাই করার কোনও উপায় নেই৷ কিছু শংসাপত্র কর্তৃপক্ষ এই নামগুলি নির্বিচারে শংসাপত্রগুলি ইস্যু করবে, আপনি উদ্দিষ্ট ওয়েবসাইটে সংযুক্ত রয়েছেন কোনও আক্রমণকারীতে নয় তা নিশ্চিত করার কোনও উপায় নেই৷</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">ফরওয়ার্ড</translation>
<translation id="7485870689360869515">কোনো ডেটা পাওয়া যায়নি৷</translation>
<translation id="7508255263130623398">ফিরে পাওয়া নীতির ডিভাইস আইডি খালি অথবা বর্তমান ডিভাইস আইডির সাথে মিলছে না</translation>
+<translation id="7511955381719512146">আপনি যে ওয়াই-ফাই-টি ব্যবহার করছেন সেটির জন্য অপনাকে <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />-তে যেতে হতে পারে৷</translation>
<translation id="7514365320538308">ডাউনলোড করুন</translation>
<translation id="7518003948725431193">No webpage was found for the web address: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">এই সাইটে আপনার সংযোগ ব্যক্তিগত নয়</translation>
-<translation id="7535087603100972091">মান</translation>
<translation id="7537536606612762813">বাধ্যতামূলক</translation>
<translation id="7542403920425041731">আপনি নিশ্চিত করলে আপনার কার্ডের বিবরণ এই সাইটের সাথে শেয়ার করা হবে।</translation>
<translation id="7542995811387359312">স্বয়ংক্রিয় ক্রেডিট কার্ড পূরণটি অক্ষম রয়েছে কারণ এই ফর্মটি কোনও সুরক্ষিত সংযোগ ব্যবহার করে না৷</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্র প্রতারণাপূর্ণভাবে ইস্যু করা হয়ে থাকতে পারে। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
<translation id="7568593326407688803">এই পৃষ্ঠাটি<ph name="ORIGINAL_LANGUAGE" />ভাষাতে আছে আপনি কি এটিকে অনুবাদ করতে চাইবেন?</translation>
<translation id="7569952961197462199">Chrome থেকে ক্রেডিট কার্ড সরাবেন?</translation>
-<translation id="7569983096843329377">কালো</translation>
<translation id="7578104083680115302">আপনি Google এর সাথে সংরক্ষণ করেছেন এমন কার্ড ব্যবহার করে ডিভাইস জুড়ে সাইট এবং অ্যাপ্লিকেশানগুলিতে দ্রুত অর্থ পরিশোধ করুন।</translation>
<translation id="7588950540487816470">বাস্তবিক ওয়েব</translation>
<translation id="7592362899630581445">সার্ভারের শংসাপত্র, নামের সীমাবদ্ধতাগুলি লঙ্ঘন করে৷</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">এই সাইটে থাকা আক্রমণকারীরা কৌশলে আপনাকে দিয়ে এমন প্রোগ্রাম ইনস্টল করাতে পারে যা আপনার ব্রাউজিং অভিজ্ঞতার জন্য ক্ষতিকর হতে পারে (উদাহরণস্বরূপ, আপনার হোমপৃষ্ঠা পরিবর্তন করা বা আপনার পরিদর্শিত সাইটগুলিতে অতিরিক্ত বিজ্ঞাপন দেখানো)৷</translation>
<translation id="7674629440242451245">Chrome এর নতুন দুর্দান্ত বৈশিষ্ট্যগুলিতে আগ্রহী? chrome.com/dev এ আমাদের ডেভ চ্যানেল ব্যবহার করে দেখুন৷</translation>
<translation id="7682287625158474539">শিপিং</translation>
+<translation id="7699293099605015246">নিবন্ধ এখন পাওয়া যাবে না</translation>
<translation id="7701040980221191251">কিছুই নয়</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> এ এগিয়ে যান (নিরাপদ নয়) <ph name="END_LINK" /></translation>
<translation id="7714464543167945231">শংসাপত্র</translation>
<translation id="7716147886133743102">আপনার প্রশাসক ব্লক করেছে</translation>
<translation id="7716424297397655342">এই সাইটটি ক্যাশে থেকে লোড করা যাবে না</translation>
+<translation id="7723047071702270851">কার্ড সম্পাদনা করুন</translation>
<translation id="774634243536837715">বিপজ্জনক কন্টেন্ট ব্লক করা হয়েছে।</translation>
<translation id="7752995774971033316">অপরিচালিত</translation>
<translation id="7755287808199759310">আপনার পিতামাতা এটি আপনার জন্য অবরোধ মুক্ত করতে পারবেন</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">ঠিকানা যোগ করুন</translation>
<translation id="777702478322588152">জেলা</translation>
<translation id="7791543448312431591">যুক্ত করুন</translation>
+<translation id="7793553086574152071">পরের বার আরও দ্রুত পেমেন্ট করা জন্য এই কার্ডটি Google অ্যাকাউন্টে সেভ করে রাখুন</translation>
<translation id="7793809570500803535"><ph name="SITE" />-এ থাকা ওয়েবপৃষ্ঠাটি অস্থায়ীভাবে ডাউন থাকতে পারে অথবা এটিকে স্থায়ীভাবে কোনো নতুন ওয়েব ঠিকানাতে সরানো হয়েছে৷</translation>
<translation id="7800304661137206267">বার্তা প্রমাণীকরণ এবং <ph name="KX" />-কে কী এক্সচেঞ্জ নির্মাণকৌশল হিসাবে সংযোগটি <ph name="CIPHER" /> ব্যবহার করে <ph name="MAC" />-এর সাথে এনক্রিপ্ট হয়েছে৷</translation>
+<translation id="7802523362929240268">সাইটটি বৈধ</translation>
<translation id="780301667611848630">না থাক</translation>
<translation id="7805768142964895445">স্থিতি</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome থেকে ফর্ম প্রস্তাবনা সরাবেন?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' এর জন্য <ph name="NUMBER_OF_RESULTS" />টি <ph name="SEARCH_RESULTS" /> খুঁজে পাওয়া গেছে</translation>
+<translation id="782886543891417279">আপনি যে (<ph name="WIFI_NAME" />) Wi-Fiটি ব্যবহার করছেন সেটির জন্য অপনাকে এটির লগ ইন পৃষ্ঠাতে যেতে হতে পরে৷</translation>
<translation id="785549533363645510">আপনি অবশ্য অদৃশ্য থাকবেন না। ছদ্মবেশী মোডে গেলেও তা আপনার নিয়োগকর্তা, আপনার ইন্টারনেট পরিষেবা প্রদানকারী অথবা আপনার পরিদর্শন করা ওয়েবসাইট থেকে আপনার ব্রাউজিংকে আড়াল করবে না।</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">ডেবিট ও প্রিপেড কার্ড গ্রহণ করা হয়।</translation>
+<translation id="7878562273885520351">আপনার পাসওয়ার্ড অন্য কেউ পরিবর্তন করার চেষ্টা করেছে</translation>
<translation id="7887683347370398519">Check your CVC and try again</translation>
<translation id="79338296614623784">একটি সঠিক ফোন নম্বর লিখুন</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">সার্ভারের শংসাপত্র এখনও কার্যকর নয়.</translation>
-<translation id="7942349550061667556">লাল</translation>
<translation id="7947285636476623132">আপনার মেয়াদ শেষের বছর পরীক্ষা করে আবার চেষ্টা করুন</translation>
<translation id="7951415247503192394">(৩২-বিট)</translation>
<translation id="7956713633345437162">মোবাইল বুকমার্ক</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">জিজ্ঞাসা করুন (ডিফল্ট)</translation>
<translation id="8041089156583427627">প্রতিক্রিয়া পাঠান</translation>
<translation id="8041940743680923270">বিশ্বব্যাপী ডিফল্ট ব্যবহার করুন (জানতে চান)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" সঠিকভাবে কনফিগার হয়নি। সাধারণত "<ph name="SOFTWARE_NAME" />" আন-ইনস্টল করা হলে সমস্যার সমাধান হয়ে যায়। <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">নিবন্ধ দেখতে ব্যর্থ হয়েছে৷</translation>
<translation id="8091372947890762290">সার্ভারে সক্রিয়করণ বাকি আছে</translation>
+<translation id="8094917007353911263">আপনি যে নেটওয়ার্কটি ব্যবহার করছেন সেটির জন্য অপনাকে <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />-তে যেতে হতে পারে৷</translation>
+<translation id="8103161714697287722">পেমেন্টের পদ্ধতি</translation>
<translation id="8118489163946903409">পেমেন্টের পদ্ধতি</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" আপনার কম্পিউটার বা নেটওয়ার্কে সঠিক ভাবে ইনস্টল করা হয়নি। আপনার IT প্রশাসককে এই সমস্যাটি সমাধান করতে বলুন।</translation>
<translation id="8131740175452115882">নিশ্চিত হন</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> এর সার্ভার <ph name="BEGIN_ABBR" />DNS ঠিকানা<ph name="END_ABBR" />খুঁজে পাওয়া যায়নি।</translation>
<translation id="8149426793427495338">আপনার কম্পিউটারটি নিদ্রা মোডে গিয়েছে।</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">যদি আপনি এর অর্থের ব্যাপারে নিশ্চিত না হন তাহলে আপনার নেটওয়ার্ক প্রশাসকের সঙ্গে যোগাযোগ করুন৷</translation>
<translation id="8293206222192510085">বুকমার্ক যুক্ত করুন</translation>
<translation id="8294431847097064396">উৎস</translation>
+<translation id="8298115750975731693">আপনি যে (<ph name="WIFI_NAME" />) Wi-Fiটি ব্যবহার করছেন সেটির জন্য অপনাকে <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> তে যেতে হতে পারে৷</translation>
<translation id="8306404619377842860"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> এর সাথে ব্যক্তিগত সংযোগ স্থাপন করা যাবে না কারণ আপনার ডিভাইসের তারিখ ও সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানুন<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">নেটওয়ার্ক সংযোগে কোন সমস্যা হওয়ার কারণে অনুবাদ ব্যর্থ হয়েছে৷</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> এ অ্যাক্সেস অস্বীকার করা হয়েছে</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">সম্প্রতি বন্ধ হয়েছে</translation>
<translation id="8874824191258364635">একটি সঠিক কার্ড নম্বর লিখুন</translation>
<translation id="8876793034577346603">নেটওয়ার্ক কনফিগারেশন বিশ্লেষণ করতে ব্যর্থ হয়েছে৷</translation>
-<translation id="8889402386540077796">রঙ বিন্যাস</translation>
<translation id="8891727572606052622">প্রক্সি মোড অবৈধ৷</translation>
<translation id="889901481107108152">দুঃখিত, এই গবেষণা আপনার প্ল্যাটফর্মে উপলব্ধ নেই৷</translation>
<translation id="8903921497873541725">জুম বাড়ান</translation>
<translation id="8931333241327730545">আপনি কি আপনার Google অ্যাকাউন্টে এই কার্ড সংরক্ষণ করতে চান?</translation>
<translation id="8932102934695377596">আপনার ঘড়ির সময় পিছিয়ে রয়েছে</translation>
+<translation id="893332455753468063">নাম যোগ করুন</translation>
<translation id="8938939909778640821">ক্রেডিট ও প্রিপেড কার্ড গ্রহণ করা হয়</translation>
+<translation id="8957210676456822347">ক্যাপটিভ পোর্টাল অনুমোদন</translation>
<translation id="8971063699422889582">সার্ভারের শংসাপত্রের মেয়াদ ফুরিয়েছে৷</translation>
-<translation id="8986494364107987395">ব্যবহারের পরিসংখ্যান এবং ক্র্যাশ প্রতিবেদনগুলি স্বয়ংক্রিয়ভাবে Google-এ পাঠান</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">সামনের সাইটটিতে ক্ষতিকর প্রোগ্রামগুলি রয়েছে</translation>
<translation id="8997023839087525404">সার্ভারটি এমন একটি শংসাপত্র উপস্থাপন করেছে যেটি শংসাপত্রের স্বচ্ছতার নীতি ব্যবহার করে সর্বজনীনভাবে প্রকাশ করা হয়নি। এটা কিছু শংসাপত্রের জন্য একটি আবশ্যকতা, যাতে করে সেগুলির বিশ্বাসযোগ্যত করা যায় এবং আক্রমণকারীদের বিরুদ্ধে সুরক্ষা নেওয়া যায়।</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> প্রক্সীটির একটি ইউজারনেম এবং পাসওয়ার্ড প্রয়োজন।</translation>
<translation id="9005998258318286617">PDF ডকুমেন্ট লোড করা যায়নি।</translation>
+<translation id="9008201768610948239">উপেক্ষা করুন</translation>
<translation id="901974403500617787">যে ফ্ল্যাগগুলি সমস্ত সিস্টেম জুড়ে প্রয়োগ করা হয় সেগুলি শুধুমাত্র মালিকের দ্বারা সেট করা যেতে পারে: <ph name="OWNER_EMAIL" />৷</translation>
<translation id="9020200922353704812">কার্ডের বিলিং ঠিকানা প্রয়োজন</translation>
<translation id="9020542370529661692">এই পৃষ্ঠাটি <ph name="TARGET_LANGUAGE" /> এ অনুবাদ করা হয়েছে</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">আপনি <ph name="DOMAIN" />-এ পৌছানোর প্রয়াস করছেন, কিন্তু সার্ভার একটি অবৈধ শংসাপত্র উপস্থাপন করেছে|</translation>
<translation id="9050666287014529139">পাসফ্রেজ</translation>
<translation id="9065203028668620118">সম্পাদনা</translation>
-<translation id="9068849894565669697">রঙ বেছে নিন</translation>
<translation id="9069693763241529744">একটি এক্সটেনশন ব্লক করেছে</translation>
<translation id="9076283476770535406">এতে প্রাপ্তবয়স্কদের সামগ্রী থাকতে পারে</translation>
<translation id="9078964945751709336">আরও তথ্য প্রয়োজন</translation>
+<translation id="9080712759204168376">অর্ডারের সারসংক্ষেপ</translation>
<translation id="9103872766612412690"><ph name="SITE" /> সাধারণত আপনার তথ্য সুরক্ষিত রাখতে এনক্রিপশান ব্যবহার করে। এইবার যখন Chromium <ph name="SITE" /> এর সাথে সংযোগ স্থাপন করার চেষ্টা করেছে, তখন ওয়েবসাইটটি অস্বাভাবিক এবং ভুল শংসাপত্র পাঠিয়েছে। হয় একজন আক্রমণকারী <ph name="SITE" /> হওয়ার ভান করছে, অথবা একটি ওয়াই-ফাই প্রবেশ করুন স্ক্রীণ সংযোগকে বাধাপ্রদান করেছে। আপনার তথ্য এখনো নিরাপদ আছে কারণ কোনো ডেটা আদানপ্রদানের আগেই Chromium সংযোগটিকে বন্ধ করে দিয়েছে।</translation>
+<translation id="9106062320799175032">বিলিংয়ের ঠিকানা যোগ করুন</translation>
+<translation id="910908805481542201">এটি ঠিক করতে আমাকে সহায়তা করুন</translation>
+<translation id="9128870381267983090">নেটওয়ার্কে সংযোগ করুন</translation>
<translation id="9137013805542155359">প্রকৃত রূপ দেখান</translation>
<translation id="9137248913990643158">এই অ্যাপ্লিকেশানটি ব্যবহার করার আগে অনুগ্রহ করে শুরু করুন এবং Chrome এ প্রবেশ করুন।</translation>
<translation id="9148507642005240123">&amp;সম্পাদনাকে পূর্বাবস্থায় ফেরান</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> একটি অসমর্থিত প্রোটোকল ব্যবহার করে।</translation>
<translation id="9205078245616868884">আপনার ডেটা আপনার সিঙ্ক পাসফ্রেজ দিয়ে এনক্রিপ্ট করা হয়েছে। সিঙ্ক শুরু করার জন্য এটি লিখুন।</translation>
<translation id="9207861905230894330">নিবন্ধ যোগ করতে ব্যর্থ হয়েছে৷</translation>
+<translation id="9215416866750762878">একটি অ্যাপ্লিকেশন Chrome কে এই সাইটের সাথে নিরাপদভাবে সংযুক্ত হতে বাধা দিচ্ছে</translation>
<translation id="9219103736887031265">ছবিগুলি</translation>
<translation id="933612690413056017">কোনো ইন্টারনেট সংযোগ নেই</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{কিছুই নয়}=1{১টি আইটেম}one{#টি আইটেম}other{#টি আইটেম}}</translation>
<translation id="981121421437150478">অফলাইন</translation>
<translation id="988159990683914416">বিকাশকারী বিল্ড</translation>
+<translation id="989988560359834682">ঠিকানা সম্পাদনা করুন</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" আপনার কম্পিউটার বা নেটওয়ার্কে সঠিকভাবে ইনস্টল করা হয়নি:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" আন-ইনস্টল অথবা অক্ষম করে দেখুন&lt;/li&gt;
+ &lt;li&gt;অন্য ওয়াই-ফাই নেটওয়ার্কের সাথে সংযুক্ত করে দেখুন&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index 49d3e62eb47..3e91e82969b 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Adreces d'interès d'escriptori</translation>
<translation id="1074497978438210769">No segur</translation>
<translation id="1080116354587839789">Ajusta a l'amplada</translation>
+<translation id="1088860948719068836">Afegeix el titular de la targeta</translation>
<translation id="1103523840287552314">Tradueix sempre de: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostra totes les contrasenyes desades...</translation>
<translation id="1107591249535594099">Si s'activa aquesta casella, Chrome emmagatzema una còpia d'aquesta targeta al dispositiu per agilitzar l'emplenament de formularis.</translation>
<translation id="1111153019813902504">Adreces d'interès recents</translation>
<translation id="1113869188872983271">&amp;Desfés el canvi d'ordre</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (informació sincronitzada)</translation>
<translation id="1263231323834454256">Llista de lectura</translation>
<translation id="1264126396475825575">S'ha capturat un informe d'error (<ph name="CRASH_TIME" />) (encara no s'ha penjat ni ignorat)</translation>
+<translation id="1270502636509132238">Mètode de recollida</translation>
<translation id="1281526147609854549">Emès per <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">No tradueixis mai aquest lloc</translation>
<translation id="129553762522093515">Tancades recentment</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">S'està esperant que hi hagi connexió…</translation>
<translation id="153384715582417236">De moment, això és tot</translation>
<translation id="1549470594296187301">Heu d'activar el JavaScript per utilitzar aquesta funció.</translation>
-<translation id="1555130319947370107">Blau</translation>
<translation id="1559528461873125649">No existeix el fitxer o el directori</translation>
<translation id="1583429793053364125">S'ha produït un error en mostrar aquesta pàgina web.</translation>
<translation id="1592005682883173041">Accés a les dades locals</translation>
<translation id="1594030484168838125">Tria</translation>
-<translation id="161042844686301425">Cian</translation>
<translation id="1620510694547887537">Càmera</translation>
<translation id="1629803312968146339">Voleu que Chrome desi aquesta targeta?</translation>
<translation id="1639239467298939599">S'està carregant</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Cal que <ph name="NAME" /> et doni permís per visitar aquest lloc</translation>
<translation id="1721424275792716183">* El camp és obligatori</translation>
+<translation id="1727741090716970331">Afegeix un número de targeta vàlid</translation>
<translation id="1728677426644403582">Estàs consultant el codi font d'una pàgina web</translation>
<translation id="173080396488393970">Aquest tipus de targeta no s'admet</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Error de serialització</translation>
<translation id="1974060860693918893">Configuració avançada</translation>
<translation id="1978555033938440688">Versió del microprogramari</translation>
-<translation id="1995859865337580572">Verifica el CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i 1 aplicació més}other{i # aplicacions més}}</translation>
<translation id="2025186561304664664">El servidor intermediari està definit perquè es configuri automàticament.</translation>
<translation id="2030481566774242610">Volíeu dir <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Inicia la sessió a Chrome perquè Google et suggereixi contingut personalitzat</translation>
+<translation id="2091887806945687916">So</translation>
<translation id="2094505752054353250">Els dominis no coincideixen.</translation>
<translation id="2096368010154057602">Departament</translation>
<translation id="2108755909498034140">Reinicia l'ordinador</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">S'ha ignorat perquè <ph name="POLICY_NAME" /> l'ha substituït.</translation>
<translation id="2138201775715568214">S'estan cercant pàgines del Web físic a prop</translation>
<translation id="213826338245044447">Adreces d'interès per a mòbils</translation>
+<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="2154054054215849342">La sincronització no està disponible per al teu domini</translation>
<translation id="2154484045852737596">Edita la targeta</translation>
<translation id="2166049586286450108">Accés complet d'administrador</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adreça}other{# adreces}}</translation>
<translation id="2187317261103489799">Detecta (opció predeterminada)</translation>
<translation id="2202020181578195191">Introdueix un any de caducitat vàlid</translation>
+<translation id="2209523182407020534">Entre les aplicacions que poden provocar aquest error hi ha l'antivirus, el tallafoc i el programari de filtratge web o del servidor intermediari.</translation>
<translation id="2212735316055980242">No es troba la política</translation>
<translation id="2213606439339815911">S'estan recuperant les entrades...</translation>
<translation id="2218879909401188352">És possible que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instal·lin aplicacions perilloses que malmetin el teu dispositiu, afegeixin càrrecs amagats a la teva factura telefònica o et robin informació personal. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Enrere</translation>
<translation id="2503184589641749290">Targetes de dèbit i de prepagament acceptades</translation>
<translation id="2515629240566999685">Comproveu el senyal a la vostra zona</translation>
+<translation id="2524461107774643265">Afegeix més informació</translation>
+<translation id="2536110899380797252">Afegeix una adreça</translation>
<translation id="2539524384386349900">Detecta</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha enviat una resposta que no és vàlida.</translation>
<translation id="2556876185419854533">&amp;Desfés la modificació</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">En aquest moment Chromium no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
<translation id="2705137772291741111">La còpia desada (a la memòria cau) d'aquest lloc no s'ha pogut llegir.</translation>
<translation id="2709516037105925701">Emplenament autom.</translation>
+<translation id="2710942282213947212">L'ordinador conté programari que impedeix que Chromium es connecti de manera segura al web</translation>
<translation id="2712173769900027643">Demana permís</translation>
-<translation id="2713444072780614174">Blanc</translation>
<translation id="2720342946869265578">A prop</translation>
<translation id="2721148159707890343">Sol·licitud realitzada correctament</translation>
<translation id="2728127805433021124">El certificat del servidor està signat mitjançant un algoritme de signatura dèbil.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">S'ha detectat un canvi a la xarxa.</translation>
<translation id="2916038427272391327">Tanca altres programes</translation>
<translation id="2922350208395188000">No es pot comprovar el certificat del servidor.</translation>
+<translation id="2925673989565098301">Mètode d'entrega</translation>
<translation id="2928905813689894207">Adreça de facturació</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> més}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> més}}</translation>
<translation id="2941952326391522266">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat prové del domini <ph name="DOMAIN2" />. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipus de política incorrecte</translation>
<translation id="3032412215588512954">Voleu tornar a carregar aquest lloc?</translation>
<translation id="3037605927509011580">Oh, no!</translation>
+<translation id="3039538478787849737">Vols desar la targeta a Google?</translation>
<translation id="3041612393474885105">Informació del certificat</translation>
<translation id="3063697135517575841">Chrome no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
<translation id="3064966200440839136">Per pagar amb una aplicació externa sortiràs del mode d'incògnit. Vols continuar?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Error temporal del servidor</translation>
<translation id="3154506275960390542">Aquesta pàgina inclou un formulari que pot ser que no s'enviï de manera segura. La resta d'usuaris poden veure les dades que enviïs mentre estiguin en trànsit o un atacant podria modificar-les per canviar el contingut que rep el servidor.</translation>
<translation id="3157931365184549694">Restaura</translation>
+<translation id="3162559335345991374">És possible que la xarxa Wi-Fi que esteu fent servir requereixi que visiteu la seva pàgina d'inici de sessió.</translation>
<translation id="3167968892399408617">Les pàgines que consulteu en pestanyes d'incògnit no s'emmagatzemaran a l'historial del navegador, al magatzem de galetes ni a l'historial de cerques després d'haver tancat totes les pestanyes d'incògnit. Els fitxers que baixeu i les adreces d'interès que creeu sí que es desaran.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Illa</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancel·la el pagament</translation>
<translation id="3207960819495026254">S'ha afegit a les adreces d'interès.</translation>
+<translation id="3211223744486044430">Perquè la propera vegada puguis pagar més ràpidament, desa la targeta al teu compte de Google i en aquest dispositiu.</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>
<translation id="3226128629678568754">Premeu el botó de tornar a carregar per tornar a enviar les dades necessàries per carregar la pàgina.</translation>
<translation id="3227137524299004712">Micròfon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">No s'ha trobat cap resultat de la cerca</translation>
<translation id="3305707030755673451">Les vostres dades es van encriptar el dia <ph name="TIME" /> amb la vostra frase de contrasenya de sincronització. Introduïu-la per començar la sincronització.</translation>
<translation id="3320021301628644560">Afegeix una adreça de facturació</translation>
-<translation id="3329013043687509092">Saturació</translation>
<translation id="333371639341676808">Evita que aquesta pàgina creï diàlegs addicionals.</translation>
<translation id="3338095232262050444">Segur</translation>
<translation id="3340978935015468852">configuració</translation>
@@ -310,7 +320,7 @@
<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />no desarà<ph name="END_EMPHASIS" /> la informació següent:
<ph name="BEGIN_LIST" />
<ph name="LIST_ITEM" />El teu historial de navegació
- <ph name="LIST_ITEM" />Les galetes i les dades de llocs
+ <ph name="LIST_ITEM" />Les galetes i les dades de llocs web
<ph name="LIST_ITEM" />La informació que introdueixis en formularis
<ph name="END_LIST" /></translation>
<translation id="3369192424181595722">Error de rellotge</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Identificador de client:</translation>
<translation id="3391030046425686457">Adreça d'entrega</translation>
<translation id="3395827396354264108">Mètode de recollida</translation>
+<translation id="3399952811970034796">Adreça d'entrega</translation>
<translation id="3422248202833853650">Prova de sortir d'altres programes per alliberar memòria.</translation>
<translation id="3422472998109090673">Actualment no es pot accedir a <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Permet (opció predeterminada)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Informe d'error generat el <ph name="CRASH_TIME" /> i enviat el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informació del certificat</translation>
<translation id="3690164694835360974">L'inici de sessió no és segur</translation>
+<translation id="3704162925118123524">És possible que la xarxa que esteu fent servir requereixi que visiteu la pàgina d'inici de sessió.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">S'està carregant...</translation>
<translation id="3712624925041724820">Llicències exhaurides</translation>
<translation id="3714780639079136834">Activeu les dades mòbils o la Wi-Fi</translation>
+<translation id="3715597595485130451">Connexió a xarxes Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comproveu el servidor intermediari, el tallafoc i la configuració de DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Si enteneu el risc que suposa per a la vostra seguretat, podeu <ph name="BEGIN_LINK" />visitar aquest lloc no segur<ph name="END_LINK" /> abans que no s'hagin suprimit els programes perillosos.</translation>
<translation id="3739623965217189342">Enllaç que heu copiat</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Desfés l'addició</translation>
<translation id="404928562651467259">ADVERTIMENT</translation>
<translation id="4058922952496707368">Tecla "<ph name="SUBKEY" />": <ph name="ERROR" /></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="4079302484614802869">La configuració del servidor intermediari s'ha definit perquè utilitzi un URL d'script .pac, en lloc de servidors intermedis fixos.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">El número de sèrie del dispositiu no és vàlid</translation>
<translation id="410351446219883937">Reproducció automàtica</translation>
<translation id="4103763322291513355">Visiteu &lt;strong&gt;chrome://policy&lt;/strong&gt; per veure la llista d'URL inclosos a la llista negra i altres polítiques aplicades per l'administrador del sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Permet sempre en aquest lloc</translation>
<translation id="4117700440116928470">L'àmbit de la política no s'admet.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 element més}other{# elements més}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Heu provat d'accedir a <ph name="DOMAIN" />, però l'emissor ha revocat el certificat que ha presentat el servidor. Això vol dir que no heu de confiar gens en les credencials de seguretat que ha presentat el servidor. És possible que us estigueu comunicant amb un atacant.</translation>
<translation id="4394049700291259645">Desactiva</translation>
<translation id="4406896451731180161">resultats de la cerca</translation>
+<translation id="4415426530740016218">Adreça de recollida</translation>
<translation id="4424024547088906515">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Chrome considera que el seu certificat de seguretat no és de confiança. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha acceptat el certificat d'inici de sessió o pot ser que no se n'hagi proporcionat cap.</translation>
<translation id="443673843213245140">L'ús d'un servidor intermediari no està activat, però s'ha especificat una configuració explícita d'un servidor intermediari.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Desactiveu les extensions</translation>
<translation id="457875822857220463">Entrega</translation>
+<translation id="4582800630050655161">Podries perdre l'accés al compte de Google o tenir problemes de suplantació d'identitat. Chromium et recomana que canviïs la contrasenya ara.</translation>
<translation id="4587425331216688090">Voleu suprimir l'adreça de Chrome?</translation>
<translation id="4592951414987517459">La connexió a <ph name="DOMAIN" /> s'ha encriptat amb un sistema de xifratge modern.</translation>
<translation id="4594403342090139922">&amp;Desfés la supressió</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Deixa de fer servir un certificat no vàlid</translation>
+<translation id="4690954380545377795">Podries perdre l'accés al compte de Google o o tenir problemes de suplantació d'identitat. Chrome et recomana que canviïs la contrasenya ara.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">La connexió s'ha interromput</translation>
<translation id="471880041731876836">No tens permís per visitar aquest lloc web</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar el Diagnòstic de xarxa de Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">El teu pagament</translation>
<translation id="4726672564094551039">Torna a carregar les polítiques</translation>
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4736825316280949806">Reinicia Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">L'emmagatzematge de la còpia de seguretat està en mal estat</translation>
<translation id="5023310440958281426">Consulteu les polítiques de l'administrador</translation>
<translation id="5029568752722684782">Esborra la còpia</translation>
+<translation id="503069730517007720"><ph name="SOFTWARE_NAME" /> requereix un certificat arrel, però no està instal·lat. Per resoldre aquest problema, l'administrador de TI ha de consultar les instruccions per configurar <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Sobre el Traductor de Google</translation>
<translation id="5039804452771397117">Permet</translation>
<translation id="5040262127954254034">Privadesa</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experiments</translation>
<translation id="5205222826937269299">El nom és obligatori</translation>
<translation id="5222812217790122047">El correu electrònic és obligatori</translation>
+<translation id="522700295135997067">És possible que aquest lloc web t'acabi de robar la contrasenya</translation>
+<translation id="5230733896359313003">Adreça d'enviament</translation>
<translation id="5251803541071282808">Núvol</translation>
<translation id="5277279256032773186">Fas servir Chrome a la feina? Les empreses poden gestionar la configuració de Chrome dels empleats. Més informació</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Segueix aquests passos per desactivar temporalment el programari perquè puguis accedir al web. Per fer-ho, necessitaràs privilegis d'administrador.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">La teva connexió amb aquest lloc no és privada. Per sortir del mode RV en qualsevol moment, treu-te el visor i prem Enrere.</translation>
<translation id="5299298092464848405">S'ha produït un error en analitzar la política</translation>
+<translation id="5308380583665731573">Connecta</translation>
<translation id="5308689395849655368">La creació d'informes de bloqueig està desactivada.</translation>
<translation id="5317780077021120954">Desa</translation>
<translation id="5327248766486351172">Nom</translation>
+<translation id="5332219387342487447">Mètode d'enviament</translation>
<translation id="5355557959165512791">En aquest moment no pots visitar <ph name="SITE" /> perquè se li ha revocat el certificat. Els atacs i els errors de xarxa acostumen a ser temporals, o sigui que probablement la pàgina funcionarà més endavant.</translation>
<translation id="536296301121032821">No s'ha pogut emmagatzemar la configuració de la política</translation>
<translation id="5386426401304769735">La cadena de certificats d'aquest lloc conté un certificat que s'ha signat amb SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Aquest lloc de la intranet de l'empresa, l'organització o el centre educatiu té el mateix URL que un lloc web extern.
<ph name="LINE_BREAK" />
Proveu de contactar amb l'administrador del sistema.</translation>
+<translation id="5499929369096410817">Introdueix el codi de seguretat de la targeta <ph name="CREDIT_CARD" />. Aquest codi no es desarà.</translation>
<translation id="5509780412636533143">Adreces d'interès gestionades</translation>
<translation id="5510766032865166053">És possible que s'hagi mogut o s'hagi suprimit.</translation>
<translation id="5523118979700054094">Nom de la política</translation>
<translation id="552553974213252141">S'ha extret correctament el text?</translation>
<translation id="5540224163453853">No s'ha pogut trobar l'article sol·licitat.</translation>
+<translation id="5541546772353173584">Afegeix un correu electrònic</translation>
<translation id="5544037170328430102">Una pàgina inserida a <ph name="SITE" /> diu:</translation>
+<translation id="5545756402275714221">Articles que et poden interessar</translation>
<translation id="5556459405103347317">Torna a carregar</translation>
<translation id="5560088892362098740">Data de caducitat</translation>
<translation id="5565735124758917034">Actiu</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Correu electrònic</translation>
<translation id="5669703222995421982">Obtén contingut personalitzat</translation>
<translation id="5675650730144413517">Aquesta pàgina no funciona</translation>
+<translation id="5689199277474810259">Exporta a JSON</translation>
<translation id="5710435578057952990">La identitat d'aquest lloc web no ha estat verificada.</translation>
<translation id="5719499550583120431">S'accepten targetes de prepagament.</translation>
<translation id="5720705177508910913">Usuari actual</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">La connexió a <ph name="DOMAIN" /> s'ha encriptat amb un sistema de xifratge obsolet.</translation>
<translation id="5813119285467412249">&amp;Refés l'addició</translation>
<translation id="5838278095973806738">No introdueixis informació confidencial en aquest lloc (com ara contrasenyes o targetes de crèdit), ja que alguns atacants podrien robar-la.</translation>
+<translation id="5866257070973731571">Afegeix un número de telèfon</translation>
<translation id="5869405914158311789">No es pot accedir a aquest lloc</translation>
<translation id="5869522115854928033">Contrasenyes desades</translation>
<translation id="5872918882028971132">Suggeriments per als responsables</translation>
<translation id="5893752035575986141">S'accepten targetes de crèdit.</translation>
-<translation id="5901630391730855834">Groc</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (informació sincronitzada)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 en ús}other{# en ús}}</translation>
<translation id="5959728338436674663">Envia automàticament algunes <ph name="BEGIN_WHITEPAPER_LINK" />dades del sistema i contingut de les pàgines<ph name="END_WHITEPAPER_LINK" /> a Google per ajudar a detectar les aplicacions i els llocs perillosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edita la informació de contacte</translation>
<translation id="5967867314010545767">Elimina de l'historial</translation>
<translation id="5975083100439434680">Redueix</translation>
+<translation id="597552863672748783">Confirma el codi de seguretat</translation>
<translation id="598637245381783098">No es pot obrir l'aplicació de pagament</translation>
<translation id="5989320800837274978">No s'especifiquen servidors intermediaris ni URL d'script .pac.</translation>
<translation id="5990559369517809815">Una extensió ha bloquejat les peticions al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pàgina 1}other{Pàgina #}}</translation>
-<translation id="6017514345406065928">Verd</translation>
<translation id="6017850046339264347">Pot ser que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instal·lin aplicacions enganyoses que es facin passar per qui no són o recopilin dades que podrien utilitzar-se per fer un seguiment de la teva activitat. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (informació sincronitzada)</translation>
<translation id="6027201098523975773">Escriu un nom</translation>
<translation id="6040143037577758943">Tanca</translation>
-<translation id="6042308850641462728">Més</translation>
<translation id="6047233362582046994">Si entens el risc que suposa per a la teva seguretat, pots <ph name="BEGIN_LINK" />visitar aquest lloc web<ph name="END_LINK" /> abans que no s'hagin suprimit les aplicacions perjudicials.</translation>
<translation id="6047927260846328439">Aquest contingut pot provar d'enganyar-te perquè instal·lis programari o proporcionis informació personal. <ph name="BEGIN_LINK" />Mostra igualment<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">En aquests moments no pots visitar <ph name="SITE" /> perquè el lloc web fa servir una fixació de certificat. Els atacs i els errors de xarxa acostumen a ser temporals, o sigui que probablement la pàgina funcionarà més endavant.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Estàs consultant la pàgina d'una extensió</translation>
<translation id="6596325263575161958">Opcions d'encriptació</translation>
<translation id="662080504995468778">No surtis</translation>
+<translation id="6624427990725312378">Informació de contacte</translation>
<translation id="6626291197371920147">Afegeix un número de targeta vàlid</translation>
<translation id="6628463337424475685">Cerca de <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">És possible que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> provin d'instal·lar programes perillosos a l'ordinador Mac per robar-te o suprimir-te informació (per exemple, fotos, contrasenyes, missatges i targetes de crèdit). <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Escriviu el terme de cerca&gt;</translation>
<translation id="6711464428925977395">Hi ha hagut algun problema amb el servidor intermediari o l'adreça no és correcta.</translation>
-<translation id="6727102863431372879">Configura</translation>
<translation id="674375294223700098">Error de certificat del servidor desconegut.</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositiu ha entrat en mode de repòs.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Camí del perfil</translation>
<translation id="7424977062513257142">Una pàgina inserida en aquesta pàgina web diu:</translation>
+<translation id="7437289804838430631">Afegeix informació de contacte</translation>
<translation id="7441627299479586546">Usuari de la política incorrecte</translation>
<translation id="7444046173054089907">Aquest lloc està bloquejat</translation>
<translation id="7445762425076701745">La identitat del servidor al qual esteu connectat no es pot acabar de validar. Esteu connectat a un servidor que utilitza un nom que només és vàlid dins la vostra xarxa, de manera que una autoritat de certificació externa no en pot validar la propietat. Com que de tota manera algunes autoritats de certificació emetran certificats per a aquests noms, no es pot assegurar que estigueu connectat al lloc web previst i no a un atacant.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Endavant</translation>
<translation id="7485870689360869515">No s'han trobat dades.</translation>
<translation id="7508255263130623398">L'identificador de dispositiu de la política que s'ha tornat és buit o no coincideix amb l'actual</translation>
+<translation id="7511955381719512146">És possible que la xarxa Wi-Fi que esteu fent servir requereixi que visiteu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Baixa</translation>
<translation id="7518003948725431193">No s'ha trobat cap pàgina web per a l'adreça: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">La connexió amb aquest lloc no és privada</translation>
-<translation id="7535087603100972091">Valor</translation>
<translation id="7537536606612762813">Obligatòria</translation>
<translation id="7542403920425041731">Un cop confirmada, els detalls de la targeta es compartiran amb aquest lloc web.</translation>
<translation id="7542995811387359312">L'emplenament automàtic de targetes de crèdit està desactivat perquè el formulari no utilitza una connexió segura.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè és possible que el seu certificat de seguretat s'hagi emès de manera fraudulenta. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="7568593326407688803">Aquesta pàgina està en<ph name="ORIGINAL_LANGUAGE" />Voleu traduir-la?</translation>
<translation id="7569952961197462199">Voleu suprimir la targeta de crèdit de Chrome?</translation>
-<translation id="7569983096843329377">Negre</translation>
<translation id="7578104083680115302">Agilitzeu els pagaments en llocs i en aplicacions des de qualsevol dispositiu mitjançant les targetes que hàgiu desat a Google.</translation>
<translation id="7588950540487816470">El Web físic</translation>
<translation id="7592362899630581445">El certificat del servidor incompleix les restriccions de nom.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">És possible que els atacants d'aquest lloc intentin enganyar-te perquè instal·lis programes que perjudiquen la teva navegació (per exemple, et poden canviar la pàgina d'inici o mostrar anuncis addicionals als llocs que visites).</translation>
<translation id="7674629440242451245">Esteu interessat en les funcions de Chrome noves i interessants? Proveu el nostre canal per a desenvolupadors a la pàgina chrome.com/dev.</translation>
<translation id="7682287625158474539">Enviament</translation>
+<translation id="7699293099605015246">En aquests moments no hi ha articles disponibles</translation>
<translation id="7701040980221191251">Cap</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continua per accedir a <ph name="SITE" /> (no segur)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificat</translation>
<translation id="7716147886133743102">Bloquejat per l'administrador</translation>
<translation id="7716424297397655342">Aquest lloc no es pot carregar des de la memòria cau</translation>
+<translation id="7723047071702270851">Edita la targeta</translation>
<translation id="774634243536837715">S'ha bloquejat el contingut perillós.</translation>
<translation id="7752995774971033316">Sense gestionar</translation>
<translation id="7755287808199759310">El teu pare o la teva mare et poden desbloquejar el lloc</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Afegeix una adreça</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Afegeix</translation>
+<translation id="7793553086574152071">Perquè la propera vegada puguis pagar més ràpidament, desa la targeta al teu compte de Google.</translation>
<translation id="7793809570500803535">És possible que la pàgina web de <ph name="SITE" /> estigui temporalment inactiva o que s'hagi desplaçat permanentment a una adreça web nova.</translation>
<translation id="7800304661137206267">La connexió està encriptada mitjançant <ph name="CIPHER" />, amb <ph name="MAC" /> per a l'autenticació de missatges i amb <ph name="KX" /> com a mecanisme d'intercanvi clau.</translation>
+<translation id="7802523362929240268">El lloc web és legítim</translation>
<translation id="780301667611848630">No, gràcies</translation>
<translation id="7805768142964895445">Estat</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Voleu suprimir el suggeriment de formulari de Chrome?</translation>
<translation id="7815407501681723534">S'han trobat <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> per a "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">És possible que la xarxa Wi-Fi (<ph name="WIFI_NAME" />) que esteu fent servir requereixi que visiteu la seva pàgina d'inici de sessió.</translation>
<translation id="785549533363645510">Tanmateix, no sou invisible. La vostra empresa, el vostre proveïdor de serveis d'Internet i els llocs web que visiteu poden veure la vostra navegació d'incògnit.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">S'accepten targetes de dèbit i de prepagament.</translation>
+<translation id="7878562273885520351">La teva contrasenya pot estar en perill</translation>
<translation id="7887683347370398519">Comproveu el CVC i torneu-ho a provar</translation>
<translation id="79338296614623784">Introdueix un número de telèfon vàlid</translation>
<translation id="7935318582918952113">Destil·lador DOM</translation>
<translation id="7938958445268990899">El certificat del servidor encara no és vàlid.</translation>
-<translation id="7942349550061667556">Vermell</translation>
<translation id="7947285636476623132">Comprova l'any de caducitat i torna-ho a provar</translation>
<translation id="7951415247503192394">(32 bits)</translation>
<translation id="7956713633345437162">Adreces d'interès per a mòbils</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Pregunta (opció predeterminada)</translation>
<translation id="8041089156583427627">Envia suggeriments</translation>
<translation id="8041940743680923270">Utilitza l'opció predeterminada global (Pregunta)</translation>
+<translation id="8057711352706143257"><ph name="SOFTWARE_NAME" /> no s'ha configurat correctament. Normalment el problema se soluciona desinstal·lant <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">No s'ha pogut consultar l'article.</translation>
<translation id="8091372947890762290">L'activació està pendent al servidor</translation>
+<translation id="8094917007353911263">És possible que la xarxa que esteu fent servir requereixi que visiteu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Mètode de pagament</translation>
<translation id="8118489163946903409">Mètode de pagament</translation>
+<translation id="8127301229239896662"><ph name="SOFTWARE_NAME" /> no s'ha instal·lat correctament a l'ordinador o a la xarxa. Demana a l'administrador de TI que resolgui aquest problema.</translation>
<translation id="8131740175452115882">Confirma</translation>
<translation id="8134994873729925007">No s'ha trobat l'<ph name="BEGIN_ABBR" />adreça DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">L'ordinador ha entrat en mode de repòs.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Si no esteu segur de què significa això, contacteu amb l'administrador de la xarxa.</translation>
<translation id="8293206222192510085">Afegeix una adreça d'interès</translation>
<translation id="8294431847097064396">Font</translation>
+<translation id="8298115750975731693">És possible que la xarxa Wi-Fi (<ph name="WIFI_NAME" />) que esteu fent servir requereixi que visiteu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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 del dispositiu (<ph name="DATE_AND_TIME" />) no són correctes. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">No s'ha pogut executar la traducció a causa d'un problema amb la connexió de xarxa.</translation>
<translation id="8332188693563227489">S'ha rebutjat l'accés a <ph name="HOST_NAME" /></translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Tancades recentment</translation>
<translation id="8874824191258364635">Introdueix un número de targeta vàlid</translation>
<translation id="8876793034577346603">No s'ha pogut analitzar la configuració de la xarxa.</translation>
-<translation id="8889402386540077796">To</translation>
<translation id="8891727572606052622">El mode de servidor intermediari no és vàlid.</translation>
<translation id="889901481107108152">Aquest experiment no està disponible a la vostra plataforma.</translation>
<translation id="8903921497873541725">Amplia</translation>
<translation id="8931333241327730545">Voleu desar aquesta targeta al vostre compte de Google?</translation>
<translation id="8932102934695377596">El rellotge està endarrerit</translation>
+<translation id="893332455753468063">Afegeix un nom</translation>
<translation id="8938939909778640821">Targetes de crèdit i de prepagament acceptades</translation>
+<translation id="8957210676456822347">Autorització de portals captius</translation>
<translation id="8971063699422889582">El certificat del servidor ha caducat.</translation>
-<translation id="8986494364107987395">Envia automàticament estadístiques d'ús i informes d'error a Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Aquest lloc web conté programes perjudicials</translation>
<translation id="8997023839087525404">El servidor ha presentat un certificat que no s'ha divulgat públicament mitjançant la política Transparència de certificats. Això és un requisit d'alguns certificats per garantir que són de confiança i una mesura de protecció contra els atacants.</translation>
<translation id="9001074447101275817">El servidor intermediari del domini <ph name="DOMAIN" /> requereix un nom d'usuari i una contrasenya.</translation>
<translation id="9005998258318286617">No es pot carregar el document PDF.</translation>
+<translation id="9008201768610948239">Ignora</translation>
<translation id="901974403500617787">Les marques que s'apliquen a tot el sistema només les pot definir l'usuari: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Es requereix l'adreça de facturació de la targeta</translation>
<translation id="9020542370529661692">Aquesta pàgina s'ha traduït a <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Heu provat d'accedir a <ph name="DOMAIN" />, però el servidor ha presentat un certificat no vàlid.</translation>
<translation id="9050666287014529139">Frase de contrasenya</translation>
<translation id="9065203028668620118">Edita</translation>
-<translation id="9068849894565669697">Selecció de color</translation>
<translation id="9069693763241529744">Bloquejat per una extensió</translation>
<translation id="9076283476770535406">Pot incloure contingut per a adults</translation>
<translation id="9078964945751709336">Necessitem més informació</translation>
+<translation id="9080712759204168376">Resum de la comanda</translation>
<translation id="9103872766612412690"><ph name="SITE" /> utilitza normalment l'encriptació per protegir la vostra informació. En aquesta ocasió, quan Chromium ha provat de connectar-se a <ph name="SITE" />, el lloc web ha enviat credencials poc comunes i incorrectes. Pot ser que un atacant estigui provant de fer-se passar per <ph name="SITE" /> o que una pantalla d'inici de sessió a la xarxa Wi-Fi hagi interromput la connexió. En qualsevol cas, la vostra informació continua estant segura, perquè Chromium ha aturat la connexió abans no s'intercanviés cap dada.</translation>
+<translation id="9106062320799175032">Afegeix una adreça de facturació</translation>
+<translation id="910908805481542201">Ajuda'm a solucionar-ho</translation>
+<translation id="9128870381267983090">Connecteu-vos a la xarxa</translation>
<translation id="9137013805542155359">Mostra l'original</translation>
<translation id="9137248913990643158">Obre Chrome i inicia-hi la sessió abans d'utilitzar aquesta aplicació.</translation>
<translation id="9148507642005240123">&amp;Desfés la modificació</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> fa servir un protocol no admès.</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="9215416866750762878">Una aplicació impedeix que Chrome es connecti de manera segura a aquest lloc web</translation>
<translation id="9219103736887031265">Imatges</translation>
<translation id="933612690413056017">No hi ha connexió a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Cap}=1{1 element}other{# elements}}</translation>
<translation id="981121421437150478">Sense connexió</translation>
<translation id="988159990683914416">Muntatge del desenvolupador</translation>
+<translation id="989988560359834682">Edita l'adreça</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401"><ph name="SOFTWARE_NAME" /> no s'ha instal·lat correctament a l'ordinador o a la xarxa:
+ &lt;ul&gt;
+ &lt;li&gt;Prova de desinstal·lar o desactivar <ph name="SOFTWARE_NAME" />&lt;/li&gt;
+ &lt;li&gt;Prova de connectar-te a una altra xarxa&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index 3d00483e122..3b316e45b2b 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Záložky v PC</translation>
<translation id="1074497978438210769">Nezabezpečeno</translation>
<translation id="1080116354587839789">Přizpůsobit na šířku</translation>
+<translation id="1088860948719068836">Přidání jména na kartě</translation>
<translation id="1103523840287552314">Vždy překládat jazyk <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Zobrazit všechna uložená hesla...</translation>
<translation id="1107591249535594099">Pokud je tato možnost zaškrtnuta, Chrome v tomto zařízení bude za účelem rychlejšího vyplňování formulářů uchovávat kopii vaší karty.</translation>
<translation id="1111153019813902504">Nejnovější záložky</translation>
<translation id="1113869188872983271">&amp;Vrátit změnu uspořádání zpět</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synchronizováno)</translation>
<translation id="1263231323834454256">Seznam četby</translation>
<translation id="1264126396475825575">Zpráva o selhání pořízená <ph name="CRASH_TIME" /> (dosud nenahrána nebo ignorována)</translation>
+<translation id="1270502636509132238">Způsob vyzvednutí</translation>
<translation id="1281526147609854549">Vydavatel: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Tento web nikdy nepřekládat</translation>
<translation id="129553762522093515">Nedávno zavřené</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Čeká se na připojení…</translation>
<translation id="153384715582417236">To je prozatím vše</translation>
<translation id="1549470594296187301">Chcete-li tuto funkci použít, musí být aktivován JavaScript.</translation>
-<translation id="1555130319947370107">Modrá</translation>
<translation id="1559528461873125649">Daný soubor nebo adresář neexistuje.</translation>
<translation id="1583429793053364125">Při zobrazování této webové stránky došlo k chybě.</translation>
<translation id="1592005682883173041">Přístup k místním datům</translation>
<translation id="1594030484168838125">Zvolit</translation>
-<translation id="161042844686301425">Azurová</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Chcete, aby Chrome tuto kartu uložil?</translation>
<translation id="1639239467298939599">Načítání</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Operační systém</translation>
<translation id="1721312023322545264">Zdá se, že k návštěvě tohoto webu potřebujete povolení od správce <ph name="NAME" /></translation>
<translation id="1721424275792716183">* Pole je povinné</translation>
+<translation id="1727741090716970331">Přidání platného čísla karty</translation>
<translation id="1728677426644403582">Prohlížíte si zdrojový kód webové stránky</translation>
<translation id="173080396488393970">Tento typ karty není podporován</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Chyba serializace</translation>
<translation id="1974060860693918893">Rozšířená nastavení</translation>
<translation id="1978555033938440688">Verze firmwaru</translation>
-<translation id="1995859865337580572">Ověřte kód CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{a 1 další}few{a # další}many{a # další}other{a # dalších}}</translation>
<translation id="2025186561304664664">Proxy server je nastaven na automatickou konfiguraci.</translation>
<translation id="2030481566774242610">Měli jste na mysli <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474" />
<translation id="20817612488360358">Jako aktivní jsou nakonfigurována systémová nastavení proxy serveru, je však určena i explicitní konfigurace proxy serveru.</translation>
<translation id="2086652334978798447">Chcete-li od Googlu získat personalizované návrhy obsahu, přihlaste se do Chromu.</translation>
+<translation id="2091887806945687916">Zvuk</translation>
<translation id="2094505752054353250">Neshoda domén</translation>
<translation id="2096368010154057602">Oddělení</translation>
<translation id="2108755909498034140">Restartujte počítač</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Zásada ignorována, protože bylo přepsána zásadou <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Vyhledávání stránek fyzického webu v okolí</translation>
<translation id="213826338245044447">Mobilní záložky</translation>
+<translation id="214556005048008348">Zrušit platbu</translation>
<translation id="2147827593068025794">Synchronizace na pozadí</translation>
+<translation id="2148613324460538318">Přidat kartu</translation>
<translation id="2154054054215849342">Synchronizace není pro vaši doménu k dispozici</translation>
<translation id="2154484045852737596">Úprava karty</translation>
<translation id="2166049586286450108">Úplný přístup administrátora</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adres}}</translation>
<translation id="2187317261103489799">Rozpoznat (výchozí)</translation>
<translation id="2202020181578195191">Zadejte platný rok vypršení platnosti</translation>
+<translation id="2209523182407020534">Tuto chybu mohou způsobovat aplikace, jako jsou antivirové programy, firewally a software na filtrování nebo zprostředkování webového provozu.</translation>
<translation id="2212735316055980242">Zásada nebyla nalezena</translation>
<translation id="2213606439339815911">Načítání záznamů...</translation>
<translation id="2218879909401188352">Útočníci, kteří na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> aktuálně působí, by vám do zařízení mohli nainstalovat nebezpečné aplikace, které jej poškodí, přidat skryté poplatky na účet za mobilní služby nebo odcizit osobní údaje. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Zpět</translation>
<translation id="2503184589641749290">Přijímané debetní a předplacené karty</translation>
<translation id="2515629240566999685">Zkontrolovat, zda máte dostatečně silný signál</translation>
+<translation id="2524461107774643265">Přidání dalších informací</translation>
+<translation id="2536110899380797252">Přidat adresu</translation>
<translation id="2539524384386349900">Rozpoznat</translation>
<translation id="255002559098805027">Web <ph name="HOST_NAME" /> vrátil neplatnou odpověď.</translation>
<translation id="2556876185419854533">&amp;Vrátit úpravy zpět</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Prohlížeč Chromium vaši kartu aktuálně nemohl ověřit. Zkuste to prosím znovu později.</translation>
<translation id="2705137772291741111">Kopii tohoto webu uloženou v mezipaměti se nepodařilo přečíst.</translation>
<translation id="2709516037105925701">Automatické vyplňování</translation>
+<translation id="2710942282213947212">Software na počítači brání prohlížeči Chromium v bezpečném připojení k webu</translation>
<translation id="2712173769900027643">Požádat o oprávnění</translation>
-<translation id="2713444072780614174">Bílá</translation>
<translation id="2720342946869265578">Nablízku</translation>
<translation id="2721148159707890343">Požadavek byl úspěšný</translation>
<translation id="2728127805433021124">Certifikát serveru je podepsán slabým algoritmem.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Byla zjištěna změna sítě.</translation>
<translation id="2916038427272391327">Zavřete ostatní programy</translation>
<translation id="2922350208395188000">Certifikát serveru nelze zkontrolovat.</translation>
+<translation id="2925673989565098301">Způsob doručení</translation>
<translation id="2928905813689894207">Fakturační adresa</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> další}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> dalších}}</translation>
<translation id="2941952326391522266">Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Jeho bezpečnostní certifikát pochází z domény <ph name="DOMAIN2" />. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Chybný typ zásady</translation>
<translation id="3032412215588512954">Chcete tento web načíst znovu?</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
+<translation id="3039538478787849737">Uložit kartu do Googlu?</translation>
<translation id="3041612393474885105">Informace o certifikátu</translation>
<translation id="3063697135517575841">Chrome vaši kartu aktuálně nemohl ověřit. Zkuste to prosím znovu později.</translation>
<translation id="3064966200440839136">Chystáte se opustit anonymní režim, abyste mohli zaplatit v externí aplikaci. Chcete pokračovat?</translation>
@@ -278,12 +287,14 @@
<translation id="3150653042067488994">Dočasná chyba serveru</translation>
<translation id="3154506275960390542">Tato stránka obsahuje formulář, který zřejmě nebude možné bezpečně odeslat. Odeslaná data mohou při přenosu zobrazit jiní uživatelé a případný útočník je může změnit, a server tudíž přijme něco jiného, než jste odeslali.</translation>
<translation id="3157931365184549694">Obnovit</translation>
+<translation id="3162559335345991374">Síť Wi-Fi, kterou používáte, může vyžadovat, abyste navštívili její stránku přihlášení.</translation>
<translation id="3167968892399408617">Stránky, které otevřete na anonymních kartách, po zavření všech anonymních karet nezanechají žádné stopy v historii prohlížeče, v úložišti souborů cookie ani v historii vyhledávání. Zachovány však zůstanou všechny stažené soubory a vytvořené záložky.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ostrov</translation>
<translation id="3176929007561373547">Zkontrolujte nastavení proxy serveru nebo se obraťte na správce sítě, aby ověřil, zda proxy server funguje. Pokud se domníváte, že by proxy server neměl být používán: <ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Zrušit platbu</translation>
<translation id="3207960819495026254">Přidáno do záložek</translation>
+<translation id="3211223744486044430">Abyste příště mohli zaplatit rychleji, uložte si tuto kartu do účtu Google nebo na toto zařízení.</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>
<translation id="3226128629678568754">Klikněte na tlačítko Načíst znovu. Tím znovu odešlete údaje potřebné k načtení stránky.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -298,7 +309,6 @@
<translation id="3303855915957856445">Nebyly nalezeny žádné výsledky</translation>
<translation id="3305707030755673451">Vaše data byla <ph name="TIME" /> zašifrována pomocí heslové fráze pro synchronizaci. Chcete-li zahájit synchronizaci, zadejte ji.</translation>
<translation id="3320021301628644560">Přidání fakturační adresy</translation>
-<translation id="3329013043687509092">Sytost</translation>
<translation id="333371639341676808">Bránit této stránce ve vytváření dalších dialogových oken.</translation>
<translation id="3338095232262050444">Zabezpečeno</translation>
<translation id="3340978935015468852">nastavení</translation>
@@ -317,6 +327,7 @@
<translation id="3380864720620200369">Číslo klienta:</translation>
<translation id="3391030046425686457">Adresa doručení</translation>
<translation id="3395827396354264108">Způsob vyzvednutí</translation>
+<translation id="3399952811970034796">Adresa doručení</translation>
<translation id="3422248202833853650">Zkuste uvolnit paměť ukončením jiných programů.</translation>
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> momentálně není dostupný.</translation>
<translation id="3427092606871434483">Povolit (výchozí)</translation>
@@ -361,10 +372,12 @@
<translation id="3679803492151881375">Zpráva o selhání pořízená <ph name="CRASH_TIME" /> byla nahrána <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informace o certifikátu</translation>
<translation id="3690164694835360974">Přihlášení není zabezpečené</translation>
+<translation id="3704162925118123524">Síť, kterou používáte, může vyžadovat, abyste navštívili její stránku přihlášení.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Načítání...</translation>
<translation id="3712624925041724820">Byly vyčerpány licence</translation>
<translation id="3714780639079136834">Zapnout mobilní datové připojení nebo Wi-Fi</translation>
+<translation id="3715597595485130451">Připojení k síti Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Zkontrolovat proxy server, firewall a konfiguraci DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Pokud bezpečnostní rizika chápete, můžete <ph name="BEGIN_LINK" />tento nespolehlivý web navštívit<ph name="END_LINK" /> ještě před tím, než budou nebezpečné programy odstraněny.</translation>
<translation id="3739623965217189342">Zkopírovaný odkaz</translation>
@@ -399,6 +412,7 @@
<translation id="4030383055268325496">&amp;Vrátit přidání zpět</translation>
<translation id="404928562651467259">UPOZORNĚNÍ</translation>
<translation id="4058922952496707368">Klíč <ph name="SUBKEY" />: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxy je nastaveno na používání adresy URL skriptu PAC, nikoliv pevně daných serverů proxy.</translation>
@@ -406,7 +420,6 @@
<translation id="4103249731201008433">Sériové číslo zařízení je neplatné</translation>
<translation id="410351446219883937">Automatické přehrávání</translation>
<translation id="4103763322291513355">Na stránce &lt;strong&gt;chrome://policy&lt;/strong&gt; naleznete seznam zakázaných adres URL a další zásady vynucené vaším správcem systému.</translation>
-<translation id="4115378294792113321">Purpurová</translation>
<translation id="4116663294526079822">Povolit vždy na tomto webu</translation>
<translation id="4117700440116928470">Rozsah zásady není podporován.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 další}few{# další}many{# další}other{# dalších}}</translation>
@@ -444,6 +457,7 @@
<translation id="4377125064752653719">Pokusili jste se přejít na web <ph name="DOMAIN" />, ale certifikát prezentovaný tímto webem byl vydavatelem certifikátu zrušen. To znamená, že bezpečnostním pověřením, která web prezentoval, nelze zcela důvěřovat. Je možné, že komunikujete s útočníkem.</translation>
<translation id="4394049700291259645">Deaktivovat</translation>
<translation id="4406896451731180161">výsledky vyhledávání</translation>
+<translation id="4415426530740016218">Adresa vyzvednutí</translation>
<translation id="4424024547088906515">Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Chrome jeho bezpečnostnímu certifikátu nedůvěřuje. 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="4432688616882109544">Web <ph name="HOST_NAME" /> nepřijal přihlašovací certifikát, případně žádný certifikát nebyl poskytnut.</translation>
<translation id="443673843213245140">Využití proxy serveru je zakázáno, je však určena explicitní konfigurace proxy serveru.</translation>
@@ -456,6 +470,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Zkuste zakázat rozšíření.</translation>
<translation id="457875822857220463">Doručení</translation>
+<translation id="4582800630050655161">Mohli byste ztratit přístup k účtu Google nebo by mohlo dojít k odcizení vaší identity. Chromium doporučuje okamžitě změnit heslo.</translation>
<translation id="4587425331216688090">Odstranit adresu z Chromu?</translation>
<translation id="4592951414987517459">Vaše připojení k doméně <ph name="DOMAIN" /> je šifrováno za použití moderní šifrovací sady.</translation>
<translation id="4594403342090139922">&amp;Vrátit smazání zpět</translation>
@@ -464,10 +479,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Přestat používat neplatný certifikát</translation>
+<translation id="4690954380545377795">Mohli byste ztratit přístup k účtu Google nebo by mohlo dojít k odcizení vaší identity. Chrome doporučuje okamžitě změnit heslo.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Připojení bylo přerušeno</translation>
<translation id="471880041731876836">K návštěvě tohoto webu nemáte povolení</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Spustit Diagnostiku sítě systému Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Vaše platba</translation>
<translation id="4726672564094551039">Znovu načíst zásady</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Restartujte Chromium</translation>
@@ -506,6 +523,7 @@
<translation id="5019198164206649151">Záložní úložiště je ve špatném stavu</translation>
<translation id="5023310440958281426">Zkontrolujte zásady svého správce</translation>
<translation id="5029568752722684782">Vymazat kopii</translation>
+<translation id="503069730517007720">Je vyžadován kořenový certifikát pro software <ph name="SOFTWARE_NAME" />, ale není nainstalován. Při řešení tohoto problému by si měl administrátor IT prostudovat pokyny ke konfiguraci softwaru <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">O Překladači Google</translation>
<translation id="5039804452771397117">Povolit</translation>
<translation id="5040262127954254034">Ochrana soukromí</translation>
@@ -529,6 +547,8 @@
<translation id="5199729219167945352">Experimenty</translation>
<translation id="5205222826937269299">Je nutné zadat jméno</translation>
<translation id="5222812217790122047">Je nutné zadat e-mail</translation>
+<translation id="522700295135997067">Tento web vám možná právě odcizil heslo</translation>
+<translation id="5230733896359313003">Dodací adresa</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Používáte Chrome v práci? Firmy mohou spravovat nastavení prohlížeče Chrome pro své zaměstnance. Další informace</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Abyste se mohli dostat na web, podle těchto pokynů software dočasně zakažte. Budete potřebovat administrátorská práva.<ph name="END_PARAGRAPH" />
@@ -543,9 +563,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Připojení k tomuto webu není soukromé. Režim VR můžete kdykoliv ukončit tím, že sejmete náhlavní soupravu a stisknete tlačítko Zpět.</translation>
<translation id="5299298092464848405">Při analýze zásady došlo k chybě</translation>
+<translation id="5308380583665731573">Připojení</translation>
<translation id="5308689395849655368">Zprávy o selhání jsou zakázány.</translation>
<translation id="5317780077021120954">Uložit</translation>
<translation id="5327248766486351172">Název</translation>
+<translation id="5332219387342487447">Způsob dopravy</translation>
<translation id="5355557959165512791">Web <ph name="SITE" /> nyní nemůžete navštívit, protože jeho certifikát byl zrušen. Síťové chyby a útoky jsou obvykle dočasné, tato stránka pravděpodobně později bude fungovat.</translation>
<translation id="536296301121032821">Ukládání nastavení zásady se nezdařilo</translation>
<translation id="5386426401304769735">Řetězec certifikátů tohoto webu obsahuje certifikát podepsaný algoritmem SHA-1.</translation>
@@ -565,12 +587,15 @@
<translation id="5492298309214877701">Tato stránka v intranetu společnosti, organizace nebo školy má stejnou adresu URL jako externí web.
<ph name="LINE_BREAK" />
Kontaktujte administrátora systému.</translation>
+<translation id="5499929369096410817">Zadejte bezpečnostní kód pro kartu <ph name="CREDIT_CARD" />. Tento kód se neuloží.</translation>
<translation id="5509780412636533143">Spravované záložky</translation>
<translation id="5510766032865166053">Soubor mohl být přesunut nebo smazán.</translation>
<translation id="5523118979700054094">Název zásady</translation>
<translation id="552553974213252141">Byl text extrahován správně?</translation>
<translation id="5540224163453853">Požadovaný článek nebyl nalezen.</translation>
+<translation id="5541546772353173584">Přidání e-mailu</translation>
<translation id="5544037170328430102">Vložená stránka na webu <ph name="SITE" /> říká:</translation>
+<translation id="5545756402275714221">Články pro vás</translation>
<translation id="5556459405103347317">Načíst znovu</translation>
<translation id="5560088892362098740">Datum vypršení platnosti</translation>
<translation id="5565735124758917034">Aktivní</translation>
@@ -592,6 +617,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Získejte personalizovaný obsah</translation>
<translation id="5675650730144413517">Tato stránka nefunguje</translation>
+<translation id="5689199277474810259">Exportovat do formátu JSON</translation>
<translation id="5710435578057952990">Identita těchto webových stránek nebyla ověřena.</translation>
<translation id="5719499550583120431">Obchodník přijímá předplacené karty.</translation>
<translation id="5720705177508910913">Aktuální uživatel</translation>
@@ -606,27 +632,27 @@ Kontaktujte administrátora systému.</translation>
<translation id="5810442152076338065">Vaše připojení k doméně <ph name="DOMAIN" /> je šifrováno za použití zastaralé šifrovací sady.</translation>
<translation id="5813119285467412249">&amp;Opakovat přidání</translation>
<translation id="5838278095973806738">Na tento web byste neměli zadávat citlivé údaje (například hesla nebo čísla platebních karet), protože by je mohli odcizit útočníci.</translation>
+<translation id="5866257070973731571">Přidání telefonního čísla</translation>
<translation id="5869405914158311789">Tento web není dostupný</translation>
<translation id="5869522115854928033">Uložená hesla</translation>
<translation id="5872918882028971132">Návrhy rodičů</translation>
<translation id="5893752035575986141">Obchodník přijímá kreditní karty.</translation>
-<translation id="5901630391730855834">Žlutá</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronizováno)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Používá se 1}few{Používají se #}many{Používá se #}other{Používá se #}}</translation>
<translation id="5959728338436674663">Automaticky odesílat část <ph name="BEGIN_WHITEPAPER_LINK" />informací o systému a obsahu stránek<ph name="END_WHITEPAPER_LINK" /> do Googlu s cílem pomoci rozpoznávat nebezpečné aplikace a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Úprava kontaktních údajů</translation>
<translation id="5967867314010545767">Odstranit z historie</translation>
<translation id="5975083100439434680">Oddálit</translation>
+<translation id="597552863672748783">Potvrzení bezpečnostního kódu</translation>
<translation id="598637245381783098">Platební aplikaci nelze otevřít</translation>
<translation id="5989320800837274978">Nejsou určeny pevně dané servery proxy ani adresa URL skriptu PAC.</translation>
<translation id="5990559369517809815">Žádosti na tento server jsou blokovány rozšířením.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Stránka 1}few{Stránka #}many{Stránka #}other{Stránka #}}</translation>
-<translation id="6017514345406065928">Zelená</translation>
<translation id="6017850046339264347">Útočníci na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> by vám do zařízení mohli nainstalovat klamavé aplikace, které se vydávají za něco jiného nebo shromažďují data ke sledování vaší aktivity. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synchronizováno)</translation>
<translation id="6027201098523975773">Zadejte jméno</translation>
<translation id="6040143037577758943">Zavřít</translation>
-<translation id="6042308850641462728">Více</translation>
<translation id="6047233362582046994">Pokud bezpečnostní rizika chápete, můžete <ph name="BEGIN_LINK" />tento web navštívit<ph name="END_LINK" /> před tím, než budou nebezpečné aplikace odstraněny.</translation>
<translation id="6047927260846328439">Tento obsah by se vás podvodem mohl pokusit přimět k instalaci softwaru nebo odhalení osobních údajů. <ph name="BEGIN_LINK" />Přesto zobrazit<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Web <ph name="SITE" /> nyní nemůžete navštívit, protože používá připínání certifikátů. Síťové chyby a útoky jsou obvykle dočasné, tato stránka pravděpodobně později bude fungovat.</translation>
@@ -692,6 +718,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6569060085658103619">Prohlížíte si stránku rozšíření</translation>
<translation id="6596325263575161958">Možnosti šifrování</translation>
<translation id="662080504995468778">Zůstat</translation>
+<translation id="6624427990725312378">Kontaktní údaje</translation>
<translation id="6626291197371920147">Přidání platného čísla karty</translation>
<translation id="6628463337424475685">Vyhledávání <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Útočníci, kteří se aktuálně nacházejí na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, se mohou pokusit nainstalovat do vašeho počítače Mac nebezpečné programy, které mohou ukrást nebo smazat vaše informace (například fotky, hesla, zprávy nebo platební karty). <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -702,7 +729,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6710213216561001401">Předchozí</translation>
<translation id="6710594484020273272">&lt;Zadejte vyhledávací dotaz&gt;</translation>
<translation id="6711464428925977395">Došlo k chybě proxy serveru nebo jste zadali nesprávnou adresu.</translation>
-<translation id="6727102863431372879">Nastavit</translation>
<translation id="674375294223700098">Neznámá chyba certifikátu serveru.</translation>
<translation id="6753269504797312559">Hodnota zásady</translation>
<translation id="6757797048963528358">Zařízení přešlo do režimu spánku.</translation>
@@ -771,6 +797,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7400418766976504921">Adresa URL</translation>
<translation id="7419106976560586862">Cesta k profilu</translation>
<translation id="7424977062513257142">Stránka vložená na této webové stránce říká:</translation>
+<translation id="7437289804838430631">Přidat kontaktní údaje</translation>
<translation id="7441627299479586546">Chybný předmět zásady</translation>
<translation id="7444046173054089907">Tento web je blokován</translation>
<translation id="7445762425076701745">Totožnost serveru, k němuž jste připojeni, nelze plně ověřit. Jste připojeni k serveru, který používá název platný pouze v rámci vaší sítě. Externí certifikační autorita nemůže vlastnictví názvu nijak ověřit. Některé certifikační autority však vydají certifikát i pro takové názvy, a nelze tedy zaručit, že jste připojeni k požadovanému webu a nikoli k webu útočníka.</translation>
@@ -781,11 +808,11 @@ Kontaktujte administrátora systému.</translation>
<translation id="7481312909269577407">Vpřed</translation>
<translation id="7485870689360869515">Nebyla nalezena žádná data.</translation>
<translation id="7508255263130623398">Vrácené ID zařízení pro zásady je prázdné nebo neodpovídá aktuálnímu ID zařízení</translation>
+<translation id="7511955381719512146">Síť Wi-Fi, kterou používáte, může vyžadovat, abyste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Stáhnout</translation>
<translation id="7518003948725431193">Na webové adrese <ph name="URL" /> se nepodařilo nalézt žádnou webovou stránku.</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Připojení k tomuto webu není soukromé</translation>
-<translation id="7535087603100972091">Hodnota</translation>
<translation id="7537536606612762813">Povinná</translation>
<translation id="7542403920425041731">Po ověření budou údaje o kartě sdíleny s tímto webem.</translation>
<translation id="7542995811387359312">Automatické vyplňování údajů platební karty je deaktivováno, protože tento formulář nepoužívá zabezpečené připojení.</translation>
@@ -796,7 +823,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="7567204685887185387">Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Jeho bezpečnostní certifikát byl zřejmě vydán podvodně. 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="7568593326407688803">Tato stránka je v jazyce<ph name="ORIGINAL_LANGUAGE" />Chcete ji přeložit?</translation>
<translation id="7569952961197462199">Odstranit platební kartu z Chromu?</translation>
-<translation id="7569983096843329377">Černá</translation>
<translation id="7578104083680115302">Plaťte na webech a v aplikacích v různých zařízeních rychle pomocí karet uložených na Googlu.</translation>
<translation id="7588950540487816470">Fyzický web</translation>
<translation id="7592362899630581445">Certifikát serveru porušuje omezení názvů domén.</translation>
@@ -815,11 +841,13 @@ Kontaktujte administrátora systému.</translation>
<translation id="7669271284792375604">Útočníci na tomto webu by se mohli pokusit přimět vás k instalaci programů, které nepříznivě ovlivní procházení webu (například změní vaši domovskou stránku nebo na navštěvovaných stránkách budou zobrazovat další reklamy).</translation>
<translation id="7674629440242451245">Zajímají vás nové funkce Chromu? Vyzkoušejte kanál pro vývojáře na adrese chrome.com/dev.</translation>
<translation id="7682287625158474539">Doprava</translation>
+<translation id="7699293099605015246">Články momentálně nejsou dostupné</translation>
<translation id="7701040980221191251">Žádné</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Pokračovat na web <ph name="SITE" /> (nespolehlivý)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certifikát</translation>
<translation id="7716147886133743102">Blokováno administrátorem</translation>
<translation id="7716424297397655342">Tento web nelze načíst z mezipaměti</translation>
+<translation id="7723047071702270851">Úprava karty</translation>
<translation id="774634243536837715">Byl zablokován nebezpečný obsah.</translation>
<translation id="7752995774971033316">Nespravováno</translation>
<translation id="7755287808199759310">Rodič ti jej může odblokovat.</translation>
@@ -830,21 +858,24 @@ Kontaktujte administrátora systému.</translation>
<translation id="7764225426217299476">Přidat adresu</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Přidat</translation>
+<translation id="7793553086574152071">Abyste příště mohli zaplatit rychleji, uložte si tuto kartu do účtu Google.</translation>
<translation id="7793809570500803535">Webové stránky na adrese <ph name="SITE" /> jsou možná dočasně nedostupné nebo mohly být přemístěny na novou webovou adresu.</translation>
<translation id="7800304661137206267">Připojení je šifrováno pomocí standardu <ph name="CIPHER" /> s algoritmem <ph name="MAC" /> pro ověřování zpráv a mechanizmem výměny klíčů <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Web je důvěryhodný</translation>
<translation id="780301667611848630">Ne, děkuji</translation>
<translation id="7805768142964895445">Stav</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Odstranit návrh položky formuláře z Chromu?</translation>
<translation id="7815407501681723534">Nalezené <ph name="SEARCH_RESULTS" /> pro dotaz „<ph name="SEARCH_STRING" />“: <ph name="NUMBER_OF_RESULTS" /></translation>
+<translation id="782886543891417279">Síť Wi-Fi, kterou používáte (<ph name="WIFI_NAME" />), může vyžadovat, abyste navštívili její stránku přihlášení.</translation>
<translation id="785549533363645510">To neznamená, že jste neviditelní. Anonymní režim neskryje vaši aktivitu před vaším zaměstnavatelem, poskytovatelem internetových služeb ani webovými stránkami, které navštívíte.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Obchodník přijímá debetní a předplacené karty.</translation>
+<translation id="7878562273885520351">Heslo může být prolomeno</translation>
<translation id="7887683347370398519">Zkontrolujte kód CVC a zkuste to znovu</translation>
<translation id="79338296614623784">Zadejte platné telefonní číslo</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifikát serveru ještě není platný.</translation>
-<translation id="7942349550061667556">Červená</translation>
<translation id="7947285636476623132">Zkontrolujte rok vypršení platnosti a zkuste to znovu.</translation>
<translation id="7951415247503192394">(32bitový)</translation>
<translation id="7956713633345437162">Mobilní záložky</translation>
@@ -858,9 +889,13 @@ Kontaktujte administrátora systému.</translation>
<translation id="8037357227543935929">Zeptat se (výchozí)</translation>
<translation id="8041089156583427627">Odeslat svůj názor</translation>
<translation id="8041940743680923270">Použít výchozí globální hodnotu (Dotázat se)</translation>
+<translation id="8057711352706143257">Software <ph name="SOFTWARE_NAME" /> není nakonfigurován správně. Tento problém lze obvykle vyřešit odinstalováním softwaru <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Zobrazení článku se nezdařilo.</translation>
<translation id="8091372947890762290">Čeká se na aktivaci na serveru</translation>
+<translation id="8094917007353911263">Síť, kterou používáte, může vyžadovat, abyste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Platební metoda</translation>
<translation id="8118489163946903409">Platební metoda</translation>
+<translation id="8127301229239896662">Software <ph name="SOFTWARE_NAME" /> na počítači nebo v síti nebyl nainstalován správně. Požádejte administrátora IT o vyřešení tohoto problému.</translation>
<translation id="8131740175452115882">Potvrdit</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> serveru <ph name="HOST_NAME" /> nebyla nalezena.</translation>
<translation id="8149426793427495338">Počítač přešel do režimu spánku.</translation>
@@ -883,6 +918,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="8289355894181816810">Pokud nevíte, co dělat, obraťte se na svého správce sítě.</translation>
<translation id="8293206222192510085">Přidat záložku</translation>
<translation id="8294431847097064396">Zdroj</translation>
+<translation id="8298115750975731693">Síť Wi-Fi, kterou používáte (<ph name="WIFI_NAME" />), může vyžadovat, abyste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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" />). <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Překlad se nezdařil kvůli problému s připojením k síti.</translation>
<translation id="8332188693563227489">Přístup k webu <ph name="HOST_NAME" /> byl odepřen</translation>
@@ -936,20 +972,21 @@ Kontaktujte administrátora systému.</translation>
<translation id="8870413625673593573">Nedávno zavřené</translation>
<translation id="8874824191258364635">Zadejte platné číslo karty</translation>
<translation id="8876793034577346603">Analýza konfigurace sítě se nezdařila.</translation>
-<translation id="8889402386540077796">Odstín</translation>
<translation id="8891727572606052622">Neplatný režim proxy serveru.</translation>
<translation id="889901481107108152">Je nám líto, tento experiment není na vaší platformě dostupný.</translation>
<translation id="8903921497873541725">Přiblížit</translation>
<translation id="8931333241327730545">Chcete tuto kartu uložit do účtu Google?</translation>
<translation id="8932102934695377596">Vaše hodiny se zpožďují</translation>
+<translation id="893332455753468063">Přidání jména</translation>
<translation id="8938939909778640821">Přijímané kreditní a předplacené karty</translation>
+<translation id="8957210676456822347">Autorizace captive portálu</translation>
<translation id="8971063699422889582">Platnost certifikátu serveru vypršela.</translation>
-<translation id="8986494364107987395">Automaticky posílat společnosti Google statistiky používání a zprávy o selhání</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Web, na který se chystáte přejít, obsahuje škodlivé programy</translation>
<translation id="8997023839087525404">Server předložil certifikát, který nebyl zveřejněn v souladu se zásadou Certificate Transparency. U některých certifikátů je to z důvodu kontroly důvěryhodnosti a ochrany před útočníky vyžadováno.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> vyžaduje uživatelské jméno a heslo.</translation>
<translation id="9005998258318286617">Načtení dokumentu PDF se nezdařilo.</translation>
+<translation id="9008201768610948239">Ignorovat</translation>
<translation id="901974403500617787">Příznaky, které platí v celém systému, může nastavit pouze vlastník: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Fakturační adresa karty je povinná</translation>
<translation id="9020542370529661692">Stránka byla přeložena do jazyka <ph name="TARGET_LANGUAGE" /></translation>
@@ -959,11 +996,14 @@ Kontaktujte administrátora systému.</translation>
<translation id="9049981332609050619">Pokusili jste se přejít do domény <ph name="DOMAIN" />, ale server předložil certifikát, jehož platnost vypršela.</translation>
<translation id="9050666287014529139">Heslová fráze</translation>
<translation id="9065203028668620118">Upravit</translation>
-<translation id="9068849894565669697">Výběr barvy</translation>
<translation id="9069693763241529744">Blokováno rozšířením</translation>
<translation id="9076283476770535406">Může obsahovat materiály pouze pro dospělé</translation>
<translation id="9078964945751709336">Jsou potřeba další informace</translation>
+<translation id="9080712759204168376">Přehled objednávky</translation>
<translation id="9103872766612412690">Web <ph name="SITE" /> vaše informace běžně chrání šifrováním. Když se prohlížeč Chromium k webu <ph name="SITE" /> pokusil připojit tentokrát, web vrátil neobvyklé a nesprávné identifikační údaje. K tomuto problému může dojít, pokud se za web <ph name="SITE" /> pokouší vydávat nějaký útočník nebo pokud bylo připojení přerušeno přihlašovací obrazovkou sítě Wi-Fi. Vaše informace jsou i nadále v bezpečí, protože prohlížeč Chromium připojení přerušil dříve, než došlo k odeslání jakýchkoliv dat.</translation>
+<translation id="9106062320799175032">Přidání fakturační adresy</translation>
+<translation id="910908805481542201">Pomozte mi to opravit</translation>
+<translation id="9128870381267983090">Připojit k síti</translation>
<translation id="9137013805542155359">Zobrazit originál</translation>
<translation id="9137248913990643158">Chcete-li tuto aplikaci použít, přihlaste se do Chromu.</translation>
<translation id="9148507642005240123">&amp;Vrátit úpravy zpět</translation>
@@ -975,6 +1015,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="9183425211371246419">Web <ph name="HOST_NAME" /> používá nepodporovaný protokol.</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="9215416866750762878">Nějaká aplikace Chromu brání v bezpečném připojení k tomuto webu.</translation>
<translation id="9219103736887031265">Obrázky</translation>
<translation id="933612690413056017">Připojení k internetu není k dispozici</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -984,5 +1025,11 @@ Kontaktujte administrátora systému.</translation>
<translation id="975560348586398090">{COUNT,plural, =0{Žádné}=1{1 položka}few{# položky}many{# položky}other{# položek}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Vývojářské sestavení</translation>
+<translation id="989988560359834682">Upravit adresu</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Software <ph name="SOFTWARE_NAME" /> na počítači nebo v síti nebyl nainstalován správně:
+ &lt;ul&gt;
+ &lt;li&gt;Zkuste software <ph name="SOFTWARE_NAME" /> odinstalovat nebo deaktivovat.&lt;/li&gt;
+ &lt;li&gt;Zkuste se připojit k jiné síti.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index 558e82a9601..d32b8132def 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Bogmærker på pc</translation>
<translation id="1074497978438210769">Ikke sikker</translation>
<translation id="1080116354587839789">Tilpas til bredden</translation>
+<translation id="1088860948719068836">Tilføj navn på kort</translation>
<translation id="1103523840287552314">Oversæt altid <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Se alle gemte adgangskoder...</translation>
<translation id="1107591249535594099">Hvis dette felt er markeret, gemmer Chrome en kopi af dit kort på denne enhed, så formularer hurtigere kan udfyldes fremover.</translation>
<translation id="1111153019813902504">Seneste bogmærker</translation>
<translation id="1113869188872983271">&amp;Fortryd omarrangering</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synkroniseret)</translation>
<translation id="1263231323834454256">Læseliste</translation>
<translation id="1264126396475825575">Der blev registreret en nedbrudsrapport <ph name="CRASH_TIME" /> (endnu ikke uploadet eller ignoreret)</translation>
+<translation id="1270502636509132238">Afhentningsmetode</translation>
<translation id="1281526147609854549">Udgivet af <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Oversæt aldrig dette website</translation>
<translation id="129553762522093515">Senest lukkede</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Venter på forbindelse…</translation>
<translation id="153384715582417236">Det var det hele indtil videre.</translation>
<translation id="1549470594296187301">JavaScript skal være aktiveret, før du kan bruge denne funktion.</translation>
-<translation id="1555130319947370107">Blå</translation>
<translation id="1559528461873125649">Filen eller mappen findes ikke</translation>
<translation id="1583429793053364125">Der opstod en fejl ved visningen af denne webside.</translation>
<translation id="1592005682883173041">Lokal dataadgang</translation>
<translation id="1594030484168838125">Vælg</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Skal Chrome gemme dette kort?</translation>
<translation id="1639239467298939599">Indlæser...</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du skal have tilladelse fra <ph name="NAME" /> til at besøge dette website</translation>
<translation id="1721424275792716183">* Feltet skal udfyldes</translation>
+<translation id="1727741090716970331">Tilføj et gyldigt kortnummer</translation>
<translation id="1728677426644403582">Du ser kilden for en webside</translation>
<translation id="173080396488393970">Denne korttype understøttes ikke</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serialiseringsfejl</translation>
<translation id="1974060860693918893">Avanceret</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
-<translation id="1995859865337580572">Bekræft din kontrolkode</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{og 1 mere}one{og # mere}other{og # mere}}</translation>
<translation id="2025186561304664664">Proxyen konfigureres automatisk.</translation>
<translation id="2030481566774242610">Mente du <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Fortryd</translation>
<translation id="20817612488360358">Indstillingerne for systemproxy er angivet at blive brugt, men en eksplicit proxykonfiguration er også angivet.</translation>
<translation id="2086652334978798447">Log ind på Chrome for at hente brugertilpasset indhold, som er foreslået af Chrome.</translation>
+<translation id="2091887806945687916">Lyd</translation>
<translation id="2094505752054353250">Uoverensstemmelse mellem domæner</translation>
<translation id="2096368010154057602">Departement</translation>
<translation id="2108755909498034140">Genstart computeren</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignoreret, da den blev tilsidesat af <ph name="POLICY_NAME" /> .</translation>
<translation id="2138201775715568214">Leder efter Fysisk web-sider i nærheden</translation>
<translation id="213826338245044447">Bogmærker på mobil</translation>
+<translation id="214556005048008348">Annuller betaling</translation>
<translation id="2147827593068025794">Synkronisering i baggrunden</translation>
+<translation id="2148613324460538318">Tilføj kort</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgængelig for dit domæne</translation>
<translation id="2154484045852737596">Rediger kort</translation>
<translation id="2166049586286450108">Fuld administratoradgang</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresser}}</translation>
<translation id="2187317261103489799">Registrer (standardindstilling)</translation>
<translation id="2202020181578195191">Angiv et gyldigt udløbsår</translation>
+<translation id="2209523182407020534">Apps, der kan forårsage denne fejl, er blandt andet antivirus-, firewall- og webfiltrerings- eller proxysoftware.</translation>
<translation id="2212735316055980242">Politikken blev ikke fundet</translation>
<translation id="2213606439339815911">Indlæg hentes...</translation>
<translation id="2218879909401188352">Hackere, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apps, som kan skade din enhed, føje skjulte gebyrer til din mobilregning eller stjæle dine personlige oplysninger. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Gå tilbage</translation>
<translation id="2503184589641749290">Accepterede debetkort og forudbetalte kort</translation>
<translation id="2515629240566999685">Kontrollere signalet i dit område</translation>
+<translation id="2524461107774643265">Tilføj flere oplysninger</translation>
+<translation id="2536110899380797252">Tilføj adresse</translation>
<translation id="2539524384386349900">Registrer</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> sendte et ugyldigt svar.</translation>
<translation id="2556876185419854533">&amp;Fortryd redigering</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
<translation id="2705137772291741111">Den gemte (cachelagrede) kopi af dette website kunne ikke læses.</translation>
<translation id="2709516037105925701">AutoFyld</translation>
+<translation id="2710942282213947212">Der er software på computeren, som forhindrer Chromium i at oprette en sikker forbindelse til nettet</translation>
<translation id="2712173769900027643">Spørg om tilladelse</translation>
-<translation id="2713444072780614174">Hvid</translation>
<translation id="2720342946869265578">Tæt på</translation>
<translation id="2721148159707890343">Anmodning lykkedes</translation>
<translation id="2728127805433021124">Serverens certifikat er signeret ved hjælp af en svag signaturalgoritme.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Der blev registreret en netværksændring.</translation>
<translation id="2916038427272391327">Luk andre programmer</translation>
<translation id="2922350208395188000">Serverens certifikat kan ikke kontrolleres.</translation>
+<translation id="2925673989565098301">Leveringsmetode</translation>
<translation id="2928905813689894207">Faktureringsadresse</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> anden}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> anden}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> andre}}</translation>
<translation id="2941952326391522266">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er fra <ph name="DOMAIN2" />. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Forkert politiktype</translation>
<translation id="3032412215588512954">Vil du genindlæse denne side?</translation>
<translation id="3037605927509011580">Øv, surt!</translation>
+<translation id="3039538478787849737">Vil du gemme kortet på din Google-konto?</translation>
<translation id="3041612393474885105">Certifikatoplysninger</translation>
<translation id="3063697135517575841">Chrome kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
<translation id="3064966200440839136">Du forlader inkognitotilstand for at betale via en ekstern applikation. Vil du fortsætte?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Midlertidig serverfejl</translation>
<translation id="3154506275960390542">Denne side indeholder en formular, der muligvis ikke kan indsendes sikkert. Dine indsendte data kan ses af andre eller kan blive ændret af en hacker, så serveren, du sender til, modtager forkerte oplysninger.</translation>
<translation id="3157931365184549694">Gendan</translation>
+<translation id="3162559335345991374">Det Wi-Fi-netværk, du bruger, kan kræve, at du går til netværkets loginside.</translation>
<translation id="3167968892399408617">Når du har lukket alle dine inkognitofaner, gemmes der hverken cookies, browser- eller søgehistorik for de sider, du besøger i inkognitotilstand. Dog gemmes alle de filer, du downloader, og bogmærker, du opretter.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ø</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Annuller betaling</translation>
<translation id="3207960819495026254">Bogmærket</translation>
+<translation id="3211223744486044430">Gem dette kort på din Google-konto og denne enhed for at betale hurtigere næste gang.</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>
<translation id="3226128629678568754">Tryk på genindlæsningsknappen for at genindsende de data, der er nødvendige for at indlæse siden.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Der blev ikke fundet nogen søgeresultater</translation>
<translation id="3305707030755673451">Dine data blev krypteret med din adgangssætning til synkronisering d. <ph name="TIME" />. Indtast adgangssætningen for at starte synkroniseringen.</translation>
<translation id="3320021301628644560">Tilføj faktureringsadresse</translation>
-<translation id="3329013043687509092">Mætning</translation>
<translation id="333371639341676808">Undgå, at denne side laver nye dialogbokse.</translation>
<translation id="3338095232262050444">Sikker</translation>
<translation id="3340978935015468852">indstillinger</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Klient-id:</translation>
<translation id="3391030046425686457">Leveringsadresse</translation>
<translation id="3395827396354264108">Afhentningsmetode</translation>
+<translation id="3399952811970034796">Leveringsadresse</translation>
<translation id="3422248202833853650">Prøv at lukke programmer for at frigøre hukommelse.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan ikke læses i øjeblikket.</translation>
<translation id="3427092606871434483">Tillad (standardindstilling)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Nedbrud registreret <ph name="CRASH_TIME" />, uploadet <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certifikatoplysninger</translation>
<translation id="3690164694835360974">Login er ikke sikkert</translation>
+<translation id="3704162925118123524">Det netværk, du bruger, kan kræve, at du går til netværkets loginside.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Indlæser...</translation>
<translation id="3712624925041724820">Licenserne er opbrugt</translation>
<translation id="3714780639079136834">Tænde for mobildata eller Wi-Fi</translation>
+<translation id="3715597595485130451">Opret forbindelse til Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tjekke proxy-, firewall- og DNS-konfigurationen<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Hvis du forstår den sikkerhedsrisiko, du udsætter dig for, kan du <ph name="BEGIN_LINK" />gå til dette usikre website<ph name="END_LINK" />, inden de farlige programmer er fjernet.</translation>
<translation id="3739623965217189342">Link, du har kopieret</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Fortryd tilføjelse</translation>
<translation id="404928562651467259">ADVARSEL</translation>
<translation id="4058922952496707368">Nøgle "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxykonfiguration er angivet til at anvende en webadresse for .pac-script, ikke faste proxyservere.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Enhedens serienummer er ugyldigt</translation>
<translation id="410351446219883937">Autoplay</translation>
<translation id="4103763322291513355">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for at se listen over sortlistede webadresser og andre politikker, din systemadministrator har igangsat.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Tillad altid på dette website</translation>
<translation id="4117700440116928470">Politikkens omfang understøttes ikke.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 anden/andet}one{# anden/andet}other{# andre}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Du har forsøgt at få fat på <ph name="DOMAIN" />, men serverens certifikat er blevet tilbagekaldt af udgiveren. Det betyder, at du bestemt ikke bør have tillid til serverens sikkerhedsoplysninger. Du kommunikerer muligvis med en hacker.</translation>
<translation id="4394049700291259645">Deaktiver</translation>
<translation id="4406896451731180161">søgeresultater</translation>
+<translation id="4415426530740016218">Afhentningsadresse</translation>
<translation id="4424024547088906515">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller der er ikke angivet et.</translation>
<translation id="443673843213245140">Brug af en proxy er deaktiveret, men en eksplicit proxykonfiguration er angivet.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Prøv at deaktivere dine udvidelser.</translation>
<translation id="457875822857220463">Levering</translation>
+<translation id="4582800630050655161">Du kan miste adgang til din Google-konto eller udsættes for identitetstyveri. Chromium anbefaler, at du skifter din adgangskode nu.</translation>
<translation id="4587425331216688090">Vil du fjerne adressen fra Chrome?</translation>
<translation id="4592951414987517459">Din forbindelse til <ph name="DOMAIN" /> er krypteret ved hjælp af en moderne krypteringspakke.</translation>
<translation id="4594403342090139922">&amp;Fortryd sletning</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Stop med at bruge et ugyldigt certifikat</translation>
+<translation id="4690954380545377795">Du kan miste adgang til din Google-konto eller udsættes for identitetstyveri. Chrome anbefaler, at du skifter din adgangskode nu.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Din forbindelse blev afbrudt</translation>
<translation id="471880041731876836">Du har ikke tilladelse til at besøge dette website</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Køre Windows Netværksdiagnosticering<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Din betaling</translation>
<translation id="4726672564094551039">Opdater politikker</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Genstart Chromium</translation>
@@ -510,9 +527,10 @@
<translation id="5019198164206649151">Sikkerhedskopien er fejlbehæftet</translation>
<translation id="5023310440958281426">Læs din administrators politikker</translation>
<translation id="5029568752722684782">Slet kopi</translation>
+<translation id="503069730517007720">Et rodcertifikat for "<ph name="SOFTWARE_NAME" />" er påkrævet, men ikke installeret. Din IT-administrator bør kigge på konfigurationsvejledningen til "<ph name="SOFTWARE_NAME" />" for at løse dette problem. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Om Google Oversæt</translation>
<translation id="5039804452771397117">Tillad</translation>
-<translation id="5040262127954254034">Beskyttelse af personlige oplysninger</translation>
+<translation id="5040262127954254034">Privatliv</translation>
<translation id="5045550434625856497">Ugyldig adgangskode</translation>
<translation id="5056549851600133418">Artikler til dig</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Tjekke proxy-adressen<ph name="END_LINK" /></translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Eksperimenter</translation>
<translation id="5205222826937269299">Navn påkrævet</translation>
<translation id="5222812217790122047">E-mail påkrævet</translation>
+<translation id="522700295135997067">Dette website kan have stjålet din adgangskode</translation>
+<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5251803541071282808">Skyen</translation>
<translation id="5277279256032773186">Bruger du Chrome på arbejdet? Virksomheder kan administrere Chrome-indstillinger for deres medarbejdere. Få flere oplysninger</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Følg denne vejledning for at deaktivere softwaren midlertidigt, så du kan komme på nettet. Du skal have administratorrettigheder.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Din forbindelse til dette website er ikke privat. Du kan til enhver tid afslutte VR-tilstanden ved at tage headsettet af og trykke på Tilbage.</translation>
<translation id="5299298092464848405">Der opstod en fejl ved parsing af politik</translation>
+<translation id="5308380583665731573">Få forbindelse</translation>
<translation id="5308689395849655368">Rapportering af nedbrud er deaktiveret.</translation>
<translation id="5317780077021120954">Gem</translation>
<translation id="5327248766486351172">Navn</translation>
+<translation id="5332219387342487447">Leveringsmetode</translation>
<translation id="5355557959165512791">Du kan ikke besøge <ph name="SITE" /> lige nu, da dets certifikat er blevet tilbagekaldt. Netværksfejl og angreb er normalt midlertidige, så siden vil sandsynligvis fungere igen senere.</translation>
<translation id="536296301121032821">Der kunne ikke gemmes indstillinger for politik</translation>
<translation id="5386426401304769735">Certifikatkæden for dette website indeholder et certifikat, der er signeret med SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Dette website på virksomhedens, organisationens eller skolens intranet har samme webadresse som et eksternt website.
<ph name="LINE_BREAK" />
Prøv at kontakte din systemadministrator.</translation>
+<translation id="5499929369096410817">Angiv sikkerhedskoden for <ph name="CREDIT_CARD" />. Koden gemmes ikke.</translation>
<translation id="5509780412636533143">Administrerede bogmærker</translation>
<translation id="5510766032865166053">Den kan være blevet flyttet eller slettet.</translation>
<translation id="5523118979700054094">Navn på politik</translation>
<translation id="552553974213252141">Blev teksten trukket korrekt ud?</translation>
<translation id="5540224163453853">Den anmodede artikel blev ikke fundet.</translation>
+<translation id="5541546772353173584">Tilføj mail</translation>
<translation id="5544037170328430102">En integreret side på <ph name="SITE" /> siger:</translation>
+<translation id="5545756402275714221">Artikler til dig</translation>
<translation id="5556459405103347317">Genindlæs</translation>
<translation id="5560088892362098740">Udløbsdato</translation>
<translation id="5565735124758917034">Aktiv</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Få tilpasset indhold</translation>
<translation id="5675650730144413517">Denne side virker ikke</translation>
+<translation id="5689199277474810259">Eksportér i JSON</translation>
<translation id="5710435578057952990">Dette websites identitet er ikke blevet bekræftet.</translation>
<translation id="5719499550583120431">Forudbetalte kort accepteres.</translation>
<translation id="5720705177508910913">Aktuel bruger</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Din forbindelse til <ph name="DOMAIN" /> er krypteret ved hjælp af en forældet krypteringspakke.</translation>
<translation id="5813119285467412249">&amp;Annuller fortryd tilføjelse</translation>
<translation id="5838278095973806738">Du bør ikke indtaste følsomme oplysninger på dette website (f.eks. adgangskoder eller kreditkortoplysninger), da de kan blive stjålet af hackere.</translation>
+<translation id="5866257070973731571">Tilføj telefonnummer</translation>
<translation id="5869405914158311789">Der kan ikke oprettes forbindelse til dette website</translation>
<translation id="5869522115854928033">Gemte adgangskoder</translation>
<translation id="5872918882028971132">Forslag fra forældre</translation>
<translation id="5893752035575986141">Kreditkort accepteres.</translation>
-<translation id="5901630391730855834">Gul</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkroniseret)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 i brug}one{# i brug}other{# i brug}}</translation>
<translation id="5959728338436674663">Send automatisk <ph name="BEGIN_WHITEPAPER_LINK" />nogle systemoplysninger og noget sideindhold<ph name="END_WHITEPAPER_LINK" /> til Google som en hjælp til at registrere skadelige apps og websites. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Rediger kontaktoplysninger</translation>
<translation id="5967867314010545767">Fjern fra historik</translation>
<translation id="5975083100439434680">Zoom ud</translation>
+<translation id="597552863672748783">Bekræft sikkerhedskoden</translation>
<translation id="598637245381783098">Betalingsappen kan ikke åbnes</translation>
<translation id="5989320800837274978">Der er hverken angivet faste proxyservere eller en .pac-scriptwebadresse.</translation>
<translation id="5990559369517809815">Anmodninger til serveren er blokeret af en udvidelse.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Side 1}one{Side #}other{Side #}}</translation>
-<translation id="6017514345406065928">Grøn</translation>
<translation id="6017850046339264347">Hackere på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan 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_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synkroniseret)</translation>
<translation id="6027201098523975773">Angiv et navn</translation>
<translation id="6040143037577758943">Luk</translation>
-<translation id="6042308850641462728">Mere</translation>
<translation id="6047233362582046994">Hvis du er indforstået med de forbundne sikkerhedsrisici, kan du <ph name="BEGIN_LINK" />besøge dette website<ph name="END_LINK" />, inden de skadelige apps fjernes.</translation>
<translation id="6047927260846328439">Dette indhold forsøger muligvis at narre dig til at installere software eller afsløre personlige oplysninger. <ph name="BEGIN_LINK" />Vis alligevel<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan ikke besøge <ph name="SITE" /> lige nu, da websitet bruger certifikatlåsning. Netværksfejl og angreb er normalt midlertidige, så siden vil sandsynligvis fungere igen senere.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Du ser en udvidelsesside</translation>
<translation id="6596325263575161958">Krypteringsmuligheder</translation>
<translation id="662080504995468778">Bliv her</translation>
+<translation id="6624427990725312378">Kontaktoplysninger</translation>
<translation id="6626291197371920147">Tilføj gyldigt kortnummer</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> -søgning</translation>
<translation id="6630809736994426279">Brugere med ondsindede hensigter, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan forsøge at installere farlige programmer på din Mac, som stjæler eller sletter dine oplysninger (f.eks. fotos, adgangskoder, beskeder og kreditkort). <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Forrige</translation>
<translation id="6710594484020273272">&lt;Indtast søgeterm&gt;</translation>
<translation id="6711464428925977395">Der er noget galt med proxyserveren, eller adressen er forkert.</translation>
-<translation id="6727102863431372879">Angiv</translation>
<translation id="674375294223700098">Ukendt fejl i servercertifikatet.</translation>
<translation id="6753269504797312559">Politikkens værdi</translation>
<translation id="6757797048963528358">Din enhed gik i dvale.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">Webadresse</translation>
<translation id="7419106976560586862">Profilsti</translation>
<translation id="7424977062513257142">En integreret side på denne webside siger:</translation>
+<translation id="7437289804838430631">Tilføj kontaktoplysninger</translation>
<translation id="7441627299479586546">Forkert emne for politik</translation>
<translation id="7444046173054089907">Dette website er blokeret</translation>
<translation id="7445762425076701745">Identiteten på den server, som du er tilknyttet, kan ikke bekræftes. Du er tilknyttet en server via et navn, der kun er gyldigt i dit netværk, og som en ekstern certifikatautoritet derfor ikke har mulighed for at bekræfte ejerskabet på. Da enkelte certifikatautoriteter alligevel udsteder certifikater for disse navne, kan vi på ingen måde sikre, at du er tilknyttet det tilsigtede website og ikke til en forbryder.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Der blev ikke fundet nogen data.</translation>
<translation id="7508255263130623398">Det returnerede enheds-id for politikken er tomt eller stemmer ikke overens med det nuværende enheds-id</translation>
+<translation id="7511955381719512146">Det Wi-Fi-netværk, du bruger, kan kræve, at du går til <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Download</translation>
<translation id="7518003948725431193">Ingen webside fundet på webadressen: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Din forbindelse til dette website er ikke privat</translation>
-<translation id="7535087603100972091">Værdi</translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542403920425041731">Når du har bekræftet, deles dine kortoplysninger med dette website.</translation>
<translation id="7542995811387359312">Automatisk udfyldning af kreditkort er deaktiveret, fordi formularen ikke bruger en sikker forbindelse.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er udstedt på ulovlig vis. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="7568593326407688803">Denne side er på<ph name="ORIGINAL_LANGUAGE" />Vil du oversætte den?</translation>
<translation id="7569952961197462199">Vil du fjerne kreditkortet fra Chrome?</translation>
-<translation id="7569983096843329377">Sort</translation>
<translation id="7578104083680115302">Betal hurtigt på websites og i apps på alle enheder ved hjælp af kort, du har gemt med Google.</translation>
<translation id="7588950540487816470">Fysisk web</translation>
<translation id="7592362899630581445">Begrænsningerne for serverens certifikatnavn er overtrådt.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Hackere på dette website kan forsøge at narre dig til at installere programmer, der skader din browseroplevelse (f.eks. ved at ændre din startside eller vise flere annoncer på de websites, du besøger).</translation>
<translation id="7674629440242451245">Er du interesseret i smarte nye Chrome-funktioner? Prøv vores udviklerkanal på chrome.com/dev.</translation>
<translation id="7682287625158474539">Forsendelse</translation>
+<translation id="7699293099605015246">Der er ingen tilgængelige artikler lige nu</translation>
<translation id="7701040980221191251">Ingen</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsæt til <ph name="SITE" /> (usikkert)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certifikat</translation>
<translation id="7716147886133743102">Blokeret af din administrator</translation>
<translation id="7716424297397655342">Dette website kan ikke indlæses fra cachen</translation>
+<translation id="7723047071702270851">Rediger kort</translation>
<translation id="774634243536837715">Farligt indhold er blokeret.</translation>
<translation id="7752995774971033316">Administreres ikke</translation>
<translation id="7755287808199759310">Din forælder kan fjerne blokeringen for dig</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Tilføj adresse</translation>
<translation id="777702478322588152">Præfektur</translation>
<translation id="7791543448312431591">Tilføj</translation>
+<translation id="7793553086574152071">Gem dette kort på din Google-konto for at betale hurtigere næste gang.</translation>
<translation id="7793809570500803535">Websitet på <ph name="SITE" /> kan være midlertidigt nede, eller også er den permanent flyttet til en ny webadresse.</translation>
<translation id="7800304661137206267">Forbindelsen er krypteret ved hjælp af <ph name="CIPHER" /> med <ph name="MAC" /> til meddelelsesgodkendelse og <ph name="KX" /> som hovedudvekslingsmekanisme.</translation>
+<translation id="7802523362929240268">Websitet er pålideligt</translation>
<translation id="780301667611848630">Nej tak</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vil du fjerne formularforslaget fra Chrome?</translation>
<translation id="7815407501681723534">Der blev fundet <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">Det Wi-Fi-netværk, du bruger (<ph name="WIFI_NAME" />), kan kræve, at du går til netværkets loginside.</translation>
<translation id="785549533363645510">Du er dog ikke usynlig. Inkognitotilstand skjuler ikke din browserhistorik over for din arbejdsgiver, din internetudbyder eller de websites, du besøger.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Betalingskort accepteres.</translation>
+<translation id="7878562273885520351">Din adgangskode kan være kompromitteret</translation>
<translation id="7887683347370398519">Kontrollér, om din kontrolkode er korrekt, og prøv igen.</translation>
<translation id="79338296614623784">Angiv et gyldigt telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverens certifikatet er endnu ikke gyldigt.</translation>
-<translation id="7942349550061667556">Rød</translation>
<translation id="7947285636476623132">Kontrollér, om udløbsåret er korrekt, og prøv igen.</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Bogmærker på mobil</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Spørg (standardindstilling)</translation>
<translation id="8041089156583427627">Send feedback</translation>
<translation id="8041940743680923270">Brug global standard (spørg)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" er ikke konfigureret korrekt. Problemet kan normalt løses ved at afinstallere "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Artiklen kunne ikke vises.</translation>
<translation id="8091372947890762290">Aktivering afventer serveren</translation>
+<translation id="8094917007353911263">Det netværk, du bruger, kan kræve, at du går til <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Betalingsmetode</translation>
<translation id="8118489163946903409">Betalingsmetode</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" blev ikke korrekt installeret på computeren eller netværket. Bed din IT-administrator om at løse problemet.</translation>
<translation id="8131740175452115882">Bekræft</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> for <ph name="HOST_NAME" />s server blev ikke fundet.</translation>
<translation id="8149426793427495338">Din computer gik i dvale.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Kontakt din netværksadministrator, hvis du ikke er sikker på, hvad det betyder.</translation>
<translation id="8293206222192510085">Tilføj bogmærke</translation>
<translation id="8294431847097064396">Kilde</translation>
+<translation id="8298115750975731693">Det Wi-Fi-netværk, du bruger (<ph name="WIFI_NAME" />), kan kræve, at du går til <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Der kan ikke oprettes en privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, da enhedens dato og klokkeslæt (<ph name="DATE_AND_TIME" />) ikke er korrekte. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Oversættelsen mislykkedes på grund af problemer med netværksforbindelsen.</translation>
<translation id="8332188693563227489">Adgangen til <ph name="HOST_NAME" /> blev nægtet</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Senest lukkede</translation>
<translation id="8874824191258364635">Angiv et gyldigt kortnummer</translation>
<translation id="8876793034577346603">Netværkskonfiguration kunne ikke parses.</translation>
-<translation id="8889402386540077796">Farvetone</translation>
<translation id="8891727572606052622">Ugyldig proxytilstand.</translation>
<translation id="889901481107108152">Dette eksperiment er ikke tilgængeligt på din platform.</translation>
<translation id="8903921497873541725">Zoom ind</translation>
<translation id="8931333241327730545">Vil du gemme dette kort på din Google-konto?</translation>
<translation id="8932102934695377596">Dit ur er bagud</translation>
+<translation id="893332455753468063">Tilføj navn</translation>
<translation id="8938939909778640821">Accepterede betalingskort</translation>
+<translation id="8957210676456822347">Godkendelse af captive portal</translation>
<translation id="8971063699422889582">Serverens certifikat er udløbet.</translation>
-<translation id="8986494364107987395">Send automatisk brugsstatistikker og nedbrudsrapporter til Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Det website, du er på vej til, indeholder skadelige programmer</translation>
<translation id="8997023839087525404">Serveren viste et certifikat, der ikke blev fremvist offentligt ved hjælp af politikken for Certifikatsgennemsigtighed. Dette påkræves for nogle certifikater for at sikre, at de er troværdige, og beskytter mod hackere.</translation>
<translation id="9001074447101275817">Proxyserveren <ph name="DOMAIN" /> kræver et brugernavn og en adgangskode.</translation>
<translation id="9005998258318286617">PDF-dokumentet kunne ikke indlæses.</translation>
+<translation id="9008201768610948239">Ignorer</translation>
<translation id="901974403500617787">Markeringer, der gælder for hele systemet, kan kun indstilles af ejeren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Kortets faktureringsadresse er obligatorisk</translation>
<translation id="9020542370529661692">Denne side er oversat til <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Du har forsøgt at nå <ph name="DOMAIN" />, men serveren præsenterede et ugyldigt certifikat.</translation>
<translation id="9050666287014529139">Adgangssætning</translation>
<translation id="9065203028668620118">Rediger</translation>
-<translation id="9068849894565669697">Vælg farve</translation>
<translation id="9069693763241529744">Blokeret af en udvidelse</translation>
<translation id="9076283476770535406">Der er muligvis indhold for voksne på websitet</translation>
<translation id="9078964945751709336">Flere oplysninger kræves</translation>
+<translation id="9080712759204168376">Bestillingsoversigt</translation>
<translation id="9103872766612412690"><ph name="SITE" /> bruger normalt kryptering til at beskytte dine oplysninger. Da Chromium forsøgte at oprette forbindelse til <ph name="SITE" /> denne gang, returnerede websitet usædvanlige og forkerte loginoplysninger. Dette kan skyldes, at en hacker forsøger at udgive sig for at være <ph name="SITE" />, eller at en Wi-Fi-loginskærm har forstyrret forbindelsen. Dine oplysninger er stadig sikre, idet Chromium afbrød forbindelsen, inden der blev udvekslet data.</translation>
+<translation id="9106062320799175032">Tilføj faktureringsadresse</translation>
+<translation id="910908805481542201">Hjælp mig med at løse dette</translation>
+<translation id="9128870381267983090">Opret forbindelse til netværk</translation>
<translation id="9137013805542155359">Vis oprindelig</translation>
<translation id="9137248913990643158">Start og log ind på Chrome, inden du bruger denne app.</translation>
<translation id="9148507642005240123">&amp;Fortryd redigering</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> anvender en ikke-understøttet protokol.</translation>
<translation id="9205078245616868884">Dine data er krypteret med din adgangssætning til synkronisering. Indtast den for at starte synkroniseringen.</translation>
<translation id="9207861905230894330">Artiklen kunne ikke tilføjes.</translation>
+<translation id="9215416866750762878">En app forhindrer Chrome i at oprette sikker forbindelse til dette website</translation>
<translation id="9219103736887031265">Billeder</translation>
<translation id="933612690413056017">Der er ingen internetforbindelse</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ingen}=1{1 element}one{# element}other{# elementer}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Udviklerversion</translation>
+<translation id="989988560359834682">Rediger adresse</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" blev ikke korrekt installeret på computeren eller netværket:
+ &lt;ul&gt;
+ &lt;li&gt;Prøv at afinstallere eller deaktivere "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Prøv at oprette forbindelse til et andet netværk&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index 8e46b1e4735..d26c66d5fe5 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Desktop-Lesezeichen</translation>
<translation id="1074497978438210769">Nicht sicher</translation>
<translation id="1080116354587839789">An Breite anpassen</translation>
+<translation id="1088860948719068836">Angabe für "Name auf der Karte" hinzufügen</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> immer übersetzen</translation>
+<translation id="1103778128462718200">Alle gespeicherten Passwörter anzeigen...</translation>
<translation id="1107591249535594099">Bei Aktivierung speichert Chrome eine Kopie Ihrer Karte auf diesem Gerät, damit Formulare schneller ausgefüllt werden können.</translation>
<translation id="1111153019813902504">Vor Kurzem aufgerufene Lesezeichen</translation>
<translation id="1113869188872983271">&amp;Neu anordnen rückgängig machen</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synchronisiert)</translation>
<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Absturzbericht erfasst am <ph name="CRASH_TIME" />, wurde noch nicht hochgeladen oder wurde ignoriert</translation>
+<translation id="1270502636509132238">Abholoption</translation>
<translation id="1281526147609854549">Ausgestellt von <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Diese Website nie übersetzen</translation>
<translation id="129553762522093515">Kürzlich geschlossen</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Warten auf Verbindung…</translation>
<translation id="153384715582417236">Das ist im Moment alles</translation>
<translation id="1549470594296187301">Für diese Funktion muss JavaScript aktiviert sein.</translation>
-<translation id="1555130319947370107">Blau</translation>
<translation id="1559528461873125649">Datei oder Verzeichnis nicht vorhanden</translation>
<translation id="1583429793053364125">Fehler beim Anzeigen dieser Webseite.</translation>
<translation id="1592005682883173041">Zugriff auf lokale Daten</translation>
<translation id="1594030484168838125">Auswählen</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Möchten Sie, dass Chrome diese Karte speichert?</translation>
<translation id="1639239467298939599">Wird geladen...</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Betriebssystem</translation>
<translation id="1721312023322545264">Du benötigst die Berechtigung von <ph name="NAME" />, um diese Website zu besuchen</translation>
<translation id="1721424275792716183">* Pflichtfeld</translation>
+<translation id="1727741090716970331">Gültige Kartennummer hinzufügen</translation>
<translation id="1728677426644403582">Dies ist die Quelle einer Webseite</translation>
<translation id="173080396488393970">Dieser Kartentyp wird nicht unterstützt</translation>
<translation id="1734864079702812349">American Express</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Fehler bei der Serialisierung</translation>
<translation id="1974060860693918893">Erweitert</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
-<translation id="1995859865337580572">Bitte geben Sie Ihren CVC ein</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{und 1 weitere}other{und # weitere}}</translation>
<translation id="2025186561304664664">Proxy ist auf automatische Konfiguration eingestellt.</translation>
<translation id="2030481566774242610">Meinten Sie <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Melden Sie sich in Chrome an, um personalisierte, von Google vorgeschlagene Inhalte zu erhalten.</translation>
+<translation id="2091887806945687916">Ton</translation>
<translation id="2094505752054353250">Domains stimmen nicht überein.</translation>
<translation id="2096368010154057602">Verwaltungsbezirk</translation>
<translation id="2108755909498034140">Computer neu starten</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Wird ignoriert, da sie von <ph name="POLICY_NAME" /> außer Kraft gesetzt wurde.</translation>
<translation id="2138201775715568214">Nach Physical Web-Seiten zu Objekten in der Nähe wird gesucht.</translation>
<translation id="213826338245044447">Mobile Lesezeichen</translation>
+<translation id="214556005048008348">Zahlung abbrechen</translation>
<translation id="2147827593068025794">Hintergrundsynchronisierung</translation>
+<translation id="2148613324460538318">Karte hinzufügen</translation>
<translation id="2154054054215849342">Die Synchronisierung ist für Ihre Domain nicht verfügbar</translation>
<translation id="2154484045852737596">Karte bearbeiten</translation>
<translation id="2166049586286450108">Vollständiger Administratorzugriff</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 Adresse}other{# Adressen}}</translation>
<translation id="2187317261103489799">Erkennen (Standardeinstellung)</translation>
<translation id="2202020181578195191">Geben Sie ein gültiges Ablaufjahr ein</translation>
+<translation id="2209523182407020534">Anwendungen, die diesen Fehler verursachen können, sind Antivirensoftware, Firewalls, Webfilter- oder Proxy-Software.</translation>
<translation id="2212735316055980242">Richtlinie nicht gefunden</translation>
<translation id="2213606439339815911">Einträge werden abgerufen...</translation>
<translation id="2218879909401188352">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten gefährliche Apps installieren, die Ihr Gerät beschädigen, Ihrer Mobilfunkrechnung versteckte Kosten hinzufügen oder Ihre personenbezogenen Daten stehlen könnten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Zurück</translation>
<translation id="2503184589641749290">Akzeptierte Debit- und Prepaidkarten</translation>
<translation id="2515629240566999685">Signal an Ihrem Standort prüfen</translation>
+<translation id="2524461107774643265">Weitere Informationen hinzufügen</translation>
+<translation id="2536110899380797252">Adresse hinzufügen</translation>
<translation id="2539524384386349900">Erkennen</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> hat eine ungültige Antwort gesendet.</translation>
<translation id="2556876185419854533">&amp;Bearbeiten rückgängig machen</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Ihre Karte kann von Chromium zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
<translation id="2705137772291741111">Die (im Cache) gespeicherte Kopie dieser Website war nicht lesbar.</translation>
<translation id="2709516037105925701">AutoFill</translation>
+<translation id="2710942282213947212">Software auf Ihrem Computer verhindert, dass Chromium eine sichere Internetverbindung herstellt</translation>
<translation id="2712173769900027643">Berechtigung anfordern</translation>
-<translation id="2713444072780614174">Weiß</translation>
<translation id="2720342946869265578">In der Nähe</translation>
<translation id="2721148159707890343">Anfrage erfolgreich</translation>
<translation id="2728127805433021124">Das Serverzertifikat ist mit einem schwachen Signaturalgorithmus signiert.</translation>
@@ -238,11 +245,12 @@
<translation id="2826760142808435982">Die Verbindung ist mit <ph name="CIPHER" /> verschlüsselt und authentifiziert und verwendet <ph name="KX" /> als Mechanismus für den Schlüsselaustausch.</translation>
<translation id="2835170189407361413">Formular leeren</translation>
<translation id="2851634818064021665">Sie benötigen eine Berechtigung, um auf diese Website zuzugreifen</translation>
-<translation id="2856444702002559011">Hacker könnten versuchen, Ihre Daten von <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zu stehen, zum Beispiel Passwörter, Nachrichten oder Kreditkartendaten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></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="2889159643044928134">Nicht neu laden</translation>
<translation id="2909946352844186028">Eine Netzwerkänderung ist aufgetreten.</translation>
<translation id="2916038427272391327">Andere Programme schließen</translation>
<translation id="2922350208395188000">Das Serverzertifikat kann nicht überprüft werden.</translation>
+<translation id="2925673989565098301">Lieferoption</translation>
<translation id="2928905813689894207">Rechnungsadresse</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> weitere}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> weitere}}</translation>
<translation id="2941952326391522266">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat stammt von <ph name="DOMAIN2" />. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Falscher Richtlinientyp</translation>
<translation id="3032412215588512954">Möchten Sie diese Website neu laden?</translation>
<translation id="3037605927509011580">Oh nein!</translation>
+<translation id="3039538478787849737">Karte in Google speichern?</translation>
<translation id="3041612393474885105">Zertifikatinformationen</translation>
<translation id="3063697135517575841">Ihre Karte kann von Chrome zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
<translation id="3064966200440839136">Der Inkognitomodus wird beendet, um über eine externe Anwendung zu zahlen. Fortfahren?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Vorübergehender Serverfehler</translation>
<translation id="3154506275960390542">Auf dieser Seite befindet sich ein Formular, das Daten möglicherweise unsicher überträgt. Gesendete Daten können während der Übertragung von anderen gelesen oder von Angreifern geändert werden, sodass der Server modifizierte Daten erhält.</translation>
<translation id="3157931365184549694">Wiederherstellen</translation>
+<translation id="3162559335345991374">Unter Umständen müssen Sie die Anmeldeseite des verwendeten WLAN-Netzwerken aufrufen.</translation>
<translation id="3167968892399408617">Seiten, die Sie sich auf Inkognito-Tabs ansehen, werden nach dem Schließen aller Inkognito-Tabs nicht in Ihrem Browserverlauf, Cookiespeicher oder Suchverlauf gespeichert. Ihre Lesezeichen und heruntergeladenen Dateien bleiben erhalten.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Insel</translation>
@@ -287,6 +297,7 @@
folgt: <ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Zahlung abbrechen</translation>
<translation id="3207960819495026254">Mit einem Lesezeichen versehen</translation>
+<translation id="3211223744486044430">Um die Zahlung das nächste Mal schneller abzuwickeln, speichern Sie diese Karte in Ihrem Google-Konto und auf diesem Gerät.</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>
<translation id="3226128629678568754">Klicken Sie auf die Schaltfläche zum erneuten Laden, um die für das Laden der Seite erforderlichen Daten erneut zu senden.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Keine Suchergebnisse gefunden</translation>
<translation id="3305707030755673451">Ihre Daten wurden am <ph name="TIME" /> mit Ihrer Synchronisierungspassphrase verschlüsselt. Geben Sie diese ein, um die Synchronisierung zu starten.</translation>
<translation id="3320021301628644560">Rechnungsadresse hinzufügen</translation>
-<translation id="3329013043687509092">Sättigung</translation>
<translation id="333371639341676808">Diese Seite am Erstellen zusätzlicher Dialoge hindern</translation>
<translation id="3338095232262050444">Sicher</translation>
<translation id="3340978935015468852">Einstellungen</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Client-ID:</translation>
<translation id="3391030046425686457">Lieferadresse</translation>
<translation id="3395827396354264108">Abholoption</translation>
+<translation id="3399952811970034796">Lieferadresse</translation>
<translation id="3422248202833853650">Versuchen Sie, andere Programme zu beenden, um Speicher freizugeben.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ist momentan nicht erreichbar.</translation>
<translation id="3427092606871434483">Zulassen (Standardeinstellung)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375">Absturz am <ph name="CRASH_TIME" /> erfasst und am <ph name="UPLOAD_TIME" /> hochgeladen</translation>
<translation id="3681007416295224113">Zertifikatinformationen</translation>
<translation id="3690164694835360974">Log-in nicht sicher</translation>
+<translation id="3704162925118123524">Eventuell müssen Sie die Anmeldeseite des verwendeten Netzwerks aufrufen.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Wird geladen...</translation>
<translation id="3712624925041724820">Lizenzen aufgebraucht</translation>
<translation id="3714780639079136834">Mobile Daten oder WLAN aktivieren</translation>
+<translation id="3715597595485130451">WLAN-Verbindung herstellen</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, Firewall und DNS-Konfiguration prüfen<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Wenn Sie die Sicherheitsrisiken kennen, können Sie <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />, bevor die gefährlichen Programme entfernt wurden.</translation>
<translation id="3739623965217189342">Von Ihnen kopierter Link</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;Hinzufügen rückgängig machen</translation>
<translation id="404928562651467259">Warnung</translation>
<translation id="4058922952496707368">Schlüssel "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Die Proxy-Konfiguration ist auf die Verwendung einer PAC-Skript-URL und nicht die von festen Proxyservern eingestellt.</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">Seriennummer des Geräts ist ungültig.</translation>
<translation id="410351446219883937">Autoplay</translation>
<translation id="4103763322291513355">Unter &lt;strong&gt;chrome://policy&lt;/strong&gt; finden Sie eine Liste der blockierten URLs und andere Richtlinien, die durch Ihren Systemadministrator erzwungen werden.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Auf dieser Website immer zulassen</translation>
<translation id="4117700440116928470">Richtlinienbereich wird nicht unterstützt.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 weiterer}other{# weitere}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server übermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen nicht vertrauenswürdig sind. Möglicherweise kommunizieren Sie mit einem Hacker.</translation>
<translation id="4394049700291259645">Deaktivieren</translation>
<translation id="4406896451731180161">Suchergebnisse</translation>
+<translation id="4415426530740016218">Abholadresse</translation>
<translation id="4424024547088906515">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
<translation id="443673843213245140">Die Proxy-Nutzung ist deaktiviert, es ist jedoch eine explizite Proxy-Konfiguration festgelegt.</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Deaktivieren Sie Ihre Erweiterungen.</translation>
<translation id="457875822857220463">Lieferung</translation>
+<translation id="4582800630050655161">Sie könnten den Zugriff auf Ihr Google-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chromium empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
<translation id="4587425331216688090">Adresse aus Chrome entfernen?</translation>
<translation id="4592951414987517459">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer modernen Codier-Suite verschlüsselt.</translation>
<translation id="4594403342090139922">&amp;Löschen rückgängig machen</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Ungültiges Zertifikat nicht mehr verwenden</translation>
+<translation id="4690954380545377795">Sie könnten den Zugriff auf Ihr Google-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chrome empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Ihre Verbindung wurde unterbrochen</translation>
<translation id="471880041731876836">Sie sind nicht berechtigt, auf diese Website zuzugreifen</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows-Netzwerkdiagnose ausführen<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Bezahlung</translation>
<translation id="4726672564094551039">Richtlinien neu laden</translation>
<translation id="4728558894243024398">Plattform</translation>
<translation id="4736825316280949806">Chromium neu starten</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">Sicherungsspeicher ist fehlerhaft.</translation>
<translation id="5023310440958281426">Informieren Sie sich über die von Ihrem Administrator festgelegten Richtlinien.</translation>
<translation id="5029568752722684782">Kopie löschen</translation>
+<translation id="503069730517007720">Für "<ph name="SOFTWARE_NAME" />" ist ein Stammzertifikat erforderlich, das nicht installiert ist. Ihr IT-Administrator sollte die Konfigurationsanweisungen für "<ph name="SOFTWARE_NAME" />" lesen, um das Problem zu beheben. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Über Google Übersetzer</translation>
<translation id="5039804452771397117">Zulassen</translation>
<translation id="5040262127954254034">Datenschutz</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">Experimente</translation>
<translation id="5205222826937269299">Name erforderlich</translation>
<translation id="5222812217790122047">E-Mail-Adresse erforderlich</translation>
+<translation id="522700295135997067">Diese Website hat möglicherweise gerade Ihr Passwort gestohlen</translation>
+<translation id="5230733896359313003">Versandadresse</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Nutzen Sie Chrome bei der Arbeit? Unternehmen können Chrome-Einstellungen für ihre Mitarbeiter verwalten. Weitere Informationen</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Führen Sie die folgenden Schritte aus, um die Software vorübergehend zu deaktivieren und dann auf das Internet zuzugreifen. Zum Deaktivieren der Software benötigen Sie Administratorrechte.<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Ihre Verbindung zu dieser Website ist nicht sicher. Sie können den VR-Mode jederzeit verlassen, indem Sie das Headset abnehmen und auf "Zurück" klicken.</translation>
<translation id="5299298092464848405">Fehler beim Parsen der Richtlinie</translation>
+<translation id="5308380583665731573">Verbinden</translation>
<translation id="5308689395849655368">Die Absturzberichtsfunktion ist deaktiviert.</translation>
<translation id="5317780077021120954">Speichern</translation>
<translation id="5327248766486351172">Name</translation>
+<translation id="5332219387342487447">Versandart</translation>
<translation id="5355557959165512791">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da das Zertifikat widerrufen wurde. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="536296301121032821">Fehler beim Speichern der Richtlinieneinstellungen</translation>
<translation id="5386426401304769735">Die Zertifikatskette für diese Website enthält ein Zertifikat mit SHA-1-Signatur.</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">Diese Website im Intranet des Unternehmens, der Organisation oder der Schule hat die gleiche URL wie eine externe Website.
<ph name="LINE_BREAK" />
Wenden Sie sich an Ihren Systemadministrator.</translation>
+<translation id="5499929369096410817">Geben Sie den Sicherheitscode für <ph name="CREDIT_CARD" /> ein. Dieser Code wird nicht gespeichert.</translation>
<translation id="5509780412636533143">Verwaltete Lesezeichen</translation>
<translation id="5510766032865166053">Möglicherweise wurde sie verschoben oder gelöscht.</translation>
<translation id="5523118979700054094">Richtlinienname</translation>
<translation id="552553974213252141">Wurde der Text korrekt extrahiert?</translation>
<translation id="5540224163453853">Der gewünschte Artikel wurde nicht gefunden.</translation>
+<translation id="5541546772353173584">E-Mail-Adresse hinzufügen</translation>
<translation id="5544037170328430102">Auf einer in <ph name="SITE" /> eingebetteten Seite wird Folgendes angezeigt:</translation>
+<translation id="5545756402275714221">Artikel für Sie</translation>
<translation id="5556459405103347317">Neu laden</translation>
<translation id="5560088892362098740">Ablaufdatum</translation>
<translation id="5565735124758917034">Aktiv</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">E-Mail-Adresse</translation>
<translation id="5669703222995421982">Personalisierte Inhalte erhalten</translation>
<translation id="5675650730144413517">Diese Seite funktioniert nicht</translation>
+<translation id="5689199277474810259">Als JSON exportieren</translation>
<translation id="5710435578057952990">Die Identität dieser Website wurde nicht verifiziert.</translation>
<translation id="5719499550583120431">Prepaidkarten werden akzeptiert.</translation>
<translation id="5720705177508910913">Aktueller Nutzer</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer veralteten Codier-Suite verschlüsselt.</translation>
<translation id="5813119285467412249">&amp;Hinzufügen wiederholen</translation>
<translation id="5838278095973806738">Sie sollten keine vertraulichen Informationen wie Passwörter oder Kreditkartennummern auf dieser Website eingeben, da sie von Angreifern gestohlen werden könnten.</translation>
+<translation id="5866257070973731571">Telefonnummer hinzufügen</translation>
<translation id="5869405914158311789">Diese Website ist nicht erreichbar</translation>
<translation id="5869522115854928033">Gespeicherte Passwörter</translation>
<translation id="5872918882028971132">Vorschläge für Eltern</translation>
<translation id="5893752035575986141">Kreditkarten werden akzeptiert.</translation>
-<translation id="5901630391730855834">Gelb</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronisiert)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 wird verwendet}other{# werden verwendet}}</translation>
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Ich möchte automatisch einige Systeminformationen und Seiteninhalte an Google senden<ph name="END_WHITEPAPER_LINK" />, um bei der Erfassung schädlicher Apps und Websites zu helfen. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Kontaktdaten bearbeiten</translation>
<translation id="5967867314010545767">Aus Verlauf entfernen</translation>
<translation id="5975083100439434680">Verkleinern</translation>
+<translation id="597552863672748783">Sicherheitscode bestätigen</translation>
<translation id="598637245381783098">Fehler beim Öffnen der Zahlungs-App</translation>
<translation id="5989320800837274978">Weder feste Proxyserver noch eine PAC-Skript-URL sind festgelegt.</translation>
<translation id="5990559369517809815">Anfragen an den Server wurden durch eine Erweiterung blockiert.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Seite 1}other{Seite #}}</translation>
-<translation id="6017514345406065928">Grün</translation>
<translation id="6017850046339264347">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten sammeln, um Sie auszuspionieren. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synchronisiert)</translation>
<translation id="6027201098523975773">Geben Sie einen Namen ein</translation>
<translation id="6040143037577758943">Schließen</translation>
-<translation id="6042308850641462728">Mehr</translation>
<translation id="6047233362582046994">Wenn Sie die Sicherheitsrisiken kennen, können Sie <ph name="BEGIN_LINK" />diese Website aufrufen<ph name="END_LINK" />, bevor die schädlichen Apps entfernt wurden.</translation>
<translation id="6047927260846328439">Mit diesen Inhalten wird möglicherweise versucht, Sie zu täuschen und so zur Installation von Software oder der Offenlegung personenbezogener Daten zu bringen. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website das Zertifikats-Pinning nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">Dies ist eine Erweiterungsseite</translation>
<translation id="6596325263575161958">Verschlüsselungsoptionen</translation>
<translation id="662080504995468778">Bleiben</translation>
+<translation id="6624427990725312378">Kontaktdaten</translation>
<translation id="6626291197371920147">Gültige Kartennummer hinzufügen</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />-Suche</translation>
<translation id="6630809736994426279">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf Ihrem Mac zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">Zurück</translation>
<translation id="6710594484020273272">&lt;Suchbegriff eingeben&gt;</translation>
<translation id="6711464428925977395">Mit dem Proxyserver ist ein Problem aufgetreten oder die Adresse ist falsch.</translation>
-<translation id="6727102863431372879">Festlegen</translation>
<translation id="674375294223700098">Fehler wegen unbekanntem Serverzertifikat</translation>
<translation id="6753269504797312559">Wert der Richtlinie</translation>
<translation id="6757797048963528358">Ihr Gerät ist im Ruhemodus.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profilpfad</translation>
<translation id="7424977062513257142">Auf einer in dieser Webseite eingebetteten Seite wird Folgendes angezeigt:</translation>
+<translation id="7437289804838430631">Kontaktdaten hinzufügen</translation>
<translation id="7441627299479586546">Falsche(r) Nutzername/Domain der Richtlinie</translation>
<translation id="7444046173054089907">Diese Website ist blockiert</translation>
<translation id="7445762425076701745">Die Identität des Servers, mit dem Sie verbunden sind, kann nicht vollständig überprüft werden. Sie sind mit einem Server verbunden, dessen Name nur innerhalb Ihres Netzwerks gültig ist und dessen Inhaberschaft von einer externen Zertifizierungsstelle nicht überprüft werden kann. Da einige Zertifizierungsstellen ungeachtet dessen dennoch Zertifikate für diese Namen ausstellen, gibt es keine Möglichkeit, sicherzustellen, dass Sie mit der gewünschten Website und nicht mit einem Angreifer verbunden sind.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">Vorwärts</translation>
<translation id="7485870689360869515">Keine Daten gefunden</translation>
<translation id="7508255263130623398">Zurückgegebene Geräte-ID der Richtlinie ist leer oder entspricht nicht der aktuellen Geräte-ID</translation>
+<translation id="7511955381719512146">Unter Umständen erfordert das verwendete WLAN, dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
<translation id="7514365320538308">Herunterladen</translation>
<translation id="7518003948725431193">Für folgende Webadresse wurde keine Webseite gefunden: <ph name="URL" />.</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Die Verbindung zu dieser Website ist nicht sicher</translation>
-<translation id="7535087603100972091">Wert</translation>
<translation id="7537536606612762813">Verbindlich</translation>
<translation id="7542403920425041731">Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="7542995811387359312">Die Funktion zur automatischen Ausfüllung der Kreditkartendaten ist deaktiviert, da dieses Formular keine sichere Verbindung nutzt.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise in betrügerischer Absicht ausgegeben. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="7568593326407688803">Diese Seite ist auf<ph name="ORIGINAL_LANGUAGE" />Soll sie übersetzt werden?</translation>
<translation id="7569952961197462199">Kreditkarte aus Chrome entfernen?</translation>
-<translation id="7569983096843329377">Schwarz</translation>
<translation id="7578104083680115302">Mit Karten, die Sie bei Google gespeichert haben, können Sie schnell und geräteübergreifend auf Websites und in Apps bezahlen.</translation>
<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Das Serverzertifikat verstößt gegen Namensbeschränkungen.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">Unbefugte Dritte auf dieser Website versuchen eventuell, Sie zur Installation von Programmen zu bewegen, die sich nachteilig auf Ihre Browsernutzung auswirken. Dabei kann zum Beispiel Ihre Startseite geändert werden oder es erscheinen zusätzliche Anzeigen auf von Ihnen besuchten Websites.</translation>
<translation id="7674629440242451245">Interessiert an coolen neuen Chrome-Funktionen? Testen Sie unsere Dev-Version unter chrome.com/dev.</translation>
<translation id="7682287625158474539">Versand</translation>
+<translation id="7699293099605015246">Momentan sind keine Artikel verfügbar</translation>
<translation id="7701040980221191251">Keine</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Weiter zu <ph name="SITE" /> (unsicher)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Zertifikat</translation>
<translation id="7716147886133743102">Von Ihrem Administrator blockiert</translation>
<translation id="7716424297397655342">Diese Website kann nicht aus dem Cache geladen werden</translation>
+<translation id="7723047071702270851">Karte bearbeiten</translation>
<translation id="774634243536837715">Gefährliche Inhalte blockiert.</translation>
<translation id="7752995774971033316">Nicht verwaltet</translation>
<translation id="7755287808199759310">Deine Eltern können die Blockierung aufheben</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">Adresse hinzufügen</translation>
<translation id="777702478322588152">Präfektur</translation>
<translation id="7791543448312431591">Hinzufügen</translation>
+<translation id="7793553086574152071">Um die Zahlung das nächste Mal schneller abzuwickeln, speichern Sie diese Karte in Ihrem Google-Konto.</translation>
<translation id="7793809570500803535">Die Webseite unter <ph name="SITE" /> ist möglicherweise vorübergehend nicht verfügbar oder dauerhaft unter einer neuen URL zu erreichen.</translation>
<translation id="7800304661137206267">Die Verbindung ist mit <ph name="CIPHER" /> verschlüsselt; für die Nachrichtenauthentifizierung wird <ph name="MAC" /> verwendet und als Mechanismus für den Schlüsselaustausch <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Website ist vertrauenswürdig</translation>
<translation id="780301667611848630">Kein Interesse</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vorschlag für das Formular aus Chrome entfernen?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> für "<ph name="SEARCH_STRING" />" gefunden</translation>
+<translation id="782886543891417279">Unter Umständen müssen Sie die Anmeldeseite des verwendeten WLAN-Netzwerken (<ph name="WIFI_NAME" />) aufrufen.</translation>
<translation id="785549533363645510">Sie sind jedoch nicht unsichtbar. Der Inkognitomodus verhindert nicht, dass Informationen zu Ihren Webaktivitäten von Ihrem Arbeitgeber, Ihrem Internetanbieter oder den von Ihnen besuchten Websites erfasst werden.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Debit- und Prepaidkarten werden akzeptiert.</translation>
+<translation id="7878562273885520351">Ihr Passwort könnte gefährdet sein</translation>
<translation id="7887683347370398519">Prüfen Sie Ihren CVC und versuchen Sie es dann erneut.</translation>
<translation id="79338296614623784">Geben Sie eine gültige Telefonnummer ein</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverzertifikat ist noch nicht gültig.</translation>
-<translation id="7942349550061667556">Rot</translation>
<translation id="7947285636476623132">Prüfen Sie Ihr Ablaufjahr und versuchen Sie es dann erneut</translation>
<translation id="7951415247503192394">(32-Bit)</translation>
<translation id="7956713633345437162">Mobile Lesezeichen</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">Nachfragen (Standardeinstellung)</translation>
<translation id="8041089156583427627">Feedback geben</translation>
<translation id="8041940743680923270">Globalen Standard verwenden (Fragen)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ist nicht ordnungsgemäß konfiguriert. Durch die Deinstallation von "<ph name="SOFTWARE_NAME" />" sollte das Problem behoben werden. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Der Artikel kann nicht angezeigt werden.</translation>
<translation id="8091372947890762290">Aktivierung auf dem Server steht noch aus.</translation>
+<translation id="8094917007353911263">Unter Umständen erfordert das von Ihnen verwendete Netzwerk, dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
+<translation id="8103161714697287722">Zahlungsmethode</translation>
<translation id="8118489163946903409">Zahlungsmethode</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf Ihrem Computer oder im Netzwerk installiert. Bitten Sie Ihren IT-Administrator, das Problem zu lösen.</translation>
<translation id="8131740175452115882">Bestätigen</translation>
<translation id="8134994873729925007">Die <ph name="BEGIN_ABBR" />DNS-Adresse<ph name="END_ABBR" /> des Servers von <ph name="HOST_NAME" /> wurde nicht gefunden.</translation>
<translation id="8149426793427495338">Ihr Computer ist im Ruhemodus.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">Wenn Sie weitere Informationen dazu benötigen, kann Ihnen Ihr Netzwerkadministrator weiterhelfen.</translation>
<translation id="8293206222192510085">Lesezeichen hinzufügen</translation>
<translation id="8294431847097064396">Quelle</translation>
+<translation id="8298115750975731693">Unter Umständen erfordert das verwendete WLAN (<ph name="WIFI_NAME" />), dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
<translation id="8306404619377842860">Eine private Verbindung mit <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ist nicht möglich, da Datum und Uhrzeit Ihres Geräts (<ph name="DATE_AND_TIME" />) falsch eingestellt sind. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Die Übersetzung ist aufgrund eines Problems mit der Netzwerkverbindung fehlgeschlagen.</translation>
<translation id="8332188693563227489">Der Zugriff auf <ph name="HOST_NAME" /> wurde verweigert</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Kürzlich geschlossen</translation>
<translation id="8874824191258364635">Geben Sie eine gültige Kartennummer ein</translation>
<translation id="8876793034577346603">Fehler beim Parsen der Netzwerkkonfiguration</translation>
-<translation id="8889402386540077796">Farbton</translation>
<translation id="8891727572606052622">Ungültiger Proxy-Modus</translation>
<translation id="889901481107108152">Leider steht dieses Experiment auf Ihrer Plattform nicht zur Verfügung.</translation>
<translation id="8903921497873541725">Vergrößern</translation>
<translation id="8931333241327730545">Möchten Sie diese Karte in Ihrem Google-Konto speichern?</translation>
<translation id="8932102934695377596">Ihre Uhr geht nach.</translation>
+<translation id="893332455753468063">Name hinzufügen</translation>
<translation id="8938939909778640821">Akzeptierte Kredit- und Prepaidkarten</translation>
+<translation id="8957210676456822347">Erfassungsportal-Autorisierung</translation>
<translation id="8971063699422889582">Das Serverzertifikat ist abgelaufen.</translation>
-<translation id="8986494364107987395">Nutzungsstatistiken und Absturzberichte automatisch an Google senden</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Die Website, die Sie aufrufen möchten, enthält schädliche Programme</translation>
<translation id="8997023839087525404">Der Server präsentierte ein Zertifikat, das nicht gemäß der Richtlinie zur Zertifikatstransparenz öffentlich offengelegt wurde. Dies ist für einige Zertifikate jedoch eine Voraussetzung, mit der sichergestellt wird, dass sie vertrauenswürdig sind und vor Angriffen schützen.</translation>
<translation id="9001074447101275817">Für den Proxy <ph name="DOMAIN" /> sind ein Nutzername und ein Passwort erforderlich.</translation>
<translation id="9005998258318286617">Fehler beim Laden des PDF-Dokuments.</translation>
+<translation id="9008201768610948239">Ignorieren</translation>
<translation id="901974403500617787">Parameter, die systemweit gelten, können nur vom Eigentümer festgelegt werden: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Rechnungsadresse für Kreditkarte erforderlich</translation>
<translation id="9020542370529661692">Die Seite wurde übersetzt und liegt nun auf <ph name="TARGET_LANGUAGE" /> vor.</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat sich jedoch mit einem ungültigen Zertifikat ausgewiesen.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Bearbeiten</translation>
-<translation id="9068849894565669697">Farbe auswählen</translation>
<translation id="9069693763241529744">Von einer Erweiterung blockiert</translation>
<translation id="9076283476770535406">Eventuell enthält sie nicht jugendfreie Inhalte</translation>
<translation id="9078964945751709336">Weitere Informationen erforderlich</translation>
+<translation id="9080712759204168376">Bestellübersicht</translation>
<translation id="9103872766612412690"><ph name="SITE" /> schützt Ihre Daten in der Regel durch Verschlüsselung. Als Chromium dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurück. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Chromium die Verbindung vor dem Austausch von Daten unterbrochen hat, sind Ihre Informationen weiterhin sicher.</translation>
+<translation id="9106062320799175032">Rechnungsadresse hinzufügen</translation>
+<translation id="910908805481542201">Helfen Sie mir, dieses Problem zu beheben</translation>
+<translation id="9128870381267983090">Mit Netzwerk verbinden</translation>
<translation id="9137013805542155359">Original anzeigen</translation>
<translation id="9137248913990643158">Melden Sie sich in Chrome an, bevor Sie diese App nutzen.</translation>
<translation id="9148507642005240123">&amp;Bearbeiten rückgängig machen</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> verwendet ein nicht unterstütztes Protokoll.</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="9215416866750762878">Eine Anwendung verhindert, dass Chrome eine sichere Internetverbindung zu dieser Website herstellt</translation>
<translation id="9219103736887031265">Bilder</translation>
<translation id="933612690413056017">Keine Internetverbindung</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Keine}=1{1 Eintrag}other{# Einträge}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Entwickler-Build</translation>
+<translation id="989988560359834682">Adresse bearbeiten</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf Ihrem Computer oder in Ihrem Netzwerk installiert:
+ &lt;ul&gt;
+ &lt;li&gt;Deinstallieren oder deaktivieren Sie "<ph name="SOFTWARE_NAME" />".&lt;/li&gt;
+ &lt;li&gt;Stellen Sie eine Verbindung zu einem anderen Netzwerk her.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index 93aebe3b316..a754258c043 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Σελιδοδείκτες επιτραπέζιου υπολογιστή</translation>
<translation id="1074497978438210769">Μη ασφαλής</translation>
<translation id="1080116354587839789">Προσαρμογή στο πλάτος</translation>
+<translation id="1088860948719068836">Προσθήκη ονόματος στην κάρτα</translation>
<translation id="1103523840287552314">Να μεταφράζονται πάντα τα <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Εμφάνιση όλων των αποθηκευμένων κωδικών πρόσβασης…</translation>
<translation id="1107591249535594099">Εάν επιλεγεί, το Chrome θα αποθηκεύει ένα αντίγραφο της κάρτας σας σε αυτήν τη συσκευή για ταχύτερη συμπλήρωση φορμών.</translation>
<translation id="1111153019813902504">Πρόσφατοι σελιδοδείκτες</translation>
<translation id="1113869188872983271">&amp;Αναίρεση αναδιάταξης</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (συγχρονισμένο)</translation>
<translation id="1263231323834454256">Λίστα ανάγνωσης</translation>
<translation id="1264126396475825575">Καταγράφηκαν αναφορές σφαλμάτων <ph name="CRASH_TIME" /> (δεν έχουν ακόμη μεταφορτωθεί ή παραβλεφθεί)</translation>
+<translation id="1270502636509132238">Τρόπος παραλαβής</translation>
<translation id="1281526147609854549">Εκδόθηκε από <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Να μην γίνεται ποτέ μετάφραση αυτού του ιστότοπου</translation>
<translation id="129553762522093515">Έκλεισαν πρόσφατα</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Αναμονή για σύνδεση…</translation>
<translation id="153384715582417236">Αυτά προς το παρόν</translation>
<translation id="1549470594296187301">Θα πρέπει να ενεργοποιηθεί η JavaScript για τη χρήση αυτής της λειτουργίας.</translation>
-<translation id="1555130319947370107">Μπλε</translation>
<translation id="1559528461873125649">Δεν υπάρχει τέτοιο αρχείο ή κατάλογος</translation>
<translation id="1583429793053364125">Παρουσιάστηκε πρόβλημα κατά την εμφάνιση αυτής της ιστοσελίδας.</translation>
<translation id="1592005682883173041">Πρόσβαση σε τοπικά δεδομένα</translation>
<translation id="1594030484168838125">Επιλογή</translation>
-<translation id="161042844686301425">Κυανό</translation>
<translation id="1620510694547887537">Κάμερα</translation>
<translation id="1629803312968146339">Θέλετε το Chrome να αποθηκεύσει αυτήν την κάρτα;</translation>
<translation id="1639239467298939599">Γίνεται φόρτωση</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Για να επισκεφτείτε αυτήν τη σελίδα, χρειάζεστε άδεια από τον διαχειριστή <ph name="NAME" /></translation>
<translation id="1721424275792716183">* Το πεδίο είναι υποχρεωτικό</translation>
+<translation id="1727741090716970331">Προσθήκη έγκυρου αριθμού κάρτας</translation>
<translation id="1728677426644403582">Βλέπετε την πηγή μιας ιστοσελίδας</translation>
<translation id="173080396488393970">Αυτός ο τύπος κάρτας δεν υποστηρίζεται</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Σφάλμα σειριοποίησης</translation>
<translation id="1974060860693918893">Σύνθετες</translation>
<translation id="1978555033938440688">Έκδοση υλικολογισμικού</translation>
-<translation id="1995859865337580572">Επαληθεύστε τον κωδικό CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{και άλλο 1 άτομο}other{και άλλα # άτομα}}</translation>
<translation id="2025186561304664664">Ο διακομιστής μεσολάβησης έχει ρυθμιστεί σε αυτόματη διαμόρφωση.</translation>
<translation id="2030481566774242610">Μήπως εννοείτε <ph name="LINK" />;</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Αναίρεση</translation>
<translation id="20817612488360358">Οι ρυθμίσεις διακομιστή μεσολάβησης του συστήματος έχουν οριστεί για να χρησιμοποιηθούν, αλλά καθορίζεται επίσης μια ρητή διαμόρφωση του διακομιστή μεσολάβησης.</translation>
<translation id="2086652334978798447">Για να λάβετε εξατομικευμένο περιεχόμενο που προτείνεται από την Google, συνδεθείτε στο Chrome.</translation>
+<translation id="2091887806945687916">Ήχος</translation>
<translation id="2094505752054353250">Αναντιστοιχία τομέα</translation>
<translation id="2096368010154057602">Νομός</translation>
<translation id="2108755909498034140">Επανεκκινήστε τον υπολογιστή σας</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Αγνοήθηκε επειδή αντικαταστάθηκε από την πολιτική <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Αναζήτηση κοντινών σελίδων Φυσικού δικτύου</translation>
<translation id="213826338245044447">Σελιδοδείκτες κινητής συσκευής</translation>
+<translation id="214556005048008348">Ακύρωση πληρωμής</translation>
<translation id="2147827593068025794">Συγχρονισμός παρασκηνίου</translation>
+<translation id="2148613324460538318">Προσθήκη κάρτας</translation>
<translation id="2154054054215849342">Ο συγχρονισμός δεν είναι διαθέσιμος για τον τομέα σας</translation>
<translation id="2154484045852737596">Επεξεργασία κάρτας</translation>
<translation id="2166049586286450108">Πλήρης πρόσβαση διαχειριστή</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 διεύθυνση}other{# διευθύνσεις}}</translation>
<translation id="2187317261103489799">Εντοπισμός (προεπιλογή)</translation>
<translation id="2202020181578195191">Εισαγάγετε ένα έγκυρο έτος λήξης</translation>
+<translation id="2209523182407020534">Οι εφαρμογές που μπορούν να προκαλέσουν αυτό το σφάλμα περιλαμβάνουν λογισμικό προστασίας από ιούς, τείχος προστασίας και λογισμικό φιλτραρίσματος ιστού ή λογισμικό διακομιστή μεσολάβησης.</translation>
<translation id="2212735316055980242">Η πολιτική δε βρέθηκε</translation>
<translation id="2213606439339815911">Ανάκτηση καταχωρίσεων…</translation>
<translation id="2218879909401188352">Οι εισβολείς στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> θα μπορούσαν να εγκαταστήσουν επικίνδυνες εφαρμογές που προκαλούν ζημιά στη συσκευή σας, να προσθέσουν κρυφές χρεώσεις στον λογαριασμό του κινητού σας ή να κλέψουν τα προσωπικά στοιχεία σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε περισσότερα<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Επιστροφή</translation>
<translation id="2503184589641749290">Αποδεκτές χρεωστικές και προπληρωμένες κάρτες</translation>
<translation id="2515629240566999685">Ελέγξτε το σήμα στην περιοχή σας</translation>
+<translation id="2524461107774643265">Προσθήκη περισσότερων πληροφοριών</translation>
+<translation id="2536110899380797252">Προσθήκη διεύθυνσης</translation>
<translation id="2539524384386349900">Αναγνώριση</translation>
<translation id="255002559098805027">Ο κεντρικός υπολογιστής <ph name="HOST_NAME" /> έστειλε μια μη έγκυρη απόκριση.</translation>
<translation id="2556876185419854533">&amp;Αναίρεση επεξεργασίας</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Δεν ήταν δυνατή η επιβεβαίωση της κάρτας σας από το Chromium αυτήν τη στιγμή. Δοκιμάστε ξανά αργότερα.</translation>
<translation id="2705137772291741111">Δεν είναι δυνατή η ανάγνωση του αποθηκευμένου αντιγράφου (κρυφής μνήμης) αυτού του ιστότοπου.</translation>
<translation id="2709516037105925701">Αυτόματη συμπλήρωση</translation>
+<translation id="2710942282213947212">Κάποιο λογισμικό στον υπολογιστή σας παρεμποδίζει την ασφαλή σύνδεση του Chromium στον ιστό</translation>
<translation id="2712173769900027643">Να ζητηθεί άδεια</translation>
-<translation id="2713444072780614174">Λευκό</translation>
<translation id="2720342946869265578">Σε κοντινή απόσταση</translation>
<translation id="2721148159707890343">Το αίτημα ήταν επιτυχές</translation>
<translation id="2728127805433021124">Το πιστοποιητικό του διακομιστή είναι υπογεγραμμένο με έναν αδύναμο αλγόριθμο υπογραφής.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Εντοπίστηκε μια αλλαγή δικτύου.</translation>
<translation id="2916038427272391327">Κλείστε τα άλλα προγράμματα</translation>
<translation id="2922350208395188000">Δεν είναι δυνατός ο έλεγχος του πιστοποιητικού του διακομιστή.</translation>
+<translation id="2925673989565098301">Τρόπος προβολής</translation>
<translation id="2928905813689894207">Διεύθυνση χρέωσης</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ακόμη}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ακόμη}}</translation>
<translation id="2941952326391522266">Ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του είναι από το <ph name="DOMAIN2" />. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Λανθασμένος τύπος πολιτικής</translation>
<translation id="3032412215588512954">Θέλετε να φορτώσετε ξανά αυτόν τον ιστότοπο;</translation>
<translation id="3037605927509011580">Όπα! Κάτι πήγε στραβά!</translation>
+<translation id="3039538478787849737">Να αποθηκευτεί η κάρτα στο Google;</translation>
<translation id="3041612393474885105">Πληροφορίες πιστοποιητικού</translation>
<translation id="3063697135517575841">Δεν ήταν δυνατή η επιβεβαίωση της κάρτας σας από το Chrome αυτήν τη στιγμή. Δοκιμάστε ξανά αργότερα.</translation>
<translation id="3064966200440839136">Αποχώρηση από την κατάσταση ανώνυμης περιήγησης για πληρωμή μέσω εξωτερικής εφαρμογής. Συνέχεια;</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Προσωρινό σφάλμα διακομιστή</translation>
<translation id="3154506275960390542">Αυτή η σελίδα περιέχει μια φόρμα η οποία πιθανώς να μην υποβληθεί με ασφάλεια. Τα δεδομένα που στέλνετε μπορούν να προβληθούν από άλλους κατά την αποστολή ή μπορούν να τροποποιηθούν από κάποιον εισβολέα ώστε να αλλάξει το περιεχόμενο που θα λάβει ο διακομιστής.</translation>
<translation id="3157931365184549694">Επαναφορά</translation>
+<translation id="3162559335345991374">Το Wi-Fi που χρησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη σελίδα σύνδεσής του.</translation>
<translation id="3167968892399408617">Οι σελίδες που προβάλλετε στις καρτέλες της ανώνυμης περιήγησης δεν διατηρούνται στο ιστορικό του προγράμματος περιήγησης, στα cookie ή στο ιστορικό αναζήτησης, αφού κλείσετε όλες τις καρτέλες της ανώνυμης περιήγησης. Τα αρχεία που κατεβάζετε ή οι σελιδοδείκτες που δημιουργείτε θα διατηρούνται.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Νησί</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Ακύρωση πληρωμής</translation>
<translation id="3207960819495026254">Προστέθηκε στους σελιδοδείκτες</translation>
+<translation id="3211223744486044430">Για να πληρώσετε πιο γρήγορα την επόμενη φορά, αποθηκεύστε αυτήν την κάρτα στον Λογαριασμό σας Google και σε αυτήν τη συσκευή.</translation>
<translation id="3225919329040284222">Ο διακομιστής παρουσίασε ένα πιστοποιητικό που δεν αντιστοιχεί στις ενσωματωμένες προϋποθέσεις. Αυτές οι προϋποθέσεις συμπεριλαμβάνονται σε συγκεκριμένους ιστότοπους υψηλής ασφάλειας για την προστασία σας.</translation>
<translation id="3226128629678568754">Πατήστε το κουμπί της επανάληψης φόρτωσης για να υποβάλετε ξανά τα δεδομένα που απαιτούνται για τη φόρτωση της σελίδας.</translation>
<translation id="3227137524299004712">Μικρόφωνο</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Δεν βρέθηκαν αποτελέσματα αναζήτησης</translation>
<translation id="3305707030755673451">Τα δεδομένα σας κρυπτογραφήθηκαν με τη δική σας φράση πρόσβασης συγχρονισμού στις <ph name="TIME" />. Πληκτρολογήστε την για να ξεκινήσει ο συγχρονισμός.</translation>
<translation id="3320021301628644560">Προσθήκη διεύθυνσης χρέωσης</translation>
-<translation id="3329013043687509092">Κορεσμός</translation>
<translation id="333371639341676808">Αποτροπή δημιουργίας πρόσθετων πλαισίων διαλόγου από αυτή τη σελίδα.</translation>
<translation id="3338095232262050444">Ασφαλές</translation>
<translation id="3340978935015468852">ρυθμίσεις</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Αναγνωριστικό πελάτη:</translation>
<translation id="3391030046425686457">Διεύθυνση παράδοσης</translation>
<translation id="3395827396354264108">Τρόπος παραλαβής</translation>
+<translation id="3399952811970034796">Διεύθυνση παράδοσης</translation>
<translation id="3422248202833853650">Δοκιμάστε να εξέλθετε από τα άλλα προγράμματα για να απελευθερώσετε μνήμη.</translation>
<translation id="3422472998109090673">Προς το παρόν, δεν είναι δυνατή η πρόσβαση στον κεντρικό υπολογιστή <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Να επιτρέπεται (προεπιλογή)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Η αναφορά σφαλμάτων καταγράφηκε στις <ph name="CRASH_TIME" /> και μεταφορτώθηκε στις <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Πληροφορίες πιστοποιητικού</translation>
<translation id="3690164694835360974">Μη ασφαλής σύνδεση</translation>
+<translation id="3704162925118123524">Το δίκτυο που χρησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη σελίδα σύνδεσης του.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Φόρτωση...</translation>
<translation id="3712624925041724820">Οι άδειες έχουν εξαντληθεί</translation>
<translation id="3714780639079136834">Ενεργοποιήστε τα δεδομένα κινητής τηλεφωνίας ή το Wi-Fi</translation>
+<translation id="3715597595485130451">Σύνδεση σε Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Ελέγξτε το διακομιστή μεσολάβησης, το τείχος προστασίας και τη διαμόρφωση DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Εάν κατανοείτε τους κινδύνους για την ασφάλειά σας, μπορείτε να <ph name="BEGIN_LINK" />επισκεφτείτε αυτόν τον μη ασφαλή ιστότοπο<ph name="END_LINK" /> πριν από την κατάργηση των επικίνδυνων προγραμμάτων.</translation>
<translation id="3739623965217189342">Σύνδεσμος που αντιγρ.</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Αναίρεση προσθήκης</translation>
<translation id="404928562651467259">ΠΡΟΕΙΔΟΠΟΙΗΣΗ</translation>
<translation id="4058922952496707368">Κλειδί "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">Προσθήκη έγκυρης διεύθυνσης</translation>
<translation id="4072486802667267160">Προέκυψε σφάλμα κατά την επεξεργασία της παραγγελίας σας. Δοκιμάστε ξανά.</translation>
<translation id="4075732493274867456">Η εφαρμογή πελάτης και ο διακομιστής δεν υποστηρίζουν κάποια κοινή έκδοση πρωτοκόλλου SSL ή σουίτα κρυπτογράφησης.</translation>
<translation id="4079302484614802869">Η διαμόρφωση του διακομιστή μεσολάβησης είναι ορισμένη να χρησιμοποιεί μια διεύθυνση URL σεναρίου .pac και όχι σταθερούς διακομιστές μεσολάβησης.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Ο σειριακός αριθμός της συσκευής δεν είναι έγκυρος</translation>
<translation id="410351446219883937">Αυτόματη αναπαραγωγή</translation>
<translation id="4103763322291513355">Επισκεφτείτε την &lt;strong&gt;chrome://policy&lt;/strong&gt; για να δείτε τη λίστα των ανεπιθύμητων διευθύνσεων URL και άλλες πολιτικές που έχουν τεθεί σε εφαρμογή από το διαχειριστή του συστήματός σας.</translation>
-<translation id="4115378294792113321">Ματζέντα</translation>
<translation id="4116663294526079822">Να επιτρέπεται πάντα σε αυτόν τον ιστότοπο</translation>
<translation id="4117700440116928470">Το εύρος της πολιτικής δεν υποστηρίζεται.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 ακόμα}other{# ακόμα}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Προσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, όμως το πιστοποιητικό που παρουσιάστηκε από το διακομιστή ανακλήθηκε από τον εκδότη του. Αυτό σημαίνει ότι τα διαπιστευτήρια ασφαλείας που παρουσιάστηκαν από το διακομιστή δεν πρέπει σε καμία περίπτωση να θεωρηθούν αξιόπιστα. Ενδέχεται να επικοινωνείτε με κάποιον εισβολέα.</translation>
<translation id="4394049700291259645">Απενεργοποίηση</translation>
<translation id="4406896451731180161">αποτελέσματα αναζήτησης</translation>
+<translation id="4415426530740016218">Διεύθυνση παραλαβής</translation>
<translation id="4424024547088906515">Ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωρείται έμπιστο από τον Chrome. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
<translation id="4432688616882109544">Ο κεντρικός υπολογιστής <ph name="HOST_NAME" /> δεν αποδέχτηκε το πιστοποιητικό σύνδεσής σας ή μπορεί να μην διατέθηκε πιστοποιητικό σύνδεσης.</translation>
<translation id="443673843213245140">Η χρήση ενός διακομιστή μεσολάβησης είναι απενεργοποιημένη, αλλά έχει καθοριστεί μια ρητή διαμόρφωση διακομιστή μεσολάβησης.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Δοκιμάστε να απενεργοποιήσετε τις επεκτάσεις σας.</translation>
<translation id="457875822857220463">Παράδοση</translation>
+<translation id="4582800630050655161">Μπορεί να χάσετε την πρόσβαση στον Λογαριασμό σας Google ή να πέσετε θύμα κλοπής στοιχείων ταυτότητας. Το Chromium συνιστά να αλλάξετε τον κωδικό πρόσβασής σας τώρα.</translation>
<translation id="4587425331216688090">Κατάργηση διεύθυνσης από το Chrome;</translation>
<translation id="4592951414987517459">Η σύνδεσή σας στο <ph name="DOMAIN" /> κρυπτογραφείται χρησιμοποιώντας ένα σύγχρονο πρόγραμμα κρυπτογράφησης.</translation>
<translation id="4594403342090139922">&amp;Αναίρεση διαγραφής</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">Ο διακομιστής δεν κατάφερε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του περιέχει σφάλματα. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
<translation id="4690462567478992370">Διακοπή χρήσης μη έγκυρου πιστοποιητικού</translation>
+<translation id="4690954380545377795">Μπορεί να χάσετε την πρόσβαση στον Λογαριασμό σας Google ή να πέσετε θύμα κλοπής στοιχείων ταυτότητας. Το Chrome συνιστά να αλλάξετε τον κωδικό πρόσβασής σας τώρα.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Η σύνδεσή σας διακόπηκε</translation>
<translation id="471880041731876836">Δεν έχετε άδεια να επισκεφτείτε αυτόν τον ιστότοπο</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Να εκτελέσετε τον Διαγνωστικό έλεγχο δικτύου των Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Η πληρωμή σας</translation>
<translation id="4726672564094551039">Επανάληψη φόρτωσης πολιτικών</translation>
<translation id="4728558894243024398">Πλατφόρμα</translation>
<translation id="4736825316280949806">Επανεκκινήστε το Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Η αποθήκευση αντιγράφων ασφαλείας είναι σε κακή κατάσταση</translation>
<translation id="5023310440958281426">Ελέγξτε τις πολιτικές του διαχειριστή</translation>
<translation id="5029568752722684782">Διαγραφή αντιγράφου</translation>
+<translation id="503069730517007720">Απαιτείται πιστοποιητικό ρίζας για το λογισμικό "<ph name="SOFTWARE_NAME" />" αλλά δεν έχει εγκατασταθεί. Ο διαχειριστής IT πρέπει να εξετάσει τις οδηγίες διαμόρφωσης για το λογισμικό "<ph name="SOFTWARE_NAME" />", προκειμένου να διορθώσει αυτό το πρόβλημα. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Σχετικά με τη Google Μετάφραση</translation>
<translation id="5039804452771397117">Επιτρέπεται</translation>
<translation id="5040262127954254034">Απόρρητο</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Πειράματα</translation>
<translation id="5205222826937269299">Απαιτείται όνομα</translation>
<translation id="5222812217790122047">Απαιτείται διεύθυνση ηλεκτρονικού ταχυδρομείου</translation>
+<translation id="522700295135997067">Αυτός ο ιστότοπος μπορεί να έχει υποκλέψει τον κωδικό πρόσβασής σας</translation>
+<translation id="5230733896359313003">Διεύθυνση αποστολής</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Χρησιμοποιείτε το Chrome στη δουλειά σας; Οι επιχειρήσεις μπορούν να διαχειρίζονται τις ρυθμίσεις του Chrome για τους εργαζόμενούς τους. Μάθετε περισσότερα</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Ακολουθήστε αυτά τα βήματα, για να απενεργοποιήσετε προσωρινά το λογισμικό, προκειμένου να συνδεθείτε στον ιστό. Θα πρέπει να έχετε προνόμια προγραμματιστή.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Η σύνδεσή σας σε αυτόν τον ιστότοπο δεν είναι ιδιωτική. Για έξοδο από τη λειτουργία VR, ανά πάσα στιγμή, αφαιρέστε το ακουστικό και πιέστε πίσω.</translation>
<translation id="5299298092464848405">Σφάλμα ανάλυσης πολιτικής</translation>
+<translation id="5308380583665731573">Σύνδεση</translation>
<translation id="5308689395849655368">Η αναφορά σφαλμάτων είναι απενεργοποιημένη.</translation>
<translation id="5317780077021120954">Αποθήκευση</translation>
<translation id="5327248766486351172">Όνομα</translation>
+<translation id="5332219387342487447">Μέθοδος αποστολής</translation>
<translation id="5355557959165512791">Δεν μπορείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή επειδή το πιστοποιητικό έχει ανακληθεί. Τα σφάλματα δικτύου και οι επιθέσεις είναι συνήθως προσωρινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουργήσει αργότερα.</translation>
<translation id="536296301121032821">Αποτυχία αποθήκευσης ρυθμίσεων πολιτικής</translation>
<translation id="5386426401304769735">Η αλυσίδα πιστοποιητικού για αυτόν τον ιστότοπο περιέχει ένα πιστοποιητικό το οποίο είναι υπογεγραμμένο με χρήση SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Αυτός ο ιστότοπος που βρίσκεται στο εσωτερικό δίκτυο της εταιρείας, του οργανισμού ή του σχολείου έχει το ίδιο URL με έναν εξωτερικό ιστότοπο.
<ph name="LINE_BREAK" />
Δοκιμάστε να επικοινωνήσετε με το διαχειριστή δικτύου σας.</translation>
+<translation id="5499929369096410817">Εισαγάγετε τον κωδικό ασφαλείας για την πιστωτική κάρτα <ph name="CREDIT_CARD" />. Αυτός ο κωδικός δεν θα αποθηκευτεί.</translation>
<translation id="5509780412636533143">Διαχειριζόμενοι σελιδοδείκτες</translation>
<translation id="5510766032865166053">Ενδέχεται να έχει μετακινηθεί ή να έχει διαγραφεί.</translation>
<translation id="5523118979700054094">Όνομα πολιτικής</translation>
<translation id="552553974213252141">Έγινε σωστή εξαγωγή του κειμένου;</translation>
<translation id="5540224163453853">Δεν ήταν δυνατή η εύρεση του άρθρου που ζητήσατε.</translation>
+<translation id="5541546772353173584">Προσθήκη διεύθυνσης ηλεκτρονικού ταχυδρομείου</translation>
<translation id="5544037170328430102">Μια ενσωματωμένη σελίδα στον ιστότοπο <ph name="SITE" /> λέει:</translation>
+<translation id="5545756402275714221">Άρθρα για εσάς</translation>
<translation id="5556459405103347317">Επαναφόρτωση</translation>
<translation id="5560088892362098740">Ημερομηνία λήξης</translation>
<translation id="5565735124758917034">Ενεργό</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Διεύθυνση ηλεκτρονικού ταχυδρομείου</translation>
<translation id="5669703222995421982">Λήψη εξατομικευμένου περιεχομένου</translation>
<translation id="5675650730144413517">Αυτή η σελίδα δεν λειτουργεί</translation>
+<translation id="5689199277474810259">Εξαγωγή σε JSON</translation>
<translation id="5710435578057952990">Η ταυτότητα αυτού του ιστότοπου δεν έχει επαληθευτεί.</translation>
<translation id="5719499550583120431">Οι προπληρωμένες κάρτες γίνονται δεκτές.</translation>
<translation id="5720705177508910913">Τρέχων χρήστης</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Η σύνδεσή σας στο <ph name="DOMAIN" /> κρυπτογραφείται χρησιμοποιώντας ένα απαρχαιωμένο πρόγραμμα κρυπτογράφησης.</translation>
<translation id="5813119285467412249">&amp;Επανάληψη προσθήκης</translation>
<translation id="5838278095973806738">Δεν θα πρέπει να εισαγάγετε ευαίσθητες πληροφορίες σε αυτόν τον ιστότοπο (για παράδειγμα, κωδικούς πρόσβασης ή πιστωτικές κάρτες), επειδή ενδέχεται να υποκλαπούν από εισβολείς.</translation>
+<translation id="5866257070973731571">Προσθήκη αριθμού τηλεφώνου</translation>
<translation id="5869405914158311789">Δεν είναι δυνατή η πρόσβαση σε αυτόν τον ιστότοπο</translation>
<translation id="5869522115854928033">Αποθηκευμένοι κωδικοί πρόσβασης</translation>
<translation id="5872918882028971132">Γονικές προτάσεις</translation>
<translation id="5893752035575986141">Οι πιστωτικές κάρτες γίνονται δεκτές.</translation>
-<translation id="5901630391730855834">Κίτρινο</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (συγχρονισμένο)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 σε χρήση}other{# σε χρήση}}</translation>
<translation id="5959728338436674663">Αυτόματη αποστολή ορισμένων <ph name="BEGIN_WHITEPAPER_LINK" />πληροφοριών συστήματος και περιεχομένου σελίδων<ph name="END_WHITEPAPER_LINK" /> στην Google για διευκόλυνση του εντοπισμού επικίνδυνων εφαρμογών και ιστοτόπων<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Επεξεργασία στοιχείων επικοινωνίας</translation>
<translation id="5967867314010545767">Κατάργηση από το ιστορικό</translation>
<translation id="5975083100439434680">Σμίκρυνση</translation>
+<translation id="597552863672748783">Επιβεβαίωση κωδικού ασφαλείας</translation>
<translation id="598637245381783098">Δεν είναι δυνατό το άνοιγμα της εφαρμογής πληρωμής</translation>
<translation id="5989320800837274978">Δεν προσδιορίζονται ούτε οι σταθεροί διακομιστές μεσολάβησης ούτε μια διεύθυνση URL σεναρίου .pac.</translation>
<translation id="5990559369517809815">Τα αιτήματα για τον διακομιστή έχουν αποκλειστεί από μια επέκταση.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1 σελίδα}other{# σελίδες}}</translation>
-<translation id="6017514345406065928">Πράσινο</translation>
<translation id="6017850046339264347">Οι εισβολείς στον ιστότοπο <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (συγχρονισμένο)</translation>
<translation id="6027201098523975773">Εισαγωγή ονόματος</translation>
<translation id="6040143037577758943">Κλείσιμο</translation>
-<translation id="6042308850641462728">Περισσότερα</translation>
<translation id="6047233362582046994">Εάν κατανοείτε τους κινδύνους για την ασφάλειά σας, μπορείτε να <ph name="BEGIN_LINK" />επισκεφτείτε αυτόν τον ιστότοπο<ph name="END_LINK" /> πριν από την κατάργηση των επιβλαβών εφαρμογών.</translation>
<translation id="6047927260846328439">Αυτό το περιεχόμενο μπορεί να προσπαθήσει να σας εξαπατήσει έτσι ώστε να εγκαταστήσετε λογισμικό ή να αποκαλύψετε προσωπικά στοιχεία. <ph name="BEGIN_LINK" />Εμφάνιση ούτως ή άλλως<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Δεν μπορείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος χρησιμοποιεί certificate pinning (κλείδωμα πιστοποιητικών). Τα σφάλματα δικτύου και οι επιθέσεις είναι συνήθως προσωρινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουργήσει αργότερα.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Βλέπετε μια σελίδα επέκτασης</translation>
<translation id="6596325263575161958">Επιλογές κρυπτογράφησης</translation>
<translation id="662080504995468778">Παραμονή</translation>
+<translation id="6624427990725312378">Στοιχεία επικοινωνίας</translation>
<translation id="6626291197371920147">Προσθήκη έγκυρου αριθμού κάρτας</translation>
<translation id="6628463337424475685">Αναζήτηση <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Οι εισβολείς που βρίσκονται αυτήν τη στιγμή στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ενδέχεται να επιχειρήσουν να εγκαταστήσουν επικίνδυνα προγράμματα στον υπολογιστή σας Mac, για να υποκλέψουν ή να διαγράψουν τα δεδομένα σας (για παράδειγμα, φωτογραφίες, κωδικούς πρόσβασης, μηνύματα και πιστωτικές κάρτες). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε περισσότερα<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Προηγούμενο</translation>
<translation id="6710594484020273272">&lt;Πληκτρολογήστε όρο αναζήτησης&gt;</translation>
<translation id="6711464428925977395">Υπάρχει κάποιο πρόβλημα με το διακομιστή μεσολάβησης ή η διεύθυνση είναι εσφαλμένη.</translation>
-<translation id="6727102863431372879">Ορισμός</translation>
<translation id="674375294223700098">Άγνωστο σφάλμα πιστοποιητικού διακομιστή</translation>
<translation id="6753269504797312559">Τιμή πολιτικής</translation>
<translation id="6757797048963528358">Η συσκευή σας τέθηκε σε αδράνεια.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Διαδρομή προφίλ</translation>
<translation id="7424977062513257142">Μια ενσωματωμένη σελίδα σε αυτό τον ιστότοπο λέει:</translation>
+<translation id="7437289804838430631">Προσθήκη στοιχείων επικοινωνίας</translation>
<translation id="7441627299479586546">Εσφαλμένο θέμα πολιτικής</translation>
<translation id="7444046173054089907">Αυτός ο ιστότοπος είναι αποκλεισμένος</translation>
<translation id="7445762425076701745">Η ταυτότητα του διακομιστή στον οποίο έχετε συνδεθεί δεν μπορεί να επικυρωθεί πλήρως. Είστε συδεδεμένοι σε ένα διακομιστή χρησιμοποιώντας ένα όνομα που είναι έγκυρο μόνο εντός του δικτύου σας, την κατοχή του οποίου δεν έχει τρόπο να επικυρώσει μια εξωτερική αρχή πιστοποίησης. Καθώς ορισμένες αρχές πιστοποιητικών εκδίδουν πιστοποιητικά για αυτά τα ονόματα ούτως ή άλλως, δεν υπάρχει τρόπος να βεβαιωθείτε ότι είστε συνδεδεμένοι στον ιστότοπο που επιθυμείτε και όχι σε έναν εισβολέα.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Προώθηση</translation>
<translation id="7485870689360869515">Δεν βρέθηκαν δεδομένα</translation>
<translation id="7508255263130623398">Η εμφανιζόμενη συσκευή πολιτικής είναι κενή ή δεν αντιστοιχεί στο τρέχον αναγνωριστικό συσκευής</translation>
+<translation id="7511955381719512146">Το Wi-Fi που χρησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη διεύθυνση <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Λήψη</translation>
<translation id="7518003948725431193">Δεν βρέθηκε καμία ιστοσελίδα για τη διεύθυνση ιστού:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Η σύνδεσή σας σε αυτόν τον ιστότοπο δεν είναι ιδιωτική</translation>
-<translation id="7535087603100972091">Τιμή</translation>
<translation id="7537536606612762813">Υποχρεωτική</translation>
<translation id="7542403920425041731">Μετά την επιβεβαίωση, τα στοιχεία της κάρτας θα κοινοποιηθούν σε αυτόν τον ιστότοπο.</translation>
<translation id="7542995811387359312">Η αυτόματη συμπλήρωση πιστωτικής κάρτας έχει απενεργοποιηθεί, επειδή αυτή η φόρμα δεν χρησιμοποιεί ασφαλή σύνδεση.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μπορεί να εκδόθηκε παράνομα. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
<translation id="7568593326407688803">Αυτή η σελίδα είναι στα<ph name="ORIGINAL_LANGUAGE" />Θέλετε να τη μεταφράσετε;</translation>
<translation id="7569952961197462199">Κατάργηση πιστωτικής κάρτας από το Chrome;</translation>
-<translation id="7569983096843329377">Μαύρο</translation>
<translation id="7578104083680115302">Κάντε γρήγορες πληρωμές σε ιστότοπους και εφαρμογές σε διαφορετικές συσκευές χρησιμοποιώντας κάρτες που έχετε αποθηκεύσει στο Google.</translation>
<translation id="7588950540487816470">Φυσικό δίκτυο</translation>
<translation id="7592362899630581445">Το πιστοποιητικό του διακομιστή παραβαίνει τους περιορισμούς ονόματος.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Οι εισβολείς σε αυτόν τον ιστότοπο μπορεί να επιχειρήσουν να σας ξεγελάσουν, έτσι ώστε να εγκαταστήσετε προγράμματα που βλάπτουν την εμπειρία περιήγησής σας (για παράδειγμα, αλλάζοντας την αρχική σελίδα σας ή εμφανίζοντας επιπλέον διαφημίσεις στους ιστότοπους που επισκέπτεστε).</translation>
<translation id="7674629440242451245">Θέλετε να ενημερώνεστε για τις συναρπαστικές νέες δυνατότητες του Chrome; Επισκεφτείτε το κανάλι προγραμματιστών στη διεύθυνση chrome.com/dev.</translation>
<translation id="7682287625158474539">Αποστολή</translation>
+<translation id="7699293099605015246">Δεν υπάρχουν διαθέσιμα άρθρα αυτήν τη στιγμή</translation>
<translation id="7701040980221191251">Καμία</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Μετάβαση στον ιστότοπο <ph name="SITE" /> (μη ασφαλής)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Πιστοποιητικό</translation>
<translation id="7716147886133743102">Αποκλείστηκε από τον διαχειριστή σας</translation>
<translation id="7716424297397655342">Δεν είναι δυνατή η φόρτωση αυτού του ιστότοπου από την κρυφή μνήμη</translation>
+<translation id="7723047071702270851">Επεξεργασία κάρτας</translation>
<translation id="774634243536837715">Το επικίνδυνο περιεχόμενο αποκλείστηκε.</translation>
<translation id="7752995774971033316">Χωρίς διαχείριση</translation>
<translation id="7755287808199759310">Ο γονέας σας μπορεί να καταργήσει τον αποκλεισμό του για εσάς</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Προσθήκη διεύθυνσης</translation>
<translation id="777702478322588152">Νομαρχία</translation>
<translation id="7791543448312431591">Προσθήκη</translation>
+<translation id="7793553086574152071">Για να πληρώσετε πιο γρήγορα την επόμενη φορά, αποθηκεύστε αυτήν την κάρτα στον Λογαριασμό σας Google.</translation>
<translation id="7793809570500803535">Η ιστοσελίδα στη διεύθυνση <ph name="SITE" /> μπορεί να βρίσκεται προσωρινά εκτός λειτουργίας ή ίσως έχει μεταφερθεί μόνιμα σε νέα διεύθυνση ιστού.</translation>
<translation id="7800304661137206267">Η σύνδεση είναι κρυπτογραφημένη με χρήση <ph name="CIPHER" />, με <ph name="MAC" /> για έλεγχο ταυτότητας μηνυμάτων και <ph name="KX" /> ως μηχανισμό ανταλλαγής κλειδιών.</translation>
+<translation id="7802523362929240268">Ο ιστότοπος είναι νόμιμος</translation>
<translation id="780301667611848630">Όχι, ευχαριστώ</translation>
<translation id="7805768142964895445">Κατάσταση</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Κατάργηση πρότασης φόρμας από το Chrome;</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="785549533363645510">Ωστόσο, δεν είστε αόρατος/η. Με την κατάσταση ανώνυμης περιήγησης δεν μπορείτε να αποκρύψετε τα στοιχεία της περιήγησής σας από τους εργοδότες σας, τον πάροχο υπηρεσιών διαδικτύου που χρησιμοποιείτε ή τους ιστότοπους που επισκέπτεστε.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Οι χρεωστικές και οι προπληρωμένες κάρτες γίνονται δεκτές.</translation>
+<translation id="7878562273885520351">Ο κωδικός πρόσβασής σας μπορεί να έχει παραβιαστεί</translation>
<translation id="7887683347370398519">Ελέγξτε τον κωδικό σας CVC και δοκιμάστε ξανά</translation>
<translation id="79338296614623784">Εισαγάγετε έναν έγκυρο αριθμό τηλεφώνου</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Το πιστοποιητικό του διακομιστή δεν είναι ακόμα έγκυρο.</translation>
-<translation id="7942349550061667556">Κόκκινο</translation>
<translation id="7947285636476623132">Ελέγξτε το έτος λήξης σας και δοκιμάστε ξανά</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Σελιδοδείκτες κινητής συσκευής</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Να γίνεται ερώτηση (προεπιλογή)</translation>
<translation id="8041089156583427627">Αποστολή σχολίων</translation>
<translation id="8041940743680923270">Χρήση καθολικής προεπιλεγμένης ρύθμισης (Ερώτηση)</translation>
+<translation id="8057711352706143257">Το λογισμικό "<ph name="SOFTWARE_NAME" />" δεν έχει διαμορφωθεί σωστά. Το πρόβλημα διορθώνεται συνήθως με την απεγκατάσταση του λογισμικού "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Αποτυχία προβολής άρθρου.</translation>
<translation id="8091372947890762290">Η ενεργοποίηση στο διακομιστή εκκρεμεί</translation>
+<translation id="8094917007353911263">Το δίκτυο που χρησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη διεύθυνση <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Τρόπος πληρωμής</translation>
<translation id="8118489163946903409">Τρόπος πληρωμής</translation>
+<translation id="8127301229239896662">Το λογισμικό "<ph name="SOFTWARE_NAME" />" δεν εγκαταστάθηκε σωστά στον υπολογιστή ή στο δίκτυό σας. Ζητήστε από τον διαχειριστή IT να επιλύσει αυτό το πρόβλημα.</translation>
<translation id="8131740175452115882">Επιβεβαίωση</translation>
<translation id="8134994873729925007">Δεν ήταν δυνατή η εύρεση της <ph name="BEGIN_ABBR" />διεύθυνσης DNS<ph name="END_ABBR" /> του διακομιστή <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ο υπολογιστής σας τέθηκε σε αδράνεια.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Επικοινωνήστε με το διαχειριστή του δικτύου σας εάν δεν είστε βέβαιοι για το τι σημαίνει αυτό.</translation>
<translation id="8293206222192510085">Προσθήκη σελιδοδείκτη</translation>
<translation id="8294431847097064396">Πηγή</translation>
+<translation id="8298115750975731693">Το Wi-Fi που χρησιμοποιείτε (<ph name="WIFI_NAME" />) ενδέχεται να σας ζητήσει να επισκεφτείτε τη διεύθυνση <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Δεν είναι δυνατή η δημιουργία μιας ιδιωτικής σύνδεσης <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημερομηνία και η ώρα της συσκευής σας (<ph name="DATE_AND_TIME" />) είναι λανθασμένες. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε περισσότερα<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Η μετάφραση απέτυχε λόγω προβλήματος με τη σύνδεση δικτύου.</translation>
<translation id="8332188693563227489">Απορρίφθηκε η πρόσβαση στο κεντρικό υπολογιστή <ph name="HOST_NAME" /></translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Έκλεισαν πρόσφατα</translation>
<translation id="8874824191258364635">Εισαγάγετε έναν έγκυρο αριθμό κάρτας</translation>
<translation id="8876793034577346603">Αποτυχία ανάλυσης της διαμόρφωσης δικτύου</translation>
-<translation id="8889402386540077796">Απόχρωση</translation>
<translation id="8891727572606052622">Μη έγκυρη λειτουργία διακομιστή μεσολάβησης.</translation>
<translation id="889901481107108152">Λυπούμαστε, αυτό το πείραμα δεν είναι διαθέσιμο στην πλατφόρμα σας.</translation>
<translation id="8903921497873541725">Μεγέθυνση</translation>
<translation id="8931333241327730545">Θέλετε να αποθηκεύσετε αυτήν την κάρτα στο Λογαριασμό σας Google;</translation>
<translation id="8932102934695377596">Το ρολόι σας πάει πίσω</translation>
+<translation id="893332455753468063">Προσθήκη ονόματος</translation>
<translation id="8938939909778640821">Αποδεκτές πιστωτικές και προπληρωμένες κάρτες</translation>
+<translation id="8957210676456822347">Εξουσιοδότηση πύλης υποδοχής</translation>
<translation id="8971063699422889582">Το πιστοποιητικό του διακομιστή έχει λήξει.</translation>
-<translation id="8986494364107987395">Αυτόματη αποστολή στατιστικών στοιχείων χρήσης και αναφορών σφαλμάτων στην Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Ο ιστότοπος που πρόκειται να επισκεφτείτε περιέχει κακόβουλα προγράμματα</translation>
<translation id="8997023839087525404">Ο διακομιστής παρουσίασε ένα πιστοποιητικό το οποίο δεν αποκαλύφθηκε δημοσίως με χρήση της πολιτικής Διαφάνειας πιστοποιητικών. Αυτό απαιτείται για ορισμένα πιστοποιητικά, προκειμένου να διασφαλιστεί ότι είναι αξιόπιστα και παρέχουν προστασία ενάντια σε εισβολείς.</translation>
<translation id="9001074447101275817">Απαιτείται όνομα χρήστη και κωδικός πρόσβασης για το διακομιστή μεσολάβησης <ph name="DOMAIN" />.</translation>
<translation id="9005998258318286617">Η φόρτωση του εγγράφου PDF απέτυχε.</translation>
+<translation id="9008201768610948239">Παράβλεψη</translation>
<translation id="901974403500617787">Οι επισημάνσεις που ισχύουν για ολόκληρο το σύστημα μπορούν να οριστούν μόνο από τον κάτοχο: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Απαιτείται διεύθυνση χρέωσης της κάρτας</translation>
<translation id="9020542370529661692">Αυτή η σελίδα έχει μεταφραστεί στα <ph name="TARGET_LANGUAGE" />.</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Επιχειρήσατε να μεταβείτε στον <ph name="DOMAIN" /> , αλλά ο διακομιστής παρουσίασε ένα μη έγκυρο πιστοποιητικό.</translation>
<translation id="9050666287014529139">Φράση πρόσβασής σας</translation>
<translation id="9065203028668620118">Επεξεργασία</translation>
-<translation id="9068849894565669697">Επιλογή χρώματος</translation>
<translation id="9069693763241529744">Αποκλείστηκε από μια επέκταση</translation>
<translation id="9076283476770535406">Μπορεί να διαθέτει περιεχόμενο για ενηλίκους</translation>
<translation id="9078964945751709336">Απαιτούνται περισσότερες πληροφορίες</translation>
+<translation id="9080712759204168376">Σύνοψη παραγγελίας</translation>
<translation id="9103872766612412690">Κανονικά, ο ιστότοπος <ph name="SITE" /> χρησιμοποιεί κρυπτογράφηση για να προστατεύει τα στοιχεία σας. Όταν το Chromium επιχείρησε πρόσφατα να συνδεθεί στο <ph name="SITE" />, ο ιστότοπος ανταποκρίθηκε δημιουργώντας ασυνήθιστα και εσφαλμένα διαπιστευτήρια. Αυτό μπορεί να συμβεί όταν κάποιος εισβολέας προσπαθεί να υποκριθεί ότι είναι ο ιστότοπος <ph name="SITE" /> ή όταν κάποια οθόνη σύνδεσης Wi-Fi έχει διακόψει τη σύνδεσή σας. Τα στοιχεία σας εξακολουθούν να είναι ασφαλή επειδή το Chromium διέκοψε τη σύνδεση πριν από την ανταλλαγή δεδομένων.</translation>
+<translation id="9106062320799175032">Προσθήκη διεύθυνσης χρέωσης</translation>
+<translation id="910908805481542201">Βοήθεια για επίλυση του προβλήματος</translation>
+<translation id="9128870381267983090">Σύνδεση σε δίκτυο</translation>
<translation id="9137013805542155359">Εμφάνιση πρωτοτύπου</translation>
<translation id="9137248913990643158">Εκκινήστε και συνδεθείτε στο Chrome πριν χρησιμοποιήσετε αυτήν την εφαρμογή.</translation>
<translation id="9148507642005240123">&amp;Αναίρεση επεξεργασίας</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419">Ο κεντρικός υπολογιστής <ph name="HOST_NAME" /> χρησιμοποιεί μη υποστηριζόμενο πρωτόκολλο.</translation>
<translation id="9205078245616868884">Τα δεδομένα σας είναι κρυπτογραφημένα με τη δική σας φράση πρόσβασης συγχρονισμού. Πληκτρολογήστε την για να ξεκινήσει ο συγχρονισμός.</translation>
<translation id="9207861905230894330">Αποτυχία προσθήκης άρθρου.</translation>
+<translation id="9215416866750762878">Μια εφαρμογή παρεμποδίζει την ασφαλή σύνδεση του Chrome σε αυτόν τον ιστότοπο</translation>
<translation id="9219103736887031265">Εικόνες</translation>
<translation id="933612690413056017">Δεν υπάρχει σύνδεση στο διαδίκτυο</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Κανένα}=1{1 στοιχείο}other{# στοιχεία}}</translation>
<translation id="981121421437150478">Εκτός σύνδεσης</translation>
<translation id="988159990683914416">Έκδοση προγραμματιστή</translation>
+<translation id="989988560359834682">Επεξεργασία διεύθυνσης</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Το λογισμικό "<ph name="SOFTWARE_NAME" />" δεν εγκαταστάθηκε σωστά στον υπολογιστή ή στο δίκτυό σας:
+ &lt;ul&gt;
+ &lt;li&gt;Δοκιμάστε να απεγκαταστήσετε το λογισμικό "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Δοκιμάστε να συνδεθείτε σε κάποιο άλλο δίκτυο&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index 395afc0996e..f3be3f400ad 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Desktop Bookmarks</translation>
<translation id="1074497978438210769">Not secure</translation>
<translation id="1080116354587839789">Fit to width</translation>
+<translation id="1088860948719068836">Add Name on Card</translation>
<translation id="1103523840287552314">Always translate <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Show all saved passwords...</translation>
<translation id="1107591249535594099">If ticked, Chrome will store a copy of your card on this device for faster form filling.</translation>
<translation id="1111153019813902504">Recent bookmarks</translation>
<translation id="1113869188872983271">&amp;Undo reorder</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synced)</translation>
<translation id="1263231323834454256">Reading list</translation>
<translation id="1264126396475825575">Crash report captured on <ph name="CRASH_TIME" /> (not yet uploaded or ignored)</translation>
+<translation id="1270502636509132238">Pickup Method</translation>
<translation id="1281526147609854549">Issued by <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Never translate this site</translation>
<translation id="129553762522093515">Recently closed</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Waiting for connection…</translation>
<translation id="153384715582417236">That’s all for now</translation>
<translation id="1549470594296187301">JavaScript must be enabled to use this feature.</translation>
-<translation id="1555130319947370107">Blue</translation>
<translation id="1559528461873125649">No such file or directory</translation>
<translation id="1583429793053364125">Something went wrong while displaying this web page.</translation>
<translation id="1592005682883173041">Local Data Access</translation>
<translation id="1594030484168838125">Choose</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1629803312968146339">Do you want Chrome to save this card?</translation>
<translation id="1639239467298939599">Loading</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">You need permission from <ph name="NAME" /> to visit this site</translation>
<translation id="1721424275792716183">* Field is required</translation>
+<translation id="1727741090716970331">Add Valid Card Number</translation>
<translation id="1728677426644403582">You're viewing the source of a web page</translation>
<translation id="173080396488393970">This type of card isn’t supported</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serialisation error</translation>
<translation id="1974060860693918893">Advanced</translation>
<translation id="1978555033938440688">Firmware Version</translation>
-<translation id="1995859865337580572">Please verify your CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{and 1 more}other{and # more}}</translation>
<translation id="2025186561304664664">Proxy is set to auto-configured.</translation>
<translation id="2030481566774242610">Did you mean <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">To get personalised content suggested by Google, sign in to Chrome.</translation>
+<translation id="2091887806945687916">Sound</translation>
<translation id="2094505752054353250">Domain mismatch</translation>
<translation id="2096368010154057602">Department</translation>
<translation id="2108755909498034140">Restart your computer</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignored because it was overridden by <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Looking for nearby Physical Web pages</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="2154054054215849342">Sync is not available for your domain</translation>
<translation id="2154484045852737596">Edit card</translation>
<translation id="2166049586286450108">Full Admin Access</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}other{# addresses}}</translation>
<translation id="2187317261103489799">Detect (default)</translation>
<translation id="2202020181578195191">Enter a valid expiry year</translation>
+<translation id="2209523182407020534">Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.</translation>
<translation id="2212735316055980242">Policy not found</translation>
<translation id="2213606439339815911">Fetching entries...</translation>
<translation id="2218879909401188352">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> could install dangerous apps that damage your device, add hidden charges to your mobile bill or steal your personal information. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Go back</translation>
<translation id="2503184589641749290">Accepted debit and prepaid cards</translation>
<translation id="2515629240566999685">Checking the signal in your area</translation>
+<translation id="2524461107774643265">Add More Information</translation>
+<translation id="2536110899380797252">Add Address</translation>
<translation id="2539524384386349900">Detect</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> sent an invalid response.</translation>
<translation id="2556876185419854533">&amp;Undo Edit</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium was unable to confirm your card at this time. Please try again later.</translation>
<translation id="2705137772291741111">The saved (cached) copy of this site was unreadable.</translation>
<translation id="2709516037105925701">Auto-fill</translation>
+<translation id="2710942282213947212">Software on your computer is stopping Chromium from safely connecting to the web</translation>
<translation id="2712173769900027643">Ask permission</translation>
-<translation id="2713444072780614174">White</translation>
<translation id="2720342946869265578">Nearby</translation>
<translation id="2721148159707890343">Request succeeded</translation>
<translation id="2728127805433021124">Server's certificate is signed using a weak signature algorithm.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">A network change was detected.</translation>
<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="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="2941952326391522266">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is from <ph name="DOMAIN2" />. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Wrong policy type</translation>
<translation id="3032412215588512954">Do you want to reload this site?</translation>
<translation id="3037605927509011580">Aw, Snap!</translation>
+<translation id="3039538478787849737">Save card to Google?</translation>
<translation id="3041612393474885105">Certificate Information</translation>
<translation id="3063697135517575841">Chrome was unable to confirm your card at this time. Please try again later.</translation>
<translation id="3064966200440839136">Leaving incognito mode to pay via an external application. Continue?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Temporary server error</translation>
<translation id="3154506275960390542">This page includes a form that may not submit securely. Data that you send can be viewed by others while in transit or could be modified by an attacker to change what the server receives.</translation>
<translation id="3157931365184549694">Restore</translation>
+<translation id="3162559335345991374">The Wi-Fi that you are using may require you to visit its login page.</translation>
<translation id="3167968892399408617">Pages that you view in incognito tabs won’t stick around in your browser’s history, cookie store or search history after you’ve closed all of your incognito tabs. Any files you download or bookmarks you create will be kept.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Island</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancel payment</translation>
<translation id="3207960819495026254">Bookmarked</translation>
+<translation id="3211223744486044430">To pay faster next time, save this card to your Google Account and to this device.</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>
<translation id="3226128629678568754">Press the reload button to resubmit the data needed to load the page.</translation>
<translation id="3227137524299004712">Microphone</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">No search results found</translation>
<translation id="3305707030755673451">Your data was encrypted with your sync passphrase on <ph name="TIME" />. Enter it to start sync.</translation>
<translation id="3320021301628644560">Add billing address</translation>
-<translation id="3329013043687509092">Saturation</translation>
<translation id="333371639341676808">Prevent this page from creating additional dialogues.</translation>
<translation id="3338095232262050444">Secure</translation>
<translation id="3340978935015468852">settings</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Client ID:</translation>
<translation id="3391030046425686457">Delivery address</translation>
<translation id="3395827396354264108">Pickup method</translation>
+<translation id="3399952811970034796">Delivery Address</translation>
<translation id="3422248202833853650">Try exiting other programmes to free up memory.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is currently unreachable.</translation>
<translation id="3427092606871434483">Allow (default)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Crash report captured on <ph name="CRASH_TIME" />, uploaded on <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certificate information</translation>
<translation id="3690164694835360974">Login not secure</translation>
+<translation id="3704162925118123524">The network that you are using may require you to visit its log-in page.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Loading...</translation>
<translation id="3712624925041724820">Licenses exhausted</translation>
<translation id="3714780639079136834">Turning on mobile data or Wi-Fi</translation>
+<translation id="3715597595485130451">Connect to Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Checking the proxy, firewall and DNS configuration<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">If you understand the risks to your security, you may <ph name="BEGIN_LINK" />visit this unsafe site<ph name="END_LINK" /> before the dangerous programs have been removed.</translation>
<translation id="3739623965217189342">Link that you copied</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Undo add</translation>
<translation id="404928562651467259">WARNING</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxy configuration is set to use a .pac script URL, not fixed proxy servers.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Device serial number is invalid</translation>
<translation id="410351446219883937">Autoplay</translation>
<translation id="4103763322291513355">Visit &lt;strong&gt;chrome://policy&lt;/strong&gt; to see the list of blacklisted URLs and other policies enforced by your system administrator.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Always allow on this site</translation>
<translation id="4117700440116928470">Policy scope is not supported.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 other}other{# others}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">You attempted to reach <ph name="DOMAIN" />, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker.</translation>
<translation id="4394049700291259645">Disable</translation>
<translation id="4406896451731180161">search results</translation>
+<translation id="4415426530740016218">Pickup Address</translation>
<translation id="4424024547088906515">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> didn’t accept your login certificate, or one may not have been provided.</translation>
<translation id="443673843213245140">Use of a proxy is disabled but an explicit proxy configuration is specified.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Try disabling your extensions.</translation>
<translation id="457875822857220463">Delivery</translation>
+<translation id="4582800630050655161">You could lose access to your Google Account or experience identity theft. Chromium recommends that you change your password now.</translation>
<translation id="4587425331216688090">Remove address from Chrome?</translation>
<translation id="4592951414987517459">Your connection to <ph name="DOMAIN" /> is encrypted using a modern cipher suite.</translation>
<translation id="4594403342090139922">&amp;Undo Delete</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Stop using an invalid certificate</translation>
+<translation id="4690954380545377795">You could lose access to your Google Account or experience identity theft. Chrome recommends that you change your password now.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Your connection was interrupted</translation>
<translation id="471880041731876836">You don't have permission to visit this site</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Running Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Your payment</translation>
<translation id="4726672564094551039">Reload policies</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Restart Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Backing store in bad state</translation>
<translation id="5023310440958281426">Check your administrator's policies</translation>
<translation id="5029568752722684782">Clear copy</translation>
+<translation id="503069730517007720">A root certificate for '<ph name="SOFTWARE_NAME" />' is required but isn’t installed. Your IT administrator should look at configuration instructions for '<ph name="SOFTWARE_NAME" />' to fix this problem. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">About Google Translate</translation>
<translation id="5039804452771397117">Allow</translation>
<translation id="5040262127954254034">Privacy</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experiments</translation>
<translation id="5205222826937269299">Name required</translation>
<translation id="5222812217790122047">Email (required)</translation>
+<translation id="522700295135997067">This site may have just stolen your password</translation>
+<translation id="5230733896359313003">Delivery Address</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Using Chrome at work? Businesses can manage Chrome settings for their employees. Find out more</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Follow these steps to temporarily disable the software so that you can get on the web. You'll need administrator privileges.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Your connection to this site is not private. To exit VR mode at any time, remove headset and press back.</translation>
<translation id="5299298092464848405">Error parsing policy</translation>
+<translation id="5308380583665731573">Connect</translation>
<translation id="5308689395849655368">Crash reporting is disabled.</translation>
<translation id="5317780077021120954">Save</translation>
<translation id="5327248766486351172">Name</translation>
+<translation id="5332219387342487447">Delivery Method</translation>
<translation id="5355557959165512791">You cannot visit <ph name="SITE" /> right now because its certificate has been revoked. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="536296301121032821">Failed to store policy settings</translation>
<translation id="5386426401304769735">The certificate chain for this site contains a certificate signed using SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">This site on the company, organisation or school intranet has the same URL as an external website.
<ph name="LINE_BREAK" />
Try contacting your system administrator.</translation>
+<translation id="5499929369096410817">Enter the security code for <ph name="CREDIT_CARD" />. This code won't be saved.</translation>
<translation id="5509780412636533143">Managed bookmarks</translation>
<translation id="5510766032865166053">It may have been moved or deleted.</translation>
<translation id="5523118979700054094">Policy name</translation>
<translation id="552553974213252141">Was the text extracted correctly?</translation>
<translation id="5540224163453853">Could not find the requested article.</translation>
+<translation id="5541546772353173584">Add Email</translation>
<translation id="5544037170328430102">An embedded page at <ph name="SITE" /> says:</translation>
+<translation id="5545756402275714221">Articles for You</translation>
<translation id="5556459405103347317">Reload</translation>
<translation id="5560088892362098740">Expiry Date</translation>
<translation id="5565735124758917034">Active</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Get personalised content</translation>
<translation id="5675650730144413517">This page isn’t working</translation>
+<translation id="5689199277474810259">Export to JSON</translation>
<translation id="5710435578057952990">The identity of this website has not been verified.</translation>
<translation id="5719499550583120431">Prepaid cards are accepted.</translation>
<translation id="5720705177508910913">Current user</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Your connection to <ph name="DOMAIN" /> is encrypted using an obsolete cipher suite.</translation>
<translation id="5813119285467412249">&amp;Redo Add</translation>
<translation id="5838278095973806738">You should not enter any sensitive information on this site (for example, passwords or credit cards), because it could be stolen by attackers.</translation>
+<translation id="5866257070973731571">Add Phone Number</translation>
<translation id="5869405914158311789">This site can’t be reached</translation>
<translation id="5869522115854928033">Saved passwords</translation>
<translation id="5872918882028971132">Parent Suggestions</translation>
<translation id="5893752035575986141">Credit cards are accepted.</translation>
-<translation id="5901630391730855834">Yellow</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synced)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 in use}other{# in use}}</translation>
<translation id="5959728338436674663">Automatically send some <ph name="BEGIN_WHITEPAPER_LINK" />system information and page content<ph name="END_WHITEPAPER_LINK" /> to Google to help detect dangerous apps and sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edit Contact Info</translation>
<translation id="5967867314010545767">Remove from history</translation>
<translation id="5975083100439434680">Zoom out</translation>
+<translation id="597552863672748783">Confirm security code</translation>
<translation id="598637245381783098">Can’t open payment app</translation>
<translation id="5989320800837274978">Neither fixed proxy servers nor a .pac script URL are specified.</translation>
<translation id="5990559369517809815">Requests to the server have been blocked by an extension.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}other{Page #}}</translation>
-<translation id="6017514345406065928">Green</translation>
<translation id="6017850046339264347">Attackers on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> could install deceptive apps that pretend to be something else or collect data that may be used to track you. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synced)</translation>
<translation id="6027201098523975773">Enter a name</translation>
<translation id="6040143037577758943">Close</translation>
-<translation id="6042308850641462728">More</translation>
<translation id="6047233362582046994">If you understand the risks to your security, you may <ph name="BEGIN_LINK" />visit this site<ph name="END_LINK" /> before the harmful apps have been removed.</translation>
<translation id="6047927260846328439">This content might try to trick you into installing software or revealing personal information. <ph name="BEGIN_LINK" />Show anyway<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">You cannot visit <ph name="SITE" /> right now because the website uses certificate pinning. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">You're viewing an extension page</translation>
<translation id="6596325263575161958">Encryption options</translation>
<translation id="662080504995468778">Stay</translation>
+<translation id="6624427990725312378">Contact Info</translation>
<translation id="6626291197371920147">Add valid card number</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Search</translation>
<translation id="6630809736994426279">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> might attempt to install dangerous programs on your Mac that steal or delete your information (for example, photos, passwords, messages and credit cards). <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Previous</translation>
<translation id="6710594484020273272">&lt;Type search term&gt;</translation>
<translation id="6711464428925977395">There is something wrong with the proxy server or the address is incorrect.</translation>
-<translation id="6727102863431372879">Set</translation>
<translation id="674375294223700098">Unknown server certificate error.</translation>
<translation id="6753269504797312559">Policy Value</translation>
<translation id="6757797048963528358">Your device went to sleep.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profile Path</translation>
<translation id="7424977062513257142">An embedded page on this webpage says:</translation>
+<translation id="7437289804838430631">Add contact info</translation>
<translation id="7441627299479586546">Wrong policy subject</translation>
<translation id="7444046173054089907">This site is blocked</translation>
<translation id="7445762425076701745">The identity of the server to which you are connected cannot be fully validated. You are connected to a server using a name valid only within your network, and an external certificate authority has no way to validate ownership. As some certificate authorities will issue certificates for these names regardless, there is no way to ensure that you are connected to the intended website and not to an attacker.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Forward</translation>
<translation id="7485870689360869515">No data found.</translation>
<translation id="7508255263130623398">Returned policy device ID is empty or doesn't match current device ID</translation>
+<translation id="7511955381719512146">The Wi-Fi that you are using may require you to visit <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Download</translation>
<translation id="7518003948725431193">No web page was found for the web address: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Your connection to this site is not private</translation>
-<translation id="7535087603100972091">Value</translation>
<translation id="7537536606612762813">Mandatory</translation>
<translation id="7542403920425041731">Once you confirm, your card details will be shared with this site.</translation>
<translation id="7542995811387359312">Automatic credit card filling is disabled because this form does not use a secure connection.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="7568593326407688803">This page is in<ph name="ORIGINAL_LANGUAGE" />Would you like to translate it?</translation>
<translation id="7569952961197462199">Remove credit card from Chrome?</translation>
-<translation id="7569983096843329377">Black</translation>
<translation id="7578104083680115302">Pay quickly on sites and apps across devices using cards that you have saved with Google.</translation>
<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Server's certificate violates name constraints.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Attackers on this site might try to trick you into installing programs that harm your browsing experience (for example, by changing your homepage or showing extra ads on sites that you visit).</translation>
<translation id="7674629440242451245">Interested in cool new Chrome features? Try our dev channel at chrome.com/dev.</translation>
<translation id="7682287625158474539">Shipping</translation>
+<translation id="7699293099605015246">Articles aren't available at the moment.</translation>
<translation id="7701040980221191251">None</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Proceed to <ph name="SITE" /> (unsafe)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificate</translation>
<translation id="7716147886133743102">Blocked by your administrator</translation>
<translation id="7716424297397655342">This site can’t be loaded from the cache</translation>
+<translation id="7723047071702270851">Edit Card</translation>
<translation id="774634243536837715">Dangerous content blocked.</translation>
<translation id="7752995774971033316">Unmanaged</translation>
<translation id="7755287808199759310">Your parent can unblock it for you</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Add address</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">Add</translation>
+<translation id="7793553086574152071">To pay faster next time, save this card to your Google Account.</translation>
<translation id="7793809570500803535">The web page at <ph name="SITE" /> might be temporarily down or it may have been moved permanently to a new web address.</translation>
<translation id="7800304661137206267">The connection is encrypted using <ph name="CIPHER" />, with <ph name="MAC" /> for message authentication and <ph name="KX" /> as the key exchange mechanism.</translation>
+<translation id="7802523362929240268">Site is legitimate</translation>
<translation id="780301667611848630">No, thank you</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Remove form suggestion from Chrome?</translation>
<translation id="7815407501681723534">Found <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">The Wi-Fi that you are using (<ph name="WIFI_NAME" />) may require you to visit its login page.</translation>
<translation id="785549533363645510">However, you aren’t invisible. Going incognito doesn’t hide your browsing from your employer, your Internet service provider or the websites that you visit.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Debit and prepaid cards are accepted.</translation>
+<translation id="7878562273885520351">Your password may be compromised</translation>
<translation id="7887683347370398519">Check your CVC and try again</translation>
<translation id="79338296614623784">Enter a valid phone number</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Server's certificate is not yet valid.</translation>
-<translation id="7942349550061667556">Red</translation>
<translation id="7947285636476623132">Check your expiry year and try again</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Mobile bookmarks</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Ask (default)</translation>
<translation id="8041089156583427627">Send Feedback</translation>
<translation id="8041940743680923270">Use global default (Ask)</translation>
+<translation id="8057711352706143257">'<ph name="SOFTWARE_NAME" />' isn’t configured correctly. Uninstalling '<ph name="SOFTWARE_NAME" />' usually fixes the problem. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Failed to view article.</translation>
<translation id="8091372947890762290">Activation is pending on the server</translation>
+<translation id="8094917007353911263">The network that you are using may require you to visit <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Payment Method</translation>
<translation id="8118489163946903409">Payment method</translation>
+<translation id="8127301229239896662">'<ph name="SOFTWARE_NAME" />' wasn’t installed properly on your computer or network. Ask your IT administrator to resolve this issue.</translation>
<translation id="8131740175452115882">Confirm</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />’s server <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> could not be found.</translation>
<translation id="8149426793427495338">Your computer went to sleep.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Contact your network administrator if you're not sure what this means.</translation>
<translation id="8293206222192510085">Add Bookmark</translation>
<translation id="8294431847097064396">Source</translation>
+<translation id="8298115750975731693">The Wi-Fi that you are using (<ph name="WIFI_NAME" />) may require you to visit <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">The translation failed because of a problem with the network connection.</translation>
<translation id="8332188693563227489">Access to <ph name="HOST_NAME" /> was denied</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Recently Closed</translation>
<translation id="8874824191258364635">Enter a valid card number</translation>
<translation id="8876793034577346603">Network configuration failed to be parsed.</translation>
-<translation id="8889402386540077796">Hue</translation>
<translation id="8891727572606052622">Invalid proxy mode.</translation>
<translation id="889901481107108152">Sorry, this experiment is not available on your platform.</translation>
<translation id="8903921497873541725">Zoom in</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="8938939909778640821">Accepted credit and prepaid cards</translation>
+<translation id="8957210676456822347">Captive Portal Authorisation</translation>
<translation id="8971063699422889582">Server's certificate has expired.</translation>
-<translation id="8986494364107987395">Automatically send usage statistics and crash reports to Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">The site ahead contains harmful programs</translation>
<translation id="8997023839087525404">The server presented a certificate that was not publicly disclosed using the Certificate Transparency policy. This is a requirement for some certificates, to ensure that they are trustworthy and protect against attackers.</translation>
<translation id="9001074447101275817">The proxy <ph name="DOMAIN" /> requires a username and password.</translation>
<translation id="9005998258318286617">Failed to load PDF document.</translation>
+<translation id="9008201768610948239">Ignore</translation>
<translation id="901974403500617787">Flags that apply system-wide can only be set by the owner: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Card billing address required</translation>
<translation id="9020542370529661692">This page has been translated to <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">You attempted to reach <ph name="DOMAIN" />, but the server presented an invalid certificate.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Edit</translation>
-<translation id="9068849894565669697">Select colour</translation>
<translation id="9069693763241529744">Blocked by an extension</translation>
<translation id="9076283476770535406">It may have mature content</translation>
<translation id="9078964945751709336">More information required</translation>
+<translation id="9080712759204168376">Order Summary</translation>
<translation id="9103872766612412690"><ph name="SITE" /> normally uses encryption to protect your information. When Chromium tried to connect to <ph name="SITE" /> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE" />, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Chromium stopped the connection before any data was exchanged.</translation>
+<translation id="9106062320799175032">Add Billing Address</translation>
+<translation id="910908805481542201">Help me fix this</translation>
+<translation id="9128870381267983090">Connect to network</translation>
<translation id="9137013805542155359">Show original</translation>
<translation id="9137248913990643158">Please start and sign in to Chrome before using this app.</translation>
<translation id="9148507642005240123">&amp;Undo edit</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> uses an unsupported protocol.</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="9215416866750762878">An application is stopping Chrome from safely connecting to this site</translation>
<translation id="9219103736887031265">Images</translation>
<translation id="933612690413056017">There is no Internet connection</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{None}=1{1 item}other{# items}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Developer Build</translation>
+<translation id="989988560359834682">Edit Address</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">'<ph name="SOFTWARE_NAME" />' wasn’t installed properly on your computer or the network:
+ &lt;ul&gt;
+ &lt;li&gt;Try uninstalling or disabling '<ph name="SOFTWARE_NAME" />'&lt;/li&gt;
+ &lt;li&gt;Try connecting to another network&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index ae2ffce9c04..5c29056b462 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Favoritos de escritorio</translation>
<translation id="1074497978438210769">No seguro</translation>
<translation id="1080116354587839789">Ajustar al ancho</translation>
+<translation id="1088860948719068836">Agregar el nombre en la tarjeta</translation>
<translation id="1103523840287552314">Siempre traducir <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostrar todas las contraseñas guardadas…</translation>
<translation id="1107591249535594099">Si marcas esta opción, Chrome almacenará una copia de la tarjeta en el dispositivo para completar más rápidamente los formularios.</translation>
<translation id="1111153019813902504">Favoritos recientes</translation>
<translation id="1113869188872983271">&amp;Deshacer Reorganizar</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizados)</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">El informe de fallos se capturó el <ph name="CRASH_TIME" /> (todavía no se cargó ni se ignoró)</translation>
+<translation id="1270502636509132238">Método de retiro</translation>
<translation id="1281526147609854549">Emitido por <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nunca traducir este sitio</translation>
<translation id="129553762522093515">Cerrado recientemente</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Esperando conexión…</translation>
<translation id="153384715582417236">Eso es todo por ahora</translation>
<translation id="1549470594296187301">JavaScript debe estar habilitado para usar esta función.</translation>
-<translation id="1555130319947370107">Azul</translation>
<translation id="1559528461873125649">El archivo o directorio no existe</translation>
<translation id="1583429793053364125">Se produjo un error al mostrar la página web.</translation>
<translation id="1592005682883173041">Acceso a datos locales</translation>
<translation id="1594030484168838125">Seleccionar</translation>
-<translation id="161042844686301425">Cian</translation>
<translation id="1620510694547887537">Cámara</translation>
<translation id="1629803312968146339">¿Quieres que Chrome guarde esta tarjeta?</translation>
<translation id="1639239467298939599">Cargando</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Necesitas permiso de <ph name="NAME" /> para visitar este sitio</translation>
<translation id="1721424275792716183">* El campo es obligatorio</translation>
+<translation id="1727741090716970331">Agregar un número de tarjeta válido</translation>
<translation id="1728677426644403582">Estás viendo la fuente de una página web</translation>
<translation id="173080396488393970">No se acepta este tipo de tarjeta</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Error de serialización</translation>
<translation id="1974060860693918893">Avanzada</translation>
<translation id="1978555033938440688">Versión de firmware</translation>
-<translation id="1995859865337580572">Verifica tu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{y 1 más}other{y # más}}</translation>
<translation id="2025186561304664664">El proxy se estableció en configuración automática.</translation>
<translation id="2030481566774242610">¿Quisiste decir: <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Para obtener contenido personalizado y sugerido por Google, accede a tu cuenta en Chrome.</translation>
+<translation id="2091887806945687916">Sonido</translation>
<translation id="2094505752054353250">El dominio no coincide.</translation>
<translation id="2096368010154057602">Departamento</translation>
<translation id="2108755909498034140">Reinicia la computadora.</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Se ignoró porque fue anulada por <ph name="POLICY_NAME" /> .</translation>
<translation id="2138201775715568214">Buscando páginas web físicas cercanas</translation>
<translation id="213826338245044447">Favoritos del celular</translation>
+<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
+<translation id="2148613324460538318">Agregar tarjeta</translation>
<translation id="2154054054215849342">El servicio de sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 dirección}other{# direcciones}}</translation>
<translation id="2187317261103489799">Detectar (predeterminado)</translation>
<translation id="2202020181578195191">Ingresa un año de vencimiento válido</translation>
+<translation id="2209523182407020534">Las aplicaciones que pueden causar este error incluyen antivirus, firewall, filtros web o software proxy.</translation>
<translation id="2212735316055980242">No se encontró la política.</translation>
<translation id="2213606439339815911">Recuperando entradas…</translation>
<translation id="2218879909401188352">Es posible que los atacantes que se encuentran actualmente en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instalen apps peligrosas que dañen tu dispositivo, agreguen cargos ocultos en la factura de tu servicio móvil o roben tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Ir atrás</translation>
<translation id="2503184589641749290">Tarjetas de débito y prepago aceptadas</translation>
<translation id="2515629240566999685">Verificar la señal en tu área.</translation>
+<translation id="2524461107774643265">Agregar más información</translation>
+<translation id="2536110899380797252">Agregar dirección</translation>
<translation id="2539524384386349900">Detectar</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> envió una respuesta no válida.</translation>
<translation id="2556876185419854533">&amp;Deshacer Editar</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chrome no pudo confirmar tu tarjeta. Vuelve a intentarlo más tarde.</translation>
<translation id="2705137772291741111">La copia guardada (en caché) de este sitio es ilegible.</translation>
<translation id="2709516037105925701">Autocompletar</translation>
+<translation id="2710942282213947212">Un software en tu computadora impide que Chromium se conecte de forma segura a la Web</translation>
<translation id="2712173769900027643">Solicitar permiso</translation>
-<translation id="2713444072780614174">Blanco</translation>
<translation id="2720342946869265578">Cercanas</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2728127805433021124">El certificado del servidor está firmado con un algoritmo de firma no seguro.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Se detectó un cambio de red.</translation>
<translation id="2916038427272391327">Cierra los demás programas.</translation>
<translation id="2922350208395188000">No se puede comprobar el certificado del servidor.</translation>
+<translation id="2925673989565098301">Método de entrega</translation>
<translation id="2928905813689894207">Dirección de facturación</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}}</translation>
<translation id="2941952326391522266">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad proviene de <ph name="DOMAIN2" />. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipo de política incorrecto</translation>
<translation id="3032412215588512954">¿Deseas volver a cargar este sitio?</translation>
<translation id="3037605927509011580">¡Oh, no!</translation>
+<translation id="3039538478787849737">¿Quieres guardar la tarjeta en Google?</translation>
<translation id="3041612393474885105">Información sobre el certificado</translation>
<translation id="3063697135517575841">Chrome no pudo confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
<translation id="3064966200440839136">Saldrás del modo de navegación incógnito para pagar mediante una aplicación externa. ¿Deseas continuar?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Error temporal del servidor</translation>
<translation id="3154506275960390542">Esta página incluye un formulario cuyo envío no es seguro. Es posible que otras personas vean los datos que envíes mientras están en tránsito o que un atacante los modifique antes de que los reciba el servidor.</translation>
<translation id="3157931365184549694">Restaurar</translation>
+<translation id="3162559335345991374">Es posible que la red Wi-Fi que estás usando requiera que visites la página de acceso.</translation>
<translation id="3167968892399408617">Una vez que cierres todas las pestañas de incógnito, las páginas que hayas visitado en ese modo no se guardarán en el historial del navegador, en la lista de cookies ni en el historial de búsquedas. Se guardarán los archivos que descargues y los favoritos que crees.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Isla</translation>
@@ -288,6 +298,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancelar pago</translation>
<translation id="3207960819495026254">Agregada a favoritos</translation>
+<translation id="3211223744486044430">Para realizar pagos más rápido la próxima vez, guarda esta tarjeta en tu cuenta de Google y en este dispositivo.</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>
<translation id="3226128629678568754">Presiona el botón para volver a cargar y, de ese modo, enviar nuevamente los datos necesarios para cargar la página.</translation>
<translation id="3227137524299004712">Micrófono</translation>
@@ -302,7 +313,6 @@
<translation id="3303855915957856445">No se encontraron resultados en la búsqueda</translation>
<translation id="3305707030755673451">Tus datos se encriptaron con tu frase de contraseña para sincronización el <ph name="TIME" />. Debes ingresarla para iniciar la sincronización.</translation>
<translation id="3320021301628644560">Agregar dirección de facturación</translation>
-<translation id="3329013043687509092">Saturación</translation>
<translation id="333371639341676808">Evita que esta página cree cuadros de diálogo adicionales.</translation>
<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">configuración</translation>
@@ -321,6 +331,7 @@
<translation id="3380864720620200369">ID de cliente:</translation>
<translation id="3391030046425686457">Dirección de entrega</translation>
<translation id="3395827396354264108">Método de retiro</translation>
+<translation id="3399952811970034796">Dirección de entrega</translation>
<translation id="3422248202833853650">Prueba cerrar los demás programas para liberar memoria.</translation>
<translation id="3422472998109090673">No se puede acceder a <ph name="HOST_NAME" /> en este momento.</translation>
<translation id="3427092606871434483">Permitir (predeterminado)</translation>
@@ -366,10 +377,12 @@
<translation id="3679803492151881375">El informe de fallos se capturó el <ph name="CRASH_TIME" /> y se cargó el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Información sobre el certificado</translation>
<translation id="3690164694835360974">Acceso no seguro</translation>
+<translation id="3704162925118123524">Es posible que la red que estás usando requiera que visites la página de acceso.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi.</translation>
+<translation id="3715597595485130451">Conectar a Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar la configuración del proxy, firewall o DNS<ph name="END_LINK" />.</translation>
<translation id="3736520371357197498">Si comprendes los riesgos para tu seguridad, puedes <ph name="BEGIN_LINK" />visitar este sitio no seguro<ph name="END_LINK" /> antes de que se hayan eliminado los programas peligrosos.</translation>
<translation id="3739623965217189342">Vínculo copiado</translation>
@@ -404,6 +417,7 @@
<translation id="4030383055268325496">&amp;Deshacer Agregar</translation>
<translation id="404928562651467259">ADVERTENCIA</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">El proxy está configurado para usar una URL de script .pac, no servidores proxy fijos.</translation>
@@ -411,7 +425,6 @@
<translation id="4103249731201008433">El número de serie del dispositivo no es válido.</translation>
<translation id="410351446219883937">Reproducción automática</translation>
<translation id="4103763322291513355">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver las URL en lista negra y otras políticas que estableció el administrador del sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Permitir siempre en este sitio</translation>
<translation id="4117700440116928470">No se admite el alcance de la política.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 más}other{# más}}</translation>
@@ -449,6 +462,7 @@
<translation id="4377125064752653719">Intentaste acceder a <ph name="DOMAIN" />, pero el emisor anuló el certificado que presentó el servidor. Esto significa que no se debe confiar en absoluto en las credenciales de seguridad que presentó el servidor. Te puedes estar comunicando con un atacante.</translation>
<translation id="4394049700291259645">Inhabilitar</translation>
<translation id="4406896451731180161">resultados de búsqueda</translation>
+<translation id="4415426530740016218">Dirección de retiro</translation>
<translation id="4424024547088906515">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chrome no confía en el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no aceptó tu certificado de acceso o es posible que no se haya proporcionado.</translation>
<translation id="443673843213245140">Se inhabilitó el uso de un proxy, pero se especificó una configuración explícita de proxy.</translation>
@@ -461,6 +475,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Intenta inhabilitar tus extensiones.</translation>
<translation id="457875822857220463">Entrega</translation>
+<translation id="4582800630050655161">Es posible que hayas perdido el acceso a tu cuenta de Google o sufrido un robo de identidad. Chromium te recomienda que cambies la contraseña ahora.</translation>
<translation id="4587425331216688090">¿Confirmas que quieres quitar la dirección de Chrome?</translation>
<translation id="4592951414987517459">Tu conexión a <ph name="DOMAIN" /> está encriptada con un conjunto de cifrado moderno.</translation>
<translation id="4594403342090139922">&amp;Deshacer Eliminar</translation>
@@ -469,10 +484,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Dejar de usar un certificado no válido</translation>
+<translation id="4690954380545377795">Es posible que hayas perdido el acceso a tu cuenta de Google o sufrido un robo de identidad. Chrome te recomienda que cambies la contraseña ahora.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Se interrumpió la conexión</translation>
<translation id="471880041731876836">No tienes permiso para visitar este sitio</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ejecución del Diagnóstico de red de Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Tu pago</translation>
<translation id="4726672564094551039">Volver a cargar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4736825316280949806">Reinicia Chromium.</translation>
@@ -511,6 +528,7 @@
<translation id="5019198164206649151">La memoria auxiliar se encuentra en mal estado.</translation>
<translation id="5023310440958281426">Revisa las políticas del administrador.</translation>
<translation id="5029568752722684782">Borrar la copia</translation>
+<translation id="503069730517007720">Se requiere un certificado raíz para "<ph name="SOFTWARE_NAME" />", pero no está instalado. Tu administrador de IT debe analizar las instrucciones de configuración de "<ph name="SOFTWARE_NAME" />" para corregir este problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Acerca de Google Traductor</translation>
<translation id="5039804452771397117">Permitir</translation>
<translation id="5040262127954254034">Privacidad</translation>
@@ -534,6 +552,8 @@
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5205222826937269299">Nombre (obligatorio)</translation>
<translation id="5222812217790122047">Correo electrónico (obligatorio)</translation>
+<translation id="522700295135997067">Es posible que este sitio haya robado tu contraseña</translation>
+<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5251803541071282808">Nube</translation>
<translation id="5277279256032773186">¿Usas Chrome en el trabajo? Las empresas pueden administrar la configuración de Chrome para sus empleados. Más información</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Realiza estos pasos para inhabilitar el software de forma temporal, para que puedas acceder a la Web. Necesitarás privilegios de administrador.<ph name="END_PARAGRAPH" />
@@ -548,9 +568,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Tu conexión a este sitio no es privada. Para salir del modo RV en cualquier momento, quita los auriculares y presiona Atrás.</translation>
<translation id="5299298092464848405">Error al analizar la política</translation>
+<translation id="5308380583665731573">Conectar</translation>
<translation id="5308689395849655368">Notificación de fallas desactivada.</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nombre</translation>
+<translation id="5332219387342487447">Método de envío</translation>
<translation id="5355557959165512791">No puedes visitar <ph name="SITE" /> ahora porque este certificado se revocó. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
<translation id="536296301121032821">Error al almacenar la configuración de la política</translation>
<translation id="5386426401304769735">La cadena del certificado de este sitio web contiene un certificado que se firmó con SHA-1.</translation>
@@ -570,12 +592,15 @@
<translation id="5492298309214877701">En la intranet de la compañía, organización o escuela, este sitio tiene la misma URL que un sitio web externo
<ph name="LINE_BREAK" />
Intenta contactar al administrador de tu sistema.</translation>
+<translation id="5499929369096410817">Ingresa el código de seguridad de la tarjeta <ph name="CREDIT_CARD" />. Este código no se guardará.</translation>
<translation id="5509780412636533143">Favoritos administrados</translation>
<translation id="5510766032865166053">Es posible que lo hayan movido o borrado.</translation>
<translation id="5523118979700054094">Nombre de la política</translation>
<translation id="552553974213252141">¿Se extrajo el texto correctamente?</translation>
<translation id="5540224163453853">No se pudo encontrar el artículo solicitado.</translation>
+<translation id="5541546772353173584">Agregar correo electrónico</translation>
<translation id="5544037170328430102">Una página incrustada en <ph name="SITE" /> dice:</translation>
+<translation id="5545756402275714221">Artículos para ti</translation>
<translation id="5556459405103347317">Cargar de nuevo</translation>
<translation id="5560088892362098740">Fecha de vencimiento</translation>
<translation id="5565735124758917034">Activo</translation>
@@ -597,6 +622,7 @@
<translation id="5659593005791499971">Correo electrónico</translation>
<translation id="5669703222995421982">Obtener contenido personalizado</translation>
<translation id="5675650730144413517">Esta página no funciona</translation>
+<translation id="5689199277474810259">Exportar a JSON</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5719499550583120431">Se aceptan tarjetas de prepago.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
@@ -611,27 +637,27 @@
<translation id="5810442152076338065">Tu conexión a <ph name="DOMAIN" /> está encriptada con un conjunto de cifrado obsoleto.</translation>
<translation id="5813119285467412249">&amp;Rehacer Agregar</translation>
<translation id="5838278095973806738">No debes ingresar información confidencial en este sitio (p. ej., contraseñas o tarjetas de crédito), ya que los atacantes podrían robarla.</translation>
+<translation id="5866257070973731571">Agregar número de teléfono</translation>
<translation id="5869405914158311789">No se puede acceder a este sitio</translation>
<translation id="5869522115854928033">Contraseñas almacenadas</translation>
<translation id="5872918882028971132">Sugerencias para padres</translation>
<translation id="5893752035575986141">Se aceptan tarjetas de crédito.</translation>
-<translation id="5901630391730855834">Amarillo</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 en uso}other{# en uso}}</translation>
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />determinado contenido de la página e información del sistema<ph name="END_WHITEPAPER_LINK" /> a Google para detectar apps y sitios peligrosos <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Editar la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Alejar</translation>
+<translation id="597552863672748783">Confirmar código de seguridad</translation>
<translation id="598637245381783098">No se puede abrir la app de pago</translation>
<translation id="5989320800837274978">No se especifican servidores proxy fijos ni URL de secuencias de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión bloqueó las solicitudes al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}other{Página #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Es posible que los atacantes que se encuentran en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instalen apps engañosas que se hagan pasar por otro tipo de contenido o que recopilen datos que se usen para rastrearte. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizados)</translation>
<translation id="6027201098523975773">Ingresa un nombre</translation>
<translation id="6040143037577758943">Cerrar</translation>
-<translation id="6042308850641462728">Más</translation>
<translation id="6047233362582046994">Si comprendes los riesgos de seguridad, puedes <ph name="BEGIN_LINK" />visitar este sitio<ph name="END_LINK" /> antes de que se hayan quitado las apps dañinas.</translation>
<translation id="6047927260846328439">Es posible que este contenido trate de engañarte para que instales software o reveles información personal. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">No puedes visitar <ph name="SITE" /> ahora porque el sitio web usa la fijación de certificados. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
@@ -698,6 +724,7 @@
<translation id="6569060085658103619">Estás viendo la página de una extensión</translation>
<translation id="6596325263575161958">Opciones de encriptación</translation>
<translation id="662080504995468778">Permanecer aquí</translation>
+<translation id="6624427990725312378">Información de contacto</translation>
<translation id="6626291197371920147">Agregar un número de tarjeta válido</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Búsqueda</translation>
<translation id="6630809736994426279">Es posible que los atacantes que actualmente se encuentran en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten instalar programas peligrosos en tu Mac para robar o borrar información (p. ej., 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>
@@ -708,7 +735,6 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Escribe el término de búsqueda&gt;</translation>
<translation id="6711464428925977395">Hay un error en el servidor proxy o la dirección es incorrecta.</translation>
-<translation id="6727102863431372879">Establecer</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido.</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositivo se suspendió.</translation>
@@ -777,6 +803,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Ruta del perfil</translation>
<translation id="7424977062513257142">Una página incrustada en esta página web dice:</translation>
+<translation id="7437289804838430631">Agregar información de contacto</translation>
<translation id="7441627299479586546">Nombre de usuario o dominio de política incorrecto</translation>
<translation id="7444046173054089907">Este sitio está bloqueado</translation>
<translation id="7445762425076701745">La identidad del servidor al que estás conectado no se puede validar en su totalidad. Estás conectado a un servidor utilizando un nombre que sólo es válido dentro de tu red y cuya propiedad no puede validar una entidad externa de certificación. Debido a que algunas entidades emiten certificados aún para estos nombres, no hay manera de asegurar que estás conectado al sitio web que pretendías o a un atacante.</translation>
@@ -787,11 +814,11 @@
<translation id="7481312909269577407">Reenviar</translation>
<translation id="7485870689360869515">No se encontró ningún dato.</translation>
<translation id="7508255263130623398">El ID de dispositivo de la política que se muestra está vacío o no coincide con el ID de dispositivo actual</translation>
+<translation id="7511955381719512146">Es posible que la red Wi-Fi que estás usando requiera que accedas a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Descargar</translation>
<translation id="7518003948725431193">No se encontró una página web para la siguiente dirección web: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Tu conexión con este sitio no es privada</translation>
-<translation id="7535087603100972091">Valor</translation>
<translation id="7537536606612762813">Obligatoria</translation>
<translation id="7542403920425041731">Después de que se confirme, los datos de tu tarjeta se compartirán con este sitio.</translation>
<translation id="7542995811387359312">El rellenado automático de la tarjeta de crédito se inhabilitó porque este formulario no usa una conexión segura.</translation>
@@ -802,7 +829,6 @@
<translation id="7567204685887185387">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad podría haberse emitido de forma fraudulenta. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="7568593326407688803">Esta página está en<ph name="ORIGINAL_LANGUAGE" />¿Quieres traducirla?</translation>
<translation id="7569952961197462199">¿Confirmas que quieres quitar la tarjeta de crédito de Chrome?</translation>
-<translation id="7569983096843329377">Negro</translation>
<translation id="7578104083680115302">Paga con rapidez en sitios y apps a través de varios dispositivos con tarjetas que guardaste en Google.</translation>
<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">El certificado del servidor no cumple con las restricciones de nombre.</translation>
@@ -821,11 +847,13 @@
<translation id="7669271284792375604">Es posible que los atacantes de este sitio intenten engañarte para que instales programas que pueden afectar tu experiencia de navegación (p. ej., podrían cambiar la página principal o mostrar más anuncios en los sitios que visitas).</translation>
<translation id="7674629440242451245">Si estás interesado en probar nuevas e interesantes funciones de Chrome, visita nuestro canal de programadores en chrome.com/dev.</translation>
<translation id="7682287625158474539">Envío</translation>
+<translation id="7699293099605015246">Los artículos no están disponibles en este momento</translation>
<translation id="7701040980221191251">Ninguno</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continuar a <ph name="SITE" /> (no seguro)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificado</translation>
<translation id="7716147886133743102">Bloqueado por tu administrador</translation>
<translation id="7716424297397655342">No se puede cargar este sitio desde la caché</translation>
+<translation id="7723047071702270851">Editar tarjeta</translation>
<translation id="774634243536837715">Se bloqueó contenido peligroso.</translation>
<translation id="7752995774971033316">Sin administrar</translation>
<translation id="7755287808199759310">Uno de tus padres puede desbloquearlo por ti</translation>
@@ -836,21 +864,24 @@
<translation id="7764225426217299476">Agregar dirección</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Agregar</translation>
+<translation id="7793553086574152071">Para realizar pagos más rápido la próxima vez, guarda esta tarjeta en tu cuenta de Google.</translation>
<translation id="7793809570500803535">Es posible que la página web en <ph name="SITE" /> no funcione temporalmente o se haya trasladado de manera permanente a una nueva dirección web.</translation>
<translation id="7800304661137206267">La conexión está encriptada mediante <ph name="CIPHER" />, con <ph name="MAC" /> para la autenticación de mensajes y <ph name="KX" /> como mecanismo de intercambio clave.</translation>
+<translation id="7802523362929240268">El sitio es legítimo</translation>
<translation id="780301667611848630">No, gracias</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">¿Confirmas que quieres quitar la sugerencia de formulario de Chrome?</translation>
<translation id="7815407501681723534">Se encontraron <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">Es posible que la red Wi-Fi que estás usando (<ph name="WIFI_NAME" />) requiera que visites la página de acceso.</translation>
<translation id="785549533363645510">Sin embargo, no eres invisible. El modo de navegación de incógnito no oculta tu navegación de tu empleador, de tu proveedor de servicios de Internet, ni de los sitios web que visitas.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Se aceptan tarjetas de débito y prepago.</translation>
+<translation id="7878562273885520351">Es posible que tu contraseña esté en peligro</translation>
<translation id="7887683347370398519">Verifica tu CVC y vuelve a intentarlo.</translation>
<translation id="79338296614623784">Ingresa un número de teléfono válido</translation>
<translation id="7935318582918952113">Filtro de DOM</translation>
<translation id="7938958445268990899">El certificado del servidor aún no es válido.</translation>
-<translation id="7942349550061667556">Rojo</translation>
<translation id="7947285636476623132">Comprueba el año de vencimiento y vuelve a intentarlo</translation>
<translation id="7951415247503192394">(32 bits)</translation>
<translation id="7956713633345437162">Favoritos del celular</translation>
@@ -864,9 +895,13 @@
<translation id="8037357227543935929">Preguntar (predeterminado)</translation>
<translation id="8041089156583427627">Enviar comentario</translation>
<translation id="8041940743680923270">Usar configuración global predeterminada (Preguntar)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" no se configuró correctamente. Prueba desinstalar "<ph name="SOFTWARE_NAME" />" para corregir el problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Error al visualizar artículo</translation>
<translation id="8091372947890762290">La activación está pendiente en el servidor.</translation>
+<translation id="8094917007353911263">Es posible que la red que estás usando requiera que accedas a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Forma de pago</translation>
<translation id="8118489163946903409">Forma de pago</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" no se instaló correctamente en tu computadora o red. Solicita al administrador de IT que corrija este problema.</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se encontró la <ph name="BEGIN_ABBR" />dirección DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">La computadora se suspendió.</translation>
@@ -889,6 +924,7 @@
<translation id="8289355894181816810">Comunícate con el administrador de red si no entiendes bien lo que significa.</translation>
<translation id="8293206222192510085">Agregar Marcador</translation>
<translation id="8294431847097064396">Fuente</translation>
+<translation id="8298115750975731693">Es posible que la red Wi-Fi que estás usando (<ph name="WIFI_NAME" />) requiera que accedas a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">No se puede establecer una conexión privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y hora del dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Se produjo un error en la traducción a causa de un problema con la conexión de red.</translation>
<translation id="8332188693563227489">Se denegó el acceso a <ph name="HOST_NAME" /></translation>
@@ -942,20 +978,21 @@
<translation id="8870413625673593573">Cerrado recientemente</translation>
<translation id="8874824191258364635">Ingresa un número de tarjeta válido</translation>
<translation id="8876793034577346603">No se pudo analizar la configuración de red.</translation>
-<translation id="8889402386540077796">Tono</translation>
<translation id="8891727572606052622">Modo proxy no válido</translation>
<translation id="889901481107108152">Este experimento no está disponible en tu plataforma.</translation>
<translation id="8903921497873541725">Acercar</translation>
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">El reloj está atrasado</translation>
+<translation id="893332455753468063">Agregar nombre</translation>
<translation id="8938939909778640821">Tarjetas de crédito y prepago aceptadas</translation>
+<translation id="8957210676456822347">Autorización de portal cautivo</translation>
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
-<translation id="8986494364107987395">Enviar automáticamente estadísticas de uso e informes sobre fallos a Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">El siguiente sitio contiene programas peligrosos</translation>
<translation id="8997023839087525404">El servidor presentó un certificado que no se divulgó de forma pública con la política Certificado de transparencia. Este es un requisito para algunos certificados que permite garantizar su confiabilidad y protegerte de atacantes.</translation>
<translation id="9001074447101275817">El proxy <ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
<translation id="9005998258318286617">No se pudo cargar el documento PDF.</translation>
+<translation id="9008201768610948239">Ignorar</translation>
<translation id="901974403500617787">El propietario es el único que puede especificar las marcas que se aplican a todo el sistema: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Se requiere una dirección de facturación de la tarjeta</translation>
<translation id="9020542370529661692">Esta página se tradujo al <ph name="TARGET_LANGUAGE" />.</translation>
@@ -965,11 +1002,14 @@
<translation id="9049981332609050619">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor presentó un certificado no válido.</translation>
<translation id="9050666287014529139">Frase de contraseña</translation>
<translation id="9065203028668620118">Editar</translation>
-<translation id="9068849894565669697">Seleccionar color</translation>
<translation id="9069693763241529744">Bloqueado por una extensión</translation>
<translation id="9076283476770535406">Es posible que incluya contenido para adultos</translation>
<translation id="9078964945751709336">Se requiere más información</translation>
+<translation id="9080712759204168376">Resumen del pedido</translation>
<translation id="9103872766612412690"><ph name="SITE" /> suele utilizar la encriptación para proteger la información. Cuando Chromium intentó conectarse a <ph name="SITE" />, el sitio web devolvió credenciales incorrectas y poco comunes. Es posible que un atacante quiera suplantar a <ph name="SITE" /> o que una pantalla de acceso Wi-Fi haya interrumpido la conexión. Tu información permanece segura porque Chromium detuvo la conexión para evitar el intercambio de datos.</translation>
+<translation id="9106062320799175032">Agregar dirección de facturación</translation>
+<translation id="910908805481542201">Ayudarme a solucionar este problema</translation>
+<translation id="9128870381267983090">Conectarse a una red</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Abre Chrome y accede a tu cuenta antes de usar esta app.</translation>
<translation id="9148507642005240123">&amp;Deshacer Editar</translation>
@@ -981,6 +1021,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utiliza un protocolo no compatible.</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="9215416866750762878">Una aplicación impide que Chrome se conecte de forma segura a este sitio</translation>
<translation id="9219103736887031265">Imágenes</translation>
<translation id="933612690413056017">No hay conexión a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -990,5 +1031,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ninguno}=1{1 elemento}other{# elementos}}</translation>
<translation id="981121421437150478">Sin conexión</translation>
<translation id="988159990683914416">Build para desarrolladores</translation>
+<translation id="989988560359834682">Modificar dirección</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" no se instaló correctamente en tu computadora o red:
+ &lt;ul&gt;
+ &lt;li&gt;Prueba desinstalar o inhabilitar "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Prueba conectarte a otra red&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index 378dce1c291..09780cdf4ee 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Marcadores del ordenador</translation>
<translation id="1074497978438210769">No es seguro</translation>
<translation id="1080116354587839789">Se ajusta al ancho</translation>
+<translation id="1088860948719068836">Añade el nombre de la tarjeta</translation>
<translation id="1103523840287552314">Traducir siempre el <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostrar todas las contraseñas guardadas...</translation>
<translation id="1107591249535594099">Si se selecciona, Chrome almacenará una copia de tu tarjeta en este dispositivo para completar formularios más rápidamente.</translation>
<translation id="1111153019813902504">Marcadores visitados recientemente</translation>
<translation id="1113869188872983271">&amp;Deshacer reorganización</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizados)</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> (todavía no se ha subido ni ignorado)</translation>
+<translation id="1270502636509132238">Método de recogida</translation>
<translation id="1281526147609854549">Emitido por <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">No traducir nunca este sitio</translation>
<translation id="129553762522093515">Cerrado recientemente</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Esperando conexión…</translation>
<translation id="153384715582417236">Eso es todo por ahora</translation>
<translation id="1549470594296187301">JavaScript debe estar habilitado para utilizar esta función.</translation>
-<translation id="1555130319947370107">Azul</translation>
<translation id="1559528461873125649">No existe el archivo o el directorio.</translation>
<translation id="1583429793053364125">Se ha producido un error al mostrar esta página web.</translation>
<translation id="1592005682883173041">Acceso a datos locales</translation>
<translation id="1594030484168838125">Seleccionar</translation>
-<translation id="161042844686301425">Cian</translation>
<translation id="1620510694547887537">Cámara</translation>
<translation id="1629803312968146339">¿Quieres que Chrome guarde esta tarjeta?</translation>
<translation id="1639239467298939599">Cargando</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1721312023322545264">Necesitas permiso de <ph name="NAME" /> para acceder a este sitio web</translation>
<translation id="1721424275792716183">* El campo es obligatorio</translation>
+<translation id="1727741090716970331">Añade un número de tarjeta válido</translation>
<translation id="1728677426644403582">Estás viendo el código fuente de una página web</translation>
<translation id="173080396488393970">No se admite este tipo de tarjeta</translation>
<translation id="1734864079702812349">American Express</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Error de serialización</translation>
<translation id="1974060860693918893">Configuración avanzada</translation>
<translation id="1978555033938440688">Versión de firmware</translation>
-<translation id="1995859865337580572">Verifica el CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{y una más}other{y # más}}</translation>
<translation id="2025186561304664664">Se ha establecido que el proxy se configure automáticamente.</translation>
<translation id="2030481566774242610">¿Querías decir <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Para obtener contenido personalizado sugerido por Google, inicia sesión en Chrome.</translation>
+<translation id="2091887806945687916">Sonido</translation>
<translation id="2094505752054353250">El dominio no coincide</translation>
<translation id="2096368010154057602">Departamento</translation>
<translation id="2108755909498034140">Reinicia el ordenador</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Se ha ignorado la política porque la anula <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Buscando páginas de la Web física cercanas</translation>
<translation id="213826338245044447">Marcadores del móvil</translation>
+<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
+<translation id="2148613324460538318">Añadir tarjeta</translation>
<translation id="2154054054215849342">La sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{Una dirección}other{# direcciones}}</translation>
<translation id="2187317261103489799">Detectar (predeterminado)</translation>
<translation id="2202020181578195191">Introduce un año de vencimiento válido</translation>
+<translation id="2209523182407020534">Entre las aplicaciones que pueden provocar este error se incluyen software cortafuegos, antivirus, proxy y de filtrado web.</translation>
<translation id="2212735316055980242">Política no encontrada</translation>
<translation id="2213606439339815911">Recuperando entradas...</translation>
<translation id="2218879909401188352">Se ha detectado la presencia de atacantes en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> que podrían instalar aplicaciones peligrosas que dañen tu dispositivo, añadir cargos ocultos a tu factura del móvil o robar tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Volver</translation>
<translation id="2503184589641749290">Tarjetas prepago y de débito aceptadas</translation>
<translation id="2515629240566999685">Comprobar la señal en tu zona</translation>
+<translation id="2524461107774643265">Añade más información</translation>
+<translation id="2536110899380797252">Añadir dirección</translation>
<translation id="2539524384386349900">Detectar</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha enviado una respuesta no válida.</translation>
<translation id="2556876185419854533">&amp;Deshacer edición</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
<translation id="2705137772291741111">La copia guardada (almacenada en caché) de este sitio web no se ha podido leer.</translation>
<translation id="2709516037105925701">Autocompletar</translation>
+<translation id="2710942282213947212">Hay software en tu ordenador que impide que Chromium se conecte a la Web de forma segura</translation>
<translation id="2712173769900027643">Solicitar permiso</translation>
-<translation id="2713444072780614174">Blanco</translation>
<translation id="2720342946869265578">Cercanas</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2728127805433021124">El certificado del servidor está firmado con un algoritmo de firma no seguro.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Se ha detectado un cambio de red.</translation>
<translation id="2916038427272391327">Cierra otros programas</translation>
<translation id="2922350208395188000">No es posible comprobar el certificado del servidor.</translation>
+<translation id="2925673989565098301">Método de entrega</translation>
<translation id="2928905813689894207">Dirección de facturación</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> más}}</translation>
<translation id="2941952326391522266">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad procede de <ph name="DOMAIN2" />. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipo de política incorrecto</translation>
<translation id="3032412215588512954">¿Quieres volver a cargar este sitio web?</translation>
<translation id="3037605927509011580">¡Oh, no!</translation>
+<translation id="3039538478787849737">¿Quieres guardar la tarjeta en Google?</translation>
<translation id="3041612393474885105">Datos del certificado</translation>
<translation id="3063697135517575841">Chrome no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
<translation id="3064966200440839136">Saldrás del modo incógnito para realizar un pago en una aplicación externa. ¿Quieres continuar?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Error de servidor temporal</translation>
<translation id="3154506275960390542">Es posible que un formulario de esta página no se envíe de forma segura. Otros usuarios pueden ver los datos que envías mientras estén en circulación y un atacante podría modificar lo que recibe el servidor.</translation>
<translation id="3157931365184549694">Restaurar</translation>
+<translation id="3162559335345991374">La red Wi-Fi que estás utilizando puede requerir que accedas a su página de inicio de sesión.</translation>
<translation id="3167968892399408617">Las páginas que aparezcan en las pestañas de incógnito no se guardarán en el historial del navegador, en el almacén de cookies ni en el historial de búsquedas una vez que hayas cerrado todas tus pestañas de incógnito. Se mantendrán los archivos que descargues o los marcadores que crees.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Isla</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancelar pago</translation>
<translation id="3207960819495026254">Añadido a marcadores</translation>
+<translation id="3211223744486044430">Guarda esta tarjeta en tu cuenta de Google y en este dispositivo para pagar más rápido la próxima vez.</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>
<translation id="3226128629678568754">Pulsa el botón de actualización de página para que se vuelvan a enviar los datos necesarios para cargar la página.</translation>
<translation id="3227137524299004712">Micrófono</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">No se han encontrado resultados de búsqueda</translation>
<translation id="3305707030755673451">Tus datos se cifraron con tu frase de contraseña de sincronización el <ph name="TIME" />. Introdúcela para iniciar la sincronización.</translation>
<translation id="3320021301628644560">Añadir dirección de facturación</translation>
-<translation id="3329013043687509092">Saturación</translation>
<translation id="333371639341676808">Evita que esta página cree cuadros de diálogo adicionales.</translation>
<translation id="3338095232262050444">Es seguro</translation>
<translation id="3340978935015468852">configuración</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID de cliente:</translation>
<translation id="3391030046425686457">Dirección de entrega</translation>
<translation id="3395827396354264108">Método de recogida</translation>
+<translation id="3399952811970034796">Dirección de entrega</translation>
<translation id="3422248202833853650">Prueba a salir de otros programas para liberar memoria.</translation>
<translation id="3422472998109090673">No se puede acceder a la página <ph name="HOST_NAME" /> en este momento.</translation>
<translation id="3427092606871434483">Permitir (predeterminado)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> y subido el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Datos del certificado</translation>
<translation id="3690164694835360974">Inicio de sesión no seguro</translation>
+<translation id="3704162925118123524">La red que estás utilizando puede requerir el acceso a su página de inicio de sesión.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi</translation>
+<translation id="3715597595485130451">Conectarse a una red Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar el proxy, el cortafuegos y la configuración de DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Si entiendes los riesgos para tu seguridad, puedes <ph name="BEGIN_LINK" />acceder a este sitio no seguro<ph name="END_LINK" /> antes de que se hayan eliminado los programas peligrosos.</translation>
<translation id="3739623965217189342">Enlace copiado</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Deshacer acción de añadir</translation>
<translation id="404928562651467259">ADVERTENCIA</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Se ha configurado el proxy para que use una URL de secuencia de comandos .pac, en lugar de servidores proxy fijos.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">El número de serie del dispositivo no es válido.</translation>
<translation id="410351446219883937">Reproducción automática</translation>
<translation id="4103763322291513355">Accede a la página &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URLs no admitidas y otras políticas establecidas por el administrador del sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Permitir siempre en este sitio</translation>
<translation id="4117700440116928470">No se admite el alcance de la política.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{Uno más}other{# más}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Has intentado acceder a <ph name="DOMAIN" />, pero el emisor ha revocado el certificado mostrado por el servidor, lo que significa que las credenciales de seguridad presentadas por el servidor no son de confianza. Es posible que hayas accedido a la página de un atacante.</translation>
<translation id="4394049700291259645">Inhabilitar</translation>
<translation id="4406896451731180161">resultados de la búsqueda</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="4432688616882109544"><ph name="HOST_NAME" /> no ha aceptado el certificado de inicio de sesión o es posible que no se haya proporcionado ninguno.</translation>
<translation id="443673843213245140">Se ha inhabilitado el uso de un servidor proxy, pero se han especificado ajustes de proxy explícitos.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Inhabilita las extensiones.</translation>
<translation id="457875822857220463">Envío</translation>
+<translation id="4582800630050655161">Podrías perder el acceso a tu cuenta de Google o experimentar problemas de suplantación de identidad. Chromium te recomienda que cambies la contraseña ahora.</translation>
<translation id="4587425331216688090">¿Eliminar dirección de Chrome?</translation>
<translation id="4592951414987517459">Tu conexión con <ph name="DOMAIN" /> está cifrada con un conjunto de cifrado moderno.</translation>
<translation id="4594403342090139922">&amp;Deshacer eliminación</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Dejar de utilizar un certificado no válido</translation>
+<translation id="4690954380545377795">Podrías perder el acceso a tu cuenta de Google o experimentar problemas de suplantación de identidad. Chrome te recomienda que cambies la contraseña ahora.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Se ha interrumpido la conexión</translation>
<translation id="471880041731876836">No tienes permiso para acceder a este sitio web</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ejecutar Diagnósticos de red de Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Tu pago</translation>
<translation id="4726672564094551039">Volver a cargar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4736825316280949806">Reinicia Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">El almacén secundario está en mal estado.</translation>
<translation id="5023310440958281426">Consulta las políticas del administrador</translation>
<translation id="5029568752722684782">Borrar copia</translation>
+<translation id="503069730517007720">Se necesita un certificado raíz para "<ph name="SOFTWARE_NAME" />", pero no está instalado. El administrador de TI debe comprobar las instrucciones de configuración de "<ph name="SOFTWARE_NAME" />" para solucionar este problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Informacion del Traductor de Google</translation>
<translation id="5039804452771397117">Permitir</translation>
<translation id="5040262127954254034">Privacidad</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5205222826937269299">Nombre obligatorio</translation>
<translation id="5222812217790122047">Correo electrónico obligatorio</translation>
+<translation id="522700295135997067">Es posible que este sitio web te acabe de robar la contraseña</translation>
+<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5251803541071282808">Nube</translation>
<translation id="5277279256032773186">¿Usas Chrome en el trabajo? Las empresas pueden administrar la configuración de Chrome de sus empleados. Más información</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Sigue estos pasos para inhabilitar temporalmente el software y poder acceder a la Web. Necesitarás privilegios de administrador.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Tu conexión a este sitio web no es privada. Para salir del modo RV en cualquier momento, quita el visor y pulsa Atrás.</translation>
<translation id="5299298092464848405">Error al analizar la política</translation>
+<translation id="5308380583665731573">Conectar</translation>
<translation id="5308689395849655368">Notificación de fallos inhabilitada</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nombre</translation>
+<translation id="5332219387342487447">Método de envío</translation>
<translation id="5355557959165512791">No puedes acceder a <ph name="SITE" /> en este momento porque su certificado se ha revocado. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde.</translation>
<translation id="536296301121032821">Error al almacenar la configuración de la política</translation>
<translation id="5386426401304769735">La cadena de certificados de este sitio web contiene un certificado firmado con SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Este sitio web de la intranet del centro educativo, de la organización o de la empresa tiene la misma URL que un sitio web externo.
<ph name="LINE_BREAK" />
Ponte en contacto con el administrador del sistema.</translation>
+<translation id="5499929369096410817">Introduce el código de seguridad de la tarjeta <ph name="CREDIT_CARD" />. Este código no se guardará.</translation>
<translation id="5509780412636533143">Marcadores administrados</translation>
<translation id="5510766032865166053">Es posible que se haya movido o eliminado.</translation>
<translation id="5523118979700054094">Nombre de la política</translation>
<translation id="552553974213252141">¿Se ha extraído el texto correctamente?</translation>
<translation id="5540224163453853">No se ha podido encontrar el artículo solicitado.</translation>
+<translation id="5541546772353173584">Añade un correo electrónico</translation>
<translation id="5544037170328430102">Una página insertada en <ph name="SITE" /> dice:</translation>
+<translation id="5545756402275714221">Artículos recomendados para ti</translation>
<translation id="5556459405103347317">Volver a cargar</translation>
<translation id="5560088892362098740">Fecha de caducidad</translation>
<translation id="5565735124758917034">Activo</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Correo electrónico</translation>
<translation id="5669703222995421982">Obtener contenido personalizado</translation>
<translation id="5675650730144413517">Esta página no funciona</translation>
+<translation id="5689199277474810259">Exportar a JSON</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5719499550583120431">Se aceptan tarjetas prepago.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Tu conexión con <ph name="DOMAIN" /> está cifrada con un conjunto de cifrado obsoleto.</translation>
<translation id="5813119285467412249">&amp;Rehacer acción de añadir</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="5866257070973731571">Añade un número de teléfono</translation>
<translation id="5869405914158311789">No se puede acceder a este sitio web</translation>
<translation id="5869522115854928033">Contraseñas guardadas</translation>
<translation id="5872918882028971132">Sugerencias de padres</translation>
<translation id="5893752035575986141">Se aceptan tarjetas de crédito.</translation>
-<translation id="5901630391730855834">Amarillo</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 en uso}other{# en uso}}</translation>
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />información del sistema y contenido de las páginas<ph name="END_WHITEPAPER_LINK" /> a Google para facilitar la detección de aplicaciones y sitios web peligrosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edita la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Reducir</translation>
+<translation id="597552863672748783">Confirmar código de seguridad</translation>
<translation id="598637245381783098">No se ha podido abrir la aplicación de pago</translation>
<translation id="5989320800837274978">No se han especificado servidores proxy fijos ni una URL de secuencia de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión ha bloqueado el envío de solicitudes al servidor.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}other{Página #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Se ha detectado la presencia de atacantes en el sitio web <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />. Estos podrían 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_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizados)</translation>
<translation id="6027201098523975773">Introduce un nombre</translation>
<translation id="6040143037577758943">Cerrar</translation>
-<translation id="6042308850641462728">Más</translation>
<translation id="6047233362582046994">Si entiendes los riesgos para tu seguridad, puedes <ph name="BEGIN_LINK" />acceder a este sitio web<ph name="END_LINK" /> antes de que se hayan eliminado las aplicaciones dañinas.</translation>
<translation id="6047927260846328439">Es posible que este contenido intente engañarte para que instales software o reveles información personal. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web utiliza la fijación de certificados. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Estas viendo la página de una extensión</translation>
<translation id="6596325263575161958">Opciones de cifrado</translation>
<translation id="662080504995468778">Seguir aquí</translation>
+<translation id="6624427990725312378">Información de contacto</translation>
<translation id="6626291197371920147">Añadir un número de tarjeta válido</translation>
<translation id="6628463337424475685">Búsqueda de <ph name="ENGINE" /></translation>
<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>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Introducir término de búsqueda&gt;</translation>
<translation id="6711464428925977395">Se ha producido un error con el servidor proxy o la dirección es incorrecta.</translation>
-<translation id="6727102863431372879">Establecer</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido</translation>
<translation id="6753269504797312559">Valor de la política</translation>
<translation id="6757797048963528358">El dispositivo se ha suspendido.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Ruta del perfil</translation>
<translation id="7424977062513257142">Una página insertada en este sitio web dice:</translation>
+<translation id="7437289804838430631">Añade la información de contacto</translation>
<translation id="7441627299479586546">Asunto de política incorrecto</translation>
<translation id="7444046173054089907">Este sitio web se ha bloqueado</translation>
<translation id="7445762425076701745">La identidad del servidor al que estás conectado no se puede validar por completo. Estás conectado a un servidor con un nombre que solo es válido en tu red y cuya propiedad no puede validar en modo alguno una entidad emisora de certificados externa. A pesar de ello, algunas entidades emisoras emiten certificados para esos nombres, por lo que no es posible garantizar que estés conectado al sitio web deseado, en lugar de a un atacante.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Adelante</translation>
<translation id="7485870689360869515">No se han encontrado datos.</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="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>
<translation id="7514365320538308">Descargar</translation>
<translation id="7518003948725431193">No se ha encontrado ninguna página web para la dirección <ph name="URL" />.</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Tu conexión con este sitio web no es privada</translation>
-<translation id="7535087603100972091">Valor</translation>
<translation id="7537536606612762813">Obligatoria</translation>
<translation id="7542403920425041731">Cuando la confirmes, la información de la tarjeta se compartirá con este sitio web.</translation>
<translation id="7542995811387359312">La opción de autocompletado de la tarjeta de crédito está inhabilitada porque este formulario no utiliza una conexión segura.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad podría haberse emitido de forma fraudulenta. El problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="7568593326407688803">Esta página está escrita en<ph name="ORIGINAL_LANGUAGE" />¿Quieres traducirla?</translation>
<translation id="7569952961197462199">¿Eliminar tarjeta de crédito de Chrome?</translation>
-<translation id="7569983096843329377">Negro</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="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">El certificado del servidor incluye un nombre que está fuera de su cobertura.</translation>
@@ -820,11 +846,13 @@
<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="7674629440242451245">Si estás interesado en probar nuevas e interesantes funciones de Chrome, prueba el canal para desarrolladores en la página chrome.com/dev.</translation>
<translation id="7682287625158474539">Dirección de envío</translation>
+<translation id="7699293099605015246">Los artículos no están disponibles en este momento</translation>
<translation id="7701040980221191251">Ninguno</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Acceder a <ph name="SITE" /> (sitio no seguro)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificado</translation>
<translation id="7716147886133743102">Bloqueado por el administrador</translation>
<translation id="7716424297397655342">No se puede cargar este sitio web desde la caché</translation>
+<translation id="7723047071702270851">Edita la tarjeta</translation>
<translation id="774634243536837715">Contenido peligroso bloqueado.</translation>
<translation id="7752995774971033316">No administrado</translation>
<translation id="7755287808199759310">Uno de tus padres puede desbloquearlo</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Añadir dirección</translation>
<translation id="777702478322588152">Prefectura</translation>
<translation id="7791543448312431591">Añadir</translation>
+<translation id="7793553086574152071">Guarda esta tarjeta en tu cuenta de Google para pagar más rápido la próxima vez.</translation>
<translation id="7793809570500803535">Es posible que la página web de <ph name="SITE" /> esté temporalmente inactiva o que se haya trasladado definitivamente a otra dirección web.</translation>
<translation id="7800304661137206267">La conexión se ha encriptado mediante <ph name="CIPHER" />, con <ph name="MAC" /> para la autenticación del mensaje y con <ph name="KX" /> como mecanismo de intercambio de claves.</translation>
+<translation id="7802523362929240268">El sitio web es legítimo</translation>
<translation id="780301667611848630">No, gracias</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">¿Eliminar sugerencia de formulario de Chrome?</translation>
<translation id="7815407501681723534">Se han encontrado <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> de <ph name="SEARCH_STRING" /></translation>
+<translation id="782886543891417279">La red Wi-Fi que estás utilizando (<ph name="WIFI_NAME" />) puede requerir que accedas a su página de inicio de sesión.</translation>
<translation id="785549533363645510">Ten en cuenta que tus acciones no serán totalmente invisibles. El uso del modo incógnito no te permite ocultar tu actividad de navegación a tu empresa, a tu proveedor de servicios de Internet o a los sitios web que visites.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Se aceptan tarjetas prepago y de débito.</translation>
+<translation id="7878562273885520351">Es posible que tu contraseña se haya vulnerado</translation>
<translation id="7887683347370398519">Comprueba el código CVC y vuelve a intentarlo</translation>
<translation id="79338296614623784">Introduce un número de teléfono válido</translation>
<translation id="7935318582918952113">Extractor de DOM</translation>
<translation id="7938958445268990899">Aún no es válido el certificado de servidor.</translation>
-<translation id="7942349550061667556">Rojo</translation>
<translation id="7947285636476623132">Consulta el año de vencimiento y vuelve a intentarlo</translation>
<translation id="7951415247503192394">(32 bits)</translation>
<translation id="7956713633345437162">Marcadores del móvil</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Preguntar (predeterminado)</translation>
<translation id="8041089156583427627">Enviar</translation>
<translation id="8041940743680923270">Utilizar valor predeterminado global (Preguntar)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" no se ha configurado correctamente. Normalmente, el problema se soluciona al desinstalar "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Se ha producido un error al ver el artículo.</translation>
<translation id="8091372947890762290">La activación está pendiente en el servidor.</translation>
+<translation id="8094917007353911263">La red 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>
+<translation id="8103161714697287722">Método de pago</translation>
<translation id="8118489163946903409">Método de pago</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" no se ha instalado correctamente en tu ordenador o red. Ponte en contacto con el administrador de TI para resolver el problema.</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se ha podido encontrar la <ph name="BEGIN_ABBR" />dirección DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">El ordenador se ha suspendido.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Si tienes alguna duda, ponte en contacto con el administrador de red.</translation>
<translation id="8293206222192510085">Añadir marcador</translation>
<translation id="8294431847097064396">Origen</translation>
+<translation id="8298115750975731693">La red Wi-Fi que estás utilizando (<ph name="WIFI_NAME" />) puede requerir que accedas a la página <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">No se puede establecer ninguna 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. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Se ha producido un error de traducción debido a un problema con la conexión de red.</translation>
<translation id="8332188693563227489">Se ha denegado el acceso a <ph name="HOST_NAME" /></translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Cerrado recientemente</translation>
<translation id="8874824191258364635">Introduce un número de tarjeta válido</translation>
<translation id="8876793034577346603">No se ha podido analizar la configuración de red.</translation>
-<translation id="8889402386540077796">Matiz</translation>
<translation id="8891727572606052622">El modo de proxy no es válido.</translation>
<translation id="889901481107108152">Esta función experimental no está disponible en tu plataforma.</translation>
<translation id="8903921497873541725">Acercar</translation>
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">Tu reloj está atrasado</translation>
+<translation id="893332455753468063">Añade un nombre</translation>
<translation id="8938939909778640821">Tarjetas prepago y de crédito aceptadas</translation>
+<translation id="8957210676456822347">Autorización de portal cautivo</translation>
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
-<translation id="8986494364107987395">Enviar automáticamente estadísticas de uso e informes sobre fallos a Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">El sitio al que vas a acceder contiene programas dañinos</translation>
<translation id="8997023839087525404">El servidor ha mostrado un certificado que no se ha hecho público mediante la Política de Transparencia en los Certificados. Este requisito se aplica a algunos certificados para garantizar que son de confianza y ofrecer protección contra los atacantes.</translation>
<translation id="9001074447101275817">El proxy <ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
<translation id="9005998258318286617">Se ha producido un error al cargar el documento PDF.</translation>
+<translation id="9008201768610948239">Ignorar</translation>
<translation id="901974403500617787">Las opciones que se aplican a todo el sistema solo las puede establecer el propietario: <ph name="OWNER_EMAIL" />.</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>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado no válido.</translation>
<translation id="9050666287014529139">Frase de contraseña</translation>
<translation id="9065203028668620118">Editar</translation>
-<translation id="9068849894565669697">Seleccionar color</translation>
<translation id="9069693763241529744">Bloqueado por una extensión</translation>
<translation id="9076283476770535406">Es posible que incluya contenido para adultos</translation>
<translation id="9078964945751709336">Se necesita más información</translation>
+<translation id="9080712759204168376">Resumen del pedido</translation>
<translation id="9103872766612412690"><ph name="SITE" /> utiliza normalmente el cifrado para proteger tu información. Cuando Chromium intentó establecer conexión con <ph name="SITE" />, el sitio web devolvió unas credenciales inusuales e incorrectas. Esto puede ocurrir si un atacante intenta suplantar la identidad de <ph name="SITE" /> o si una pantalla de inicio de sesión Wi-Fi interrumpe la conexión. Tu información sigue estando protegida, ya que Chromium detuvo la conexión antes de que se intercambiaran datos.</translation>
+<translation id="9106062320799175032">Añade una dirección de facturación</translation>
+<translation id="910908805481542201">Ayuda para solucionarlo</translation>
+<translation id="9128870381267983090">Conectarse a la red</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Abre Chrome e inicia sesión en el navegador para usar esta aplicación.</translation>
<translation id="9148507642005240123">&amp;Deshacer edición</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">La página <ph name="HOST_NAME" /> utiliza un protocolo no admitido.</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="9215416866750762878">Hay una aplicación que impide que Chrome se conecte a este sitio web de forma segura</translation>
<translation id="9219103736887031265">Imágenes</translation>
<translation id="933612690413056017">No hay conexión a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ninguno}=1{1 elemento}other{# elementos}}</translation>
<translation id="981121421437150478">Sin conexión</translation>
<translation id="988159990683914416">Build para desarrolladores</translation>
+<translation id="989988560359834682">Editar dirección</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" no se ha instalado correctamente en tu ordenador o red:
+ &lt;ul&gt;
+ &lt;li&gt;Prueba a desinstalar o inhabilitar "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Prueba a conectarte a otra red&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index fa05fdfb245..ae6dab3ef67 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Töölaua järjehoidjad</translation>
<translation id="1074497978438210769">Pole turvaline</translation>
<translation id="1080116354587839789">Sobita laiusesse</translation>
+<translation id="1088860948719068836">Kaardil oleva nime lisamine</translation>
<translation id="1103523840287552314">Tõlgi alati: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Kuva kõik salvestatud paroolid …</translation>
<translation id="1107591249535594099">Kui see on märgitud, salvestab Chrome teie kaardi koopia sellesse seadmesse, et vormi kiiremini täita.</translation>
<translation id="1111153019813902504">Hiljuti kasutatud järjehoidjad</translation>
<translation id="1113869188872983271">&amp;Võta korrastamine tagasi</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sünkroonitud)</translation>
<translation id="1263231323834454256">Lugemisloend</translation>
<translation id="1264126396475825575">Krahhiaruanne talletati <ph name="CRASH_TIME" /> (ei ole veel üles laaditud ega eiratud)</translation>
+<translation id="1270502636509132238">Kättesaamisviis</translation>
<translation id="1281526147609854549">Väljaandja: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Ära kunagi seda saiti tõlgi</translation>
<translation id="129553762522093515">Viimati suletud</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Ühenduse ootamine …</translation>
<translation id="153384715582417236">See on praeguseks kõik</translation>
<translation id="1549470594296187301">Selle funktsiooni kasutamiseks peab JavaScript olema lubatud.</translation>
-<translation id="1555130319947370107">Sinine</translation>
<translation id="1559528461873125649">Pole sellist faili või kataloogi</translation>
<translation id="1583429793053364125">Veebilehe kuvamisel läks midagi valesti.</translation>
<translation id="1592005682883173041">Juurdepääs kohalikele andmetele</translation>
<translation id="1594030484168838125">Vali</translation>
-<translation id="161042844686301425">Tsüaan</translation>
<translation id="1620510694547887537">Kaamera</translation>
<translation id="1629803312968146339">Kas soovite, et Chrome salvestaks selle kaardi?</translation>
<translation id="1639239467298939599">Laadimine</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Vajate saidi külastamiseks halduri <ph name="NAME" /> luba</translation>
<translation id="1721424275792716183">* Kohustuslik väli</translation>
+<translation id="1727741090716970331">Kehtiva kaardinumbri lisamine</translation>
<translation id="1728677426644403582">Vaatate veebilehe lähtekoodi</translation>
<translation id="173080396488393970">Seda tüüpi kaarti ei toetata</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Viga jadaks teisendamisel</translation>
<translation id="1974060860693918893">Täpsemad</translation>
<translation id="1978555033938440688">Püsivara versioon</translation>
-<translation id="1995859865337580572">Kinnitage oma CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ja veel 1}other{ja veel #}}</translation>
<translation id="2025186561304664664">Puhverserver seadistatakse automaatselt.</translation>
<translation id="2030481566774242610">Kas mõtlesite aadressi <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Google'i soovitatud isikupärastatud sisu hankimiseks logige Chrome'i sisse.</translation>
+<translation id="2091887806945687916">Heli</translation>
<translation id="2094505752054353250">Domeeni vastuolu</translation>
<translation id="2096368010154057602">Osakond</translation>
<translation id="2108755909498034140">Taaskäivitage oma arvuti</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Seda ignoreeritakse, kuna reegel <ph name="POLICY_NAME" /> alistab selle.</translation>
<translation id="2138201775715568214">Lähedalasuvate füüsilise veebi lehtede otsimine</translation>
<translation id="213826338245044447">Mobiili järjehoidjad</translation>
+<translation id="214556005048008348">Tühista makse</translation>
<translation id="2147827593068025794">Taustal sünkroonimine</translation>
+<translation id="2148613324460538318">Lisa kaart</translation>
<translation id="2154054054215849342">Sünkroonimisteenus pole domeeni jaoks saadaval</translation>
<translation id="2154484045852737596">Kaardi muutmine</translation>
<translation id="2166049586286450108">Täielik administraatorijuurdepääs</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 aadress}other{# aadressi}}</translation>
<translation id="2187317261103489799">Tuvasta (vaikimisi)</translation>
<translation id="2202020181578195191">Sisestage kehtiv aegumisaasta</translation>
+<translation id="2209523182407020534">Selle vea võib põhjustada näiteks viirusetõrjetarkvara, tulemüür või veebi filtreerimise või puhverserveritarkvara.</translation>
<translation id="2212735316055980242">Reeglit ei leitud</translation>
<translation id="2213606439339815911">Kirjete toomine ...</translation>
<translation id="2218879909401188352">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad installida ohtlikke rakendusi, mis kahjustavad teie seadet, lisavad mobiiliarvele varjatud kulusid või varastavad teie isiklikke andmeid. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Mine tagasi</translation>
<translation id="2503184589641749290">Aktsepteeritavad ettemakstud ja deebetkaardid</translation>
<translation id="2515629240566999685">Kontrollige oma piirkonna signaali</translation>
+<translation id="2524461107774643265">Lisateabe lisamine</translation>
+<translation id="2536110899380797252">Lisa aadress</translation>
<translation id="2539524384386349900">Tuvasta</translation>
<translation id="255002559098805027">Host <ph name="HOST_NAME" /> saatis sobimatu vastuse.</translation>
<translation id="2556876185419854533">&amp;Võta muudatus tagasi</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
<translation id="2705137772291741111">Selle saidi (vahemällu) salvestatud koopia oli loetamatu.</translation>
<translation id="2709516037105925701">Automaatne täitmine</translation>
+<translation id="2710942282213947212">Teie arvutis olev tarkvara ei luba Chromiumil veebiga ohutult ühendust luua</translation>
<translation id="2712173769900027643">Küsi luba</translation>
-<translation id="2713444072780614174">Valge</translation>
<translation id="2720342946869265578">Läheduses</translation>
<translation id="2721148159707890343">Taotlus õnnestus</translation>
<translation id="2728127805433021124">Serveri sertifikaat on allkirjastatud nõrga allkirjaalgoritmiga.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Tuvastati võrgumuudatus.</translation>
<translation id="2916038427272391327">Sulgege muud programmid</translation>
<translation id="2922350208395188000">Serveri sertifikaati ei saa kontrollida.</translation>
+<translation id="2925673989565098301">Kohaletoimetamisviis</translation>
<translation id="2928905813689894207">Arveldusaadress</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaati pärineb domeenilt <ph name="DOMAIN2" />. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Reegli tüüp on vale</translation>
<translation id="3032412215588512954">Kas soovite selle saidi uuesti laadida?</translation>
<translation id="3037605927509011580">Ups, ebaõnn!</translation>
+<translation id="3039538478787849737">Kas salvestada kaart Google'isse?</translation>
<translation id="3041612393474885105">Sertifikaadi andmed</translation>
<translation id="3063697135517575841">Chrome ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
<translation id="3064966200440839136">Väljute inkognito režiimist, et välise rakenduse kaudu maksta. Kas soovite jätkata?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Serveris ilmnes ajutine viga</translation>
<translation id="3154506275960390542">See leht sisaldab vormi, mille esitamine ei pruugi olla turvaline. Teised võivad andmete edastamisel neid vaadata või ründaja võib serverile saadetavaid andmeid muuta.</translation>
<translation id="3157931365184549694">Taasta</translation>
+<translation id="3162559335345991374">WiFi-võrk, mida kasutate, võib nõuda sisselogimislehe külastamist.</translation>
<translation id="3167968892399408617">Inkognito vahelehtedel kuvatavaid lehti ei talletata pärast vahelehtede sulgemist brauseri ajalukku, küpsistefailide salve ega otsinguajalukku. Allalaaditavad failid ja järjehoidjatesse lisatud sisu säilitatakse.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Saar</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Tühista makse</translation>
<translation id="3207960819495026254">Järjehoidjatesse lisatud</translation>
+<translation id="3211223744486044430">Kui soovite järgmisel korral kiiremini maksta, salvestage kaart oma Google'i kontole ja sellesse seadmesse.</translation>
<translation id="3225919329040284222">Serveri esitatud sertifikaat ei vasta sisseehitatud ootustele. Ootused on teie kaitsmiseks kaasatud kindlate kõrge turvalisusega veebisaitide jaoks.</translation>
<translation id="3226128629678568754">Lehe laadimiseks vajalike andmete uuesti esitamiseks vajutage uuesti laadimise nuppu.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Otsingutulemusi ei leitud</translation>
<translation id="3305707030755673451">Teie andmed krüpteeriti <ph name="TIME" /> teie sünkroonimisparooliga. Sisestage see sünkroonimise alustamiseks.</translation>
<translation id="3320021301628644560">Arveldusaadressi lisamine</translation>
-<translation id="3329013043687509092">Küllastus</translation>
<translation id="333371639341676808">Keela sellel leheküljel lisadialoogide loomine.</translation>
<translation id="3338095232262050444">Turvaline</translation>
<translation id="3340978935015468852">seaded</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Kliendi ID:</translation>
<translation id="3391030046425686457">Kohaletoimetamise aadress</translation>
<translation id="3395827396354264108">Kättesaamisviis</translation>
+<translation id="3399952811970034796">Kohaletoimetamisaadress</translation>
<translation id="3422248202833853650">Proovige mälu vabastamiseks väljuda muudest programmidest.</translation>
<translation id="3422472998109090673">Hostiga <ph name="HOST_NAME" /> ei saa praegu ühendust.</translation>
<translation id="3427092606871434483">Luba (vaikimisi)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Krahhiaruanne jäädvustati ajal <ph name="CRASH_TIME" />, see laaditi üles ajal <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikaadi andmed</translation>
<translation id="3690164694835360974">Sisselogimine pole turvaline</translation>
+<translation id="3704162925118123524">Võrk, mida kasutate, võib nõuda sisselogimislehe külastamist.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laadimine...</translation>
<translation id="3712624925041724820">Litsentsid on ammendunud</translation>
<translation id="3714780639079136834">Lülitage sisse mobiilne andmeside või WiFi</translation>
+<translation id="3715597595485130451">Ühenduse loomine WiFi-võrguga</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kontrollige puhverserveri, tulemüüri ja DNS-i seadistust<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Kui mõistate, kuidas teie turvalisust ohustatakse, siis võite <ph name="BEGIN_LINK" />seda ebaturvalist saiti külastada<ph name="END_LINK" /> enne, kui ohtlikud programmid on eemaldatud.</translation>
<translation id="3739623965217189342">Teie kopeeritud link</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Võta lisamine tagasi</translation>
<translation id="404928562651467259">HOIATUS</translation>
<translation id="4058922952496707368">Võti „<ph name="SUBKEY" />”: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Puhverserveri konfigureerimine on määratud kasutama pac-skripti URL-i, mitte fikseeritud puhverservereid.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Seadme seerianumber on kehtetu</translation>
<translation id="410351446219883937">Automaatesitus</translation>
<translation id="4103763322291513355">Külastage saiti &lt;strong&gt;chrome://policy&lt;/strong&gt;, et näha mustas nimekirjas olevate URL-ide loendit ja teisi reegleid, mille on jõustanud teie süsteemiadministraator.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Luba sellel saidil alati</translation>
<translation id="4117700440116928470">Reegli ulatust ei toetata.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{veel 1}other{veel #}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Püüdsite jõuda saidile <ph name="DOMAIN" />, kuid sertifikaadi väljaandja on serveri esitatud sertifikaadi tagasi võtnud. See tähendab, et serveri esitatud turvamandaate ei tohiks mingil juhul usaldada. Võimalik, et suhtlete ründajaga.</translation>
<translation id="4394049700291259645">Keela</translation>
<translation id="4406896451731180161">otsingutulemused</translation>
+<translation id="4415426530740016218">Kättesaamisaadress</translation>
<translation id="4424024547088906515">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, Chrome ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> ei aktsepteerinud teie sisselogimise sertifikaati või te ei esitanud seda.</translation>
<translation id="443673843213245140">Puhverserveri kasutamine on keelatud, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Keelake laiendused.</translation>
<translation id="457875822857220463">Kohaletoimetamine</translation>
+<translation id="4582800630050655161">Võite kaotada juurdepääsu oma Google'i kontole või teie identiteet võidakse varastada. Chromium soovitab teil kohe oma parooli muuta.</translation>
<translation id="4587425331216688090">Kas eemaldada Chrome'ist aadress?</translation>
<translation id="4592951414987517459">Teie ühendus domeeniga <ph name="DOMAIN" /> on krüpteeritud tänapäevase šifreerimiskomplektiga.</translation>
<translation id="4594403342090139922">&amp;Võta kustutamine tagasi</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Lõpeta kehtetu sertifikaadi kasutamine</translation>
+<translation id="4690954380545377795">Võite kaotada juurdepääsu oma Google'i kontole või teie identiteet võidakse varastada. Chrome soovitab teil kohe oma parooli muuta.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Teie ühendus katkes</translation>
<translation id="471880041731876836">Teil ei ole selle saidi külastamiseks luba</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsi võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Teie makse</translation>
<translation id="4726672564094551039">Laadi reeglid uuesti</translation>
<translation id="4728558894243024398">Platvorm</translation>
<translation id="4736825316280949806">Taaskäivitage Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Varusalves esineb probleeme</translation>
<translation id="5023310440958281426">Tutvuge administraatori reeglitega</translation>
<translation id="5029568752722684782">Kustuta koopia</translation>
+<translation id="503069730517007720">Vaja on tarkvara „<ph name="SOFTWARE_NAME" />” juursertifikaati, kuid see pole installitud. Teie IT-administraator peaks probleemi lahendamiseks tarkvara „<ph name="SOFTWARE_NAME" />” seadistamisjuhised üle vaatama. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Teave Google'i tõlke kohta</translation>
<translation id="5039804452771397117">Luba</translation>
<translation id="5040262127954254034">Privaatsus</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Katsed</translation>
<translation id="5205222826937269299">Nimi on nõutav</translation>
<translation id="5222812217790122047">E-posti aadress on nõutav</translation>
+<translation id="522700295135997067">See sait võis äsja varastada teie parooli</translation>
+<translation id="5230733896359313003">Tarneaadress</translation>
<translation id="5251803541071282808">Pilv</translation>
<translation id="5277279256032773186">Kas kasutate Chrome'i tööl? Ettevõtted võivad hallata töötajate Chrome'i seadeid. Lisateave</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Tarkvara ajutiseks keelamiseks ja veebi pääsemiseks järgige neid toiminguid. Teil on vaja administraatoriõigusi.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Teie ühendus saidiga ei ole privaatne. VR-režiimist väljumiseks võite igal ajal eemaldada peakomplekti ja vajutada tagasinuppu.</translation>
<translation id="5299298092464848405">Reegli sõelumisel ilmnes viga</translation>
+<translation id="5308380583665731573">Ühendamine</translation>
<translation id="5308689395849655368">Krahhide aruandlus on keelatud.</translation>
<translation id="5317780077021120954">Salvesta</translation>
<translation id="5327248766486351172">Nimi</translation>
+<translation id="5332219387342487447">Tarneviis</translation>
<translation id="5355557959165512791">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest selle sertifikaat on tühistatud. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="536296301121032821">Reegli seadete talletamine ebaõnnestus</translation>
<translation id="5386426401304769735">Selle saidi sertifikaadiahel sisaldab sertifikaati, mis on allkirjastatud SHA-1-ga.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Sellel ettevõtte, organisatsiooni või kooli intranetis oleval saidil on sama URL mis välisel veebisaidil.
<ph name="LINE_BREAK" />
Võtke ühendust süsteemiadministraatoriga.</translation>
+<translation id="5499929369096410817">Sisestage krediitkaardi <ph name="CREDIT_CARD" /> turvakood. Seda koodi ei salvestata.</translation>
<translation id="5509780412636533143">Hallatud järjehoidjad</translation>
<translation id="5510766032865166053">See võidi teisaldada või kustutada.</translation>
<translation id="5523118979700054094">Reegli nimi</translation>
<translation id="552553974213252141">Kas tekst ekstraktiti õigesti?</translation>
<translation id="5540224163453853">Taotletud artiklit ei õnnestunud leida.</translation>
+<translation id="5541546772353173584">E-posti aadressi lisamine</translation>
<translation id="5544037170328430102">Manustatud leht saidil <ph name="SITE" /> ütleb:</translation>
+<translation id="5545756402275714221">Teile soovitatud artiklid</translation>
<translation id="5556459405103347317">Laadi uuesti</translation>
<translation id="5560088892362098740">Aegumiskuupäev</translation>
<translation id="5565735124758917034">Aktiivne</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Meil</translation>
<translation id="5669703222995421982">Isikupärastatud sisu hankimine</translation>
<translation id="5675650730144413517">See leht ei tööta</translation>
+<translation id="5689199277474810259">Ekspordi JSON-vormingus</translation>
<translation id="5710435578057952990">Selle veebisaidi identiteeti pole kinnitanud.</translation>
<translation id="5719499550583120431">Kaupmees aktsepteerib ettemakstud kaarte.</translation>
<translation id="5720705177508910913">Praegune kasutaja</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Teie ühendus domeeniga <ph name="DOMAIN" /> on krüpteeritud aegunud šifreerimiskomplektiga.</translation>
<translation id="5813119285467412249">&amp;Lisa uuesti</translation>
<translation id="5838278095973806738">Te ei tohiks sellele saidile sisestada tundlikku teavet (nt paroolid või krediitkaardid), kuna ründajad võivad selle varastada.</translation>
+<translation id="5866257070973731571">Telefoninumbri lisamine</translation>
<translation id="5869405914158311789">Selle saidiga ei saa ühendust</translation>
<translation id="5869522115854928033">Salvestatud paroolid</translation>
<translation id="5872918882028971132">Vanema soovitused</translation>
<translation id="5893752035575986141">Kaupmees aktsepteerib krediitkaarte.</translation>
-<translation id="5901630391730855834">Kollane</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sünkroonitud)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 on kasutusel}other{# on kasutusel}}</translation>
<translation id="5959728338436674663">Saatke Google'ile automaatselt <ph name="BEGIN_WHITEPAPER_LINK" />süsteemiteavet ja lehe sisu<ph name="END_WHITEPAPER_LINK" />, et aidata tuvastada ohtlikke rakendusi ja saite. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Kontaktteabe muutmine</translation>
<translation id="5967867314010545767">Eemalda ajaloost</translation>
<translation id="5975083100439434680">Suumib välja</translation>
+<translation id="597552863672748783">Turvakoodi kinnitamine</translation>
<translation id="598637245381783098">Makserakendust ei saa avada</translation>
<translation id="5989320800837274978">Määratud ei ole fikseeritud puhverservereid ega pac-skriptiga URL-i.</translation>
<translation id="5990559369517809815">Laiendus blokeeris serverisse saadetavad päringud.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Lk 1}other{Lk #}}</translation>
-<translation id="6017514345406065928">Roheline</translation>
<translation id="6017850046339264347">Ründajad saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> võivad installida petlikke rakendusi, mis esinevad millegi muuna või koguvad andmeid, mida võidakse kasutada teie jälgimiseks. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sünkroonitud)</translation>
<translation id="6027201098523975773">Sisestage nimi</translation>
<translation id="6040143037577758943">Sulge</translation>
-<translation id="6042308850641462728">Rohkem</translation>
<translation id="6047233362582046994">Kui mõistate, kuidas see teie turvalisust ohustab, siis võite <ph name="BEGIN_LINK" />seda saiti külastada<ph name="END_LINK" /> enne, kui kahjulikud rakendused on eemaldatud.</translation>
<translation id="6047927260846328439">See sisu võib meelitada teid installima tarkvara või avaldama isiklikke andmeid. <ph name="BEGIN_LINK" />Kuva ikkagi<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest veebisait kasutab sertifikaadi kinnitamist. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Vaatate laienduse lehte</translation>
<translation id="6596325263575161958">Krüpteerimise valikud</translation>
<translation id="662080504995468778">Jää siia</translation>
+<translation id="6624427990725312378">Kontaktteave</translation>
<translation id="6626291197371920147">Kehtiva kaardinumbri lisamine</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />'i otsing</translation>
<translation id="6630809736994426279">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad proovida installida teie Maci ohtlikke programme, mis varastavad teie teavet või kustutavad selle (nt fotod, paroolid, sõnumid ja krediitkaarditeave). <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Eelmine</translation>
<translation id="6710594484020273272">&lt;Sisestage otsingutermin&gt;</translation>
<translation id="6711464428925977395">Puhverserveriga on midagi valesti või aadress on vale.</translation>
-<translation id="6727102863431372879">Määra</translation>
<translation id="674375294223700098">Serveri sertifikaadi tundmatu viga.</translation>
<translation id="6753269504797312559">Reegli väärtus</translation>
<translation id="6757797048963528358">Teie seade lülitus unerežiimile.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profiili tee</translation>
<translation id="7424977062513257142">Selle veebilehe manustatud leht ütleb:</translation>
+<translation id="7437289804838430631">Lisa kontaktteave</translation>
<translation id="7441627299479586546">Reegli objekt on vale</translation>
<translation id="7444046173054089907">See sait on blokeeritud</translation>
<translation id="7445762425076701745">Serveri identiteeti, millega olete ühenduses, ei saa täielikult valideerida. Olete ühenduses serveriga nime abil, mis kehtib ainult teie võrgus, mistõttu ei saa väline sertifitseerimisorgan selle omandiõigust valideerida. Kuna mõni sertifitseerimisorgan väljastab sertifikaate hoolimata nende nimedest, puudub igasugune võimalus tagada, et olete ühenduses soovitud veebisaidi, mitte ründajaga.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Edasta</translation>
<translation id="7485870689360869515">Andmeid ei leitud.</translation>
<translation id="7508255263130623398">Tagastatud reegli seadme-ID on tühi või ei kattu praeguse seadme-ID-ga</translation>
+<translation id="7511955381719512146">WiFi-võrk, mida kasutate, võib nõuda veebilehe <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> külastamist.</translation>
<translation id="7514365320538308">Laadi alla</translation>
<translation id="7518003948725431193">Järgneval veebiaadressil ei olnud ühtegi veebilehte: <ph name="URL" /></translation>
<translation id="7521387064766892559">Javascript</translation>
<translation id="7526934274050461096">Teie ühendus selle saidiga pole privaatne</translation>
-<translation id="7535087603100972091">Väärtus</translation>
<translation id="7537536606612762813">Kohustuslik</translation>
<translation id="7542403920425041731">Kui selle kinnitate, jagatakse teie kaardi üksikasju selle saidiga.</translation>
<translation id="7542995811387359312">Automaatne krediitkaardi täide on keelatud, sest see vorm ei kasuta turvalist ühendust.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat võib olla väljastatud pettuse teel. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="7568593326407688803">See leht on keeles<ph name="ORIGINAL_LANGUAGE" />Kas soovite seda tõlkida?</translation>
<translation id="7569952961197462199">Kas eemaldada Chrome'ist krediitkaart?</translation>
-<translation id="7569983096843329377">Must</translation>
<translation id="7578104083680115302">Google'i salvestatud kaartide abil saate eri seadmetes saitidel ja rakendustes kiirelt maksta.</translation>
<translation id="7588950540487816470">Füüsiline veeb</translation>
<translation id="7592362899630581445">Serveri sertifikaat rikub nime piiranguid.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Sellel saidil asuvad ründajad võivad proovida meelitada teid installima programme, mis kahjustavad sirvimiskogemust (nt muudavad avalehte või kuvavad külastatavatel saitidel lisareklaame).</translation>
<translation id="7674629440242451245">Kas olete huvitatud Chrome'i uutest lahedatest funktsioonidest? Proovige meie arenduskanalit aadressil chrome.com/beta.</translation>
<translation id="7682287625158474539">Kohaletoimetamine</translation>
+<translation id="7699293099605015246">Artiklid pole praegu saadaval</translation>
<translation id="7701040980221191251">Mitte ükski</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Edasiliikumine saidile <ph name="SITE" /> (ebaturvaline)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifikaat</translation>
<translation id="7716147886133743102">Blokeeris administraator</translation>
<translation id="7716424297397655342">Seda saiti ei saa vahemälust laadida</translation>
+<translation id="7723047071702270851">Kaardi muutmine</translation>
<translation id="774634243536837715">Ohtlik sisu blokeeriti.</translation>
<translation id="7752995774971033316">Haldamata</translation>
<translation id="7755287808199759310">Vanem saab blokeeringu teie eest tühistada</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Lisage aadress</translation>
<translation id="777702478322588152">Prefektuur</translation>
<translation id="7791543448312431591">Lisa</translation>
+<translation id="7793553086574152071">Kui soovite järgmisel korral kiiremini maksta, salvestage kaart oma Google'i kontole.</translation>
<translation id="7793809570500803535">Veebileht aadressil <ph name="SITE" /> võib olla ajutiselt maas või jäädavalt uuele veebiaadressile teisaldatud.</translation>
<translation id="7800304661137206267">Ühenduse krüptimise moodus on <ph name="CIPHER" />, <ph name="MAC" /> sõnumite autentimiseks ja võtme vahetusmehhanism on <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Sait on seaduslik</translation>
<translation id="780301667611848630">Ei, aitäh</translation>
<translation id="7805768142964895445">Olek</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Kas eemaldada Chrome'ist vormi soovitus?</translation>
<translation id="7815407501681723534">Otsingule „<ph name="SEARCH_STRING" />” leiti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
+<translation id="782886543891417279">WiFi-võrk, mida kasutate (<ph name="WIFI_NAME" />), võib nõuda sisselogimislehe külastamist.</translation>
<translation id="785549533363645510">Te pole siiski nähtamatu. Inkognito režiimi kasutamine ei varja teie sirvimist tööandja, Interneti-teenuse pakkuja ega külastatavate veebisaitide eest.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Kaupmees aktsepteerib ettemakstud ja deebetkaarte.</translation>
+<translation id="7878562273885520351">Teie parool võib olla ohus</translation>
<translation id="7887683347370398519">Kontrollige CVC-d ja proovige uuesti</translation>
<translation id="79338296614623784">Sisestage kehtiv telefoninumber</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serveri sertifikaat ei kehti veel.</translation>
-<translation id="7942349550061667556">Punane</translation>
<translation id="7947285636476623132">Kontrollige aegumisaastat ja proovige uuesti</translation>
<translation id="7951415247503192394">(32-bitine)</translation>
<translation id="7956713633345437162">Mobiili järjehoidjad</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Küsi (vaikimisi)</translation>
<translation id="8041089156583427627">Saada tagasiside</translation>
<translation id="8041940743680923270">Kasuta globaalset vaikeseadet (küsi)</translation>
+<translation id="8057711352706143257">Tarkvara „<ph name="SOFTWARE_NAME" />” ei ole õigesti seadistatud. Tarkvara „<ph name="SOFTWARE_NAME" />” desinstallimine lahendab tavaliselt probleemi. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Artikli kuvamine ebaõnnestus.</translation>
<translation id="8091372947890762290">Aktiveerimine on serveris ootel</translation>
+<translation id="8094917007353911263">Võrk, mida kasutate, võib nõuda veebilehe <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> külastamist.</translation>
+<translation id="8103161714697287722">Makseviis</translation>
<translation id="8118489163946903409">Makseviis</translation>
+<translation id="8127301229239896662">Tarkvara „<ph name="SOFTWARE_NAME" />” ei installitud teie arvutisse või võrku korralikult. Paluge IT-administraatoril see probleem lahendada.</translation>
<translation id="8131740175452115882">Kinnita</translation>
<translation id="8134994873729925007">Hosti <ph name="HOST_NAME" /> serveri <ph name="BEGIN_ABBR" />DNS-aadressi<ph name="END_ABBR" /> ei leitud.</translation>
<translation id="8149426793427495338">Teie arvuti lülitus unerežiimile.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Kui te pole kindel, mida see tähendab, võtke ühendust oma võrguadministraatoriga.</translation>
<translation id="8293206222192510085">Lisa järjehoidja</translation>
<translation id="8294431847097064396">Allikas</translation>
+<translation id="8298115750975731693">WiFi-võrk, mida kasutate (<ph name="WIFI_NAME" />), võib nõuda veebilehe <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> külastamist.</translation>
<translation id="8306404619377842860">Domeeniga <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei saa privaatset ühendust luua, kuna seadme kuupäev ja kellaaeg (<ph name="DATE_AND_TIME" />) on valed. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Tõlkimine ebaõnnestus võrguühenduse probleemi tõttu.</translation>
<translation id="8332188693563227489">Juurdepääs hostile <ph name="HOST_NAME" /> blokeeriti</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Viimati suletud</translation>
<translation id="8874824191258364635">Sisestaeg kehtiv kaardinumber</translation>
<translation id="8876793034577346603">Võrgu seadistust ei õnnestunud sõeluda.</translation>
-<translation id="8889402386540077796">Värvitoon</translation>
<translation id="8891727572606052622">Kehtetu puhverserveri režiim.</translation>
<translation id="889901481107108152">Kahjuks ei ole see eksperiment teie platvormil saadaval.</translation>
<translation id="8903921497873541725">Suurendab</translation>
<translation id="8931333241327730545">Kas soovite selle kaardi salvestada oma Google'i kontole?</translation>
<translation id="8932102934695377596">Teie kell on taga</translation>
+<translation id="893332455753468063">Nime lisamine</translation>
<translation id="8938939909778640821">Aktsepteeritavad ettemakstud ja krediitkaardid</translation>
+<translation id="8957210676456822347">Kontrollportaali volitamine</translation>
<translation id="8971063699422889582">Serveri sertifikaat on aegunud.</translation>
-<translation id="8986494364107987395">Saada kasutusstatistika ja krahhiaruanded automaatselt Google'ile</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Sait, mille soovite avada, sisaldab kahjulikke programme</translation>
<translation id="8997023839087525404">Server esitas sertifikaadi, mida ei ole sertifikaadi läbipaistvuse reegli kohaselt avalikustatud. See on teatud sertifikaatide puhul nõutav, et need oleksid usaldusväärsed ja kaitseksid ründajate eest.</translation>
<translation id="9001074447101275817">Puhverserver <ph name="DOMAIN" /> nõuab kasutajanime ja parooli.</translation>
<translation id="9005998258318286617">PDF-dokumendi laadimine ebaõnnestus.</translation>
+<translation id="9008201768610948239">Eira</translation>
<translation id="901974403500617787">Kogu süsteemis kehtivaid märgiseid saab määrata ainult omanik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Kaardi arveldusaadress on nõutav</translation>
<translation id="9020542370529661692">See leht on tõlgitud <ph name="TARGET_LANGUAGE" /> keelde</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Proovisite jõuda domeenile <ph name="DOMAIN" />, kuid server esitas kehtetu sertifikaadi.</translation>
<translation id="9050666287014529139">Parool</translation>
<translation id="9065203028668620118">Muuda</translation>
-<translation id="9068849894565669697">Värvi valimine</translation>
<translation id="9069693763241529744">Blokeeris laiendus</translation>
<translation id="9076283476770535406">See võib sisaldada täiskasvanutele mõeldud sisu</translation>
<translation id="9078964945751709336">Vaja on rohkem teavet</translation>
+<translation id="9080712759204168376">Tellimuse kokkuvõte</translation>
<translation id="9103872766612412690">Sait <ph name="SITE" /> kasutab teie teabe kaitsmiseks tavaliselt krüpteerimist. Kui Chromium püüdis seekord saidiga <ph name="SITE" /> ühendust luua, tagastas veebisait ebatavalised ja valed mandaadid. See võib juhtuda siis, kui ründaja proovib teeselda, et on sait <ph name="SITE" />, või WiFi sisselogimisekraan on ühenduse katkestanud. Teie teave on endiselt kaitstud, sest Chromium peatas ühenduse enne andmevahetust.</translation>
+<translation id="9106062320799175032">Arveldusaadressi lisamine</translation>
+<translation id="910908805481542201">Aita mul seda parandada</translation>
+<translation id="9128870381267983090">Ühendumine Internetiga</translation>
<translation id="9137013805542155359">Kuva originaal</translation>
<translation id="9137248913990643158">Enne selle rakenduse kasutamist alustage ja logige Chrome'i sisse.</translation>
<translation id="9148507642005240123">&amp;Võta muudatus tagasi</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">Host <ph name="HOST_NAME" /> kasutab toetamata protokolli.</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="9215416866750762878">Rakendus ei luba Chrome'il selle saidiga ohutult ühendust luua</translation>
<translation id="9219103736887031265">Pildid</translation>
<translation id="933612690413056017">Interneti-ühendus puudub</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ühtegi}=1{1 üksus}other{# üksust}}</translation>
<translation id="981121421437150478">Võrguühenduseta</translation>
<translation id="988159990683914416">Arendaja järk</translation>
+<translation id="989988560359834682">Aadressi muutmine</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Tarkvara „<ph name="SOFTWARE_NAME" />” ei installitud teie arvutisse või võrku korralikult.
+ &lt;ul&gt;
+ &lt;li&gt;Proovige tarkvara „<ph name="SOFTWARE_NAME" />” desinstallida või keelata&lt;/li&gt;
+ &lt;li&gt;Proovige luua ühendus mõne teise võrguga&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index d0b5a95e6de..f5507206fae 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">نشانک‌های دسک‌تاپ</translation>
<translation id="1074497978438210769">امن نیست</translation>
<translation id="1080116354587839789">متناسب با پهنا</translation>
+<translation id="1088860948719068836">افزودن نام روی کارت</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> همیشه ترجمه شود</translation>
+<translation id="1103778128462718200">نمایش همه گذرواژه‌های ذخیره‌شده…</translation>
<translation id="1107591249535594099">‏اگر علامت زده شود، Chrome یک کپی از این کارت را در دستگاه نگهداری می‌کند تا برای پرکردن فرم‌ها از آن استفاده شود.</translation>
<translation id="1111153019813902504">نشانک‌های اخیر</translation>
<translation id="1113869188872983271">&amp;واگرد ترتیب‌بندی مجدد</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />، <ph name="TYPE_2" /> (همگام‌سازی‌شده)</translation>
<translation id="1263231323834454256">فهرست خواندن</translation>
<translation id="1264126396475825575">گزارش خرابی ثبت‌شده در <ph name="CRASH_TIME" /> (هنوز بارگذاری نشده است یا نادیده‌ گرفته شده است)</translation>
+<translation id="1270502636509132238">روش تحویل گرفتن</translation>
<translation id="1281526147609854549">صادرشده توسط <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">این سایت هرگز ترجمه نشود</translation>
<translation id="129553762522093515">اخیراً بسته‌شده</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">درانتظار برقراری اتصال…‏</translation>
<translation id="153384715582417236">درحال‌حاضر مورد دیگری وجود ندارد</translation>
<translation id="1549470594296187301">برای استفاده از این قابلیت، جاوا اسکریپت باید فعال باشد.</translation>
-<translation id="1555130319947370107">آبی</translation>
<translation id="1559528461873125649">فاقد چنین فایل یا دایرکتوری است</translation>
<translation id="1583429793053364125">هنگام نمایش این صفحه وب مشکلی پیش آمد.</translation>
<translation id="1592005682883173041">دسترسی داده محلی</translation>
<translation id="1594030484168838125">انتخاب</translation>
-<translation id="161042844686301425">فیروزه‌ای</translation>
<translation id="1620510694547887537">دوربین</translation>
<translation id="1629803312968146339">‏می‌خواهید Chrome این کارت را ذخیره کند؟</translation>
<translation id="1639239467298939599">بارگیری</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">برای بازدید این سایت باید از <ph name="NAME" /> اجازه بگیرید</translation>
<translation id="1721424275792716183">* این فیلد اجباری است</translation>
+<translation id="1727741090716970331">افزودن شماره کارت معتبر</translation>
<translation id="1728677426644403582">درحال مشاهده منبع یک صفحه وب هستید</translation>
<translation id="173080396488393970">این نوع کارت پشتیبانی نمی‌شود</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">خطای ترتیب</translation>
<translation id="1974060860693918893">پیشرفته</translation>
<translation id="1978555033938440688">نسخه میان‌افزار</translation>
-<translation id="1995859865337580572">‏لطفاً CVC خود را تأیید کنید</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{و ۱ برنامه دیگر}one{و # برنامه دیگر}other{و # برنامه دیگر}}</translation>
<translation id="2025186561304664664">پروکسی بر روی پیکربندی خودکار تنظیم شده است.</translation>
<translation id="2030481566774242610">منظورتان <ph name="LINK" /> بود؟</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">لغو</translation>
<translation id="20817612488360358">تنظیمات پروکسی سیستم تنظیم شده تا مورد استفاده قرار گیرد، اما یک پیکربندی مشخص برای پروکسی نیز تعیین شده است.</translation>
<translation id="2086652334978798447">‏برای دریافت محتوای شخصی‌سازی‌شده پیشنهادی Google، به Chrome وارد شوید.</translation>
+<translation id="2091887806945687916">صدا</translation>
<translation id="2094505752054353250">عدم تطابق دامنه</translation>
<translation id="2096368010154057602">حوزه</translation>
<translation id="2108755909498034140">رایانه را راه‌اندازی مجدد کنید</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">نادیده گرفته شد زیرا <ph name="POLICY_NAME" /> آن را لغو می‌کند.</translation>
<translation id="2138201775715568214">در حال جستجوی صفحات وب فیزیکی اطراف</translation>
<translation id="213826338245044447">نشانک‌های تلفن‌ همراه</translation>
+<translation id="214556005048008348">لغو پرداخت</translation>
<translation id="2147827593068025794">همگام‌سازی پس‌زمینه</translation>
+<translation id="2148613324460538318">افزودن کارت</translation>
<translation id="2154054054215849342">همگام‌سازی برای دامنه شما در دسترس نیست</translation>
<translation id="2154484045852737596">ویرایش کارت</translation>
<translation id="2166049586286450108">دسترسی کامل سرپرست</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{۱ نشانی}one{# نشانی}other{# نشانی}}</translation>
<translation id="2187317261103489799">تشخیص (پیش‌فرض)</translation>
<translation id="2202020181578195191">سال انقضای معتبری وارد کنید</translation>
+<translation id="2209523182407020534">برنامه‌هایی که می‌توانند موجب بروز این خطا شوند شامل ضدویروس‌ها، دیوار آتش و نرم‌افزار پراکسی و فیلتر کردن وب هستند.</translation>
<translation id="2212735316055980242">خط‌مشی یافت نشد</translation>
<translation id="2213606439339815911">در حال واکشی موارد...</translation>
<translation id="2218879909401188352">درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> می‌توانند برنامه‌های خطرناکی نصب کنند که به دستگاهتان آسیب می‌زنند، هزینه‌های پنهانی به صورت‌حساب دستگاه همراهتان اضافه می‌کنند یا اطلاعات شخصی‌تان را سرقت می‌کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">بازگشت</translation>
<translation id="2503184589641749290">کارت‌های نقدی و پیش‌پرداخت قابل‌قبول</translation>
<translation id="2515629240566999685">بررسی سیگنال در منطقه‌تان</translation>
+<translation id="2524461107774643265">افزودن اطلاعات بیشتر</translation>
+<translation id="2536110899380797252">افزودن نشانی</translation>
<translation id="2539524384386349900">تشخیص</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> پاسخی نامعتبر ارسال کرد.</translation>
<translation id="2556876185419854533">&amp;واگرد ویرایش</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">‏Chromium درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطفاً بعداً دوباره امتحان کنید.</translation>
<translation id="2705137772291741111">کپی ذخیره‌شده (ذخیره موقت‌شده) این سایت قابل خواندن نبود.</translation>
<translation id="2709516037105925701">تکمیل خودکار</translation>
+<translation id="2710942282213947212">‏نرم‌افزاری در رایانه‌تان مانع از اتصال ایمن Chromium به وب می‌شود</translation>
<translation id="2712173769900027643">درخواست اجازه</translation>
-<translation id="2713444072780614174">سفید</translation>
<translation id="2720342946869265578">اطراف</translation>
<translation id="2721148159707890343">درخواست با موفقیت انجام شد</translation>
<translation id="2728127805433021124">گواهی سرور با استفاده از یک الگوریتم امضای ضعیف امضا شده است.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">تغییر شبکه تشخیص داده شد.</translation>
<translation id="2916038427272391327">برنامه‌های دیگر را ببندید</translation>
<translation id="2922350208395188000">گواهی سرور بررسی نمی‌شود.</translation>
+<translation id="2925673989565098301">روش ارسال</translation>
<translation id="2928905813689894207">نشانی صورت‌حساب</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> نشانی دیگر}}</translation>
<translation id="2941952326391522266">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن از <ph name="DOMAIN2" /> است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">نوع خط‌مشی اشتباه است</translation>
<translation id="3032412215588512954">می‌خواهید این سایت را تازه‌سازی کنید؟</translation>
<translation id="3037605927509011580">اوه، نه!</translation>
+<translation id="3039538478787849737">‏کارت در Google ذخیره شود؟</translation>
<translation id="3041612393474885105">اطلاعات گواهی</translation>
<translation id="3063697135517575841">‏Chrome درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطفاً بعداً دوباره امتحان کنید.</translation>
<translation id="3064966200440839136">درحال خروج از حالت ناشناس، برای پرداخت ازطریق یک برنامه خارجی. ادامه می‌دهید؟</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">خطای موقت سرور</translation>
<translation id="3154506275960390542">این صفحه حاوی فرمی است که ممکن است به‌طور ایمن ارسال نشود. دیگران می‌توانند داده‌هایی را که ارسال می‌کنید درحین انتقال ببینند یا مهاجمان می‌توانند برای تغییر آنچه سرور دریافت می‌کند، آن‌ها را تغییر دهند.</translation>
<translation id="3157931365184549694">بازیابی</translation>
+<translation id="3162559335345991374">‏شبکه Wi-Fi مورد استفاده‌تان احتمالاً نیاز دارد که به یک صفحه ورود به سیستم بروید.</translation>
<translation id="3167968892399408617">صفحه‌هایی که در برگه‌های حالت ناشناس مرور می‌کنید، بعد از بستن همه برگه‌های حالت ناشناس در سابقه مرورگر، فضای ذخیره کوکی یا سابقه جستجو باقی نمی‌مانند. فایل‌هایی که بارگیری می‌کنید یا نشانک‌هایی که ایجاد می‌کنید حفظ می‌شود.</translation>
<translation id="3169472444629675720">کشف کردن</translation>
<translation id="3174168572213147020">جزیره</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">لغو پرداخت</translation>
<translation id="3207960819495026254">نشانک‌گذاری شده</translation>
+<translation id="3211223744486044430">‏برای اینکه دفعه بعد سریع‌تر پرداخت کنید، این کارت را در حساب Google و این دستگاه ذخیره کنید.</translation>
<translation id="3225919329040284222">سرور گواهی را نشان می‌دهد که با موارد پیش‌بینی‌شده داخلی مطابقت ندارد. این پیش‌بینی‌ها به‌طور حتم وب‌سایتهای دارای امنیت بالا را جهت محافظت از شما در بر می‌گیرند.</translation>
<translation id="3226128629678568754">دکمه تازه‌سازی را فشار دهید تا داده‌های مورد نیاز برای بارگیری صفحه مجدداً ارسال شود.</translation>
<translation id="3227137524299004712">میکروفن</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">هیچ نتیجه‌ای برای جستجو یافت نشد</translation>
<translation id="3305707030755673451">داده‌های شما در تاریخ <ph name="TIME" /> با عبارت عبور همگام‌سازی‌تان رمزگذاری شد. برای شروع همگام‌سازی آن را وارد کنید.</translation>
<translation id="3320021301628644560">افزودن نشانی صورتحساب</translation>
-<translation id="3329013043687509092">اشباع رنگ</translation>
<translation id="333371639341676808">از ایجاد کادرهای گفتگوی دیگر توسط این صفحه جلوگیری شود.</translation>
<translation id="3338095232262050444">ایمن</translation>
<translation id="3340978935015468852">تنظیمات</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">شناسه سرویس‌گیرنده:</translation>
<translation id="3391030046425686457">نشانی ارسال</translation>
<translation id="3395827396354264108">روش تحویل گرفتن</translation>
+<translation id="3399952811970034796">نشانی ارسال</translation>
<translation id="3422248202833853650">سعی کنید از برنامه‌های دیگر خارج شوید تا حافظه آزاد شود.</translation>
<translation id="3422472998109090673">دسترسی به <ph name="HOST_NAME" /> درحال حاضر امکان‌پذیر نیست.</translation>
<translation id="3427092606871434483">اجازه (پیش‌فرض)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">گزارش خرابی در <ph name="CRASH_TIME" /> ثبت شد، در <ph name="UPLOAD_TIME" /> بارگذاری شد</translation>
<translation id="3681007416295224113">اطلاعات گواهی</translation>
<translation id="3690164694835360974">ورود به سیستم امن نیست</translation>
+<translation id="3704162925118123524">شاید شبکه‌ای که استفاده می‌کنید، بازدید از صفحه ورود به سیستم خودش را برای شما ضروری کرده باشد.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> ‏<ph name="BOOKMARKED" /> ‏<ph name="TITLE" /> ‏<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">در حال بارکردن…</translation>
<translation id="3712624925041724820">مجوزها دیگر معتبر نیستند</translation>
<translation id="3714780639079136834">‏روشن کردن داده‌ شبکه تلفن همراه یا Wi-Fi</translation>
+<translation id="3715597595485130451">‏اتصال به Wi-Fi</translation>
<translation id="3717027428350673159">‏<ph name="BEGIN_LINK" />بررسی پروکسی، دیوار آتش و پیکربندی DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">اگر خطرات امنیتی که متوجه شما هستند را درک می‌کنید، می‌توانید قبل از حذف شدن برنامه‌های خطرناک از <ph name="BEGIN_LINK" />این سایت غیرایمن بازدید کنید<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">پیوندی که کپی کرده‌اید</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;واگرد افزودن</translation>
<translation id="404928562651467259">اخطار</translation>
<translation id="4058922952496707368">کلید "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">افزودن نشانی معتبر</translation>
<translation id="4072486802667267160">هنگام پردازش سفارش شما خطایی روی داد. لطفاً دوباره امتحان کنید.</translation>
<translation id="4075732493274867456">‏کلاینت و سرور از مجموعه رمزگذاری یا نسخه پروتکل SSL مشترکی استفاده نمی‌کنند.</translation>
<translation id="4079302484614802869">‏تنظیمات پروکسی، برای استفاده از آدرس اسکریپت pac. تنظیم شده است و از سرورهای ثابت نمی‌تواند استفاده کند.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">شماره سریال دستگاه نامعتبر است</translation>
<translation id="410351446219883937">پخش خودکار</translation>
<translation id="4103763322291513355">‏برای مشاهده فهرست نشانی‌های وب ممنوع و سایر خط‌مشی‌های اجباری براساس تصمیم سرپرست سیستم خود از &lt;strong&gt;chrome://policy&lt;/strong&gt; بازدید نمایید.</translation>
-<translation id="4115378294792113321">سرخابی</translation>
<translation id="4116663294526079822">همیشه مجاز در این سایت</translation>
<translation id="4117700440116928470">محدوده خط‌مشی پشتیبانی نمی‌شود.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{۱ مورد دیگر}one{# مورد دیگر}other{# مورد دیگر}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">شما سعی در دسترسی به <ph name="DOMAIN" /> را داشتید، اما صادر کننده، گواهی ارائه شده از سوی سرور را باطل کرده است. یعنی اصلاً نباید به اطلاعات کاربری که این سرور ارائه می‌کند اطمینان کرد. ممکن است شما با مهاجمی در ارتباط باشید.</translation>
<translation id="4394049700291259645">غیر فعال کردن</translation>
<translation id="4406896451731180161">نتایج جستجو</translation>
+<translation id="4415426530740016218">نشانی تحویل گرفتن</translation>
<translation id="4424024547088906515">‏این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد Chrome نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> گواهی ورود به سیستمتان را نپذیرفت یا ممکن است گواهی‌ای ارائه نشده باشد.</translation>
<translation id="443673843213245140">استفاده از پروکسی غیرفعال است اما یک پیکربندی خاص برای پروکسی تعیین شده است.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">افزونه‌ها را غیرفعال کنید.</translation>
<translation id="457875822857220463">ارسال</translation>
+<translation id="4582800630050655161">‏ممکن است دسترسی به حساب Google را از دست بدهید یا به سرقت هویت دچار شوید. Chromium توصیه می‌کند هم‌اکنون گذرواژه‌تان را تغییر دهید.</translation>
<translation id="4587425331216688090">‏آدرس از Chrome پاک شود؟</translation>
<translation id="4592951414987517459">اتصال شما به <ph name="DOMAIN" /> با استفاده از یک مجموعه رمز مدرن، رمزگذاری شده است.</translation>
<translation id="4594403342090139922">&amp;واگرد حذف</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">،</translation>
<translation id="467662567472608290">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن خطاهایی دارد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="4690462567478992370">توقف استفاده از گواهینامه نامعتبر</translation>
+<translation id="4690954380545377795">‏ممکن است دسترسی به حساب Google را از دست بدهید یا به سرقت هویت دچار شوید. Chrome توصیه می‌کند هم‌اکنون گذرواژه‌تان را تغییر دهید.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">اتصال شما قطع شد</translation>
<translation id="471880041731876836">برای بازدید کردن از این سایت، مجوز لازم ندارید</translation>
<translation id="4722547256916164131">‏<ph name="BEGIN_LINK" />در حال اجرای Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">پرداخت شما</translation>
<translation id="4726672564094551039">تازه‌سازی خط مشی‌ها</translation>
<translation id="4728558894243024398">پلت فورم</translation>
<translation id="4736825316280949806">‏Chromium را راه‌اندازی مجدد کنید</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">پشتیبان‌گیری ذخیره در وضعیت نادرست است</translation>
<translation id="5023310440958281426">خط‌مشی‌های سرپرست سیستمتان را بررسی کنید</translation>
<translation id="5029568752722684782">پاک کردن نسخه کپی</translation>
+<translation id="503069730517007720">برای «<ph name="SOFTWARE_NAME" />» گواهینامه ریشه‌ لازم است اما نصب نشده است. برای رفع این مشکل، سرپرست فناوری اطلاعات شما باید دستورالعمل‌های پیکربندی مربوط به «<ph name="SOFTWARE_NAME" />» را بررسی کند. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">‏درباره ‏‫مترجم Google‬</translation>
<translation id="5039804452771397117">اجازه دادن</translation>
<translation id="5040262127954254034">حریم خصوصی</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">آزمایشات</translation>
<translation id="5205222826937269299">نام ضروری است</translation>
<translation id="5222812217790122047">رایانامه ضروری است</translation>
+<translation id="522700295135997067">ممکن است این سایت اخیراً گذرواژه‌تان را سرقت کرده باشد</translation>
+<translation id="5230733896359313003">نشانی تحویل کالا</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">‏از Chrome در محل کار استفاده می‌کنید؟ کسب و کارها می‌توانند تنظیمات Chrome را برای کارمندانشان مدیریت کنند. بیشتر بدانید</translation>
<translation id="5281113152797308730">‏<ph name="BEGIN_PARAGRAPH" />با دنبال کردن این مراحل، نرم‌افزار را موقتاً غیرفعال کنید تا بتوانید به وب دسترسی داشته باشید. انجام این مراحل به امتیازهای سرپرستی نیاز دارد.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">‏اتصال شما به این سایت خصوصی نیست. درهرزمانی برای خروج از حالت VR، هدست را جدا کنید و «برگشت» را فشار دهید.</translation>
<translation id="5299298092464848405">خطا در تجزیه خط‌‌مشی</translation>
+<translation id="5308380583665731573">اتصال</translation>
<translation id="5308689395849655368">گزارش خرابی غیر فعال است.</translation>
<translation id="5317780077021120954">ذخیره</translation>
<translation id="5327248766486351172">نام</translation>
+<translation id="5332219387342487447">روش ارسال کالا</translation>
<translation id="5355557959165512791">درحال‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا گواهینامه آن لغو شده است. معمولاً خطاهای شبکه و حمله‌ها موقتی هستند، بنابراین احتمالاً این صفحه بعداً کار خواهد کرد.</translation>
<translation id="536296301121032821">تنظیمات خط‌‌مشی ذخیره نشد</translation>
<translation id="5386426401304769735">‏زنجیره گواهی این سایت حاوی یک گواهی با امضای SHA-1 است.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">نشانی وب این سایت در اینترانت شرکت، سازمان یا محل تحصیل با نشانی وب یک وب‌سایت خارجی یکسان است.
<ph name="LINE_BREAK" />
با سرپرست سیستم تماس بگیرید.</translation>
+<translation id="5499929369096410817">کد امنیتی <ph name="CREDIT_CARD" /> را وارد کنید. این کد ذخیره نمی‌شود.</translation>
<translation id="5509780412636533143">نشانک‌های مدیریت شده</translation>
<translation id="5510766032865166053">ممکن است جابه‌جا یا حذف شده باشد.</translation>
<translation id="5523118979700054094">نام خط‌مشی</translation>
<translation id="552553974213252141">آیا نوشتار به درستی استخراج شده است؟</translation>
<translation id="5540224163453853">مقاله درخواستی یافت نشد.</translation>
+<translation id="5541546772353173584">افزودن رایانامه</translation>
<translation id="5544037170328430102">صفحه جاسازی‌شده‌ای در <ph name="SITE" /> می‌گوید:</translation>
+<translation id="5545756402275714221">مقاله‌هایی برای شما</translation>
<translation id="5556459405103347317">تازه‌سازی</translation>
<translation id="5560088892362098740">تاریخ انقضا</translation>
<translation id="5565735124758917034">فعال</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">رایانامه</translation>
<translation id="5669703222995421982">دریافت محتوای شخصی‌سازی‌شده</translation>
<translation id="5675650730144413517">این صفحه کار نمی‌کند</translation>
+<translation id="5689199277474810259">‏صادر کردن به JSON</translation>
<translation id="5710435578057952990">هویت این وب سایت تأیید نشده است.</translation>
<translation id="5719499550583120431">کارت‌های پیش‌پرداخت پذیرفته می‌شوند.</translation>
<translation id="5720705177508910913">کاربر کنونی</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">اتصال شما به <ph name="DOMAIN" /> با استفاده از یک مجموعه رمز منسوخ، رمزگذاری شده است.</translation>
<translation id="5813119285467412249">&amp;انجام مجدد افزودن</translation>
<translation id="5838278095973806738">نباید هیچ اطلاعات حساسی (مثل گذرواژه یا کارت اعتباری) را در این سایت وارد کنید، زیرا ممکن است مهاجمین آن‌ها را سرقت کنند.</translation>
+<translation id="5866257070973731571">افزودن شماره تلفن</translation>
<translation id="5869405914158311789">دسترسی به این سایت امکان‌پذیر نیست</translation>
<translation id="5869522115854928033">گذرواژه‌های ذخیره‌شده</translation>
<translation id="5872918882028971132">پیشنهادات والدین</translation>
<translation id="5893752035575986141">کارت‌های اعتباری پذیرفته می‌شوند.</translation>
-<translation id="5901630391730855834">زرد</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (همگام‌سازی‌شده)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{۱ کوکی درحال استفاده}one{# کوکی درحال استفاده}other{# کوکی درحال استفاده}}</translation>
<translation id="5959728338436674663">‏ارسال خودکار برخی از <ph name="BEGIN_WHITEPAPER_LINK" />اطلاعات سیستم و محتوای صفحه<ph name="END_WHITEPAPER_LINK" /> به Google برای کمک به شناسایی برنامه‌ها و سایت‌های خطرناک. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">ویرایش اطلاعات تماس</translation>
<translation id="5967867314010545767">حذف از سابقه</translation>
<translation id="5975083100439434680">کوچک نمایی</translation>
+<translation id="597552863672748783">تأیید کد امنیتی</translation>
<translation id="598637245381783098">برنامه پرداخت باز نشد</translation>
<translation id="5989320800837274978">‏سرور پروکسی ثابت و URL اسکریپت pac. تعیین نشده‌اند.</translation>
<translation id="5990559369517809815">درخواست‌های ارسالی به سرور توسط یک برنامهٔ افزودنی مسدود شد.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{صفحه ۱}one{صفحه #}other{صفحه #}}</translation>
-<translation id="6017514345406065928">سبز</translation>
<translation id="6017850046339264347">مهاجم‌ها در <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="6025416945513303461"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /> (همگام‌سازی‌شده)</translation>
<translation id="6027201098523975773">نامی وارد کنید</translation>
<translation id="6040143037577758943">بستن</translation>
-<translation id="6042308850641462728">بیشتر</translation>
<translation id="6047233362582046994">اگر خطری را که امنیتتان را تهدید می‌کند درک می‌کنید، می‌توانید قبل از حذف برنامه‌های مضر، <ph name="BEGIN_LINK" />از این سایت بازدید کنید<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">شاید محتوای این صفحه تلاش کند شما را فریب دهد تا نرم‌افزاری نصب کنید یا اطلاعات شخصی را افشا سازید. <ph name="BEGIN_LINK" />درهرصورت نمایش داده شود<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">درحال‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا وب‌سایت از پین کردن گواهینامه استفاده می‌کند. خطاهای شبکه و حمله‌ها موقتی هستند، بنابراین احتمالاً این صفحه بعداً کار خواهد کرد.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">درحال مشاهده یک صفحه افزونه هستید</translation>
<translation id="6596325263575161958">گزینه‌های رمزگذاری</translation>
<translation id="662080504995468778">ماندن</translation>
+<translation id="6624427990725312378">اطلاعات تماس</translation>
<translation id="6626291197371920147">افزودن شماره کارت معتبر</translation>
<translation id="6628463337424475685">جستجوی <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">‏شاید درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> در تلاش باشند برنامه‌های خطرناکی در Mac شما نصب کنند که اطلاعاتتان (مانند عکس‌ها، گذرواژه‌ها، پیام‌ها و کارت‌های اعتباری) را به سرقت می‌برند یا حذف می‌کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">قبلی</translation>
<translation id="6710594484020273272">&lt;عبارت جستجو را تایپ کنید&gt;</translation>
<translation id="6711464428925977395">مشکلی در سرور پروکسی وجود دارد یا این آدرس درست نیست.</translation>
-<translation id="6727102863431372879">تنظیم</translation>
<translation id="674375294223700098">خطای ناشناس گواهی سرور.</translation>
<translation id="6753269504797312559">مقدار خط‌‌مشی</translation>
<translation id="6757797048963528358">دستگاهتان به خواب رفته است.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">نشانی وب</translation>
<translation id="7419106976560586862">مسیر نمایه</translation>
<translation id="7424977062513257142">صفحه جاسازی‌شده‌ای در این صفحه وب می‌گوید:</translation>
+<translation id="7437289804838430631">افرودن اطلاعات تماس</translation>
<translation id="7441627299479586546">موضوع خط‌مشی اشتباه است</translation>
<translation id="7444046173054089907">این سایت مسدود شده است</translation>
<translation id="7445762425076701745">هویت سروری که به آن متصل شده‌اید به‌طور کامل راستی‌آزمایی نمی‌شود. با استفاده از نامی به سرور متصل شده‌اید که فقط در شبکه شما معتبر است و ارائه دهنده مجوز خارجی قادر به راستی‌آزمایی مالکیت آن نیست. به دلیل آنکه برخی از ارائه دهندگان مجوز بدون توجه به هر موردی، مجوزهایی را برای این نام‌ها ارائه می‌کنند، روشی برای اطمینان از این امر وجود ندارد که آیا شما به سایت مورد نظر خود متصل شده‌اید یا یک سایت مضر.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">ارسال کردن</translation>
<translation id="7485870689360869515">هیچ داده‌ای یافت نشد.</translation>
<translation id="7508255263130623398">شناسه دستگاه خط‌مشی برگردانده‌شده خالی است یا با شناسه کنونی دستگاه مطابقت ندارد</translation>
+<translation id="7511955381719512146">‏شبکه Wi-Fi مورد استفاده‌تان احتمالاً نیاز دارد که به صفحه <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> بروید.</translation>
<translation id="7514365320538308">بارگیری</translation>
<translation id="7518003948725431193">صفحه وبی با این آدرس وب یافت نشد: <ph name="URL" /></translation>
<translation id="7521387064766892559">جاوا اسکریپت</translation>
<translation id="7526934274050461096">اتصال شما به این سایت خصوصی نیست</translation>
-<translation id="7535087603100972091">مقدار</translation>
<translation id="7537536606612762813">اجباری</translation>
<translation id="7542403920425041731">بعد از تأیید شما، جزئیات کارتتان با این سایت به اشتراک گذاشته می‌شود.</translation>
<translation id="7542995811387359312">تکمیل خودکار کارت اعتباری غیر فعال است زیرا این فرم از یک اتصال امن استفاده نمی‌کند.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ ممکن است گواهی امنیتی آن به صورت تقلبی صادر شده باشد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="7568593326407688803">این صفحه به <ph name="ORIGINAL_LANGUAGE" /> است، آیا مایلید ترجمه شود؟</translation>
<translation id="7569952961197462199">‏کارت اعتباری از Chrome پاک شود؟</translation>
-<translation id="7569983096843329377">سیاه</translation>
<translation id="7578104083680115302">‏با استفاده از کارت‌هایی که با Google ذخیره کرده‌اید به‌سرعت در همه دستگاه‌هایتان پرداخت‌های سایت‌ها و برنامه‌ها را انجام دهید.</translation>
<translation id="7588950540487816470">وب فیزیکی</translation>
<translation id="7592362899630581445">گواهی سرور محدودیت‌های نام را نقض می‌کند.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">مهاجمان در این سایت ممکن است تلاش کنند شما را با نصب برنامه‌هایی که به تجربه مرور شما آسیب می‌رساند، فریب دهند (مثلاً با تغییر دادن صفحه اصلی شما یا با نشان دادن آگهی‌های بیش از حد در سایت‌هایی که بازدید می‌کنید).</translation>
<translation id="7674629440242451245">‏علاقه‌مند به قابلیت‌های جدید و جالب Chrome هستید؟ کانال برنامه‌نویسان ما را در chrome.com/dev امتحان کنید.</translation>
<translation id="7682287625158474539">ارسال</translation>
+<translation id="7699293099605015246">مقاله‌ها درحال‌حاضر دردسترس نیستند</translation>
<translation id="7701040980221191251">هیچ کدام</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ادامه به <ph name="SITE" /> (غیرایمن)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">گواهی</translation>
<translation id="7716147886133743102">توسط سرپرست مسدود شده است</translation>
<translation id="7716424297397655342">این سایت نمی‌تواند از حافظه پنهان بار شود</translation>
+<translation id="7723047071702270851">ویرایش کارت</translation>
<translation id="774634243536837715">محتوای خطرناک مسدود شد.</translation>
<translation id="7752995774971033316">مدیریت نشده</translation>
<translation id="7755287808199759310">والدینتان می‌توانند این سایت را برای شما بگشایند</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">افزودن آدرس</translation>
<translation id="777702478322588152">حوزه اداری</translation>
<translation id="7791543448312431591">افزودن</translation>
+<translation id="7793553086574152071">‏برای اینکه دفعه بعد سریع‌تر پرداخت کنید، این کارت را در حساب Google ذخیره کنید.</translation>
<translation id="7793809570500803535">ممکن است صفحهٔ وب در <ph name="SITE" /> موقتاً خراب باشد یا ممکن است برای همیشه به یک آدرس وب جدید منتقل شده باشد.</translation>
<translation id="7800304661137206267">اتصال با استفاده از <ph name="CIPHER" /> و با <ph name="MAC" /> برای راستی‌آزمایی پیام و <ph name="KX" /> به‌عنوان مکانیسم تبدیل کلید رمزگذاری می‌شود.</translation>
+<translation id="7802523362929240268">سایت مجاز است</translation>
<translation id="780301667611848630">نه متشکرم</translation>
<translation id="7805768142964895445">وضعیت</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">‏پیشنهاد فرم از Chrome پاک شود؟</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="785549533363645510">اما، شما نامرئی نیستید. با استفاده از حالت ناشناس، مرورتان از چشمان کارفرمای شما، ارائه‌دهنده خدمات اینترنت یا وب‌‌سایت‌هایی که بازدید می‌کنید پنهان نمی‌ماند.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">کارت‌های نقدی و پیش‌پرداخت پذیرفته می‌شوند.</translation>
+<translation id="7878562273885520351">ممکن است گذرواژه‌تان درمعرض خطر باشد</translation>
<translation id="7887683347370398519">‏CVC را بررسی کرده و دوباره امتحان کنید</translation>
<translation id="79338296614623784">شماره تلفن معتبری وارد کنید</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">گواهی سرور هنوز معتبر نیست.</translation>
-<translation id="7942349550061667556">قرمز</translation>
<translation id="7947285636476623132">سال انقضا را بررسی و دوباره امتحان کنید</translation>
<translation id="7951415247503192394">(۳۲ بیت)</translation>
<translation id="7956713633345437162">نشانک‌های تلفن‌ همراه</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">درخواست (پیش‌فرض)</translation>
<translation id="8041089156583427627">ارسال بازخورد</translation>
<translation id="8041940743680923270">استفاده از پیش‌فرض جهانی (سؤال شود)</translation>
+<translation id="8057711352706143257">«<ph name="SOFTWARE_NAME" />» درست پیکربندی نمی‌شود. معمولاً حذف‌ نصب «<ph name="SOFTWARE_NAME" />» مشکل را برطرف می‌کند. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">مشاهده مقاله ناموفق بود.</translation>
<translation id="8091372947890762290">فعال‌سازی در سرور در حالت تعلیق است</translation>
+<translation id="8094917007353911263">شبکه‌ای که از آن استفاده می‌کنید ممکن است از شما بخواهد که <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> را ببینید.</translation>
+<translation id="8103161714697287722">روش پرداخت</translation>
<translation id="8118489163946903409">روش پرداخت</translation>
+<translation id="8127301229239896662">«<ph name="SOFTWARE_NAME" />» به‌درستی در رایانه یا شبکه‌تان پیکربندی نشد. از سرپرست فناوری اطلاعات خود بخواهید این مشکل را حل کند.</translation>
<translation id="8131740175452115882">تأیید</translation>
<translation id="8134994873729925007">‏<ph name="BEGIN_ABBR" />نشانی DNS<ph name="END_ABBR" /> سرور <ph name="HOST_NAME" /> پیدا نشد.</translation>
<translation id="8149426793427495338">رایانه‌تان به خواب رفته است.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">اگر این موضوع را متوجه نمی‌شوید، با سرپرست شبکه‌تان تماس بگیرید.</translation>
<translation id="8293206222192510085">افزودن نشانک</translation>
<translation id="8294431847097064396">منبع</translation>
+<translation id="8298115750975731693">‏شبکه Wi-Fi (<ph name="WIFI_NAME" />) مورد استفاده‌تان احتمالاً نیاز دارد که به صفحه <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> بروید.</translation>
<translation id="8306404619377842860">برقراری اتصال خصوصی با <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ممکن نیست، زیرا تاریخ و زمان دستگاهتان (<ph name="DATE_AND_TIME" />) نادرست است. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">ترجمه انجام نشد چون مشکلی در اتصال به شبکه رخ داد.</translation>
<translation id="8332188693563227489">دسترسی به <ph name="HOST_NAME" /> رد شد</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">اخیراً بسته‌شده</translation>
<translation id="8874824191258364635">شماره کارت معتبری وارد کنید</translation>
<translation id="8876793034577346603">پیکربندی شبکه نتوانست تجزیه شود.</translation>
-<translation id="8889402386540077796">رنگ‌مایه</translation>
<translation id="8891727572606052622">حالت پروکسی نامعتبر است.</translation>
<translation id="889901481107108152">متأسفیم، این آزمایش بر روی دستگاه شما قابل انجام نیست.</translation>
<translation id="8903921497873541725">بزرگ‌نمایی</translation>
<translation id="8931333241327730545">‏می‌خواهید این کارت را در حساب Google خود ذخیره کنید؟</translation>
<translation id="8932102934695377596">ساعت شما عقب است</translation>
+<translation id="893332455753468063">افزودن نام</translation>
<translation id="8938939909778640821">کارت‌های اعتباری و پیش‌پرداخت قابل‌قبول</translation>
+<translation id="8957210676456822347">مجوز پورتال محدود</translation>
<translation id="8971063699422889582">گواهی سرور منقضی شده است.</translation>
-<translation id="8986494364107987395">‏ارسال خودکار آمار کاربرد و گزارش‌های خرابی به Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">سایت در پیش‌رو حاوی برنامه‌های خطرناک است</translation>
<translation id="8997023839087525404">سرور گواهی‌ای را ارائه کرده است که با استفاده از خط‌مشی شفافیت گواهینامه به‌صورت عمومی نشان داده نشده است. برای برخی گواهی‌ها این یک مسئله ضروری است تا از قابل اعتماد بودن آن‌ها و محافظت دربرابر مهاجمین اطمینان حاصل شود.</translation>
<translation id="9001074447101275817">پروکسی <ph name="DOMAIN" /> به نام کاربری و گذرواژه نیاز دارد.</translation>
<translation id="9005998258318286617">‏سند PDF بارگیری نشد.</translation>
+<translation id="9008201768610948239">نادیده گرفتن</translation>
<translation id="901974403500617787">پرچم‌هایی که در تمام سیستم اعمال می‌شوند فقط توسط مالک قابل تنظیم هستند: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">نشانی صورت‌حساب کارت لازم است</translation>
<translation id="9020542370529661692">این صفحه به <ph name="TARGET_LANGUAGE" /> ترجمه شده است</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">شما سعی کردید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور یک گواهی نامعتبر را نشان داد.</translation>
<translation id="9050666287014529139">عبارت عبور</translation>
<translation id="9065203028668620118">ویرایش</translation>
-<translation id="9068849894565669697">انتخاب رنگ</translation>
<translation id="9069693763241529744">توسط افزونه مسدود شده است</translation>
<translation id="9076283476770535406">این سایت ممکن است شامل محتوای مخصوص بزرگسالان باشد</translation>
<translation id="9078964945751709336">اطلاعات بیشتری نیاز است</translation>
+<translation id="9080712759204168376">خلاصه سفارش</translation>
<translation id="9103872766612412690">‏<ph name="SITE" /> معمولاً برای محافظت از اطلاعات شما از رمزگذاری استفاده می‌کند. اما این بار که Chromium تلاش کرد به <ph name="SITE" /> متصل شود، وب‌سایت اعتبارنامه‌ای نامعمول و نادرست را برگرداند. ممکن است مهاجمی در تلاش باشد خود را به‌جای <ph name="SITE" /> معرفی کند یا یک صفحه ورود به سیستم Wi-Fi در ارتباط اختلال ایجاد کرده باشد. اطلاعات شما همچنان ایمن است، زیرا Chromium قبل از هرگونه تبادل داده، اتصال را متوقف کرد.</translation>
+<translation id="9106062320799175032">افزودن نشانی صورت‌حساب</translation>
+<translation id="910908805481542201">برای برطرف کردن آن به من کمک کنید</translation>
+<translation id="9128870381267983090">اتصال به شبکه</translation>
<translation id="9137013805542155359">نمایش مورد اصلی</translation>
<translation id="9137248913990643158">‏لطفاً پیش از استفاده از این برنامه، Chrome را باز کنید و به سیستم آن وارد شوید.</translation>
<translation id="9148507642005240123">&amp;واگرد ویرایش</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> از یک پروتکل پشتیبانی‌نشده استفاده می‌کند.</translation>
<translation id="9205078245616868884">داده‌های شما با عبارت عبور همگام‌سازی رمزگذاری می‌شود. برای شروع همگام‌سازی آن را وارد کنید.</translation>
<translation id="9207861905230894330">افزودن مقاله ناموفق بود.</translation>
+<translation id="9215416866750762878">‏برنامه‌ای مانع از اتصال ایمن Chrome به این سایت می‌شود</translation>
<translation id="9219103736887031265">تصاویر</translation>
<translation id="933612690413056017">اتصال اینترنت قطع است</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{هیچ‌کدام}=1{۱ مورد}one{# مورد}other{# مورد}}</translation>
<translation id="981121421437150478">آفلاین</translation>
<translation id="988159990683914416">ساخت برنامه‌نویس</translation>
+<translation id="989988560359834682">ویرایش آدرس</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">‏«<ph name="SOFTWARE_NAME" />» به‌درستی در رایانه یا شبکه‌تان پیکربندی نشد:
+ &lt;ul&gt;
+ &lt;li&gt;«<ph name="SOFTWARE_NAME" />» را حذف‌نصب یا غیرفعال کنید&lt;/li&gt;
+ &lt;li&gt;به شبکه دیگری متصل شوید&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index 56a2cccadc8..b77cdd4674d 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Työpöytäkirjanmerkit</translation>
<translation id="1074497978438210769">Ei turvallinen</translation>
<translation id="1080116354587839789">Sovita leveyteen</translation>
+<translation id="1088860948719068836">Lisää kortissa oleva nimi</translation>
<translation id="1103523840287552314">Käännä <ph name="LANGUAGE" /> aina</translation>
+<translation id="1103778128462718200">Näytä kaikki tallennetut salasanat…</translation>
<translation id="1107591249535594099">Jos tämä ruutu on valittu, Chrome tallentaa kortin kopion tälle laitteelle, jotta lomakkeiden täyttö nopeutuu.</translation>
<translation id="1111153019813902504">Uusimmat kirjanmerkit</translation>
<translation id="1113869188872983271">K&amp;umoa uudelleenjärjestely</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synkronoitu)</translation>
<translation id="1263231323834454256">Lukulista</translation>
<translation id="1264126396475825575">Kaatumisraportti tallennettu <ph name="CRASH_TIME" /> (ei vielä lähetetty tai ohitettu)</translation>
+<translation id="1270502636509132238">Noutotapa</translation>
<translation id="1281526147609854549">Myöntäjä: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Älä käännä tätä sivustoa</translation>
<translation id="129553762522093515">Hiljattain suljetut välilehdet</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Odotetaan yhteyttä…</translation>
<translation id="153384715582417236">Siinä kaikki toistaiseksi</translation>
<translation id="1549470594296187301">Tämän ominaisuuden käyttö edellyttää JavaScriptiä.</translation>
-<translation id="1555130319947370107">Sininen</translation>
<translation id="1559528461873125649">Tiedostoa tai hakemistoa ei ole olemassa</translation>
<translation id="1583429793053364125">Jokin meni vikaan tätä verkkosivua näytettäessä.</translation>
<translation id="1592005682883173041">Tietojen paikallinen käyttö</translation>
<translation id="1594030484168838125">Valitse</translation>
-<translation id="161042844686301425">Turkoosi</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Haluatko, että Chrome tallentaa tämän kortin?</translation>
<translation id="1639239467298939599">Ladataan</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Käyttöjärjestelmä</translation>
<translation id="1721312023322545264">Tarvitset henkilön <ph name="NAME" /> luvan käydä tällä sivustolla</translation>
<translation id="1721424275792716183">* Kenttä on pakollinen.</translation>
+<translation id="1727741090716970331">Lisää kelvollinen kortin numero</translation>
<translation id="1728677426644403582">Tämä on verkkosivun lähdekoodi.</translation>
<translation id="173080396488393970">Tätä korttityyppiä ei tueta.</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Sarjaesittämisen virhe</translation>
<translation id="1974060860693918893">Lisäasetukset</translation>
<translation id="1978555033938440688">Laiteohjelmiston versio</translation>
-<translation id="1995859865337580572">Vahvista CVC.</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ja 1 muu}other{ja # muuta}}</translation>
<translation id="2025186561304664664">Välityspalvelimen asetus: automaattisesti määritetty.</translation>
<translation id="2030481566774242610">Tarkoititko: <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Kirjaudu Chromeen, niin voit lisätä Googlen suosittelemaa sisältöä.</translation>
+<translation id="2091887806945687916">Ääni</translation>
<translation id="2094505752054353250">Verkkotunnukset eivät ole yhteensopivat</translation>
<translation id="2096368010154057602">Osasto</translation>
<translation id="2108755909498034140">Käynnistä tietokone uudelleen.</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ei käytetä – käytännön <ph name="POLICY_NAME" /> ohittama.</translation>
<translation id="2138201775715568214">Etsitään lähistöllä olevia Fyysisen webin sivuja</translation>
<translation id="213826338245044447">Mobiilikirjanmerkit</translation>
+<translation id="214556005048008348">Peruuta maksu</translation>
<translation id="2147827593068025794">Taustasynkronointi</translation>
+<translation id="2148613324460538318">Lisää kortti</translation>
<translation id="2154054054215849342">Synkronointi ei ole käytettävissä verkkotunnuksessasi.</translation>
<translation id="2154484045852737596">Muokkaa korttia</translation>
<translation id="2166049586286450108">Järjestelmänvalvojan täydet käyttöoikeudet</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 osoite}other{# osoitetta}}</translation>
<translation id="2187317261103489799">Tunnista (oletus)</translation>
<translation id="2202020181578195191">Anna kelvollinen viimeinen voimassaolovuosi.</translation>
+<translation id="2209523182407020534">Tätä virhettä voivat aiheuttaa esimerkiksi virustorjuntaohjelmat, palomuurit ja verkon suodatus- tai välityspalvelinohjelmistot.</translation>
<translation id="2212735316055980242">Käytäntöä ei löydy</translation>
<translation id="2213606439339815911">Noudetaan merkintöjä…</translation>
<translation id="2218879909401188352">Sivustolla <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> tällä hetkellä olevat hyökkääjät voivat asentaa vaarallisia laitettasi vahingoittavia sovelluksia, lisätä piilomaksuja puhelinlaskuusi tai varastaa henkilökohtaisia tietojasi. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Takaisin</translation>
<translation id="2503184589641749290">Hyväksytyt maksu- ja prepaid-kortit</translation>
<translation id="2515629240566999685">Tarkista alueesi mobiilisignaali.</translation>
+<translation id="2524461107774643265">Lisää tietoja</translation>
+<translation id="2536110899380797252">Lisää osoite</translation>
<translation id="2539524384386349900">Tunnista</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> lähetti virheellisen vastauksen.</translation>
<translation id="2556876185419854533">K&amp;umoa muokkaus</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
<translation id="2705137772291741111">Tämän sivuston välimuistiin tallennettu kopio oli lukukelvoton.</translation>
<translation id="2709516037105925701">Automaattinen täyttö</translation>
+<translation id="2710942282213947212">Tietokoneelle asennettu ohjelmisto estää Chromiumia muodostamasta turvallista yhteyttä verkkoon</translation>
<translation id="2712173769900027643">Pyydä käyttölupaa</translation>
-<translation id="2713444072780614174">Valkoinen</translation>
<translation id="2720342946869265578">Nearby</translation>
<translation id="2721148159707890343">Pyyntö onnistui</translation>
<translation id="2728127805433021124">Palvelimen varmenne on allekirjoitettu heikolla allekirjoitusalgoritmilla.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Verkossa havaittiin muutos.</translation>
<translation id="2916038427272391327">Sulje muita ohjelmia.</translation>
<translation id="2922350208395188000">Palvelimen varmennetta ei voi tarkistaa.</translation>
+<translation id="2925673989565098301">Toimitustapa</translation>
<translation id="2928905813689894207">Laskutusosoite</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" /><ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{ ja <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> toinen}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> muuta}}</translation>
<translation id="2941952326391522266">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on verkkotunnuksesta <ph name="DOMAIN2" />. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Väärä käytäntötyyppi</translation>
<translation id="3032412215588512954">Haluatko päivittää tämän sivuston?</translation>
<translation id="3037605927509011580">Voi räkä!</translation>
+<translation id="3039538478787849737">Tallennetaanko kortti Googleen?</translation>
<translation id="3041612393474885105">Varmenteen tiedot</translation>
<translation id="3063697135517575841">Chrome ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
<translation id="3064966200440839136">Incognito-tilasta poistutaan ulkoisessa sovelluksessa maksamisen vuoksi. Haluatko jatkaa?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Tilapäinen palvelinvirhe</translation>
<translation id="3154506275960390542">Tällä sivulla on taulukko, jota ei ehkä voi lähettää turvallisesti. Muut voivat nähdä lähettämäsi tiedot siirron aikana tai hyökkääjä voi muuttaa niitä, ennen kuin ne saapuvat palvelimelle.</translation>
<translation id="3157931365184549694">Palauta</translation>
+<translation id="3162559335345991374">Käyttämäsi Wi-Fi saattaa edellyttää kirjautumista.</translation>
<translation id="3167968892399408617">Incognito-välilehdillä avattujen sivujen tietoja ei säilytetä selaimen historiassa, evästeissä tai hakuhistoriassa, kun kaikki incognito-välilehdet suljetaan. Ladatut tiedostot ja luodut kirjanmerkit säilytetään.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Saari</translation>
@@ -288,6 +298,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Peruuta maksu</translation>
<translation id="3207960819495026254">Kirjanmerkeissä</translation>
+<translation id="3211223744486044430">Jos haluat maksaa nopeammin seuraavalla kerralla, tallenna tämä kortti Google-tilillesi ja tälle laitteelle.</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>
<translation id="3226128629678568754">Paina päivityspainiketta, niin sivun lataukseen tarvittavat tiedot lähetetään uudelleen.</translation>
<translation id="3227137524299004712">Mikrofoni</translation>
@@ -302,7 +313,6 @@
<translation id="3303855915957856445">Ei hakutuloksia</translation>
<translation id="3305707030755673451">Tietosi salattiin synkronoinnin tunnuslauseesi avulla <ph name="TIME" />. Aloita synkronointi antamalla tunnuslause.</translation>
<translation id="3320021301628644560">Lisää laskutusosoite</translation>
-<translation id="3329013043687509092">Värikylläisyys</translation>
<translation id="333371639341676808">Estä tätä sivua luomasta muita viestejä.</translation>
<translation id="3338095232262050444">Turvallinen</translation>
<translation id="3340978935015468852">asetuksissa</translation>
@@ -321,6 +331,7 @@
<translation id="3380864720620200369">Asiakastunnus:</translation>
<translation id="3391030046425686457">Toimitusosoite</translation>
<translation id="3395827396354264108">Noutotapa</translation>
+<translation id="3399952811970034796">Toimitusosoite</translation>
<translation id="3422248202833853650">Yritä vapauttaa muistia sulkemalla muita ohjelmia.</translation>
<translation id="3422472998109090673">Sivustoon <ph name="HOST_NAME" /> ei saada tällä hetkellä yhteyttä.</translation>
<translation id="3427092606871434483">Salli (oletus)</translation>
@@ -366,10 +377,12 @@
<translation id="3679803492151881375">Kaatumisraportti tallennettu <ph name="CRASH_TIME" />, lähetetty <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Varmenteen tiedot</translation>
<translation id="3690164694835360974">Sisäänkirjautuminen ei ole turvallinen</translation>
+<translation id="3704162925118123524">Käyttämäsi verkko saattaa edellyttää kirjautumista.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Ladataan...</translation>
<translation id="3712624925041724820">Käyttöluvat ovat lopussa</translation>
<translation id="3714780639079136834">Ota mobiilidata tai Wi-Fi käyttöön.</translation>
+<translation id="3715597595485130451">Yhteyden muodostaminen Wi-Fi-verkkoon</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen, palomuurin ja nimipalvelun määritykset<ph name="END_LINK" />.</translation>
<translation id="3736520371357197498">Jos ymmärrät käyntiä koskevat turvallisuusriskit, voit <ph name="BEGIN_LINK" />siirtyä vaarantuneeseen sivustoon<ph name="END_LINK" /> jo ennen haitallisten ohjelmien poistamista.</translation>
<translation id="3739623965217189342">Kopioimasi linkki</translation>
@@ -404,6 +417,7 @@
<translation id="4030383055268325496">K&amp;umoa lisäys</translation>
<translation id="404928562651467259">Varoitus</translation>
<translation id="4058922952496707368">Avain <ph name="SUBKEY" />: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Välityspalvelinmääritykset on asetettu käyttämään .pac-URL-osoitteita, ei kiinteitä välityspalvelimia.</translation>
@@ -411,7 +425,6 @@
<translation id="4103249731201008433">Laitteen sarjanumero on virheellinen</translation>
<translation id="410351446219883937">Automaattinen toisto</translation>
<translation id="4103763322291513355">Voit lukea listan kielletyistä URL-osoitteista 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="4115378294792113321">Purppura</translation>
<translation id="4116663294526079822">Salli aina tässä sivustossa</translation>
<translation id="4117700440116928470">Käytännön laajuutta ei tueta.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 muu}other{# muuta}}</translation>
@@ -449,6 +462,7 @@
<translation id="4377125064752653719">Yritit yhdistää sivustoon <ph name="DOMAIN" />, mutta varmenteen myöntäjä on kumonnut palvelimen esittämän varmenteen. Palvelimen esittämiin suojaustietoihin ei siis tule luottaa. Saatat olla tekemisissä hakkerin kanssa.</translation>
<translation id="4394049700291259645">Poista käytöstä</translation>
<translation id="4406896451731180161">hakutulokset</translation>
+<translation id="4415426530740016218">Nouto-osoite</translation>
<translation id="4424024547088906515">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; Chrome ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ei hyväksynyt kirjautumisvarmennettasi, tai varmennetta ei annettu.</translation>
<translation id="443673843213245140">Välityspalvelinta ei saa käyttää, mutta erilliset välityspalvelimen asetukset on määritetty.</translation>
@@ -461,6 +475,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Poista laajennukset käytöstä.</translation>
<translation id="457875822857220463">Toimitus</translation>
+<translation id="4582800630050655161">Saatat menettää Google-tilisi käyttöoikeuden tai joutua identiteettivarkauden uhriksi. Chromium suosittelee vaihtamaan salasanan nyt.</translation>
<translation id="4587425331216688090">Poistetaanko osoite Chromen tiedoista?</translation>
<translation id="4592951414987517459">Yhteytesi kohteeseen <ph name="DOMAIN" /> on salattu nykyaikaisella salaustekniikalla.</translation>
<translation id="4594403342090139922">K&amp;umoa poisto</translation>
@@ -469,10 +484,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Lopeta virheellisten varmenteiden käyttö</translation>
+<translation id="4690954380545377795">Saatat menettää Google-tilisi käyttöoikeuden tai joutua identiteettivarkauden uhriksi. Chrome suosittelee vaihtamaan salasanan nyt.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Yhteys keskeytyi</translation>
<translation id="471880041731876836">Sinulla ei ole lupaa siirtyä tälle sivustolle.</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsin verkon diagnostiikkaa<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Maksu</translation>
<translation id="4726672564094551039">Päivitä käytännöt</translation>
<translation id="4728558894243024398">Käyttöympäristö</translation>
<translation id="4736825316280949806">Käynnistä Chromium uudelleen.</translation>
@@ -511,6 +528,7 @@
<translation id="5019198164206649151">Tallennustila on virheellisessä tilassa</translation>
<translation id="5023310440958281426">Tarkista järjestelmänvalvojan käytännöt</translation>
<translation id="5029568752722684782">Poista kopio</translation>
+<translation id="503069730517007720">Ohjelmiston <ph name="SOFTWARE_NAME" /> juurivarmennetta edellytetään, mutta sitä ei ole asennettu. IT-järjestelmänvalvojan on tutustuttava ohjelmiston <ph name="SOFTWARE_NAME" /> määritysohjeisiin, jotta hän voi korjata tämän ongelman. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Tietoja Google-kääntäjästä</translation>
<translation id="5039804452771397117">Salli</translation>
<translation id="5040262127954254034">Tietosuoja</translation>
@@ -534,6 +552,8 @@
<translation id="5199729219167945352">Kokeilut</translation>
<translation id="5205222826937269299">Nimi vaaditaan</translation>
<translation id="5222812217790122047">Sähköposti vaaditaan</translation>
+<translation id="522700295135997067">Tämä sivusto saattoi juuri varastaa salasanasi.</translation>
+<translation id="5230733896359313003">Toimitusosoite</translation>
<translation id="5251803541071282808">Pilvi</translation>
<translation id="5277279256032773186">Käytätkö Chromea töissä? Yritykset voivat hallita Chromen asetuksia työntekijöidensä puolesta. Lisätietoja</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Voit poistaa ohjelmiston väliaikaisesti käytöstä ja päästä verkkoon noudattamalla näitä ohjeita. Nämä vaiheet edellyttävät järjestelmänvalvojan käyttöoikeuksia.<ph name="END_PARAGRAPH" />
@@ -548,9 +568,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Yhteytesi tähän sivustoon ei ole yksityinen. Voit poistua VR-tilasta milloin tahansa ottamalla headsetin pois ja valitsemalla Takaisin.</translation>
<translation id="5299298092464848405">Virhe jäsennettäessä käytäntöä</translation>
+<translation id="5308380583665731573">Muodosta yhteys</translation>
<translation id="5308689395849655368">Kaatumisraportit on poistettu käytöstä.</translation>
<translation id="5317780077021120954">Tallenna</translation>
<translation id="5327248766486351172">Nimi</translation>
+<translation id="5332219387342487447">Toimitustapa</translation>
<translation id="5355557959165512791"><ph name="SITE" /> ei juuri nyt ole käytettävissä, koska sen varmenne ei ole voimassa. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="536296301121032821">Käytännön asetuksien tallentaminen epäonnistui</translation>
<translation id="5386426401304769735">Tämän sivuston varmenneketju sisältää varmenteen, joka on allekirjoitettu SHA-1:llä.</translation>
@@ -570,12 +592,15 @@
<translation id="5492298309214877701">Tällä yrityksen, organisaation tai oppilaitoksen intranetissä olevalla sivustolla on sama URL-osoite kuin ulkoisella verkkosivustolla.
<ph name="LINE_BREAK" />
Ota yhteyttä järjestelmänvalvojaasi.</translation>
+<translation id="5499929369096410817">Anna kortin <ph name="CREDIT_CARD" /> turvakoodi. Tätä koodia ei tallenneta.</translation>
<translation id="5509780412636533143">Hallinnoidut kirjanmerkit</translation>
<translation id="5510766032865166053">Se on voitu siirtää tai poistaa.</translation>
<translation id="5523118979700054094">Käytännön nimi</translation>
<translation id="552553974213252141">Noudettiinko teksti oikein?</translation>
<translation id="5540224163453853">Pyydettyä artikkelia ei löydy.</translation>
+<translation id="5541546772353173584">Lisää sähköposti</translation>
<translation id="5544037170328430102">Viesti upotetulta sivulta osoitteessa <ph name="SITE" />:</translation>
+<translation id="5545756402275714221">Sinulle valitut artikkelit</translation>
<translation id="5556459405103347317">Lataa uudelleen</translation>
<translation id="5560088892362098740">Viimeinen voimassaolopäivä</translation>
<translation id="5565735124758917034">Aktiivinen</translation>
@@ -597,6 +622,7 @@
<translation id="5659593005791499971">Sähköposti</translation>
<translation id="5669703222995421982">Hanki räätälöityä sisältöä</translation>
<translation id="5675650730144413517">Sivu ei toimi</translation>
+<translation id="5689199277474810259">Vie JSON-tiedostoon</translation>
<translation id="5710435578057952990">Tämän sivuston identiteettiä ei ole vahvistettu.</translation>
<translation id="5719499550583120431">Prepaid-kortit hyväksytään.</translation>
<translation id="5720705177508910913">Nykyinen käyttäjä</translation>
@@ -611,27 +637,27 @@
<translation id="5810442152076338065">Yhteytesi kohteeseen <ph name="DOMAIN" /> on salattu vanhentuneella salaustekniikalla.</translation>
<translation id="5813119285467412249">&amp;Toista lisäys</translation>
<translation id="5838278095973806738">Älä anna tälle sivustolle salasanoja, luottokorttinumeroita tai muita arkaluonteisia tietoja, sillä hyökkääjät saattavat varastaa ne.</translation>
+<translation id="5866257070973731571">Lisää puhelinnumero</translation>
<translation id="5869405914158311789">Sivustoon ei saada yhteyttä</translation>
<translation id="5869522115854928033">Tallennetut salasanat</translation>
<translation id="5872918882028971132">Ylätason ehdotukset</translation>
<translation id="5893752035575986141">Luottokortit hyväksytään.</translation>
-<translation id="5901630391730855834">Keltainen</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkronoitu)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 käytössä}other{# käytössä}}</translation>
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Lähetä automaattisesti<ph name="END_WHITEPAPER_LINK" /> joitain järjestelmän tietoja ja sivujen sisältöjä Googlelle auttaaksesi sitä havaitsemaan vaarallisia sovelluksia ja sivustoja. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Muokkaa yhteystietoja</translation>
<translation id="5967867314010545767">Poista historiasta</translation>
<translation id="5975083100439434680">Loitonna</translation>
+<translation id="597552863672748783">Vahvista turvakoodi</translation>
<translation id="598637245381783098">Maksusovelluksen avaaminen ei onnistu.</translation>
<translation id="5989320800837274978">Kiinteitä välityspalvelimia tai .pac-URL-osoitetta ei ole määritetty.</translation>
<translation id="5990559369517809815">Laajennus esti palvelinpyynnöt.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Sivu 1}other{Sivu #}}</translation>
-<translation id="6017514345406065928">Vihreä</translation>
<translation id="6017850046339264347">Sivuston <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökkääjät voivat asentaa harhaanjohtavia sovelluksia, jotka teeskentelevät olevansa jotain muuta tai keräävät tietoja, joiden avulla ne voivat seurata sinua. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synkronoitu)</translation>
<translation id="6027201098523975773">Kirjoita nimi</translation>
<translation id="6040143037577758943">Sulje</translation>
-<translation id="6042308850641462728">Lisää</translation>
<translation id="6047233362582046994">Jos ymmärrät käyntiä koskevat turvallisuusriskit, voit <ph name="BEGIN_LINK" />siirtyä tälle sivustolle<ph name="END_LINK" /> jo ennen haitallisten sovellusten poistamista.</translation>
<translation id="6047927260846328439">Tämä sisältö saattaa yrittää huijata sinua asentamaan ohjelmistoja tai paljastamaan henkilökohtaisia tietoja. <ph name="BEGIN_LINK" />Näytä silti<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> ei juuri nyt ole käytettävissä, koska se käyttää varmenteiden kiinnittämistä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
@@ -698,6 +724,7 @@
<translation id="6569060085658103619">Tämä on laajennussivu.</translation>
<translation id="6596325263575161958">Salausasetukset</translation>
<translation id="662080504995468778">Jää</translation>
+<translation id="6624427990725312378">Yhteystiedot</translation>
<translation id="6626291197371920147">Lisää kelvollinen kortin numero</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />-haku</translation>
<translation id="6630809736994426279">Sivustolle <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää asentaa Maciisi vaarallisia ohjelmia, jotka varastavat tai poistavat tietojasi, esimerkiksi kuvia, salasanoja, viestejä tai luottokorttitietoja. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -708,7 +735,6 @@
<translation id="6710213216561001401">Edellinen</translation>
<translation id="6710594484020273272">&lt;Anna hakukysely&gt;</translation>
<translation id="6711464428925977395">Välityspalvelimessa on jotain vikaa tai osoite on virheellinen.</translation>
-<translation id="6727102863431372879">Aseta</translation>
<translation id="674375294223700098">Tuntematon palvelimen varmennevirhe.</translation>
<translation id="6753269504797312559">Käytännön arvo</translation>
<translation id="6757797048963528358">Laitteesi siirtyi virransäästötilaan.</translation>
@@ -777,6 +803,7 @@
<translation id="7400418766976504921">URL-osoite</translation>
<translation id="7419106976560586862">Profiilin polku</translation>
<translation id="7424977062513257142">Viesti tälle verkkosivulle upotetulta sivulta:</translation>
+<translation id="7437289804838430631">Lisää yhteystieto</translation>
<translation id="7441627299479586546">Väärä käytännön aihe</translation>
<translation id="7444046173054089907">Tämä sivusto on estetty</translation>
<translation id="7445762425076701745">Palvelimen, johon olet muodostanut yhteyden, identiteettiä ei voi täysin todentaa. Tietokoneesi on yhdistetty palvelimeen sellaisen nimen avulla, joka on kelvollinen vain verkkosi sisällä ja jonka omistajaa ulkopuolinen varmenteen myöntäjä ei pysty todentamaan. Koska jotkin varmenteen myöntäjät kuitenkin myöntävät varmenteita tällaisille nimille, et voi varmistaa, että olet muodostanut yhteyden haluamaasi verkkosivustoon etkä hakkeriin.</translation>
@@ -787,11 +814,11 @@
<translation id="7481312909269577407">Seuraava</translation>
<translation id="7485870689360869515">Tietoja ei löydy.</translation>
<translation id="7508255263130623398">Palautettu käytännön laitetunnus on tyhjä tai ei vastaa nykyistä laitetunnusta.</translation>
+<translation id="7511955381719512146">Käyttämäsi Wi-Fi saattaa edellyttää vierailua osoitteessa <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Lataa</translation>
<translation id="7518003948725431193">Verkkosivua ei löytynyt osoitteelle: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Sivustoon muodostamasi yhteys ei ole yksityinen.</translation>
-<translation id="7535087603100972091">Arvo</translation>
<translation id="7537536606612762813">Pakollinen</translation>
<translation id="7542403920425041731">Vahvistamisen jälkeen korttisi tiedot jaetaan sivuston kanssa.</translation>
<translation id="7542995811387359312">Automaattinen luottokortin tietojen täyttäminen on poistettu käytöstä, koska tämä lomake ei käytä suojattua yhteyttä.</translation>
@@ -802,7 +829,6 @@
<translation id="7567204685887185387">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on ehkä luotu vilpillisesti. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="7568593326407688803">Tämä sivu on kirjoitettu kielellä<ph name="ORIGINAL_LANGUAGE" />Haluatko kääntää sen?</translation>
<translation id="7569952961197462199">Poistetaanko luottokortti Chromen tiedoista?</translation>
-<translation id="7569983096843329377">Musta</translation>
<translation id="7578104083680115302">Voit maksaa sivustoilla ja sovelluksissa nopeasti eri laitteillasi käyttämällä Googleen tallennettuja kortteja.</translation>
<translation id="7588950540487816470">Fyysinen web</translation>
<translation id="7592362899630581445">Palvelimen varmenne rikkoo nimirajoituksia.</translation>
@@ -821,11 +847,13 @@
<translation id="7669271284792375604">Tämän sivuston hyökkääjät saattavat yrittää huijata sinua asentamaan ohjelmia, jotka ovat haitallisia selauskokemuksellesi (esimerkiksi vaihtamalla aloitussivusi tai näyttämällä ylimääräisiä mainoksia käymilläsi sivustoilla).</translation>
<translation id="7674629440242451245">Oletko kiinnostunut Chromen uusista jännittävistä ominaisuuksista? Kokeile kehittäjäkanavaa osoitteessa chrome.com/dev.</translation>
<translation id="7682287625158474539">Toimitus</translation>
+<translation id="7699293099605015246">Artikkelit eivät juuri nyt ole saatavilla.</translation>
<translation id="7701040980221191251">Ei mitään</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Siirry sivustoon <ph name="SITE" /> (tämä ei ole turvallista)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Varmenne</translation>
<translation id="7716147886133743102">Järjestelmänvalvojan estämä</translation>
<translation id="7716424297397655342">Tätä sivustoa ei voi ladata välimuistista</translation>
+<translation id="7723047071702270851">Muokkaa korttia</translation>
<translation id="774634243536837715">Vaarallinen sisältö estetty</translation>
<translation id="7752995774971033316">Ei hallinnoida</translation>
<translation id="7755287808199759310">Vanhempasi voi kumota eston puolestasi.</translation>
@@ -836,21 +864,24 @@
<translation id="7764225426217299476">Lisää osoite</translation>
<translation id="777702478322588152">Prefektuuri</translation>
<translation id="7791543448312431591">Lisää</translation>
+<translation id="7793553086574152071">Jos haluat maksaa nopeammin seuraavalla kerralla, tallenna tämä kortti Google-tilillesi.</translation>
<translation id="7793809570500803535">Osoitteessa <ph name="SITE" /> oleva sivu saattaa olla väliaikaisesti pois käytöstä, tai se on voitu siirtää pysyvästi uuteen osoitteeseen.</translation>
<translation id="7800304661137206267">Tämä yhteys on salattu käyttäen algoritmia <ph name="CIPHER" />, viestit todennetaan menetelmällä <ph name="MAC" /> ja avainvaihtomekanismi on toteutettu menetelmällä <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Sivusto on luotettava</translation>
<translation id="780301667611848630">Ei kiitos</translation>
<translation id="7805768142964895445">Tila</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Poistetaanko lomake-ehdotus Chromen tiedoista?</translation>
<translation id="7815407501681723534">Haku <ph name="SEARCH_STRING" /> tuotti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
+<translation id="782886543891417279">Käyttämäsi Wi-Fi (<ph name="WIFI_NAME" />) saattaa edellyttää kirjautumista.</translation>
<translation id="785549533363645510">Et ole kuitenkaan näkymätön. Incognito-tilan käyttäminen ei kätke selaamistasi työnantajaltasi, internetpalveluntarjoajaltasi tai käyttämiltäsi sivustoilta.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Maksu- ja prepaid-kortit hyväksytään.</translation>
+<translation id="7878562273885520351">Salasanasi on saattanut vaarantua.</translation>
<translation id="7887683347370398519">Tarkista CVC ja yritä uudelleen.</translation>
<translation id="79338296614623784">Anna kelvollinen puhelinnumero.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Palvelimen varmenne ei ole vielä voimassa.</translation>
-<translation id="7942349550061667556">Punainen</translation>
<translation id="7947285636476623132">Tarkista vanhentumisvuosi ja yritä uudelleen.</translation>
<translation id="7951415247503192394">(32-bittinen)</translation>
<translation id="7956713633345437162">Mobiilikirjanmerkit</translation>
@@ -864,9 +895,13 @@
<translation id="8037357227543935929">Kysy (oletus)</translation>
<translation id="8041089156583427627">Lähetä palautetta</translation>
<translation id="8041940743680923270">Käytä yleistä oletusasetusta (kysy)</translation>
+<translation id="8057711352706143257"><ph name="SOFTWARE_NAME" /> on määritetty virheellisesti. Ongelma korjaantuu yleensä, jos <ph name="SOFTWARE_NAME" /> poistetaan. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Artikkelin näyttäminen epäonnistui.</translation>
<translation id="8091372947890762290">Aktivointi odottaa palvelimella</translation>
+<translation id="8094917007353911263">Käyttämäsi verkko saattaa edellyttää vierailua osoitteessa <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Maksutapa</translation>
<translation id="8118489163946903409">Maksutapa</translation>
+<translation id="8127301229239896662"><ph name="SOFTWARE_NAME" /> on asennettu virheellisesti tietokoneellesi tai verkkoon. Pyydä järjestelmänvalvojaasi ratkaisemaan ongelma.</translation>
<translation id="8131740175452115882">Vahvista</translation>
<translation id="8134994873729925007">Isäntänimen <ph name="HOST_NAME" /> palvelimen <ph name="BEGIN_ABBR" />DNS-osoitetta<ph name="END_ABBR" /> ei löytynyt.</translation>
<translation id="8149426793427495338">Tietokoneesi siirtyi virransäästötilaan.</translation>
@@ -889,6 +924,7 @@
<translation id="8289355894181816810">Ota yhteyttä verkon ylläpitäjään, jos et tiedä, mitä tämä tarkoittaa.</translation>
<translation id="8293206222192510085">Lisää kirjanmerkki</translation>
<translation id="8294431847097064396">Lähde</translation>
+<translation id="8298115750975731693">Käyttämäsi Wi-Fi (<ph name="WIFI_NAME" />) saattaa edellyttää vierailua osoitteessa <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Verkkotunnukseen <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei voi muodostaa salattua yhteyttä, koska tietokoneesi aika ja päivämäärä (<ph name="DATE_AND_TIME" />) ovat virheelliset. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Käännös epäonnistui, koska verkkoyhteydessä esiintyi ongelmia.</translation>
<translation id="8332188693563227489">Sivuston <ph name="HOST_NAME" /> käyttöoikeus evättiin</translation>
@@ -942,20 +978,21 @@
<translation id="8870413625673593573">Hiljattain suljetut</translation>
<translation id="8874824191258364635">Anna kelvollinen kortin numero.</translation>
<translation id="8876793034577346603">Verkkoasetuksia ei voitu jäsentää.</translation>
-<translation id="8889402386540077796">Sävy</translation>
<translation id="8891727572606052622">Virheellinen välityspalvelimen tila.</translation>
<translation id="889901481107108152">Tämä kokeilu ei ole käytettävissä käyttöympäristössäsi.</translation>
<translation id="8903921497873541725">Lähennä</translation>
<translation id="8931333241327730545">Haluatko tallentaa tämän kortin Google-tilillesi?</translation>
<translation id="8932102934695377596">Kellosi jätättää</translation>
+<translation id="893332455753468063">Lisää nimi</translation>
<translation id="8938939909778640821">Hyväksytyt luotto- ja prepaid-kortit</translation>
+<translation id="8957210676456822347">Captive portal -valtuutus</translation>
<translation id="8971063699422889582">Palvelimen varmenne on vanhentunut.</translation>
-<translation id="8986494364107987395">Lähetä Googlelle käyttötilastoja ja virheraportteja automaattisesti</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Sivusto sisältää haitallisia ohjelmia</translation>
<translation id="8997023839087525404">Palvelimen lähettämän varmenteen tietoja ei ole annettu yleiseen käyttöön Certificate Transparency ‑käytännön mukaisesti. Tietojen antamista edellytetään joiltakin varmenteilta, jotta niiden luotettavuus voidaan varmistaa ja käyttäjiä suojella hyökkääjiltä.</translation>
<translation id="9001074447101275817">Välityspalvelin <ph name="DOMAIN" /> vaatii käyttäjänimen ja salasanan.</translation>
<translation id="9005998258318286617">PDF-asiakirjan lataaminen epäonnistui.</translation>
+<translation id="9008201768610948239">Ohita</translation>
<translation id="901974403500617787">Koko järjestelmään vaikuttavat merkinnät voi tehdä vain omistaja: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Kortin laskutusosoite pakollinen</translation>
<translation id="9020542370529661692">Sivu on käännetty kielelle <ph name="TARGET_LANGUAGE" /></translation>
@@ -965,11 +1002,14 @@
<translation id="9049981332609050619">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti virheellisen varmenteen.</translation>
<translation id="9050666287014529139">Tunnuslause</translation>
<translation id="9065203028668620118">Muokkaa</translation>
-<translation id="9068849894565669697">Valitse väri</translation>
<translation id="9069693763241529744">Laajennuksen estämä</translation>
<translation id="9076283476770535406">Se saattaa sisältää vain aikuisille tarkoitettua sisältöä.</translation>
<translation id="9078964945751709336">Lisätietoja tarvitaan</translation>
+<translation id="9080712759204168376">Tilauksen yhteenveto</translation>
<translation id="9103872766612412690"><ph name="SITE" /> suojaa tietosi normaalisti salauksen avulla. Kun Chromium yritti tällä kertaa yhdistää sivustoon <ph name="SITE" />, sivusto palautti epätavalliset ja virheelliset kirjautumistiedot. Hyökkääjä saattaa yrittää esiintyä sivustona <ph name="SITE" />, tai Wi-Fi-kirjautumisruutu on keskeyttänyt yhteyden. Tietosi ovat edelleen turvassa, sillä Chromium katkaisi yhteyden, ennen kuin mitään tietoja vaihdettiin.</translation>
+<translation id="9106062320799175032">Lisää laskutusosoite</translation>
+<translation id="910908805481542201">Auta minua korjaamaan asia</translation>
+<translation id="9128870381267983090">Yhdistä verkkoon</translation>
<translation id="9137013805542155359">Näytä alkuperäinen</translation>
<translation id="9137248913990643158">Aloita ja kirjaudu sisään Chromeen ennen tämän sovelluksen käyttämistä.</translation>
<translation id="9148507642005240123">K&amp;umoa muokkaus</translation>
@@ -981,6 +1021,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> käyttää protokollaa, jota ei tueta.</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="9215416866750762878">Sovellus estää Chromea muodostamasta turvallista yhteyttä tähän sivustoon</translation>
<translation id="9219103736887031265">Kuvat</translation>
<translation id="933612690413056017">Ei internetyhteyttä</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -990,5 +1031,12 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ei mitään}=1{1 kohde}other{# kohdetta}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Kehittäjän koontiversio</translation>
+<translation id="989988560359834682">Osoitteen muokkaus</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401"><ph name="SOFTWARE_NAME" /> on asennettu virheellisesti tietokoneellesi tai verkkoon:
+
+ &lt;ul&gt;
+ &lt;li&gt;Yritä poistaa <ph name="SOFTWARE_NAME" /> tai poistaa se käytöstä&lt;/li&gt;
+ &lt;li&gt;Yritä yhdistää toiseen verkkoon&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index cbf3fd95fc0..e2632f43afb 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Mga Bookmark sa Desktop</translation>
<translation id="1074497978438210769">Hindi secure</translation>
<translation id="1080116354587839789">Pagkasyahin sa lapad</translation>
+<translation id="1088860948719068836">Magdagdag ng Pangalan sa Card</translation>
<translation id="1103523840287552314">Palaging i-translate ang <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Ipakita ang lahat ng naka-save na password...</translation>
<translation id="1107591249535594099">Kung lalagyan ng check, mag-iimbak ang Chrome ng kopya ng iyong card sa device na ito para sa mas mabilis na pagsagot sa form.</translation>
<translation id="1111153019813902504">Mga kamakailang bookmark</translation>
<translation id="1113869188872983271">&amp;I-undo ang pagbabago sa ayos</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (naka-sync)</translation>
<translation id="1263231323834454256">Listahan ng babasahin</translation>
<translation id="1264126396475825575">Ulat ng pag-crash na nakuha noong <ph name="CRASH_TIME" /> (hindi pa naa-upload o nababalewala)</translation>
+<translation id="1270502636509132238">Paraan sa Pag-pick up</translation>
<translation id="1281526147609854549">Inisyu ng <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Huwag isalin kailanman ang site na ito</translation>
<translation id="129553762522093515">Kamakailang isinara</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Naghihintay ng koneksyon…</translation>
<translation id="153384715582417236">'Yan na muna sa ngayon</translation>
<translation id="1549470594296187301">Dapat naka-enable ang JavaScript upang magamit ang feature na ito.</translation>
-<translation id="1555130319947370107">Asul</translation>
<translation id="1559528461873125649">Walang naturang file o direktoryo</translation>
<translation id="1583429793053364125">Nagkaroon ng problema habang ipinapakita ang webpage na ito.</translation>
<translation id="1592005682883173041">Access sa Lokal na Data</translation>
<translation id="1594030484168838125">Pumili</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1629803312968146339">Gusto mo bang i-save ng Chrome ang card na ito?</translation>
<translation id="1639239467298939599">Naglo-load</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Kailangan mo ng pahintulot mula kay <ph name="NAME" /> upang mabisita ang site na ito</translation>
<translation id="1721424275792716183">Kinakailangan ang field na may *</translation>
+<translation id="1727741090716970331">Magdagdag ng Wastong Numero ng Card</translation>
<translation id="1728677426644403582">Pinagmulan ng isang web page ang tinitingnan mo</translation>
<translation id="173080396488393970">Hindi sinusuportahan ang uri ng card na ito</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Error sa serialization</translation>
<translation id="1974060860693918893">Advanced</translation>
<translation id="1978555033938440688">Bersyon ng Firmware</translation>
-<translation id="1995859865337580572">Paki-verify ang iyong CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{at 1 pa}one{at # pa}other{at # pa}}</translation>
<translation id="2025186561304664664">Nakatakda sa awtomatikong naka-configure ang proxy.</translation>
<translation id="2030481566774242610">Ang ibig mo bang sabihin ay <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Upang makakuha ng naka-personalize na content na iminumungkahi ng Google, mag-sign in sa Chrome.</translation>
+<translation id="2091887806945687916">Tunog</translation>
<translation id="2094505752054353250">Maling pagtutugma sa domain</translation>
<translation id="2096368010154057602">Departamento</translation>
<translation id="2108755909498034140">I-restart ang iyong computer</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Binalewala dahil na-override ito ng <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Naghahanap ng mga kalapit na page sa Pisikal na Web</translation>
<translation id="213826338245044447">Mga Bookmark sa Mobile</translation>
+<translation id="214556005048008348">Kanselahin ang pagbabayad</translation>
<translation id="2147827593068025794">Pag-sync sa Background</translation>
+<translation id="2148613324460538318">Magdagdag ng Card</translation>
<translation id="2154054054215849342">Hindi available ang pag-sync para sa iyong domain</translation>
<translation id="2154484045852737596">I-edit ang card</translation>
<translation id="2166049586286450108">Ganap na Access ng Admin</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}one{# address}other{# na address}}</translation>
<translation id="2187317261103489799">Tukuyin (default)</translation>
<translation id="2202020181578195191">Maglagay ng wastong taon ng pag-expire</translation>
+<translation id="2209523182407020534">Kabilang ang antivirus, firewall, at pag-filter ng web o proxy na software sa mga application na maaaring magsanhi ng ganitong error.</translation>
<translation id="2212735316055980242">Hindi nahanap ang patakaran</translation>
<translation id="2213606439339815911">Kinukuha ang mga entry...</translation>
<translation id="2218879909401188352">Ang mga umaatake na kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ay maaaring mag-install ng mga mapanganib na app na makakapinsala sa iyong device, magdagdag ng mga hindi alam na singil sa mobile bill mo, o magnakaw ng iyong personal na impormasyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Bumalik</translation>
<translation id="2503184589641749290">Mga tinatanggap na debit at prepaid card</translation>
<translation id="2515629240566999685">Suriin ang signal sa iyong lugar</translation>
+<translation id="2524461107774643265">Magdagdag ng Higit Pang Impormasyon</translation>
+<translation id="2536110899380797252">Magdagdag ng Address</translation>
<translation id="2539524384386349900">Tukuyin</translation>
<translation id="255002559098805027">Nagpadala ng di-wastong tugon ang <ph name="HOST_NAME" />.</translation>
<translation id="2556876185419854533">&amp;I-undo ang Pag-e-edit</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Hindi nakumpirma ng Chromium ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
<translation id="2705137772291741111">Hindi mabasa ang naka-save (naka-cache) na kopya ng site na ito.</translation>
<translation id="2709516037105925701">AutoFill</translation>
+<translation id="2710942282213947212">Pinipigilan ng software sa iyong computer na makakonekta nang ligtas ang Chromium sa web</translation>
<translation id="2712173769900027643">Humingi ng pahintulot</translation>
-<translation id="2713444072780614174">Puti</translation>
<translation id="2720342946869265578">Malapit</translation>
<translation id="2721148159707890343">Matagumpay ang kahilingan</translation>
<translation id="2728127805433021124">Nilagdaan ang certificate ng server gamit ang mahinang algorithm ng lagda.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">May nakitang pagbabago sa network.</translation>
<translation id="2916038427272391327">Isara ang iba pang program</translation>
<translation id="2922350208395188000">Hindi masuri ang certificate ng server.</translation>
+<translation id="2925673989565098301">Paraan ng Paghahatid</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" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> pa}}</translation>
<translation id="2941952326391522266">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; mula sa <ph name="DOMAIN2" /> ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Maling uri ng patakaran</translation>
<translation id="3032412215588512954">Gusto mo bang i-reload ang site na ito?</translation>
<translation id="3037605927509011580">Ay, Naku!</translation>
+<translation id="3039538478787849737">I-save ang card sa Google?</translation>
<translation id="3041612393474885105">Impormasyon sa Certificate</translation>
<translation id="3063697135517575841">Hindi nakumpirma ng Chrome ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
<translation id="3064966200440839136">Aalis sa incognito mode upang magbayad sa pamamagitan ng external na application. Magpatuloy?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Pansamantalang error sa server</translation>
<translation id="3154506275960390542">Naglalaman ang page na ito ng isang form na maaaring hindi secure na maisusumite. Maaaring makita ng iba ang data na iyong ipapadala habang ipinapadala ito o maaaring mabago ng isang nang-aatake upang baguhin kung ano ang matatanggap ng server.</translation>
<translation id="3157931365184549694">Ipanumbalik</translation>
+<translation id="3162559335345991374">Maaaring hilingin ng Wi-Fi na ginagamit mo na bisitahin mo ang page nito sa pag-login.</translation>
<translation id="3167968892399408617">Ang mga page na titingnan mo sa mga tab na incognito ay hindi mananatili sa history, cookie store o history ng paghahanap ng iyong browser kapag naisara mo na ang lahat ng iyong tab na incognito. Papanatilihin ang anumang mga file na ida-download mo o mga bookmark na gagawin mo.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Pulo</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Kanselahin ang Pagbabayad</translation>
<translation id="3207960819495026254">Naka-bookmark</translation>
+<translation id="3211223744486044430">Upang mas mabilis na makapagbayad sa susunod, i-save ang card na ito sa iyong Google Account at sa device na ito.</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>
<translation id="3226128629678568754">Pindutin ang button na i-reload upang isumiteng muli ang data na kailangan upang ma-load ang pahina.</translation>
<translation id="3227137524299004712">Mikropono</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Walang nakitang resulta ng paghahanap</translation>
<translation id="3305707030755673451">Na-encrypt ang iyong data gamit ang iyong passphrase sa pag-sync noong <ph name="TIME" />. Ilagay ito upang simulan ang pag-sync.</translation>
<translation id="3320021301628644560">Magdagdag ng billing address</translation>
-<translation id="3329013043687509092">Saturation</translation>
<translation id="333371639341676808">Iwasan ang pahinang ito mula sa paglikha ng karagdagang mga dialog.</translation>
<translation id="3338095232262050444">Secure</translation>
<translation id="3340978935015468852">mga setting</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Client ID:</translation>
<translation id="3391030046425686457">Address kung saan maghahatid</translation>
<translation id="3395827396354264108">Pamamaraan sa pag-pick up</translation>
+<translation id="3399952811970034796">Delivery Address</translation>
<translation id="3422248202833853650">Subukang lumabas sa iba pang program upang magbakante ng memory.</translation>
<translation id="3422472998109090673">Hindi makakonekta sa <ph name="HOST_NAME" /> sa kasalukuyan.</translation>
<translation id="3427092606871434483">Payagan (default)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Nakuha ang ulat ng pag-crash noong <ph name="CRASH_TIME" />, na-upload noong <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Impormasyon sa certificate</translation>
<translation id="3690164694835360974">Hindi ligtas ang pag-log in</translation>
+<translation id="3704162925118123524">Ang network na ginagamit mo ay maaaring humiling sa iyo na bisitahin ang page ng pag-login nito.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Naglo-load...</translation>
<translation id="3712624925041724820">Naubos na ang mga lisensya</translation>
<translation id="3714780639079136834">I-on ang mobile data o Wi-Fi</translation>
+<translation id="3715597595485130451">Kumonekta sa Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Suriin ang configuration ng proxy, firewall at DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Kung nauunawaan mo ang mga peligro sa iyong seguridad, maaari mong <ph name="BEGIN_LINK" />bisitahin ang hindi ligtas na site na ito<ph name="END_LINK" /> bago maalis ang mga mapanganib na program.</translation>
<translation id="3739623965217189342">Link na kinopya mo</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;I-undo ang pagdagdag</translation>
<translation id="404928562651467259">BABALA</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Nakatakda ang configuration ng proxy upang gumamit ng isang .pac script URL, hindi ng mga hindi nababagong proxy server.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Di-wasto ang serial number ng device</translation>
<translation id="410351446219883937">I-autoplay</translation>
<translation id="4103763322291513355">Bisitahin ang &lt;strong&gt;chrome://policy&lt;/strong&gt; upang makita ang listahan ng mga naka-blacklist na URL at iba pang mga patakaran na ipinapatupad ng iyong system administrator.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Palaging payagan sa site na ito</translation>
<translation id="4117700440116928470">Hindi sinusuportahan ang saklaw ng patakaran.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 pa}one{# pa}other{# pa}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Tinangka mong maabot ang <ph name="DOMAIN" />, subalit ang certificate na ipinakita ng server ay binawi ng nagbigay nito. Nangangahulugan ito na ang mga kredensyal sa seguridad na ipinakita ng server ay talagang hindi dapat pagkatiwalaan. Maaaring nakikipag-ugnay ka sa isang nang-aatake.</translation>
<translation id="4394049700291259645">Huwag paganahin</translation>
<translation id="4406896451731180161">mga resulta ng paghahanap</translation>
+<translation id="4415426530740016218">Address sa Pag-pick up</translation>
<translation id="4424024547088906515">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chrome ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="4432688616882109544">Hindi tinanggap ng <ph name="HOST_NAME" /> ang iyong certificate sa pag-log in o maaaring walang ibinigay.</translation>
<translation id="443673843213245140">Hindi pinagana ang paggamit ng isang proxy ngunit tinutukoy ang isang tahasang configuration ng proxy.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Subukang i-disable ang iyong mga extension.</translation>
<translation id="457875822857220463">Paghahatid</translation>
+<translation id="4582800630050655161">Maaari kang mawalan ng access sa iyong Google Account o manakawan ng pagkakakilanlan. Inirerekomenda ng Chromium na palitan na ang password mo.</translation>
<translation id="4587425331216688090">Alisin ang address sa Chrome?</translation>
<translation id="4592951414987517459">Naka-encrypt ang iyong koneksyon sa <ph name="DOMAIN" /> gamit ang isang makabagong cipher suite.</translation>
<translation id="4594403342090139922">&amp;I-undo ang Pagtanggal</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Ihinto ang paggamit ng di-wastong certificate</translation>
+<translation id="4690954380545377795">Maaari kang mawalan ng access sa iyong Google Account o manakawan ng pagkakakilanlan. Inirerekomenda ng Chrome na palitan na ang password mo.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Naputol ang iyong koneksyon</translation>
<translation id="471880041731876836">Wala kang pahintulot na bisitahin ang site na ito</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Magpatakbo ng Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Iyong pagbabayad</translation>
<translation id="4726672564094551039">I-reload ang mga patakaran</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">I-restart ang Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Hindi maganda ang katayuan ng backing store</translation>
<translation id="5023310440958281426">Suriin ang mga patakaran ng iyong administrator</translation>
<translation id="5029568752722684782">I-clear ang kopya</translation>
+<translation id="503069730517007720">Kinakailangan ang root certificate para sa "<ph name="SOFTWARE_NAME" />" ngunit hindi ito naka-install. Dapat tingnan ng IT administrator ang mga tagubilin sa pag-configure para sa "<ph name="SOFTWARE_NAME" />" upang maayos ang problemang ito. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Tungkol sa Google Translate</translation>
<translation id="5039804452771397117">Payagan</translation>
<translation id="5040262127954254034">Privacy</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Mga Eksperimento</translation>
<translation id="5205222826937269299">Kailangan ng pangalan</translation>
<translation id="5222812217790122047">Kailangan ng email</translation>
+<translation id="522700295135997067">Maaaring ninakaw ng site na ito ang iyong password</translation>
+<translation id="5230733896359313003">Address na Padadalhan</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Ginagamit mo ba ang Chrome sa trabaho? Maaaring pamahalaan ng mga negosyo ang mga setting ng Chrome para sa kanilang mga empleyado. Matuto pa</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Sundin ang mga hakbang na ito upang pansamantalang i-disable ang software upang makapunta ka sa web. Kakailanganin mo ang mga pribilehiyong pang-administrator.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Hindi pribado ang iyong koneksyon sa site na ito. Upang lumabas sa VR mode anumang oras, alisin ang headset at pindutin ang bumalik.</translation>
<translation id="5299298092464848405">Error sa pag-parse ng patakaran</translation>
+<translation id="5308380583665731573">Kumonekta</translation>
<translation id="5308689395849655368">Hindi pinagana ang pag-uulat ng pag-crash.</translation>
<translation id="5317780077021120954">I-save</translation>
<translation id="5327248766486351172">Pangalan</translation>
+<translation id="5332219387342487447">Pamamaraan ng Pagpapadala</translation>
<translation id="5355557959165512791">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil binawi na ang certificate nito. Karaniwang pansamantala lang ang mga error at pag-atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="536296301121032821">Nabigo i-load ang mga setting ng patakaran sa store</translation>
<translation id="5386426401304769735">Naglalaman ang chain ng certificate para sa site na ito ng certificate na naka-sign gamit ang SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Ang URL ng site na ito sa intranet ng kumpanya, organisasyon o paaralan ay kapareho ng URL ng isang external na website.
<ph name="LINE_BREAK" />
Subukang makipag-ugnayan sa iyong system administrator.</translation>
+<translation id="5499929369096410817">Ilagay ang panseguridad na code na para sa <ph name="CREDIT_CARD" />. Hindi ise-save ang code na ito.</translation>
<translation id="5509780412636533143">Mga pinamamahalaang bookmark</translation>
<translation id="5510766032865166053">Maaaring inilipat o na-delete ito.</translation>
<translation id="5523118979700054094">Pangalan ng patakaran</translation>
<translation id="552553974213252141">Nakuha ba nang tama ang text?</translation>
<translation id="5540224163453853">Hindi mahanap ang hiniling na artikulo.</translation>
+<translation id="5541546772353173584">Magdagdag ng Email</translation>
<translation id="5544037170328430102">Isinasaad ng isang naka-embed na page sa <ph name="SITE" /> na:</translation>
+<translation id="5545756402275714221">Mga Artikulo para sa Iyo</translation>
<translation id="5556459405103347317">I-reload</translation>
<translation id="5560088892362098740">Petsa ng Pag-expire</translation>
<translation id="5565735124758917034">Aktibo</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Makakuha ng naka-personalize na content</translation>
<translation id="5675650730144413517">Hindi gumagana ang page na ito</translation>
+<translation id="5689199277474810259">I-export sa JSON</translation>
<translation id="5710435578057952990">Ang pagkilala ng website na ito ay hindi natukoy.</translation>
<translation id="5719499550583120431">Tinatanggap ang mga prepaid card.</translation>
<translation id="5720705177508910913">Kasalukuyang user</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Naka-encrypt ang iyong koneksyon sa <ph name="DOMAIN" /> gamit ang isang hindi na ginagamit na cipher suite.</translation>
<translation id="5813119285467412249">&amp;Gawing Muli ang Pagdagdag</translation>
<translation id="5838278095973806738">Hindi ka dapat maglagay ng anumang sensitibong impormasyon sa site na ito (halimbawa, mga password o credit card), dahil maaari itong nakawin ng mga umaatake.</translation>
+<translation id="5866257070973731571">Magdagdag ng Numero ng Telepono</translation>
<translation id="5869405914158311789">Hindi makakonekta sa site na ito</translation>
<translation id="5869522115854928033">Mga naka-save na password</translation>
<translation id="5872918882028971132">Mga Suhestyon ng Magulang</translation>
<translation id="5893752035575986141">Tinatanggap ang mga credit card.</translation>
-<translation id="5901630391730855834">Dilaw</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (naka-sync)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 ang ginagamit}one{# ang ginagamit}other{# ang ginagamit}}</translation>
<translation id="5959728338436674663">Awtomatikong magpadala ng ilang <ph name="BEGIN_WHITEPAPER_LINK" />impormasyon sa system at content ng page<ph name="END_WHITEPAPER_LINK" /> sa Google upang makatulong na tumukoy ng mapapanganib na app at site. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">I-edit ang Impormasyon ng Contact</translation>
<translation id="5967867314010545767">Alisin sa history</translation>
<translation id="5975083100439434680">Mag-zoom out</translation>
+<translation id="597552863672748783">Kumpirmahin ang panseguridad na code</translation>
<translation id="598637245381783098">Hindi mabuksan ang app sa pagbabayad</translation>
<translation id="5989320800837274978">Hindi tunukoy ang alinman sa mga hindi nababagong proxy server o isang .pac script URL.</translation>
<translation id="5990559369517809815">Na-block ng isang extension ang mga kahilingan sa server.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}one{Page #}other{Page #}}</translation>
-<translation id="6017514345406065928">Berde</translation>
<translation id="6017850046339264347">Ang mga umaatake sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ay maaaring mag-install ng mga mapanlinlang na app na nagpapanggap na ibang bagay o nangongolekta ng data na maaaring gamitin upang subaybayan ka. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (naka-sync)</translation>
<translation id="6027201098523975773">Maglagay ng pangalan</translation>
<translation id="6040143037577758943">Isara</translation>
-<translation id="6042308850641462728">Higit pa</translation>
<translation id="6047233362582046994">Kung nauunawaan mo ang mga panganib sa iyong seguridad, maaari mong <ph name="BEGIN_LINK" />bisitahin ang site na ito<ph name="END_LINK" /> bago maalis ang mga mapaminsalang app.</translation>
<translation id="6047927260846328439">Maaaring subukan ng content na ito na linlangin kang mag-install ng software o maghayag ng personal na impormasyon. <ph name="BEGIN_LINK" />Ipakita pa rin<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil gumagamit ng pag-pin ng certificate ang website. Karaniwang pansamantala lang ang mga error at pag-atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Isang page ng extension ang tinitingnan mo</translation>
<translation id="6596325263575161958">Mga pagpipilian sa pag-encrypt</translation>
<translation id="662080504995468778">Manatili</translation>
+<translation id="6624427990725312378">Impormasyon ng Contact</translation>
<translation id="6626291197371920147">Magdagdag ng wastong card number</translation>
<translation id="6628463337424475685">Paghahanap ng <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Maaaring magtangka ang mga attacker na kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> na mag-install ng mga mapanganib na program sa iyong Mac na magnanakaw o magde-delete ng impormasyon mo (halimbawa, mga larawan, password, mensahe, at credit card). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Nakaraan</translation>
<translation id="6710594484020273272">&lt;I-type ang termino para sa paghahanap&gt;</translation>
<translation id="6711464428925977395">May problema sa proxy server, o mali ang address.</translation>
-<translation id="6727102863431372879">Itakda</translation>
<translation id="674375294223700098">Hindi alam na error sa certificate ng server</translation>
<translation id="6753269504797312559">Halaga ng patakaran</translation>
<translation id="6757797048963528358">Nag-sleep ang iyong device.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Path ng Profile</translation>
<translation id="7424977062513257142">Isinasaad ng isang naka-embed na page sa webpage na ito na:</translation>
+<translation id="7437289804838430631">Magdagdag ng Impormasyon ng Contact</translation>
<translation id="7441627299479586546">Maling paksa ng patakaran</translation>
<translation id="7444046173054089907">Naka-block ang site na ito</translation>
<translation id="7445762425076701745">Hindi ganap na mapatunayan ang pagkakakilanlan ng server na konektado ka. Konektado ka sa server gamit ang pangalan na angkop lamang sa loob ng iyong network, na walang paraan ang panglabas na certificate authority na patunayan ang pagmamay-ari. Dahil magbibigay ang ilang kinauukulan sa certificate para sa mga pangalang ito, walang paraan upang matiyak na konektado ka sa nilayong website at hindi isang umaatake.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Sumulong</translation>
<translation id="7485870689360869515">Walang nahanap na data.</translation>
<translation id="7508255263130623398">Walang laman ang ibinalik na device id ng patakaran o hindi ito tumutugma sa kasalukuyang device id</translation>
+<translation id="7511955381719512146">Maaaring hilingin ng Wi-Fi na ginagamit mo na bisitahin mo ang <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">I-download</translation>
<translation id="7518003948725431193">Walang webpage na nahanap para sa web address:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Hindi pribado ang iyong koneksyon sa site na ito</translation>
-<translation id="7535087603100972091">Value</translation>
<translation id="7537536606612762813">Kinakailangan</translation>
<translation id="7542403920425041731">Kapag nagkumpirma ka, ibabahagi ang mga detalye ng iyong card sa site na ito.</translation>
<translation id="7542995811387359312">Hindi pinagana ang awtomatikong pagpuno ng credit card dahil ang form na ito ay hindi gumagamit ng secure na koneksyon.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; maaaring mapanlokong ibinigay ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="7568593326407688803">Ang pahinang ito ay nasa<ph name="ORIGINAL_LANGUAGE" />Gusto mong isalin ito?</translation>
<translation id="7569952961197462199">Alisin ang credit card sa Chrome?</translation>
-<translation id="7569983096843329377">Itim</translation>
<translation id="7578104083680115302">Magbayad nang mabilis sa mga site at app sa iba't ibang device gamit ang mga card na na-save mo sa Google.</translation>
<translation id="7588950540487816470">Pisikal na Web</translation>
<translation id="7592362899630581445">Lumabag ang certificate ng server sa limitasyon sa pangalan.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Maaaring subukan ng mga attacker sa site na ito na linlangin ka upang mag-install ng mga program na makakasama sa iyong karanasan sa pag-browse (halimbawa, sa pamamagitan ng pagbabago ng iyong homepage o pagpapakita ng mga karagdagang ad sa mga site na binibisita mo).</translation>
<translation id="7674629440242451245">Interesado sa mga astig at bagong tampok sa Chrome? Subukan ang aming dev channel sa chrome.com/dev.</translation>
<translation id="7682287625158474539">Pagpapadala</translation>
+<translation id="7699293099605015246">Hindi available sa ngayon ang mga artikulo</translation>
<translation id="7701040980221191251">Wala</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Magpatuloy sa <ph name="SITE" /> (hindi ligtas)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificate</translation>
<translation id="7716147886133743102">Na-block ng iyong administrator</translation>
<translation id="7716424297397655342">Hindi maaaring i-load ang site na ito mula sa cache</translation>
+<translation id="7723047071702270851">I-edit ang Card</translation>
<translation id="774634243536837715">Na-block ang mapanganib na content.</translation>
<translation id="7752995774971033316">Hindi pinamamahalaan</translation>
<translation id="7755287808199759310">Maaari itong alisin sa pagkaka-block ng iyong magulang para sa iyo</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Magdagdag ng address</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">Magdagdag</translation>
+<translation id="7793553086574152071">Upang mas mabilis na makapagbayad sa susunod, i-save ang card na ito sa iyong Google Account.</translation>
<translation id="7793809570500803535">Maaaring pansamantalang sira ang webpage sa <ph name="SITE" /> o maaaring permanente itong inilipat sa isang bagong web address.</translation>
<translation id="7800304661137206267">Na-encrypt ang koneksyon gamit ang <ph name="CIPHER" />, kasama ang <ph name="MAC" /> para sa pagpapatunay ng mensahe at <ph name="KX" /> bilang mekanismo ng pangunahing pagpapalit.</translation>
+<translation id="7802523362929240268">Lehitimo ang site</translation>
<translation id="780301667611848630">Hindi salamat</translation>
<translation id="7805768142964895445">Katayuan</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Alisin ang suhestyon sa Chrome?</translation>
<translation id="7815407501681723534">Nakakita ng <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para sa '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Maaaring hilingin ng Wi-Fi na ginagamit mo (<ph name="WIFI_NAME" />) na bisitahin mo ang page nito sa pag-login.</translation>
<translation id="785549533363645510">Gayunpaman, hindi ka invisible. Kahit mag-incognito ka, hindi matatago ang iyong pagba-browse mula sa iyong employer, sa iyong internet service provider o sa mga website na binibisita mo.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Tinatanggap ang mga debit at prepaid card.</translation>
+<translation id="7878562273885520351">Maaaring makompromismo ang iyong password</translation>
<translation id="7887683347370398519">Tingnan ang iyong CVC at subukang muli</translation>
<translation id="79338296614623784">Maglagay ng wastong numero ng telepono</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Wala pang bisa ang certificate ng server.</translation>
-<translation id="7942349550061667556">Pula</translation>
<translation id="7947285636476623132">Tingnan ang iyong taon ng pag-expire at subukang muli</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Mga bookmark sa mobile</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Magtanong (default)</translation>
<translation id="8041089156583427627">Magpadala ng Feedback</translation>
<translation id="8041940743680923270">Gamitin ang pangkalahatang default (Tanungin)</translation>
+<translation id="8057711352706143257">Hindi maayos na naka-configure ang "<ph name="SOFTWARE_NAME" />." Kadalasang naaayos ang problema kapag in-uninstall ang "<ph name="SOFTWARE_NAME" />." <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Hindi natingnan ang artikulo.</translation>
<translation id="8091372947890762290">Nakabinbin sa server ang pag-activate</translation>
+<translation id="8094917007353911263">Maaaring hilingin ng network na ginagamit mo na bisitahin mo ang <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Paraan ng Pagbabayad</translation>
<translation id="8118489163946903409">Paraan ng pagbabayad</translation>
+<translation id="8127301229239896662">Hindi na-install nang maayos ang "<ph name="SOFTWARE_NAME" />" sa iyong computer o network. Magtanong sa IT administrator mo upang malutas ang isyung ito.</translation>
<translation id="8131740175452115882">Kumpirmahin</translation>
<translation id="8134994873729925007">Hindi makita ang <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> ng server ng <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Nag-sleep ang iyong computer.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Makipag-ugnay sa administrator ng iyong network kung hindi ka sigurado kung ano ang ibig sabihin nito.</translation>
<translation id="8293206222192510085">Magdagdag ng Bookmark</translation>
<translation id="8294431847097064396">Pinagmulan</translation>
+<translation id="8298115750975731693">Maaaring hilingin ng Wi-Fi na ginagamit mo (<ph name="WIFI_NAME" />) na bisitahin mo ang <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Hindi makakonekta nang pribado sa <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> dahil mali ang petsa at oras (<ph name="DATE_AND_TIME" />) sa iyong device. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Nabigo ang translation dahil sa problema sa koneksyon sa network.</translation>
<translation id="8332188693563227489">Tinanggihan ang access sa <ph name="HOST_NAME" /></translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Recently Closed</translation>
<translation id="8874824191258364635">Maglagay ng wastong numero ng card</translation>
<translation id="8876793034577346603">Nabigong ma-parse ang configuration ng network.</translation>
-<translation id="8889402386540077796">Hue</translation>
<translation id="8891727572606052622">Di-wastong mode ng proxy.</translation>
<translation id="889901481107108152">Paumanhin, hindi available ang eksperimentong ito sa iyong platform.</translation>
<translation id="8903921497873541725">Mag-zoom in</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>
+<translation id="893332455753468063">Magdagdag ng Pangalan</translation>
<translation id="8938939909778640821">Mga tinatanggap na credit at prepaid card</translation>
+<translation id="8957210676456822347">Pagpapahintulot sa Captive Portal</translation>
<translation id="8971063699422889582">Nag-expire na ang certificate ng server.</translation>
-<translation id="8986494364107987395">Awtomatikong ipadala ang mga istatistika ng paggamit at mga ulat ng pag-crash sa Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Ang susunod na site ay naglalaman ng mga mapanirang program</translation>
<translation id="8997023839087525404">Nagpakita ang server ng certificate na hindi inihayag sa publiko gamit ang patakaran sa Transparency ng Certificate. Kinakailangan ito para sa ilang certificate, upang matiyak na mapagkakatiwalaan ang mga ito at maprotektahan laban sa mga umaatake.</translation>
<translation id="9001074447101275817">Nangangailangan ang proxy na <ph name="DOMAIN" /> ng username at password.</translation>
<translation id="9005998258318286617">Hindi na-load ang PDF document.</translation>
+<translation id="9008201768610948239">Balewalain</translation>
<translation id="901974403500617787">Ang may-ari lang ang maaaring magtakda ng mga flag na nalalapat sa buong system: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Kinakailangan ang address sa pagsingil ng card</translation>
<translation id="9020542370529661692">Na-translate sa <ph name="TARGET_LANGUAGE" /> ang pahinang ito</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Tinangka mong maabot ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng isang di-wastong certificate.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">I-edit</translation>
-<translation id="9068849894565669697">Pumili ng kulay</translation>
<translation id="9069693763241529744">Na-block ng isang extension</translation>
<translation id="9076283476770535406">Maaaring mayroon itong mature content</translation>
<translation id="9078964945751709336">Nangangailangan ng higit pang impormasyon</translation>
+<translation id="9080712759204168376">Buod ng Order</translation>
<translation id="9103872766612412690">Karaniwang gumagamit ang <ph name="SITE" /> ng pag-encrypt upang protektahan ang iyong impormasyon. Noong sinubukang kumonekta ng Chromium sa <ph name="SITE" /> sa pagkakataong ito, nagbalik ang website ng mga hindi pangkaraniwan at maling kredensyal. Maaari itong mangyari kapag sinusubukan ng isang attacker na magpanggap bilang <ph name="SITE" />, o naputol ang koneksyon dahil sa isang screen ng pag-sign in sa Wi-Fi. Secure pa rin ang iyong impormasyon dahil inihinto ng Chromium ang koneksyon bago magkaroon ng palitan ng anumang data.</translation>
+<translation id="9106062320799175032">Magdagdag ng Billing Address</translation>
+<translation id="910908805481542201">Tulungan akong ayusin ito</translation>
+<translation id="9128870381267983090">Kumonekta sa network</translation>
<translation id="9137013805542155359">Ipakita ang orihinal</translation>
<translation id="9137248913990643158">Magsimula at mag-sign in sa Chrome bago gamitin ang app na ito.</translation>
<translation id="9148507642005240123">&amp;I-undo ang pag-e-edit</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">Gumagamit ng hindi sinusuportahang protocol ang <ph name="HOST_NAME" />.</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="9215416866750762878">Pinipigilan ng isang application na makakonekta nang ligtas ang Chrome sa site na ito</translation>
<translation id="9219103736887031265">Mga Larawan</translation>
<translation id="933612690413056017">Walang koneksyon sa Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Wala}=1{1 item}one{# item}other{# na item}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Bumuo ang Developer</translation>
+<translation id="989988560359834682">I-edit ang Address</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Hindi na-install nang maayos ang "<ph name="SOFTWARE_NAME" />" sa iyong computer o sa network:
+ &lt;ul&gt;
+ &lt;li&gt;Subukang i-uninstall o i-disable ang "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Subukang kumonekta sa ibang network&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index 4abea50140e..2d94a818617 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Favoris sur l'ordinateur</translation>
<translation id="1074497978438210769">Non sécurisé</translation>
<translation id="1080116354587839789">Ajuster à la largeur</translation>
+<translation id="1088860948719068836">Ajouter le nom du titulaire de la carte</translation>
<translation id="1103523840287552314">Toujours traduire les pages en <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Afficher tous les mots de passe enregistrés…</translation>
<translation id="1107591249535594099">Si cette case est cochée, une copie de votre carte est stockée sur cet appareil pour compléter les formulaires plus rapidement.</translation>
<translation id="1111153019813902504">Favoris consultés récemment</translation>
<translation id="1113869188872983271">&amp;Annuler la réorganisation</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synchronisés)</translation>
<translation id="1263231323834454256">Liste de lecture</translation>
<translation id="1264126396475825575">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> (pas encore importé ou ignoré)</translation>
+<translation id="1270502636509132238">Mode d'enlèvement</translation>
<translation id="1281526147609854549">Émis par <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
<translation id="129553762522093515">Récemment fermés</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">En attente de connexion…</translation>
<translation id="153384715582417236">C'est tout !</translation>
<translation id="1549470594296187301">Vous devez activer JavaScript pour utiliser cette fonctionnalité.</translation>
-<translation id="1555130319947370107">Bleu</translation>
<translation id="1559528461873125649">Fichier ou répertoire inexistant</translation>
<translation id="1583429793053364125">Une erreur s'est produite lors de l'affichage de la page Web.</translation>
<translation id="1592005682883173041">Accès aux données locales</translation>
<translation id="1594030484168838125">Sélectionner</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Appareil photo</translation>
<translation id="1629803312968146339">Voulez-vous que cette carte soit enregistrée dans Chrome ?</translation>
<translation id="1639239467298939599">Chargement en cours</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Système d'exploitation</translation>
<translation id="1721312023322545264">Vous devez disposer de l'autorisation de <ph name="NAME" /> pour consulter ce site</translation>
<translation id="1721424275792716183">* Champ obligatoire</translation>
+<translation id="1727741090716970331">Ajouter un numéro de carte valide</translation>
<translation id="1728677426644403582">Vous consultez actuellement la source d'une page Web</translation>
<translation id="173080396488393970">Type de carte non accepté</translation>
<translation id="1734864079702812349">American Express</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Erreur de sérialisation.</translation>
<translation id="1974060860693918893">Paramètres avancés</translation>
<translation id="1978555033938440688">Version du micrologiciel</translation>
-<translation id="1995859865337580572">Veuillez confirmer votre code CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{et 1 autre}one{et # autre}other{et # autres}}</translation>
<translation id="2025186561304664664">Le proxy est défini sur la configuration automatique.</translation>
<translation id="2030481566774242610">Essayez avec <ph name="LINK" /></translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Pour obtenir une recommandation de contenu personnalisé de la part de Google, connectez-vous à Chrome.</translation>
+<translation id="2091887806945687916">Son</translation>
<translation id="2094505752054353250">Le domaine ne correspond pas</translation>
<translation id="2096368010154057602">Département</translation>
<translation id="2108755909498034140">Redémarrez l'ordinateur</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorée parce que remplacée par <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Recherche de pages Web physique à proximité</translation>
<translation id="213826338245044447">Favoris sur mobile</translation>
+<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="2154054054215849342">La synchronisation n'est pas disponible pour votre domaine</translation>
<translation id="2154484045852737596">Modifier la carte</translation>
<translation id="2166049586286450108">Accès administrateur complet</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresses}}</translation>
<translation id="2187317261103489799">Détecter (par défaut)</translation>
<translation id="2202020181578195191">Saisissez une année d'expiration valide</translation>
+<translation id="2209523182407020534">Les antivirus, les pare-feu et les logiciels de filtrage Web ou de proxy font partie des applications qui peuvent être à l'origine du problème.</translation>
<translation id="2212735316055980242">Règle introuvable.</translation>
<translation id="2213606439339815911">Obtention des entrées en cours…</translation>
<translation id="2218879909401188352">Les pirates informatiques qui contrôlent le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> peuvent installer des applications dangereuses qui endommagent votre appareil, ajoutent des frais cachés à votre facture de téléphonie mobile ou dérobent vos informations personnelles. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Retour</translation>
<translation id="2503184589641749290">Cartes de débit et cartes prépayées acceptées</translation>
<translation id="2515629240566999685">Vérifier le signal dans votre zone</translation>
+<translation id="2524461107774643265">Ajouter des informations</translation>
+<translation id="2536110899380797252">Ajouter une adresse</translation>
<translation id="2539524384386349900">Détecter</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> a envoyé une réponse incorrecte.</translation>
<translation id="2556876185419854533">&amp;Annuler la modification</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Impossible de valider votre carte dans Chromium pour le moment. Veuillez réessayer plus tard.</translation>
<translation id="2705137772291741111">La copie enregistrée (en cache) de ce site est illisible.</translation>
<translation id="2709516037105925701">Saisie automatique</translation>
+<translation id="2710942282213947212">Un logiciel installé sur votre ordinateur empêche Chromium de se connecter au Web de manière sécurisée</translation>
<translation id="2712173769900027643">Demander l'autorisation</translation>
-<translation id="2713444072780614174">Blanc</translation>
<translation id="2720342946869265578">À proximité</translation>
<translation id="2721148159707890343">Demande réussie.</translation>
<translation id="2728127805433021124">Le certificat du serveur a été signé avec un algorithme de signature faible.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Un changement de réseau a été détecté.</translation>
<translation id="2916038427272391327">Fermez les autres programmes</translation>
<translation id="2922350208395188000">Impossible de vérifier le certificat du serveur.</translation>
+<translation id="2925673989565098301">Mode de livraison</translation>
<translation id="2928905813689894207">Adresse de facturation</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autre}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> autres}}</translation>
<translation id="2941952326391522266">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité provient du domaine <ph name="DOMAIN2" />. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Type de règle incorrect.</translation>
<translation id="3032412215588512954">Voulez-vous actualiser ce site ?</translation>
<translation id="3037605927509011580">Aie aie aie</translation>
+<translation id="3039538478787849737">Enregistrer la carte dans Google ?</translation>
<translation id="3041612393474885105">Informations relatives au certificat</translation>
<translation id="3063697135517575841">Impossible de valider votre carte dans Chrome pour le moment. Veuillez réessayer plus tard.</translation>
<translation id="3064966200440839136">En payant via une application externe, vous allez quitter le mode navigation privée. Voulez-vous continuer ?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Erreur temporaire du serveur.</translation>
<translation id="3154506275960390542">Cette page inclut un formulaire dont la transmission n'est peut-être pas sécurisée. Les données envoyées pourront être vues par d'autres personnes pendant leur transfert ou modifiées par un pirate informatique afin de changer le message reçu par le serveur.</translation>
<translation id="3157931365184549694">Restaurer</translation>
+<translation id="3162559335345991374">Pour utiliser ce réseau Wi-Fi, il est possible que vous deviez vous rendre sur la page de connexion correspondante.</translation>
<translation id="3167968892399408617">Les pages consultées dans les onglets de navigation privée ne sont pas enregistrées dans l'historique de votre navigateur, dans les cookies ni dans l'historique des recherches une fois que vous avez fermé tous les onglets de navigation privée. Les fichiers téléchargés et les favoris ajoutés sont conservés.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Île</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Annuler le paiement</translation>
<translation id="3207960819495026254">Favori</translation>
+<translation id="3211223744486044430">Pour régler plus rapidement vos achats la prochaine fois, enregistrez cette carte dans votre compte Google et sur cet appareil.</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>
<translation id="3226128629678568754">Veuillez appuyer sur le bouton d'actualisation pour renvoyer les données nécessaires au chargement de la page.</translation>
<translation id="3227137524299004712">Micro</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Aucun résultat de recherche n'a été trouvé.</translation>
<translation id="3305707030755673451">Vos données ont été chiffrées avec votre phrase secrète de synchronisation le <ph name="TIME" />. Saisissez-la pour lancer la synchronisation.</translation>
<translation id="3320021301628644560">Ajouter une adresse de facturation</translation>
-<translation id="3329013043687509092">Saturation</translation>
<translation id="333371639341676808">Empêcher cette page de générer des boîtes de dialogue supplémentaires</translation>
<translation id="3338095232262050444">Sécurisé</translation>
<translation id="3340978935015468852">paramètres</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID client :</translation>
<translation id="3391030046425686457">Adresse de livraison</translation>
<translation id="3395827396354264108">Mode d'enlèvement</translation>
+<translation id="3399952811970034796">Adresse de livraison</translation>
<translation id="3422248202833853650">Essayez de fermer les autres programmes pour libérer de la mémoire.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> est actuellement inaccessible.</translation>
<translation id="3427092606871434483">Autoriser (par défaut)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> et importé le <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informations relatives au certificat</translation>
<translation id="3690164694835360974">Connexion non sécurisée</translation>
+<translation id="3704162925118123524">Pour utiliser ce réseau, il est possible que vous deviez vous rendre sur la page de connexion correspondante.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Chargement en cours...</translation>
<translation id="3712624925041724820">Licences épuisées.</translation>
<translation id="3714780639079136834">Activer les données mobiles ou le réseau Wi-Fi</translation>
+<translation id="3715597595485130451">Connexion au réseau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Vérifier les configurations du proxy, du pare-feu et du DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Si vous avez compris les risques auxquels vous vous exposez, vous pouvez <ph name="BEGIN_LINK" />consulter ce site dangereux<ph name="END_LINK" /> avant que les programmes malveillants n'aient été supprimés.</translation>
<translation id="3739623965217189342">Lien copié</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Annuler l'ajout</translation>
<translation id="404928562651467259">AVERTISSEMENT</translation>
<translation id="4058922952496707368">Clé "<ph name="SUBKEY" />" : <ph name="ERROR" /></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>
<translation id="4079302484614802869">La configuration du proxy est définie pour utiliser une URL de script .pac, et non pas des serveurs proxy déterminés.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Le numéro de série de l'appareil n'est pas valide.</translation>
<translation id="410351446219883937">Lecture automatique</translation>
<translation id="4103763322291513355">Accédez à &lt;strong&gt;chrome://policy&lt;/strong&gt; pour consulter une liste des URL ajoutées à la liste noire et des autres règles définies par votre administrateur système.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Toujours autoriser sur ce site</translation>
<translation id="4117700440116928470">La portée de la règle n'est pas compatible.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 autre}one{# autre}other{# autres}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le certificat présenté par le serveur a été révoqué par son émetteur. Cela signifie que le certificat présenté par le serveur ne doit pas être approuvé. Il est donc possible que vous communiquiez avec un pirate informatique.</translation>
<translation id="4394049700291259645">Désactiver</translation>
<translation id="4406896451731180161">résultats de recherche</translation>
+<translation id="4415426530740016218">Adresse d'enlèvement</translation>
<translation id="4424024547088906515">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 considéré comme fiable par Chrome. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> n'a pas accepté votre certificat de connexion, ou vous ne l'avez pas fourni.</translation>
<translation id="443673843213245140">L'utilisation d'un proxy est désactivée, mais une configuration de proxy explicite est spécifiée.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Essayez de désactiver les extensions.</translation>
<translation id="457875822857220463">Livraison</translation>
+<translation id="4582800630050655161">Vous pourriez perdre l'accès à votre compte Google ou vous faire dérober votre identité. L'équipe Chromium vous recommande de modifier votre mot de passe maintenant.</translation>
<translation id="4587425331216688090">Supprimer l'adresse de Chrome ?</translation>
<translation id="4592951414987517459">Votre connexion à <ph name="DOMAIN" /> est chiffrée à l'aide d'une méthode de chiffrement récente.</translation>
<translation id="4594403342090139922">&amp;Annuler la suppression</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Arrêter d'utiliser un certificat non valide</translation>
+<translation id="4690954380545377795">Vous pourriez perdre l'accès à votre compte Google ou vous faire dérober votre identité. L'équipe Chrome vous recommande de modifier votre mot de passe maintenant.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Votre connexion a été interrompue</translation>
<translation id="471880041731876836">Vous n'êtes pas autorisé à consulter ce site</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Exécuter les diagnostics réseau de Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Votre paiement</translation>
<translation id="4726672564094551039">Actualiser les règles</translation>
<translation id="4728558894243024398">Plate-forme</translation>
<translation id="4736825316280949806">Relancez Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">L'espace de stockage destiné à la sauvegarde est en mauvais état.</translation>
<translation id="5023310440958281426">Vérifiez les règles définies par votre administrateur</translation>
<translation id="5029568752722684782">Effacer la copie</translation>
+<translation id="503069730517007720">Veuillez installer un certificat racine pour "<ph name="SOFTWARE_NAME" />". Nous recommandons à votre administrateur informatique de lire les instructions de configuration du logiciel "<ph name="SOFTWARE_NAME" />" afin de remédier à la situation. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">À propos de Google Traduction</translation>
<translation id="5039804452771397117">Autoriser</translation>
<translation id="5040262127954254034">Confidentialité</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Prototypes</translation>
<translation id="5205222826937269299">Veuillez saisir un nom</translation>
<translation id="5222812217790122047">Veuillez saisir une adresse e-mail</translation>
+<translation id="522700295135997067">Ce site vient peut-être de dérober votre mot de passe</translation>
+<translation id="5230733896359313003">Adresse de livraison</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Vous utilisez Chrome au travail ? Les entreprises peuvent gérer les paramètres Chrome de leurs employés. En savoir plus</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Suivez ces étapes pour désactiver temporairement le logiciel afin d'accéder au Web. Vous devez disposer des droits d'administrateur.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Votre connexion à ce site n'est pas privée. Pour quitter le mode Réalité virtuelle à tout moment, retirez le casque, puis appuyez sur Retour.</translation>
<translation id="5299298092464848405">Erreur d'analyse de la règle.</translation>
+<translation id="5308380583665731573">Connexion</translation>
<translation id="5308689395849655368">L'envoi de rapports d'erreur est désactivé.</translation>
<translation id="5317780077021120954">Enregistrer</translation>
<translation id="5327248766486351172">Nom</translation>
+<translation id="5332219387342487447">Mode de livraison</translation>
<translation id="5355557959165512791">Le site <ph name="SITE" /> est actuellement inaccessible, car son certificat a été révoqué. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page plus tard.</translation>
<translation id="536296301121032821">Échec du stockage des paramètres de la règle.</translation>
<translation id="5386426401304769735">La chaîne de certificats de ce site contient un certificat signé avec SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Ce site situé sur l'intranet de l'entreprise, de l'organisation ou de l'établissement scolaire possède la même URL qu'un site Web externe.
<ph name="LINE_BREAK" />
Essayez de contacter votre administrateur système.</translation>
+<translation id="5499929369096410817">Saisissez le code de sécurité de la carte <ph name="CREDIT_CARD" />. Ce code ne sera pas enregistré.</translation>
<translation id="5509780412636533143">Favoris gérés</translation>
<translation id="5510766032865166053">Il a peut-être été déplacé ou supprimé.</translation>
<translation id="5523118979700054094">Nom de la règle</translation>
<translation id="552553974213252141">Le texte a-t-il été extrait correctement ?</translation>
<translation id="5540224163453853">Impossible de trouver l'article demandé.</translation>
+<translation id="5541546772353173584">Ajouter une adresse e-mail</translation>
<translation id="5544037170328430102">Une page intégrée à l'adresse <ph name="SITE" /> indique :</translation>
+<translation id="5545756402275714221">Articles pour vous</translation>
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5560088892362098740">Date d'expiration</translation>
<translation id="5565735124758917034">Actif</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Obtenir une recommandation de contenu personnalisé</translation>
<translation id="5675650730144413517">Cette page ne fonctionne pas</translation>
+<translation id="5689199277474810259">Exporter au format JSON</translation>
<translation id="5710435578057952990">L'identité de ce site Web n'a pas été vérifiée.</translation>
<translation id="5719499550583120431">Les cartes prépayées sont acceptées.</translation>
<translation id="5720705177508910913">Utilisateur actuel</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Votre connexion à <ph name="DOMAIN" /> est chiffrée à l'aide d'une méthode de chiffrement obsolète.</translation>
<translation id="5813119285467412249">&amp;Rétablir l'ajout</translation>
<translation id="5838278095973806738">Vous ne devriez pas saisir d'informations sensibles sur ce site (par exemple, vos mots de passe ou les informations de votre carte de paiement), car elles risquent d'être dérobées par des pirates informatiques.</translation>
+<translation id="5866257070973731571">Ajouter un numéro de téléphone</translation>
<translation id="5869405914158311789">Ce site est inaccessible</translation>
<translation id="5869522115854928033">Mots de passe enregistrés</translation>
<translation id="5872918882028971132">Suggestions des parents</translation>
<translation id="5893752035575986141">Les cartes de crédit sont acceptées.</translation>
-<translation id="5901630391730855834">Jaune</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronisés)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 en cours d'utilisation}one{# en cours d'utilisation}other{# en cours d'utilisation}}</translation>
<translation id="5959728338436674663">Envoyer automatiquement <ph name="BEGIN_WHITEPAPER_LINK" />des informations système et du contenu de page<ph name="END_WHITEPAPER_LINK" /> à Google afin de faciliter la détection d'applications et de sites dangereux. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Modifier les coordonnées</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
+<translation id="597552863672748783">Confirmer le code de sécurité</translation>
<translation id="598637245381783098">Impossible d'ouvrir l'application de paiement</translation>
<translation id="5989320800837274978">Aucun serveur proxy déterminé ou URL de script .pac n'a été indiqué.</translation>
<translation id="5990559369517809815">Les requêtes vers le serveur ont été bloquées par une extension.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Page 1}one{Page #}other{Page #}}</translation>
-<translation id="6017514345406065928">Vert</translation>
<translation id="6017850046339264347">Les pirates informatiques qui contrôlent le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> peuvent installer des applications trompeuses se faisant passer pour d'autres, ou collecter des données afin de vous surveiller. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synchronisés)</translation>
<translation id="6027201098523975773">Saisissez un nom</translation>
<translation id="6040143037577758943">Fermer</translation>
-<translation id="6042308850641462728">Plus</translation>
<translation id="6047233362582046994">Si vous êtes conscient des risques auxquels vous vous exposez, vous pouvez <ph name="BEGIN_LINK" />consulter ce site<ph name="END_LINK" /> avant que les applications dangereuses aient été supprimées.</translation>
<translation id="6047927260846328439">Ce contenu peut vous inciter à installer un logiciel ou vous soutirer des informations personnelles. <ph name="BEGIN_LINK" />Je souhaite y accéder malgré tout.<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Le site <ph name="SITE" /> est actuellement inaccessible, car il utilise l'épinglage des certificats. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page plus tard.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Vous consultez actuellement une page d'extension</translation>
<translation id="6596325263575161958">Options de chiffrement</translation>
<translation id="662080504995468778">Rester</translation>
+<translation id="6624427990725312378">Coordonnées</translation>
<translation id="6626291197371920147">Ajouter un numéro de carte valide</translation>
<translation id="6628463337424475685">Recherche <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Des individus malveillants à l'œuvre sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pourraient tenter d'installer des programmes dangereux sur votre Mac afin de récupérer ou de supprimer certaines informations (photos, 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>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Précédent</translation>
<translation id="6710594484020273272">&lt;Saisissez le terme de recherche&gt;</translation>
<translation id="6711464428925977395">Le serveur proxy présente une erreur, ou l'adresse est incorrecte.</translation>
-<translation id="6727102863431372879">Définir</translation>
<translation id="674375294223700098">Erreur inconnue liée au certificat du serveur.</translation>
<translation id="6753269504797312559">Valeur de la règle</translation>
<translation id="6757797048963528358">Votre appareil s'est mis en veille.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Chemin d'accès au profil</translation>
<translation id="7424977062513257142">Une page intégrée à cette page Web indique :</translation>
+<translation id="7437289804838430631">Ajouter des coordonnées</translation>
<translation id="7441627299479586546">Objet de la règle incorrect.</translation>
<translation id="7444046173054089907">Ce site est bloqué</translation>
<translation id="7445762425076701745">Impossible de valider entièrement l'identité du serveur auquel vous êtes connecté. Le nom utilisé pour cette connexion n'est valide que sur votre réseau et aucune autorité de certification externe ne peut en vérifier la propriété. Certaines autorités de certification délivrent tout de même des certificats pour ces types de nom, par conséquent nous ne sommes pas en mesure de vérifier que vous êtes connecté au site voulu et non à un site malveillant.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Avancer</translation>
<translation id="7485870689360869515">Aucune donnée n'a été trouvée.</translation>
<translation id="7508255263130623398">L'ID d'appareil de la règle renvoyé est vide ou ne correspond pas à l'ID d'appareil actuel.</translation>
+<translation id="7511955381719512146">Pour utiliser ce réseau Wi-Fi, il est possible que vous deviez vous rendre sur la page <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Télécharger</translation>
<translation id="7518003948725431193">Aucune page Web trouvée à l'adresse :<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Votre connexion à ce site n'est pas privée</translation>
-<translation id="7535087603100972091">Valeur</translation>
<translation id="7537536606612762813">Obligatoire</translation>
<translation id="7542403920425041731">Une fois la validation terminée, les informations relatives à votre carte seront partagées avec ce site.</translation>
<translation id="7542995811387359312">La saisie automatique des numéros de carte de paiement est désactivée, car la connexion utilisée par ce formulaire n'est pas sécurisée.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />. Il se peut que son certificat de sécurité ait été émis de manière frauduleuse. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="7568593326407688803">Cette page est en<ph name="ORIGINAL_LANGUAGE" />Voulez-vous la traduire ?</translation>
<translation id="7569952961197462199">Supprimer les données de carte de paiement de Chrome ?</translation>
-<translation id="7569983096843329377">Noir</translation>
<translation id="7578104083680115302">Payez rapidement sur des sites et dans des applications sur tous vos appareils au moyen de cartes que vous avez enregistrées sur Google.</translation>
<translation id="7588950540487816470">Web physique</translation>
<translation id="7592362899630581445">Le certificat du serveur ne respecte pas les restrictions de noms.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Des individus malveillants à l'œuvre sur ce site pourraient vous inciter à installer des programmes qui nuisent à votre confort de navigation (par exemple, en changeant votre page d'accueil ou en affichant des annonces supplémentaires sur les sites que vous consultez.</translation>
<translation id="7674629440242451245">Vous souhaitez bénéficier de nouvelles fonctionnalités Chrome passionnantes ? Essayez notre version en développement à l'adresse chrome.com/dev.</translation>
<translation id="7682287625158474539">Adresse de livraison</translation>
+<translation id="7699293099605015246">Articles non disponibles pour le moment</translation>
<translation id="7701040980221191251">Aucun</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continuer vers le site <ph name="SITE" /> (dangereux)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificat</translation>
<translation id="7716147886133743102">Bloqué par votre administrateur</translation>
<translation id="7716424297397655342">Impossible de charger ce site à partir du cache</translation>
+<translation id="7723047071702270851">Modifier la carte</translation>
<translation id="774634243536837715">Contenu dangereux bloqué.</translation>
<translation id="7752995774971033316">Non géré</translation>
<translation id="7755287808199759310">Ton parent peut te le débloquer</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Ajouter une adresse</translation>
<translation id="777702478322588152">Préfecture</translation>
<translation id="7791543448312431591">Ajouter</translation>
+<translation id="7793553086574152071">Pour régler vos achats plus rapidement la prochaine fois, enregistrez cette carte dans votre compte Google.</translation>
<translation id="7793809570500803535">Il est possible que la page Web située à l'adresse <ph name="SITE" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une nouvelle adresse Web.</translation>
<translation id="7800304661137206267">La connexion est chiffrée au moyen de <ph name="CIPHER" />, avec <ph name="MAC" /> pour l'authentification des messages et <ph name="KX" /> pour la méthode d'échange de clés.</translation>
+<translation id="7802523362929240268">Ce site est légitime</translation>
<translation id="780301667611848630">Non merci</translation>
<translation id="7805768142964895445">État</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Supprimer la suggestion de saisie de formulaire de Chrome ?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> trouvé(s) pour "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">Pour utiliser ce réseau Wi-Fi (<ph name="WIFI_NAME" />), il est possible que vous deviez vous rendre sur la page de connexion correspondante.</translation>
<translation id="785549533363645510">Cependant, cela ne vous rend pas invisible. Si vous passez en mode navigation privée, votre employeur, votre fournisseur d'accès à Internet ou les sites Web que vous consultez pourront toujours avoir accès à votre historique de navigation.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> : <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Les cartes de débit et les cartes prépayées sont acceptées.</translation>
+<translation id="7878562273885520351">Votre mot de passe a peut-être été piraté</translation>
<translation id="7887683347370398519">Veuillez vérifier votre code CVC et réessayer.</translation>
<translation id="79338296614623784">Saisissez un numéro de téléphone valide</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Le certificat du serveur n'est pas encore valide.</translation>
-<translation id="7942349550061667556">Rouge</translation>
<translation id="7947285636476623132">Veuillez vérifier l'année d'expiration, puis réessayer</translation>
<translation id="7951415247503192394">(32 bits)</translation>
<translation id="7956713633345437162">Favoris sur mobile</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Demander (par défaut)</translation>
<translation id="8041089156583427627">Envoyer</translation>
<translation id="8041940743680923270">Utiliser le paramètre global par défaut ("Demander")</translation>
+<translation id="8057711352706143257">Le logiciel "<ph name="SOFTWARE_NAME" />" n'est pas configuré correctement. En général, la désinstallation de "<ph name="SOFTWARE_NAME" />" permet de remédier à la situation. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Échec de l'affichage de l'article.</translation>
<translation id="8091372947890762290">Activation en attente sur le serveur.</translation>
+<translation id="8094917007353911263">Pour utiliser ce réseau, il est possible que deviez vous rendre sur la page <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Mode de paiement</translation>
<translation id="8118489163946903409">Mode de paiement</translation>
+<translation id="8127301229239896662">Le logiciel "<ph name="SOFTWARE_NAME" />" n'a pas été installé correctement sur votre ordinateur ou sur votre réseau. Demandez à l'administrateur informatique de résoudre le problème.</translation>
<translation id="8131740175452115882">Confirmer</translation>
<translation id="8134994873729925007">Impossible de trouver l'<ph name="BEGIN_ABBR" />adresse DNS<ph name="END_ABBR" /> du serveur <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Votre ordinateur s'est mis en veille.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Contactez votre administrateur réseau si vous n'êtes pas sûr de vous.</translation>
<translation id="8293206222192510085">Ajouter aux favoris</translation>
<translation id="8294431847097064396">Source</translation>
+<translation id="8298115750975731693">Pour utiliser ce réseau Wi-Fi (<ph name="WIFI_NAME" />), il est possible que vous deviez vous rendre sur la page <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Échec de la traduction en raison d'un problème de connexion réseau</translation>
<translation id="8332188693563227489">L'accès à <ph name="HOST_NAME" /> a été refusé</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Récemment fermés</translation>
<translation id="8874824191258364635">Saisissez un numéro de carte valide</translation>
<translation id="8876793034577346603">Échec de l'analyse de la configuration du réseau.</translation>
-<translation id="8889402386540077796">Teinte</translation>
<translation id="8891727572606052622">Mode proxy non valide.</translation>
<translation id="889901481107108152">Désolé, cette fonctionnalité expérimentale n'est pas disponible pour votre plate-forme.</translation>
<translation id="8903921497873541725">Zoom avant</translation>
<translation id="8931333241327730545">Voulez-vous enregistrer cette carte dans votre compte Google ?</translation>
<translation id="8932102934695377596">Votre horloge est en retard</translation>
+<translation id="893332455753468063">Ajouter un nom</translation>
<translation id="8938939909778640821">Cartes de crédit et cartes prépayées acceptées</translation>
+<translation id="8957210676456822347">Autorisation du portail captif</translation>
<translation id="8971063699422889582">Le certificat du serveur a expiré.</translation>
-<translation id="8986494364107987395">Envoyer automatiquement les statistiques d'utilisation et les rapports d'erreur à Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Le site Web que vous allez ouvrir contient des programmes dangereux</translation>
<translation id="8997023839087525404">Le certificat présenté par le serveur n'a pas été communiqué au public. Selon les règles de transparence des certificats, certains certificats doivent obligatoirement être communiqués publiquement pour garantir qu'ils sont dignes de confiance et qu'ils protègent contre les individus malveillants.</translation>
<translation id="9001074447101275817">Le proxy <ph name="DOMAIN" /> nécessite un nom d'utilisateur et un mot de passe.</translation>
<translation id="9005998258318286617">Échec de chargement du document PDF.</translation>
+<translation id="9008201768610948239">Ignorer</translation>
<translation id="901974403500617787">Seul le propriétaire suivant peut définir les options qui s'appliquent à tout le système : <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Adresse de facturation de la carte obligatoire</translation>
<translation id="9020542370529661692">Cette page a été traduite en <ph name="TARGET_LANGUAGE" />.</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Vous avez tenté de contacter <ph name="DOMAIN" />, mais le certificat présenté par le serveur est incorrect.</translation>
<translation id="9050666287014529139">Phrase secrète</translation>
<translation id="9065203028668620118">Modifier</translation>
-<translation id="9068849894565669697">Sélectionner couleur</translation>
<translation id="9069693763241529744">Bloqué par une extension</translation>
<translation id="9076283476770535406">Il est possible qu'il comporte du contenu réservé aux adultes</translation>
<translation id="9078964945751709336">Veuillez fournir d'autres informations</translation>
+<translation id="9080712759204168376">Récapitulatif de la commande</translation>
<translation id="9103872766612412690">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 Chromium 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>
+<translation id="9106062320799175032">Ajouter une adresse de facturation</translation>
+<translation id="910908805481542201">M'aider à régler le problème</translation>
+<translation id="9128870381267983090">Connexion au réseau</translation>
<translation id="9137013805542155359">Afficher l'original</translation>
<translation id="9137248913990643158">Veuillez démarrer Chrome et vous connecter à votre compte avant d'utiliser cette application</translation>
<translation id="9148507642005240123">&amp;Annuler la modification</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utilise un protocole incompatible.</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="9215416866750762878">Une application empêche Chrome de se connecter à ce site de manière sécurisée</translation>
<translation id="9219103736887031265">Images</translation>
<translation id="933612690413056017">Aucune connexion Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Aucun}=1{1 élément}one{# élément}other{# éléments}}</translation>
<translation id="981121421437150478">Hors connexion</translation>
<translation id="988159990683914416">Build de développement</translation>
+<translation id="989988560359834682">Modifier l'adresse</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Le logiciel "<ph name="SOFTWARE_NAME" />" n'a pas été installé correctement sur votre ordinateur ou sur le réseau :
+ &lt;ul&gt;
+ &lt;li&gt;Essayez de désinstaller ou de désactiver "<ph name="SOFTWARE_NAME" />".&lt;/li&gt;
+ &lt;li&gt;Essayez de vous connecter à un autre réseau.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index 7a3b1129791..5e00364df2d 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">ડેસ્કટૉપ બુકમાર્ક્સ</translation>
<translation id="1074497978438210769">સુરક્ષિત નથી</translation>
<translation id="1080116354587839789">પહોળાઈ પ્રમાણે ફિટ કરો</translation>
+<translation id="1088860948719068836">કાર્ડ પર નામ ઉમેરો</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> નો હંમેશાં અનુવાદ કરો</translation>
+<translation id="1103778128462718200">બધા સાચવેલા પાસવર્ડ બતાવો…</translation>
<translation id="1107591249535594099">જો ચેક કરેલું હોય, તો ઝડપથી ફોર્મ ભરવા માટે Chrome આ ઉપકરણ પર તમારા કાર્ડની એક કૉપિ સંગ્રહશે.</translation>
<translation id="1111153019813902504">હાલનાં બુકમાર્ક્સ</translation>
<translation id="1113869188872983271">&amp;પુનઃક્રમાંકિત કરવું પૂર્વવત્ કરો</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (સમન્વયિત)</translation>
<translation id="1263231323834454256">વાચન સૂચિ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> એ ક્રેશ રિપોર્ટ કૅપ્ચર કરવામાં આવી (હજી સુધી અપલોડ કરવામાં કે અવગણવામાં આવેલ નથી)</translation>
+<translation id="1270502636509132238">પિકઅપ પદ્ધતિ</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> દ્વારા જારી કરાયેલ</translation>
<translation id="1285320974508926690">આ સાઇટનું ક્યારેય ભાષાંતર કરશો નહીં</translation>
<translation id="129553762522093515">તાજેતરમાં બંધ કરેલા</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">કનેક્શનની રાહ જોઈ રહ્યાં છીએ...</translation>
<translation id="153384715582417236">હમણાં માટે બસ આટલું પૂરતું છે</translation>
<translation id="1549470594296187301">આ સુવિધાનો ઉપયોગ કરવા માટે JavaScript સક્ષમ કરેલ હોવી આવશ્યક છે.</translation>
-<translation id="1555130319947370107">વાદળી</translation>
<translation id="1559528461873125649">આવી કોઈ ફાઇલ અથવા નિર્દેશિકા નથી</translation>
<translation id="1583429793053364125">આ વેબપૃષ્ઠ પ્રદર્શિત કરતી વખતે કંઇક ખોટું થયું.</translation>
<translation id="1592005682883173041">સ્થાનિક ડેટા ઍક્સેસ</translation>
<translation id="1594030484168838125">પસંદ કરો</translation>
-<translation id="161042844686301425">સ્યાન</translation>
<translation id="1620510694547887537">કૅમેરો</translation>
<translation id="1629803312968146339">શું તમે ઇચ્છો છો કે Chrome આ કાર્ડ સાચવે?</translation>
<translation id="1639239467298939599">લોડ કરી રહ્યું છે</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">આ સાઇટની મુલાકાત લેવા માટે તમને <ph name="NAME" /> ની પરવાનગીની જરૂર છે</translation>
<translation id="1721424275792716183">* ફીલ્ડ આવશ્યક છે</translation>
+<translation id="1727741090716970331">માન્ય કાર્ડ નંબર ઉમેરો</translation>
<translation id="1728677426644403582">તમે વેબ પૃષ્ઠનો સ્રોત જોઈ રહ્યાં છો</translation>
<translation id="173080396488393970">આ પ્રકારનું કાર્ડ સમર્થિત નથી</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">અનુક્રમાંકન ભૂલ</translation>
<translation id="1974060860693918893">વિગતવાર</translation>
<translation id="1978555033938440688">ફર્મવેયર સંસ્કરણ</translation>
-<translation id="1995859865337580572">કૃપા કરીને તમારું CVC ચકાસો</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{અને 1 વધુ}one{અને # વધુ}other{અને # વધુ}}</translation>
<translation id="2025186561304664664">પ્રોક્સી સ્વતઃ ગોઠવાયેલી પર સેટ છે.</translation>
<translation id="2030481566774242610">શું તમારો અર્થ <ph name="LINK" /> છે?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">પૂર્વવત કરો</translation>
<translation id="20817612488360358">સિસ્ટમ પ્રોક્સી સેટિંગ્સ ઉપયોગમાં લેવા માટે સેટ છે પણ એક સ્પષ્ટ પ્રોક્સી ગોઠવણી પણ ઉલ્લેખિત કરેલી છે.</translation>
<translation id="2086652334978798447">Google દ્વારા સૂચવેલ વ્યક્તિગત કરેલ સામગ્રી મેળવવા માટે, Chrome માં સાઇન ઇન કરો.</translation>
+<translation id="2091887806945687916">ધ્વનિ</translation>
<translation id="2094505752054353250">ડોમેન મેળ ખાતું નથી</translation>
<translation id="2096368010154057602">વિભાગ</translation>
<translation id="2108755909498034140">તમારું કમ્પ્યુટર પુનઃપ્રારંભ કરો</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">અવગણ્યું કારણ કે તે <ph name="POLICY_NAME" /> દ્વારા ઓવરરાઇડ થયું હતું.</translation>
<translation id="2138201775715568214">નજીકના વાસ્તવિક વેબ પૃષ્ઠોને શોધી રહ્યાં છો</translation>
<translation id="213826338245044447">મોબાઇલ બુકમાર્ક્સ</translation>
+<translation id="214556005048008348">ચુકવણી રદ કરો</translation>
<translation id="2147827593068025794">પૃષ્ઠભૂમિ સમન્વયન</translation>
+<translation id="2148613324460538318">કાર્ડ ઉમેરો</translation>
<translation id="2154054054215849342">સમન્વયન તમારા ડોમેન માટે ઉપલબ્ધ નથી.</translation>
<translation id="2154484045852737596">કાર્ડ સંપાદિત કરો</translation>
<translation id="2166049586286450108">સંપૂર્ણ વ્યવસ્થાપક ઍક્સેસ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 સરનામું}one{# સરનામાં}other{# સરનામાં}}</translation>
<translation id="2187317261103489799">શોધો (ડિફૉલ્ટ)</translation>
<translation id="2202020181578195191">એક માન્ય સમાપ્તિ વર્ષ દાખલ કરો</translation>
+<translation id="2209523182407020534">આ ભૂલનું કારણ હોઈ શકે તેવી ઍપ્લિકેશનોમાં ઍન્ટિવાયરસ, ફાયરવૉલ અને વેબ-ફિલ્ટરિંગ અથવા પ્રૉક્સી સૉફ્ટવેરનો સમાવેશ થાય છે.</translation>
<translation id="2212735316055980242">નીતિ મળી નથી</translation>
<translation id="2213606439339815911">પ્રવિષ્ટિઓનું આનયન કરી રહ્યાં છે...</translation>
<translation id="2218879909401188352">હાલમાં હુમલાખોરો <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પર જોખમકારક ઍપ્લિકેશન ઇન્સ્ટૉલ કરી શકે છે જે તમારા ઉપકરણને નુકસાન પહોંચાડે છે, તમારા મોબાઇલ બિલમાં છુપાયેલા ચાર્જ ઉમેરી શકે છે અથવા તમારી વ્યક્તિગત માહિતી ચોરી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">પાછા જાઓ</translation>
<translation id="2503184589641749290">સ્વીકૃત ડેબિટ અને પ્રીપેઇડ કાર્ડ</translation>
<translation id="2515629240566999685">તમારા વિસ્તારમાં સિગ્નલ તપાસીને</translation>
+<translation id="2524461107774643265">વધુ માહિતી ઉમેરો</translation>
+<translation id="2536110899380797252">સરનામું ઉમેરો</translation>
<translation id="2539524384386349900">શોધો</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> એ અમાન્ય પ્રતિસાદ મોકલ્યો.</translation>
<translation id="2556876185419854533">&amp;સંપાદિત કરવું પૂર્વવત્‌ કરો</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">આ સમયે Chromium તમારા કાર્ડની પુષ્ટિ કરવામાં અસમર્થ હતું. કૃપા કરીને પછીથી ફરી પ્રયાસ કરો.</translation>
<translation id="2705137772291741111">આ સાઇટની સાચવેલ (કૅશ કરેલ) કૉપિ વાંચવા યોગ્ય ન હતી.</translation>
<translation id="2709516037105925701">સ્વતઃભરો</translation>
+<translation id="2710942282213947212">તમારા કમ્પ્યુટરમાંનું સૉફ્ટવેર Chromiumને સુરક્ષિત રીતે વેબ સાથે કનેક્ટ થવાથી રોકી રહ્યું છે</translation>
<translation id="2712173769900027643">પરવાનગી માગો</translation>
-<translation id="2713444072780614174">શ્વેત</translation>
<translation id="2720342946869265578">નજીકના</translation>
<translation id="2721148159707890343">વિનંતી સફળ થઇ</translation>
<translation id="2728127805433021124">સર્વરનું પ્રમાણપત્ર એક નબળા હસ્તાક્ષર અલ્ગોરિધમનો ઉપયોગ કરીને હસ્તાક્ષરિત કરેલું છે.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">નેટવર્ક ફેરફાર મળ્યો હતો.</translation>
<translation id="2916038427272391327">અન્ય પ્રોગ્રામ બંધ કરો</translation>
<translation id="2922350208395188000">સર્વરનું પ્રમાણપત્ર તપાસી શકાતું નથી.</translation>
+<translation id="2925673989565098301">વિતરણ પદ્ધતિ</translation>
<translation id="2928905813689894207">બિલિંગનું સરનામું</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> વધુ}}</translation>
<translation id="2941952326391522266">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર <ph name="DOMAIN2" /> નું છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">ખોટો નીતિ પ્રકાર</translation>
<translation id="3032412215588512954">શું તમે આ સાઇટ ફરીથી લોડ કરવા માંગો છો?</translation>
<translation id="3037605927509011580">અરર કંઇક ભુલ થઇ!</translation>
+<translation id="3039538478787849737">કાર્ડને Google પર સાચવીએ?</translation>
<translation id="3041612393474885105">પ્રમાણપત્ર માહિતી</translation>
<translation id="3063697135517575841">આ સમયે Chrome તમારા કાર્ડની પુષ્ટિ કરવામાં અસમર્થ હતું. કૃપા કરીને પછીથી ફરી પ્રયાસ કરો.</translation>
<translation id="3064966200440839136">બાહ્ય ઍપ્લિકેશન મારફતે ચુકવણી કરવા માટે છુપો મોડ છોડી રહ્યાં છીએ. તો ચાલુ રાખીએ?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">અસ્થાયી સર્વર ભૂલ</translation>
<translation id="3154506275960390542">આ પૃષ્ઠમાં એક ફૉર્મ છે, જે કદાચ સુરક્ષિત રીતે સબમિટ નહીં થાય. જે ડેટા તમે મોકલો તેને પરિવહન દરમિયાન અન્ય લોકો જોઈ શકશે અથવા સર્વર જે મેળવે, તે બદલવા માટે હુમલાખોર ફેરફાર કરી શકશે.</translation>
<translation id="3157931365184549694">પુનઃસ્થાપિત કરો</translation>
+<translation id="3162559335345991374">તમે ઉપયોગ કરી રહ્યાં છો તે Wi-Fi ને તેના લોગિન પૃષ્ઠની મુલાકાત લેવાની જરૂર હોઈ શકે છે.</translation>
<translation id="3167968892399408617">તમે છુપા ટેબ્સમાં જુઓ છો તે પૃષ્ઠો તમે તમારા બધા છુપા ટેબ્સ બંધ કરી દો તે પછી તમારા બ્રાઉઝરના ઇતિહાસ, કુકી સ્ટોર અથવા શોધ ઇતિહાસમાં રહેશે નહીં. તમે ડાઉનલોડ કરો છો તે કોઈપણ ફાઇલો અથવા તમે બનાવો છો તે બુકમાર્ક્સ રાખવામાં આવશે.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">આઇલેન્ડ</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">ચુકવણી રદ કરો</translation>
<translation id="3207960819495026254">બુકમાર્ક કરેલ</translation>
+<translation id="3211223744486044430">આગલી વખતે વધુ ઝડપથી ચુકવણી કરવા માટે, આ કાર્ડને તમારા Google એકાઉન્ટ અને આ ઉપકરણ પર સાચવો.</translation>
<translation id="3225919329040284222">સર્વર એક પ્રમાણપત્ર પ્રસ્તુત કરે છે જે બિલ્ટ-ઇન અપેક્ષાઓ સાથે મેળ ખાતું નથી. આ અપેક્ષાઓમાં તમને સુરક્ષિત રાખવા માટે અમુક ચોક્કસ, ઉચ્ચ-સુરક્ષા વેબસાઇટ્સનો સમાવેશ થાય છે.</translation>
<translation id="3226128629678568754">પૃષ્ઠને લોડ કરવા માટે જરૂરી ડેટા ફરીથી સબમિટ કરવા માટે ફરીથી લોડ કરો બટન દબાવો.</translation>
<translation id="3227137524299004712">માઇક્રોફોન</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">કોઈ શોધ પરિણામો મળ્યાં નથી</translation>
<translation id="3305707030755673451">તમારો ડેટા <ph name="TIME" /> ના રોજ તમારા સમન્વયન પાસફ્રેઝ સાથે એન્ક્રિપ્ટ કરવામાં આવ્યો હતો. સમન્વયન શરૂ કરવા માટે તે દાખલ કરો.</translation>
<translation id="3320021301628644560">બિલિંગ સરનામું ઉમેરો</translation>
-<translation id="3329013043687509092">સંતૃપ્તતા</translation>
<translation id="333371639341676808">આ પૃષ્ઠને વધારાનાં સંવાદો બનાવવાથી રોકો.</translation>
<translation id="3338095232262050444">સુરક્ષિત</translation>
<translation id="3340978935015468852">સેટિંગ્સ</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ક્લાઇન્ટ ID:</translation>
<translation id="3391030046425686457">વિતરણ માટેનું સરનામું</translation>
<translation id="3395827396354264108">પિકઅપ પદ્ધતિ</translation>
+<translation id="3399952811970034796">વિતરણ માટેનું સરનામું</translation>
<translation id="3422248202833853650">મેમરી ખાલી કરવા માટે અન્ય પ્રોગ્રામથી બહાર નીકળવાનો પ્રયાસ કરો.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> હાલમાં પહોંચવા યોગ્ય નથી.</translation>
<translation id="3427092606871434483">મંજૂરી આપો (ડિફૉલ્ટ)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> એ ક્રેશ રિપોર્ટ કૅપ્ચર કરી અને <ph name="UPLOAD_TIME" /> એ અપલોડ કર્યો હતો</translation>
<translation id="3681007416295224113">પ્રમાણપત્ર માહિતી</translation>
<translation id="3690164694835360974">લોગિન સુરક્ષિત નથી</translation>
+<translation id="3704162925118123524">તમે ઉપયોગમાં લઈ રહ્યાં છો તે નેટવર્ક માટે, તમારે તેના લોગિન પૃષ્ઠની મુલાકાત લેવાની જરૂર હોઈ શકે છે.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">લોડ કરી રહ્યું છે...</translation>
<translation id="3712624925041724820">લાઇસેંસીસ પૂર્ણ</translation>
<translation id="3714780639079136834">મોબાઇલ ડેટા અથવા Wi-Fi ચાલુ કરીને</translation>
+<translation id="3715597595485130451">Wi-Fi થી કનેક્ટ કરો</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />પ્રોક્સી, ફાયરવોલ અને DNS ગોઠવણી તપાસીને<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">જો તમે તમારી સુરક્ષાના જોખમોને સમજો છો, તો તમે જોખમી પ્રોગ્રામ્સ દૂર કરી દેવામાં આવે તે પહેલાં <ph name="BEGIN_LINK" />આ અસલામત સાઇટની મુલાકાત<ph name="END_LINK" /> લઈ શકો છો.</translation>
<translation id="3739623965217189342">તમે કૉપિ કરેલ લિંક</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;ઉમેરવું પૂર્વવત્ કરો</translation>
<translation id="404928562651467259">ચેતવણી</translation>
<translation id="4058922952496707368">કી "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">માન્ય સરનામું ઉમેરો</translation>
<translation id="4072486802667267160">તમારા ઑર્ડરની પ્રક્રિયા કરતી વખતે એક ભૂલ આવી હતી. કૃપા કરીને ફરીથી પ્રયાસ કરો.</translation>
<translation id="4075732493274867456">ક્લાઇન્ટ અને સર્વર સામાન્ય SSL પ્રોટોકોલ સંસ્કરણ અથવા સાઇફર સ્યૂટનું સમર્થન કરતાં નથી.</translation>
<translation id="4079302484614802869">પ્રોક્સી ગોઠવણી .pac સ્ક્રિપ્ટ URL નો ઉપયોગ કરવા માટે સેટ છે, નિયત પ્રોક્સી સર્વર્સ માટે નહીં.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">ઉપકરણ અનુક્ર્માંક નંબર અમાન્ય છે</translation>
<translation id="410351446219883937">ઑટોપ્લે</translation>
<translation id="4103763322291513355">બ્લેકલિસ્ટ કરેલા URL ની સૂચિ અને તમારા સિસ્ટમ વ્યવસ્થાપક દ્વારા લાગુ અન્ય નીતિઓ જોવા માટે &lt;strong&gt;chrome://policy&lt;/strong&gt; ની મુલાકાત લો.</translation>
-<translation id="4115378294792113321">કિરમજી</translation>
<translation id="4116663294526079822">હંમેશા આ સાઇટ પર મંજૂરી આપો</translation>
<translation id="4117700440116928470">નીતિ મર્યાદા સમર્થિત નથી.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 અન્ય}one{# અન્ય}other{# અન્ય}}</translation>
@@ -443,11 +456,12 @@
<translation id="4325863107915753736">લેખ શોધવામાં નિષ્ફળ થયાં</translation>
<translation id="4326324639298822553">તમારી સમાપ્તિ તારીખ તપાસો અને ફરી પ્રયાસ કરો</translation>
<translation id="4331708818696583467">સુરક્ષિત નથી</translation>
-<translation id="4356973930735388585">આ સાઇટ પરના હુમલાખોરો તમારા કમ્પ્યુટર પર તમારી માહિતી (ઉદાહરણ તરીકે, ફોટા, પાસવર્ડ્સ, સંદેશા અને ક્રેડિટ કાર્ડ્સ) ને ચોરી શકે કે કાઢી નાખે તેવા જોખમી પ્રોગ્રામ્સને ઇન્સ્ટોલ કરવાનો પ્રયાસ કરી શકે છે.</translation>
+<translation id="4356973930735388585">આ સાઇટ પરના હુમલાખોરો તમારા કમ્પ્યુટર પર તમારી માહિતી (ઉદાહરણ તરીકે, ફોટો, પાસવર્ડ્સ, સંદેશા અને ક્રેડિટ કાર્ડ્સ) ને ચોરી શકે કે કાઢી નાખે તેવા જોખમી પ્રોગ્રામ્સને ઇન્સ્ટોલ કરવાનો પ્રયાસ કરી શકે છે.</translation>
<translation id="4372948949327679948">અપેક્ષિત <ph name="VALUE_TYPE" /> મૂલ્ય.</translation>
<translation id="4377125064752653719">તમે <ph name="DOMAIN" /> પર પહોંચવાનો પ્રયાસ કર્યો, પણ સર્વર દ્વારા પ્રસ્તુત કરવામાં આવેલું પ્રમાણપત્ર તેના રજૂકર્તા દ્વારા જ રદ કરવામાં આવ્યું છે. આનો અર્થ છે કે સર્વરે પ્રસ્તુત કરેલા સુરક્ષા પ્રમાણપત્રો પૂર્ણપણે વિશ્વસનીય નથી. તમે કોઈ હુમલાખોર જોડે વાત કરતા હોઈ શકો છો.</translation>
<translation id="4394049700291259645">અક્ષમ કરો</translation>
<translation id="4406896451731180161">શોધ પરિણામો</translation>
+<translation id="4415426530740016218">પિકઅપ માટેનું સરનામું</translation>
<translation id="4424024547088906515">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર Chrome દ્વારા વિશ્વસનીય નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> એ તમારું લોગિન પ્રમાણપત્ર સ્વીકાર્યું ન હતું અથવા કદાચ કોઈ એક પ્રદાન કરવામાં આવ્યું નથી.</translation>
<translation id="443673843213245140">પ્રોક્સીનો ઉપયોગ અક્ષમ કરેલો છે પણ એક સ્પષ્ટ પ્રોક્સી ગોઠવણી ઉલ્લેખિત છે.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">ફ્લેશ</translation>
<translation id="4558551763791394412">તમારા એક્સ્ટેન્શન્સને અક્ષમ કરવાનો પ્રયાસ કરો.</translation>
<translation id="457875822857220463">વિતરણ</translation>
+<translation id="4582800630050655161">તમે તમારા Google એકાઉન્ટનો ઍક્સેસ ગુમાવી શકો છો અથવા તમને ઓળખ ચોરીનો અનુભવ થઈ શકે છે. Chromium તમને હમણાં જ તમારો પાસવર્ડ બદલવાની ભલામણ કરે છે.</translation>
<translation id="4587425331216688090">Chrome માંથી સરનામું દૂર કરીએ?</translation>
<translation id="4592951414987517459">આધુનિક સાઇફર સ્યૂટનો ઉપયોગ કરીને <ph name="DOMAIN" /> સાથેનું તમારું કનેક્શન એન્ક્રિપ્ટ કરાયું છે.</translation>
<translation id="4594403342090139922">&amp;કાઢી નાખવું પૂર્વવત્‌ કરો</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેના સુરક્ષા પ્રમાણપત્રમાં ભૂલો છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
<translation id="4690462567478992370">અમાન્ય પ્રમાણપત્રનો ઉપયોગ કરવાનું બંધ કરો</translation>
+<translation id="4690954380545377795">તમે તમારા Google એકાઉન્ટનો ઍક્સેસ ગુમાવી શકો છો અથવા તમને ઓળખ ચોરીનો અનુભવ થઈ શકે છે. Chrome તમને હમણાં જ તમારો પાસવર્ડ બદલવાની ભલામણ કરે છે.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">તમારું કનેક્શન અવરોધાયું હતું</translation>
<translation id="471880041731876836">તમારી પાસે આ સાઇટની મુલાકાત લેવાની પરવાનગી નથી</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows નેટવર્ક ડાયગ્નોસ્ટિક્સ ચલાવી રહ્યાં છે<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">તમારી ચુકવણી</translation>
<translation id="4726672564094551039">નીતિઓ ફરીથી લોડ કરો</translation>
<translation id="4728558894243024398">પ્લેટફોર્મ</translation>
<translation id="4736825316280949806">Chromium ને પુનઃપ્રારંભ કરો</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">બેકઅપ સ્ટોર કરવું ખરાબ સ્થિતિમાં છે</translation>
<translation id="5023310440958281426">તમારા વ્યવસ્થાપકની નીતિઓ તપાસો</translation>
<translation id="5029568752722684782">કૉપિ સાફ કરો</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" માટેનું રૂટ પ્રમાણપત્ર આવશ્યક છે પરંતુ તે ઇન્સ્ટૉલ કરેલું નથી. આ સમસ્યાના નિવારણ માટે તમારા IT વ્યવસ્થાપકે "<ph name="SOFTWARE_NAME" />" ની ગોઠવણી માટેની સૂચના જોવી જરૂરી છે. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google અનુવાદ વિશે</translation>
<translation id="5039804452771397117">મંજૂરી આપો</translation>
<translation id="5040262127954254034">ગોપનીયતા</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">પ્રયોગો</translation>
<translation id="5205222826937269299">નામ આવશ્યક છે</translation>
<translation id="5222812217790122047">ઇમેઇલ આવશ્યક છે</translation>
+<translation id="522700295135997067">આ સાઇટે હમણાં જ તમારો પાસવર્ડ ચોર્યો હોઈ શકે છે</translation>
+<translation id="5230733896359313003">વિતરણ માટેનું સરનામું</translation>
<translation id="5251803541071282808">મેઘ</translation>
<translation id="5277279256032773186">કાર્ય પર Chrome નો ઉપયોગ કરી રહ્યાં છો? વ્યવસાયો તેમના કર્મચારીઓ માટે Chrome સેટિંગ્સને સંચાલિત કરી શકે છે. વધુ જાણો</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />સૉફ્ટવેરને અસ્થાયીરૂપે અક્ષમ કરવા માટે આ પગલાં અનુસરો જેથી તમે વેબ પર જઈ શકો. તમને વ્યવસ્થાપકના વિશેષાધિકારની જરૂર પડશે.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">આ સાઇટ પરનું તમારું કનેક્શન ખાનગી નથી. કોઈપણ સમયે VR મોડથી બહાર નીકળવા માટે, હેડસેટ દૂર કરો અને પાછળ દબાવો.</translation>
<translation id="5299298092464848405">ભૂલ વિશ્લેષણ નીતિ</translation>
+<translation id="5308380583665731573">કનેક્ટ કરો</translation>
<translation id="5308689395849655368">ક્રેશની જાણ કરવાનું અક્ષમ કર્યું છે.</translation>
<translation id="5317780077021120954">સાચવો</translation>
<translation id="5327248766486351172">નામ</translation>
+<translation id="5332219387342487447">શિપિંગ પદ્ધતિ</translation>
<translation id="5355557959165512791">તમે અત્યારે <ph name="SITE" />ની મુલાકાત લઈ શકતાં નથી કારણ કે તેનું પ્રમાણપત્ર રદબાતલ કરવામાં આવ્યું છે. નેટવર્કમાં ભૂલ આવવી અને હુમલા થવા સામાન્ય રીતે અસ્થાયી હોય છે, તેથી આ પેજ સંભવિત રૂપે થોડા સમય પછી કાર્ય કરશે.</translation>
<translation id="536296301121032821">નીતિ સેટિંગ્સ સ્ટોર કરવામાં નિષ્ફળ થયાં</translation>
<translation id="5386426401304769735">આ સાઇટ માટેની પ્રમાણપત્ર શ્રૃંખલા SHA-1 નો ઉપયોગ કરીને સહી કરેલ પ્રમાણપત્ર ધરાવે છે.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">કંપની, સંસ્થા અથવા શાળા ઇન્ટ્રાનેટ પર આ સાઇટ બાહ્ય વેબસાઇટ જેવું જ URL ધરાવે છે.
<ph name="LINE_BREAK" />
તમારા સિસ્ટમ વ્યવસ્થાપકનો સંપર્ક કરવાનો પ્રયાસ કરો.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> માટે સુરક્ષા કોડ દાખલ કરો. આ કોડ સાચવવામાં આવશે નહીં.</translation>
<translation id="5509780412636533143">સંચાલિત બુકમાર્ક્સ</translation>
<translation id="5510766032865166053">તે કદાચ ખસેડવામાં કે કાઢી નાખવામાં આવી છે</translation>
<translation id="5523118979700054094">નીતિનું નામ</translation>
<translation id="552553974213252141">શું ટેક્સ્ટ ઠીકથી કાઢી હતી?</translation>
<translation id="5540224163453853">વિનંતી કરેલ લેખ શોધી શકાયો નથી.</translation>
+<translation id="5541546772353173584">ઇમેઇલ ઍડ્રેસ ઉમેરો</translation>
<translation id="5544037170328430102"><ph name="SITE" /> પરનું એમ્બેડ કરેલ પૃષ્ઠ આ કહે છે:</translation>
+<translation id="5545756402275714221">તમારા માટે લેખ</translation>
<translation id="5556459405103347317">ફરિથી લોડ કરો</translation>
<translation id="5560088892362098740">સમાપ્તિ તારીખ</translation>
<translation id="5565735124758917034">સક્રિય</translation>
@@ -590,12 +615,13 @@
<translation id="5622887735448669177">શું તમે આ સાઇટ છોડવા માંગો છો?</translation>
<translation id="5629630648637658800">નીતિ સેટિંગ્સ લોડ કરવામાં નિષ્ફળ થયાં</translation>
<translation id="5631439013527180824">અમાન્ય ઉપકરણ સંચાલન ટોકન</translation>
-<translation id="5633066919399395251"><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="5633066919399395251"><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="563324245173044180">ભ્રામક કન્ટેન્ટ અવરોધિત કરી</translation>
<translation id="5646376287012673985">સ્થાન</translation>
<translation id="5659593005791499971">ઇમેઇલ</translation>
<translation id="5669703222995421982">વ્યક્તિગત કરેલ સામગ્રી મેળવો</translation>
<translation id="5675650730144413517">આ પૃષ્ઠ કામ કરી રહ્યું નથી</translation>
+<translation id="5689199277474810259">JSON પર નિકાસ કરો</translation>
<translation id="5710435578057952990">આ વેબસાઇટની ઓળખ ચકાસવામાં આવી નથી.</translation>
<translation id="5719499550583120431">પ્રીપેઇડ કાર્ડ સ્વીકારવામાં આવે છે.</translation>
<translation id="5720705177508910913">વર્તમાન વપરાશકર્તા</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" /> સાથેના તમારા કનેક્શનને ઑબ્સોલિટ સાઇફર સ્યૂટનો ઉપયોગ કરીને એન્ક્રિપ્ટ કરાયું છે.</translation>
<translation id="5813119285467412249">&amp;ઉમેરવું ફરી કરો</translation>
<translation id="5838278095973806738">તમારે આ સાઇટ પર કોઈપણ સંવેદનશીલ માહિતી (ઉદાહરણ તરીકે, પાસવર્ડ્સ અથવા ક્રેડિટ કાર્ડ્સ) દાખલ કરવી જોઈએ નહીં, કારણ કે તે હુમલાખોર દ્વારા ચોરવામાં આવી શકે છે.</translation>
+<translation id="5866257070973731571">ફોન નંબર ઉમેરો</translation>
<translation id="5869405914158311789">આ સાઇટ પર પહોંચી શકાતું નથી</translation>
<translation id="5869522115854928033">સાચવેલા પાસવર્ડ્સ</translation>
<translation id="5872918882028971132">પેરેન્ટ સૂચનો</translation>
<translation id="5893752035575986141">ક્રેડિટ કાર્ડ સ્વીકારવામાં આવે છે.</translation>
-<translation id="5901630391730855834">પીળો</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (સમન્વયિત)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 ઉપયોગમાં છે}one{# ઉપયોગમાં છે}other{# ઉપયોગમાં છે}}</translation>
<translation id="5959728338436674663">જોખમી અ‍ૅપ્લિકેશનો અને સાઇટ્સ શોધવામાં સહાય કરવા માટે Google ને કેટલીક <ph name="BEGIN_WHITEPAPER_LINK" />સિસ્ટમ માહિતી અને પૃષ્ઠ સામગ્રી<ph name="END_WHITEPAPER_LINK" /> આપમેળે મોકલો. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">સંપર્ક માહિતીમાં ફેરફાર કરો</translation>
<translation id="5967867314010545767">ઇતિહાસમાંથી દૂર કરો</translation>
<translation id="5975083100439434680">ઝૂમ ઘટાડો</translation>
+<translation id="597552863672748783">સુરક્ષા કોડની પુષ્ટિ કરો</translation>
<translation id="598637245381783098">ચુકવણી ઍપ્લિકેશન ખોલી શકાતી નથી</translation>
<translation id="5989320800837274978">નિયત પ્રોક્સી સર્વર્સ અથવા .pac સ્ક્રિપ્ટનો URL નો ઉલ્લેખ કરેલો નથી.</translation>
<translation id="5990559369517809815">સર્વર પરની વિનંતિઓને એક્સ્ટેંશન દ્વારા અવરોધિત કરવામાં આવી છે.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{પૃષ્ઠ 1}one{પૃષ્ઠ #}other{પૃષ્ઠ #}}</translation>
-<translation id="6017514345406065928">લીલો</translation>
<translation id="6017850046339264347">હુમલાખોરો <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (સમન્વયિત)</translation>
<translation id="6027201098523975773">એક નામ દાખલ કરો</translation>
<translation id="6040143037577758943">બંધ કરો</translation>
-<translation id="6042308850641462728">વધુ</translation>
<translation id="6047233362582046994">જો તમે તમારી સુરક્ષાના જોખમોને સમજો છો, તો તમે જોખમકારક ઍપ્લિકેશનો દૂર કરતા પહેલા <ph name="BEGIN_LINK" />આ સાઇટની મુલાકાત<ph name="END_LINK" /> લઈ શકો છો.</translation>
<translation id="6047927260846328439">આ કન્ટેન્ટ કદાચ સૉફ્ટવેર ઇન્સ્ટૉલ કરવા માટે અથવા વ્યક્તિગત માહિતી કઢાવવા માટે તમારી સાથે કપટ કરવાનો પ્રયાસ કરી શકે છે. <ph name="BEGIN_LINK" />છતાં પણ બતાવો<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">તમે અત્યારે આ <ph name="SITE" />ની મુલાકાત લઈ શકતાં નથી કારણ કે આ વેબસાઇટ પ્રમાણપત્ર પિનિંગનો ઉપયોગ કરે છે. નેટવર્કમાં ભૂલ આવવી અને હુમલા થવા સામાન્ય રીતે અસ્થાયી હોય છે, તેથી આ પેજ સંભવિત રૂપે થોડા સમય પછી કાર્ય કરશે.</translation>
@@ -697,9 +723,10 @@
<translation id="6569060085658103619">તમે એક્સ્ટેન્શન પૃષ્ઠ જોઈ રહ્યાં છો</translation>
<translation id="6596325263575161958">એન્ક્રિપ્શન વિકલ્પો</translation>
<translation id="662080504995468778">પૃષ્ઠ પર રહો</translation>
+<translation id="6624427990725312378">સંપર્ક માહિતી</translation>
<translation id="6626291197371920147">માન્ય કાર્ડ નંબર ઉમેરો</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> શોધ</translation>
-<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પરના હુમલાખોરો કદાચ હાલમાં તમારા Mac પર જોખમી પ્રોગ્રામ ઇન્સ્ટૉલ કરવાનો પ્રયાસ કરે છે કે જે તમારી માહિતી (ઉદાહરણ તરીકે, ફોટા, પાસવર્ડ, સંદેશા અને ક્રેડિટ કાર્ડ) ચોરી અથવા કાઢી નાખી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પરના હુમલાખોરો કદાચ હાલમાં તમારા Mac પર જોખમી પ્રોગ્રામ ઇન્સ્ટૉલ કરવાનો પ્રયાસ કરે છે કે જે તમારી માહિતી (ઉદાહરણ તરીકે, ફોટો, પાસવર્ડ, સંદેશા અને ક્રેડિટ કાર્ડ) ચોરી અથવા કાઢી નાખી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">આ નીતિ દૂર કરવામાં આવેલી છે.</translation>
<translation id="6657585470893396449">પાસવર્ડ</translation>
<translation id="6671697161687535275">Chromium માંથી ફોર્મ સૂચન દૂર કરીએ?</translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">પહેલાનું</translation>
<translation id="6710594484020273272">&lt;શોધ શબ્દ લખો&gt;</translation>
<translation id="6711464428925977395">પ્રોક્સી સર્વરમાં કંઈક ખોટું થયું છે અથવા તો સરનામું ખોટું છે.</translation>
-<translation id="6727102863431372879">સેટ કરો</translation>
<translation id="674375294223700098">અજ્ઞાત સર્વર પ્રમાણપત્ર ભૂલ.</translation>
<translation id="6753269504797312559">નીતિ મૂલ્ય</translation>
<translation id="6757797048963528358">તમારું ઉપકરણ નિષ્ક્રિય થઈ ગયું હતું.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">પ્રોફાઇલ પાથ</translation>
<translation id="7424977062513257142">આ વેબપૃષ્ઠ પરનું એમ્બેડ કરેલ પૃષ્ઠ આ કહે છે:</translation>
+<translation id="7437289804838430631">સંપર્ક માહિતી ઉમેરો</translation>
<translation id="7441627299479586546">ખોટો નીતિ વિષય</translation>
<translation id="7444046173054089907">આ સાઇટ અવરોધિત છે</translation>
<translation id="7445762425076701745">તમે જે સર્વરથી કનેક્ટ છો તેની ઓળખ સંપૂર્ણ રૂપે માન્ય કરી શકાતી નથી. તમે જે નામનો ઉપયોગ કરીને સર્વરથી કનેક્ટ છો, તે ફક્ત તમારા નેટવર્કની અંતર્ગત જ માન્ય છે, જેના બાહ્ય પ્રમાણપત્ર અધિકારીને માલિકીને માન્ય કરવાની કોઈ રીત નથી. આના પર ધ્યાન આપ્યાં વગર કેટલાક પ્રમાણપત્ર અધિકારીઓ આ નામો માટે પ્રમાણપત્ર બહાર પાડશે, તેથી તમે ઇચ્છિત વેબસાઇટથી કનેક્ટ છો કોઈ હુમલાખોરથી નહીં, તેની ખાતરી કરવાની કોઈ રીત નથી.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">ફોર્વર્ડ કરો</translation>
<translation id="7485870689360869515">કોઈ ડેટા મળ્યો નથી.</translation>
<translation id="7508255263130623398">પરત થયેલ નીતિ ઉપકરણ id ખાલી છે અથવા વર્તમાન ટોકન સાથે મેળ ખાતું નથી</translation>
+<translation id="7511955381719512146">તમે ઉપયોગ કરી રહ્યાં છો તે Wi-Fi ને <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ની મુલાકાત લેવાની જરૂર પડી શકે છે.</translation>
<translation id="7514365320538308">ડાઉનલોડ કરો</translation>
<translation id="7518003948725431193">વેબ સરનામાં માટે કોઈ વેબપેજ મળ્યું નથી: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">આ સાઇટ પરનું તમારું કનેક્શન ખાનગી નથી</translation>
-<translation id="7535087603100972091">મૂલ્ય</translation>
<translation id="7537536606612762813">ફરજિયાત</translation>
<translation id="7542403920425041731">એકવાર તમે પુષ્ટિ કરી લો તે પછી, આ સાઇટ સાથે તમારા કાર્ડની વિગતો શેર કરવામાં આવશે.</translation>
<translation id="7542995811387359312">આપમેળે ક્રેડિટ કાર્ડ ભરણ અક્ષમ કર્યું છે કારણ કે આ ફોર્મ સુરક્ષિત કનેક્શનનો ઉપયોગ કરતું નથી.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર કપટપૂર્વક રજૂ કરવામાં આવેલ હોઈ શકે છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
<translation id="7568593326407688803">આ પૃષ્ઠ<ph name="ORIGINAL_LANGUAGE" />માં છે શું તમે તેને અનુવાદિત કરવા માંગો છો?</translation>
<translation id="7569952961197462199">Chrome માંથી ક્રેડિટ કાર્ડ દૂર કરીએ?</translation>
-<translation id="7569983096843329377">શ્યામ</translation>
<translation id="7578104083680115302">તમે Google સાથે સાચવ્યાં છે તે કાર્ડ્સનો ઉપયોગ કરીને સમગ્ર ઉપકરણોમાં સાઇટ્સ અને ઍપ્લિકેશનો પર ઝડપથી ચુકવણી કરો.</translation>
<translation id="7588950540487816470">વાસ્તવિક વેબ</translation>
<translation id="7592362899630581445">સર્વરનું પ્રમાણપત્ર, નામ નિગ્રહોનું ઉલ્લંઘન કરે છે.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">આ સાઇટ પરના હુમલાખોરો તમને તમારા બ્રાઉઝિંગ અનુભવને નુકસાન પહોંચાડે એવા પ્રોગ્રામ્સ ઇન્સ્ટૉલ કરવા માટે છેતરવાનો પ્રયાસ કરી શકે છે (ઉદાહરણ તરીકે, તમારું હોમપેજ બદલીને અથવા તમે મુલાકાત લો છો તે સાઇટ્સ પર વધુ પડતી જાહેરાતો બતાવીને).</translation>
<translation id="7674629440242451245">શું કૂલ નવી Chrome સુવિધાઓમાં રુચિ ધરાવો છો? chrome.com/dev પર અમારી dev ચૅનલ અજમાવી જુઓ.</translation>
<translation id="7682287625158474539">શિપિંગ</translation>
+<translation id="7699293099605015246">લેખો અત્યારે ઉપલબ્ધ નથી</translation>
<translation id="7701040980221191251">કોઈ નહીં</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> પર આગળ વધો (અસલામત)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">પ્રમાણપત્ર</translation>
<translation id="7716147886133743102">વ્યવસ્થાપક દ્વારા અવરોધિત કરેલ છે</translation>
<translation id="7716424297397655342">કૅશમાંથી આ સાઇટ લોડ કરી શકાતી નથી</translation>
+<translation id="7723047071702270851">કાર્ડમાં ફેરફાર કરો</translation>
<translation id="774634243536837715">જોખમકારક કન્ટેન્ટ અવરોધિત કર્યુ.</translation>
<translation id="7752995774971033316">બિનસંચાલિત</translation>
<translation id="7755287808199759310">તમારા માટે તમારા માતાપિતા તેને અનાવરોધિત કરી શકે છે</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">સરનામું ઉમેરો</translation>
<translation id="777702478322588152">પ્રીફેચર</translation>
<translation id="7791543448312431591">ઉમેરો</translation>
+<translation id="7793553086574152071">આગલી વખતે વધુ ઝડપથી ચુકવણી કરવા માટે, આ કાર્ડને તમારા Google એકાઉન્ટ પર સાચવો.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> પરનાં વેબ પૃષ્ઠ અસ્થાયી ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ સરનામાં પર ખસેડવામાં આવ્યા હોઈ શકે છે.</translation>
<translation id="7800304661137206267">કનેક્શન <ph name="CIPHER" /> નો ઉપયોગ કરીને, સંદેશ ઑથેંટિકેશન માટે <ph name="MAC" /> સાથે અને કી એક્સ્ચેંજ તંત્ર તરીકે <ph name="KX" /> એન્ક્રિપ્ટ કરેલું છે, </translation>
+<translation id="7802523362929240268">સાઇટ કાયદેસર છે</translation>
<translation id="780301667611848630">નહીં, આભાર</translation>
<translation id="7805768142964895445">સ્થિતિ</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome માંથી ફોર્મ સૂચનો દૂર કરીએ?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' માટે <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> મળ્યાં</translation>
+<translation id="782886543891417279">તમે ઉપયોગ કરી રહ્યાં છો તે Wi-Fi (<ph name="WIFI_NAME" />) ને તેના લોગિન પૃષ્ઠની મુલાકાત લેવાની જરૂર હોઈ શકે છે.</translation>
<translation id="785549533363645510">જો કે, તમે અદૃશ્ય નથી. છુપામાં જવું તમારા નિયોક્તા, તમારા ઇન્ટરનેટ સેવા પ્રદાતા અથવા તમે મુલાકાત લો છો તે વેબસાઇટ્સથી તમારા બ્રાઉઝિંગને છુપાવતું નથી.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">ડેબિટ અને પ્રીપેઇડ કાર્ડ સ્વીકારવામાં આવે છે.</translation>
+<translation id="7878562273885520351">તમારા પાસવર્ડ સાથે ચેડાં થઈ શકે છે</translation>
<translation id="7887683347370398519">તમારું CVC તપાસો અને ફરીથી પ્રયાસ કરો</translation>
<translation id="79338296614623784">એક માન્ય ફોન નંબર દાખલ કરો</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">સર્વરનું પ્રમાણપત્ર હજી માન્ય નથી.</translation>
-<translation id="7942349550061667556">લાલ</translation>
<translation id="7947285636476623132">તમારું સમાપ્તિ વર્ષ તપાસો અને ફરી પ્રયાસ કરો</translation>
<translation id="7951415247503192394">(32-બિટ)</translation>
<translation id="7956713633345437162">મોબાઇલ બુકમાર્ક્સ</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">પૂછો (ડિફૉલ્ટ)</translation>
<translation id="8041089156583427627">પ્રતિસાદ મોકલો</translation>
<translation id="8041940743680923270">વૈશ્વિક ડિફોલ્ટનો ઉપયોગ કરો (કહો)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />"ની ગોઠવણી યોગ્ય રીતે કરવામાં આવી નથી. સામાન્ય રીતે "<ph name="SOFTWARE_NAME" />"ને અનઇન્સ્ટૉલ કરવાથી સમસ્યા હલ થઈ જાય છે. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">લેખ જોવામાં નિષ્ફળ થયાં.</translation>
<translation id="8091372947890762290">સક્રિયતા સર્વર પર બાકી છે</translation>
+<translation id="8094917007353911263">તમે ઉપયોગ કરી રહ્યાં છો તે નેટવર્કને <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ની મુલાકાત લેવાની જરૂર પડી શકે છે.</translation>
+<translation id="8103161714697287722">ચુકવણીની પદ્ધતિ</translation>
<translation id="8118489163946903409">ચુકવણી પદ્ધતિ</translation>
+<translation id="8127301229239896662">તમારા કમ્પ્યુટરમાં અથવા નેટવર્ક પર "<ph name="SOFTWARE_NAME" />" યોગ્ય રીતે ઇન્સ્ટૉલ થયું નથી. તમારા IT વ્યવસ્થાપકને આ સમસ્યા હલ કરવાનું કહો.</translation>
<translation id="8131740175452115882">પુષ્ટિ કરો</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> નું સર્વર <ph name="BEGIN_ABBR" />DNS સરનામું<ph name="END_ABBR" /> શોધી શકાયું નથી.</translation>
<translation id="8149426793427495338">તમારું કમ્પ્યુટર નિષ્ક્રિય થઈ ગયું હતું.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">આ શું છે તે ખાતરીપૂર્વક જાણતા ન હો તો તમારા નેટવર્ક વ્યવસ્થાપકનો સંપર્ક કરો.</translation>
<translation id="8293206222192510085">બુકમાર્ક ઉમેરો</translation>
<translation id="8294431847097064396">સ્રોત</translation>
+<translation id="8298115750975731693">તમે ઉપયોગ કરી રહ્યાં છો તે Wi-Fi (<ph name="WIFI_NAME" />) ને <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ની મુલાકાત લેવાની જરૂર પડી શકે છે.</translation>
<translation id="8306404619377842860"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> સાથે ખાનગી કનેક્શન સ્થાપિત કરી શકાતું નથી કારણ કે તમારા ઉપકરણની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) ખોટા છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">નેટવર્ક કનેક્શનમાં સમસ્યાને કારણે ભાષાંતર નિષ્ફળ રહ્યું.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ની ઍક્સેસ નકારાઈ હતી</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">તાજેતરમાં બંધ કરેલા</translation>
<translation id="8874824191258364635">એક માન્ય કાર્ડ નંબર દાખલ કરો</translation>
<translation id="8876793034577346603">નેટવર્ક ગોઠવણી વિશ્લેષિત થવામાં નિષ્ફળ થઇ.</translation>
-<translation id="8889402386540077796">હ્યુ</translation>
<translation id="8891727572606052622">અમાન્ય પ્રોક્સી મોડ.</translation>
<translation id="889901481107108152">માફ કરશો, આ પ્રયોગ તમારા પ્લેટફોર્મ પર ઉપલબ્ધ નથી.</translation>
<translation id="8903921497873541725">ઝૂમ વધારો</translation>
<translation id="8931333241327730545">શું તમે આ કાર્ડને તમારા Google એકાઉન્ટમાં સાચવવા માગો છો?</translation>
<translation id="8932102934695377596">તમારી ઘડિયાળ પાછળ છે</translation>
+<translation id="893332455753468063">નામ ઉમેરો</translation>
<translation id="8938939909778640821">સ્વીકૃત ક્રેડિટ અને પ્રીપેઇડ કાર્ડ</translation>
+<translation id="8957210676456822347">કૅપ્ટિવ પોર્ટલ અધિકૃતતા</translation>
<translation id="8971063699422889582">સર્વરના પ્રમાણપત્રની સમયસીમા સમાપ્ત થઈ છે.</translation>
-<translation id="8986494364107987395">ઉપયોગિતા આંકડાઓ અને ક્રેશ રિપોર્ટ્સ Google ને આપમેળે મોકલો</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">સાઇટમાં આગળ હાનિકારક પ્રોગ્રામ્સ છે</translation>
<translation id="8997023839087525404">સર્વરે એવું પ્રમાણપત્ર પ્રસ્તુત કર્યું કે જે પ્રમાણપત્ર પારદર્શિતા નીતિનો ઉપયોગ કરીને સાર્વજનિક રીતે જાહેર કર્યું ન હતું. આ કેટલાક પ્રમાણપત્રો માટે એ ખાતરી કરવા હેતુ આવશ્યક છે કે તેઓ વિશ્વસનીય છે અને હુમલાખારો સામે રક્ષણ કરે છે.</translation>
<translation id="9001074447101275817">પ્રોક્સી <ph name="DOMAIN" /> ને વપરાશકર્તાનામ અને પાસવર્ડની જરૂર છે.</translation>
<translation id="9005998258318286617">PDF દસ્તાવેજ લોડ કરવામાં નિષ્ફળ થયાં.</translation>
+<translation id="9008201768610948239">અવગણો</translation>
<translation id="901974403500617787">ધ્વજો કે જે સિસ્ટમ-વ્યાપી લાગુ છે તે ફક્ત માલિક દ્વારા જ સેટ કરી શકાય છે: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">કાર્ડનું બિલિંગ સરનામું આવશ્યક છે</translation>
<translation id="9020542370529661692">આ પૃષ્ઠનો <ph name="TARGET_LANGUAGE" /> માં અનુવાદ કરવામાં આવ્યો છે</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">તમે <ph name="DOMAIN" /> સુધી પહોંચવાનો પ્રયાસ કર્યો, પરંતુ સર્વરે અમાન્ય પ્રમાણપત્ર પ્રસ્તુત કર્યું. </translation>
<translation id="9050666287014529139">પાસફ્રેઝ</translation>
<translation id="9065203028668620118">સંપાદન</translation>
-<translation id="9068849894565669697">રંગ પસંદ કરો</translation>
<translation id="9069693763241529744">એક્સ્ટેન્શન દ્વારા અવરોધિત કરેલ છે</translation>
<translation id="9076283476770535406">તેમાં વયસ્ક સામગ્રી હોઈ શકે છે</translation>
<translation id="9078964945751709336">વધુ માહિતી આવશ્યક</translation>
+<translation id="9080712759204168376">ઑર્ડરનો સારાંશ</translation>
<translation id="9103872766612412690"><ph name="SITE" /> સામાન્ય રીતે તમારી માહિતીને સુરક્ષિત રાખવા માટે એન્ક્રિપ્શનનો ઉપયોગ કરે છે. જ્યારે આ સમયે Chromium દ્વારા <ph name="SITE" /> થી કનેક્ટ કરવાનો પ્રયાસ થયો, ત્યારે વેબસાઇટે અસામાન્ય અને ખોટા ઓળખાણપત્રોને પાછા મોકલ્યાં. આવું ત્યારે થઇ શકે જ્યારે કોઈ હુમલાખોર <ph name="SITE" /> હોવાનો ડોળ કરવાનો પ્રયાસ કરી રહ્યો હોય અથવા કોઈ Wi-Fi સાઇન-ઇન સ્ક્રીને કનેક્શનમાં વિક્ષેપ પાડ્યો હોય. તમારી માહિતી હજી પણ સુરક્ષિત છે કારણ કે Chromium એ કોઈપણ ડેટા વિનિમય થાય તે પહેલાં જ કનેક્શન રોકી દીધું.</translation>
+<translation id="9106062320799175032">બિલિંગ સરનામું ઉમેરો</translation>
+<translation id="910908805481542201">આને સુધારવામાં મારી સહાય કરો</translation>
+<translation id="9128870381267983090">નેટવર્કથી કનેક્ટ કરો</translation>
<translation id="9137013805542155359">મૂળ બતાવો</translation>
<translation id="9137248913990643158">આ ઍપ્લિકેશનનો ઉપયોગ કરતાં પહેલાં કૃપા કરીને Chrome ને પ્રારંભ કરો અને સાઇન ઇન કરો.</translation>
<translation id="9148507642005240123">&amp;સંપાદિત કરવું પૂર્વવત્‌ કરો</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" />, એક અસમર્થિત પ્રોટોકોલનો ઉપયોગ કરે છે.</translation>
<translation id="9205078245616868884">તમારો ડેટા તમારા સમન્વયન પાસફ્રેઝ સાથે એન્ક્રિપ્ટ કરવામાં આવ્યો છે. સમન્વયન શરૂ કરવા માટે તે દાખલ કરો.</translation>
<translation id="9207861905230894330">લેખ ઉમેરવામાં નિષ્ફળ થયાં.</translation>
+<translation id="9215416866750762878">કોઈ ઍપ્લિકેશન Chromeને આ સાઇટ સાથે સુરક્ષિત રીતે કનેક્ટ થવાથી અટકાવી રહી છે</translation>
<translation id="9219103736887031265">છબીઓ</translation>
<translation id="933612690413056017">કોઈ ઇન્ટરનેટ કનેક્શન નથી</translation>
<translation id="933712198907837967">ડાઇનર્સ ક્લબ</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{કોઈ નહીં}=1{1 આઇટમ}one{# આઇટમ}other{# આઇટમ}}</translation>
<translation id="981121421437150478">ઑફલાઇન</translation>
<translation id="988159990683914416">વિકાસકર્તા બિલ્ડ</translation>
+<translation id="989988560359834682">સરનામું સંપાદિત કરો</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">તમારા કમ્પ્યુટરમાં અથવા નેટવર્ક પર "<ph name="SOFTWARE_NAME" />" યોગ્ય રીતે ઇન્સ્ટૉલ થયું નથી:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />"ને અનઇન્સ્ટૉલ કે બંધ કરવાનો પ્રયાસ કરો&lt;/li&gt;
+ &lt;li&gt;બીજા નેટવર્ક સાથે કનેક્ટ કરવાનો પ્રયાસ કરો&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index d04ed52c226..048367a383a 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">डेस्कटॉप बुकमार्क</translation>
<translation id="1074497978438210769">सुरक्षित नहीं है</translation>
<translation id="1080116354587839789">चौड़ाई में फ़िट करें</translation>
+<translation id="1088860948719068836">कार्ड पर नाम जोड़ें</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> का हमेशा अनुवाद करें</translation>
+<translation id="1103778128462718200">सेव किए गए सभी पासवर्ड दिखाएं...</translation>
<translation id="1107591249535594099">चेक किए होने पर, अधिक तेज़ फ़ॉर्म भरने के लिए Chrome इस डिवाइस पर आपके कार्ड की कॉपी संग्रहित कर लेगा.</translation>
<translation id="1111153019813902504">हाल के बुकमार्क</translation>
<translation id="1113869188872983271">&amp;पुन: क्रमित करना वापस लाएं</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (सिंक किए गए)</translation>
<translation id="1263231323834454256">पठन सूची</translation>
<translation id="1264126396475825575">ख़राबी रिपोर्ट <ph name="CRASH_TIME" /> पर कैप्चर की गई (अभी तक अपलोड नहीं की गई या उसे अनदेखा किया गया)</translation>
+<translation id="1270502636509132238">पिकअप का तरीका</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> ने जारी किया है</translation>
<translation id="1285320974508926690">कभी भी इस साइट का अनुवाद न करें</translation>
<translation id="129553762522093515">हाल ही में बंद किए गए</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">कनेक्‍शन के इंतज़ार में…</translation>
<translation id="153384715582417236">अभी के लिए हो गया</translation>
<translation id="1549470594296187301">इस सुविधा का उपयोग करने के लिए JavaScript को सक्षम किया जाना चाहिए.</translation>
-<translation id="1555130319947370107">नीला</translation>
<translation id="1559528461873125649">कोई ऐसी फ़ाइल या निर्देशिका नहीं है</translation>
<translation id="1583429793053364125">यह वेबपेज प्रदर्शित करते समय कोई समस्या हुई.</translation>
<translation id="1592005682883173041">स्थानीय डेटा एक्सेस</translation>
<translation id="1594030484168838125">चुनें</translation>
-<translation id="161042844686301425">स्यान</translation>
<translation id="1620510694547887537">कैमरा</translation>
<translation id="1629803312968146339">क्या आप चाहते हैं कि Chrome इस कार्ड को सहेजे?</translation>
<translation id="1639239467298939599">लोड हो रहा है</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">आपको <ph name="NAME" /> से इस साइट पर जाने की अनुमति लेनी होगी</translation>
<translation id="1721424275792716183">* फ़ील्ड ज़रूरी है</translation>
+<translation id="1727741090716970331">मान्य कार्ड नंबर जोड़ें</translation>
<translation id="1728677426644403582">आप एक वेब पेज का स्रोत देख रहे हैं</translation>
<translation id="173080396488393970">इस तरह का कार्ड काम नहीं करता</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">क्रमबद्ध करने में गड़बड़ी</translation>
<translation id="1974060860693918893">उन्नत</translation>
<translation id="1978555033938440688">फ़र्मवेयर वर्शन</translation>
-<translation id="1995859865337580572">कृपया अपने CVC की पुष्टि करें</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{और 1 अधिक}one{और # अधिक}other{और # अधिक}}</translation>
<translation id="2025186561304664664">प्रॉक्‍सी स्‍वत: कॉन्‍फ़‍िगर पर सेट है.</translation>
<translation id="2030481566774242610">क्या आप मतलब <ph name="LINK" /> से है?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">वापस लाएं</translation>
<translation id="20817612488360358">सिस्‍टम प्रॉक्‍सी सेटिंग उपयोग किए जाने के लिए सेट हैं लेकिन कोई स्पष्‍ट प्रॉक्‍सी कॉन्फ़िगरेशन भी निर्दिष्ट है.</translation>
<translation id="2086652334978798447">Google द्वारा सुझाई गई वैयक्तिकृत सामग्री प्राप्त करने के लिए, Chrome में प्रवेश करें.</translation>
+<translation id="2091887806945687916">ध्वनि</translation>
<translation id="2094505752054353250">डोमेन का गलत-मिलान</translation>
<translation id="2096368010154057602">विभाग</translation>
<translation id="2108755909498034140">अपना कंप्यूटर फिर से चालू करें</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">ध्यान नहीं दिया गया क्योंकि यह <ph name="POLICY_NAME" /> द्वारा ओवरराइड की गई थी.</translation>
<translation id="2138201775715568214">आस-पास के जीते-जागते वेब पृष्‍ठ खोजे जा रहे हैं</translation>
<translation id="213826338245044447">मोबाइल बुकमार्क</translation>
+<translation id="214556005048008348">भुगतान न करें</translation>
<translation id="2147827593068025794">पृष्ठभूमि समन्वयन</translation>
+<translation id="2148613324460538318">कार्ड जोड़ें</translation>
<translation id="2154054054215849342">आपके डोमेन के लिए सिंक करने की सुविधा उपलब्‍ध नहीं है</translation>
<translation id="2154484045852737596">कार्ड संपादित करें</translation>
<translation id="2166049586286450108">पूर्ण व्यवस्थापकीय एक्सेस</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 पता}one{# पते}other{# पते}}</translation>
<translation id="2187317261103489799">पता लगाएं (डिफ़ॉल्ट)</translation>
<translation id="2202020181578195191">खत्म होने का मान्य वर्ष डालें</translation>
+<translation id="2209523182407020534">जिन ऐप्लिकेशन से यह गड़बड़ी हो सकती है उनमें एंटीवायरस, फ़ायरवॉल और वेब-फ़िल्टरिंग या प्रॉक्सी सॉफ़्टवेयर शामिल हैं.</translation>
<translation id="2212735316055980242">नीति नहीं मिली</translation>
<translation id="2213606439339815911">प्रविष्टियां फ़ेच की जा रही हैं...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर इस समय मौजूद हमलावर ऐसे खतरनाक ऐप्लिकेशन इंस्टॉल कर सकते हैं जो आपके डिवाइस को नुकसान पहुंचा सकते हैं और आपके मोबाइल बिल में अनजाने खर्चे जोड़ सकते हैं या आपकी व्‍यक्‍तिगत जानकारी चुरा सकते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">वापस जाएं</translation>
<translation id="2503184589641749290">स्वीकृत डेबिट और प्रीपेड कार्ड</translation>
<translation id="2515629240566999685">अपने क्षेत्र में सिग्नल की जांच करें</translation>
+<translation id="2524461107774643265">ज़्यादा जानकारी जोड़ें</translation>
+<translation id="2536110899380797252">पता जोड़ें</translation>
<translation id="2539524384386349900">पता लगाएं</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ने एक अमान्य प्रतिसाद भेजा है.</translation>
<translation id="2556876185419854533">&amp;संपादन वापस लाएं</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">क्रोमियम इस समय आपके कार्ड की पुष्टि नहीं कर सका. कृपया बाद में पुन: प्रयास करें.</translation>
<translation id="2705137772291741111">इस साइट की सहेजी गई (संचित) कॉपी पढ़ने योग्य नहीं थी.</translation>
<translation id="2709516037105925701">ऑटोमैटिक भरना</translation>
+<translation id="2710942282213947212">आपके कंप्यूटर पर मौजूद सॉफ़्टवेयर क्रोमियम को सुरक्षित तरीके से वेब से जुड़ने से रोक रहा है</translation>
<translation id="2712173769900027643">अनुमति मांगें</translation>
-<translation id="2713444072780614174">सफ़ेद</translation>
<translation id="2720342946869265578">आस-पास</translation>
<translation id="2721148159707890343">अनुरोध सफल रहा</translation>
<translation id="2728127805433021124">सर्वर का प्रमाणपत्र एक कमज़ोर हस्ताक्षर एल्गोरिदम का उपयोग करके हस्ताक्षरित किया गया है.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">नेटवर्क में बदलाव का पता चला.</translation>
<translation id="2916038427272391327">दूसरे प्रोग्राम बंद करें</translation>
<translation id="2922350208395188000">सर्वर प्रमाणपत्र की जांच नहीं की जा सकती.</translation>
+<translation id="2925673989565098301">डिलीवरी का तरीका</translation>
<translation id="2928905813689894207">बिलिंग पता</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}}</translation>
<translation id="2941952326391522266">यह सर्वर यह प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र <ph name="DOMAIN2" /> की ओर से है. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">गलत नीति प्रकार</translation>
<translation id="3032412215588512954">क्या आप इस साइट को फिर से लोड करना चाहते हैं?</translation>
<translation id="3037605927509011580">हे भगवान!</translation>
+<translation id="3039538478787849737">Google में कार्ड सेव करें?</translation>
<translation id="3041612393474885105">प्रमाणपत्र जानकारी</translation>
<translation id="3063697135517575841">Chrome इस समय आपके कार्ड की पुष्टि नहीं कर सका. कृपया बाद में पुन: प्रयास करें.</translation>
<translation id="3064966200440839136">किसी बाहरी ऐप्लिकेशन के ज़रिए भुगतान करने के लिए गुप्त मोड छोड़ रहे हैं. जारी रखना चाहते हैं?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">अस्थायी सर्वर गड़बड़ी</translation>
<translation id="3154506275960390542">इस पेज में ऐसा फ़ॉर्म शामिल है, जो सुरक्षित रूप से सबमिट नहीं किया जा सकता है. ट्रांज़िट में होने के दौरान आपके भेजे जाने वाले डेटा को दूसरे लोग देख सकते हैं या सर्वर को मिलने वाली सामग्री में बदलाव करने के लिए कोई आक्रमणकर्ता उसे संशोधित कर सकता है.</translation>
<translation id="3157931365184549694">पुनर्स्थापित करें</translation>
+<translation id="3162559335345991374">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
<translation id="3167968892399408617">आपके द्वारा गुप्त टैब में देखे जाने वाले पेज, आपके द्वारा अपने सभी गुप्त टैब बंद कर देने के बाद आपके ब्राउज़र के इतिहास, कुकी संग्रह, या खोज इतिहास में नहीं रहेंगे. आपके द्वारा डाउनलोड की गईं सभी फ़ाइलें या बनाए गए बुकमार्क रख लिए जाएंगे.</translation>
<translation id="3169472444629675720">तलाश करें</translation>
<translation id="3174168572213147020">द्वीप</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">भुगतान रद्द करें</translation>
<translation id="3207960819495026254">बुकमार्क किया गया</translation>
+<translation id="3211223744486044430">अगली बार तेज़ी से भुगतान करने के लिए, इस कार्ड को अपने Google खाते में और इस डिवाइस में सेव करें.</translation>
<translation id="3225919329040284222">सर्वर द्वारा कोई प्रमाणपत्र प्रस्‍तुत किया गया, जो बिल्‍ट-इन अपेक्षाओं से मिलान नहीं करता. इन अपेक्षाओं को आपकी सुरक्षा करने के लिए कुछ, उच्‍च-सुरक्षा वेबसाइटों के लिए शामिल किया गया है.</translation>
<translation id="3226128629678568754">पेज को लोड करने के लिए आवश्यक डेटा पुन: सबमिट करने के लिए पुन: लोड करें बटन दबाएं.</translation>
<translation id="3227137524299004712">माइक्रोफ़ोन</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">कोई खोज परिणाम नहीं मिला</translation>
<translation id="3305707030755673451">आपका डेटा आपके समन्वयन पासफ़्रेज़ के साथ <ph name="TIME" /> को एन्क्रिप्ट किया गया था. समन्वयन शुरू करने के लिए इसे डालें.</translation>
<translation id="3320021301628644560">बिलिंग पता जोड़ें</translation>
-<translation id="3329013043687509092">संतृप्तता</translation>
<translation id="333371639341676808">इस पेज को अतिरिक्त ब्लॉग बनाने से रोकें.</translation>
<translation id="3338095232262050444">सुरक्षित</translation>
<translation id="3340978935015468852">सेटिंग</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">क्लाइंट आईडी:</translation>
<translation id="3391030046425686457">वितरण पता</translation>
<translation id="3395827396354264108">पिकअप का तरीका</translation>
+<translation id="3399952811970034796">डिलीवरी का पता</translation>
<translation id="3422248202833853650">जगह खाली करने के लिए दूसरे प्रोग्राम से बाहर निकलकर देखें.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> वर्तमान में पहुंच योग्य नहीं है.</translation>
<translation id="3427092606871434483">अनुमति दें (डिफ़ॉल्ट)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">ख़राबी रिपोर्ट <ph name="CRASH_TIME" /> पर कैप्चर की गई, <ph name="UPLOAD_TIME" /> पर अपलोड की गई</translation>
<translation id="3681007416295224113">प्रमाणपत्र जानकारी</translation>
<translation id="3690164694835360974">लॉगिन सुरक्षित नहीं है</translation>
+<translation id="3704162925118123524">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड हो रही हैं...</translation>
<translation id="3712624925041724820">लाइसेंस समाप्त हो गए</translation>
<translation id="3714780639079136834">मोबाइल डेटा या वाई-फ़ाई चालू करें</translation>
+<translation id="3715597595485130451">वाई-फ़ाई से कनेक्ट करें</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />प्रॉक्सी, फायरवॉल और DNS कॉन्फ़िगरेशन की जांच करें<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">यदि आप अपनी सुरक्षा में होने वाले जोखिमों को समझते हैं, तो आप खतरनाक प्रोग्राम निकाले जाने से पहले <ph name="BEGIN_LINK" />इस असुरक्षित साइट पर विज़िट<ph name="END_LINK" /> कर सकते हैं.</translation>
<translation id="3739623965217189342">काॅपी किया गया लिंक</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;जोड़ना वापस लाएं</translation>
<translation id="404928562651467259">चेतावनी</translation>
<translation id="4058922952496707368">कुंजी "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">मान्य पता जोड़ें</translation>
<translation id="4072486802667267160">आपका आदेश संसाधित करते समय गड़बड़ी हुई. कृपया फिर से कोशिश करें.</translation>
<translation id="4075732493274867456">क्लाइंट और सर्वर, सामान्य SSL प्रोटोकॉल वर्शन या सिफ़र सुइट का समर्थन नहीं करते हैं.</translation>
<translation id="4079302484614802869">प्रॉक्‍सी कॉन्‍फ़िगरेशन को .pac स्‍क्रिप्‍ट URL का उपयोग करने के लिए सेट किया जाता है, फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर के लिए नहीं.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">डिवाइस की क्रम संख्या अमान्य है</translation>
<translation id="410351446219883937">स्वतः चलाएं</translation>
<translation id="4103763322291513355">काली सूची में डाले गए URL तथा आपके सिस्टम व्यवस्थापक द्वारा लागू की गई अन्य नीतियों को देखने के लिए &lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाएं.</translation>
-<translation id="4115378294792113321">मैजेंटा</translation>
<translation id="4116663294526079822">इस साइट पर हमेशा अनुमति दें</translation>
<translation id="4117700440116928470">नीति क्षेत्र समर्थित नहीं है.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 अन्य}one{# अन्‍य}other{# अन्‍य}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">आपने <ph name="DOMAIN" /> तक पहुंचने का प्रयास किया, लेकिन सर्वर द्वारा प्रस्तुत प्रमाणपत्र को उसके जारीकर्ता द्वारा रद्द कर दिया गया है. इसका अर्थ है कि सर्वर द्वारा प्रस्तुत सुरक्षा प्रमाणिकता पर पूर्णतया विश्वास नहीं करना चाहिए. हो सकता है कि आप किसी हमलावर से बातचीत कर रहे हों.</translation>
<translation id="4394049700291259645">अक्षम करें</translation>
<translation id="4406896451731180161">खोज परिणाम</translation>
+<translation id="4415426530740016218">पिकअप का पता</translation>
<translation id="4424024547088906515">यह सर्वर यह नहीं प्रमाणित कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र Chrome द्वारा विश्वसनीय नहीं है. ऐसा गलत कॉन्फ़िगरेशन या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपका लॉगिन प्रमाणपत्र स्वीकार नहीं किया है या हो सकता है कि प्रमाणपत्र उपलब्ध नहीं कराया गया हो.</translation>
<translation id="443673843213245140">प्रॉक्‍सी का उपयोग अक्षम है लेकिन कोई स्‍पष्ट प्रॉक्‍सी कॉन्फ़िगरेशन निर्दिष्ट किया गया है.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">फ़्लैश</translation>
<translation id="4558551763791394412">अपने एक्सटेंशन अक्षम करके देखें.</translation>
<translation id="457875822857220463">वितरण</translation>
+<translation id="4582800630050655161">आप अपने Google खाते का एक्सेस खो सकते हैं या आपकी पहचान चोरी हो सकती है. Chromium आपको इसी समय अपना पासवर्ड बदलने का सुझाव देता है.</translation>
<translation id="4587425331216688090">Chrome से पता निकालें?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> से आपके कनेक्शन को किसी आधुनिक सिफ़र सुइट का उपयोग करके एन्‍क्रिप्‍ट किया गया है.</translation>
<translation id="4594403342090139922">&amp;हटाना वापस लाएं</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">यह सर्वर यह प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सुरक्षा प्रमाणपत्र में त्रुटियां हैं. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="4690462567478992370">अमान्य प्रमाणपत्र का उपयोग करना बंद करें</translation>
+<translation id="4690954380545377795">आप अपने Google खाते का एक्सेस खो सकते हैं या आपकी पहचान चोरी हो सकती है. Chrome आपको इसी समय अपना पासवर्ड बदलने का सुझाव देता है.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">आपका कनेक्शन बाधित था</translation>
<translation id="471880041731876836">आपको इस साइट पर जाने की अनुमति नहीं है</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवर्क निदान चलाकर देखें<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">आपका भुगतान</translation>
<translation id="4726672564094551039">नीतियां फिर से लोड करें</translation>
<translation id="4728558894243024398">प्लेटफ़ॉर्म</translation>
<translation id="4736825316280949806">क्रोमियम को फिर से शुरू करें</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">बैकिंग संग्रह खराब स्थिति में है</translation>
<translation id="5023310440958281426">अपने व्यवस्थापक की नीतियां देखें</translation>
<translation id="5029568752722684782">स्‍पष्‍ट कॉपी</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" के रूट प्रमाणपत्र की ज़रूरत है लेकिन वह इंस्टॉल नहीं है. यह समस्या ठीक करने के लिए आपके आईटी व्यवस्थापक को "<ph name="SOFTWARE_NAME" />" के कॉन्फ़िगरेशन से जुड़े निर्देशों पर नज़र डालनी चाहिए. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google अनुवाद के बारे में</translation>
<translation id="5039804452771397117">अनुमति दें</translation>
<translation id="5040262127954254034">निजता</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">प्रयोग</translation>
<translation id="5205222826937269299">नाम आवश्यक है</translation>
<translation id="5222812217790122047">ईमेल आवश्यक है</translation>
+<translation id="522700295135997067">शायद इस साइट ने अभी-अभी आपका पासवर्ड चुरा लिया है</translation>
+<translation id="5230733896359313003">शिपिंग पता</translation>
<translation id="5251803541071282808">क्लाउड</translation>
<translation id="5277279256032773186">कार्यस्थल पर Chrome का उपयोग कर रहे हैं? कंपनियां अपने कर्मचारियों के लिए Chrome सेटिंग प्रबंधित कर सकती हैं. और जानें</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />इन चरणों का पालन करके सॉफ़्टवेयर को कुछ समय के लिए अक्षम करें ताकि आप वेब पर जा सकें. आपको व्यावस्थापकीय विशेषाधिकारों की ज़रूरत होगी.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">इस साइट से आपका कनेक्शन निजी नहीं है. VR मोड से किसी भी समय बाहर निकलने के लिए, हेडसेट निकालें और वापस जाएं दबाएं.</translation>
<translation id="5299298092464848405">नीति पार्स करने में गड़बड़ी</translation>
+<translation id="5308380583665731573">कनेक्ट करें</translation>
<translation id="5308689395849655368">क्रैश की रिपोर्ट करना अक्षम कर दिया गया है.</translation>
<translation id="5317780077021120954">सहेजें</translation>
<translation id="5327248766486351172">नाम</translation>
+<translation id="5332219387342487447">शिपिंग का तरीका</translation>
<translation id="5355557959165512791">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि उसका प्रमाणपत्र निरस्त कर दिया गया है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
<translation id="536296301121032821">नीति सेटिंग संग्रहित करने में विफल</translation>
<translation id="5386426401304769735">इस साइट की प्रमाणपत्र श्रृंखला में, SHA-1 का उपयोग करके हस्ताक्षर किया गया प्रमाणपत्र शामिल है.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">कंपनी, संगठन या विद्यालय के इंट्रानेट पर इस साइट का URL एक बाहरी वेबसाइट जैसा है.
<ph name="LINE_BREAK" />
अपने सिस्टम व्यस्थापक से संपर्क करने का प्रयास करें.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> का सुरक्षा कोड डालें. यह कोड सेव नहीं किया जाएगा.</translation>
<translation id="5509780412636533143">प्रबंधित बुकमार्क</translation>
<translation id="5510766032865166053">हो सकता है कि उसे ले जाया गया हो या हटा दिया गया हो.</translation>
<translation id="5523118979700054094">नीति का नाम</translation>
<translation id="552553974213252141">क्या लेख सही तरीके से निकाला गया था?</translation>
<translation id="5540224163453853">अनुरोध किया गया लेख नहीं ढूंढा जा सका.</translation>
+<translation id="5541546772353173584">ईमेल जोड़ें</translation>
<translation id="5544037170328430102"><ph name="SITE" /> पर एम्‍बेड किए गए पृष्‍ठ का कहना है:</translation>
+<translation id="5545756402275714221">आपके लिए लेख</translation>
<translation id="5556459405103347317">पुन: लोड करें</translation>
<translation id="5560088892362098740">समयसीमा समाप्ति दिनांक</translation>
<translation id="5565735124758917034">सक्रिय</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">ईमेल</translation>
<translation id="5669703222995421982">खास आपके लिए बनी सामग्री पाएं</translation>
<translation id="5675650730144413517">यह पेज काम नहीं कर रहा है</translation>
+<translation id="5689199277474810259">JSON में निर्यात करें</translation>
<translation id="5710435578057952990">इस वेबसाइट की पहचान सत्यापित नहीं की गई है.</translation>
<translation id="5719499550583120431">प्रीपेड कार्ड स्वीकार किए जाते हैं.</translation>
<translation id="5720705177508910913">वर्तमान उपयोगकर्ता</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" /> से आपके कनेक्शन को किसी अप्रचलित सिफ़र सुइट का उपयोग करके एन्‍क्रिप्‍ट किया गया है.</translation>
<translation id="5813119285467412249">&amp;जोड़ना फिर से करें</translation>
<translation id="5838278095973806738">आपको इस साइट पर कोई भी संवेदनशील जानकारी (उदाहरण के लिए, पासवर्ड या क्रेडिट कार्ड) नहीं डालनी चाहिए, क्योंकि उसे हमलावर चुरा सकते हैं.</translation>
+<translation id="5866257070973731571">फ़ोन नंबर जोड़ें</translation>
<translation id="5869405914158311789">इस साइट तक नहीं पहुंचा जा सकता</translation>
<translation id="5869522115854928033">सहेजे गए पासवर्ड</translation>
<translation id="5872918882028971132">अभिभावक सुझाव</translation>
<translation id="5893752035575986141">क्रेडिट कार्ड स्वीकार किए जाते हैं.</translation>
-<translation id="5901630391730855834">पीला</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (सिंक किया गया)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 उपयोग में है}one{# उपयोग में हैं}other{# उपयोग में हैं}}</translation>
<translation id="5959728338436674663">Google को कुछ <ph name="BEGIN_WHITEPAPER_LINK" />सिस्टम संबंधी जानकारी और पेज सामग्री<ph name="END_WHITEPAPER_LINK" /> अपने आप भेजें ताकि खतरनाक ऐप्लिकेशन और साइटों का पता लगाने में सहायता मिल सके. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">संपर्क जानकारी में बदलाव करें</translation>
<translation id="5967867314010545767">इतिहास से निकालें</translation>
<translation id="5975083100439434680">ज़ूम आउट</translation>
+<translation id="597552863672748783">सुरक्षा कोड की पुष्टि करें</translation>
<translation id="598637245381783098">भुगतान ऐप्लिकेशन नहीं खोला जा सकता</translation>
<translation id="5989320800837274978">न तो कोई फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर और न ही कोई .pac स्क्रिप्ट URL निर्दिष्ट किए गए हैं.</translation>
<translation id="5990559369517809815">सर्वर से किए गए अनुरोधों को एक्‍सटेंशन द्वारा अवरुद्ध कर दिया गया है.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{पेज 1}one{पेज #}other{पेज #}}</translation>
-<translation id="6017514345406065928">हरा</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (सिंक किए गए)</translation>
<translation id="6027201098523975773">नाम डालें</translation>
<translation id="6040143037577758943">बंद करें</translation>
-<translation id="6042308850641462728">अधिक</translation>
<translation id="6047233362582046994">अगर आप अपनी सुरक्षा में होने वाले जोखिमों को समझते हैं, तो खतरनाक ऐप्लिकेशन निकाले जाने से पहले आप <ph name="BEGIN_LINK" />इस साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
<translation id="6047927260846328439">यह सामग्री आपसे धोखे से सॉफ़्टवेयर इंस्‍टॉल करवाने या व्यक्तिगत जानकारी का खुलासा करवाने की कोशिश कर सकती है. <ph name="BEGIN_LINK" />फिर भी दिखाएं<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि वेबसाइट प्रमाणपत्र पिनिंग का उपयोग करती है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">आप एक एक्सटेंशन पेज देख रहे हैं</translation>
<translation id="6596325263575161958">सुरक्षित तरीका विकल्प</translation>
<translation id="662080504995468778">इसपर रहें</translation>
+<translation id="6624427990725312378">संपर्क जानकारी</translation>
<translation id="6626291197371920147">मान्य कार्ड नंबर जोड़ें</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> खोज</translation>
<translation id="6630809736994426279">इस समय <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपके Mac पर ऐसे खतरनाक प्रोग्राम इंस्टॉल करने की कोशिश कर सकते हैं जो आपकी जानकारी (उदाहरण के लिए, फ़ोटो, पासवर्ड, संदेश और क्रेडिट कार्ड) चुराते हैं या उसे हटा देते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">पिछला</translation>
<translation id="6710594484020273272">&lt;खोज शब्द लिखें&gt;</translation>
<translation id="6711464428925977395">प्रॉक्सी सर्वर के साथ कुछ गलत है या पता गलत है.</translation>
-<translation id="6727102863431372879">सेट करें</translation>
<translation id="674375294223700098">अज्ञात सर्वर प्रमाणपत्र गड़बड़ी.</translation>
<translation id="6753269504797312559">नीति मान</translation>
<translation id="6757797048963528358">आपका डिवाइस निष्क्रिय हो गया है.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">प्रोफ़ाइल पथ</translation>
<translation id="7424977062513257142">इस वेबपृष्‍ठ पर एम्‍बेड किए गए पृष्‍ठ का कहना है:</translation>
+<translation id="7437289804838430631">संपर्क जानकारी जोड़ें</translation>
<translation id="7441627299479586546">गलत नीति विषय</translation>
<translation id="7444046173054089907">यह साइट अवरोधित है</translation>
<translation id="7445762425076701745">जिस सर्वर से आप कनेक्‍ट हैं उसकी पहचान पूर्णत: सत्‍यापित नहीं की जा सकती. आपने केवल आपके नेटवर्क में ही मान्‍य नाम का उपयोग कर किसी सर्वर से कनेक्‍ट किया है, जिसकी मान्‍यता का सत्‍यापन कोई बाह्य प्रमाणपत्र प्राधिकरण नहीं करता है. जैसा कि कुछ प्रमाणपत्र प्राधिकरण इन नामों के लिए प्रमाणपत्र जारी कर देंगे, और इस पर ध्यान नहीं दिया जाएगा कि यह सुनिश्‍चित करने का कोई तरीका नहीं है कि आप नियत वेबसाइट से कनेक्‍ट हैं, न कि किसी आक्रमणकर्ता से.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">आगे भेजें</translation>
<translation id="7485870689360869515">कोई डेटा नहीं मिला</translation>
<translation id="7508255263130623398">वापस लौटाया हुआ नीति डिवाइस आईडी खाली है या उसका मिलान वर्तमान डिवाइस आईडी से नहीं होता है</translation>
+<translation id="7511955381719512146">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
<translation id="7514365320538308">डाउनलोड करें</translation>
<translation id="7518003948725431193">इस वेब पते के लिए कोई वेब पेज नहीं मिला था: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">इस साइट से आपका कनेक्‍शन निजी नहीं है</translation>
-<translation id="7535087603100972091">मान</translation>
<translation id="7537536606612762813">आवश्यक</translation>
<translation id="7542403920425041731">आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ साझा किए जाएंगे.</translation>
<translation id="7542995811387359312">स्वतः क्रेडिट कार्ड भरना अक्षम किया गया है क्योंकि यह फ़ॉर्म किसी सुरक्षित कनेक्शन का उपयोग नहीं करता है.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">यह सर्वर यह प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है इसका सुरक्षा प्रमाणपत्र धोखे से जारी किया गया हो. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="7568593326407688803">यह पृष्ठ<ph name="ORIGINAL_LANGUAGE" />में है क्या आप इसका अनुवाद करना चाहेंगे?</translation>
<translation id="7569952961197462199">Chrome से क्रेडिट कार्ड निकालें?</translation>
-<translation id="7569983096843329377">काला</translation>
<translation id="7578104083680115302">Google के साथ सहेजे गए कार्ड का उपयोग करके डिवाइसों में मौजूद साइटों और ऐप्‍स पर तुरंत भुगतान करें.</translation>
<translation id="7588950540487816470">जीता-जागता वेब</translation>
<translation id="7592362899630581445">सर्वर का प्रमाणपत्र नाम संबंधी प्रतिबंधों का उल्लंघन करता है.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">इस साइट पर मौजूद हमलावर आपके ब्राउज़िंग अनुभव को हानि पहुंचा सकने वाले प्रोग्राम इंस्टॉल करने के लिए आपको भ्रमित कर सकते हैं (उदाहरण के लिए, आपके मुखपृष्ठ को बदलकर या आपकी विज़िट की जा रहीं साइट पर अतिरिक्त विज्ञापन दिखाकर).</translation>
<translation id="7674629440242451245">शानदार नई Chrome सुविधाओं में रूचि है? तो chrome.com/dev पर हमारा डेव चैनल आज़माएं.</translation>
<translation id="7682287625158474539">शिपिंग</translation>
+<translation id="7699293099605015246">फ़िलहाल लेख उपलब्ध नहीं हैं</translation>
<translation id="7701040980221191251">कुछ नहीं</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> में आगे बढ़ें (असुरक्षित)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">प्रमाणपत्र</translation>
<translation id="7716147886133743102">आपके व्यवस्थापक की ओर से अवरोधित है</translation>
<translation id="7716424297397655342">इस साइट को संचय से लोड नहीं किया जा सकता</translation>
+<translation id="7723047071702270851">कार्ड में बदलाव करें</translation>
<translation id="774634243536837715">खतरनाक सामग्री ब्लॉक की गई.</translation>
<translation id="7752995774971033316">अप्रबंधित</translation>
<translation id="7755287808199759310">आपका अभिभावक इसे आपके लिए अनवरोधित कर सकता है</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">पता जोड़ें</translation>
<translation id="777702478322588152">प्रशासक प्रांत</translation>
<translation id="7791543448312431591">जोड़ें</translation>
+<translation id="7793553086574152071">अगली बार तेज़ी से भुगतान करने के लिए, इस कार्ड को अपने Google खाते में सेव करें.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> पर मौजूद वेबपेज संभवत: अस्थायी रूप से कार्य नहीं कर रहा है या उसे स्थायी रूप से नए वेब पते पर स्थानांतरित कर दिया गया है.</translation>
<translation id="7800304661137206267">कनेक्शन को संदेश प्रमाणीकरण के लिए <ph name="MAC" /> और मुख्य एक्सचेंज क्रियाविधि के रूप में <ph name="KX" /> के साथ, <ph name="CIPHER" /> का उपयोग करते हुए एन्क्रिप्ट किया गया है.</translation>
+<translation id="7802523362929240268">साइट वैध है</translation>
<translation id="780301667611848630">जी नहीं, रहने दें </translation>
<translation id="7805768142964895445">स्थिति</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome से फ़ॉर्म सुझाव को निकालें?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' के लिए <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> मिले</translation>
+<translation id="782886543891417279">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
<translation id="785549533363645510">हालांकि, आप अदृश्य नहीं हैं. गुप्त मोड में रहने से आपकी ब्राउज़िंग आपके नियोक्ता, आपके इंटरनेट सेवा प्रदाता या आपके द्वारा देखी जाने वाली वेबसाइट से छिपती नहीं है.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">डेबिट और प्रीपेड कार्ड स्वीकार किए जाते हैं.</translation>
+<translation id="7878562273885520351">आपके पासवर्ड से छेड़छाड़ की जा सकती है</translation>
<translation id="7887683347370398519">अपना CVC जांचें और पुन: प्रयास करें</translation>
<translation id="79338296614623784">मान्य फ़ोन नंबर डालें</translation>
<translation id="7935318582918952113">DOM डिस्टिलर</translation>
<translation id="7938958445268990899">सर्वर का प्रमाणपत्र अभी तक मान्य नहीं है.</translation>
-<translation id="7942349550061667556">लाल</translation>
<translation id="7947285636476623132">अपना समाप्ति वर्ष जांचें और फिर से कोशिश करें</translation>
<translation id="7951415247503192394">(32-बिट)</translation>
<translation id="7956713633345437162">मोबाइल बुकमार्क</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">पूछें (डिफ़ॉल्ट)</translation>
<translation id="8041089156583427627">सुझाव भेजें</translation>
<translation id="8041940743680923270">वैश्विक डिफ़ॉल्ट का उपयोग करें (पूछें)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" सही तरीके से कॉन्फ़िगर नहीं किया गया है. आमतौर पर "<ph name="SOFTWARE_NAME" />" को अनइंस्टॉल करने से समस्या ठीक हो जाती है. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">लेख देखने में विफल रहा.</translation>
<translation id="8091372947890762290">सर्वर पर सक्रियण लंबित है</translation>
+<translation id="8094917007353911263">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="8103161714697287722">भुगतान विधि</translation>
<translation id="8118489163946903409">भुगतान विधि</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" आपके कंप्यूटर या नेटवर्क पर ठीक से इंस्टॉल नहीं हुआ था. अपने आईटी व्यवस्थापक से इस समस्या को ठीक करने के लिए कहें.</translation>
<translation id="8131740175452115882">दुबारा पूछें</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> का सर्वर <ph name="BEGIN_ABBR" />DNS पता<ph name="END_ABBR" /> नहीं ढूंढ़ा जा सका.</translation>
<translation id="8149426793427495338">आपका कंप्यूटर निष्क्रिय हो गया है.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">यदि आप सुनिश्चित नहीं हैं कि इसका क्या मतलब है, तो अपने नेटवर्क व्यवस्थापक से संपर्क करें.</translation>
<translation id="8293206222192510085">बुकमार्क जोड़ें</translation>
<translation id="8294431847097064396">स्रोत</translation>
+<translation id="8298115750975731693">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
<translation id="8306404619377842860"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से निजी कनेक्शन नहीं बनाया जा सकता क्योंकि आपके डिवाइस का दिनांक और समय (<ph name="DATE_AND_TIME" />) गलत है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">नेटवर्क कनेक्शन में कोई समस्या होने के कारण अनुवाद विफल हुआ.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> का एक्सेस अस्वीकृत किया गया</translation>
@@ -919,7 +955,7 @@
<translation id="859285277496340001">प्रमाणपत्र यह जांचने के लिए कोई तंत्र निर्दिष्‍ट नहीं करता कि इसे रद्द कर दिया गया है या नहीं.</translation>
<translation id="8620436878122366504">आपके अभिभावकों ने अभी तक इसकी स्वीकृति नहीं दी है</translation>
<translation id="8647750283161643317">सभी को डिफ़ॉल्ट पर रीसेट करें</translation>
-<translation id="8660471606262461360">Google पेमेंट्स से</translation>
+<translation id="8660471606262461360">Google Payments से</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> से आपके कनेक्शन को एन्क्रिप्ट नहीं किया गया है.</translation>
<translation id="8718314106902482036">भुगतान पूरा नहीं हुआ</translation>
<translation id="8725066075913043281">पुन: प्रयास करें</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">हाल ही में बंद किए गए</translation>
<translation id="8874824191258364635">मान्य कार्ड संख्या डालें</translation>
<translation id="8876793034577346603">नेटवर्क कॉन्फ़िगरेशन पार्स होने में विफल रहा.</translation>
-<translation id="8889402386540077796">रंग</translation>
<translation id="8891727572606052622">अमान्य प्रॉक्सी मोड.</translation>
<translation id="889901481107108152">क्षमा करें, यह प्रयोग आपके प्‍लेटफ़ॉर्म पर उपलब्ध नहीं है.</translation>
<translation id="8903921497873541725">ज़ूम इन करें</translation>
<translation id="8931333241327730545">क्या आप इस कार्ड को अपने Google खाते में सहेजना चाहते हैं?</translation>
<translation id="8932102934695377596">आपकी घड़ी पीछे है</translation>
+<translation id="893332455753468063">नाम जोड़ें</translation>
<translation id="8938939909778640821">स्वीकृत क्रेडिट और प्रीपेड कार्ड</translation>
+<translation id="8957210676456822347">कैप्‍टिव पोर्टल प्राधिकरण</translation>
<translation id="8971063699422889582">सर्वर के प्रमाणपत्र की समय-सीमा समाप्त हो चुकी है.</translation>
-<translation id="8986494364107987395">उपयोग संबंधी आंकड़े और क्रैश रिपोर्ट अपने आप Google को भेजने की अनुमति दें</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">साइट में आगे हानिकारक प्रोग्राम हैं</translation>
<translation id="8997023839087525404">सर्वर ने एक प्रमाणपत्र प्रस्तुत किया है, जिसे प्रमाणपत्र पारदर्शिता पॉलिसी का उपयोग करके सार्वजनिक रूप से प्रकट नहीं किया गया था. कुछ प्रमाणपत्रों के लिए यह सुनिश्चित करना आवश्यक है कि वे विश्वसनीय हैं और आक्रमणकर्ताओं से रक्षा करते हैं.</translation>
<translation id="9001074447101275817">प्रॉक्‍सी <ph name="DOMAIN" /> के लिए उपयोगकर्ता नाम और पासवर्ड की आवश्यकता है.</translation>
<translation id="9005998258318286617">PDF दस्तावेज़ लोड नहीं किया जा सका.</translation>
+<translation id="9008201768610948239">ध्यान न दें</translation>
<translation id="901974403500617787">सिस्टम-व्यापी रूप से लागू होने वाले फ़्लैग केवल मालिक द्वारा ही सेट किए जा सकते हैं: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">कार्ड बिलिंग पता ज़रूरी है</translation>
<translation id="9020542370529661692">इस पेज का <ph name="TARGET_LANGUAGE" /> में अनुवाद कर दिया गया है</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">आपने <ph name="DOMAIN" /> पर पहुंचने का प्रयास किया, लेकिन सर्वर ने एक अमान्‍य प्रमाणपत्र प्रस्तुत किया.</translation>
<translation id="9050666287014529139">पासफ़्रेज़</translation>
<translation id="9065203028668620118">संपादित करें</translation>
-<translation id="9068849894565669697">रंग चुनें</translation>
<translation id="9069693763241529744">किसी एक्सटेंशन से अवरोधित है</translation>
<translation id="9076283476770535406">इसमें वयस्क सामग्री हो सकती है</translation>
<translation id="9078964945751709336">अधिक जानकारी की आवश्यकता है</translation>
+<translation id="9080712759204168376">आदेश सारांश</translation>
<translation id="9103872766612412690"><ph name="SITE" /> आपकी जानकारी की सुरक्षा करने के लिए आमतौर पर एन्क्रिप्शन का उपयोग करती है. जब क्रोमियम ने इस बार <ph name="SITE" /> से कनेक्ट करने का प्रयास किया, तो वेबसाइट ने असामान्य और गलत क्रेडेंशियल वापस भेजे. ऐसा तब हो सकता है जब कोई हमलावर <ph name="SITE" /> होने का दावा करने का प्रयास कर रहा हो या किसी वाई-फ़ाई प्रवेश स्क्रीन ने कनेक्शन को बाधित कर दिया हो. आपकी जानकारी अभी भी सुरक्षित है क्योंकि किसी भी डेटा के आदान-प्रदान से पहले ही क्रोमियम ने कनेक्शन को रोक दिया था.</translation>
+<translation id="9106062320799175032">बिलिंग पता जोड़ें</translation>
+<translation id="910908805481542201">इसे ठीक करने में मेरी सहायता करें</translation>
+<translation id="9128870381267983090">नेटवर्क से कनेक्ट करें</translation>
<translation id="9137013805542155359">मूल दिखाएं</translation>
<translation id="9137248913990643158">इस ऐप्लिकेशन का उपयोग करने से पहले कृपया Chrome शुरू करके उसमें प्रवेश करें.</translation>
<translation id="9148507642005240123">&amp;संपादन वापस लाएं</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> एक असमर्थित प्रोटोकॉल का उपयोग करता है.</translation>
<translation id="9205078245616868884">आपका डेटा आपके समन्वयन पासफ़्रेज़ के साथ एन्क्रिप्ट किया गया है. समन्वयन शुरू करने के लिए इसे डालें.</translation>
<translation id="9207861905230894330">लेख जोड़ने में विफल रहा.</translation>
+<translation id="9215416866750762878">एक ऐप्‍लिकेशन Chrome को इस साइट से सुरक्षित तरीके से कनेक्‍ट होने से रोक रहा है</translation>
<translation id="9219103736887031265">चित्र</translation>
<translation id="933612690413056017">कोई इंटरनेट कनेक्शन नहीं है</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{कुछ नहीं}=1{1 आइटम}one{# आइटम}other{# आइटम}}</translation>
<translation id="981121421437150478">ऑफ़लाइन</translation>
<translation id="988159990683914416">डेवलपर बिल्ड</translation>
+<translation id="989988560359834682">पता संपादित करें</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" आपके कंप्यूटर या नेटवर्क पर ठीक से इंस्टॉल नहीं हुआ था:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" को अनइंस्टॉल करके या बंद करके देखें&lt;/li&gt;
+ &lt;li&gt;किसी दूसरे नेटवर्क से कनेक्ट करके देखें&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index 36438525a71..edcbc634f7e 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Oznake radne površine</translation>
<translation id="1074497978438210769">Nije sigurno</translation>
<translation id="1080116354587839789">Prilagođavanje širini</translation>
+<translation id="1088860948719068836">Dodajte ime na kartici</translation>
<translation id="1103523840287552314">Uvijek prevedi <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Prikaži sve spremljene zaporke...</translation>
<translation id="1107591249535594099">Ako je označeno, Chrome će pohraniti kopiju vaše kartice na uređaj radi bržeg popunjavanja obrazaca.</translation>
<translation id="1111153019813902504">Najnovije oznake</translation>
<translation id="1113869188872983271">&amp;Poništi promjenu rasporeda</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sinkronizirano)</translation>
<translation id="1263231323834454256">Popis za čitanje</translation>
<translation id="1264126396475825575">Izvješća o rušenju programa generirana <ph name="CRASH_TIME" /> (još nisu prenesena ili zanemarena)</translation>
+<translation id="1270502636509132238">Način preuzimanja</translation>
<translation id="1281526147609854549">Izdavač: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nikad nemoj prevoditi ovu web-lokaciju</translation>
<translation id="129553762522093515">Nedavno zatvoreno</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Čekanje na uspostavu veze…</translation>
<translation id="153384715582417236">To je zasad sve</translation>
<translation id="1549470594296187301">Za upotrebu te značajke mora biti omogućen JavaScript.</translation>
-<translation id="1555130319947370107">Plava</translation>
<translation id="1559528461873125649">Nema takve datoteke ili direktorija</translation>
<translation id="1583429793053364125">Nešto nije u redu s prikazivanjem ove web-stranice.</translation>
<translation id="1592005682883173041">Pristup lokalnim podacima</translation>
<translation id="1594030484168838125">Odaberi</translation>
-<translation id="161042844686301425">Cijan</translation>
<translation id="1620510694547887537">Fotoaparat</translation>
<translation id="1629803312968146339">Želite li da Chrome spremi tu karticu?</translation>
<translation id="1639239467298939599">Učitavanje</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264"><ph name="NAME" /> mora dopustiti da posjetiš tu web-lokaciju</translation>
<translation id="1721424275792716183">* Polje je obavezno</translation>
+<translation id="1727741090716970331">Dodajte važeći broj kartice</translation>
<translation id="1728677426644403582">Gledate izvor web-stranice</translation>
<translation id="173080396488393970">Ova vrsta kartice nije podržana</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Pogreška postavljanja u seriju</translation>
<translation id="1974060860693918893">Napredno</translation>
<translation id="1978555033938440688">Verzija opreme</translation>
-<translation id="1995859865337580572">Potvrdite svoj CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i još 1}one{i još #}few{i još #}other{i još #}}</translation>
<translation id="2025186561304664664">Proxy je postavljen na automatsko konfiguriranje.</translation>
<translation id="2030481566774242610">Jeste li mislili <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Prijavite se u Chrome ako želite da vam Google predlaže sadržaje.</translation>
+<translation id="2091887806945687916">Zvuk</translation>
<translation id="2094505752054353250">Domena se ne podudara</translation>
<translation id="2096368010154057602">Departman</translation>
<translation id="2108755909498034140">Ponovo pokrenite računalo</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Zanemareno jer je nadjačano pravilom <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Traženje stranica Fizičkog weba u blizini</translation>
<translation id="213826338245044447">Mobilne oznake</translation>
+<translation id="214556005048008348">Otkaži plaćanje</translation>
<translation id="2147827593068025794">Sinkronizacija u pozadini</translation>
+<translation id="2148613324460538318">Dodaj karticu</translation>
<translation id="2154054054215849342">Sinkronizacija nije dostupna za vašu domenu</translation>
<translation id="2154484045852737596">Uredite karticu</translation>
<translation id="2166049586286450108">Potpuni administratorski pristup</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
<translation id="2187317261103489799">Otkrij (zadano)</translation>
<translation id="2202020181578195191">Unesite važeću godinu isteka</translation>
+<translation id="2209523182407020534">Aplikacije koje mogu prouzročiti tu pogrešku uključuju antivirusni softver, softver vatrozida ili proxyja ili softver za filtriranje weba.</translation>
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
<translation id="2218879909401188352">Napadači koji su trenutačno na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogli bi instalirati opasne aplikacije koje će oštetiti uređaj, dodati skrivene troškove na račun za mobilne usluge ili ukrasti vaše osobne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Natrag</translation>
<translation id="2503184589641749290">Prihvaćene debitne i pretplatne kartice</translation>
<translation id="2515629240566999685">provjerite jačinu signala na svom području</translation>
+<translation id="2524461107774643265">Dodajte još podataka</translation>
+<translation id="2536110899380797252">Dodaj adresu</translation>
<translation id="2539524384386349900">Otkrij</translation>
<translation id="255002559098805027">Host <ph name="HOST_NAME" /> poslao je nevažeći odgovor.</translation>
<translation id="2556876185419854533">&amp;Poništi uređivanje</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
<translation id="2705137772291741111">Spremljena (predmemorirana) kopija web-lokacije nije čitljiva.</translation>
<translation id="2709516037105925701">Automatsko popunjavanje</translation>
+<translation id="2710942282213947212">Softver na računalu sprječava sigurno povezivanje Chromea s webom</translation>
<translation id="2712173769900027643">Traži dopuštenje</translation>
-<translation id="2713444072780614174">Bijela</translation>
<translation id="2720342946869265578">U blizini</translation>
<translation id="2721148159707890343">Zahtjev je uspio</translation>
<translation id="2728127805433021124">Certifikat poslužitelja potpisan je slabim algoritmom potpisa.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Otkrivena je promjena mreže.</translation>
<translation id="2916038427272391327">Zatvorite ostale programe</translation>
<translation id="2922350208395188000">Certifikat poslužitelja nije moguće provjeriti.</translation>
+<translation id="2925673989565098301">Način dostave</translation>
<translation id="2928905813689894207">Adresa za naplatu</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov je sigurnosni certifikat s domene <ph name="DOMAIN2" />. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Pogrešna vrsta pravila</translation>
<translation id="3032412215588512954">Želite li ponovo učitati tu web-lokaciju?</translation>
<translation id="3037605927509011580">O, ne!</translation>
+<translation id="3039538478787849737">Želite li spremiti karticu na Google?</translation>
<translation id="3041612393474885105">Podaci o certifikatu</translation>
<translation id="3063697135517575841">Chrome nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
<translation id="3064966200440839136">Napuštate anonimni način rada da biste platili putem vanjske aplikacije. Želite li nastaviti?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Privremena pogreška poslužitelja</translation>
<translation id="3154506275960390542">Ova stranica sadrži obrazac koji se možda neće poslati na siguran način. Podaci koje šaljete mogu biti vidljivi drugima tijekom prijenosa ili bi ih mogao izmijeniti napadač prije nego što ih primi poslužitelj.</translation>
<translation id="3157931365184549694">Vrati</translation>
+<translation id="3162559335345991374">Za Wi-Fi koji upotrebljavate možda ćete morati posjetiti stranicu za prijavu.</translation>
<translation id="3167968892399408617">Stranice koje pregledavate na anonimnim karticama ne zadržavaju se u povijesti preglednika, pohrani kolačića ili povijesti pretraživanja nakon što zatvorite sve anonimne kartice, ali će se zadržati sve datoteke koje preuzmete ili oznake koje napravite.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Otok</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Otkaži plaćanje</translation>
<translation id="3207960819495026254">Označeno</translation>
+<translation id="3211223744486044430">Da biste sljedeći put platili brže, spremite ovu karticu na svoj Google račun i na ovaj uređaj.</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>
<translation id="3226128629678568754">Pritisnite gumb za ponovno učitavanje da biste ponovo poslali podatke koji su potrebni za učitavanje stranice.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Nisu pronađeni rezultati pretraživanja</translation>
<translation id="3305707030755673451">Vaši su podaci šifrirani vašom šifrom za sinkronizaciju <ph name="TIME" />. Unesite je da biste pokrenuli sinkronizaciju.</translation>
<translation id="3320021301628644560">Dodajte adresu za naplatu</translation>
-<translation id="3329013043687509092">Zasićenje</translation>
<translation id="333371639341676808">Spriječite ovu stranicu od stvaranja dodatnih dijaloga.</translation>
<translation id="3338095232262050444">Sigurno</translation>
<translation id="3340978935015468852">postavke</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID klijenta:</translation>
<translation id="3391030046425686457">Adresa za dostavu</translation>
<translation id="3395827396354264108">Način preuzimanja</translation>
+<translation id="3399952811970034796">Adresa za dostavu</translation>
<translation id="3422248202833853650">Pokušajte zatvoriti ostale programe da biste oslobodili memoriju.</translation>
<translation id="3422472998109090673">Host <ph name="HOST_NAME" /> trenutačno nije dostupan.</translation>
<translation id="3427092606871434483">Dopusti (zadano)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375">Izvješće o rušenju programa generirano u <ph name="CRASH_TIME" />, preneseno u <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Podaci o certifikatu</translation>
<translation id="3690164694835360974">Prijava nije sigurna</translation>
+<translation id="3704162925118123524">Mreža koju upotrebljavate može zahtijevati posjet stranici za prijavu.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Učitavanje...</translation>
<translation id="3712624925041724820">Licence su potrošene</translation>
<translation id="3714780639079136834">uključite mobilne podatke ili Wi-Fi</translation>
+<translation id="3715597595485130451">Povezivanje s Wi-Fi mrežom</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />provjerite proxy, vatrozid i konfiguraciju DNS-a<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Ako ste svjesni sigurnosnih rizika, možete <ph name="BEGIN_LINK" />posjetiti tu nesigurnu web-lokaciju<ph name="END_LINK" /> prije uklanjanja opasnih programa.</translation>
<translation id="3739623965217189342">Veza koju ste kopirali</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;Poništi dodavanje</translation>
<translation id="404928562651467259">UPOZORENJE</translation>
<translation id="4058922952496707368">Stavka "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfiguracija proxy poslužitelja postavljena je za upotrebu URL-a .pac skripte, a ne fiksnih proxy poslužitelja.</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">Serijski broj uređaja nije važeći</translation>
<translation id="410351446219883937">Automatska reprodukcija</translation>
<translation id="4103763322291513355">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste vidjeli popis nedopuštenih URL-ova i druga pravila koja je nametnuo vaš administrator sustava.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Uvijek dopusti na ovoj web-lokaciji</translation>
<translation id="4117700440116928470">Opseg pravila nije podržan.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 druga stavka}one{# druga stavka}few{# druge stavke}other{# drugih stavki}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719">Pokušali ste doseći domenu <ph name="DOMAIN" />, ali certifikat koji je poslužitelj predstavio povučen je od strane izdavača. Prema tome nikako ne biste trebali vjerovati sigurnosnim certifikatima koje predstavlja poslužitelj. Možda komunicirate s napadačem.</translation>
<translation id="4394049700291259645">Onemogući</translation>
<translation id="4406896451731180161">rezultati pretraživanja</translation>
+<translation id="4415426530740016218">Adresa preuzimanja</translation>
<translation id="4424024547088906515">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; Chrome smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> nije prihvatio vaš certifikat za prijavu ili certifikat nije poslan.</translation>
<translation id="443673843213245140">Upotreba proxy poslužitelja onemogućena je, ali određena je izričita konfiguracija proxy poslužitelja.</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">Bljeskalica</translation>
<translation id="4558551763791394412">Pokušajte onemogućiti proširenja.</translation>
<translation id="457875822857220463">Dostava</translation>
+<translation id="4582800630050655161">Mogli biste izgubiti pristup svojem Google računu ili bi netko mogao ukrasti vaš identitet. Chromium preporučuje da odmah promijenite zaporku.</translation>
<translation id="4587425331216688090">Želite li s Chromea ukloniti adresu?</translation>
<translation id="4592951414987517459">Vaša veza s domenom <ph name="DOMAIN" /> kriptirana je modernim kriptografskim paketom.</translation>
<translation id="4594403342090139922">&amp;Poništi brisanje</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Prestani upotrebljavati nevažeći certifikat</translation>
+<translation id="4690954380545377795">Mogli biste izgubiti pristup svojem Google računu ili bi netko mogao ukrasti vaš identitet. Chrome preporučuje da odmah promijenite zaporku.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Veza je prekinuta</translation>
<translation id="471880041731876836">Nemaš dopuštenje za posjet toj web-lokaciji</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Vaše plaćanje</translation>
<translation id="4726672564094551039">Ponovo učitaj pravila</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Ponovo pokrenite Chromium</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">Sigurnosno pohranjivanje u neispravnom je stanju</translation>
<translation id="5023310440958281426">Provjerite pravila svojeg administratora</translation>
<translation id="5029568752722684782">Izbriši kopiju</translation>
+<translation id="503069730517007720">Potreban je korijenski certifikat za "<ph name="SOFTWARE_NAME" />", ali nije instaliran. Vaš IT administrator trebao bi pogledati upute za konfiguraciju softvera "<ph name="SOFTWARE_NAME" />" kako bi riješio taj problem. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">O Google Prevoditelju</translation>
<translation id="5039804452771397117">Dopusti</translation>
<translation id="5040262127954254034">Privatnost</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">Eksperimenti</translation>
<translation id="5205222826937269299">Ime je obavezno</translation>
<translation id="5222812217790122047">E-pošta (obavezno)</translation>
+<translation id="522700295135997067">Ova web-lokacija možda vam je upravo ukrala zaporku</translation>
+<translation id="5230733896359313003">Adresa za dostavu</translation>
<translation id="5251803541071282808">Oblak</translation>
<translation id="5277279256032773186">Upotrebljavate li Chrome na poslu? Tvrtke mogu upravljati Chromeovim postavkama za svoje zaposlenike. Saznajte više</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Privremeno onemogućite softver prema ovim uputama da biste se povezali s webom. Potrebne su vam administratorske povlastice.<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Veza s tom web-lokacijom nije privatna. Da biste zatvorili VR način, skinite masku i pritisnite Natrag.</translation>
<translation id="5299298092464848405">Pogreška u pravilu analize</translation>
+<translation id="5308380583665731573">Povežite se</translation>
<translation id="5308689395849655368">Onemogućeno je izvješćivanje o padu.</translation>
<translation id="5317780077021120954">Spremi</translation>
<translation id="5327248766486351172">Naziv</translation>
+<translation id="5332219387342487447">Način otpreme</translation>
<translation id="5355557959165512791">Trenutačno ne možete otvoriti web-lokaciju <ph name="SITE" /> jer je njezin certifikat opozvan. Mrežne pogreške i napadi uglavnom su privremeni i ta bi stranica kasnije trebala funkcionirati.</translation>
<translation id="536296301121032821">Pohrana postavki pravila nije uspjela</translation>
<translation id="5386426401304769735">Lanac certifikata za ovu web-lokaciju sadrži certifikat s SHA-1 potpisom.</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">Web-lokacija na intranetu tvrtke, organizacije ili škole ima isti URL kao i vanjska web-lokacija.
<ph name="LINE_BREAK" />
Pokušajte se obratiti administratoru sustava.</translation>
+<translation id="5499929369096410817">Unesite sigurnosni kôd za karticu <ph name="CREDIT_CARD" />. Taj se kôd neće spremiti.</translation>
<translation id="5509780412636533143">Upravljane oznake</translation>
<translation id="5510766032865166053">Datoteka je možda premještena ili izbrisana.</translation>
<translation id="5523118979700054094">Naziv pravila</translation>
<translation id="552553974213252141">Je li tekst ispravno izdvojen?</translation>
<translation id="5540224163453853">Traženi članak nije pronađen.</translation>
+<translation id="5541546772353173584">Dodajte e-adresu</translation>
<translation id="5544037170328430102">Ugrađena stranica na web-lokaciji <ph name="SITE" /> navodi sljedeće:</translation>
+<translation id="5545756402275714221">Preporučeni članci</translation>
<translation id="5556459405103347317">Ponovno učitaj</translation>
<translation id="5560088892362098740">Datum isteka</translation>
<translation id="5565735124758917034">Aktivno</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">E-pošta</translation>
<translation id="5669703222995421982">Predlaganje sadržaja</translation>
<translation id="5675650730144413517">Stranica ne funkcionira</translation>
+<translation id="5689199277474810259">Izvezi u JSON</translation>
<translation id="5710435578057952990">Identitet ove web lokacije nije ovjeren.</translation>
<translation id="5719499550583120431">Prihvaćaju se pretplatne kartice.</translation>
<translation id="5720705177508910913">Trenutačni korisnik:</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065">Vaša veza s domenom <ph name="DOMAIN" /> kriptirana je zastarjelim kriptografskim paketom.</translation>
<translation id="5813119285467412249">&amp;Ponovi dodavanje</translation>
<translation id="5838278095973806738">Na ovu web-lokaciju nemojte unositi osjetljive podatke (na primjer, zaporke ili kreditne kartice) jer su je možda ukrali napadači.</translation>
+<translation id="5866257070973731571">Dodajte telefonski broj</translation>
<translation id="5869405914158311789">Web-lokacija ne može se dohvatiti</translation>
<translation id="5869522115854928033">Spremljene zaporke</translation>
<translation id="5872918882028971132">Nadređeni prijedlozi</translation>
<translation id="5893752035575986141">Prihvaćaju se kreditne kartice.</translation>
-<translation id="5901630391730855834">Žuta</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinkronizirano)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 u upotrebi}one{# u upotrebi}few{# u upotrebi}other{# u upotrebi}}</translation>
<translation id="5959728338436674663">Automatski šalji Googleu neke <ph name="BEGIN_WHITEPAPER_LINK" />podatke o sustavu i sadržaj stranice<ph name="END_WHITEPAPER_LINK" /> radi otkrivanja opasnih aplikacija i web-lokacija. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Uredite podatke za kontakt</translation>
<translation id="5967867314010545767">Ukloni iz povijesti</translation>
<translation id="5975083100439434680">Smanji</translation>
+<translation id="597552863672748783">Potvrdite sigurnosni kôd</translation>
<translation id="598637245381783098">Aplikacija za plaćanje ne može se otvoriti</translation>
<translation id="5989320800837274978">Nisu određeni fiksni proxy poslužitelji ni URL .pac skripte.</translation>
<translation id="5990559369517809815">Zahtjevi poslužitelju blokirani su proširenjem.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. stranica}one{#. stranica}few{#. stranica}other{#. stranica}}</translation>
-<translation id="6017514345406065928">Zelena</translation>
<translation id="6017850046339264347">Napadači na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogli bi 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_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sinkronizirano)</translation>
<translation id="6027201098523975773">Unesite ime</translation>
<translation id="6040143037577758943">Zatvori</translation>
-<translation id="6042308850641462728">Više</translation>
<translation id="6047233362582046994">Ako ste svjesni sigurnosnih rizika, možete <ph name="BEGIN_LINK" />posjetiti ovu web-lokaciju<ph name="END_LINK" /> prije uklanjanja štetnih aplikacija.</translation>
<translation id="6047927260846328439">Ovaj vas sadržaj može na prijevaru pokušati navesti da instalirate softver ili odate svoje osobne podatke. <ph name="BEGIN_LINK" />Ipak prikaži<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Trenutačno ne možete otvoriti <ph name="SITE" /> jer web-lokacija upotrebljava prikvačivanje certifikata. Mrežne pogreške i napadi obično su privremeni, tako da će stranica kasnije vjerojatno funkcionirati.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">Gledate stranicu proširenja</translation>
<translation id="6596325263575161958">Opcije šifriranja</translation>
<translation id="662080504995468778">Ostani</translation>
+<translation id="6624427990725312378">Podaci za kontakt</translation>
<translation id="6626291197371920147">Dodajte važeći broj kartice</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Pretraživanje</translation>
<translation id="6630809736994426279">Napadači koji su trenutačno na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu pokušati instalirati opasne programe na vaš Mac radi krađe ili brisanja vaših podataka (na primjer fotografija, zaporki, poruka i brojeva kreditnih kartica). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">Prethodno</translation>
<translation id="6710594484020273272">&lt;Upišite pojam za pretraživanje&gt;</translation>
<translation id="6711464428925977395">Nešto nije u redu s proxy poslužiteljem ili adresa nije točna.</translation>
-<translation id="6727102863431372879">Postavi</translation>
<translation id="674375294223700098">Nepoznata pogreška certifikata poslužitelja</translation>
<translation id="6753269504797312559">Vrijednost pravila</translation>
<translation id="6757797048963528358">Uređaj je u stanju mirovanja.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Putanja profila</translation>
<translation id="7424977062513257142">Ugrađena stranica na ovoj web-lokaciji navodi sljedeće:</translation>
+<translation id="7437289804838430631">Dodajte podatke za kontakt</translation>
<translation id="7441627299479586546">Pogrešan predmet pravila</translation>
<translation id="7444046173054089907">Ova je web-lokacija blokirana</translation>
<translation id="7445762425076701745">Identitet poslužitelja s kojim ste se povezali ne može se u potpunosti potvrditi. Povezali ste se s poslužiteljem upotrebom imena koje je valjano samo unutar vaše mreže, a za koje vanjsko tijelo za izdavanje certifikata nikako ne može potvrditi vlasništvo. Budući da postoje tijela za izdavanje certifikata koja će izdati certifikat za ta imena bez obzira na sve, nema načina da budete sigurni da ste povezani sa željenom web-lokacijom, a ne s napadačem.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">Naprijed</translation>
<translation id="7485870689360869515">Nema pronađenih podataka.</translation>
<translation id="7508255263130623398">Vraćeni ID uređaja pravila prazan je ili ne odgovara trenutačnom ID-u uređaja</translation>
+<translation id="7511955381719512146">Za Wi-Fi koji upotrebljavate možda ćete morati posjetiti stranicu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Preuzmi</translation>
<translation id="7518003948725431193">Za web-adresu nije pronađena web-stranica:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Veza s web-lokacijom nije privatna</translation>
-<translation id="7535087603100972091">Vrijednost</translation>
<translation id="7537536606612762813">Obavezno</translation>
<translation id="7542403920425041731">Nakon što ih potvrdite, podaci o kartici dijelit će se s ovom web-lokacijom.</translation>
<translation id="7542995811387359312">Automatsko popunjavanje kreditne kartice onemogućeno je jer se ovaj obrazac ne služi sigurnom vezom.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat možda je lažan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="7568593326407688803">Ova je stranica na ovom jeziku:<ph name="ORIGINAL_LANGUAGE" />Želite li je prevesti?</translation>
<translation id="7569952961197462199">Želite li s Chromea ukloniti kreditnu karticu?</translation>
-<translation id="7569983096843329377">Crna</translation>
<translation id="7578104083680115302">Plaćajte brzo na web-lokacijama i u aplikacijama na više uređaja karticama koje ste spremili na Google.</translation>
<translation id="7588950540487816470">Fizički web</translation>
<translation id="7592362899630581445">Certifikat poslužitelja krši ograničenja naziva.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">Napadači na ovoj web-lokaciji mogu vas pokušati navesti na instaliranje programa koji smanjuju kvalitetu pregledavanja interneta (npr. promjenom početne stranice ili prikazivanjem dodatnih oglasa na web-lokacijama koje posjetite).</translation>
<translation id="7674629440242451245">Zanimaju li vas nove, kul značajke preglednika Chrome? Isprobajte naš razvojni kanal na stranici chrome.com/dev.</translation>
<translation id="7682287625158474539">Dostava</translation>
+<translation id="7699293099605015246">Članci trenutačno nisu dostupni</translation>
<translation id="7701040980221191251">Nema</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Idi na web-lokaciju <ph name="SITE" /> (nije sigurno)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certifikat</translation>
<translation id="7716147886133743102">Blokirao administrator</translation>
<translation id="7716424297397655342">Web-lokacija se ne može učitati iz predmemorije</translation>
+<translation id="7723047071702270851">Uredite karticu</translation>
<translation id="774634243536837715">Blokiran je opasan sadržaj.</translation>
<translation id="7752995774971033316">Nema upravitelja</translation>
<translation id="7755287808199759310">Roditelj je može deblokirati</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">Dodaj adresu</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
+<translation id="7793553086574152071">Da biste sljedeći put platili brže, spremite ovu karticu na svoj Google račun.</translation>
<translation id="7793809570500803535">Web-stranica na web-lokaciji <ph name="SITE" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="7800304661137206267">Veza je šifrirana pomoću <ph name="CIPHER" />, za provjeru autentičnosti poruke koristi se <ph name="MAC" />, a <ph name="KX" /> služi za mehanizam razmjene ključeva.</translation>
+<translation id="7802523362929240268">Web-lokacija je legitimna</translation>
<translation id="780301667611848630">Ne, hvala</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Želite li s Chromea ukloniti prijedlog za obrasce?</translation>
<translation id="7815407501681723534">Pronađeno <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">Za Wi-Fi koji upotrebljavate (<ph name="WIFI_NAME" />) možda ćete morati posjetiti stranicu za prijavu.</translation>
<translation id="785549533363645510">Niste nevidljivi. Anonimni način ne sakriva vaše pregledavanje od poslodavca, davatelja internetskih usluga ili posjećenih web-lokacija.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Prihvaćaju se debitne i pretplatne kartice.</translation>
+<translation id="7878562273885520351">Vaša je zaporka možda ugrožena</translation>
<translation id="7887683347370398519">Provjerite CVC i pokušajte ponovo</translation>
<translation id="79338296614623784">Unesite važeći telefonski broj</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifkat poslužitelja još nije valjan.</translation>
-<translation id="7942349550061667556">Crvena</translation>
<translation id="7947285636476623132">Provjerite godinu isteka, pa pokušajte ponovo</translation>
<translation id="7951415247503192394">(32-bitni)</translation>
<translation id="7956713633345437162">Mobilne oznake</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">Pitaj (zadano)</translation>
<translation id="8041089156583427627">Slanje povratnih informacija</translation>
<translation id="8041940743680923270">Upotrijebi globalnu zadanu vrijednost (pitaj)</translation>
+<translation id="8057711352706143257">Softver "<ph name="SOFTWARE_NAME" />" nije ispravno konfiguriran. Taj se problem obično rješava deinstaliranjem softvera "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Prikaz članka nije uspio.</translation>
<translation id="8091372947890762290">Aktivacija je na čekanju na poslužitelju</translation>
+<translation id="8094917007353911263">Za mrežu koju upotrebljavate možda ćete morati posjetiti stranicu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Način plaćanja</translation>
<translation id="8118489163946903409">Način plaćanja</translation>
+<translation id="8127301229239896662">Softver "<ph name="SOFTWARE_NAME" />" nije ispravno instaliran na vašem računalu ili mreži. Obratite se IT administratoru za rješavanje tog problema.</translation>
<translation id="8131740175452115882">Potvrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS adresa<ph name="END_ABBR" /> poslužitelja hosta <ph name="HOST_NAME" /> nije pronađena.</translation>
<translation id="8149426793427495338">Računalo je u stanju mirovanja.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">Obratite se svojem mrežnom administratoru ako niste sigurni što to znači.</translation>
<translation id="8293206222192510085">Dodaj oznaku</translation>
<translation id="8294431847097064396">Izvor</translation>
+<translation id="8298115750975731693">Za Wi-Fi koji upotrebljavate (<ph name="WIFI_NAME" />) možda ćete morati posjetiti stranicu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Nije moguće uspostaviti privatnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vrijeme uređaja (<ph name="DATE_AND_TIME" />) nisu točni. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Prijevod nije uspio zbog problema s mrežnom vezom.</translation>
<translation id="8332188693563227489">Pristup hostu <ph name="HOST_NAME" /> je odbijen</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Nedavno zatvoreno</translation>
<translation id="8874824191258364635">Unesite važeći broj kreditne kartice</translation>
<translation id="8876793034577346603">Mrežna konfiguracija nije uspješno analizirana.</translation>
-<translation id="8889402386540077796">Ton</translation>
<translation id="8891727572606052622">Nevažeći način proxy poslužitelja.</translation>
<translation id="889901481107108152">Nažalost, ovaj eksperiment nije dostupan na vašoj platformi.</translation>
<translation id="8903921497873541725">Povećaj</translation>
<translation id="8931333241327730545">Želite li spremiti tu karticu na Google račun?</translation>
<translation id="8932102934695377596">Sat kasni</translation>
+<translation id="893332455753468063">Dodajte ime</translation>
<translation id="8938939909778640821">Prihvaćene kreditne i pretplatne kartice</translation>
+<translation id="8957210676456822347">Autorizacija obaveznog portala za autentifikaciju</translation>
<translation id="8971063699422889582">Istekao je certifikat poslužitelja.</translation>
-<translation id="8986494364107987395">Automatski šalji Googleu statistiku o upotrebi i izvješća o padu programa</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Sljedeća web-lokacija sadrži štetne programe</translation>
<translation id="8997023839087525404">Poslužitelj je prikazao certifikat koji nije javno otkriven putem pravila Transparentnost certifikata. Taj se zahtjev postavlja za neke certifikate radi provjere njihove pouzdanosti i zaštite od napada.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> zahtijeva korisničko ime i zaporku.</translation>
<translation id="9005998258318286617">Učitavanje PDF dokumenta nije uspjelo.</translation>
+<translation id="9008201768610948239">Zanemari</translation>
<translation id="901974403500617787">Oznake koje se primjenjuju na razini sustava može postaviti samo vlasnik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Potrebna je adresa za naplatu kartice</translation>
<translation id="9020542370529661692">Ova je stranica prevedena na <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,12 +1000,15 @@
<translation id="9049981332609050619">Pokušali ste pristupiti domeni <ph name="DOMAIN" />, ali poslužitelj je prikazao nevažeći certifikat.</translation>
<translation id="9050666287014529139">Zaporka</translation>
<translation id="9065203028668620118">Uredi</translation>
-<translation id="9068849894565669697">Odaberite boju</translation>
<translation id="9069693763241529744">Blokiralo proširenje</translation>
<translation id="9076283476770535406">Možda ima sadržaj za odrasle</translation>
<translation id="9078964945751709336">Potrebno je više podataka</translation>
+<translation id="9080712759204168376">Sažetak narudžbe</translation>
<translation id="9103872766612412690"><ph name="SITE" /> obično upotrebljava enkripciju radi zaštite vaših podataka. Prilikom ovog pokušaja povezivanja Chromiuma s web-lokacijom <ph name="SITE" /> ta je web-lokacija vratila neuobičajene
i netočne vjerodajnice. To može značiti da se neki napadač pokušava predstaviti kao <ph name="SITE" /> ili je zaslon za prijavu na Wi-Fi prekinuo vezu. Vaši su podaci još uvijek sigurni jer je Chromium zaustavio povezivanje prije razmjene podataka.</translation>
+<translation id="9106062320799175032">Dodajte adresu za naplatu</translation>
+<translation id="910908805481542201">Pomozi mi da to riješim</translation>
+<translation id="9128870381267983090">Povezivanje s mrežom</translation>
<translation id="9137013805542155359">Prikaži original</translation>
<translation id="9137248913990643158">Pokrenite Chrome i prijavite se na njega da biste mogli upotrebljavati tu aplikaciju.</translation>
<translation id="9148507642005240123">&amp;Poništi uređivanje</translation>
@@ -980,6 +1020,7 @@ i netočne vjerodajnice. To može značiti da se neki napadač pokušava predsta
<translation id="9183425211371246419">Host <ph name="HOST_NAME" /> upotrebljava nepodržane protokole.</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="9215416866750762878">Aplikacija sprječava sigurno povezivanje Chromea s ovom web-lokacijom</translation>
<translation id="9219103736887031265">Slike</translation>
<translation id="933612690413056017">Nema internetske veze</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@ i netočne vjerodajnice. To može značiti da se neki napadač pokušava predsta
<translation id="975560348586398090">{COUNT,plural, =0{Nijedna}=1{1 stavka}one{# stavka}few{# stavke}other{# stavki}}</translation>
<translation id="981121421437150478">Izvanmrežno</translation>
<translation id="988159990683914416">Sastavak razvojnog programera</translation>
+<translation id="989988560359834682">Uređivanje adrese</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Softver "<ph name="SOFTWARE_NAME" />" nije ispravno instaliran na vašem računalu ili mreži:
+ &lt;ul&gt;
+ &lt;li&gt;Pokušajte deinstalirati ili onemogućiti softver "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Pokušajte se povezati s drugom mrežom&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index 11eb909f56c..55f212a49f4 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Asztali könyvjelzők</translation>
<translation id="1074497978438210769">Nem biztonságos</translation>
<translation id="1080116354587839789">Szélességhez igazítás</translation>
+<translation id="1088860948719068836">Adja meg a kártyán szereplő nevet</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> - mindig legyen lefordítva</translation>
+<translation id="1103778128462718200">Az összes mentett jelszó megjelenítése…</translation>
<translation id="1107591249535594099">Ha be van jelölve, a Chrome ezen az eszközön tárolja a kártya egy példányát az űrlapok gyorsabb kitöltéséhez.</translation>
<translation id="1111153019813902504">Legutóbbi könyvjelzők</translation>
<translation id="1113869188872983271">&amp;Átrendezés visszavonása</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (szinkronizálva)</translation>
<translation id="1263231323834454256">Olvasási lista</translation>
<translation id="1264126396475825575">Hibajelentés készült: <ph name="CRASH_TIME" /> (még nincs feltöltve vagy mellőzték)</translation>
+<translation id="1270502636509132238">Átvételi mód</translation>
<translation id="1281526147609854549">Kibocsátó: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Ezt a webhelyet soha ne fordítsa le</translation>
<translation id="129553762522093515">Mostanában bezárt</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Várakozás a kapcsolódásra…</translation>
<translation id="153384715582417236">Egyelőre ennyi</translation>
<translation id="1549470594296187301">A funkció használatához engedélyezni kell a JavaScriptet.</translation>
-<translation id="1555130319947370107">Kék</translation>
<translation id="1559528461873125649">Nincs ilyen fájl vagy könyvtár</translation>
<translation id="1583429793053364125">Valami nem sikerült a weboldal megjelenítése során.</translation>
<translation id="1592005682883173041">Helyi adatok elérése</translation>
<translation id="1594030484168838125">Kiválaszt</translation>
-<translation id="161042844686301425">Cián</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Szeretné, hogy a Chrome mentse ezt a kártyát?</translation>
<translation id="1639239467298939599">Betöltés</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">A webhely felkereséséhez <ph name="NAME" /> engedélyére van szükség</translation>
<translation id="1721424275792716183">* A mező kitöltése kötelező</translation>
+<translation id="1727741090716970331">Érvényes kártyaszámot adjon meg</translation>
<translation id="1728677426644403582">Jelenleg weboldal forrását tekinti meg</translation>
<translation id="173080396488393970">Ez a kártyatípus nem támogatott</translation>
<translation id="1734864079702812349">American Express</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Szerializálási hiba</translation>
<translation id="1974060860693918893">Speciális</translation>
<translation id="1978555033938440688">Firmware verziószáma</translation>
-<translation id="1995859865337580572">Igazolja a CVC-kódot</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{és 1 további}other{és # további}}</translation>
<translation id="2025186561304664664">Automatikusan konfigurálhatóra beállított proxy.</translation>
<translation id="2030481566774242610">Erre gondolt: <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">A Google által javasolt, személyre szabott tartalmak fogadásához jelentkezzen be a Chrome-ba.</translation>
+<translation id="2091887806945687916">Hang</translation>
<translation id="2094505752054353250">Domainkeveredés</translation>
<translation id="2096368010154057602">Megye</translation>
<translation id="2108755909498034140">Indítsa újra a számítógépet</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">A rendszer figyelmen kívül hagyja, mivel a(z) <ph name="POLICY_NAME" /> felülírta.</translation>
<translation id="2138201775715568214">A Fizikai web közeli oldalainak keresése</translation>
<translation id="213826338245044447">Mobil könyvjelzők</translation>
+<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="2154054054215849342">A szinkronizálás az Ön domainjén nem áll rendelkezésre</translation>
<translation id="2154484045852737596">Kártya szerkesztése</translation>
<translation id="2166049586286450108">Teljes rendszergazdai hozzáférés</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 cím}other{# cím}}</translation>
<translation id="2187317261103489799">Észlelés (alapértelmezett)</translation>
<translation id="2202020181578195191">Érvényes lejárati évet kell megadnia</translation>
+<translation id="2209523182407020534">A hibát okozó alkalmazás lehet tűzfal, illetve víruskereső, webszűrő vagy proxyszoftver.</translation>
<translation id="2212735316055980242">Nem találhatók irányelvek</translation>
<translation id="2213606439339815911">Bejegyzések lekérése...</translation>
<translation id="2218879909401188352">A(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő támadók veszélyes alkalmazásokat telepíthetnek, amelyek károsíthatják eszközét, rejtett költségeket okozhatnak a mobiltelefon-számlán, vagy ellophatják személyes adatait. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Visszalépés</translation>
<translation id="2503184589641749290">Elfogadott bank- és feltöltőkártyák</translation>
<translation id="2515629240566999685">A térerő ellenőrzése tartózkodási helyén</translation>
+<translation id="2524461107774643265">További adatok hozzáadása</translation>
+<translation id="2536110899380797252">Cím hozzáadása</translation>
<translation id="2539524384386349900">Felismerés</translation>
<translation id="255002559098805027">A(z) <ph name="HOST_NAME" /> érvénytelen választ küldött.</translation>
<translation id="2556876185419854533">&amp;Szerkesztés visszavonása</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">A Chromium ez alkalommal nem tudta ellenőrizni az Ön kártyáját. Próbálja újra később.</translation>
<translation id="2705137772291741111">A webhely mentett (gyorsítótárazott) példánya nem olvasható.</translation>
<translation id="2709516037105925701">Automatikus kitöltés</translation>
+<translation id="2710942282213947212">A számítógépen található valamelyik szoftver megakadályozza a Chromiumot abban, hogy biztonságosan csatlakozzon az internethez</translation>
<translation id="2712173769900027643">Engedély kérése</translation>
-<translation id="2713444072780614174">Fehér</translation>
<translation id="2720342946869265578">A közelben</translation>
<translation id="2721148159707890343">Sikeres kérés</translation>
<translation id="2728127805433021124">A szerver tanúsítványa gyenge aláírási algoritmussal van aláírva.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Változást érzékeltünk a hálózatban.</translation>
<translation id="2916038427272391327">Zárja be a többi programot</translation>
<translation id="2922350208395188000">A szerver tanúsítványát nem sikerült leellenőrizni.</translation>
+<translation id="2925673989565098301">Kézbesítési mód</translation>
<translation id="2928905813689894207">Számlázási cím</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a következőről származik: <ph name="DOMAIN2" />. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Nem megfelelő irányelvtípus</translation>
<translation id="3032412215588512954">Szeretné újratölteni a webhelyet?</translation>
<translation id="3037605927509011580">A manóba!</translation>
+<translation id="3039538478787849737">Menti a kártyát a Google rendszerébe?</translation>
<translation id="3041612393474885105">Tanúsítvány adatai</translation>
<translation id="3063697135517575841">A Chrome ez alkalommal nem tudta ellenőrizni az Ön kártyáját. Próbálja újra később.</translation>
<translation id="3064966200440839136">Inkognitómód elhagyása külső alkalmazással történő fizetéshez. Folytatja?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Átmeneti szerverhiba</translation>
<translation id="3154506275960390542">Az oldal olyan űrlapot tartalmaz, amely esetében előfordulhat, hogy küldése nem biztonságosan történik. Az elküldött adatokat továbbítás közben mások is megtekinthetik, illetve támadók módosíthatják, hogy a szerver mást kapjon helyettük.</translation>
<translation id="3157931365184549694">Visszaállítás</translation>
+<translation id="3162559335345991374">Az Ön által használt Wi-Fi-hálózat megkövetelheti bejelentkezési oldalának felkeresését.</translation>
<translation id="3167968892399408617">Az inkognitólapon megtekintett oldalak az összes inkognitólap bezárását követően nem szerepelnek majd böngészési előzményei között, a cookie-k gyűjtőhelyén, illetve a keresési előzményekben. A letöltött fájlok és a könyvjelzők azonban megmaradnak.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Sziget</translation>
@@ -285,6 +295,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Fizetés visszavonása</translation>
<translation id="3207960819495026254">Könyvjelzőzött</translation>
+<translation id="3211223744486044430">A következő alkalommal gyorsabban fizethet, ha kártyáját Google-fiókjába és az eszközre menti.</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>
<translation id="3226128629678568754">Nyomja meg a frissítés gombot az oldal betöltéséhez szükséges adatok újraküldéséhez.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -299,7 +310,6 @@
<translation id="3303855915957856445">Nincs találat</translation>
<translation id="3305707030755673451">Adatainak titkosítása megtörtént összetett szinkronizálási jelszavával a következő időpontban: <ph name="TIME" />. Adja meg a jelszót a szinkronizálás megkezdéséhez.</translation>
<translation id="3320021301628644560">Számlázási cím hozzáadása</translation>
-<translation id="3329013043687509092">Telítettség</translation>
<translation id="333371639341676808">Ez az oldal ne nyisson meg további párbeszédablakokat.</translation>
<translation id="3338095232262050444">Biztonságos</translation>
<translation id="3340978935015468852">beállítások</translation>
@@ -318,6 +328,7 @@
<translation id="3380864720620200369">Ügyfél-azonosító:</translation>
<translation id="3391030046425686457">Szállítási cím</translation>
<translation id="3395827396354264108">Átvételi mód</translation>
+<translation id="3399952811970034796">Szállítási cím</translation>
<translation id="3422248202833853650">Próbáljon meg bezárni más programokat memória felszabadítása céljából.</translation>
<translation id="3422472998109090673">A(z) <ph name="HOST_NAME" /> jelenleg nem érhető el.</translation>
<translation id="3427092606871434483">Engedélyezés (alapértelmezett)</translation>
@@ -363,10 +374,12 @@
<translation id="3679803492151881375">A hibajelentés elkészítésének ideje: <ph name="CRASH_TIME" />; a feltöltés ideje: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Tanúsítvány adatai</translation>
<translation id="3690164694835360974">A bejelentkezés nem biztonságos</translation>
+<translation id="3704162925118123524">Előfordulhat, hogy az Ön által használt hálózat megköveteli a bejelentkezési oldalán történő bejelentkezést.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Betöltés...</translation>
<translation id="3712624925041724820">Az engedélyek elfogytak</translation>
<translation id="3714780639079136834">A mobiladatok vagy a Wi-Fi bekapcsolása</translation>
+<translation id="3715597595485130451">Csatlakozás Wi-Fi-hálózathoz</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />A proxy, a tűzfal és a DNS-konfiguráció ellenőrzése<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Ha tisztában van a biztonságát fenyegető kockázatokkal, a veszélyes programok eltávolítása előtt is <ph name="BEGIN_LINK" />felkeresheti a nem biztonságos webhelyet<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">Átmásolt link</translation>
@@ -401,6 +414,7 @@
<translation id="4030383055268325496">&amp;Hozzáadás visszavonása</translation>
<translation id="404928562651467259">FIGYELMEZTETÉS</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" kulcs: <ph name="ERROR" /></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>
<translation id="4079302484614802869">A proxykonfiguráció a .pac típusú szkript URL-cím, nem pedig a fix proxyszerverek használatára van beállítva.</translation>
@@ -408,7 +422,6 @@
<translation id="4103249731201008433">Az eszköz sorozatszáma érvénytelen</translation>
<translation id="410351446219883937">Automatikus lejátszás</translation>
<translation id="4103763322291513355">Látogasson el a &lt;strong&gt;chrome://policy&lt;/strong&gt; oldalra a feketelistán lévő URL-ek és egyéb, a rendszergazda által előírt szabályok megtekintéséhez.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Mindig engedélyezze ezen az oldalon</translation>
<translation id="4117700440116928470">Az irányelv hatásköre nem támogatott.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 egyéb}other{# egyéb}}</translation>
@@ -446,6 +459,7 @@
<translation id="4377125064752653719">A(z) <ph name="DOMAIN" /> webhelyet próbálta megnyitni, de a kiállító visszavonta a szerver által bemutatott tanúsítványt. Ez azt jelenti, hogy a szerver biztonsági igazolásaiban egyáltalán nem lehet megbízni. Lehet, hogy egy támadóval áll kapcsolatban.</translation>
<translation id="4394049700291259645">Kikapcsolás</translation>
<translation id="4406896451731180161">keresési találat</translation>
+<translation id="4415426530740016218">Átvételi cím</translation>
<translation id="4424024547088906515">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a Chrome szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="4432688616882109544">A(z) <ph name="HOST_NAME" /> nem fogadta el az Ön bejelentkezési tanúsítványát, vagy nem talált ilyet.</translation>
<translation id="443673843213245140">A proxy használata le van tiltva, de kifejezett proxykonfiguráció van megadva.</translation>
@@ -458,6 +472,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Próbálkozzon a bővítmények letiltásával.</translation>
<translation id="457875822857220463">Szállítás</translation>
+<translation id="4582800630050655161">Elveszítheti hozzáférést Google-fiókjához, vagy visszaélhetnek személyes adataival. A Chromium azt javasolja, hogy azonnal módosítsa jelszavát.</translation>
<translation id="4587425331216688090">Eltávolítja a címet a Chrome-ból?</translation>
<translation id="4592951414987517459">A(z) <ph name="DOMAIN" /> domainnel való kapcsolata modern kriptográfiával van titkosítva.</translation>
<translation id="4594403342090139922">&amp;Törlés visszavonása</translation>
@@ -466,10 +481,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Érvénytelen tanúsítvány használatának befejezése</translation>
+<translation id="4690954380545377795">Elveszítheti hozzáférést Google-fiókjához, vagy visszaélhetnek személyes adataival. A Chrome azt javasolja, hogy azonnal módosítsa jelszavát.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Kapcsolata megszakadt</translation>
<translation id="471880041731876836">Nincs jogosultsága a webhely felkereséséhez</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />A Windows Hálózati diagnosztika futtatása<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Fizetés</translation>
<translation id="4726672564094551039">Házirendek újratöltése</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Indítsa újra a Chromiumot</translation>
@@ -508,6 +525,7 @@
<translation id="5019198164206649151">A háttértároló állapota nem megfelelő</translation>
<translation id="5023310440958281426">Ellenőrizze rendszergazdai házirendjeit</translation>
<translation id="5029568752722684782">Példány törlése</translation>
+<translation id="503069730517007720">A(z) „<ph name="SOFTWARE_NAME" />” szoftverhez főtanúsítványra van szükség, amely azonban nincs telepítve. A rendszergazda a(z) „<ph name="SOFTWARE_NAME" />” beállítási útmutatójában találhat segítséget a probléma megoldásához. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">A Google Fordító leírása</translation>
<translation id="5039804452771397117">Engedélyezés</translation>
<translation id="5040262127954254034">Adatvédelem</translation>
@@ -531,6 +549,8 @@
<translation id="5199729219167945352">Kísérletek</translation>
<translation id="5205222826937269299">A név megadása kötelező</translation>
<translation id="5222812217790122047">Az e-mail-cím megadása kötelező</translation>
+<translation id="522700295135997067">Előfordulhat, hogy a webhely éppen most lopta el a jelszavát</translation>
+<translation id="5230733896359313003">Szállítási cím</translation>
<translation id="5251803541071282808">Felhő</translation>
<translation id="5277279256032773186">A munkahelyén használja a Chrome-ot? A cégek kezelhetik a Chrome-beállításokat alkalmazottaik számára. További információ.</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Kövesse ezeket a lépéseket, ha szeretné átmenetileg letiltani a szoftvert, hogy hozzáférhessen az internethez. Rendszergazdai jogosultságokra lesz szüksége.<ph name="END_PARAGRAPH" />
@@ -545,9 +565,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Kapcsolata a webhellyel nem privát. Bármikor kiléphet a VR módból, ha leveszi a headsetet, és megnyomja a Vissza gombot.</translation>
<translation id="5299298092464848405">Irányelv-előfeldolgozási hiba</translation>
+<translation id="5308380583665731573">Csatlakozás</translation>
<translation id="5308689395849655368">A hibabejelentés ki van kapcsolva.</translation>
<translation id="5317780077021120954">Mentés</translation>
<translation id="5327248766486351172">Név</translation>
+<translation id="5332219387342487447">Szállítási mód</translation>
<translation id="5355557959165512791">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mert a webhely tanúsítványát visszavonták. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal működése később valószínűleg helyreáll.</translation>
<translation id="536296301121032821">Az irányelv-beállítások tárolása sikertelen</translation>
<translation id="5386426401304769735">A webhely tanúsítványlánca SHA-1 titkosítással aláírt tanúsítványt tartalmaz.</translation>
@@ -567,12 +589,15 @@
<translation id="5492298309214877701">Ennek a vállalati, szervezeti vagy iskolai intraneten található webhelynek az URL-címe megegyezik egy külső webhely URL-címével.
<ph name="LINE_BREAK" />
Javasoljuk, hogy forduljon a rendszergazdához.</translation>
+<translation id="5499929369096410817">Adja meg a következő kártya biztonsági kódját: <ph name="CREDIT_CARD" />. A kódot nem menti a rendszer.</translation>
<translation id="5509780412636533143">Kezelt könyvjelzők</translation>
<translation id="5510766032865166053">Előfordulhat, hogy át lett helyezve, vagy törölve lett.</translation>
<translation id="5523118979700054094">Az irányelv neve</translation>
<translation id="552553974213252141">Megfelelően kinyerte a szöveget?</translation>
<translation id="5540224163453853">A kért cikk nem található.</translation>
+<translation id="5541546772353173584">E-mail-cím hozzáadása</translation>
<translation id="5544037170328430102">A(z) <ph name="SITE" /> egy beágyazott oldalának közlendője:</translation>
+<translation id="5545756402275714221">Cikkek Önnek</translation>
<translation id="5556459405103347317">Újratöltés</translation>
<translation id="5560088892362098740">Lejárati dátum</translation>
<translation id="5565735124758917034">Aktív</translation>
@@ -594,6 +619,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Személyre szabott tartalmak fogadása</translation>
<translation id="5675650730144413517">Az oldal nem működik</translation>
+<translation id="5689199277474810259">Exportálás JSON formátumba</translation>
<translation id="5710435578057952990">A webhely valódiságát nem ellenőriztük.</translation>
<translation id="5719499550583120431">Elfogadott feltöltőkártyák.</translation>
<translation id="5720705177508910913">Jelenlegi felhasználó</translation>
@@ -608,27 +634,27 @@
<translation id="5810442152076338065">A(z) <ph name="DOMAIN" /> domainnel való kapcsolata elavult kriptográfiával van titkosítva.</translation>
<translation id="5813119285467412249">&amp;Hozzáadás újra</translation>
<translation id="5838278095973806738">Ne írjon be semmilyen bizalmas adatot (például jelszót vagy hitelkártyaadatot) a webhelyen, mivel a támadók ellophatják.</translation>
+<translation id="5866257070973731571">Telefonszám hozzáadása</translation>
<translation id="5869405914158311789">A webhely nem érhető el</translation>
<translation id="5869522115854928033">Mentett jelszavak</translation>
<translation id="5872918882028971132">Szülői javaslatok</translation>
<translation id="5893752035575986141">Elfogadott hitelkártyák.</translation>
-<translation id="5901630391730855834">Sárga</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (szinkronizálva)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 van használatban}other{# van használatban}}</translation>
<translation id="5959728338436674663">Bizonyos <ph name="BEGIN_WHITEPAPER_LINK" />rendszer-információk és oldaltartalmak<ph name="END_WHITEPAPER_LINK" /> automatikus küldése a Google-nak a veszélyes alkalmazások és webhelyek felderítése érdekében. <ph name="PRIVACY_PAGE_LINK" /></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="5975083100439434680">Kicsinyítés</translation>
+<translation id="597552863672748783">Biztonsági kód megerősítése</translation>
<translation id="598637245381783098">Nem sikerült megnyitni a fizetőalkalmazást</translation>
<translation id="5989320800837274978">Sem fix proxyszerver, sem pedig .pac típusú szkript URL-címe nincs megadva.</translation>
<translation id="5990559369517809815">A szerver felé irányuló kéréseket egy bővítmény blokkolja.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. oldal}other{#. oldal}}</translation>
-<translation id="6017514345406065928">Zöld</translation>
<translation id="6017850046339264347">A(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő támadók megtévesztő alkalmazásokat telepíthetnek, amelyek más alkalmazásnak tettethetik magukat, illetve az Ön nyomon követésére alkalmas adatokat gyűjthetnek. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (szinkronizálva)</translation>
<translation id="6027201098523975773">Adjon meg nevet</translation>
<translation id="6040143037577758943">Bezárás</translation>
-<translation id="6042308850641462728">Hosszabban</translation>
<translation id="6047233362582046994">Ha tisztában van a biztonságát fenyegető kockázatokkal, a káros alkalmazások eltávolítása előtt is <ph name="BEGIN_LINK" />felkeresheti ezt a webhelyet<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">Lehet, hogy ez a tartalom megpróbálja rávenni Önt szoftver telepítésére vagy személyes adatok kiadására. <ph name="BEGIN_LINK" />Megjelenítés mindenképpen<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel a webhely tanúsítványrögzítést használ. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal működése később valószínűleg helyreáll.</translation>
@@ -695,6 +721,7 @@
<translation id="6569060085658103619">Jelenleg bővítményoldalt tekint meg</translation>
<translation id="6596325263575161958">Titkosítási lehetőségek</translation>
<translation id="662080504995468778">Mégse</translation>
+<translation id="6624427990725312378">Kapcsolatfelvételi adatok</translation>
<translation id="6626291197371920147">Adjon meg érvényes kártyaszámot</translation>
<translation id="6628463337424475685">Keresés: <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Előfordulhat, hogy a(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhely támadói olyan veszélyes programokat kísérelnek meg telepíteni az Ön Mac típusú számítógépére, amelyek ellopják vagy törlik adatait (például fotóit, jelszavait, üzeneteit és hitelkártyaadatait). <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -705,7 +732,6 @@
<translation id="6710213216561001401">Előző</translation>
<translation id="6710594484020273272">&lt;Írja be a keresési kifejezést&gt;</translation>
<translation id="6711464428925977395">Valami gond van a proxyszerverrel, vagy a cím nem megfelelő.</translation>
-<translation id="6727102863431372879">Beállítás</translation>
<translation id="674375294223700098">Ismeretlen szervertanúsítvány-hiba.</translation>
<translation id="6753269504797312559">Házirend értéke</translation>
<translation id="6757797048963528358">Eszköze alvó üzemmódba váltott.</translation>
@@ -774,6 +800,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profil elérési útja</translation>
<translation id="7424977062513257142">A weboldal egy beágyazott oldalának közlendője:</translation>
+<translation id="7437289804838430631">Kapcsolatfelvételi adatok hozzáadása</translation>
<translation id="7441627299479586546">Az irányelv tárgya nem megfelelő</translation>
<translation id="7444046173054089907">Ez a webhely le van tiltva</translation>
<translation id="7445762425076701745">Nem sikerült teljesen ellenőrizni a szerver azonosságát, amelyhez kapcsolódik. Egy olyan névvel kapcsolódik a szerverhez, amelynek tulajdonjogát egy külső tanúsítványkibocsátó nem ellenőrizheti. Mivel egyes tanúsítványkibocsátók figyelmen kívül hagyják ezeket a neveket, így semmi nem biztosítja, hogy a kívánt webhelyhez kapcsolódik, és nem egy támadó webhelyhez.</translation>
@@ -784,11 +811,11 @@
<translation id="7481312909269577407">Előre</translation>
<translation id="7485870689360869515">Nem található adat.</translation>
<translation id="7508255263130623398">A visszakapott házirend eszközazonosítója üres, vagy nem felel meg a jelenlegi eszközazonosítónak</translation>
+<translation id="7511955381719512146">Az Ön által használt Wi-Fi-hálózat megkövetelheti a(z) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> felkeresését.</translation>
<translation id="7514365320538308">Letöltés</translation>
<translation id="7518003948725431193">Nem található weboldal az internetcímen:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">A webhellyel való kapcsolata nem privát</translation>
-<translation id="7535087603100972091">Érték</translation>
<translation id="7537536606612762813">Kötelező</translation>
<translation id="7542403920425041731">Az igazolást követően a böngésző megosztja kártyaadatait a webhellyel.</translation>
<translation id="7542995811387359312">Az automatikus bankkártya-kitöltés le van tiltva, mivel ez az űrlap nem biztonságos kapcsolatot használ.</translation>
@@ -799,7 +826,6 @@
<translation id="7567204685887185387">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványát csalással állíthatták ki. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="7568593326407688803">Az oldal nyelve<ph name="ORIGINAL_LANGUAGE" />Kívánja lefordítani?</translation>
<translation id="7569952961197462199">Eltávolítja a hitelkártyát a Chrome-ból?</translation>
-<translation id="7569983096843329377">Fekete</translation>
<translation id="7578104083680115302">A Google rendszerében mentett kártyákkal gyorsan fizethet webhelyeken és alkalmazásokban bármelyik eszközén.</translation>
<translation id="7588950540487816470">Fizikai web</translation>
<translation id="7592362899630581445">A szervertanúsítvány sérti a névre vonatkozó megkötéseket.</translation>
@@ -818,11 +844,13 @@
<translation id="7669271284792375604">A webhelyen lévő támadók megpróbálhatják csellel rávenni Önt olyan programok telepítésére, amelyek károsak a böngészési élmény szempontjából (például módosítják a kezdőlapot, vagy plusz hirdetéseket jelenítenek meg a felkeresett webhelyeken).</translation>
<translation id="7674629440242451245">Érdekli néhány remek új Chrome-funkció? Próbálja ki a fejlesztői csatornánkat a chrome.com/dev webhelyen.</translation>
<translation id="7682287625158474539">Szállítási cím</translation>
+<translation id="7699293099605015246">A cikkek jelenleg nem állnak rendelkezésre</translation>
<translation id="7701040980221191251">Nincs</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Tovább a(z) <ph name="SITE" /> webhelyre (nem biztonságos)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Tanúsítvány</translation>
<translation id="7716147886133743102">Rendszergazda tiltja</translation>
<translation id="7716424297397655342">A webhely nem tölthető be a gyorsítótárból</translation>
+<translation id="7723047071702270851">Kártya szerkesztése</translation>
<translation id="774634243536837715">Veszélyes tartalom letiltva.</translation>
<translation id="7752995774971033316">Nem kezelt</translation>
<translation id="7755287808199759310">A letiltást a szülő oldhatja fel</translation>
@@ -833,21 +861,24 @@
<translation id="7764225426217299476">Cím hozzáadása</translation>
<translation id="777702478322588152">Prefektúra</translation>
<translation id="7791543448312431591">Hozzáadás</translation>
+<translation id="7793553086574152071">A következő alkalommal gyorsabban fizethet, ha Google-fiókjába menti kártyáját.</translation>
<translation id="7793809570500803535">Lehetséges, hogy a(z) <ph name="SITE" /> webhelyen található oldal ideiglenesen nem érhető el, vagy véglegesen új címre költözött.</translation>
<translation id="7800304661137206267">A kapcsolat a(z) <ph name="CIPHER" /> használatával lett kódolva, <ph name="MAC" /> algoritmussal az üzenethitelesítéshez és <ph name="KX" /> algoritmussal a kulcscserélő folyamathoz.</translation>
+<translation id="7802523362929240268">A webhely valódi</translation>
<translation id="780301667611848630">Köszönöm, nem</translation>
<translation id="7805768142964895445">Állapot</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Eltávolítja a javaslatot a Chrome-ból?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> található a(z) „<ph name="SEARCH_STRING" />” kifejezésre</translation>
+<translation id="782886543891417279">Az Ön által használt Wi-Fi-hálózat (<ph name="WIFI_NAME" />) megkövetelheti a bejelentkezést a bejelentkezési oldalán.</translation>
<translation id="785549533363645510">Azonban Ön nem teljesen láthatatlan. Az inkognitómód használata nem rejti el böngészési műveleteit munkáltatója, az internetszolgáltatója és a felkeresett webhelyek elől.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Elfogadott bank- és feltöltőkártyák.</translation>
+<translation id="7878562273885520351">Előfordultat, hogy jelszava már nem biztonságos</translation>
<translation id="7887683347370398519">Ellenőrizze a CVC-t, majd próbálja újra</translation>
<translation id="79338296614623784">Érvényes telefonszámot adjon meg</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">A szerver tanúsítványa még nem érvényes.</translation>
-<translation id="7942349550061667556">Piros</translation>
<translation id="7947285636476623132">Ellenőrizze a lejárati évet, majd próbálja újra</translation>
<translation id="7951415247503192394">(32 bites)</translation>
<translation id="7956713633345437162">Mobil könyvjelzők</translation>
@@ -861,9 +892,13 @@
<translation id="8037357227543935929">Kérdezzen rá (alapértelmezés szerint)</translation>
<translation id="8041089156583427627">Visszajelzés küldése</translation>
<translation id="8041940743680923270">Globális alapértelmezés használata (Megkérdezés)</translation>
+<translation id="8057711352706143257">A(z) „<ph name="SOFTWARE_NAME" />” nincs megfelelően beállítva. A(z) „<ph name="SOFTWARE_NAME" />” eltávolítása általában megoldja a problémát. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Nem sikerült megtekinteni a cikket.</translation>
<translation id="8091372947890762290">Az aktiválás függőben van a szerveren</translation>
+<translation id="8094917007353911263">Az Ön által használt hálózat megkövetelheti a(z) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> felkeresését.</translation>
+<translation id="8103161714697287722">Fizetési mód</translation>
<translation id="8118489163946903409">Fizetési mód</translation>
+<translation id="8127301229239896662">A(z) „<ph name="SOFTWARE_NAME" />” nem megfelelően lett telepítve a számítógépre vagy a hálózatra. A probléma elhárítása érdekében forduljon rendszergazdájához.</translation>
<translation id="8131740175452115882">Megerősítés</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> szerverének <ph name="BEGIN_ABBR" />DNS-címe<ph name="END_ABBR" /> nem található.</translation>
<translation id="8149426793427495338">Számítógépe alvó üzemmódba váltott.</translation>
@@ -886,6 +921,7 @@
<translation id="8289355894181816810">Forduljon a hálózati rendszergazdához, ha nem tudja, hogy ez mit jelent.</translation>
<translation id="8293206222192510085">Könyvjelző hozzáadása</translation>
<translation id="8294431847097064396">Forrás</translation>
+<translation id="8298115750975731693">Az Ön által használt Wi-Fi-hálózat (<ph name="WIFI_NAME" />) megkövetelheti a(z) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> felkeresését.</translation>
<translation id="8306404619377842860">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" />). <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8308427013383895095">A fordítás a hálózati kapcsolat problémája miatt nem sikerült.</translation>
<translation id="8332188693563227489">A hozzáférés megtagadva a következőhöz: <ph name="HOST_NAME" /></translation>
@@ -939,20 +975,21 @@
<translation id="8870413625673593573">Mostanában bezárt</translation>
<translation id="8874824191258364635">Érvényes kártyaszámot adjon meg</translation>
<translation id="8876793034577346603">A hálózati konfiguráció előfeldolgozása sikertelen.</translation>
-<translation id="8889402386540077796">Színárnyalat</translation>
<translation id="8891727572606052622">Érvénytelen proxymód.</translation>
<translation id="889901481107108152">Sajnos ez a kísérlet nem érhető el az Ön operációs rendszerén.</translation>
<translation id="8903921497873541725">Nagyítás</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>
+<translation id="893332455753468063">Név hozzáadása</translation>
<translation id="8938939909778640821">Elfogadott hitel- és feltöltőkártyák</translation>
+<translation id="8957210676456822347">Hitelesítés hitelesítési portállal</translation>
<translation id="8971063699422889582">A szerver tanúsítványa lejárt.</translation>
-<translation id="8986494364107987395">Használati statisztikák és hibajelentések automatikus küldése a Google-nak</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">A felkeresni kívánt webhely ártalmas programokat tartalmaz</translation>
<translation id="8997023839087525404">A szerver olyan tanúsítványt mutatott be, amelyet nem A tanúsítványok átláthatósága keretrendszer segítségével hoztak nyilvánosságra. Ez egyes tanúsítványoknál követelmény annak biztosítása érdekében, hogy az adott tanúsítványok megbízhatók, és védelmet nyújtanak a támadók ellen.</translation>
<translation id="9001074447101275817">A(z) <ph name="DOMAIN" /> proxy felhasználónevet és jelszót kér.</translation>
<translation id="9005998258318286617">A PDF-dokumentum betöltése sikertelen.</translation>
+<translation id="9008201768610948239">Mellőzés</translation>
<translation id="901974403500617787">Rendszerszinten érvényes jelölőket csak a tulajdonos (<ph name="OWNER_EMAIL" />) állíthat be.</translation>
<translation id="9020200922353704812">A hitelkártyához tartozó számlázási cím megadása kötelező</translation>
<translation id="9020542370529661692">Az oldalt lefordítottuk <ph name="TARGET_LANGUAGE" /> nyelvre.</translation>
@@ -962,11 +999,14 @@
<translation id="9049981332609050619">Megpróbálta elérni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver érvénytelen tanúsítványt mutatott be.</translation>
<translation id="9050666287014529139">Összetett jelszó</translation>
<translation id="9065203028668620118">Szerkesztés</translation>
-<translation id="9068849894565669697">Szín kiválasztása</translation>
<translation id="9069693763241529744">Bővítmény tiltja</translation>
<translation id="9076283476770535406">Lehet, hogy felnőtt tartalommal rendelkezik</translation>
<translation id="9078964945751709336">Több információra van szükség</translation>
+<translation id="9080712759204168376">Megrendelés összegzése</translation>
<translation id="9103872766612412690">A(z) <ph name="SITE" /> webhely rendes esetben titkosítást alkalmaz az Ön adatainak védelme érdekében. Amikor a Chromium most csatlakozni próbált, a(z) <ph name="SITE" /> webhely szokatlan és helytelen hitelesítési adatokat küldött vissza.Ez olyankor fordulhat elő, amikor egy támadó megpróbálja magát kiadni a(z) <ph name="SITE" /> webhelynek, vagy valamilyen Wi-Fi-bejelentkezési képernyő megszakította a kapcsolatot. Adatai továbbra is biztonságban vannak, mivel a Chromium még azt megelőzően megszakította a kapcsolatot, hogy bármiféle adatcserére sor kerülhetett volna.</translation>
+<translation id="9106062320799175032">Számlázási cím hozzáadása</translation>
+<translation id="910908805481542201">Segítséget kérek a probléma megoldásához</translation>
+<translation id="9128870381267983090">Csatlakozás hálózathoz</translation>
<translation id="9137013805542155359">Eredeti megjelenítése</translation>
<translation id="9137248913990643158">Indítsa el a Chrome böngészőt és jelentkezzen be az alkalmazás használata előtt.</translation>
<translation id="9148507642005240123">&amp;Szerkesztés visszavonása</translation>
@@ -978,6 +1018,7 @@
<translation id="9183425211371246419">A(z) <ph name="HOST_NAME" /> egy nem támogatott protokollt használ.</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="9215416866750762878">Valamelyik alkalmazás megakadályozza a Chrome-ot abban, hogy biztonságosan csatlakozzon a webhelyhez</translation>
<translation id="9219103736887031265">Képek</translation>
<translation id="933612690413056017">Nincs internetkapcsolat</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -987,5 +1028,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Nincs}=1{1 elem}other{# elem}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Fejlesztői változat</translation>
+<translation id="989988560359834682">Cím szerkesztése</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">A(z) „<ph name="SOFTWARE_NAME" />” nem megfelelően lett telepítve a számítógépre vagy a hálózatra:
+ &lt;ul&gt;
+ &lt;li&gt;Próbálkozzon a(z) „<ph name="SOFTWARE_NAME" />” eltávolításával vagy letiltásával.&lt;/li&gt;
+ &lt;li&gt;Próbáljon másik hálózathoz csatlakozni.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index b0575a6ceb1..8ca6bcb9a67 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Bookmark Desktop</translation>
<translation id="1074497978438210769">Tidak aman</translation>
<translation id="1080116354587839789">Paskan dengan lebar</translation>
+<translation id="1088860948719068836">Tambahkan Nama di Kartu</translation>
<translation id="1103523840287552314">Selalu terjemahkan <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Tampilkan semua sandi tersimpan...</translation>
<translation id="1107591249535594099">Apabila dicentang, Chrome akan menyimpan salinan kartu Anda pada perangkat ini untuk pengisian formulir yang lebih cepat.</translation>
<translation id="1111153019813902504">Bookmark yang baru dibuka</translation>
<translation id="1113869188872983271">&amp;Urungkan pengaturan ulang</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (disinkronkan)</translation>
<translation id="1263231323834454256">Daftar bacaan</translation>
<translation id="1264126396475825575">Laporan kerusakan diambil pada pukul <ph name="CRASH_TIME" /> (belum diupload atau diabaikan)</translation>
+<translation id="1270502636509132238">Metode Pengambilan</translation>
<translation id="1281526147609854549">Diterbitkan oleh <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Jangan pernah terjemahkan situs ini</translation>
<translation id="129553762522093515">Barusan ditutup</translation>
@@ -66,19 +69,17 @@
<translation id="14171126816530869">Identitas <ph name="ORGANIZATION" /> di <ph name="LOCALITY" /> telah diverifikasi oleh <ph name="ISSUER" />.</translation>
<translation id="1426410128494586442">Ya</translation>
<translation id="1430915738399379752">Cetak</translation>
-<translation id="1506687042165942984">Tampilkan salinan tersimpan (yang diketahui telah habis masa berlakunya) dari laman ini.</translation>
+<translation id="1506687042165942984">Tampilkan salinan tersimpan (yang diketahui telah habis masa berlakunya) dari halaman ini.</translation>
<translation id="1517433312004943670">Perlu nomor telepon</translation>
<translation id="1517500485252541695">Kartu kredit dan debit yang diterima</translation>
<translation id="1519264250979466059">Tanggal Dibuat</translation>
<translation id="1527263332363067270">Menunggu sambungan internet...</translation>
<translation id="153384715582417236">Itu saja untuk sekarang</translation>
<translation id="1549470594296187301">JavaScript harus diaktifkan untuk menggunakan fitur ini.</translation>
-<translation id="1555130319947370107">Biru</translation>
<translation id="1559528461873125649">Tidak ada file atau direktori tersebut</translation>
-<translation id="1583429793053364125">Terjadi masalah sewaktu menampilkan laman web ini.</translation>
+<translation id="1583429793053364125">Terjadi masalah sewaktu menampilkan halaman web ini.</translation>
<translation id="1592005682883173041">Akses Data Lokal</translation>
<translation id="1594030484168838125">Pilih</translation>
-<translation id="161042844686301425">Sian</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Ingin Chrome menyimpan kartu ini?</translation>
<translation id="1639239467298939599">Memuat</translation>
@@ -87,7 +88,7 @@
<translation id="1644184664548287040">Konfigurasi cadangan tidak valid dan tidak dapat diimpor.</translation>
<translation id="1644574205037202324">Riwayat</translation>
<translation id="1645368109819982629">Protokol yang tidak didukung</translation>
-<translation id="1655462015569774233">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir kemarin. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan laman ini.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir # hari yang lalu. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan laman ini.}}</translation>
+<translation id="1655462015569774233">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir kemarin. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan halaman ini.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir # hari yang lalu. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan halaman ini.}}</translation>
<translation id="1656489000284462475">Pengambilan</translation>
<translation id="1663943134801823270">Kartu dan alamat berasal dari Chrome. Anda dapat mengelolanya di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> biasanya menggunakan enkripsi untuk melindungi informasi Anda. Saat Google Chrome mencoba menyambung ke <ph name="SITE" /> kali ini, situs web mengembalikan kredensial yang salah dan tidak biasa. Hal ini dapat terjadi jika ada penyerang yang berpura-pura menjadi <ph name="SITE" />, atau layar masuk Wi-Fi mengganggu sambungan. Informasi Anda masih aman karena Google Chrome menghentikan sambungan sebelum terjadi pertukaran data apa pun.</translation>
@@ -96,13 +97,14 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Anda memerlukan izin dari <ph name="NAME" /> untuk mengunjungi situs ini</translation>
<translation id="1721424275792716183">* Kolom wajib diisi</translation>
+<translation id="1727741090716970331">Tambahkan Nomor Kartu yang Valid</translation>
<translation id="1728677426644403582">Anda melihat sumber halaman web</translation>
<translation id="173080396488393970">Jenis kartu tidak didukung</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Coba hubungi admin sistem.</translation>
<translation id="1740951997222943430">Masukkan bulan habis masa berlaku yang valid</translation>
<translation id="17513872634828108">Buka tab</translation>
-<translation id="1753706481035618306">Nomor laman</translation>
+<translation id="1753706481035618306">Nomor halaman</translation>
<translation id="1763864636252898013">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi perangkat Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Jaringan Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Perbarui frasa sandi sinkronisasi Anda.</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Kesalahan serialisasi</translation>
<translation id="1974060860693918893">Lanjutan</translation>
<translation id="1978555033938440688">Versi Firmware</translation>
-<translation id="1995859865337580572">Harap verifikasi CVC Anda</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lainnya}other{dan # lainnya}}</translation>
<translation id="2025186561304664664">Proxy disetel ke konfigurasi otomatis.</translation>
<translation id="2030481566774242610">Mungkin maksud Anda <ph name="LINK" />?</translation>
@@ -141,14 +142,17 @@
<translation id="2079545284768500474">Urungkan</translation>
<translation id="20817612488360358">Setelan proxy sistem disetel untuk digunakan namun konfigurasi proxy eksplisit juga ditentukan.</translation>
<translation id="2086652334978798447">Untuk mendapatkan konten hasil personalisasi yang disarankan oleh Google, masuk ke Chrome.</translation>
+<translation id="2091887806945687916">Suara</translation>
<translation id="2094505752054353250">Ketidakcocokan domain</translation>
<translation id="2096368010154057602">Departemen</translation>
<translation id="2108755909498034140">Mulai ulang komputer</translation>
<translation id="2113977810652731515">Kartu</translation>
<translation id="2114841414352855701">Diabaikan karena diganti dengan <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Mencari laman Web Fisik di sekitar</translation>
+<translation id="2138201775715568214">Mencari halaman Web Fisik di sekitar</translation>
<translation id="213826338245044447">Bookmark Seluler</translation>
+<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Sinkronisasi Latar Belakang</translation>
+<translation id="2148613324460538318">Tambahkan Kartu</translation>
<translation id="2154054054215849342">Sinkronisasi tidak tersedia untuk domain Anda</translation>
<translation id="2154484045852737596">Edit kartu</translation>
<translation id="2166049586286450108">Akses Penuh Admin</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
<translation id="2187317261103489799">Deteksi (default)</translation>
<translation id="2202020181578195191">Masukkan tahun habis masa berlaku yang valid</translation>
+<translation id="2209523182407020534">Aplikasi yang dapat menyebabkan error ini mencakup antivirus, firewall, dan software proxy atau pemfilteran web.</translation>
<translation id="2212735316055980242">Kebijakan tidak ditemukan</translation>
<translation id="2213606439339815911">Mengambil entri...</translation>
<translation id="2218879909401188352">Saat ini, penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat menginstal aplikasi berbahaya yang dapat merusak perangkat, menambahkan biaya tersembunyi ke tagihan seluler, atau mencuri informasi pribadi Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Kembali</translation>
<translation id="2503184589641749290">Kartu prabayar dan debit yang diterima</translation>
<translation id="2515629240566999685">Periksa sinyal di area Anda</translation>
+<translation id="2524461107774643265">Tambahkan Informasi Lainnya</translation>
+<translation id="2536110899380797252">Tambahkan Alamat</translation>
<translation id="2539524384386349900">Deteksi</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> mengirimkan tanggapan yang tidak valid.</translation>
<translation id="2556876185419854533">&amp;Urungkan Pengeditan</translation>
@@ -212,15 +219,15 @@
<translation id="2653659639078652383">Kirim</translation>
<translation id="2666117266261740852">Tutup tab atau aplikasi lain</translation>
<translation id="2670429602441959756">Halaman ini berisi fitur yang belum didukung dalam VR. Keluar...</translation>
-<translation id="2674170444375937751">Yakin ingin menghapus laman ini dari riwayat?</translation>
+<translation id="2674170444375937751">Yakin ingin menghapus halaman ini dari riwayat?</translation>
<translation id="2677748264148917807">Keluar</translation>
<translation id="2702801445560668637">Daftar Bacaan</translation>
<translation id="2704283930420550640">Nilai tidak sesuai format.</translation>
<translation id="2704951214193499422">Saat ini Chromium tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
<translation id="2705137772291741111">Salinan tersimpan (dalam cache) situs ini tidak dapat dibaca.</translation>
<translation id="2709516037105925701">Isi-Otomatis</translation>
+<translation id="2710942282213947212">Software di komputer membuat Chromium tidak terhubung dengan aman ke web</translation>
<translation id="2712173769900027643">Minta izin</translation>
-<translation id="2713444072780614174">Putih</translation>
<translation id="2720342946869265578">Di Sekitar</translation>
<translation id="2721148159707890343">Permintaan berhasil</translation>
<translation id="2728127805433021124">Sertifikat server ditandai menggunakan algoritme yang lemah.</translation>
@@ -243,10 +250,11 @@
<translation id="2909946352844186028">Perubahan jaringan terdeteksi.</translation>
<translation id="2916038427272391327">Tutup program lain</translation>
<translation id="2922350208395188000">Sertifikat server tidak dapat diperiksa.</translation>
+<translation id="2925673989565098301">Metode Pengiriman</translation>
<translation id="2928905813689894207">Alamat Penagihan</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lainnya}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lainnya}}</translation>
<translation id="2941952326391522266">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya dari <ph name="DOMAIN2" />. Hal ini disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
-<translation id="2948083400971632585">Anda dapat menonaktifkan proxy apa pun yang dikonfigurasi untuk sambungan dari laman setelan.</translation>
+<translation id="2948083400971632585">Anda dapat menonaktifkan proxy apa pun yang dikonfigurasi untuk sambungan dari halaman setelan.</translation>
<translation id="2955913368246107853">Tutup bilah cari</translation>
<translation id="2958431318199492670">Konfigurasi jaringan tidak mematuhi standar ONC. Bagian dari konfigurasi mungkin tidak diimpor.</translation>
<translation id="2966678944701946121">Habis masa berlaku: <ph name="EXPIRATION_DATE_ABBR" />, ditambahkan pada <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -265,19 +273,21 @@
<translation id="3024663005179499861">Jenis kebijakan salah</translation>
<translation id="3032412215588512954">Ingin memuat ulang situs ini?</translation>
<translation id="3037605927509011580">Yah!</translation>
+<translation id="3039538478787849737">Simpan kartu ke Google?</translation>
<translation id="3041612393474885105">Informasi Sertifikat</translation>
<translation id="3063697135517575841">Saat ini Chrome tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
<translation id="3064966200440839136">Keluar dari mode penyamaran untuk membayar melalui aplikasi eksternal. Lanjutkan?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Tidak ada}=1{1 sandi}other{# sandi}}</translation>
<translation id="3093245981617870298">Anda sedang offline.</translation>
<translation id="3105172416063519923">ID Aset:</translation>
-<translation id="3109728660330352905">Anda tidak memiliki otorisasi untuk melihat laman ini.</translation>
+<translation id="3109728660330352905">Anda tidak memiliki otorisasi untuk melihat halaman ini.</translation>
<translation id="3120730422813725195">Elo</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Konektivitas<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Gagal mendekodekan tanggapan</translation>
<translation id="3150653042067488994">Kesalahan server sementara</translation>
<translation id="3154506275960390542">Halaman ini berisi formulir yang mungkin tidak dikirim dengan aman. Data yang Anda kirim dapat dilihat oleh orang lain saat transit atau dapat diubah oleh penyerang untuk mengubah data yang akan diterima server.</translation>
<translation id="3157931365184549694">Pulihkan</translation>
+<translation id="3162559335345991374">Wi-Fi yang digunakan mungkin mewajibkan Anda mengunjungi halaman masuknya.</translation>
<translation id="3167968892399408617">Halaman yang Anda lihat di tab penyamaran tidak akan disimpan dalam riwayat browser, penyimpanan cookie, atau riwayat penelusuran setelah Anda menutup semua tab penyamaran. File apa pun yang didownload atau bookmark yang dibuat akan tetap tersimpan.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Pulau</translation>
@@ -287,13 +297,14 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Batalkan Pembayaran</translation>
<translation id="3207960819495026254">Diberi bookmark</translation>
+<translation id="3211223744486044430">Untuk membayar lebih cepat di lain waktu, simpan kartu ini ke Akun Google Anda dan ke perangkat ini.</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>
-<translation id="3226128629678568754">Tekan tombol muat ulang untuk mengirimkan lagi data yang dibutuhkan untuk memuat laman ini.</translation>
+<translation id="3226128629678568754">Tekan tombol muat ulang untuk mengirimkan lagi data yang dibutuhkan untuk memuat halaman ini.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
-<translation id="3228969707346345236">Terjemahan gagal karena laman sudah dalam bahasa <ph name="LANGUAGE" />.</translation>
+<translation id="3228969707346345236">Terjemahan gagal karena halaman sudah dalam bahasa <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Masukkan CVC untuk <ph name="CREDIT_CARD" /></translation>
<translation id="3234666976984236645">Selalu deteksi konten penting di situs ini</translation>
-<translation id="3254409185687681395">Bookmark laman ini</translation>
+<translation id="3254409185687681395">Bookmark halaman ini</translation>
<translation id="3270847123878663523">&amp;Urungkan Pengaturan Ulang</translation>
<translation id="3282497668470633863">Tambahkan nama di kartu</translation>
<translation id="3286538390144397061">Mulai Ulang Sekarang</translation>
@@ -301,8 +312,7 @@
<translation id="3303855915957856445">Hasil penelusuran tidak ditemukan</translation>
<translation id="3305707030755673451">Data Anda dienkripsi dengan frasa sandi sinkronisasi pada tanggal <ph name="TIME" />. Masukkan frasa sandi untuk memulai sinkronisasi.</translation>
<translation id="3320021301628644560">Tambahkan alamat penagihan</translation>
-<translation id="3329013043687509092">Saturasi</translation>
-<translation id="333371639341676808">Cegah dialog lain dari laman ini.</translation>
+<translation id="333371639341676808">Cegah dialog lain dari halaman ini.</translation>
<translation id="3338095232262050444">Aman</translation>
<translation id="3340978935015468852">setelan</translation>
<translation id="3345135638360864351">Permintaan Anda untuk mengakses situs ini tidak dapat dikirimkan ke <ph name="NAME" />. Coba lagi.</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID Klien:</translation>
<translation id="3391030046425686457">Alamat pengiriman</translation>
<translation id="3395827396354264108">Metode pengambilan</translation>
+<translation id="3399952811970034796">Alamat Pengiriman</translation>
<translation id="3422248202833853650">Coba program lain yang ada untuk mengosongkan memori.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> saat ini tidak dapat dijangkau.</translation>
<translation id="3427092606871434483">Izinkan (default)</translation>
@@ -365,14 +376,16 @@
<translation id="3679803492151881375">Laporan kerusakan direkam pada <ph name="CRASH_TIME" />, diupload pada <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informasi sertifikat</translation>
<translation id="3690164694835360974">Proses masuk tidak aman</translation>
+<translation id="3704162925118123524">Jaringan yang digunakan mungkin mewajibkan Anda mengunjungi halaman masuk jaringan.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Memuat...</translation>
<translation id="3712624925041724820">Lisensi habis</translation>
<translation id="3714780639079136834">Aktifkan data seluler atau Wi-Fi</translation>
+<translation id="3715597595485130451">Menyambung ke jaringan Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Periksa proxy, firewall, dan konfigurasi DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Jika Anda memahami risiko terhadap keamanan, Anda dapat <ph name="BEGIN_LINK" />mengunjungi situs tidak aman ini<ph name="END_LINK" /> sebelum program berbahaya tersebut dibuang.</translation>
<translation id="3739623965217189342">Tautan yang Anda salin</translation>
-<translation id="3744899669254331632">Anda tidak dapat mengunjungi <ph name="SITE" /> sekarang karena situs web mengirim kredensial tak beraturan yang tidak dapat diproses Chromium. Kesalahan jaringan dan serangan biasanya bersifat sementara, sehingga laman ini mungkin akan bekerja nanti.</translation>
+<translation id="3744899669254331632">Anda tidak dapat mengunjungi <ph name="SITE" /> sekarang karena situs web mengirim kredensial tak beraturan yang tidak dapat diproses Chromium. Kesalahan jaringan dan serangan biasanya bersifat sementara, sehingga halaman ini mungkin akan bekerja nanti.</translation>
<translation id="3748148204939282805">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat mengelabui Anda agar melakukan tindakan yang berbahaya seperti menginstal software atau mengungkap informasi pribadi Anda (misalnya sandi, nomor telepon, atau kartu kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="375403751935624634">Terjemahan gagal karena kesalahan server.</translation>
<translation id="3759461132968374835">Tidak ada laporan kondisi ngadat saat ini. Kondisi ngadat yang terjadi saat pelaporan kondisi ngadat tidak diaktifkan tidak akan tampil di sini.</translation>
@@ -398,11 +411,12 @@
<translation id="397105322502079400">Menghitung...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> diblokir.</translation>
<translation id="3987940399970879459">Kurang dari 1 MB</translation>
-<translation id="40103911065039147">{URL_count,plural, =1{1 laman web di sekitar}other{# laman web di sekitar}}</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 halaman web di sekitar}other{# halaman web di sekitar}}</translation>
<translation id="4021036232240155012">DNS adalah layanan jaringan yang menerjemahkan nama situs web ke alamat Internet-nya.</translation>
<translation id="4030383055268325496">&amp;Urungkan penambahan</translation>
<translation id="404928562651467259">PERINGATAN</translation>
<translation id="4058922952496707368">Kunci "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfigurasi proxy disetel untuk menggunakan URL skrip .pac, bukan server proxy yang tetap.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Nomor seri perangkat tidak valid</translation>
<translation id="410351446219883937">Putar otomatis</translation>
<translation id="4103763322291513355">Kunjungi &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat daftar URL yang masuk daftar hitam dan kebijakan lain yang diterapkan oleh administrator sistem Anda.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Selalu izinkan di situs ini</translation>
<translation id="4117700440116928470">Lingkup kebijakan tidak didukung.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 lainnya}other{# lainnya}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi sertifikat yang disajikan oleh server telah dibatalkan oleh penerbitnya. Artinya informasi rahasia keamanan yang disajikan tidak dapat dipercaya. Anda mungkin sedang berkomunikasi dengan penyerang.</translation>
<translation id="4394049700291259645">Nonaktifkan</translation>
<translation id="4406896451731180161">hasil penelusuran</translation>
+<translation id="4415426530740016218">Alamat Pengambilan</translation>
<translation id="4424024547088906515">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chrome. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sertifikat masuk Anda, atau sertifikat masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proxy dinonaktifkan tetapi konfigurasi proxy yang eksplisit ditentukan.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Coba nonaktifkan ekstensi.</translation>
<translation id="457875822857220463">Pengiriman</translation>
+<translation id="4582800630050655161">Anda dapat kehilangan akses ke Akun Google atau mengalami pencurian identitas. Chromium merekomendasikan untuk mengubah sandi saat ini.</translation>
<translation id="4587425331216688090">Hapus alamat dari Chrome?</translation>
<translation id="4592951414987517459">Sambungan Anda ke <ph name="DOMAIN" /> dienkripsi menggunakan cipher suite modern.</translation>
<translation id="4594403342090139922">&amp;Urungkan Penghapusan</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Berhenti menggunakan sertifikat yang tidak valid</translation>
+<translation id="4690954380545377795">Anda dapat kehilangan akses ke Akun Google atau mengalami pencurian identitas. Chrome merekomendasikan untuk mengubah sandi saat ini.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Sambungan Anda terganggu</translation>
<translation id="471880041731876836">Anda tidak memiliki izin untuk membuka situs ini</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Pembayaran Anda</translation>
<translation id="4726672564094551039">Muat ulang kebijakan</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Buka Ulang Chromium</translation>
@@ -485,7 +502,7 @@
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
<translation id="4800132727771399293">Periksa tanggal masa berlaku habis dan CVC, lalu coba lagi</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
-<translation id="4807049035289105102">Saat ini Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut mengirim kredensial acak yang tidak dapat diproses oleh Google Chrome. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti.</translation>
+<translation id="4807049035289105102">Saat ini Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut mengirim kredensial acak yang tidak dapat diproses oleh Google Chrome. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi halaman ini mungkin akan bekerja nanti.</translation>
<translation id="4813512666221746211">Kesalahan jaringan</translation>
<translation id="4816492930507672669">Paskan dengan halaman</translation>
<translation id="483020001682031208">Tidak ada halaman Web Fisik untuk ditampilkan</translation>
@@ -495,7 +512,7 @@
<translation id="4880827082731008257">Telusuri riwayat</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4913131542719409934">Perlu autentikasi</translation>
-<translation id="4914479371620770914">{URL_count,plural, =1{dan 1 laman web lainnya}other{dan # laman web lainnya}}</translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{dan 1 halaman web lainnya}other{dan # halaman web lainnya}}</translation>
<translation id="4916962322362512664"><ph name="DEVICE_NAME" /></translation>
<translation id="4923417429809017348">Laman ini telah diterjemahkan dari bahasa yang tidak diketahui ke bahasa <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Pembayaran</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Penyimpanan cadangan dalam kondisi buruk</translation>
<translation id="5023310440958281426">Periksa kebijakan administrator Anda</translation>
<translation id="5029568752722684782">Hapus salinan</translation>
+<translation id="503069730517007720">Sertifikat root wajib untuk "<ph name="SOFTWARE_NAME" />" tidak diinstal. Administrator IT Anda harus melihat petunjuk konfigurasi untuk "<ph name="SOFTWARE_NAME" />" agar dapat menyelesaikan masalah ini. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Tentang Google Terjemahan</translation>
<translation id="5039804452771397117">Izinkan</translation>
<translation id="5040262127954254034">Privasi</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Eksperimen</translation>
<translation id="5205222826937269299">Nama wajib diisi</translation>
<translation id="5222812217790122047">Email wajib diisi</translation>
+<translation id="522700295135997067">Situs ini mungkin telah mencuri sandi Anda</translation>
+<translation id="5230733896359313003">Alamat Pengiriman</translation>
<translation id="5251803541071282808">Awan</translation>
<translation id="5277279256032773186">Menggunakan Chrome di kantor? Perusahaan dapat mengelola setelan Chrome untuk karyawan mereka. Pelajari lebih lanjut</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Ikuti langkah-langkah berikut untuk menonaktifkan software sementara waktu, sehingga Anda dapat online. Anda memerlukan hak istimewa administrator.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Sambungan Anda ke situs ini tidak bersifat pribadi. Untuk keluar dari mode VR setiap saat, copot headset dan tekan kembali.</translation>
<translation id="5299298092464848405">Kebijakan kesalahan penguraian</translation>
+<translation id="5308380583665731573">Sambungkan</translation>
<translation id="5308689395849655368">Pelaporan kondisi ngadat dinonaktifkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
<translation id="5327248766486351172">Nama</translation>
+<translation id="5332219387342487447">Metode Pengiriman</translation>
<translation id="5355557959165512791">Anda tidak dapat membuka <ph name="SITE" /> sekarang karena sertifikatnya telah dicabut. Error jaringan dan serangan biasanya bersifat sementara, sehingga halaman ini mungkin akan berfungsi nanti.</translation>
<translation id="536296301121032821">Gagal menyimpan setelan kebijakan</translation>
<translation id="5386426401304769735">Rantai sertifikat untuk situs ini berisi sertifikat yang ditandatangani menggunakan SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Situs yang ada di intranet perusahaan, organisasi, atau sekolah ini memiliki URL yang sama dengan situs web eksternal.
<ph name="LINE_BREAK" />
Coba hubungi administrator sistem Anda.</translation>
+<translation id="5499929369096410817">Masukkan kode keamanan untuk <ph name="CREDIT_CARD" />. Kode ini tidak akan disimpan.</translation>
<translation id="5509780412636533143">Mengelola bookmark</translation>
<translation id="5510766032865166053">File mungkin telah dipindahkan atau dihapus.</translation>
<translation id="5523118979700054094">Nama kebijakan</translation>
<translation id="552553974213252141">Apakah teks diekstrak dengan benar?</translation>
<translation id="5540224163453853">Tidak dapat menemukan artikel yang diminta.</translation>
+<translation id="5541546772353173584">Tambahkan Email</translation>
<translation id="5544037170328430102">Laman tersemat di <ph name="SITE" /> menyatakan:</translation>
+<translation id="5545756402275714221">Artikel untuk Anda</translation>
<translation id="5556459405103347317">Muat ulang</translation>
<translation id="5560088892362098740">Tanggal Habis Masa Berlaku</translation>
<translation id="5565735124758917034">Aktif</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Mendapatkan konten hasil personalisasi</translation>
<translation id="5675650730144413517">Halaman ini tidak berfungsi</translation>
+<translation id="5689199277474810259">Ekspor ke JSON</translation>
<translation id="5710435578057952990">Identitas situs Web ini belum diverifikasi.</translation>
<translation id="5719499550583120431">Kartu prabayar diterima.</translation>
<translation id="5720705177508910913">Pengguna saat ini</translation>
@@ -604,33 +630,33 @@
<translation id="5765072501007116331">Untuk melihat persyaratan dan metode pengiriman, pilih alamat</translation>
<translation id="5778550464785688721">Kontrol penuh perangkat MIDI</translation>
<translation id="5784606427469807560">Terjadi masalah saat mengonfirmasi kartu. Periksa sambungan internet Anda dan coba lagi.</translation>
-<translation id="5785756445106461925">Selain itu, laman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah tampilan perangkat.</translation>
+<translation id="5785756445106461925">Selain itu, halaman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah tampilan perangkat.</translation>
<translation id="5786044859038896871">Ingin mengisi informasi kartu?</translation>
<translation id="5803412860119678065">Ingin mengisi <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Sambungan Anda ke <ph name="DOMAIN" /> dienkripsi menggunakan cipher suite yang sudah usang.</translation>
<translation id="5813119285467412249">&amp;Ulangi Penambahan</translation>
<translation id="5838278095973806738">Jangan masukkan informasi sensitif apa pun di situs ini (misalnya, sandi atau kartu kredit), karena penyerang dapat mencurinya.</translation>
+<translation id="5866257070973731571">Tambahkan Nomor Telepon</translation>
<translation id="5869405914158311789">Situs ini tidak dapat dijangkau</translation>
<translation id="5869522115854928033">Sandi tersimpan</translation>
<translation id="5872918882028971132">Saran Induk</translation>
<translation id="5893752035575986141">Kartu kredit diterima.</translation>
-<translation id="5901630391730855834">Kuning</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (disinkronkan)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 terpakai}other{# terpakai}}</translation>
<translation id="5959728338436674663">Kirim beberapa <ph name="BEGIN_WHITEPAPER_LINK" />informasi sistem dan konten halaman<ph name="END_WHITEPAPER_LINK" /> secara otomatis ke Google untuk membantu mendeteksi aplikasi dan situs berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edit Info Kontak</translation>
<translation id="5967867314010545767">Hapus dari riwayat</translation>
<translation id="5975083100439434680">Perkecil</translation>
+<translation id="597552863672748783">Konfirmasi kode keamanan</translation>
<translation id="598637245381783098">Tidak dapat membuka aplikasi pembayaran</translation>
<translation id="5989320800837274978">Baik proxy server tetap ataupun URL skrip .pac tidak ditentukan.</translation>
<translation id="5990559369517809815">Permintaan ke server telah dicekal oleh ekstensi.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Halaman 1}other{Halaman #}}</translation>
-<translation id="6017514345406065928">Hijau</translation>
<translation id="6017850046339264347">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat menginstal aplikasi penipuan dengan berpura-pura menjadi sesuatu yang lain atau mengumpulkan data yang dapat digunakan untuk melacak Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (disinkronkan)</translation>
<translation id="6027201098523975773">Masukkan nama</translation>
<translation id="6040143037577758943">Tutup</translation>
-<translation id="6042308850641462728">Lainnya</translation>
<translation id="6047233362582046994">Jika Anda memahami risiko keamanan tersebut, Anda dapat <ph name="BEGIN_LINK" />mengunjungi situs ini<ph name="END_LINK" /> sebelum aplikasi berbahaya tersebut dihapus.</translation>
<translation id="6047927260846328439">Konten ini mungkin mencoba mengelabui Anda agar menginstal software atau mengungkapkan informasi pribadi. <ph name="BEGIN_LINK" />Tetap tampilkan<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Anda tidak dapat membuka <ph name="SITE" /> sekarang karena situs menggunakan penyematan sertifikat. Error jaringan dan serangan biasanya bersifat sementara, sehingga halaman ini mungkin akan berfungsi nanti.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Anda melihat halaman ekstensi</translation>
<translation id="6596325263575161958">Opsi enkripsi</translation>
<translation id="662080504995468778">Tinggal</translation>
+<translation id="6624427990725312378">Info Kontak</translation>
<translation id="6626291197371920147">Tambahkan kartu yang valid</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Penelusuran</translation>
<translation id="6630809736994426279">Saat ini, penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin berusaha menginstal program berbahaya di Mac Anda yang dapat mencuri atau menghapus informasi Anda (misalnya, foto, sandi, pesan, dan kartu kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Sebelumnya</translation>
<translation id="6710594484020273272">&lt;Ketik istilah penelusuran&gt;</translation>
<translation id="6711464428925977395">Ada yang salah dengan server proxy, atau alamat tidak benar.</translation>
-<translation id="6727102863431372879">Setel</translation>
<translation id="674375294223700098">Kesalahan sertifikat server tidak dikenal.</translation>
<translation id="6753269504797312559">Nilai kebijakan</translation>
<translation id="6757797048963528358">Perangkat Anda sedang dalam mode tidur.</translation>
@@ -775,7 +801,8 @@
<translation id="7390545607259442187">Konfirmasi Kartu</translation>
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Jalur Profil</translation>
-<translation id="7424977062513257142">Laman tersemat di laman web ini menyatakan:</translation>
+<translation id="7424977062513257142">Laman tersemat di halaman web ini menyatakan:</translation>
+<translation id="7437289804838430631">Tambahkan Info Kontak</translation>
<translation id="7441627299479586546">Subjek kebijakan salah</translation>
<translation id="7444046173054089907">Situs ini diblokir</translation>
<translation id="7445762425076701745">Identitas server yang Anda sambungkan tidak dapat divalidasi sepenuhnya. Anda terhubung ke server menggunakan nama yang hanya valid dalam jaringan Anda, yang mana otoritas sertifikat eksternal sama sekali tidak dapat memvalidasi kepemilikannya. Karena sejumlah otoritas sertifikat akan tetap menerbitkan sertifikat untuk nama tersebut, tidak dapat dipastikan apakah Anda akan tersambung ke situs web yang dimaksudkan dan bahwa tidak akan ada penyerang.</translation>
@@ -786,22 +813,21 @@
<translation id="7481312909269577407">Maju</translation>
<translation id="7485870689360869515">Tidak ada data yang ditemukan.</translation>
<translation id="7508255263130623398">ID perangkat kebijakan yang dikembalikan kosong atau tidak cocok dengan ID perangkat saat ini</translation>
+<translation id="7511955381719512146">Wi-Fi yang digunakan mungkin mewajibkan Anda mengunjungi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Download</translation>
-<translation id="7518003948725431193">Tidak ada laman web yang ditemukan untuk alamat web:<ph name="URL" /></translation>
+<translation id="7518003948725431193">Tidak ada halaman web yang ditemukan untuk alamat web:<ph name="URL" /></translation>
<translation id="7521387064766892559">Javascript</translation>
<translation id="7526934274050461096">Koneksi Anda ke situs ini tidak bersifat pribadi</translation>
-<translation id="7535087603100972091">Nilai</translation>
<translation id="7537536606612762813">Wajib</translation>
<translation id="7542403920425041731">Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini.</translation>
<translation id="7542995811387359312">Pengisian kartu kredit otomatis dinonaktifkan karena formulir ini tidak menggunakan sambungan aman.</translation>
<translation id="7543525346216957623">Tanyakan kepada orang tua</translation>
-<translation id="7549584377607005141">Laman web ini membutuhkan data yang Anda masukkan sebelumnya agar dapat ditampilkan dengan benar. Anda dapat mengirimkan data ini lagi, namun dengan begitu Anda akan mengulangi tindakan apa pun yang sebelumnya dilakukan oleh laman ini.</translation>
+<translation id="7549584377607005141">Laman web ini membutuhkan data yang Anda masukkan sebelumnya agar dapat ditampilkan dengan benar. Anda dapat mengirimkan data ini lagi, namun dengan begitu Anda akan mengulangi tindakan apa pun yang sebelumnya dilakukan oleh halaman ini.</translation>
<translation id="7552846755917812628">Coba tips berikut:</translation>
<translation id="7554791636758816595">Tab Baru</translation>
<translation id="7567204685887185387">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin telah dikeluarkan dengan curang. Hal ini disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="7568593326407688803">Laman ini dalam bahasa<ph name="ORIGINAL_LANGUAGE" />Ingin diterjemahkan?</translation>
<translation id="7569952961197462199">Hapus kartu kredit dari Chrome?</translation>
-<translation id="7569983096843329377">Hitam</translation>
<translation id="7578104083680115302">Bayar di situs dan aplikasi di semua perangkat dengan cepat menggunakan kartu yang disimpan dengan Google.</translation>
<translation id="7588950540487816470">Web Fisik</translation>
<translation id="7592362899630581445">Sertifikat server melanggar batasan nama.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Penyerang di situs ini mungkin berusaha mengelabui Anda agar memasang program yang dapat membahayakan pengalaman menjelajah Anda (misalnya dengan mengubah beranda Anda atau menayangkan iklan ekstra pada situs yang dikunjungi).</translation>
<translation id="7674629440242451245">Tertarik dengan fitur Chrome baru yang keren? Coba saluran dev kami di chrome.com/dev.</translation>
<translation id="7682287625158474539">Pengiriman</translation>
+<translation id="7699293099605015246">Artikel tidak tersedia untuk saat ini</translation>
<translation id="7701040980221191251">Tidak ada</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Lanjutkan ke <ph name="SITE" /> (tidak aman)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifikat</translation>
<translation id="7716147886133743102">Diblokir oleh administrator</translation>
<translation id="7716424297397655342">Situs ini tidak dapat dimuat dari cache</translation>
+<translation id="7723047071702270851">Edit Kartu</translation>
<translation id="774634243536837715">Konten berbahaya diblokir.</translation>
<translation id="7752995774971033316">Tidak terkelola</translation>
<translation id="7755287808199759310">Orang tua dapat membuka blokirnya untukmu</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Tambahkan alamat</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Tambahkan</translation>
+<translation id="7793553086574152071">Untuk membayar lebih cepat di pembelian selanjutnya, simpan kartu ini ke Akun Google Anda.</translation>
<translation id="7793809570500803535">Laman web di <ph name="SITE" /> mungkin sedang tidak aktif untuk sementara atau telah dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="7800304661137206267">Sambungan dienkripsi menggunakan <ph name="CIPHER" />, dengan <ph name="MAC" /> untuk autentikasi pesan dan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
+<translation id="7802523362929240268">Situs ini sah</translation>
<translation id="780301667611848630">Lain kali</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Hapus sebagai saran dari Chrome?</translation>
<translation id="7815407501681723534">Ditemukan <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> hasil untuk '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Wi-Fi yang digunakan (<ph name="WIFI_NAME" />) mungkin mewajibkan Anda mengunjungi halaman masuknya.</translation>
<translation id="785549533363645510">Namun, Anda masih dapat terlihat. Masuk ke mode penyamaran tidak menyembunyikan penjelajahan Anda dari atasan, penyedia layanan internet, atau situs web yang Anda kunjungi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Kartu debit dan prabayar diterima.</translation>
+<translation id="7878562273885520351">Sandi Anda mungkin disusupi</translation>
<translation id="7887683347370398519">Periksa CVC dan coba lagi</translation>
<translation id="79338296614623784">Masukkan nomor telepon yang valid</translation>
<translation id="7935318582918952113">Penyaring DOM</translation>
<translation id="7938958445268990899">Sertifikat server belum valid.</translation>
-<translation id="7942349550061667556">Merah</translation>
<translation id="7947285636476623132">Periksa tahun kedaluwarsa dan coba lagi</translation>
<translation id="7951415247503192394">(32 bit)</translation>
<translation id="7956713633345437162">Bookmark seluler</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Tanyakan (default)</translation>
<translation id="8041089156583427627">Kirim Masukan</translation>
<translation id="8041940743680923270">Gunakan default global (Tanyakan)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" tidak dikonfigurasi dengan benar. Biasanya masalah akan terselesaikan dengan meng-uninstal "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
<translation id="8091372947890762290">Aktivasi ditunda di server</translation>
+<translation id="8094917007353911263">Jaringan yang Anda gunakan mungkin mewajibkan Anda mengunjungi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Metode Pembayaran</translation>
<translation id="8118489163946903409">Metode pembayaran</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" tidak diinstal dengan benar di komputer atau jaringan Anda. Mintalah administrator IT untuk menyelesaikan masalah ini.</translation>
<translation id="8131740175452115882">Konfirmasi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> server <ph name="HOST_NAME" /> tidak dapat ditemukan.</translation>
<translation id="8149426793427495338">Komputer Anda sedang dalam mode tidur.</translation>
@@ -880,7 +915,7 @@
<translation id="8225771182978767009">Orang yang menyiapkan komputer ini telah memilih untuk memblokir situs ini.</translation>
<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8238581221633243064">Buka halaman dalam tab Penyamaran baru</translation>
-<translation id="8241707690549784388">Laman yang dicari menggunakan informasi yang Anda masukkan. Kembali ke laman tersebut dapat menyebabkan pengulangan tindakan apa pun yang Anda lakukan. Apakah Anda ingin melanjutkan?</translation>
+<translation id="8241707690549784388">Laman yang dicari menggunakan informasi yang Anda masukkan. Kembali ke halaman tersebut dapat menyebabkan pengulangan tindakan apa pun yang Anda lakukan. Apakah Anda ingin melanjutkan?</translation>
<translation id="8241712895048303527">Blokir di situs ini</translation>
<translation id="8249320324621329438">Terakhir diambil:</translation>
<translation id="8253091569723639551">Perlu alamat penagihan</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Hubungi administrator jaringan Anda jika Anda tidak yakin apa maksudnya.</translation>
<translation id="8293206222192510085">Tambahkan Bookmark</translation>
<translation id="8294431847097064396">Sumber</translation>
+<translation id="8298115750975731693">Wi-Fi yang digunakan (<ph name="WIFI_NAME" />) mungkin mewajibkan Anda mengunjungi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat diterapkan karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) perangkat tidak tepat. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Terjemahan gagal karena ada masalah dengan koneksi jaringan.</translation>
<translation id="8332188693563227489">Akses ke <ph name="HOST_NAME" /> ditolak</translation>
@@ -912,8 +948,8 @@
<translation id="8503813439785031346">Nama Pengguna</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="8543556556237226809">Ada pertanyaan? Hubungi orang yang memantau profil Anda.</translation>
-<translation id="8553075262323480129">Terjemahan gagal karena bahasa laman tidak dapat ditentukan.</translation>
-<translation id="8571890674111243710">Menerjemahkan laman ke <ph name="LANGUAGE" />...</translation>
+<translation id="8553075262323480129">Terjemahan gagal karena bahasa halaman tidak dapat ditentukan.</translation>
+<translation id="8571890674111243710">Menerjemahkan halaman ke <ph name="LANGUAGE" />...</translation>
<translation id="858637041960032120">+ nomor telepon</translation>
<translation id="859285277496340001">Sertifikat tidak menetapkan mekanisme untuk memeriksa apakah sertifikat telah ditarik.</translation>
<translation id="8620436878122366504">Orang tuamu belum menyetujuinya</translation>
@@ -940,35 +976,39 @@
<translation id="8870413625673593573">Barusan Ditutup</translation>
<translation id="8874824191258364635">Masukkan nomor kartu yang valid</translation>
<translation id="8876793034577346603">Konfigurasi jaringan gagal diuraikan.</translation>
-<translation id="8889402386540077796">Rona</translation>
<translation id="8891727572606052622">Mode proxy tidak valid.</translation>
<translation id="889901481107108152">Maaf, percobaan ini tidak tersedia di platform Anda.</translation>
<translation id="8903921497873541725">Perbesar</translation>
<translation id="8931333241327730545">Ingin menyimpan kartu ini ke Akun Google Anda?</translation>
<translation id="8932102934695377596">Setelan waktu Anda terlalu lambat</translation>
+<translation id="893332455753468063">Tambahkan Nama</translation>
<translation id="8938939909778640821">Kartu kredit dan prabayar yang diterima</translation>
+<translation id="8957210676456822347">Otorisasi Portal Tawanan</translation>
<translation id="8971063699422889582">Sertifikat server telah kedaluwarsa.</translation>
-<translation id="8986494364107987395">Kirim statistik penggunaan dan laporan kerusakan ke Google secara otomatis</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Situs yang akan dibuka berisi program berbahaya</translation>
<translation id="8997023839087525404">Server menampilkan sertifikat yang tidak diungkapkan ke publik melalui kebijakan Transparansi Sertifikat. Ini adalah persyaratan untuk beberapa sertifikat, untuk memastikan bahwa sertifikat dapat dipercaya agar terlindung dari penyerang.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> memerlukan nama pengguna dan sandi.</translation>
<translation id="9005998258318286617">Gagal memuat dokumen PDF.</translation>
+<translation id="9008201768610948239">Abaikan</translation>
<translation id="901974403500617787">Tanda yang berlaku bagi sistem secara luas hanya dapat disetel oleh pemilik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Perlu alamat penagihan kartu</translation>
<translation id="9020542370529661692">Laman ini telah diterjemahkan ke <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9035022520814077154">Kesalahan keamanan</translation>
<translation id="9038649477754266430">Gunakan layanan prediksi agar halaman dimuat dengan lebih cepat</translation>
-<translation id="9039213469156557790">Selain itu, laman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah perilaku laman.</translation>
+<translation id="9039213469156557790">Selain itu, halaman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah perilaku halaman.</translation>
<translation id="9049981332609050619">Anda berupaya menjangkau <ph name="DOMAIN" />, tetapi server menyajikan sertifikat yang tidak valid.</translation>
<translation id="9050666287014529139">Frasa sandi</translation>
<translation id="9065203028668620118">Edit</translation>
-<translation id="9068849894565669697">Pilih warna</translation>
<translation id="9069693763241529744">Diblokir oleh ekstensi</translation>
<translation id="9076283476770535406">Situs mungkin berisi konten dewasa</translation>
<translation id="9078964945751709336">Dibutuhkan informasi lebih lanjut</translation>
+<translation id="9080712759204168376">Ringkasan Pesanan</translation>
<translation id="9103872766612412690"><ph name="SITE" /> biasanya menggunakan enkripsi untuk melindungi informasi Anda. Saat Chromium mencoba menyambung ke <ph name="SITE" /> kali ini, situs web mengembalikan kredensial yang salah dan tidak biasa. Hal ini dapat terjadi jika ada penyerang yang berpura-pura menjadi <ph name="SITE" />, atau layar masuk Wi-Fi mengganggu sambungan. Informasi Anda masih aman karena Chromium menghentikan sambungan sebelum terjadi pertukaran data apa pun.</translation>
-<translation id="9137013805542155359">Perlihatkan laman asli</translation>
+<translation id="9106062320799175032">Tambahkan Alamat Penagihan</translation>
+<translation id="910908805481542201">Bantu saya memperbaiki hal ini</translation>
+<translation id="9128870381267983090">Sambungkan ke jaringan</translation>
+<translation id="9137013805542155359">Perlihatkan halaman asli</translation>
<translation id="9137248913990643158">Mulai dan login ke Chrome sebelum menggunakan aplikasi ini.</translation>
<translation id="9148507642005240123">&amp;Urungkan pengeditan</translation>
<translation id="9154194610265714752">Diperbarui</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> menggunakan protokol yang tidak didukung.</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="9215416866750762878">Aplikasi membuat Chrome tidak terhubung dengan aman ke situs ini</translation>
<translation id="9219103736887031265">Gambar</translation>
<translation id="933612690413056017">Tidak ada koneksi Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Tidak ada}=1{1 item}other{# item}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Buatan Pengembang</translation>
+<translation id="989988560359834682">Edit Alamat</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" tidak diinstal dengan benar di komputer atau jaringan Anda:
+ &lt;ul&gt;
+ &lt;li&gt;Coba uninstal atau nonaktifkan "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Coba hubungkan ke jaringan lain&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index 92268665c0d..d1fd85536b7 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Preferiti desktop</translation>
<translation id="1074497978438210769">Non sicuro</translation>
<translation id="1080116354587839789">Adatta in larghezza</translation>
+<translation id="1088860948719068836">Aggiungi il nome indicato sulla carta</translation>
<translation id="1103523840287552314">Traduci sempre <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostra tutte le password salvate…</translation>
<translation id="1107591249535594099">Se questa opzione viene selezionata, Chrome memorizza una copia della carta sul dispositivo per velocizzare la compilazione dei moduli.</translation>
<translation id="1111153019813902504">Preferiti aggiunti di recente</translation>
<translation id="1113869188872983271">&amp;Annulla ridisposizione</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizzati)</translation>
<translation id="1263231323834454256">Elenco di lettura</translation>
<translation id="1264126396475825575">Rapporto sugli arresti anomali generato il giorno <ph name="CRASH_TIME" /> (non ancora caricato o ignorato)</translation>
+<translation id="1270502636509132238">Metodo di ritiro</translation>
<translation id="1281526147609854549">Emesso da <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Non tradurre mai questo sito</translation>
<translation id="129553762522093515">Chiuse di recente</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">In attesa di connessione…</translation>
<translation id="153384715582417236">Per il momento è tutto</translation>
<translation id="1549470594296187301">JavaScript deve essere attivato per utilizzare questa funzione.</translation>
-<translation id="1555130319947370107">Blu</translation>
<translation id="1559528461873125649">Nessun file o directory corrispondente</translation>
<translation id="1583429793053364125">Si è verificato un problema durante la visualizzazione della pagina web.</translation>
<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="1629803312968146339">Vuoi che Chrome salvi questa carta?</translation>
<translation id="1639239467298939599">Caricamento</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1721312023322545264">Ti occorre l'autorizzazione di <ph name="NAME" /> per poter visitare il sito</translation>
<translation id="1721424275792716183">* Campo obbligatorio</translation>
+<translation id="1727741090716970331">Aggiungi un numero di carta valido</translation>
<translation id="1728677426644403582">È visualizzata l'origine di una pagina web</translation>
<translation id="173080396488393970">Questo tipo di carta non è supportato</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Errore di serializzazione</translation>
<translation id="1974060860693918893">Avanzate</translation>
<translation id="1978555033938440688">Versione firmware</translation>
-<translation id="1995859865337580572">Verifica il tuo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{e un'altra}other{e altre #}}</translation>
<translation id="2025186561304664664">È stata impostata la configurazione automatica del proxy.</translation>
<translation id="2030481566774242610">Forse cercavi <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Per ricevere contenuti suggeriti appositamente per te da Google, accedi a Chrome.</translation>
+<translation id="2091887806945687916">Audio</translation>
<translation id="2094505752054353250">Dominio non corrispondente</translation>
<translation id="2096368010154057602">Dipartimento</translation>
<translation id="2108755909498034140">Riavvia il computer</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorata perché è stata sostituita da <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Ricerca di pagine Physical Web nelle vicinanze in corso</translation>
<translation id="213826338245044447">Preferiti su disp. mobili</translation>
+<translation id="214556005048008348">Annulla pagamento</translation>
<translation id="2147827593068025794">Sincronizzazione in background</translation>
+<translation id="2148613324460538318">Aggiungi carta</translation>
<translation id="2154054054215849342">Il servizio di sincronizzazione non è disponibile per il tuo dominio</translation>
<translation id="2154484045852737596">Modifica la carta</translation>
<translation id="2166049586286450108">Accesso amministrativo completo</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}other{# indirizzi}}</translation>
<translation id="2187317261103489799">Rileva (predefinita)</translation>
<translation id="2202020181578195191">Inserisci un anno di scadenza valido</translation>
+<translation id="2209523182407020534">Le applicazioni che possono causare questo errore includono software antivirus, firewall e proxy o di filtraggio web.</translation>
<translation id="2212735316055980242">Criterio non trovato</translation>
<translation id="2213606439339815911">Recupero voci...</translation>
<translation id="2218879909401188352">Gli utenti malintenzionati attualmente presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero installare app pericolose che danneggiano il tuo dispositivo, generano addebiti nascosti sulla fattura del cellulare o si impossessano delle tue informazioni personali. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Indietro</translation>
<translation id="2503184589641749290">Carte di debito e prepagate accettate</translation>
<translation id="2515629240566999685">Controllare il segnale nella tua area</translation>
+<translation id="2524461107774643265">Aggiungi altre informazioni</translation>
+<translation id="2536110899380797252">Aggiungi indirizzo</translation>
<translation id="2539524384386349900">Rileva</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ha inviato una risposta non valida.</translation>
<translation id="2556876185419854533">&amp;Annulla modifica</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Al momento non è possibile confermare la carta in Chromium. Riprova più tardi.</translation>
<translation id="2705137772291741111">La copia del sito salvata (nella cache) era illeggibile.</translation>
<translation id="2709516037105925701">Compilazione automatica</translation>
+<translation id="2710942282213947212">Il software installato sul computer sta impedendo a Chromium di connettersi in sicurezza a Internet</translation>
<translation id="2712173769900027643">Chiedi autorizzazione</translation>
-<translation id="2713444072780614174">Bianco</translation>
<translation id="2720342946869265578">Qui vicino</translation>
<translation id="2721148159707890343">Richiesta riuscita</translation>
<translation id="2728127805433021124">Il certificato del server è stato firmato utilizzando un algoritmo di firma debole.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">È stato rilevato un cambio di rete.</translation>
<translation id="2916038427272391327">Chiudi altri programmi</translation>
<translation id="2922350208395188000">Il certificato del server non può essere verificato.</translation>
+<translation id="2925673989565098301">Metodo di consegna</translation>
<translation id="2928905813689894207">Indirizzo di fatturazione</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> altro}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza proviene da <ph name="DOMAIN2" />. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipo di criterio errato</translation>
<translation id="3032412215588512954">Vuoi ricaricare questo sito?</translation>
<translation id="3037605927509011580">Uffa!</translation>
+<translation id="3039538478787849737">Vuoi salvare la carta in Google?</translation>
<translation id="3041612393474885105">Informazioni certificato</translation>
<translation id="3063697135517575841">Al momento non è possibile confermare la carta in Chrome. Riprova più tardi.</translation>
<translation id="3064966200440839136">Per procedere al pagamento tramite un'applicazione esterna, uscirai dalla modalità di navigazione in incognito. Continuare?</translation>
@@ -278,12 +287,14 @@
<translation id="3150653042067488994">Errore temporaneo del server</translation>
<translation id="3154506275960390542">Questa pagina include un modulo che potrebbe non essere inviato in modo sicuro. I dati inviati possono essere visualizzati da altri durante il transito o potrebbero essere modificati da un utente malintenzionato al fine di modificare i dati ricevuti dal server.</translation>
<translation id="3157931365184549694">Ripristina</translation>
+<translation id="3162559335345991374">La rete Wi-Fi in uso potrebbe richiedere la visita della relativa pagina di accesso.</translation>
<translation id="3167968892399408617">Le pagine visualizzate nelle schede in incognito non vengono memorizzate nella cronologia del browser, nell'archivio di cookie o nella cronologia delle ricerche dopo avere chiuso tutte le schede in incognito. I file scaricati o i preferiti creati verranno conservati.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Isola</translation>
<translation id="3176929007561373547">Controlla le impostazioni del proxy o contatta il tuo amministratore di rete per verificare che il server proxy funzioni. Se non ritieni di dover utilizzare un server proxy: <ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Annulla pagamento</translation>
<translation id="3207960819495026254">Aggiunto ai Preferiti</translation>
+<translation id="3211223744486044430">Per pagare più velocemente la prossima volta, salva questa carta sul tuo account Google e su questo dispositivo.</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>
<translation id="3226128629678568754">Premi il pulsante Ricarica per inviare di nuovo i dati necessari per caricare la pagina.</translation>
<translation id="3227137524299004712">Microfono</translation>
@@ -298,7 +309,6 @@
<translation id="3303855915957856445">Nessun risultato di ricerca trovato</translation>
<translation id="3305707030755673451">I tuoi dati sono stati criptati con la tua passphrase di sincronizzazione in data <ph name="TIME" />. Inseriscila per avviare la sincronizzazione.</translation>
<translation id="3320021301628644560">Aggiungi l'indirizzo di fatturazione</translation>
-<translation id="3329013043687509092">Saturazione</translation>
<translation id="333371639341676808">Impedisci alla pagina di creare altre finestre di dialogo.</translation>
<translation id="3338095232262050444">Sicuro</translation>
<translation id="3340978935015468852">impostazioni</translation>
@@ -317,6 +327,7 @@
<translation id="3380864720620200369">ID client:</translation>
<translation id="3391030046425686457">Indirizzo di consegna</translation>
<translation id="3395827396354264108">Metodo di ritiro</translation>
+<translation id="3399952811970034796">Indirizzo di consegna</translation>
<translation id="3422248202833853650">Prova a uscire da altri programmi per liberare spazio nella memoria.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> non è attualmente raggiungibile.</translation>
<translation id="3427092606871434483">Consenti (predefinita)</translation>
@@ -362,10 +373,12 @@
<translation id="3679803492151881375">Rapporto sugli arresti anomali generato in data <ph name="CRASH_TIME" />, caricato in data <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informazioni certificato</translation>
<translation id="3690164694835360974">Accesso non sicuro</translation>
+<translation id="3704162925118123524">La rete che stai utilizzando può richiedere di visitare la relativa pagina di accesso.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Caricamento in corso...</translation>
<translation id="3712624925041724820">Licenze esaurite</translation>
<translation id="3714780639079136834">Attivare la rete dati mobile o Wi-Fi</translation>
+<translation id="3715597595485130451">Collegati alla rete Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controllare la configurazione del proxy, firewall e DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Se sei consapevole dei rischi per la tua sicurezza, potresti <ph name="BEGIN_LINK" />visitare questo sito non sicuro<ph name="END_LINK" /> senza aspettare che vengano rimossi i programmi pericolosi.</translation>
<translation id="3739623965217189342">Link che hai copiato</translation>
@@ -400,6 +413,7 @@
<translation id="4030383055268325496">&amp;Annulla aggiunta</translation>
<translation id="404928562651467259">AVVISO</translation>
<translation id="4058922952496707368">Chiave "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">L'impostazione della configurazione proxy prevede l'utilizzo di un URL script .pac, non di server proxy fissi.</translation>
@@ -407,7 +421,6 @@
<translation id="4103249731201008433">Il numero di serie del dispositivo non è valido</translation>
<translation id="410351446219883937">Riproduzione automatica</translation>
<translation id="4103763322291513355">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; per visualizzare l'elenco di URL inseriti nella blacklist e altre norme applicate dall'amministratore di sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Consenti sempre su questo sito</translation>
<translation id="4117700440116928470">L'ambito della norma non è supportato.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 altro}other{# altri}}</translation>
@@ -445,6 +458,7 @@
<translation id="4377125064752653719">Hai tentato di accedere a <ph name="DOMAIN" /> ma il server ha presentato un certificato revocato dall'autorità di certificazione. Ciò significa che le credenziali di sicurezza presentate dal server non sono assolutamente attendibili. Potresti avere stabilito una comunicazione con un utente malintenzionato.</translation>
<translation id="4394049700291259645">Disabilita</translation>
<translation id="4406896451731180161">risultati di ricerca</translation>
+<translation id="4415426530740016218">Indirizzo di ritiro</translation>
<translation id="4424024547088906515">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chrome. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> non ha accettato il certificato di accesso oppure non ne è stato fornito uno.</translation>
<translation id="443673843213245140">L'utilizzo di un proxy è stato disattivato ma è stata specificata una configurazione proxy esplicita.</translation>
@@ -457,6 +471,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Prova a disattivare le estensioni.</translation>
<translation id="457875822857220463">Consegna</translation>
+<translation id="4582800630050655161">Potresti non riuscire più ad accedere al tuo account Google o subire un furto d'identità. Chromium ti consiglia di cambiare subito la password.</translation>
<translation id="4587425331216688090">Rimuovere l'indirizzo da Chrome?</translation>
<translation id="4592951414987517459">La connessione a <ph name="DOMAIN" /> è criptata tramite un pacchetto di crittografia moderno.</translation>
<translation id="4594403342090139922">&amp;Annulla eliminazione</translation>
@@ -465,10 +480,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Interrompi l'utilizzo di un certificato non valido</translation>
+<translation id="4690954380545377795">Potresti non riuscire più ad accedere al tuo account Google o subire un furto d'identità. Chrome ti consiglia di cambiare subito la password.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">La connessione è stata interrotta</translation>
<translation id="471880041731876836">Non sei autorizzato a visitare questo sito</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Il tuo pagamento</translation>
<translation id="4726672564094551039">Ricarica norme</translation>
<translation id="4728558894243024398">Piattaforma</translation>
<translation id="4736825316280949806">Riavvia Chromium</translation>
@@ -507,6 +524,7 @@
<translation id="5019198164206649151">Archivio di backup in stato non valido</translation>
<translation id="5023310440958281426">Consulta le norme dell'amministratore</translation>
<translation id="5029568752722684782">Cancella copia</translation>
+<translation id="503069730517007720">Per "<ph name="SOFTWARE_NAME" />" è richiesto un certificato radice che non è installato. L'amministratore IT deve consultare le istruzioni di configurazione relative a "<ph name="SOFTWARE_NAME" />" per risolvere il problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Informazioni su Google Traduttore</translation>
<translation id="5039804452771397117">Consenti</translation>
<translation id="5040262127954254034">Privacy</translation>
@@ -530,6 +548,8 @@
<translation id="5199729219167945352">Esperimenti</translation>
<translation id="5205222826937269299">Nome obbligatorio</translation>
<translation id="5222812217790122047">Email obbligatoria</translation>
+<translation id="522700295135997067">Questo sito potrebbe avere appena rubato la tua password</translation>
+<translation id="5230733896359313003">Indirizzo di spedizione</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Utilizzi Chrome al lavoro? Le aziende possono gestire le impostazioni di Chrome per conto dei propri dipendenti. Ulteriori informazioni</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Svolgi i seguenti passaggi per disattivare temporaneamente il software e accedere così al Web. Devi disporre di privilegi di amministratore.<ph name="END_PARAGRAPH" />
@@ -544,9 +564,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">La tua connessione a questo sito non è privata. Per uscire dalla modalità VR in qualsiasi momento, rimuovi l'auricolare e premi Indietro.</translation>
<translation id="5299298092464848405">Errore durante l'analisi del criterio</translation>
+<translation id="5308380583665731573">Connessione</translation>
<translation id="5308689395849655368">La segnalazione degli arresti anomali è disattivata.</translation>
<translation id="5317780077021120954">Salva</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5332219387342487447">Modalità di spedizione</translation>
<translation id="5355557959165512791">Al momento non puoi visitare il sito <ph name="SITE" /> perché il relativo certificato è stato revocato. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi.</translation>
<translation id="536296301121032821">Archiviazione delle impostazioni criterio non riuscita</translation>
<translation id="5386426401304769735">Il certificato di questo sito contiene un certificato che è stato firmato utilizzando SHA-1.</translation>
@@ -566,12 +588,15 @@
<translation id="5492298309214877701">Il sito nell'Intranet dell'azienda, dell'organizzazione o della scuola ha lo stesso URL del sito web esterno.
<ph name="LINE_BREAK" />
Prova a contattare l'amministratore di sistema.</translation>
+<translation id="5499929369096410817">Inserisci il codice di sicurezza della carta <ph name="CREDIT_CARD" />. Il codice non verrà salvato.</translation>
<translation id="5509780412636533143">Preferiti gestiti</translation>
<translation id="5510766032865166053">Potrebbe essere stato spostato o eliminato.</translation>
<translation id="5523118979700054094">Nome norma</translation>
<translation id="552553974213252141">Il testo è stato estratto correttamente?</translation>
<translation id="5540224163453853">Impossibile trovare l'articolo richiesto.</translation>
+<translation id="5541546772353173584">Aggiungi email</translation>
<translation id="5544037170328430102">Una pagina incorporata in <ph name="SITE" /> dice:</translation>
+<translation id="5545756402275714221">Articoli per te</translation>
<translation id="5556459405103347317">Ricarica</translation>
<translation id="5560088892362098740">Data di scadenza</translation>
<translation id="5565735124758917034">Attivo</translation>
@@ -593,6 +618,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Ricevi contenuti suggeriti appositamente per te</translation>
<translation id="5675650730144413517">La pagina non funziona</translation>
+<translation id="5689199277474810259">Esporta in JSON</translation>
<translation id="5710435578057952990">L'identità di questo sito web non è stata verificata.</translation>
<translation id="5719499550583120431">Le carte prepagate sono accettate.</translation>
<translation id="5720705177508910913">Utente corrente</translation>
@@ -607,27 +633,27 @@
<translation id="5810442152076338065">La connessione a <ph name="DOMAIN" /> è criptata tramite un pacchetto di crittografia obsoleto.</translation>
<translation id="5813119285467412249">&amp;Ripeti aggiunta</translation>
<translation id="5838278095973806738">Non dovresti inserire dati sensibili in questo sito (ad esempio password o carte di credito) perché potrebbero essere intercettati da utenti malintenzionati.</translation>
+<translation id="5866257070973731571">Aggiungi numero di telefono</translation>
<translation id="5869405914158311789">Impossibile raggiungere il sito</translation>
<translation id="5869522115854928033">Password salvate</translation>
<translation id="5872918882028971132">Suggerimenti per i genitori</translation>
<translation id="5893752035575986141">Le carte di credito sono accettate.</translation>
-<translation id="5901630391730855834">Giallo</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizzati)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 in uso}other{# in uso}}</translation>
<translation id="5959728338436674663">Invia automaticamente a Google <ph name="BEGIN_WHITEPAPER_LINK" />alcune informazioni sul sistema e alcuni contenuti delle pagine<ph name="END_WHITEPAPER_LINK" /> per contribuire a rilevare app e siti pericolosi. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Modifica informazioni di contatto</translation>
<translation id="5967867314010545767">Rimuovi da cronologia</translation>
<translation id="5975083100439434680">Diminuisci lo zoom</translation>
+<translation id="597552863672748783">Conferma codice di sicurezza</translation>
<translation id="598637245381783098">Impossibile aprire l'app per i pagamenti</translation>
<translation id="5989320800837274978">Non sono stati specificati né server proxy fissi né un URL script .pac.</translation>
<translation id="5990559369517809815">Le richieste al server sono state bloccate da un'estensione.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}other{Pagina #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Gli utenti malintenzionati presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 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_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizzati)</translation>
<translation id="6027201098523975773">Inserisci un nome</translation>
<translation id="6040143037577758943">Chiudi</translation>
-<translation id="6042308850641462728">Più</translation>
<translation id="6047233362582046994">Se sei consapevole dei rischi per la tua sicurezza, potresti <ph name="BEGIN_LINK" />visitare questo sito<ph name="END_LINK" /> senza aspettare che vengano rimosse le app dannose.</translation>
<translation id="6047927260846328439">Questi contenuti potrebbero cercare di indurti con l'inganno a installare software o a rivelare informazioni personali. <ph name="BEGIN_LINK" />Mostra comunque<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Al momento non puoi visitare il sito web <ph name="SITE" /> perché utilizza il blocco dei certificati. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi.</translation>
@@ -693,6 +719,7 @@
<translation id="6569060085658103619">È visualizzata la pagina di un'estensione</translation>
<translation id="6596325263575161958">Opzioni di crittografia</translation>
<translation id="662080504995468778">Rimani</translation>
+<translation id="6624427990725312378">Informazioni di contatto</translation>
<translation id="6626291197371920147">Aggiungi un numero di carta valido</translation>
<translation id="6628463337424475685">Ricerca <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Gli utenti malintenzionati attualmente presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero cercare di installare sul tuo Mac programmi pericolosi che carpiscono o eliminano le tue informazioni (ad esempio, foto, password, messaggi e carte di credito). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -703,7 +730,6 @@
<translation id="6710213216561001401">Indietro</translation>
<translation id="6710594484020273272">&lt;Digita un termine di ricerca&gt;</translation>
<translation id="6711464428925977395">Si è verificato un problema con il server proxy oppure l'indirizzo non è corretto.</translation>
-<translation id="6727102863431372879">Imposta</translation>
<translation id="674375294223700098">Errore sconosciuto del certificato del server.</translation>
<translation id="6753269504797312559">Valore norma</translation>
<translation id="6757797048963528358">Il dispositivo è entrato in modalità sospensione.</translation>
@@ -772,6 +798,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Percorso profilo</translation>
<translation id="7424977062513257142">Una pagina incorporata in questa pagina web dice:</translation>
+<translation id="7437289804838430631">Aggiungi informazioni di contatto</translation>
<translation id="7441627299479586546">Oggetto del criterio errato</translation>
<translation id="7444046173054089907">Questo sito è bloccato</translation>
<translation id="7445762425076701745">Impossibile convalidare completamente l'identità del server a cui sei collegato. Sei collegato a un server con un nome valido soltanto nella tua rete, di cui un'autorità di certificazione esterna non può convalidare in alcun modo la proprietà. Poiché alcune autorità di certificazione emettono comunque certificati per questi nomi, non è in alcun modo possibile garantire che tu sia collegato al sito web desiderato anziché a un sito dannoso.</translation>
@@ -782,11 +809,11 @@
<translation id="7481312909269577407">Avanti</translation>
<translation id="7485870689360869515">Nessun dato trovato.</translation>
<translation id="7508255263130623398">L'ID dispositivo della norma restituito è vuoto o non corrisponde all'ID dispositivo corrente</translation>
+<translation id="7511955381719512146">La rete Wi-Fi in uso potrebbe richiedere la visita della pagina <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Scarica</translation>
<translation id="7518003948725431193">Nessuna pagina web trovata per l'indirizzo web: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">La connessione a questo sito non è privata</translation>
-<translation id="7535087603100972091">Valore</translation>
<translation id="7537536606612762813">Obbligatoria</translation>
<translation id="7542403920425041731">Dopo essere stati confermati, i dati della carta saranno condivisi con questo sito.</translation>
<translation id="7542995811387359312">La compilazione automatica della carta di credito è disattivata perché questo modulo non utilizza una connessione sicura.</translation>
@@ -797,7 +824,6 @@
<translation id="7567204685887185387">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato emesso in modo fraudolento. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="7568593326407688803">Questa pagina è in<ph name="ORIGINAL_LANGUAGE" />Vuoi tradurla?</translation>
<translation id="7569952961197462199">Rimuovere la carta di credito da Chrome?</translation>
-<translation id="7569983096843329377">Nero</translation>
<translation id="7578104083680115302">Paga velocemente su siti e app su più dispositivi utilizzando le carte salvate su Google.</translation>
<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Il certificato del server vìola i vincoli relativi ai nomi.</translation>
@@ -816,11 +842,13 @@
<translation id="7669271284792375604">I malintenzionati su questo sito potrebbero cercare di indurti con l'inganno a installare programmi che danneggiano la tua navigazione (ad esempio cambiando la tua pagina iniziale o mostrando annunci extra sui siti che visiti).</translation>
<translation id="7674629440242451245">Ti interessano le nuove e straordinarie funzioni di Chrome? Prova il nostro canale Dev all'indirizzo chrome.com/dev.</translation>
<translation id="7682287625158474539">Spedizione</translation>
+<translation id="7699293099605015246">Gli articoli non sono al momento disponibili</translation>
<translation id="7701040980221191251">Nessuno</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Procedi su <ph name="SITE" /> (non sicuro)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificato</translation>
<translation id="7716147886133743102">Bloccata dall'amministratore</translation>
<translation id="7716424297397655342">Impossibile caricare il sito dalla cache</translation>
+<translation id="7723047071702270851">Modifica la carta</translation>
<translation id="774634243536837715">Contenuti pericolosi bloccati.</translation>
<translation id="7752995774971033316">Non gestito</translation>
<translation id="7755287808199759310">Il tuo genitore può sbloccarlo per te</translation>
@@ -831,21 +859,24 @@
<translation id="7764225426217299476">Aggiungi indirizzo</translation>
<translation id="777702478322588152">Prefettura</translation>
<translation id="7791543448312431591">Aggiungi</translation>
+<translation id="7793553086574152071">Per pagare più velocemente la prossima volta, salva questa carta sul tuo account Google.</translation>
<translation id="7793809570500803535">La pagina web all'indirizzo <ph name="SITE" /> potrebbe non essere momentaneamente disponibile o potrebbe essere stata spostata definitivamente su un nuovo indirizzo web.</translation>
<translation id="7800304661137206267">La connessione è stata criptata utilizzando <ph name="CIPHER" />, con <ph name="MAC" /> per l'autenticazione dei messaggi e <ph name="KX" /> come meccanismo principale di scambio delle chiavi.</translation>
+<translation id="7802523362929240268">Il sito è legittimo</translation>
<translation id="780301667611848630">No grazie</translation>
<translation id="7805768142964895445">Stato</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Rimuovere il suggerimento per i moduli da Chrome?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> per "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /></translation>
+<translation id="782886543891417279">La rete Wi-Fi in uso (<ph name="WIFI_NAME" />) potrebbe richiedere la visita della relativa pagina di accesso.</translation>
<translation id="785549533363645510">Non sei completamente invisibile: se navighi in incognito, la tua navigazione non viene nascosta al tuo datore di lavoro, al provider di servizi Internet o ai siti web che visiti.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Le carte di debito e prepagate sono accettate.</translation>
+<translation id="7878562273885520351">La tua password potrebbe essere stata compromessa</translation>
<translation id="7887683347370398519">Controlla il tuo codice CVC e riprova</translation>
<translation id="79338296614623784">Inserisci un numero di telefono valido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Il certificato del server non è ancora valido.</translation>
-<translation id="7942349550061667556">Rosso</translation>
<translation id="7947285636476623132">Controlla l'anno di scadenza e riprova</translation>
<translation id="7951415247503192394">(a 32 bit)</translation>
<translation id="7956713633345437162">Preferiti su disp. mobili</translation>
@@ -859,9 +890,13 @@
<translation id="8037357227543935929">Chiedi (predefinita)</translation>
<translation id="8041089156583427627">Invia feedback</translation>
<translation id="8041940743680923270">Usa predefinita globale (Chiedi)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" non è configurato correttamente. La disinstallazione di "<ph name="SOFTWARE_NAME" />" solitamente risolve il problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Impossibile visualizzare l'articolo.</translation>
<translation id="8091372947890762290">Attivazione in attesa sul server</translation>
+<translation id="8094917007353911263">La rete in uso potrebbe richiedere la visita della pagina <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Metodo di pagamento</translation>
<translation id="8118489163946903409">Metodo di pagamento</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" non è stato installato correttamente sul computer o sulla rete. Chiedi all'amministratore IT di risolvere il problema.</translation>
<translation id="8131740175452115882">Conferma</translation>
<translation id="8134994873729925007">Impossibile trovare l'<ph name="BEGIN_ABBR" />indirizzo DNS<ph name="END_ABBR" /> del server <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Il computer è entrato in modalità sospensione.</translation>
@@ -884,6 +919,7 @@
<translation id="8289355894181816810">Contatta l'amministratore di rete se non sei sicuro del significato.</translation>
<translation id="8293206222192510085">Aggiunta preferito</translation>
<translation id="8294431847097064396">Origine</translation>
+<translation id="8298115750975731693">La rete Wi-Fi in uso (<ph name="WIFI_NAME" />) potrebbe richiedere la visita della pagina <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">La traduzione non è riuscita a causa di un problema con la connessione di rete.</translation>
<translation id="8332188693563227489">Accesso a <ph name="HOST_NAME" /> negato</translation>
@@ -936,20 +972,21 @@
<translation id="8870413625673593573">Chiusi di recente</translation>
<translation id="8874824191258364635">Inserisci un numero di carta di credito valido</translation>
<translation id="8876793034577346603">Analisi della configurazione di rete non riuscita.</translation>
-<translation id="8889402386540077796">Tonalità</translation>
<translation id="8891727572606052622">Modalità proxy non valida.</translation>
<translation id="889901481107108152">Spiacenti, questo esperimento non è disponibile sulla tua piattaforma.</translation>
<translation id="8903921497873541725">Aumenta lo zoom</translation>
<translation id="8931333241327730545">Vuoi salvare la scheda nel tuo account Google?</translation>
<translation id="8932102934695377596">L'orologio è indietro</translation>
+<translation id="893332455753468063">Aggiungi nome</translation>
<translation id="8938939909778640821">Carte di credito e prepagate accettate</translation>
+<translation id="8957210676456822347">Autorizzazione Captive Portal</translation>
<translation id="8971063699422889582">Il certificato del server è scaduto.</translation>
-<translation id="8986494364107987395">Invia automaticamente a Google statistiche sull'utilizzo e rapporti sugli arresti anomali</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Il sito che stai per visitare contiene programmi dannosi</translation>
<translation id="8997023839087525404">Il server ha presentato un certificato che non è stato reso pubblico tramite le norme di Certificate Transparency, la cui applicazione costituisce un requisito di alcuni certificati al fine di garantire la loro attendibilità nonché la sicurezza nei confronti dei malintenzionati.</translation>
<translation id="9001074447101275817">Il proxy <ph name="DOMAIN" /> richiede un nome utente e una password.</translation>
<translation id="9005998258318286617">Impossibile caricare il documento PDF.</translation>
+<translation id="9008201768610948239">Ignora</translation>
<translation id="901974403500617787">I contrassegni che si applicano a livello di sistema possono essere impostati solo dal proprietario: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Indirizzo di fatturazione della carta obbligatorio</translation>
<translation id="9020542370529661692">Questa pagina è stata tradotta in <ph name="TARGET_LANGUAGE" /></translation>
@@ -959,11 +996,14 @@
<translation id="9049981332609050619">Hai tentato di connetterti a <ph name="DOMAIN" />, ma il server ha presentato un certificato scaduto.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Modifica</translation>
-<translation id="9068849894565669697">Seleziona colore</translation>
<translation id="9069693763241529744">Bloccata da un'estensione</translation>
<translation id="9076283476770535406">Può includere contenuti per adulti</translation>
<translation id="9078964945751709336">Sono necessarie maggiori informazioni</translation>
+<translation id="9080712759204168376">Riepilogo dell'ordine</translation>
<translation id="9103872766612412690"><ph name="SITE" /> in genere utilizza la crittografia per proteggere le tue informazioni. Questa volta, quando Chromium ha provato a connettersi a <ph name="SITE" />, il sito web ha restituito credenziali insolite e sbagliate. È possibile che un malintenzionato stia cercando di spacciarsi per il sito <ph name="SITE" /> oppure che una schermata di accesso alla rete Wi-Fi abbia interrotto la connessione. Le tue informazioni sono ancora al sicuro perché Chromium ha interrotto la connessione prima che avvenissero scambi di dati.</translation>
+<translation id="9106062320799175032">Aggiungi indirizzo di fatturazione</translation>
+<translation id="910908805481542201">Aiutami a risolvere il problema</translation>
+<translation id="9128870381267983090">Collegati alla rete</translation>
<translation id="9137013805542155359">Mostra originale</translation>
<translation id="9137248913990643158">Accedi a Chrome prima di usare questa app.</translation>
<translation id="9148507642005240123">&amp;Annulla modifica</translation>
@@ -975,6 +1015,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utilizza un protocollo non supportato.</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="9215416866750762878">Un'applicazione sta impedendo a Chrome di connettersi in sicurezza a questo sito.</translation>
<translation id="9219103736887031265">Immagini</translation>
<translation id="933612690413056017">Connessione Internet assente</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -984,5 +1025,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Nessuno}=1{1 elemento}other{# elementi}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Build</translation>
+<translation id="989988560359834682">Modifica indirizzo</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" non è stato installato correttamente sul computer o sulla rete:
+ &lt;ul&gt;
+ &lt;li&gt;Prova a disinstallare o disattivare "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Prova a collegarti a un'altra rete&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index 9c49fb858a4..2eff5d0fa48 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">סימניות שולחן עבודה</translation>
<translation id="1074497978438210769">לא מאובטח</translation>
<translation id="1080116354587839789">התאם לרוחב</translation>
+<translation id="1088860948719068836">הוספת השם שמופיע בכרטיס</translation>
<translation id="1103523840287552314">תרגם <ph name="LANGUAGE" /> תמיד</translation>
+<translation id="1103778128462718200">הצגת כל הסיסמאות השמורות...</translation>
<translation id="1107591249535594099">‏אם האפשרות הזו מסומנת, Chrome ישמור עותק של הכרטיס במכשיר הזה כדי למלא טפסים במהירות רבה יותר.</translation>
<translation id="1111153019813902504">סימניות אחרונות</translation>
<translation id="1113869188872983271">&amp;ביטול של שינוי סדר</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (מסונכרנים)</translation>
<translation id="1263231323834454256">רשימת קריאה</translation>
<translation id="1264126396475825575">דוח הקריסה תועד ב-<ph name="CRASH_TIME" /> (עדיין לא העלית אותו או בחרת להתעלם ממנו)</translation>
+<translation id="1270502636509132238">שיטת איסוף</translation>
<translation id="1281526147609854549">הונפק על-ידי <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">לעולם אל תתרגם אתר זה</translation>
<translation id="129553762522093515">נסגרו לאחרונה</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">ממתין לחיבור...</translation>
<translation id="153384715582417236">זה הכול בינתיים</translation>
<translation id="1549470594296187301">‏JavaScript צריך להיות מופעל כדי להשתמש בתכונה זו.</translation>
-<translation id="1555130319947370107">כחול</translation>
<translation id="1559528461873125649">אין קובץ או ספרייה בשם זה</translation>
<translation id="1583429793053364125">משהו השתבש בעת הצגת דף אינטרנט זה.</translation>
<translation id="1592005682883173041">גישה לנתונים מקומיים</translation>
<translation id="1594030484168838125">בחר</translation>
-<translation id="161042844686301425">ציאן</translation>
<translation id="1620510694547887537">מצלמה</translation>
<translation id="1629803312968146339">‏האם תרצה ש-Chrome ישמור את הכרטיס הזה?</translation>
<translation id="1639239467298939599">טוען</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">מערכת הפעלה</translation>
<translation id="1721312023322545264">עליך לפנות אל <ph name="NAME" /> לקבלת הרשאה לביקור באתר הזה</translation>
<translation id="1721424275792716183">* זהו שדה חובה</translation>
+<translation id="1727741090716970331">הוספת מספר כרטיס חוקי</translation>
<translation id="1728677426644403582">אתה מציג את המקור של דף אינטרנט</translation>
<translation id="173080396488393970">אין תמיכה בכרטיס מסוג זה</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">שגיאה בעריכה בסידרה</translation>
<translation id="1974060860693918893">מתקדם</translation>
<translation id="1978555033938440688">גרסת קושחה</translation>
-<translation id="1995859865337580572">הזן את קוד האימות</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ואפליקציה אחת נוספת}two{ושתי אפליקציות נוספות}many{ו-# אפליקציות נוספות}other{ו-# אפליקציות נוספות}}</translation>
<translation id="2025186561304664664">‏שרת Proxy נקבע למוגדר אוטומטית.</translation>
<translation id="2030481566774242610">האם התכוונת ל-<ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">בטל פעולה</translation>
<translation id="20817612488360358">‏נקבע שימוש בהגדרות שרת Proxy של מערכת אך בנוסף מצוינת גם תצורה מפורשת של שרת Proxy.</translation>
<translation id="2086652334978798447">‏כדי לקבל מ-Google הצעות לתוכן מותאם אישית, היכנס אל Chrome.</translation>
+<translation id="2091887806945687916">צליל</translation>
<translation id="2094505752054353250">אי התאמה בדומיינים</translation>
<translation id="2096368010154057602">מחלקה</translation>
<translation id="2108755909498034140">אתחול המחשב</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">המערכת התעלמה משום שהמדיניות בוטלה על ידי <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">מחפש דפים של האינטרנט הווירטופיזי בקרבת מקום</translation>
<translation id="213826338245044447">סימניות לנייד</translation>
+<translation id="214556005048008348">ביטול תשלום</translation>
<translation id="2147827593068025794">סינכרון ברקע</translation>
+<translation id="2148613324460538318">הוספת כרטיס</translation>
<translation id="2154054054215849342">סנכרון אינו זמין בדומיין שלך</translation>
<translation id="2154484045852737596">עריכת כרטיס</translation>
<translation id="2166049586286450108">גישה מלאה של מנהל המערכת</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{כתובת אחת}two{שתי כתובות}many{# כתובות}other{# כתובות}}</translation>
<translation id="2187317261103489799">זהה (ברירת מחדל)</translation>
<translation id="2202020181578195191">עליך להזין שנת תפוגה חוקית</translation>
+<translation id="2209523182407020534">יישומים שיכולים לגרום לשגיאה הזו: אנטי וירוס, חומת אש או תוכנת סינון אינטרנט.</translation>
<translation id="2212735316055980242">לא נמצאה מדיניות</translation>
<translation id="2213606439339815911">מאחזר רשומות...</translation>
<translation id="2218879909401188352">תוקפים שמשתמשים עכשיו ב-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> עלולים להתקין יישומים מסוכנים ולגרום נזק למכשיר שלך, להגדיל את החיובים שלך על החבילה לנייד או לגנוב את המידע האישי שלך. <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">חזור</translation>
<translation id="2503184589641749290">כרטיסי חיוב וכרטיסים משולמים מראש שהסוחר מקבל</translation>
<translation id="2515629240566999685">לבדוק את האות באזור שלך</translation>
+<translation id="2524461107774643265">הוספת עוד מידע</translation>
+<translation id="2536110899380797252">הוספת כתובת</translation>
<translation id="2539524384386349900">זהה</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> שלח תגובה לא חוקית.</translation>
<translation id="2556876185419854533">&amp;ביטול עריכה</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">‏ל-Chromium אין כרגע אפשרות לאשר את הכרטיס. נסה שוב מאוחר יותר.</translation>
<translation id="2705137772291741111">העותק השמור (בקובץ השמור) של האתר הזה היה בלתי קריא.</translation>
<translation id="2709516037105925701">מילוי אוטומטי</translation>
+<translation id="2710942282213947212">‏תוכנה במחשב שלך מונעת מ-Chromium להתחבר באופן מאובטח לאינטרנט</translation>
<translation id="2712173769900027643">בקש רשות</translation>
-<translation id="2713444072780614174">לבן</translation>
<translation id="2720342946869265578">קרוב</translation>
<translation id="2721148159707890343">הבקשה בוצעה בהצלחה</translation>
<translation id="2728127805433021124">האישור של השרת נחתם באמצעות אלגוריתם של חתימה חלשה.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">אותר שינוי ברשת.</translation>
<translation id="2916038427272391327">סגירת תוכניות אחרות</translation>
<translation id="2922350208395188000">לא ניתן לבדוק את אישור השרת.</translation>
+<translation id="2925673989565098301">שיטת משלוח</translation>
<translation id="2928905813689894207">כתובת לחיוב</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />. אישור האבטחה שלו הוא מ-<ph name="DOMAIN2" />. ייתכן שהסיבה לכך היא תצורה שגויה או תוקף המיירט את החיבור שלך.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">סוג המדיניות שגוי</translation>
<translation id="3032412215588512954">האם ברצונך לטעון מחדש את האתר?</translation>
<translation id="3037605927509011580">אוי, לא!</translation>
+<translation id="3039538478787849737">‏לשמור את הכרטיס ב-Google?</translation>
<translation id="3041612393474885105">פרטי אישור</translation>
<translation id="3063697135517575841">‏Chrome לא הצליח לאשר את הכרטיס שלך הפעם. נסה שוב מאוחר יותר.</translation>
<translation id="3064966200440839136">בחרת לצאת ממצב גלישה בסתר כדי לשלם באמצעות יישום חיצוני. להמשיך?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">שגיאת שרת זמנית</translation>
<translation id="3154506275960390542">דף זה כולל טופס שעשוי להישלח באופן לא מאובטח. הנתונים שתשלח יהיו גלויים במהלך ההעברה, וקיימת סכנה שמישהו ישנה את הפרטים שהשרת יקבל.</translation>
<translation id="3157931365184549694">שחזר</translation>
+<translation id="3162559335345991374">‏ייתכן שתידרש להיכנס לדף ההתחברות של רשת ה-Wi-Fi שבה אתה משתמש.</translation>
<translation id="3167968892399408617">‏דפים שאתה מציג בכרטיסיות גלישה בסתר לא יישארו בהיסטוריית הדפדפן, באחסון קובצי ה-Cookie או בהיסטוריית החיפושים לאחר שתסגור את כל כרטיסיות הגלישה בסתר. קבצים שהורדת או סימניות שיצרת יישמרו.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">אי</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">בטל תשלום</translation>
<translation id="3207960819495026254">מסומן בסימניה</translation>
+<translation id="3211223744486044430">‏אם שומרים את פרטי הכרטיס בחשבון Google ובמכשיר זה, בפעם הבאה התשלום יהיה מהיר יותר.</translation>
<translation id="3225919329040284222">השרת הציג אישור שאינו תואם את הציפיות המובנות. ציפיות אלה נכללות עבור אתרי אינטרנט מסוימים בעלי אבטחה גבוהה כדי להגן עליך.</translation>
<translation id="3226128629678568754">לחץ על לחצן הטעינה מחדש כדי לשלוח מחדש את הנתונים הדרושים לטעינת הדף.</translation>
<translation id="3227137524299004712">מיקרופון</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">לא נמצאו תוצאות חיפוש</translation>
<translation id="3305707030755673451">הנתונים שלך הוצפנו ב-<ph name="TIME" /> באמצעות ביטוי הסיסמה לסינכרון. הזן אותו כדי להתחיל בסינכרון.</translation>
<translation id="3320021301628644560">הוספה של כתובת לחיוב</translation>
-<translation id="3329013043687509092">רווייה</translation>
<translation id="333371639341676808">מנע מדף זה ליצור דיאלוגים נוספים.</translation>
<translation id="3338095232262050444">מאובטח</translation>
<translation id="3340978935015468852">הגדרות</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">מספר לקוח:</translation>
<translation id="3391030046425686457">כתובת למשלוח</translation>
<translation id="3395827396354264108">שיטת איסוף</translation>
+<translation id="3399952811970034796">כתובת למשלוח</translation>
<translation id="3422248202833853650">מומלץ לצאת מתוכניות אחרות וכך לפנות מקום בזיכרון.</translation>
<translation id="3422472998109090673">לא ניתן לגשת כרגע אל <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">התר (ברירת מחדל)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">דוח קריסה תועד ב-<ph name="CRASH_TIME" />, הועלה ב-<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">פרטי אישור</translation>
<translation id="3690164694835360974">ההתחברות אינה מאובטחת</translation>
+<translation id="3704162925118123524">ייתכן שתוצג דרישה להיכנס לדף ההתחברות של הרשת שבה אתה משתמש.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">טוען...</translation>
<translation id="3712624925041724820">אין מספיק רישיונות</translation>
<translation id="3714780639079136834">‏להפעיל נתונים לנייד או את ה-Wi-Fi</translation>
+<translation id="3715597595485130451">‏התחברות ל-Wi-Fi</translation>
<translation id="3717027428350673159">‏<ph name="BEGIN_LINK" />לבדוק את תצורת ה-DNS, חומת האש ושרת ה-Proxy<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">אם אתה מבין את הסיכונים בנוגע לאבטחה שלך, תוכל <ph name="BEGIN_LINK" />להיכנס לאתר לא בטוח זה<ph name="END_LINK" /> לפני הסרת התכניות המסוכנות.</translation>
<translation id="3739623965217189342">קישור שהעתקת</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;ביטול הוספה</translation>
<translation id="404928562651467259">אזהרה</translation>
<translation id="4058922952496707368">מפתח "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">הוספה של כתובת חוקית</translation>
<translation id="4072486802667267160">התרחשה שגיאה במהלך עיבוד התשלום שלך. נסה שוב.</translation>
<translation id="4075732493274867456">‏הלקוח והשרת אינם תומכים בגרסה נפוצה של פרוטוקול SSL או בחבילת צפנים.</translation>
<translation id="4079302484614802869">‏תצורת ה-Proxy מוגדרת להשתמש בכתובת אתר של סקריפט מסוג ‎.Pac ולא בשרתי Proxy קבועים.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">המספר הסידורי של המכשיר אינו חוקי</translation>
<translation id="410351446219883937">הפעלה אוטומטית</translation>
<translation id="4103763322291513355">‏היכנס לכתובת &lt;strong&gt;chrome://policy&lt;/strong&gt; כדי לראות רשימה של כתובות אתרים שנמנעה אליהם הגישה, כמו גם תקנונים אחרים שנאכפו על ידי מנהל המערכת שלך.</translation>
-<translation id="4115378294792113321">מגנטה</translation>
<translation id="4116663294526079822">אפשר תמיד באתר זה</translation>
<translation id="4117700440116928470">היקף המדיניות אינו נתמך.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{אחד נוסף}two{שניים נוספים}many{# נוספים}other{# נוספים}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">ניסית להשיג את <ph name="DOMAIN" />, אך האישור שהשרת הציג בוטל על ידי המנפיק שלו. פירוש הדבר שאין כל אפשרות לתת אמון באישורי האבטחה שהשרת הציג. ייתכן שאתה מתקשר עם תוקף.</translation>
<translation id="4394049700291259645">השבת</translation>
<translation id="4406896451731180161">תוצאות חיפוש</translation>
+<translation id="4415426530740016218">כתובת איסוף</translation>
<translation id="4424024547088906515">‏השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />. אישור האבטחה שלו לא נחשב כמהימן על ידי Chrome. ייתכן שהסיבה לכך היא תצורה שגויה או תוקף המיירט את החיבור שלך.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> לא אישר את אישור ההתחברות שלך, או שלא סופק אישור התחברות.</translation>
<translation id="443673843213245140">‏השימוש בשרת Proxy הושבת, אך צויינה תצורת שרת Proxy מפורשת.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">נסה להשבית את התוספים.</translation>
<translation id="457875822857220463">משלוח</translation>
+<translation id="4582800630050655161">‏הגישה שלך לחשבון Google עלולה להישלל והזהות שלך עלולה להיגנב. לגלישה בטוחה ב-Chromium, מומלץ לשנות את הסיסמה עכשיו.</translation>
<translation id="4587425331216688090">‏האם להסיר את הכתובת מ-Chrome?</translation>
<translation id="4592951414987517459">החיבור שלך אל <ph name="DOMAIN" /> מוצפן באמצעות חבילת צופן מתקדמת.</translation>
<translation id="4594403342090139922">&amp;ביטול מחיקה</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />; אישור האבטחה שלו מכיל שגיאות. ייתכן שהסיבה לכך היא הגדרה שגויה או תוקף המיירט את החיבור שלך.</translation>
<translation id="4690462567478992370">הפסק להשתמש באישור לא חוקי</translation>
+<translation id="4690954380545377795">‏הגישה שלך לחשבון Google עלולה להישלל והזהות שלך עלולה להיגנב. לגלישה בטוחה ב-Chrome, מומלץ לשנות את הסיסמה עכשיו.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">החיבור נקטע</translation>
<translation id="471880041731876836">אין לך הרשאה להיכנס אל האתר הזה</translation>
<translation id="4722547256916164131">‏<ph name="BEGIN_LINK" />מפעיל את אבחון הרשת של Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">התשלום שלך</translation>
<translation id="4726672564094551039">טען מדיניות מחדש</translation>
<translation id="4728558894243024398">פלטפורמה</translation>
<translation id="4736825316280949806">‏אתחול ה-Chromium</translation>
@@ -514,6 +531,7 @@ Del</translation>
<translation id="5019198164206649151">האחסון המשמש כגיבוי אינו תקין</translation>
<translation id="5023310440958281426">בדוק את תקנון מנהל המערכת שלך</translation>
<translation id="5029568752722684782">נקה את העותק</translation>
+<translation id="503069730517007720">‏יש צורך באישור שורש בשביל "<ph name="SOFTWARE_NAME" />", אבל לא מותקן אישור כזה. על מנהל ה-IT לבדוק את הוראות התצורה של "<ph name="SOFTWARE_NAME" />" כדי לפתור את הבעיה. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">‏מידע על Google Translate</translation>
<translation id="5039804452771397117">אפשר</translation>
<translation id="5040262127954254034">פרטיות</translation>
@@ -537,6 +555,8 @@ Del</translation>
<translation id="5199729219167945352">ניסויים</translation>
<translation id="5205222826937269299">שם (חובה)</translation>
<translation id="5222812217790122047">אימייל (חובה)</translation>
+<translation id="522700295135997067">ייתכן שהאתר הזה גנב עכשיו את הזהות שלך</translation>
+<translation id="5230733896359313003">כתובת למשלוח</translation>
<translation id="5251803541071282808">ענן</translation>
<translation id="5277279256032773186">‏משתמש ב-Chrome בעבודה? עסקים יכולים לנהל את ההגדרות של Chrome עבור העובדים. למידע נוסף</translation>
<translation id="5281113152797308730">‏<ph name="BEGIN_PARAGRAPH" />בצע את השלבים הבאים על מנת להשבית את התוכנה באופן זמני, כדי שתוכל להתחבר לאינטרנט. יש צורך בהרשאות מנהל מערכת.<ph name="END_PARAGRAPH" />
@@ -551,9 +571,11 @@ Del</translation>
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">‏החיבור שלך לאתר זה אינו פרטי. כדי לצאת ממצב VR בכל שלב, הסר את האוזניות ולחץ על 'הקודם'.</translation>
<translation id="5299298092464848405">שגיאה בניתוח המדיניות</translation>
+<translation id="5308380583665731573">התחברות</translation>
<translation id="5308689395849655368">דיווח קריסות מושבת.</translation>
<translation id="5317780077021120954">שמור</translation>
<translation id="5327248766486351172">שם</translation>
+<translation id="5332219387342487447">שיטת משלוח</translation>
<translation id="5355557959165512791">נכון לעכשיו אי אפשר לבקר באתר <ph name="SITE" /> מאחר שהאישור שלו בוטל. שגיאות רשת ומתקפות הן בדרך כלל זמניות, כך שהדף הזה יחזור כנראה לפעול מאוחר יותר.</translation>
<translation id="536296301121032821">אחסון הגדרות המדיניות נכשל</translation>
<translation id="5386426401304769735">‏שרשרת האישורים של האתר הזה כוללת אישור שנחתם באמצעות SHA-1.</translation>
@@ -574,12 +596,15 @@ Del</translation>
של אתר חיצוני.
<ph name="LINE_BREAK" />
נסה ליצור קשר עם מנהל המערכת.</translation>
+<translation id="5499929369096410817">יש להזין את קוד האבטחה של <ph name="CREDIT_CARD" />. המערכת לא תשמור את הקוד.</translation>
<translation id="5509780412636533143">סימניות מנוהלות</translation>
<translation id="5510766032865166053">ייתכן שהוא הועבר או נמחק.</translation>
<translation id="5523118979700054094">שם מדיניות</translation>
<translation id="552553974213252141">האם הטקסט נשלף כראוי?</translation>
<translation id="5540224163453853">לא ניתן היה למצוא את הפריט המבוקש.</translation>
+<translation id="5541546772353173584">הוספת כתובת אימייל</translation>
<translation id="5544037170328430102">דף המוטמע ב-<ph name="SITE" /> אומר:</translation>
+<translation id="5545756402275714221">מאמרים שעשויים לעניין אותך</translation>
<translation id="5556459405103347317">טען שוב</translation>
<translation id="5560088892362098740">תאריך תפוגה</translation>
<translation id="5565735124758917034">פעיל</translation>
@@ -601,6 +626,7 @@ Del</translation>
<translation id="5659593005791499971">אימייל</translation>
<translation id="5669703222995421982">התאמה אישית של תוכן</translation>
<translation id="5675650730144413517">הדף הזה לא עובד</translation>
+<translation id="5689199277474810259">‏ייצוא אל JSON</translation>
<translation id="5710435578057952990">הזהות של אתר זה לא אומתה.</translation>
<translation id="5719499550583120431">אפשר לשלם באמצעות כרטיסים משולמים מראש.</translation>
<translation id="5720705177508910913">משתמש נוכחי:</translation>
@@ -615,27 +641,27 @@ Del</translation>
<translation id="5810442152076338065">החיבור שלך אל <ph name="DOMAIN" /> מוצפן באמצעות חבילת צופן מיושנת.</translation>
<translation id="5813119285467412249">&amp;ביצוע מחדש של הוספה</translation>
<translation id="5838278095973806738">אין להזין מידע רגיש באתר הזה (כמו סיסמאות או מספרי כרטיסי אשראי), מאחר שתוקפים עלולים לקבל אליו גישה.</translation>
+<translation id="5866257070973731571">הוספת מספר טלפון</translation>
<translation id="5869405914158311789">לא ניתן לגשת לאתר הזה</translation>
<translation id="5869522115854928033">סיסמאות שמורות</translation>
<translation id="5872918882028971132">הצעות להורים</translation>
<translation id="5893752035575986141">אפשר לשלם באמצעות כרטיסי אשראי.</translation>
-<translation id="5901630391730855834">צהוב</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (מסונכרנים)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{אחד נמצא בשימוש}two{שניים נמצאים בשימוש}many{# נמצאים בשימוש}other{# נמצאים בשימוש}}</translation>
<translation id="5959728338436674663">‏שלח באופן אוטומטי <ph name="BEGIN_WHITEPAPER_LINK" />חלק מפרטי המערכת ותוכן הדף<ph name="END_WHITEPAPER_LINK" /> אל Google כדי לעזור בזיהוי של אפליקציות ואתרים מסוכנים. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">עריכת הפרטים ליצירת קשר</translation>
<translation id="5967867314010545767">הסר מההיסטוריה</translation>
<translation id="5975083100439434680">התרחק</translation>
+<translation id="597552863672748783">אישור קוד אבטחה</translation>
<translation id="598637245381783098">לא ניתן לפתוח את אפליקציית התשלומים</translation>
<translation id="5989320800837274978">‏לא צוינו שרתי Proxy קבועים ולא כתובת אתר של סקריפט ‎.pac</translation>
<translation id="5990559369517809815">בקשות שנשלחו לשרת נחסמו על ידי תוסף.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{דף 1}two{דף #}many{דף #}other{דף #}}</translation>
-<translation id="6017514345406065928">ירוק</translation>
<translation id="6017850046339264347">תוקפים שמשתמשים ב-<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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (מסונכרנים)</translation>
<translation id="6027201098523975773">עליך להזין שם</translation>
<translation id="6040143037577758943">סגור</translation>
-<translation id="6042308850641462728">עוד</translation>
<translation id="6047233362582046994">אם אתה מבין את סיכוני האבטחה, תוכל <ph name="BEGIN_LINK" />להיכנס לאתר הזה<ph name="END_LINK" /> לפני הסרת היישומים המזיקים.</translation>
<translation id="6047927260846328439">ייתכן שבתוכן הזה יש מידע מטעה שנועד לגרום לך להתקין תוכנות או לחשוף מידע אישי. <ph name="BEGIN_LINK" />הצג בכל זאת<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">נכון לעכשיו אי אפשר לבקר באתר <ph name="SITE" />, מאחר שבאתר הזה נעשה שימוש בנעיצת אישורים. שגיאות רשת ומתקפות הן בדרך כלל זמניות, כך שהדף הזה יחזור כנראה לפעול מאוחר יותר.</translation>
@@ -702,6 +728,7 @@ Del</translation>
<translation id="6569060085658103619">אתה מציג דף של תוסף</translation>
<translation id="6596325263575161958">אפשרויות הצפנה</translation>
<translation id="662080504995468778">הישאר</translation>
+<translation id="6624427990725312378">פרטי איש קשר</translation>
<translation id="6626291197371920147">הוסף מספר כרטיס חוקי</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> חיפוש</translation>
<translation id="6630809736994426279">‏תוקפים שנמצאים כרגע באתר <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> עלולים להתקין במחשב ה-MAC שלך תוכנות מסוכנות שגונבות מידע או מוחקות אותו (לדוגמה, תמונות, סיסמאות, הודעות וכרטיסי אשראי). <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -712,7 +739,6 @@ Del</translation>
<translation id="6710213216561001401">הקודם</translation>
<translation id="6710594484020273272">&lt;הקלד מונח חיפוש&gt;</translation>
<translation id="6711464428925977395">‏משהו אינו תקין בשרת ה-proxy, או שהכתובת שגויה.</translation>
-<translation id="6727102863431372879">הגדר</translation>
<translation id="674375294223700098">שגיאת אישור שרת לא ידוע.</translation>
<translation id="6753269504797312559">ערך מדיניות</translation>
<translation id="6757797048963528358">המכשיר עבר למצב שינה.</translation>
@@ -781,6 +807,7 @@ Del</translation>
<translation id="7400418766976504921">כתובת אתר</translation>
<translation id="7419106976560586862">נתיב פרופיל</translation>
<translation id="7424977062513257142">דף המוטמע בדף אינטרנט זה אומר:</translation>
+<translation id="7437289804838430631">הוספת פרטים ליצירת קשר</translation>
<translation id="7441627299479586546">נושא המדיניות שגוי</translation>
<translation id="7444046173054089907">האתר הזה חסום</translation>
<translation id="7445762425076701745">לא ניתן לאמת לגמרי את הזהות של השרת שאליו אתה מחובר. אתה מחובר לשרת באמצעות שם שקיים רק ברשת שלך, ושלרשות אישורים חיצונית אין דרך לאמת את בעלותך עליו. מכיוון שחלק מרשויות האישורים ינפיקו אישורים לשמות אלה ללא קשר, אין דרך להבטיח שאתה מחובר לאתר המיועד ואינך גורם תוקף.</translation>
@@ -791,11 +818,11 @@ Del</translation>
<translation id="7481312909269577407">קדימה</translation>
<translation id="7485870689360869515">לא נמצאו נתונים.</translation>
<translation id="7508255263130623398">מזהה המכשיר במדיניות שהוחזר ריק או שאינו תואם את מזהה המכשיר הנוכחי</translation>
+<translation id="7511955381719512146">‏ייתכן שתידרש להיכנס ל-<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> עבור רשת ה-Wi-Fi שבה אתה משתמש.</translation>
<translation id="7514365320538308">הורד</translation>
<translation id="7518003948725431193">לא נמצא דף אינטרנט עבור כתובת האינטרנט: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">החיבור שלך לאתר זה אינו פרטי</translation>
-<translation id="7535087603100972091">ערך</translation>
<translation id="7537536606612762813">הכרחי</translation>
<translation id="7542403920425041731">ברגע שתאשר, פרטי הכרטיס שלך ישותפו עם האתר הזה.</translation>
<translation id="7542995811387359312">מילוי אוטומטי של פרטי כרטיס אשראי מושבת כיוון שטופס זה אינו משתמש בחיבור מאובטח.</translation>
@@ -806,7 +833,6 @@ Del</translation>
<translation id="7567204685887185387">השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />. ייתכן שאישור האבטחה שלו נופק כהונאה. הסיבה לכך עשויה להיות הגדרה שגויה או תוקף המיירט את החיבור שלך.</translation>
<translation id="7568593326407688803">זהו דף ב<ph name="ORIGINAL_LANGUAGE" />האם ברצונך לתרגם אותו?</translation>
<translation id="7569952961197462199">‏האם להסיר את כרטיס האשראי מ-Chrome?</translation>
-<translation id="7569983096843329377">שחור</translation>
<translation id="7578104083680115302">‏שלם במהירות באתרים ובאפליקציות בכל המכשירים באמצעות כרטיסים ששמרת ב-Google.</translation>
<translation id="7588950540487816470">האינטרנט הווירטופיזי</translation>
<translation id="7592362899630581445">אישור השרת מפר את אילוצי השמות.</translation>
@@ -825,11 +851,13 @@ Del</translation>
<translation id="7669271284792375604">תוקפים באתר הזה עשויים לגרום לך, בדרכי מרמה, להתקין תוכניות שיפגעו בחוויית הגלישה שלך (לדוגמה, על ידי שינוי דף הבית או הצגת מודעות נוספות באתרים שבהם אתה מבקר).</translation>
<translation id="7674629440242451245">‏מעוניין בתכונות חדשות ומגניבות של Chrome? נסה את הערוץ שלנו למפתחים בכתובת chrome.com/dev.</translation>
<translation id="7682287625158474539">משלוח</translation>
+<translation id="7699293099605015246">לא ניתן להציג כרגע מאמרים</translation>
<translation id="7701040980221191251">ללא</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />המשך אל <ph name="SITE" /> (לא בטוח)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">אישור</translation>
<translation id="7716147886133743102">נחסמה על-ידי מנהל המערכת</translation>
<translation id="7716424297397655342">לא ניתן לטעון את האתר הזה מהמטמון</translation>
+<translation id="7723047071702270851">עריכת כרטיס</translation>
<translation id="774634243536837715">תוכן מסוכן נחסם.</translation>
<translation id="7752995774971033316">ללא ניהול</translation>
<translation id="7755287808199759310">אחד מההורים שלך יכול לבטל בשבילך את החסימה</translation>
@@ -840,21 +868,24 @@ Del</translation>
<translation id="7764225426217299476">הוסף כתובת</translation>
<translation id="777702478322588152">משטרת מחוז</translation>
<translation id="7791543448312431591">הוסף</translation>
+<translation id="7793553086574152071">‏אם שומרים את פרטי הכרטיס בחשבון Google, בפעם הבאה התשלום יהיה מהר יותר.</translation>
<translation id="7793809570500803535">ייתכן שדף האינטרנט בכתובת <ph name="SITE" /> אינו פעיל זמנית, או שהועבר לכתובת אינטרנט חדשה לצמיתות.</translation>
<translation id="7800304661137206267">החיבור מוצפן באמצעות <ph name="CIPHER" /> עם <ph name="MAC" /> לאימות הודעות ועם <ph name="KX" /> בתור מנגנון להחלפת מפתחות.</translation>
+<translation id="7802523362929240268">האתר חוקי</translation>
<translation id="780301667611848630">לא תודה</translation>
<translation id="7805768142964895445">סטטוס</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">‏האם להסיר מ-Chrome הצעות בשביל טפסים?</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="785549533363645510">עם זאת, אינך בלתי נראה. המעבר למצב גלישה בסתר לא מסתיר את הגלישה שלך מהמעסיק, מספק האינטרנט או מהאתרים שאליהם אתה נכנס.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">אפשר לשלם באמצעות כרטיסי חיוב וכרטיסים משולמים מראש.</translation>
+<translation id="7878562273885520351">ייתכן שאבטחת הסיסמה שלך נפגעה</translation>
<translation id="7887683347370398519">‏בדוק את ה-CVC ונסה שוב</translation>
<translation id="79338296614623784">עליך להזין מספר טלפון חוקי</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">אישור השרת עדיין לא בתוקף.</translation>
-<translation id="7942349550061667556">אדום</translation>
<translation id="7947285636476623132">בדוק את שנת התפוגה ונסה שוב</translation>
<translation id="7951415247503192394">(32 סיביות)</translation>
<translation id="7956713633345437162">סימניות לנייד</translation>
@@ -868,9 +899,13 @@ Del</translation>
<translation id="8037357227543935929">שאל (ברירת מחדל)</translation>
<translation id="8041089156583427627">שלח משוב</translation>
<translation id="8041940743680923270">השתמש בברירת המחדל הכללית (שאל)</translation>
+<translation id="8057711352706143257">יש בעיה בהגדרה של "<ph name="SOFTWARE_NAME" />". בדרך כלל, הסרת ההתקנה של "<ph name="SOFTWARE_NAME" />" פותרת את הבעיה. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">הצגת הפריט נכשלה.</translation>
<translation id="8091372947890762290">ההפעלה ממתינה בשרת</translation>
+<translation id="8094917007353911263">ייתכן שתידרש להיכנס ל-<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> עבור הרשת שבה אתה משתמש.</translation>
+<translation id="8103161714697287722">אמצעי תשלום</translation>
<translation id="8118489163946903409">אמצעי תשלום</translation>
+<translation id="8127301229239896662">‏הייתה בעיה בהתקנה של "<ph name="SOFTWARE_NAME" />" במחשב שלך או ברשת. יש לבקש ממנהל ה-IT לפתור את הבעיה.</translation>
<translation id="8131740175452115882">אישור</translation>
<translation id="8134994873729925007">‏לא ניתן היה למצוא את <ph name="BEGIN_ABBR" />כתובת ה-DNS<ph name="END_ABBR" /> של השרת של <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">המחשב עבר למצב שינה.</translation>
@@ -893,6 +928,7 @@ Del</translation>
<translation id="8289355894181816810">פנה אל מנהל הרשת אם אינך יודע מה זה אומר.</translation>
<translation id="8293206222192510085">הוסף סימניה</translation>
<translation id="8294431847097064396">מקור</translation>
+<translation id="8298115750975731693">‏ייתכן שתידרש להיכנס ל-<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> עבור רשת ה-Wi-Fi שבה אתה משתמש (<ph name="WIFI_NAME" />).</translation>
<translation id="8306404619377842860">אי אפשר ליצור חיבור פרטי אל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> מאחר שהתאריך והשעה של המכשיר שלך (<ph name="DATE_AND_TIME" />) לא נכונים. <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">התרגום נכשל עקב בעיה בחיבור הרשת.</translation>
<translation id="8332188693563227489">הגישה ל-<ph name="HOST_NAME" /> נדחתה</translation>
@@ -946,20 +982,21 @@ Del</translation>
<translation id="8870413625673593573">נסגרו לאחרונה</translation>
<translation id="8874824191258364635">עליך להזין מספר כרטיס חוקי</translation>
<translation id="8876793034577346603">ניתוח תצורת הרשת נכשל.</translation>
-<translation id="8889402386540077796">גוון</translation>
<translation id="8891727572606052622">‏מצב שרת Proxy לא חוקי.</translation>
<translation id="889901481107108152">מצטערים, ניסוי זה אינו זמין בפלטפורמה שלך.</translation>
<translation id="8903921497873541725">התקרב</translation>
<translation id="8931333241327730545">‏האם ברצונך לשמור את הכרטיס הזה בחשבון Google שלך?</translation>
<translation id="8932102934695377596">השעון שלך מאחר</translation>
+<translation id="893332455753468063">הוספת שם</translation>
<translation id="8938939909778640821">כרטיסי אשראי וכרטיסים משולמים מראש שהסוחר מקבל</translation>
+<translation id="8957210676456822347">הרשאת פורטל חובה</translation>
<translation id="8971063699422889582">פג תוקפו של אישור השרת.</translation>
-<translation id="8986494364107987395">‏שלח ל-Google דוחות קריסה וסטטיסטיקת שימוש באופן אוטומטי</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">האתר שאתה עומד לעבור אליו מכיל תוכניות מזיקות</translation>
<translation id="8997023839087525404">השרת הציג אישור שלא נחשף באופן ציבורי בעזרת מדיניות 'שקיפות אישורים'. זוהי דרישה עבור חלק מהאישורים, ומטרתה לוודא שהם מהימנים וכדי להגן מפני תוקפים.</translation>
<translation id="9001074447101275817">‏שרת ה-proxy ‏<ph name="DOMAIN" /> מצריך שם משתמש וסיסמה.</translation>
<translation id="9005998258318286617">‏הטעינה של מסמך ה-PDF נכשלה.</translation>
+<translation id="9008201768610948239">התעלם</translation>
<translation id="901974403500617787">רק הבעלים יכול להגדיר סימונים החלים על כל המערכת: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">יש להזין את הכתובת לחיוב של הכרטיס</translation>
<translation id="9020542370529661692">הדף הזה תורגם ל<ph name="TARGET_LANGUAGE" /></translation>
@@ -969,11 +1006,14 @@ Del</translation>
<translation id="9049981332609050619">ניסית להגיע ל-<ph name="DOMAIN" />, אך השרת הציג אישור לא חוקי.</translation>
<translation id="9050666287014529139">משפט-סיסמה</translation>
<translation id="9065203028668620118">ערוך</translation>
-<translation id="9068849894565669697">בחירת צבע</translation>
<translation id="9069693763241529744">נחסמה על-ידי תוסף</translation>
<translation id="9076283476770535406">ייתכן שהאתר מכיל תוכן למבוגרים בלבד</translation>
<translation id="9078964945751709336">נדרש מידע נוסף</translation>
+<translation id="9080712759204168376">סיכום הזמנה</translation>
<translation id="9103872766612412690">‏האתר <ph name="SITE" /> משתמש בדרך כלל בהצפנה כדי להגן על המידע שלך. כאשר Chromium ניסה הפעם להתחבר ל-<ph name="SITE" />, האתר שלח חזרה אישורים חריגים ושגויים. ייתכן שתוקף מנסה להתחזות לאתר <ph name="SITE" />, או שמסך כניסה ל-Wi-Fi הפריע לחיבור. המידע שלך עדיין מאובטח מכיוון ש-Chromium הפסיק את החיבור לפני חילופי הנתונים.</translation>
+<translation id="9106062320799175032">הוספה של כתובת לחיוב</translation>
+<translation id="910908805481542201">איך פותרים את הבעיה?</translation>
+<translation id="9128870381267983090">התחבר לרשת</translation>
<translation id="9137013805542155359">הצג מקור</translation>
<translation id="9137248913990643158">‏היכנס לחשבונך ב-Chrome לפני שתשתמש באפליקציה הזו.</translation>
<translation id="9148507642005240123">&amp;ביטול עריכה</translation>
@@ -985,6 +1025,7 @@ Del</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> משתמש בפרוטוקול שאינו נתמך.</translation>
<translation id="9205078245616868884">הנתונים שלך מוצפנים באמצעות ביטוי הסיסמה לסינכרון. הזן אותו כדי להתחיל בסינכרון.</translation>
<translation id="9207861905230894330">הוספת הפריט נכשלה.</translation>
+<translation id="9215416866750762878">‏יישום כלשהו לא מאפשר ל-Chrome להתחבר באופן מאובטח לאתר זה</translation>
<translation id="9219103736887031265">תמונות</translation>
<translation id="933612690413056017">אין חיבור לאינטרנט</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -994,5 +1035,11 @@ Del</translation>
<translation id="975560348586398090">{COUNT,plural, =0{ללא}=1{פריט אחד}two{שני פריטים}many{# פריטים}other{# פריטים}}</translation>
<translation id="981121421437150478">לא מקוון</translation>
<translation id="988159990683914416">גירסת מפתחים</translation>
+<translation id="989988560359834682">ערוך כתובת</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">‏הייתה בעיה בהתקנה של "<ph name="SOFTWARE_NAME" />" במחשב שלך או ברשת. אפשר לנסות אחת מהפעולות הבאות:
+ &lt;ul&gt;
+ &lt;li&gt;להסיר את ההתקנה של "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;להתחבר לרשת אחרת&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index fe09f7abf73..bcce23a7ceb 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">パソコンのブックマーク</translation>
<translation id="1074497978438210769">保護されていません</translation>
<translation id="1080116354587839789">ウィンドウ幅に合わせる</translation>
+<translation id="1088860948719068836">名義人名の追加</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" />を常に翻訳</translation>
+<translation id="1103778128462718200">保存したパスワードをすべて表示...</translation>
<translation id="1107591249535594099">チェックボックスをオンにすると、Chrome はフォームに迅速に入力するために、カード情報のコピーをこのデバイスに保存します。</translation>
<translation id="1111153019813902504">最近アクセスしたブックマーク</translation>
<translation id="1113869188872983271">順序変更の取り消し(&amp;U)</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />、<ph name="TYPE_2" />(同期済み)</translation>
<translation id="1263231323834454256">リーディング リスト</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> にクラッシュ レポートが作成されました(まだアップロードされておらず、無視の指定もありません)</translation>
+<translation id="1270502636509132238">集荷方法</translation>
<translation id="1281526147609854549">発行元: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">このサイトは翻訳しない</translation>
<translation id="129553762522093515">最近閉じたタブ</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">接続を待機しています…</translation>
<translation id="153384715582417236">現時点では他にありません</translation>
<translation id="1549470594296187301">この機能を使用するには JavaScript を有効にする必要があります。</translation>
-<translation id="1555130319947370107">青</translation>
<translation id="1559528461873125649">該当するファイルまたはディレクトリがありません</translation>
<translation id="1583429793053364125">このウェブページを表示中に問題が発生しました。</translation>
<translation id="1592005682883173041">ローカルデータへのアクセス</translation>
<translation id="1594030484168838125">選択</translation>
-<translation id="161042844686301425">シアン</translation>
<translation id="1620510694547887537">カメラ</translation>
<translation id="1629803312968146339">Chrome にこのカードを保存しますか?</translation>
<translation id="1639239467298939599">読み込み中</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">このサイトにアクセスするには <ph name="NAME" /> さんの許可が必要です</translation>
<translation id="1721424275792716183">* 必須欄です</translation>
+<translation id="1727741090716970331">有効なカード番号の追加</translation>
<translation id="1728677426644403582">ウェブページのソースを表示しています</translation>
<translation id="173080396488393970">この種類のカードはご利用いただけません</translation>
<translation id="1734864079702812349">AMEX</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">シリアル化エラーです</translation>
<translation id="1974060860693918893">詳細設定</translation>
<translation id="1978555033938440688">ファームウェアのバージョン</translation>
-<translation id="1995859865337580572">CVC を確認してください</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{他 1 個}other{他 # 個}}</translation>
<translation id="2025186561304664664">プロキシは自動設定になっています。</translation>
<translation id="2030481566774242610">もしかして: <ph name="LINK" /></translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">元に戻す</translation>
<translation id="20817612488360358">システム プロキシ設定を使用するように設定されていますが、明示的なプロキシの設定も指定されています。</translation>
<translation id="2086652334978798447">ユーザーに合わせた Google からのおすすめコンテンツを表示するには、Chrome にログインします。</translation>
+<translation id="2091887806945687916">音声</translation>
<translation id="2094505752054353250">ドメインが一致しません</translation>
<translation id="2096368010154057602">県</translation>
<translation id="2108755909498034140">パソコンを再起動する</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> によって上書きされるため無視されます。</translation>
<translation id="2138201775715568214">近くのフィジカル ウェブページを探しています</translation>
<translation id="213826338245044447">モバイルのブックマーク</translation>
+<translation id="214556005048008348">支払いをキャンセル</translation>
<translation id="2147827593068025794">バックグラウンド同期</translation>
+<translation id="2148613324460538318">カードを追加</translation>
<translation id="2154054054215849342">お使いのドメインでは同期機能をご利用いただけません</translation>
<translation id="2154484045852737596">カードを編集</translation>
<translation id="2166049586286450108">すべてのデータへの管理者アクセス</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 件のアドレス}other{# 件のアドレス}}</translation>
<translation id="2187317261103489799">検出(デフォルト)</translation>
<translation id="2202020181578195191">有効期限(年)を正しい形式で入力してください</translation>
+<translation id="2209523182407020534">このエラーの原因としては、ウィルス対策ソフトウェア、ファイアウォール ソフトウェア、ウェブ フィルタリング ソフトウェア、プロキシ ソフトウェアなどが考えられます。</translation>
<translation id="2212735316055980242">ポリシーが見つかりません</translation>
<translation id="2213606439339815911">エントリを取得しています...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> では現在、悪意のあるユーザーによって危険なアプリ(端末に問題を生じたり、モバイル利用料に不明瞭な請求を加えたり、個人情報を抜き取ったりするアプリ)がインストールされる可能性があります。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">戻る</translation>
<translation id="2503184589641749290">利用可能なデビットカードとプリペイド カード</translation>
<translation id="2515629240566999685">電波状況を確認する</translation>
+<translation id="2524461107774643265">その他の情報の追加</translation>
+<translation id="2536110899380797252">住所を追加</translation>
<translation id="2539524384386349900">検出</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> から無効な応答が送信されました。</translation>
<translation id="2556876185419854533">編集の取り消し(&amp;U)</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium でカードを確認できませんでした。しばらくしてからもう一度お試しください。</translation>
<translation id="2705137772291741111">このサイトの保存(キャッシュ)されたコピーを読み取れませんでした。</translation>
<translation id="2709516037105925701">自動入力</translation>
+<translation id="2710942282213947212">パソコンにインストールされているソフトウェアが原因で、Chromium からインターネットに安全に接続することができません</translation>
<translation id="2712173769900027643">権限をリクエスト</translation>
-<translation id="2713444072780614174">白</translation>
<translation id="2720342946869265578">周辺</translation>
<translation id="2721148159707890343">リクエストを正常に送信しました</translation>
<translation id="2728127805433021124">サーバーの証明書は脆弱な署名アルゴリズムを使用して署名されています。</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">ネットワークの変更が検出されました。</translation>
<translation id="2916038427272391327">他のプログラムを終了する</translation>
<translation id="2922350208395188000">サーバーの証明書を確認できません。</translation>
+<translation id="2925673989565098301">配達方法</translation>
<translation id="2928905813689894207">請求先住所</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 件)}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 件)}}</translation>
<translation id="2941952326391522266">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書は <ph name="DOMAIN2" /> から発行されています。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">ポリシー タイプが間違っています</translation>
<translation id="3032412215588512954">このサイトを再読み込みしますか?</translation>
<translation id="3037605927509011580">エラー</translation>
+<translation id="3039538478787849737">カードを Google に保存しますか?</translation>
<translation id="3041612393474885105">証明書情報</translation>
<translation id="3063697135517575841">Chrome でカードを確認できませんでした。しばらくしてからもう一度お試しください。</translation>
<translation id="3064966200440839136">外部アプリケーションを経由したお支払いの処理に進むため、シークレット モードを解除します。続行しますか?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">一時的なサーバー エラーです</translation>
<translation id="3154506275960390542">このページのフォームは安全に送信されない可能性があります。送信中にデータが他者に閲覧されたり、悪意のあるユーザーによりデータが変更されてサーバーに別の内容が届いたりする可能性があります。</translation>
<translation id="3157931365184549694">復元</translation>
+<translation id="3162559335345991374">ご利用の Wi-Fi ネットワークでは、ログインページへのアクセスが必要な可能性があります。</translation>
<translation id="3167968892399408617">シークレット タブで表示したページの記録は、シークレット タブをすべて閉じた後、ブラウザの履歴、Cookie の保存場所、検索履歴から消去されます。ただし、ダウンロードしたファイルや作成したブックマークは保存されます。</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">島</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">支払いをキャンセル</translation>
<translation id="3207960819495026254">ブックマークしました</translation>
+<translation id="3211223744486044430">このカードを Google アカウントとこの端末に保存すると、次回のお支払いが簡単になります。</translation>
<translation id="3225919329040284222">サーバーの提示した証明書が、組み込まれている想定の証明書と一致しません。これらの想定の証明書は、ユーザー保護のため、特定の安全性の高いウェブサイトについて用意されています。</translation>
<translation id="3226128629678568754">ページの読み込みに必要なデータを再送信するには、再読み込みボタンを押してください。</translation>
<translation id="3227137524299004712">マイク</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">一致する結果は見つかりませんでした</translation>
<translation id="3305707030755673451">データは <ph name="TIME" /> に同期パスフレーズで暗号化されました。同期を開始するには、同期パスフレーズを入力してください。</translation>
<translation id="3320021301628644560">請求先住所を追加</translation>
-<translation id="3329013043687509092">彩度</translation>
<translation id="333371639341676808">このページでこれ以上ダイアログボックスを生成しない</translation>
<translation id="3338095232262050444">保護された通信</translation>
<translation id="3340978935015468852">設定</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">クライアント ID:</translation>
<translation id="3391030046425686457">配送先住所</translation>
<translation id="3395827396354264108">受け取り方法</translation>
+<translation id="3399952811970034796">配達先住所</translation>
<translation id="3422248202833853650">メモリを解放するために、他のプログラムを終了してみてください。</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> は現在アクセスできません。</translation>
<translation id="3427092606871434483">許可(デフォルト)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> にクラッシュ レポートが作成され、<ph name="UPLOAD_TIME" /> にアップロードされました</translation>
<translation id="3681007416295224113">証明書情報</translation>
<translation id="3690164694835360974">ログイン情報は保護されません</translation>
+<translation id="3704162925118123524">ご利用のネットワークでは、ログインページへのアクセスが必要な可能性があります。</translation>
<translation id="3704609568417268905"><ph name="TIME" />、<ph name="TITLE" />(<ph name="DOMAIN" />)を<ph name="BOOKMARKED" /></translation>
<translation id="370665806235115550">読み込んでいます...</translation>
<translation id="3712624925041724820">ライセンスを使い切りました</translation>
<translation id="3714780639079136834">モバイルデータまたは Wi-Fi を有効にする</translation>
+<translation id="3715597595485130451">Wi-Fi 接続</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />プロキシ、ファイアウォール、DNS の設定を確認する<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">危険なプログラムが削除されるより前に<ph name="BEGIN_LINK" />この安全でないサイトにアクセスする<ph name="END_LINK" />場合は、セキュリティ上のリスクについてご承知おきください。</translation>
<translation id="3739623965217189342">コピーしたリンク</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">追加の取り消し(&amp;U)</translation>
<translation id="404928562651467259">警告</translation>
<translation id="4058922952496707368">キー「<ph name="SUBKEY" />」: <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">有効なアドレスの追加</translation>
<translation id="4072486802667267160">ご注文の処理中にエラーが発生しました。もう一度お試しください。</translation>
<translation id="4075732493274867456">クライアントとサーバーで、共通の SSL プロトコル バージョンまたは暗号スイートがサポートされていません。</translation>
<translation id="4079302484614802869">プロキシは固定プロキシ サーバーではなく .pac スクリプト URL を使用するように設定されています。</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">デバイスのシリアル番号が無効です</translation>
<translation id="410351446219883937">自動再生</translation>
<translation id="4103763322291513355">&lt;strong&gt;chrome://policy&lt;/strong&gt; にアクセスして、ブラックリストに登録されている URL とシステム管理者が設定した他のポリシーを確認できます。</translation>
-<translation id="4115378294792113321">マゼンタ</translation>
<translation id="4116663294526079822">このサイトでは常に許可</translation>
<translation id="4117700440116928470">ポリシーの適用範囲がサポートされていません。</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{他 1 件}other{他 # 件}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" /> にアクセスしようとしましたが、サーバーから提示された証明書は発行元により取り消されています。これは、サーバーから提示されたセキュリティ認証情報が信頼できないことを示しており、悪意のあるユーザーと通信しようとしている可能性があります。</translation>
<translation id="4394049700291259645">無効にする</translation>
<translation id="4406896451731180161">検索結果</translation>
+<translation id="4415426530740016218">集荷先住所</translation>
<translation id="4424024547088906515">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書は Chrome によって信頼されているものではありません。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> でログイン証明書が承認されなかったか、ログイン証明書が提示されていない可能性があります。</translation>
<translation id="443673843213245140">プロキシの使用は無効ですが、プロキシの設定が明示的に指定されています。</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">拡張機能を無効にしてみてください。</translation>
<translation id="457875822857220463">配送</translation>
+<translation id="4582800630050655161">Google アカウントにアクセスできなくなったり、個人情報が盗まれたりする可能性があります。Chromium で今すぐパスワードを変更することをおすすめします。</translation>
<translation id="4587425331216688090">Chrome からアドレスを削除してもよろしいですか?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> への接続は新しい暗号スイートにより暗号化されています。</translation>
<translation id="4594403342090139922">削除の取り消し(&amp;U)</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書にはエラーがあります。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
<translation id="4690462567478992370">無効な証明書の使用をやめる</translation>
+<translation id="4690954380545377795">Google アカウントにアクセスできなくなったり、個人情報が盗まれたりする可能性があります。Chrome で今すぐパスワードを変更することをおすすめします。</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">接続が中断されました</translation>
<translation id="471880041731876836">このサイトへのアクセスが許可されていません</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ネットワーク診断ツールを実行する<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">お支払い</translation>
<translation id="4726672564094551039">ポリシーを再読み込み</translation>
<translation id="4728558894243024398">プラットフォーム</translation>
<translation id="4736825316280949806">Chromium を再起動する</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">代替ストアの状態が不適切です</translation>
<translation id="5023310440958281426">管理者のポリシーを確認してください</translation>
<translation id="5029568752722684782">コピーを消去</translation>
+<translation id="503069730517007720">「<ph name="SOFTWARE_NAME" />」のルート証明書が必要ですが、インストールされていません。IT 管理者に、「<ph name="SOFTWARE_NAME" />」の設定手順を確認したうえでこの問題を修正するよう依頼してください。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google 翻訳について</translation>
<translation id="5039804452771397117">許可</translation>
<translation id="5040262127954254034">プライバシー</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">試験運用機能</translation>
<translation id="5205222826937269299">名前は必須です</translation>
<translation id="5222812217790122047">メールアドレスは必須です</translation>
+<translation id="522700295135997067">このサイトでパスワードを盗まれた可能性があります</translation>
+<translation id="5230733896359313003">配送先住所</translation>
<translation id="5251803541071282808">クラウド</translation>
<translation id="5277279256032773186">会社で Chrome を使用する場合は、従業員用に Chrome の設定を管理できます。詳細</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />このソフトウェアを一時的に無効にしてインターネットに接続できるようにするには、次の手順を行います。なお、この作業には管理者権限が必要です。<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">このサイトへの接続ではプライバシーが保護されません。VR モードを終了するには、ヘッドセットを外して「戻る」を押します。</translation>
<translation id="5299298092464848405">ポリシーの解析中にエラーが発生しました</translation>
+<translation id="5308380583665731573">接続</translation>
<translation id="5308689395849655368">障害レポートが無効になっています。</translation>
<translation id="5317780077021120954">保存</translation>
<translation id="5327248766486351172">名前</translation>
+<translation id="5332219387342487447">配送方法</translation>
<translation id="5355557959165512791"><ph name="SITE" /> は証明書が失効しているため、現在アクセスできません。通常、ネットワーク エラーやネットワークへの攻撃は一時的なものです。しばらくするとページにアクセスできるようになります。</translation>
<translation id="536296301121032821">ポリシー設定を保存できませんでした</translation>
<translation id="5386426401304769735">このサイトの証明書チェーンには SHA-1 を使って署名された証明書が含まれています。</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">このサイトは企業、団体、または学校のイントラネット上にありますが、外部のウェブサイトと同じ URL が使用されています。
<ph name="LINE_BREAK" />
システム管理者にお問い合わせください。</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> のセキュリティ コードを入力してください。このコードは保存されません。</translation>
<translation id="5509780412636533143">管理対象のブックマーク</translation>
<translation id="5510766032865166053">移動または削除された可能性があります。</translation>
<translation id="5523118979700054094">ポリシー名</translation>
<translation id="552553974213252141">テキストは正しく抽出されましたか?</translation>
<translation id="5540224163453853">リクエストされた記事が見つかりませんでした。</translation>
+<translation id="5541546772353173584">メールの追加</translation>
<translation id="5544037170328430102"><ph name="SITE" /> に埋め込まれているページの内容:</translation>
+<translation id="5545756402275714221">おすすめの記事</translation>
<translation id="5556459405103347317">再読み込み</translation>
<translation id="5560088892362098740">有効期限</translation>
<translation id="5565735124758917034">有効</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">メール</translation>
<translation id="5669703222995421982">自分向けのコンテンツを表示</translation>
<translation id="5675650730144413517">このページは動作していません</translation>
+<translation id="5689199277474810259">JSON にエクスポート</translation>
<translation id="5710435578057952990">このウェブサイトの ID は確認されていません。</translation>
<translation id="5719499550583120431">プリペイド カードをご利用いただけます。</translation>
<translation id="5720705177508910913">現在のユーザー</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" /> への接続は古い暗号スイートにより暗号化されています。</translation>
<translation id="5813119285467412249">追加のやり直し(&amp;R)</translation>
<translation id="5838278095973806738">このサイトでは機密情報(パスワード、クレジット カードなど)を入力しないでください。悪意のあるユーザーに情報が盗まれる恐れがあります。</translation>
+<translation id="5866257070973731571">電話番号の追加</translation>
<translation id="5869405914158311789">このサイトにアクセスできません</translation>
<translation id="5869522115854928033">保存したパスワード</translation>
<translation id="5872918882028971132">保護者からのおすすめ</translation>
<translation id="5893752035575986141">クレジット カードをご利用いただけます。</translation>
-<translation id="5901630391730855834">黄</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(同期済み)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 個が使用中}other{# 個が使用中}}</translation>
<translation id="5959728338436674663">危険なアプリやサイトの検出に役立てるために一部の<ph name="BEGIN_WHITEPAPER_LINK" />システム情報やページのコンテンツ<ph name="END_WHITEPAPER_LINK" />を Google に自動送信する。<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">連絡先情報の編集</translation>
<translation id="5967867314010545767">履歴から削除</translation>
<translation id="5975083100439434680">縮小する</translation>
+<translation id="597552863672748783">セキュリティ コードの確認</translation>
<translation id="598637245381783098">お支払いアプリを開けません</translation>
<translation id="5989320800837274978">固定プロキシ サーバーと .pac スクリプト URL のどちらも指定されていません。</translation>
<translation id="5990559369517809815">サーバーへのリクエストは拡張機能によってブロックされています。</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ページ 1}other{ページ #}}</translation>
-<translation id="6017514345406065928">緑</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />、<ph name="TYPE_2" />、<ph name="TYPE_3" />(同期済み)</translation>
<translation id="6027201098523975773">名前を入力してください</translation>
<translation id="6040143037577758943">閉じる</translation>
-<translation id="6042308850641462728">もっと見る</translation>
<translation id="6047233362582046994">有害なアプリがまだ存在する可能性があるにもかかわらず<ph name="BEGIN_LINK" />このサイトにアクセスする<ph name="END_LINK" />場合は、セキュリティ上の危険性をあらかじめご認識ください。</translation>
<translation id="6047927260846328439">アクセス先のコンテンツは、ユーザーをだましてソフトウェアをインストールさせようとしたり、個人情報を危険にさらしたりする可能性があります。<ph name="BEGIN_LINK" />危険性を理解したうえで表示する<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> では証明書ピンニングが使用されているため、現在アクセスできません。通常、ネットワーク エラーやネットワークへの攻撃は一時的なものです。しばらくするとページにアクセスできるようになります。</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">拡張機能のページを表示しています</translation>
<translation id="6596325263575161958">暗号化オプション</translation>
<translation id="662080504995468778">とどまる</translation>
+<translation id="6624427990725312378">連絡先情報</translation>
<translation id="6626291197371920147">有効なカード番号を追加</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> 検索</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> では現在、悪意のあるユーザーによって、お使いの Mac 上に危険なプログラム(写真、パスワード、メッセージ、クレジット カードなどの情報を盗んだり削除したりするプログラム)がインストールされる可能性があります。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">前へ</translation>
<translation id="6710594484020273272">&lt;検索キーワードを入力&gt;</translation>
<translation id="6711464428925977395">プロキシ サーバーに問題がある、またはアドレスが正しくありません。</translation>
-<translation id="6727102863431372879">設定</translation>
<translation id="674375294223700098">不明なサーバー証明書エラー</translation>
<translation id="6753269504797312559">ポリシーの値</translation>
<translation id="6757797048963528358">デバイスがスリープ状態です。</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">プロフィール パス</translation>
<translation id="7424977062513257142">このウェブページに埋め込まれているページの内容:</translation>
+<translation id="7437289804838430631">連絡先情報を追加</translation>
<translation id="7441627299479586546">ポリシーの対象が間違っています</translation>
<translation id="7444046173054089907">このサイトはブロックされています</translation>
<translation id="7445762425076701745">接続してるサーバーの身元について、十分な検証ができません。接続しているサーバーは、そのネットワーク内でのみ有効な名前を使用しており、外部認証局がその所有権を検証する方法はありません。こうした名前で証明書を発行する認証局もあるので、接続先が意図したウェブサイトか、悪意のあるユーザーのサイトかは確認できません。</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">進む</translation>
<translation id="7485870689360869515">データが見つかりません。</translation>
<translation id="7508255263130623398">返されたポリシーの端末 ID が空であるか、現在の端末 ID と一致しません</translation>
+<translation id="7511955381719512146">ご利用の Wi-Fi では、<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> へのアクセスが必要な可能性があります。</translation>
<translation id="7514365320538308">ダウンロード</translation>
<translation id="7518003948725431193">次の URL のウェブページは見つかりませんでした:<ph name="URL" /></translation>
<translation id="7521387064766892559">Javascript</translation>
<translation id="7526934274050461096">このサイトへの接続ではプライバシーが保護されません</translation>
-<translation id="7535087603100972091">値</translation>
<translation id="7537536606612762813">必須</translation>
<translation id="7542403920425041731">確認すると、カードの情報がこのサイトに共有されます。</translation>
<translation id="7542995811387359312">このフォームは安全な接続を使用していないため、クレジットカードの自動入力が無効になっています。</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書は不正に発行されたものである可能性があります。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
<translation id="7568593326407688803">これは<ph name="ORIGINAL_LANGUAGE" />のページです。翻訳しますか?</translation>
<translation id="7569952961197462199">Chrome からクレジット カードを削除してもよろしいですか?</translation>
-<translation id="7569983096843329377">黒</translation>
<translation id="7578104083680115302">どの端末でも、Google に保存したカードを使ってサイトやアプリの支払いをすばやく行うことができます。</translation>
<translation id="7588950540487816470">フィジカルウェブ</translation>
<translation id="7592362899630581445">サーバーの証明書が名前の制約に違反しています。</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">このサイトを利用すると、悪意のあるユーザーによって、閲覧時のエクスペリエンスを損なうプログラム(ホームページを改ざんする、アクセス先のサイトに追加の広告を表示するなどのプログラム)をインストールするよう誘導される可能性があります。</translation>
<translation id="7674629440242451245">Chrome の新しい機能に関心をお持ちでしたら、chrome.com/dev から Dev チャンネルをお試しください。</translation>
<translation id="7682287625158474539">発送先</translation>
+<translation id="7699293099605015246">記事は現在利用できません</translation>
<translation id="7701040980221191251">なし</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> にアクセスする(安全ではありません)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">証明書</translation>
<translation id="7716147886133743102">管理者によってブロック</translation>
<translation id="7716424297397655342">このサイトをキャッシュから読み込むことができません</translation>
+<translation id="7723047071702270851">カードの編集</translation>
<translation id="774634243536837715">危険なコンテンツがブロックされました。</translation>
<translation id="7752995774971033316">管理されていません</translation>
<translation id="7755287808199759310">ブロックの解除は保護者が行うことができます</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">住所を追加</translation>
<translation id="777702478322588152">都道府県</translation>
<translation id="7791543448312431591">追加</translation>
+<translation id="7793553086574152071">このカードを Google アカウントに保存すると、次回のお支払いが簡単になります。</translation>
<translation id="7793809570500803535"><ph name="SITE" /> のウェブページは一時的に停止しているか、新しいウェブアドレスに移動した可能性があります。</translation>
<translation id="7800304661137206267">この接続は <ph name="CIPHER" /> で暗号化されており、メッセージ認証には <ph name="MAC" />、鍵交換メカニズムには <ph name="KX" /> が使用されています。</translation>
+<translation id="7802523362929240268">正規のサイトです</translation>
<translation id="780301667611848630">いいえ</translation>
<translation id="7805768142964895445">ステータス</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome から候補を削除してもよろしいですか?</translation>
<translation id="7815407501681723534">「<ph name="SEARCH_STRING" />」に対し <ph name="NUMBER_OF_RESULTS" /> 件の <ph name="SEARCH_RESULTS" />が見つかりました</translation>
+<translation id="782886543891417279">ご利用の Wi-Fi(<ph name="WIFI_NAME" />)では、ログインページへのアクセスが必要な可能性があります。</translation>
<translation id="785549533363645510">あらゆる場所に記録が一切残らないわけではありません。シークレット モードを使っても、雇用主、インターネット サービス プロバイダ、訪問先のウェブサイトに閲覧内容が知られる可能性はあります。</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">デビットカードとプリペイド カードをご利用いただけます。</translation>
+<translation id="7878562273885520351">パスワードが不正使用される可能性があります</translation>
<translation id="7887683347370398519">CVC を確認してからもう一度お試しください</translation>
<translation id="79338296614623784">有効な電話番号を入力してください</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">サーバーの証明書が有効になっていません。</translation>
-<translation id="7942349550061667556">赤</translation>
<translation id="7947285636476623132">有効期限の「年」を確認してもう一度お試しください</translation>
<translation id="7951415247503192394">(32 ビット)</translation>
<translation id="7956713633345437162">モバイルのブックマーク</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">確認(デフォルト)</translation>
<translation id="8041089156583427627">フィードバックを送信</translation>
<translation id="8041940743680923270">グローバルのデフォルト値([確認])を使用</translation>
+<translation id="8057711352706143257">「<ph name="SOFTWARE_NAME" />」が正しく設定されていません。通常、この問題は「<ph name="SOFTWARE_NAME" />」をアンインストールすることで解決します。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">記事を表示できませんでした。</translation>
<translation id="8091372947890762290">サーバーで有効化が保留になっています</translation>
+<translation id="8094917007353911263">ご利用のネットワークでは、<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> へのアクセスが必要な可能性があります。</translation>
+<translation id="8103161714697287722">お支払い方法</translation>
<translation id="8118489163946903409">お支払い方法</translation>
+<translation id="8127301229239896662">「<ph name="SOFTWARE_NAME" />」がパソコンまたはネットワークに正しくインストールされていません。管理者にこの問題を解決するよう依頼してください。</translation>
<translation id="8131740175452115882">確認</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> のサーバーの <ph name="BEGIN_ABBR" />DNS アドレス<ph name="END_ABBR" />が見つかりませんでした。</translation>
<translation id="8149426793427495338">パソコンがスリープ状態です。</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">確認方法がわからない場合は、ネットワーク管理者までお問い合わせください。</translation>
<translation id="8293206222192510085">ブックマークの追加</translation>
<translation id="8294431847097064396">ソース</translation>
+<translation id="8298115750975731693">ご利用の Wi-Fi(<ph name="WIFI_NAME" />)では、<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> へのアクセスが必要な可能性があります。</translation>
<translation id="8306404619377842860">お使いの端末の日時(<ph name="DATE_AND_TIME" />)が正しくないため、<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> へのプライベート接続を確立できません。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">ネットワーク接続に問題があったため翻訳できませんでした。</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> へのアクセスが拒否されました</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">最近閉じたタブ</translation>
<translation id="8874824191258364635">有効なクレジット カード番号を入力してください</translation>
<translation id="8876793034577346603">ネットワーク設定を解析できませんでした。</translation>
-<translation id="8889402386540077796">色調</translation>
<translation id="8891727572606052622">プロキシ モードが無効です。</translation>
<translation id="889901481107108152">この試験運用機能は、お使いのプラットフォームでは利用できません。</translation>
<translation id="8903921497873541725">拡大する</translation>
<translation id="8931333241327730545">このカードを Google アカウントに保存しますか?</translation>
<translation id="8932102934695377596">時計が遅れています</translation>
+<translation id="893332455753468063">名前の追加</translation>
<translation id="8938939909778640821">利用可能なクレジット カードとプリペイド カード</translation>
+<translation id="8957210676456822347">キャプティブ ポータル認証</translation>
<translation id="8971063699422889582">サーバーの証明書の有効期限が切れています。</translation>
-<translation id="8986494364107987395">使用統計データと障害レポートを Google に自動送信する</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">この先のサイトには有害なプログラムがあります</translation>
<translation id="8997023839087525404">サーバーから提示された証明書は、証明書の透明性ポリシーを介して公開されていません。一部の証明書は、信頼性の確保と攻撃者からの保護のため、証明書の透明性ポリシーを介して公開されることが要件となっています。</translation>
<translation id="9001074447101275817">プロキシ <ph name="DOMAIN" /> にはユーザー名とパスワードを指定する必要があります。</translation>
<translation id="9005998258318286617">PDF ドキュメントを読み込めませんでした。</translation>
+<translation id="9008201768610948239">無視する</translation>
<translation id="901974403500617787">システム全体に適用されるフラグは所有者(<ph name="OWNER_EMAIL" />)のみが設定できます。</translation>
<translation id="9020200922353704812">カードの請求先住所を入力する必要があります</translation>
<translation id="9020542370529661692">このページは<ph name="TARGET_LANGUAGE" />に翻訳されています</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619"><ph name="DOMAIN" /> にアクセスしようとしましたが、サーバーから無効な証明書が提示されました。</translation>
<translation id="9050666287014529139">パスフレーズ</translation>
<translation id="9065203028668620118">編集</translation>
-<translation id="9068849894565669697">色の選択</translation>
<translation id="9069693763241529744">拡張機能によってブロック</translation>
<translation id="9076283476770535406">成人向けコンテンツが含まれている可能性があります</translation>
<translation id="9078964945751709336">その他の情報が必要です</translation>
+<translation id="9080712759204168376">ご注文の概要</translation>
<translation id="9103872766612412690"><ph name="SITE" /> では通常、暗号化して情報を保護しています。今回、Chromium から <ph name="SITE" /> への接続試行時に、このウェブサイトからいつもとは異なる誤った認証情報が返されました。悪意のあるユーザーが <ph name="SITE" /> になりすまそうとしているか、Wi-Fi ログイン画面で接続が中断された可能性があります。データのやり取りが行われる前に Chromium によって接続が停止されたため、情報は引き続き保護されています。</translation>
+<translation id="9106062320799175032">請求先住所の追加</translation>
+<translation id="910908805481542201">問題を修正するには</translation>
+<translation id="9128870381267983090">ネットワークに接続する</translation>
<translation id="9137013805542155359">原文のページを表示</translation>
<translation id="9137248913990643158">このアプリを使用するには、Chrome を起動してログインしてください。</translation>
<translation id="9148507642005240123">編集の取り消し(&amp;U)</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ではサポートされていないプロトコルが使用されています。</translation>
<translation id="9205078245616868884">データは同期パスフレーズで暗号化されます。同期を開始するには、同期パスフレーズを入力してください。</translation>
<translation id="9207861905230894330">記事を追加できませんでした。</translation>
+<translation id="9215416866750762878">アプリケーションが原因で、Chrome からこのサイトに安全に接続することができません</translation>
<translation id="9219103736887031265">画像</translation>
<translation id="933612690413056017">インターネット接続がありません</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{なし}=1{1 件のアイテム}other{# 件のアイテム}}</translation>
<translation id="981121421437150478">オフライン</translation>
<translation id="988159990683914416">Developer Build</translation>
+<translation id="989988560359834682">住所の編集</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">「<ph name="SOFTWARE_NAME" />」がパソコンまたはネットワークに正しくインストールされていません。
+ &lt;ul&gt;
+ &lt;li&gt;「<ph name="SOFTWARE_NAME" />」をアンインストールまたは無効化してみてください&lt;/li&gt;
+ &lt;li&gt;別のネットワークに接続してみてください&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index affa60b927a..6c4e044ffc1 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">ಡೆಸ್ಕ್‌ಟಾಪ್ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="1074497978438210769">ಸುರಕ್ಷಿತವಾಗಿಲ್ಲ</translation>
<translation id="1080116354587839789">ಅಗಲಕ್ಕೆ ಹೊಂದಿಸಿ</translation>
+<translation id="1088860948719068836">ಕಾರ್ಡ್‌ನಲ್ಲಿರುವ ಹೆಸರನ್ನು ಸೇರಿಸಿ</translation>
<translation id="1103523840287552314">ಯಾವಾಗಲೂ ಅನುವಾದಿಸಿ <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">ಉಳಿಸಿದ ಎಲ್ಲ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ತೋರಿಸಿ...</translation>
<translation id="1107591249535594099">ಪರಿಶೀಲಿಸಿದರೆ, ವೇಗವಾಗಿ ಫಾರ್ಮ್ ಭರ್ತಿ ಮಾಡಲು Chrome ಈ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ ಕಾರ್ಡ್‌ನ ಪ್ರತಿಯನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ.</translation>
<translation id="1111153019813902504">ಇತ್ತೀಚಿನ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="1113869188872983271">&amp;ಮರುಕ್ರಮಗೊಳಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆ)</translation>
<translation id="1263231323834454256">ಓದುವ ಪಟ್ಟಿ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> ನಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ (ಇನ್ನೂ ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗಿಲ್ಲ ಅಥವಾ ನಿರ್ಲಕ್ಷಿಸಲಾಗಿಲ್ಲ)</translation>
+<translation id="1270502636509132238">ಪಿಕಪ್ ವಿಧಾನ</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> ಇವರಿಂದ ನೀಡಲಾಗಿದೆ</translation>
<translation id="1285320974508926690">ಈ ಸೈಟ್ ಅನ್ನು ಎಂದಿಗೂ ಭಾಷಾಂತರಿಸದಿರಿ</translation>
<translation id="129553762522093515">ಇತ್ತೀಚೆಗೆ ಮುಚ್ಚಲಾಗಿರುವುದು</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">ಸಂಪರ್ಕಕ್ಕೆ ಕಾಯಲಾಗುತ್ತಿದೆ...</translation>
<translation id="153384715582417236">ಇದುವರೆಗೂ ಇಷ್ಟೇ</translation>
<translation id="1549470594296187301">ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬಳಸಲು JavaScript ಸಕ್ರಿಯಗೊಳಿಸಬೇಕು.</translation>
-<translation id="1555130319947370107">ನೀಲಿ</translation>
<translation id="1559528461873125649">ಆ ರೀತಿಯ ಯಾವುದೇ ಫೈಲ್ ಅಥವಾ ಡೈರೆಕ್ಟರಿ ಇಲ್ಲ</translation>
<translation id="1583429793053364125">ಈ ವೆಬ್‌ಪುಟವನ್ನು ಪ್ರದರ್ಶಿಸುವಾಗ ಯಾವುದೋ ತಪ್ಪು ಸಂಭವಿಸಿದೆ.</translation>
<translation id="1592005682883173041">ಸ್ಥಳೀಯ ಡೇಟಾ ಪ್ರವೇಶ</translation>
<translation id="1594030484168838125">ಆರಿಸಿ</translation>
-<translation id="161042844686301425">ಹಸಿರುನೀಲಿ</translation>
<translation id="1620510694547887537">ಕ್ಯಾಮರಾ</translation>
<translation id="1629803312968146339">ಈ ಕಾರ್ಡ್ ಅನ್ನು Chrome ಉಳಿಸಬೇಕೆಂದು ನೀವು ಬಯಸುವಿರಾ?</translation>
<translation id="1639239467298939599">ಲೋಡ್ ಆಗುತ್ತಿದೆ</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ಈ ಸೈಟ್‌ಗೆ ಭೇಟಿ ನೀಡಲು ನಿಮಗೆ <ph name="NAME" /> ಅವರ ಅನುಮತಿಯ ಅಗತ್ಯವಿರುತ್ತದೆ</translation>
<translation id="1721424275792716183">* ಈ ಫೀಲ್ಡ್ ಅಗತ್ಯವಿದೆ</translation>
+<translation id="1727741090716970331">ಮಾನ್ಯವಾದ ಕಾರ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ</translation>
<translation id="1728677426644403582">ನೀವು ವೆಬ್ ಪುಟದ ಮೂಲವನ್ನು ವೀಕ್ಷಿಸುತ್ತಿರುವಿರಿ</translation>
<translation id="173080396488393970">ಈ ರೀತಿಯ ಕಾರ್ಡ್‌ಗೆ ಬೆಂಬಲವಿಲ್ಲ</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">ಅನುಕ್ರಮಗೊಳಿಸುವಿಕೆಯ ದೋಷ</translation>
<translation id="1974060860693918893">ಸುಧಾರಿತ</translation>
<translation id="1978555033938440688">ಫರ್ಮ್‌ವೇರ್ ಆವೃತ್ತಿ</translation>
-<translation id="1995859865337580572">ನಿಮ್ಮ CVC ಪರಿಶೀಲಿಸಿ</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ಮತ್ತು 1 ಇನ್ನಷ್ಟು}one{ಮತ್ತು # ಇನ್ನಷ್ಟು}other{ಮತ್ತು # ಇನ್ನಷ್ಟು}}</translation>
<translation id="2025186561304664664">ಪ್ರಾಕ್ಸಿಯನ್ನು ಸ್ವಯಂ ಕಾನ್ಫಿಗರ್ ಆಗಿ ಹೊಂದಿಸಲಾಗಿದೆ.</translation>
<translation id="2030481566774242610">ನಿಮ್ಮ ಮಾತಿನ ಅರ್ಥ <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">ರದ್ದುಮಾಡಿ</translation>
<translation id="20817612488360358">ಸಿಸ್ಟಂ ಪ್ರಾಕ್ಸಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬಳಸಲು ಹೊಂದಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗವಾದ ಪ್ರಾಕ್ಸಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ಸಹ ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿದೆ.</translation>
<translation id="2086652334978798447">Google ಸಲಹೆ ನೀಡಲಾದ ವೈಯಕ್ತೀಕರಿಸಲಾದ ವಿಷಯವನ್ನು ಪಡೆದುಕೊಳ್ಳಲು, Chrome ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ.</translation>
+<translation id="2091887806945687916">ಶಬ್ಧ</translation>
<translation id="2094505752054353250">ಡೊಮೇನ್ ಹೊಂದುತ್ತಿಲ್ಲ</translation>
<translation id="2096368010154057602">ವಿಭಾಗ</translation>
<translation id="2108755909498034140">ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್ ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ರಿಂದ ಅತಿಕ್ರಮಿಸಲಾಗಿರುವ ಕಾರಣ ಇದನ್ನು ನಿರ್ಲಕ್ಷಿಸಲಾಗಿದೆ.</translation>
<translation id="2138201775715568214">ಹತ್ತಿರದ ಪ್ರತ್ಯಕ್ಷ ವೆಬ್ ಪುಟಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ</translation>
<translation id="213826338245044447">ಮೊಬೈಲ್ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
+<translation id="214556005048008348">ಪಾವತಿಯನ್ನು ರದ್ದುಮಾಡಿ</translation>
<translation id="2147827593068025794">ಹಿನ್ನೆಲೆ ಸಿಂಕ್</translation>
+<translation id="2148613324460538318">ಕಾರ್ಡ್ ಸೇರಿಸಿ</translation>
<translation id="2154054054215849342">ಸಿಂಕ್ ಸೇವೆಯು ನಿಮ್ಮ ಡೊಮೇನ್‌ಗೆ ಲಭ್ಯವಿಲ್ಲ</translation>
<translation id="2154484045852737596">ಕಾರ್ಡ್ ಎಡಿಟ್ ಮಾಡಿ</translation>
<translation id="2166049586286450108">ಪೂರ್ಣ ನಿರ್ವಾಹಕ ಪ್ರವೇಶ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 ವಿಳಾಸ}one{# ವಿಳಾಸಗಳು}other{# ವಿಳಾಸಗಳು}}</translation>
<translation id="2187317261103489799">ಪತ್ತೆ ಮಾಡಿ (ಡಿಫಾಲ್ಟ್)</translation>
<translation id="2202020181578195191">ಮಾನ್ಯವಾದ ಅವಧಿ-ಮುಕ್ತಾಯ ವರ್ಷವನ್ನು ನಮೂದಿಸಿ</translation>
+<translation id="2209523182407020534">ಈ ದೋಷವನ್ನು ಉಂಟುಮಾಡುವ ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳು ಆಂಟಿವೈರಸ್,ಫೈರ್‌ವಾಲ್‌ ಮತ್ತು ವೆಬ್‌-ಫಿಲ್ಟರಿಂಗ್ ಅಥವಾ ಪ್ರಾಕ್ಸಿ ಸಾಫ್ಟ್‌ವೇರ್ ಅನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ.</translation>
<translation id="2212735316055980242">ನೀತಿ ಕಂಡು ಬಂದಿಲ್ಲ</translation>
<translation id="2213606439339815911">ನಮೂದುಗಳನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ...</translation>
<translation id="2218879909401188352">ದಾಳಿಕೋರರು ಪ್ರಸ್ತುತ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಲ್ಲಿದ್ದಾರೆ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಹಾನಿಯನ್ನುಂಟು ಮಾಡುವ ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಬಹುದು, ನಿಮ್ಮ ಮೊಬೈಲ್ ಬಿಲ್‌ಗೆ ಮರೆಮಾಡಿದ ಶುಲ್ಕಗಳನ್ನು ಸೇರಿಸಬಹುದು, ಅಥವಾ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಕದಿಯಬಹುದು. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">ಹಿಂದಿರುಗಿ</translation>
<translation id="2503184589641749290">ಸಮ್ಮತಿಸಲಾದ ಡೆಬಿಟ್ ಮತ್ತು ಪ್ರೀಪೇಯ್ಡ್ ಕಾರ್ಡ್‌ಗಳು</translation>
<translation id="2515629240566999685">ನಿಮ್ಮ ಪ್ರದೇಶದಲ್ಲಿನ ಸಿಗ್ನಲ್ ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ</translation>
+<translation id="2524461107774643265">ಇನ್ನಷ್ಟು ಮಾಹಿತಿಯನ್ನು ಸೇರಿಸಿ</translation>
+<translation id="2536110899380797252">ವಿಳಾಸವನ್ನು ಸೇರಿಸಿ</translation>
<translation id="2539524384386349900">ಪತ್ತೆ ಮಾಡು</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ಅಮಾನ್ಯ ಪ್ರತಿಕ್ರಿಯೆ ಕಳುಹಿಸಿದೆ.</translation>
<translation id="2556876185419854533">&amp;ಸಂಪಾದಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">ಈ ಸಮಯದಲ್ಲಿ Chromium ಗೆ ನಿಮ್ಮ ಕಾರ್ಡ್ ಖಚಿತಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="2705137772291741111">ಈ ಸೈಟ್‌ನ ಉಳಿಸಿದ (ಸಂಗ್ರಹವಾಗಿರುವ) ನಕಲನ್ನು ಓದಲಾಗುತ್ತಿಲ್ಲ.</translation>
<translation id="2709516037105925701">ಸ್ವಯಂತುಂಬುವಿಕೆ</translation>
+<translation id="2710942282213947212">ಸುರಕ್ಷಿತವಾಗಿ ವೆಬ್‌ಗೆ ಸಂಪರ್ಕಿಸುವ Chromium ನ ಕಾರ್ಯವನ್ನು ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿರುವ ಸಾಫ್ಟ್‌ವೇರ್‌ ಸ್ಥಗಿತಗೊಳಿಸಿದೆ</translation>
<translation id="2712173769900027643">ಅನುಮತಿ ಕೇಳಿ</translation>
-<translation id="2713444072780614174">ಬಿಳಿ</translation>
<translation id="2720342946869265578">ಸಮೀಪ ಸಾಧನ</translation>
<translation id="2721148159707890343">ವಿನಂತಿಯನ್ನು ಯಶಸ್ವಿಗೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="2728127805433021124">ಕ್ಷೀಣವಾದ ಸಹಿ ಅಲ್ಗಾರಿದಮ್ ಬಳಸಿಕೊಂಡು ಸರ್ವರ್‌ನ ಪ್ರಮಾಣಪತ್ರಕ್ಕೆ ಸಹಿ ಮಾಡಲಾಗಿದೆ.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">ನೆಟ್‌ವರ್ಕ್ ಬದಲಾವಣೆಯನ್ನು ಪತ್ತೆ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="2916038427272391327">ಇತರ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಮುಚ್ಚಿ</translation>
<translation id="2922350208395188000">ಸರ್ವರ್‌ನ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಪರಿಶೀಲಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
+<translation id="2925673989565098301">ವಿತರಣೆ ವಿಧಾನ</translation>
<translation id="2928905813689894207">ಬಿಲ್ಲಿಂಗ್ ವಿಳಾಸ</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ಇನ್ನಷ್ಟು}}</translation>
<translation id="2941952326391522266">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವು <ph name="DOMAIN2" /> ದಿಂದ ಆಗಿದೆ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">ತಪ್ಪಾದ ನೀತಿಯ ಪ್ರಕಾರ</translation>
<translation id="3032412215588512954">ನೀವು ಈ ಸೈಟ್ ಮರುಲೋಡ್ ಮಾಡಲು ಬಯಸುವಿರಾ?</translation>
<translation id="3037605927509011580">ಓಹ್, ಹೋಯ್ತು!</translation>
+<translation id="3039538478787849737">ಕಾರ್ಡ್‌ ಅನ್ನು Google ನಲ್ಲಿ ಉಳಿಸಬೇಕೆ?</translation>
<translation id="3041612393474885105">ಪ್ರಮಾಣಪತ್ರ ಮಾಹಿತಿ</translation>
<translation id="3063697135517575841">ಈ ಸಮಯದಲ್ಲಿ Chrome ಗೆ ನಿಮ್ಮ ಕಾರ್ಡ್ ಅನ್ನು ಖಚಿತಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="3064966200440839136">ಬಾಹ್ಯ ಅಪ್ಲಿಕೇಶನ್‌‌ ಮೂಲಕರ ಪಾವತಿಸಲು ಅದೃಶ್ಯ ಮೋಡ್‌‌ ತೊರೆಯಲಾಗುತ್ತಿದೆ. ಮುಂದುವರಿಸುವುದೇ?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">ತಾತ್ಕಾಲಿಕ ಸರ್ವರ್ ದೋಷ</translation>
<translation id="3154506275960390542">ಈ ಪುಟದಲ್ಲಿರುವ ಒಂದು ಫಾರ್ಮ್ ಅನ್ನು ಸುರಕ್ಷಿತವಾಗಿ ಸಲ್ಲಿಸಲು ಸಾಧ್ಯವಾಗದಿರಬಹುದು. ರವಾನಿಸುವ ಸಮಯದಲ್ಲಿ, ನೀವು ಕಳುಹಿಸುವ ಡೇಟಾವನ್ನು ಇತರರು ವೀಕ್ಷಿಸಬಹುದು ಅಥವಾ ಸರ್ವರ್ ಪಡೆಯುವ ವಿಷಯವನ್ನು ದಾಳಿಕೋರರು ಮಾರ್ಪಡಿಸಬಹುದು.</translation>
<translation id="3157931365184549694">ಮರುಸ್ಥಾಪನೆ</translation>
+<translation id="3162559335345991374">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="3167968892399408617">ನಿಮ್ಮ ಎಲ್ಲಾ ಅಪರಿಚಿತ ಟ್ಯಾಬ್‌ಗಳನ್ನು ಮುಚ್ಚಿದ ಬಳಿಕ ನೀವು ಅಪರಿಚಿತ ಮೋಡ್‌ನಲ್ಲಿ ವೀಕ್ಷಿಸಿದ ಪುಟಗಳು ಬ್ರೌಸರ್ ಇತಿಹಾಸದಲ್ಲಿ, ಕುಕೀ ಸಂಗ್ರಹದಲ್ಲಿ ಅಥವಾ ಹುಡುಕಾಟ ಇತಿಹಾಸದಲ್ಲಿ ಉಳಿಯುವುದಿಲ್ಲ. ನೀವು ಡೌನ್‌ಲೋಡ್ ಮಾಡುವ ಯಾವುದೇ ಫೈಲ್‌ಗಳು ಇಲ್ಲವೇ ನೀವು ರಚಿಸುವ ಯಾವುದೇ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು ಹಾಗೆಯೇ ಇರಿಸಲಾಗುತ್ತದೆ.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">ದ್ವೀಪ</translation>
@@ -285,6 +295,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">ಪಾವತಿಯನ್ನು ರದ್ದುಮಾಡಿ</translation>
<translation id="3207960819495026254">ಬುಕ್‌ಮಾರ್ಕ್‌ ಮಾಡಲಾಗಿದೆ</translation>
+<translation id="3211223744486044430">ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಪಾವತಿಸಲು, ಈ ಕಾರ್ಡ್‌ ಅನ್ನು ನಿಮ್ಮ Google ಖಾತೆಯಲ್ಲಿ ಮತ್ತು ಈ ಸಾಧನದಲ್ಲಿ ಉಳಿಸಿ.</translation>
<translation id="3225919329040284222">ಆಂತರಿಕ ಮಾನದಂಡಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಸರ್ವರ್ ಹಾಜರಿಪಡಿಸಿದೆ. ನಿಮ್ಮ ಸುರಕ್ಷತೆಯ ಸಲುವಾಗಿ ಕೆಲವು ಹೆಚ್ಚು ಸುರಕ್ಷಿತ ವೆಬ್ ಸೈಟ್‌ಗಳಲ್ಲಿ ಈ ಮಾನದಂಡಗಳನ್ನು ಸೇರ್ಪಡೆಗೊಳಿಸಲಾಗಿದೆ.</translation>
<translation id="3226128629678568754">ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡುವುದಕ್ಕೆ ಅಗತ್ಯವಿರುವ ಡೇಟಾವನ್ನು ಮರುಸಲ್ಲಿಸಲು ಮರುಲೋಡ್ ಬಟನ್ ಒತ್ತಿರಿ.</translation>
<translation id="3227137524299004712">ಮೈಕ್ರೋಫೋನ್</translation>
@@ -299,7 +310,6 @@
<translation id="3303855915957856445">ಯಾವುದೇ ಹುಡುಕಾಟ ಫಲಿತಾಂಶಗಳು ಕಂಡುಬಂದಿಲ್ಲ</translation>
<translation id="3305707030755673451">ನಿಮ್ಮ ಡೇಟಾವನ್ನು <ph name="TIME" /> ರಂದು ನಿಮ್ಮ ಸಿಂಕ್ ಪಾಸ್‌ಫ್ರೇಸ್‌ನೊಂದಿಗೆ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ. ಸಿಂಕ್ ಪ್ರಾರಂಭಿಸಲು ಅದನ್ನು ನಮೂದಿಸಿ.</translation>
<translation id="3320021301628644560">ಬಿಲ್ಲಿಂಗ್ ವಿಳಾಸವನ್ನು ಸೇರಿಸಿ</translation>
-<translation id="3329013043687509092">ಸ್ಯಾಚುರೇಶನ್</translation>
<translation id="333371639341676808">ಈ ಪುಟ ಹೆಚ್ಚುವರಿ ಸಂವಾದಗಳನ್ನು ರಚಿಸುವುದನ್ನು ತಡೆಯಿರಿ.</translation>
<translation id="3338095232262050444">ಸುರಕ್ಷಿತ</translation>
<translation id="3340978935015468852">ಸೆಟ್ಟಿಂಗ್‌ಗಳು</translation>
@@ -318,6 +328,7 @@
<translation id="3380864720620200369">ಕ್ಲೈಂಟ್ ID:</translation>
<translation id="3391030046425686457">ವಿತರಣೆಯ ವಿಳಾಸಗಳು</translation>
<translation id="3395827396354264108">ಪಿಕಪ್ ವಿಧಾನ</translation>
+<translation id="3399952811970034796">ವಿತರಣೆಯ ವಿಳಾಸಗಳು</translation>
<translation id="3422248202833853650">ಮೆಮೊರಿ ಮುಕ್ತಗೊಳಿಸಲು ಇತರ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ನಿರ್ಗಮಿಸಲು ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ಅನ್ನು ಪ್ರಸ್ತುತ ತಲುಪಲಾಗುತ್ತಿಲ್ಲ.</translation>
<translation id="3427092606871434483">ಅನುಮತಿಸಿ (ಡಿಫಾಲ್ಟ್)</translation>
@@ -360,10 +371,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> ನಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ, <ph name="UPLOAD_TIME" /> ಸಮಯಕ್ಕೆ ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="3681007416295224113">ಪ್ರಮಾಣಪತ್ರ ಮಾಹಿತಿ</translation>
<translation id="3690164694835360974">ಲಾಗಿನ್ ಸುರಕ್ಷಿತವಾಗಿಲ್ಲ</translation>
+<translation id="3704162925118123524">ನೀವು ಬಳಸುತ್ತಿರುವ ನೆಟ್‌ವರ್ಕ್‌ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಭೇಟಿ ನೀಡಬೇಕಾದ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ಲೋಡ್ ಆಗುತ್ತಿದೆ...</translation>
<translation id="3712624925041724820">ಪರವಾನಗಿಗಳು ಬರಿದಾಗಿವೆ</translation>
<translation id="3714780639079136834">ಮೊಬೈಲ್ ಡೇಟಾ ಅಥವಾ ವೈ-ಫೈ ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ</translation>
+<translation id="3715597595485130451">ವೈ-ಫೈಗೆ ಸಂಪರ್ಕಿಸಿ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ಪ್ರಾಕ್ಸಿ, ಫೈರ್‌ವಾಲ್ ಮತ್ತು DNS ಕಾನ್ಫಿಗರೇಶನ್‌‌ ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">ನಿಮ್ಮ ಸುರಕ್ಷತೆ ಅಪಾಯಗಳು ನಿಮಗೆ ಅರ್ಥವಾಗಿದ್ದರೆ, ಅಪಾಯಕಾರಿ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ತೆಗೆದುಹಾಕುವುದಕ್ಕೂ ಮೊದಲು ನೀವು <ph name="BEGIN_LINK" />ಈ ಅಸುರಕ್ಷಿತ ಸೈಟ್‌ಗೆ ಭೇಟಿ ನೀಡಬಹುದು<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">ನೀವು ನಕಲಿಸಿದ ಲಿಂಕ್</translation>
@@ -398,6 +411,7 @@
<translation id="4030383055268325496">&amp;ಸೇರಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
<translation id="404928562651467259">ಎಚ್ಚರಿಕೆ</translation>
<translation id="4058922952496707368">ಕೀ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">ಮಾನ್ಯವಾದ ವಿಳಾಸ ಸೇರಿಸಿ</translation>
<translation id="4072486802667267160">ನಿಮ್ಮ ಆರ್ಡ‌ರ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಲ್ಲಿ ದೋಷ ಕಂಡುಬಂದಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="4075732493274867456">ಸಾಮಾನ್ಯ SSL ಪ್ರೊಟೋಕಾಲ್ ಆವೃತ್ತಿ ಅಥವಾ ಸೈಫರ್ ಸ್ಯೂಟ್ ಅನ್ನು ಕ್ಲೈಂಟ್ ಮತ್ತು ಸರ್ವರ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ.</translation>
<translation id="4079302484614802869">ಪ್ರಾಕ್ಸಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು .pac ಸ್ಕ್ರಿಪ್ಟ್ URL ಬಳಸುವಂತೆ ಹೊಂದಿಸಲಾಗಿದೆ, ಹೊಂದಿಸಿದ ಪ್ರಾಕ್ಸಿ ಸರ್ವರ್‌ಗಳಲ್ಲ.</translation>
@@ -405,7 +419,6 @@
<translation id="4103249731201008433">ಸಾಧನದ ಸರಣಿಯ ಸಂಖ್ಯೆ ಅಮಾನ್ಯವಾಗಿದೆ</translation>
<translation id="410351446219883937">ಆಟೋಪ್ಲೇ</translation>
<translation id="4103763322291513355">ನಿಮ್ಮ ಸಿಸ್ಟಂ ನಿರ್ವಾಹಕರು ವಿಧಿಸಿರುವ ಕಪ್ಪುಪಟ್ಟಿಯ URLಗಳು ಮತ್ತು ಇತರ ನೀತಿಗಳನ್ನು ವೀಕ್ಷಿಸಲು &lt;strong&gt;chrome://policy&lt;/strong&gt; ಗೆ ಭೇಟಿ ನೀಡಿ.</translation>
-<translation id="4115378294792113321">ಮಜೆಂತಾ</translation>
<translation id="4116663294526079822">ಈ ಸೈಟ್‌ನಲ್ಲಿ ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ</translation>
<translation id="4117700440116928470">ನೀತಿಯ ವ್ಯಾಪ್ತಿಯು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 ಇತರೆ}one{# ಇತರೆ}other{# ಇತರೆ}}</translation>
@@ -443,6 +456,7 @@
<translation id="4377125064752653719">ನೀವು <ph name="DOMAIN" /> ಅನ್ನು ತಲುಪಲು ಪ್ರಯತ್ನಿಸಿದಿರಿ, ಆದರೆ ಸರ್ವರ್ ನೀಡಿದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಅದರ ನೀಡುವವರು ಹಿಂತೆಗೆದುಕೊಂಡಿದ್ದಾರೆ. ಇದರರ್ಥ ಸರ್ವರ್ ನೀಡಿದ ಸುರಕ್ಷತೆ ರುಜುವಾತುಗಳನ್ನು ಖಂಡಿತವಾಗಿ ನಂಬಲಾಗುವುದಿಲ್ಲ. ನೀವು ಆಕ್ರಮಣಕಾರರೊಂದಿಗೆ ಸಂವಹಿಸುತ್ತಿರಬಹುದು.</translation>
<translation id="4394049700291259645">ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ</translation>
<translation id="4406896451731180161">ಹುಡುಕಾಟದ ಫಲಿತಾಂಶಗಳು</translation>
+<translation id="4415426530740016218">ಪಿಕಪ್ ವಿಳಾಸ</translation>
<translation id="4424024547088906515">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವು Chrome ಪಾಲಿಗೆ ವಿಶ್ವಾಸಾರ್ಹವಾಗಿಲ್ಲ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ನಿಮ್ಮ ಲಾಗಿನ್ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಸ್ವೀಕರಿಸಲಿಲ್ಲ ಅಥವಾ ಅದನ್ನು ಒದಗಿಸದೆ ಇರಬಹುದು.</translation>
<translation id="443673843213245140">ಪ್ರಾಕ್ಸಿಯ ಬಳಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗ ಪ್ರಾಕ್ಸಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿದೆ.</translation>
@@ -455,6 +469,7 @@
<translation id="4552089082226364758">ಫ್ಲ್ಯಾಶ್‌</translation>
<translation id="4558551763791394412">ನಿಮ್ಮ ವಿಸ್ತರಣೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="457875822857220463">ವಿತರಣೆ</translation>
+<translation id="4582800630050655161">ನಿಮ್ಮ Google ಖಾತೆಗೆ ಪ್ರವೇಶವನ್ನು ಕಳೆದುಕೊಳ್ಳಬಹುದು ಅಥವಾ ಗುರುತು ಕಳ್ಳತನ ನಿಂದನೆ ಅನುಭವಿಸಬಹುದು. ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಇದೀಗ ಬದಲಾಯಿಸುವಂತೆ Chromium ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ.</translation>
<translation id="4587425331216688090">Chrome ನಿಂದ ವಿಳಾಸವನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?</translation>
<translation id="4592951414987517459">ಆಧುನಿಕ ಸೈಫರ್ ಸೂಟ್ ಬಳಸುವ ಮೂಲಕ <ph name="DOMAIN" /> ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವನ್ನು ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="4594403342090139922">&amp;ಅಳಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
@@ -463,10 +478,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರದಲ್ಲಿ ಸಾಕಷ್ಟು ದೋಷಗಳಿವೆ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
<translation id="4690462567478992370">ಅಮಾನ್ಯ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಬಳಸಿಕೊಂಡು ನಿಲ್ಲಿಸಿ</translation>
+<translation id="4690954380545377795">ನಿಮ್ಮ Google ಖಾತೆಗೆ ಪ್ರವೇಶವನ್ನು ಕಳೆದುಕೊಳ್ಳಬಹುದು ಅಥವಾ ಗುರುತಿನ ಕಳ್ಳತನ ಅನುಭವಿಸಬಹುದು. ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಇದೀಗ ಬದಲಾಯಿಸುವಂತೆ Chrome ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">ನಿಮ್ಮ ಸಂಪರ್ಕಕ್ಕೆ ಅಡ್ಡಿಯಾಗಿದೆ</translation>
<translation id="471880041731876836">ಈ ಸೈಟ್‌ ಗೆ ಭೇಟಿ ನೀಡಲು ನೀವು ಅನುಮತಿ ಹೊಂದಿಲ್ಲ</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ನೆಟ್‌ವರ್ಕ್ ಡಯಾಗ್ನಾಸ್ಟಿಕ್ಸ್ ರನ್ ಮಾಡಲಾಗುತ್ತಿದೆ<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">ನಿಮ್ಮ ಪಾವತಿ</translation>
<translation id="4726672564094551039">ನೀತಿಗಳನ್ನು ಮರುಲೋಡ್ ಮಾಡಿ</translation>
<translation id="4728558894243024398">ಪ್ಲಾಟ್‌ಫಾರ್ಮ್</translation>
<translation id="4736825316280949806">Chromium ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
@@ -505,6 +522,7 @@
<translation id="5019198164206649151">ಕಳಪೆ ಸ್ಥಿತಿಯಲ್ಲಿ ಸಂಗ್ರಹಣೆಯನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗಿದೆ</translation>
<translation id="5023310440958281426">ನಿಮ್ಮ ನಿರ್ವಾಹಕ ನೀತಿಗಳನ್ನು ಪರಿಶೀಲಿಸಿ</translation>
<translation id="5029568752722684782">ನಕಲು ತೆರವುಗೊಳಿಸು</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" ಗೆ ರೂಟ್ ಪ್ರಮಾಣಪತ್ರದ ಅಗತ್ಯವಿದೆ ಆದರೆ ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿಲ್ಲ. ಈ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು "<ph name="SOFTWARE_NAME" />" ಗಾಗಿ ಕಾನ್ಫಿಗರೇಶನ್ ಸೂಚನೆಗಳ ಕಡೆ ಗಮನವಿಡಬೇಕು. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google ಅನುವಾದದ ಕುರಿತು</translation>
<translation id="5039804452771397117">ಅನುಮತಿಸಿ</translation>
<translation id="5040262127954254034">ಗೌಪ್ಯತೆ</translation>
@@ -528,6 +546,8 @@
<translation id="5199729219167945352">ಪ್ರಯೋಗಗಳು</translation>
<translation id="5205222826937269299">ಹೆಸರು ಅವಶ್ಯವಾಗಿದೆ</translation>
<translation id="5222812217790122047">ಇಮೇಲ್ ಅಗತ್ಯವಿದೆ</translation>
+<translation id="522700295135997067">ಈ ಸೈಟ್‌ ಕಳವು ಮಾಡಿರುವ ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಹೊಂದಿರಬಹುದು</translation>
+<translation id="5230733896359313003">ಶಿಪ್ಪಿಂಗ್ ವಿಳಾಸ</translation>
<translation id="5251803541071282808">ಮೇಘ</translation>
<translation id="5277279256032773186">ಕೆಲಸದಲ್ಲಿ Chrome ಬಳಸುತ್ತಿರುವಿರಾ? ತಮ್ಮ ಉದ್ಯೋಗಿಗಳಿಗಾಗಿ ವ್ಯವಹಾರಗಳಲ್ಲಿ Chrome ಸೆಟ್ಟಿಂಗ್‌ಗಳು ನಿರ್ವಹಿಸಬಹುದು. ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />ಈ ಹಂತಗಳನ್ನು ಅನುಸರಿಸಿ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಾಫ್ಟ್‌ವೇರ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದರೆ ನೀವು ವೆಬ್‌ ಅನ್ನು ಪಡೆದುಕೊಳ್ಳಬಹುದಾಗಿದೆ. ನಿಮಗೆ ನಿರ್ವಾಹಕರ ಸವಲತ್ತುಗಳ ಅಗತ್ಯವಿದೆ.<ph name="END_PARAGRAPH" />
@@ -541,9 +561,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">ಈ ಸೈಟ್‌ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವು ಖಾಸಗಿಯಾಗಿಲ್ಲ. ಯಾವ ಸಮಯದಲ್ಲಾದರೂ VR ಮೋಡ್‌‌ನಿಂದ ನಿರ್ಗಮಿಸಲು, ಹೆಡ್‌ಸೆಟ್ ತೆಗೆದುಹಾಕಿ ಮತ್ತು ಹಿಂದೆ ಒತ್ತಿರಿ.</translation>
<translation id="5299298092464848405">ನೀತಿಯ ಪಾರ್ಸಿಂಗ್‌ನಲ್ಲಿ ದೋಷ</translation>
+<translation id="5308380583665731573">ಸಂಪರ್ಕಿಸು</translation>
<translation id="5308689395849655368">ಕ್ರ‍್ಯಾಶ್‌‌ ವರದಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.</translation>
<translation id="5317780077021120954">ಉಳಿಸು</translation>
<translation id="5327248766486351172">ಹೆಸರು</translation>
+<translation id="5332219387342487447">ಶಿಪ್ಪಿಂಗ್ ವಿಧಾನ</translation>
<translation id="5355557959165512791">ಸದ್ಯಕ್ಕೆ ನೀವು <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಏಕೆಂದರೆ ಇದರ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಹಿಂಪಡೆದುಕೊಳ್ಳಲಾಗಿದೆ. ನೆಟ್‌ವರ್ಕ್ ದೋಷಗಳು ಮತ್ತು ಆಕ್ರಮಣಗಳು ತಾತ್ಕಾಲಿಕವಾಗಿರುತ್ತವೆ, ಹೀಗಾಗಿ ಈ ಪುಟವು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಕಾರ್ಯನಿರ್ವಹಿಸಬಹುದು.</translation>
<translation id="536296301121032821">ನೀತಿಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಸಂಗ್ರಹಿಸುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ</translation>
<translation id="5386426401304769735">ಈ ಸೈಟ್‌ಗೆ ಪ್ರಮಾಣಪತ್ರ ಸರಣಿಯು SHA-1 ಬಳಸಿಕೊಂಡು ಸಹಿ ಮಾಡಲಾದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ.</translation>
@@ -563,12 +585,15 @@
<translation id="5492298309214877701">ಬಾಹ್ಯ ವೆಬ್‌ಸೈಟ್‌‌ನ URL ಅನ್ನೇ ಕಂಪನಿ, ಸಂಸ್ಥೆ ಅಥವಾ ಶಾಲೆಯ ಇಂಟ್ರಾನೆಟ್‌ನಲ್ಲಿನ ಈ ಸೈಟ್ ಹೊಂದಿದೆ.
<ph name="LINE_BREAK" />
ನಿಮ್ಮ ಸಿಸ್ಟಂ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿ.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> ಗೆ ಸುರಕ್ಷತೆ ಕೋಡ್‌ ಅನ್ನು ನಮೂದಿಸಿ. ಈ ಕೋರ್ಡ್‌ ಅನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="5509780412636533143">ನಿರ್ವಹಿಸಿದ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="5510766032865166053">ಈ ಫೈಲನ್ನು ಬೇರೆಡೆಗೆ ಸರಿಸಿರಬಹುದು ಇಲ್ಲವೇ ಅಳಿಸಿರಬಹುದು.</translation>
<translation id="5523118979700054094">ನೀತಿ ಹೆಸರು</translation>
<translation id="552553974213252141">ಪಠ್ಯವನ್ನು ಸರಿಯಾಗಿ ಪ್ರತ್ಯೇಕಿಸಲಾಗಿದೆಯೇ?</translation>
<translation id="5540224163453853">ವಿನಂತಿಸಿದ ಲೇಖನವನ್ನು ಹುಡುಕಲು ಸಾಧವಾಗಲಿಲ್ಲ.</translation>
+<translation id="5541546772353173584">ಇಮೇಲ್ ಸೇರಿಸಿ</translation>
<translation id="5544037170328430102"><ph name="SITE" /> ನಲ್ಲಿ ಎಂಬೆಡ್ ಮಾಡಲಾದ ಪುಟವು ಹೀಗೆ ಹೇಳುತ್ತದೆ:</translation>
+<translation id="5545756402275714221">ನಿಮಗಾಗಿ ಲೇಖನಗಳು</translation>
<translation id="5556459405103347317">ಮರುಲೋಡ್‌</translation>
<translation id="5560088892362098740">ಅವಧಿ ಮುಗಿಯುವ ದಿನಾಂಕ</translation>
<translation id="5565735124758917034">ಸಕ್ರಿಯ</translation>
@@ -590,6 +615,7 @@
<translation id="5659593005791499971">ಇಮೇಲ್</translation>
<translation id="5669703222995421982">ವೈಯಕ್ತೀಕರಿಸಲಾದ ವಿಷಯವನ್ನು ಪಡೆಯಿರಿ</translation>
<translation id="5675650730144413517">ಈ ಪುಟ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲ</translation>
+<translation id="5689199277474810259">JSON ಗೆ ರಫ್ತು ಮಾಡಿ</translation>
<translation id="5710435578057952990">ಈ ವೆಬ್‌ಸೈಟ್‌ನ ಗುರುತಿಸುವಿಕೆಯನ್ನು ಇನ್ನೂ ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ.</translation>
<translation id="5719499550583120431">ಪ್ರೀಪೇಯ್ಡ್ ಕಾರ್ಡ್‌ಗಳನ್ನು ಸಮ್ಮತಿಸಲಾಗಿದೆ.</translation>
<translation id="5720705177508910913">ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ</translation>
@@ -604,27 +630,27 @@
<translation id="5810442152076338065">ಬಳಕೆಯಲ್ಲಿಲ್ಲದ ಸೈಫರ್ ಸೂಟ್ ಬಳಸುವ ಮೂಲಕ <ph name="DOMAIN" /> ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವನ್ನು ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="5813119285467412249">&amp;ಸೇರಿಸುವುದನ್ನು ಮತ್ತೆಮಾಡು</translation>
<translation id="5838278095973806738">ಈ ಸೈಟ್‌ನಲ್ಲಿ ನೀವು ಯಾವುದೇ ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು (ಉದಾಹರಣೆಗೆ, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಅಥವಾ ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್‌ಗಳು) ನಮೂದಿಸಬಾರದು, ಏಕೆಂದರೆ ಅದು ದಾಳಿಕೋರರ ಮೂಲಕ ಕಳುವಾಗಬಹುದು.</translation>
+<translation id="5866257070973731571">ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ</translation>
<translation id="5869405914158311789">ಈ ಸೈಟ್ ತಲುಪಲಾಗುವುದಿಲ್ಲ</translation>
<translation id="5869522115854928033">ಉಳಿಸಲಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು</translation>
<translation id="5872918882028971132">ಪೋಷಕ ಸಲಹೆಗಳು</translation>
<translation id="5893752035575986141">ಕ್ರೆಡಿಟ್‌ ಕಾರ್ಡ್‌ಗಳನ್ನು ಸಮ್ಮತಿಸಲಾಗಿದೆ.</translation>
-<translation id="5901630391730855834">ಹಳದಿ</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ಸಿಂಕ್‌ ಮಾಡಲಾಗಿದೆ)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 ಬಳಕೆಯಲ್ಲಿದೆ}one{# ಬಳಕೆಯಲ್ಲಿದೆ}other{# ಬಳಕೆಯಲ್ಲಿದೆ}}</translation>
<translation id="5959728338436674663">ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಸೈಟ್‌ಗಳ ಪತ್ತೆಗೆ ಸಹಾಯ ಮಾಡಲು Google ಗೆ ಕೆಲವು <ph name="BEGIN_WHITEPAPER_LINK" />ಸಿಸ್ಟಂ ಮಾಹಿತಿ ಮತ್ತು ಪುಟ ವಿಷಯ<ph name="END_WHITEPAPER_LINK" />ವನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕಳುಹಿಸಿ. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">ಸಂಪರ್ಕ ಮಾಹಿತಿಯನ್ನು ಎಡಿಟ್ ಮಾಡಿ</translation>
<translation id="5967867314010545767">ಇತಿಹಾಸದಿಂದ ತೆಗೆದುಹಾಕಿ</translation>
<translation id="5975083100439434680">ಝೂಮ್ ಔಟ್</translation>
+<translation id="597552863672748783">ಸುರಕ್ಷತೆ ಕೋಡ್ ಅನ್ನು ದೃಢೀಕರಿಸಿ</translation>
<translation id="598637245381783098">ಪಾವತಿ ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ</translation>
<translation id="5989320800837274978">ಹೊಂದಿಸಿದ ಪ್ರಾಕ್ಸಿ ಸರ್ವರ್‌ಗಳು ಆಗಲಿ ಅಥವಾ .pac ಸ್ಕ್ರಿಪ್ಟ್ URL ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಿಲ್ಲ.</translation>
<translation id="5990559369517809815">ಸರ್ವರ್‌ಗಳ ವಿನಂತಿಗಳನ್ನು ವಿಸ್ತರಣೆಯಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{ಪುಟ 1}one{ಪುಟ #}other{ಪುಟ #}}</translation>
-<translation id="6017514345406065928">ಹಸಿರು</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (ಸಿಂಕ್‌ ಮಾಡಲಾಗಿದೆ)</translation>
<translation id="6027201098523975773">ಹೆಸರು ನಮೂದಿಸಿ</translation>
<translation id="6040143037577758943">ಮುಚ್ಚಿರಿ</translation>
-<translation id="6042308850641462728">ಇನ್ನಷ್ಟು</translation>
<translation id="6047233362582046994">ನಿಮ್ಮ ಸುರಕ್ಷತೆ ಅಪಾಯಗಳು ನಿಮಗೆ ಅರ್ಥವಾಗಿದ್ದರೆ, ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕುವುದಕ್ಕೂ ಮೊದಲು ನೀವು <ph name="BEGIN_LINK" />ಈ ಸೈಟ್‌ಗೆ ಭೇಟಿ<ph name="END_LINK" /> ನೀಡಬಹುದು.</translation>
<translation id="6047927260846328439">ಈ ಕಂಟೆಂಟ್‌ ಸಾಫ್ಟ್‌ವೇರ್ ಸ್ಥಾಪಿಸುವಂತೆ ಅಥವಾ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಬಹಿರಂಗಪಡಿಸುವಂತೆ ನಿಮ್ಮನ್ನು ಮೋಸಗೊಳಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರಬಹುದು. <ph name="BEGIN_LINK" />ಹೇಗಿದ್ದರೂ ತೋರಿಸಿ<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ನೀವು ಸದ್ಯಕ್ಕೆ <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಏಕೆಂದರೆ, ವೆಬ್‌ಸೈಟ್ ಪ್ರಮಾಣಪತ್ರ ಪಿನ್ ಮಾಡುವಿಕೆಯನ್ನು ಬಳಸುತ್ತದೆ. ನೆಟ್‌ವರ್ಕ್ ದೋಷಗಳು ಮತ್ತು ಆಕ್ರಮಣಗಳು ತಾತ್ಕಾಲಿಕವಾಗಿರುತ್ತವೆ, ಹೀಗಾಗಿ ಈ ಪುಟವು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಕಾರ್ಯ ನಿರ್ವಹಿಸಬಹುದು.</translation>
@@ -690,6 +716,7 @@
<translation id="6569060085658103619">ನೀವು ವಿಸ್ತರಣೆ ಪುಟವನ್ನು ವೀಕ್ಷಿಸುತ್ತಿರುವಿರಿ</translation>
<translation id="6596325263575161958">ಎನ್‌ಕ್ರಿಫ್ಶನ್ ಆಯ್ಕೆಗಳು</translation>
<translation id="662080504995468778">ಉಳಿಯಿರಿ</translation>
+<translation id="6624427990725312378">ಸಂಪರ್ಕ ಮಾಹಿತಿ</translation>
<translation id="6626291197371920147">ಮಾನ್ಯವಾದ ಕಾರ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ಹುಡುಕಾಟ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನ ದಾಳಿಕೋರರು ನಿಮ್ಮ Macನಲ್ಲಿ ಮಾಹಿತಿಯನ್ನು (ಉದಾಹರಣೆಗೆ, ಫೋಟೋಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಮಾಹಿತಿಗಳು) ಕದಿಯಲು ಇಲ್ಲವೇ ಅಳಿಸಲು ಅಪಾಯಕಾರಿ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಸ್ಥಾಪಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರಬಹುದು. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -700,7 +727,6 @@
<translation id="6710213216561001401">ಹಿಂದೆ</translation>
<translation id="6710594484020273272">&lt;ಹುಡುಕಾಟದ ಪದ ಟೈಪ್ ಮಾಡಿ&gt;</translation>
<translation id="6711464428925977395">ಪ್ರಾಕ್ಸಿ ಸರ್ವರ್‌‌ನಲ್ಲಿ ಏನೋ ದೋಷವಿದೆ ಅಥವಾ ವಿಳಾಸವು ತಪ್ಪಾಗಿದೆ.</translation>
-<translation id="6727102863431372879">ಹೊಂದಿಸು</translation>
<translation id="674375294223700098">ಅಪರಿಚಿತ ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರ ದೋಷ.</translation>
<translation id="6753269504797312559">ನೀತಿ ಮೌಲ್ಯ</translation>
<translation id="6757797048963528358">ನಿಮ್ಮ ಸಾಧನವು ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗಿದೆ.</translation>
@@ -769,6 +795,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">ಪ್ರೊಫೈಲ್ ಹಾದಿ</translation>
<translation id="7424977062513257142">ಈ ವೆಬ್‌ಪುಟದಲ್ಲಿ ಎಂಬೆಡ್ ಮಾಡಲಾದ ಪುಟವು ಹೀಗೆ ಹೇಳುತ್ತದೆ:</translation>
+<translation id="7437289804838430631">ಸಂಪರ್ಕ ಮಾಹಿತಿಯನ್ನು ಸೇರಿಸು</translation>
<translation id="7441627299479586546">ತಪ್ಪಾದ ನೀತಿಯ ವಿಷಯ</translation>
<translation id="7444046173054089907">ಈ ಸೈಟ್ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ</translation>
<translation id="7445762425076701745">ನೀವು ಸಂಪರ್ಕ ಮಾಡಿರುವ ಸರ್ವರ್‌ನ ಗುರುತನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಮೌಲ್ಯೀಕರಿಸಲಾಗುವುದಿಲ್ಲ. ನೀವು ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ನಲ್ಲಿಯೇ ಮಾನ್ಯವಿರುವ ಹೆಸರನ್ನು ಮಾತ್ರ ಬಳಸಿಕೊಂಡು ಸಂಪರ್ಕ ಹೊಂದಿರುವಿರಿ, ಇದರ ಮಾಲಿಕತ್ವವನ್ನು ಮೌಲ್ಯೀಕರಿಸುವ ಯಾವ ಅವಕಾಶವನ್ನೂ ಬಾಹ್ಯ ಪ್ರಮಾಣಪತ್ರ ಪ್ರಾಧಿಕಾರವು ಹೊಂದಿಲ್ಲ. ಕೆಲವು ಪ್ರಮಾಣಪತ್ರ ಪ್ರಾಧಿಕಾರಗಳು, ಯಾವುದೇ ಹೆಸರನ್ನು ಪರಿಗಣಿಸದೇ, ಪ್ರಮಾಣಪತ್ರಗಳನ್ನು ಬಿಡುಗಡೆ ಮಾಡುವ ಕಾರಣದಿಂದಾಗಿ, ನೀವು ಉದ್ದೇಶಿತ ವೆಬ್‌ಸೈಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಿರುವಿರೇ ಹೊರತು ದಾಳಿ ಮಾಡಲು ಅಲ್ಲ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳುವ ಯಾವ ಅವಕಾಶವೂ ಇಲ್ಲ.</translation>
@@ -779,11 +806,11 @@
<translation id="7481312909269577407">ಫಾರ್ವರ್ಡ್</translation>
<translation id="7485870689360869515">ಯಾವುದೇ ಡೇಟಾ ಕಂಡುಬಂದಿಲ್ಲ.</translation>
<translation id="7508255263130623398">ಹಿಂತಿರುಗಿಸಲಾದ ನೀತಿಯ ಸಾಧನ ಐಡಿ ಖಾಲಿ ಇದೆ ಅಥವಾ ಪ್ರಸ್ತುತ ಸಾಧನ ಐಡಿಗೆ ಹೊಂದಾಣಿಕೆಯಾಗುವುದಿಲ್ಲ</translation>
+<translation id="7511955381719512146">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈಗೆ ನೀವು <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ಅನ್ನು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="7514365320538308">ಡೌನ್‌ಲೋಡ್</translation>
<translation id="7518003948725431193">ಈ ವೆಬ್ ವಿಳಾಸಕ್ಕಾಗಿ ಯಾವುದೇ ವೆಬ್ ಪುಟವು ಕಂಡುಬರಲಿಲ್ಲ: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">ಈ ಸೈಟ್‌ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವು ಖಾಸಗಿಯಾಗಿಲ್ಲ.</translation>
-<translation id="7535087603100972091">ಮೌಲ್ಯ</translation>
<translation id="7537536606612762813">ಕಡ್ಡಾಯ</translation>
<translation id="7542403920425041731">ನೀವು ಒಮ್ಮೆ ಖಚಿತಪಡಿಸಿದರೆ, ನಿಮ್ಮ ಕಾರ್ಡ್ ವಿವರಗಳನ್ನು ಈ ಸೈಟ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.</translation>
<translation id="7542995811387359312">ಈ ಫಾರ್ಮ್ ಸುರಕ್ಷಿತವಾದ ಸಂಪರ್ಕವನ್ನು ಬಳಸುತ್ತಿಲ್ಲವಾದ ಕಾರಣ ಸ್ವಯಂಚಾಲಿತ ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಭರ್ತಿ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.</translation>
@@ -794,7 +821,6 @@
<translation id="7567204685887185387">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವನ್ನು ವಂಚನೆಯಿಂದ ನೀಡಿರಬಹುದು. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
<translation id="7568593326407688803">ಈ ಪುಟವು<ph name="ORIGINAL_LANGUAGE" />ನಲ್ಲಿದೆ ನೀವು ಅದನ್ನು ಭಾಷಾಂತರಿಸಲು ಬಯಸುವಿರಾ?</translation>
<translation id="7569952961197462199">Chrome ನಿಂದ ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ತೆಗೆದುಹಾಕುವುದೇ?</translation>
-<translation id="7569983096843329377">ಕಪ್ಪು</translation>
<translation id="7578104083680115302">Google ನೊಂದಿಗೆ ನೀವು ಉಳಿಸಲಾದ ಕಾರ್ಡ್‌ಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಸಾಧನಗಳಾದ್ಯಂತ ಸೈಟ್‌ಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿ ತ್ವರಿತವಾಗಿ ಪಾವತಿಸಿ.</translation>
<translation id="7588950540487816470">ಭೌತಿಕ ವೆಬ್</translation>
<translation id="7592362899630581445">ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರವು ಹೆಸರಿನ ನಿರ್ಬಂಧನೆಗಳನ್ನು ಉಲ್ಲಂಘಿಸುತ್ತದೆ.</translation>
@@ -813,11 +839,13 @@
<translation id="7669271284792375604">ನಿಮ್ಮ ಬ್ರೌಸಿಂಗ್‌ ಅನುಭವವನ್ನು ಹಾನಿಮಾಡಲು ಸ್ಥಾಪಿಸಲಾಗುವ ಪ್ರೋಗ್ರಾಂಗಳಲ್ಲಿ ನಿಮ್ಮನ್ನು ವಂಚಿಸಲು ಆಕ್ರಮಣಕಾರರು ಈ ಸೈಟ್‌ ಮೇಲೆ ದಾಳಿ ಮಾಡಬಹುದು (ಉದಾಹರಣೆಗೆ, ನಿಮ್ಮ ಮುಖಪುಟವನ್ನು ಬದಲಾಯಿಸಲಾಗುತ್ತದೆ ಅಥವಾ ನೀವು ಭೇಟಿ ನೀಡುವ ಸೈಟ್‌ಗಳಲ್ಲಿ ಹೆಚ್ಚಿನ ಜಾಹೀರಾತುಗಳನ್ನು ತೋರಿಸಲಾಗುತ್ತದೆ).</translation>
<translation id="7674629440242451245">ಉತ್ತಮವಾದ ಹೊಸ Chrome ವೈಶಿಷ್ಟ್ಯಗಳಲ್ಲಿ ಆಸಕ್ತಿ ಇದೆಯೇ? chrome.com/dev ನಲ್ಲಿ ನಮ್ಮ dev ಚಾನಲ್ ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="7682287625158474539">ಶಿಪ್ಪಿಂಗ್</translation>
+<translation id="7699293099605015246">ಲೇಖನಗಳು ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ</translation>
<translation id="7701040980221191251">ಯಾವುದೂ ಇಲ್ಲ</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> ಗೆ (ಅಸುರಕ್ಷಿತ) ಮುಂದುವರೆಸು<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">ಪ್ರಮಾಣಪತ್ರ</translation>
<translation id="7716147886133743102">ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ</translation>
<translation id="7716424297397655342">ಸಂಗ್ರಹದಿಂದ ಈ ಸೈಟ್ ಲೋಡ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ</translation>
+<translation id="7723047071702270851">ಕಾರ್ಡ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ</translation>
<translation id="774634243536837715">ಅಪಾಯಕಾರಿ ವಿಷಯವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ.</translation>
<translation id="7752995774971033316">ನಿರ್ವಹಣೆಯಲ್ಲಿಲ್ಲ</translation>
<translation id="7755287808199759310">ನಿಮ್ಮ ಪೋಷಕರು ನಿಮಗಾಗಿ ಅದನ್ನು ಅನಿರ್ಬಂಧಿಸಬಹುದಾಗಿದೆ</translation>
@@ -828,21 +856,24 @@
<translation id="7764225426217299476">ವಿಳಾಸ ಸೇರಿಸಿ</translation>
<translation id="777702478322588152">Prefecture</translation>
<translation id="7791543448312431591">ಸೇರಿಸು</translation>
+<translation id="7793553086574152071">ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಪಾವತಿಸಲು, ಈ ಕಾರ್ಡ್‌ ಅನ್ನು ನಿಮ್ಮ Google ಖಾತೆಯಲ್ಲಿ ಉಳಿಸಿ.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> ನಲ್ಲಿರುವ ವೆಬ್‌ಪುಟವು ತಾತ್ಕಾಲಿಕವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರಬಹುದು ಅಥವಾ ಅದನ್ನು ಶಾಶ್ವತವಾಗಿ ಹೊಸ ವೆಬ್ ವಿಳಾಸಕ್ಕೆ ಸರಿಸಿರಬಹುದು.</translation>
<translation id="7800304661137206267">ಸಂದೇಶದ ದೃಢೀಕರಣಕ್ಕಾಗಿ <ph name="MAC" /> ಮತ್ತು <ph name="KX" /> ನಂತೆ ಕೀಲಿ ವಿನಿಮಯದ ಯಾಂತ್ರಿಕತೆ ಜೊತೆಗೆ <ph name="CIPHER" /> ಅನ್ನು ಬಳಸಿ ಸಂಪರ್ಕವನ್ನು ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ.</translation>
+<translation id="7802523362929240268">ಸೈಟ್‌ ಕಾನೂನುಬದ್ಧವಾಗಿದೆ</translation>
<translation id="780301667611848630">ಬೇಡ, ಧನ್ಯವಾದಗಳು</translation>
<translation id="7805768142964895445">ಸ್ಥಿತಿ</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome ನಿಂದ ಫಾರ್ಮ್ ಸಲಹೆಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ಗೆ '<ph name="SEARCH_STRING" />' ಕಂಡುಬಂದಿದೆ</translation>
+<translation id="782886543891417279">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ (<ph name="WIFI_NAME" />) ಅದರ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="785549533363645510">ಆದರೆ, ನೀವು ಅದೃಶ್ಯರಾಗಿರುವುದಿಲ್ಲ. ಅಜ್ಞಾತವಾಗಿ ಹೋಗುವುದರಿಂದ ನಿಮ್ಮ ಉದ್ಯೋಗದಾತರು, ನಿಮ್ಮ ಇಂಟರ್ನೆಟ್ ಸೇವಾ ಪೂರೈಕೆದಾರರು ಇಲ್ಲವೇ ನೀವು ಭೇಟಿ ನೀಡುವ ವೆಬ್‌ಸೈಟ್‌ಗಳಿಂದ ನಿಮ್ಮ ಬ್ರೌಸಿಂಗ್ ಮರೆ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">ಡೆಬಿಟ್ ಮತ್ತು ಪ್ರೀಪೇಯ್ಡ್ ಕಾರ್ಡ್‌ಗಳನ್ನು ಸಮ್ಮತಿಸಲಾಗಿದೆ.</translation>
+<translation id="7878562273885520351">ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಸುಲಭವಾಗಿ ಪತ್ತೆ ಮಾಡಬಹುದು</translation>
<translation id="7887683347370398519">ನಿಮ್ಮ CVC ಅನ್ನು ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</translation>
<translation id="79338296614623784">ಮಾನ್ಯವಾದ ಫೋನ್ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ</translation>
<translation id="7935318582918952113">DOM ಡಿಸ್ಟಿಲರ್</translation>
<translation id="7938958445268990899">ಸರ್ವರ್‌ನ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಇನ್ನೂ ಮಾನ್ಯಗೊಳಿಸಿಲ್ಲ.</translation>
-<translation id="7942349550061667556">ಕೆಂಪು</translation>
<translation id="7947285636476623132">ನಿಮ್ಮ ಮುಕ್ತಾಯ ವರ್ಷವನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಪುನಃ ಪ್ರಯತ್ನಿಸಿ</translation>
<translation id="7951415247503192394">(32-ಬಿಟ್)</translation>
<translation id="7956713633345437162">ಮೊಬೈಲ್ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
@@ -856,9 +887,13 @@
<translation id="8037357227543935929">ಕೇಳು (ಡಿಫಾಲ್ಟ್)</translation>
<translation id="8041089156583427627">ಪ್ರತಿಕ್ರಿಯೆ ಕಳುಹಿಸಿ</translation>
<translation id="8041940743680923270">ಜಾಗತಿಕ ಡಿಫಾಲ್ಟ್ ಬಳಸಿ (ಕೇಳಿ)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ಅನ್ನು ಸರಿಯಾಗಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿಲ್ಲ. ಸಾಮಾನ್ಯವಾಗಿ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು "<ph name="SOFTWARE_NAME" />" ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">ಲೇಖನವನ್ನು ವೀಕ್ಷಿಸಲು ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="8091372947890762290">ಸರ್ವರ್‌ನಲ್ಲಿ ಸಕ್ರಿಯತೆ ಬಾಕಿ ಉಳಿದಿದೆ</translation>
+<translation id="8094917007353911263">ನೀವು ಬಳಸುತ್ತಿರುವ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ನೀವು <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ಅನ್ನು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
+<translation id="8103161714697287722">ಪಾವತಿ ವಿಧಾನ</translation>
<translation id="8118489163946903409">ಪಾವತಿ ವಿಧಾನ</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್ ಅಥವಾ ನೆಟ್‌ವರ್ಕ್ ನಲ್ಲಿ ಸರಿಯಾಗಿ ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿಲ್ಲ: ಈ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರಿಗೆ ತಿಳಿಸಿ.</translation>
<translation id="8131740175452115882">ದೃಢೀಕರಿಸು</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ಅವರ ಸರ್ವರ್‌ <ph name="BEGIN_ABBR" />DNS ವಿಳಾಸ<ph name="END_ABBR" /> ಕಂಡುಬಂದಿಲ್ಲ.</translation>
<translation id="8149426793427495338">ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್ ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗಿದೆ.</translation>
@@ -881,6 +916,7 @@
<translation id="8289355894181816810">ಇದರ ಅರ್ಥವೇನೆಂದು ನಿಮಗೆ ಖಚಿತವಾಗದಿದ್ದರೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.</translation>
<translation id="8293206222192510085">ಬುಕ್‌ಮಾರ್ಕ್ ಸೇರಿಸು</translation>
<translation id="8294431847097064396">ಮೂಲ</translation>
+<translation id="8298115750975731693">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ (<ph name="WIFI_NAME" />) ಗೆ ನೀವು <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ಅನ್ನು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="8306404619377842860"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಖಾಸಗಿ ಸಂಪರ್ಕವನ್ನು ಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ಏಕೆಂದರೆ ನಿಮ್ಮ ಸಾಧನದ ದಿನಾಂಕ ಮತ್ತು ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪ್ಪಾಗಿದೆ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕದಲ್ಲಿನ ಸಮಸ್ಯೆಯಿಂದಾಗಿ ಭಾಷಾಂತರವು ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ಗೆ ಪ್ರವೇಶವನ್ನು ನಿರಾಕರಿಸಲಾಗಿದೆ</translation>
@@ -934,20 +970,21 @@
<translation id="8870413625673593573">ಇತ್ತೀಚೆಗೆ ಮುಚ್ಚಿರುವುದು</translation>
<translation id="8874824191258364635">ಮಾನ್ಯವಾದ ಕಾರ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ</translation>
<translation id="8876793034577346603">ಪಾರ್ಸ್ ಮಾಡಬೇಕಾಗಿರುವ ನೆಟ್‌ವರ್ಕ್ ಕಾನ್ಫಿಗರೇಶನ್ ವಿಫಲವಾಗಿದೆ.</translation>
-<translation id="8889402386540077796">ವರ್ಣ</translation>
<translation id="8891727572606052622">ಅಮಾನ್ಯವಾದ ಪ್ರಾಕ್ಸಿ ಮೋಡ್.</translation>
<translation id="889901481107108152">ಕ್ಷಮಿಸಿ, ಈ ಪ್ರಯೋಗವು ನಿಮ್ಮ ಪ್ಲ್ಯಾಟ್‌ಫಾರ್ಮ್‌ನಲ್ಲಿ ಲಭ್ಯವಿಲ್ಲ.</translation>
<translation id="8903921497873541725">ಝೂಮ್ ಇನ್</translation>
<translation id="8931333241327730545">ಈ ಕಾರ್ಡನ್ನು ನಿಮ್ಮ Google ಖಾತೆನಲ್ಲಿ ಉಳಿಸಲು ಬಯಸುವಿರಾ?</translation>
<translation id="8932102934695377596">ನಿಮ್ಮ ಗಡಿಯಾರ ಹಿಂದೆ ಇದೆ</translation>
+<translation id="893332455753468063">ಹೆಸರು ಸೇರಿಸಿ</translation>
<translation id="8938939909778640821">ಸಮ್ಮತಿಸಲಾದ ಕ್ರೆಡಿಟ್ ಮತ್ತು ಪ್ರೀಪೇಯ್ಡ್ ಕಾರ್ಡ್‌ಗಳು</translation>
+<translation id="8957210676456822347">ಕ್ಯಾಪ್ಟಿವ್ ಪೋರ್ಟಲ್ ದೃಢೀಕರಣ</translation>
<translation id="8971063699422889582">ಸರ್ವರ್‌ನ ಪ್ರಕಮಾಣಪತ್ರದ ಅವಧಿ ಮುಕ್ತಾಯಗೊಂಡಿದೆ.</translation>
-<translation id="8986494364107987395">ಬಳಕೆಯ ಅಂಕಿಅಂಶಗಳನ್ನು ಮತ್ತು ಕ್ರಾಶ್ ವರದಿಗಳನ್ನು Google ಗೆ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ರವಾನಿಸು</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">ಈ ಮುಂದಕ್ಕೆ ಸೈಟ್ ಹಾನಿಕಾರಕ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಹೊಂದಿದೆ</translation>
<translation id="8997023839087525404">ಪ್ರಮಾಣಪತ್ರ ಪಾರದರ್ಶಕತೆ ನೀತಿಯನ್ನು ಬಳಸಿಕೊಂಡು ಸಾರ್ವಜನಿಕವಾಗಿ ಬಹಿರಂಗಗೊಳಿಸದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಸರ್ವರ್ ಪ್ರಸ್ತುತಪಡಿಸಿದೆ. ಇದು ಅವುಗಳು ವಿಶ್ವಾಸಾರ್ಹವಾಗಿವೆ ಮತ್ತು ಆಕ್ರಮಣಗಾರರ ವಿರುದ್ಧ ರಕ್ಷಣೆಯನ್ನು ನೀಡುತ್ತವೆ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಕೆಲವು ಪ್ರಮಾಣಪತ್ರಗಳಿಗೆ ಅಗತ್ಯವಾಗಿದೆ.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> ಪ್ರಾಕ್ಸಿಗೆ ಬಳಕೆದಾರಹೆಸರು ಮತ್ತು ಪಾಸ್‌ವರ್ಡ್ ಅಗತ್ಯವಿರುತ್ತದೆ.</translation>
<translation id="9005998258318286617">PDF ಡಾಕ್ಯುಮೆಂಟ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ.</translation>
+<translation id="9008201768610948239">ನಿರ್ಲಕ್ಷಿಸಿ</translation>
<translation id="901974403500617787">ಸಿಸ್ಟಂನಾದ್ಯಂತ ಅನ್ವಯವಾಗುವ ಫ್ಲ್ಯಾಗ್‌ಗಳನ್ನು ಮಾಲೀಕರಿಂದ ಮಾತ್ರ ಹೊಂದಿಸಲು ಸಾಧ್ಯ: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">ಕಾರ್ಡ್‌ ಬಿಲ್ಲಿಂಗ್ ವಿಳಾಸದ ಅಗತ್ಯವಿದೆ</translation>
<translation id="9020542370529661692">ಈ ಪುಟವನ್ನು <ph name="TARGET_LANGUAGE" /> ಗೆ ಅನುವಾದಿಸಲಾಗಿದೆ</translation>
@@ -957,11 +994,14 @@
<translation id="9049981332609050619">ನೀವು <ph name="DOMAIN" /> ಅನ್ನು ತಲುಪಲು ಪ್ರಯತ್ನಿಸಿರುವಿರಿ, ಆದರೆ ಸರ್ವರ್ ಅಮಾನ್ಯ ಪ್ರಮಾಣಪತ್ರವನ್ನು ನೀಡಿದೆ.</translation>
<translation id="9050666287014529139">ಪಾಸ್‌ಫ್ರೇಸ್</translation>
<translation id="9065203028668620118">ಎಡಿಟ್</translation>
-<translation id="9068849894565669697">ಬಣ್ಣವನ್ನು ಆಯ್ಕೆಮಾಡಿ</translation>
<translation id="9069693763241529744">ವಿಸ್ತರಣೆಯ ಮೂಲಕ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ</translation>
<translation id="9076283476770535406">ಇದು ಪ್ರಬುದ್ಧ ವಿಷಯವನ್ನು ಹೊಂದಿರಬಹುದು</translation>
<translation id="9078964945751709336">ಇನ್ನಷ್ಟು ಮಾಹಿತಿಯ ಅಗತ್ಯವಿದೆ</translation>
+<translation id="9080712759204168376">ಆರ್ಡರ್ ಸಾರಾಂಶ</translation>
<translation id="9103872766612412690"><ph name="SITE" /> ಸಾಮಾನ್ಯವಾಗಿ ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸಂರಕ್ಷಿಸಲು ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಪ್ರಯೋಜನವನ್ನು ಬಳಸಿಕೊಳ್ಳುತ್ತದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ Chromium <ph name="SITE" /> ವೆಬ್‌ಸೈಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ಆ ವೆಬ್‌ಸೈಟ್‌‌ ಅಸಹಜ ಮತ್ತು ತಪ್ಪು ರುಜುವಾತುಗಳನ್ನು ಹಿಂತಿರುಗಿಸಿದೆ. ದಾಳಿಕೋರರು <ph name="SITE" /> ರೂಪದಲ್ಲಿ ಸೋಗು ಹಾಕಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವಾಗ ಅಥವಾ ವೈ-ಫೈ ಸೈನ್-ಇನ್ ಪರದೆಯು ಸಂಪರ್ಕಕ್ಕೆ ಅಡ್ಡಿಯುಂಟು ಮಾಡಿದಾಗ ಇದು ಕಂಡುಬರಬಹುದು. ಯಾವುದೇ ಡೇಟಾವನ್ನು ವಿನಿಮಯ ಮಾಡಿಕೊಳ್ಳುವ ಮೊದಲೇ Chromium ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿರುವ ಕಾರಣ, ನಿಮ್ಮ ಮಾಹಿತಿ ಈಗಲೂ ಸುರಕ್ಷಿತವಾಗಿದೆ.</translation>
+<translation id="9106062320799175032">ಬಿಲ್ಲಿಂಗ್ ವಿಳಾಸವನ್ನು ಸೇರಿಸಿ</translation>
+<translation id="910908805481542201">ಇದನ್ನು ಸರಿಪಡಿಸಲು ನನಗೆ ಸಹಾಯ ಮಾಡಿ</translation>
+<translation id="9128870381267983090">ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸು</translation>
<translation id="9137013805542155359">ಮೂಲವನ್ನು ತೋರಿಸಿ</translation>
<translation id="9137248913990643158">ಈ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸುವ ಮೊದಲು Chrome ಪ್ರಾರಂಭಿಸಿ ಮತ್ತು ಸೈನ್ ಇನ್ ಮಾಡಿ.</translation>
<translation id="9148507642005240123">&amp;ಸಂಪಾದಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
@@ -973,6 +1013,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ಬೆಂಬಲಿತವಲ್ಲದ ಪ್ರೋಟೋಕಾಲ್ ಬಳಸುತ್ತಿದೆ.</translation>
<translation id="9205078245616868884">ನಿಮ್ಮ ಡೇಟಾವನ್ನು ನಿಮ್ಮ ಸಿಂಕ್ ಪಾಸ್‌ಫ್ರೇಸ್‌ನೊಂದಿಗೆ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ. ಸಿಂಕ್ ಪ್ರಾರಂಭಿಸಲು ಅದನ್ನು ನಮೂದಿಸಿ.</translation>
<translation id="9207861905230894330">ಲೇಖನವನ್ನು ಸೇರಿಸಲು ವಿಫಲವಾಗಿದೆ.</translation>
+<translation id="9215416866750762878">ಈ ಸೈಟ್‌ಗೆ ಸುರಕ್ಷಿತವಾಗಿ ಸಂಪರ್ಕಿಸುವ Chromeನ ಕಾರ್ಯವನ್ನು ಅಪ್ಲಿಕೇಶನ್‌ ಸ್ಥಗಿತಗೊಳಿಸಿದೆ</translation>
<translation id="9219103736887031265">ಚಿತ್ರಗಳು</translation>
<translation id="933612690413056017">ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -982,5 +1023,7 @@
<translation id="975560348586398090">{COUNT,plural, =0{ಯಾವುದೂ ಇಲ್ಲ}=1{1 ಐಟಂ}one{# ಐಟಂಗಳು}other{# ಐಟಂಗಳು}}</translation>
<translation id="981121421437150478">ಆಫ್‌ಲೈನ್</translation>
<translation id="988159990683914416">ಡೆವಲಪರ್ ಬಿಲ್ಡ್</translation>
+<translation id="989988560359834682">ವಿಳಾಸವನ್ನು ಎಡಿಟ್ ಮಾಡಿ</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್ ಅಥವಾ ನೆಟ್‌ವರ್ಕ್‌ನಲ್ಲಿ ಸರಿಯಾಗಿ ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿಲ್ಲ: &lt;ul&gt; &lt;li&gt;"<ph name="SOFTWARE_NAME" />" ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಪ್ರಯತ್ನಿಸಿ&lt;/li&gt; &lt;li&gt;ಇನ್ನೊಂದು ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಸಿಲು ಪ್ರಯತ್ನಿಸಿ &lt;/li&gt; &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index ecf93f068db..e19d5138ab9 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">데스크톱 북마크</translation>
<translation id="1074497978438210769">안전하지 않음</translation>
<translation id="1080116354587839789">너비에 맞춤</translation>
+<translation id="1088860948719068836">카드 명의 추가</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> 항상 번역</translation>
+<translation id="1103778128462718200">저장된 비밀번호 모두 표시...</translation>
<translation id="1107591249535594099">선택하면 Chrome에서 양식을 더 빠르게 입력할 수 있도록 이 기기에 카드 사본을 저장합니다.</translation>
<translation id="1111153019813902504">최근 북마크</translation>
<translation id="1113869188872983271">재정렬 실행 취소(&amp;U)</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" />(동기화됨)</translation>
<translation id="1263231323834454256">읽기 목록</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />에 캡처된 비정상 종료 보고서(아직 업로드 또는 무시되지 않음)</translation>
+<translation id="1270502636509132238">픽업 방법</translation>
<translation id="1281526147609854549">발급 기관: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">이 사이트 번역 안함</translation>
<translation id="129553762522093515">최근에 닫은 탭</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">연결 대기 중...</translation>
<translation id="153384715582417236">새 콘텐츠가 없습니다.</translation>
<translation id="1549470594296187301">이 기능을 이용하려면 자바스크립트를 사용하도록 설정해야 합니다.</translation>
-<translation id="1555130319947370107">파란색</translation>
<translation id="1559528461873125649">해당 파일이나 디렉토리가 없습니다.</translation>
<translation id="1583429793053364125">이 웹페이지를 표시하는 도중 문제가 발생했습니다.</translation>
<translation id="1592005682883173041">로컬 데이터 액세스</translation>
<translation id="1594030484168838125">선택</translation>
-<translation id="161042844686301425">청록색</translation>
<translation id="1620510694547887537">카메라</translation>
<translation id="1629803312968146339">Chrome에서 이 카드를 저장하도록 하시겠습니까?</translation>
<translation id="1639239467298939599">로드 중</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">이 사이트를 방문하려면 <ph name="NAME" />님으로부터 권한을 받아야 합니다.</translation>
<translation id="1721424275792716183">* 필수 입력란</translation>
+<translation id="1727741090716970331">유효한 카드 번호 추가</translation>
<translation id="1728677426644403582">웹페이지 소스를 보는 중</translation>
<translation id="173080396488393970">이 유형의 카드는 지원되지 않습니다.</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">일련화 오류</translation>
<translation id="1974060860693918893">고급</translation>
<translation id="1978555033938440688">펌웨어 버전</translation>
-<translation id="1995859865337580572">CVC를 인증하세요.</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{외 1개}other{외 #개}}</translation>
<translation id="2025186561304664664">프록시가 자동 설정되도록 지정됩니다.</translation>
<translation id="2030481566774242610"><ph name="LINK" />을(를) 찾으셨나요?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">실행취소</translation>
<translation id="20817612488360358">시스템 프록시 설정이 사용하도록 설정되었지만 명시적 프록시 설정도 지정되어 있습니다.</translation>
<translation id="2086652334978798447">Google에서 추천한 맞춤설정 콘텐츠를 받으려면 Chrome에 로그인합니다.</translation>
+<translation id="2091887806945687916">소리</translation>
<translation id="2094505752054353250">도메인이 일치하지 않음</translation>
<translation id="2096368010154057602">자치구</translation>
<translation id="2108755909498034140">컴퓨터 다시 시작</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"><ph name="POLICY_NAME" />이(가) 우선 적용되었기 때문에 무시됩니다.</translation>
<translation id="2138201775715568214">주변 피지컬 웹페이지 검색 중</translation>
<translation id="213826338245044447">모바일 북마크</translation>
+<translation id="214556005048008348">결제 취소</translation>
<translation id="2147827593068025794">백그라운드 동기화</translation>
+<translation id="2148613324460538318">카드 추가</translation>
<translation id="2154054054215849342">도메인에 대해 동기화를 사용할 수 없습니다.</translation>
<translation id="2154484045852737596">카드 수정</translation>
<translation id="2166049586286450108">전체 관리자 액세스</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{주소 1개}other{주소 #개}}</translation>
<translation id="2187317261103489799">감지(기본값)</translation>
<translation id="2202020181578195191">올바른 만료 연도를 입력하세요.</translation>
+<translation id="2209523182407020534">이 오류를 일으키는 애플리케이션에는 바이러스 백신, 방화벽, 웹 필터링 또는 프록시 소프트웨어 등이 있습니다.</translation>
<translation id="2212735316055980242">정책을 찾을 수 없음</translation>
<translation id="2213606439339815911">항목을 가져오는 중...</translation>
<translation id="2218879909401188352">현재 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />에 있는 공격자는 기기를 손상시키거나, 모바일 요금에 몰래 추가 요금을 부과하거나, 개인정보를 도용하는 위험한 앱을 설치할 수도 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />자세히 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">뒤로 이동</translation>
<translation id="2503184589641749290">사용 가능한 직불카드 및 선불카드</translation>
<translation id="2515629240566999685">현재 지역의 신호 확인</translation>
+<translation id="2524461107774643265">자세한 정보 추가</translation>
+<translation id="2536110899380797252">주소 추가</translation>
<translation id="2539524384386349900">감지</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" />에서 잘못된 응답을 전송했습니다.</translation>
<translation id="2556876185419854533">수정 실행 취소(&amp;U)</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">현재 Chromium에서 카드를 확인할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
<translation id="2705137772291741111">사이트의 저장된(캐시된) 사본을 읽을 수 없습니다.</translation>
<translation id="2709516037105925701">자동완성</translation>
+<translation id="2710942282213947212">컴퓨터에 설치된 소프트웨어로 인해 Chromium이 안전하게 웹에 접속할 수 없음</translation>
<translation id="2712173769900027643">권한 요청</translation>
-<translation id="2713444072780614174">흰색</translation>
<translation id="2720342946869265578">근처</translation>
<translation id="2721148159707890343">요청 성공</translation>
<translation id="2728127805433021124">서버의 인증서가 안전성이 낮은 서명 알고리즘을 사용하여 서명되어 있습니다.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">네트워크 변경이 감지되었습니다.</translation>
<translation id="2916038427272391327">다른 프로그램 닫기</translation>
<translation id="2922350208395188000">서버 인증서를 확인할 수 없습니다.</translation>
+<translation id="2925673989565098301">배달 방법</translation>
<translation id="2928905813689894207">청구서 수신 주소</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />개}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />개}}</translation>
<translation id="2941952326391522266">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 서버의 보안 인증서가 <ph name="DOMAIN2" />에서 제공한 것입니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">잘못된 정책 유형</translation>
<translation id="3032412215588512954">이 사이트를 새로고침하시겠습니까?</translation>
<translation id="3037605927509011580">앗, 이런!</translation>
+<translation id="3039538478787849737">카드를 Google에 저장하시겠어요?</translation>
<translation id="3041612393474885105">인증서 정보</translation>
<translation id="3063697135517575841">현재 Chrome에서 카드를 확인할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
<translation id="3064966200440839136">시크릿 모드를 종료하고 외부 애플리케이션에서 결제합니다. 계속하시겠습니까?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">일시적인 서버 오류</translation>
<translation id="3154506275960390542">이 페이지에 포함된 양식은 안전하게 제출되지 않을 수 있습니다. 전송되는 데이터는 전송 중에 다른 사람이 볼 수 있으며 서버에서 수신하는 데이터를 변경하기 위해 공격자가 수정할 수 있습니다.</translation>
<translation id="3157931365184549694">복구</translation>
+<translation id="3162559335345991374">사용 중인 Wi-Fi에서 로그인 페이지 방문을 요청할 수 있습니다.</translation>
<translation id="3167968892399408617">시크릿 탭을 모두 닫으면 시크릿 탭에서 보는 페이지는 브라우저의 방문 기록, 쿠키 저장소, 검색 기록 어디에도 남지 않습니다. 단, 다운로드한 파일이나 생성한 북마크는 유지됩니다.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">섬</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">결제 취소</translation>
<translation id="3207960819495026254">북마크됨</translation>
+<translation id="3211223744486044430">이후에 더 빠르게 결제할 수 있도록 Google 계정과 이 기기에 카드를 저장하세요.</translation>
<translation id="3225919329040284222">서버가 내장된 기대치와 일치하지 않는 인증서를 전달했습니다. 이러한 기대치는 사용자를 보호하기 위해 보안이 엄격한 특정 웹사이트에 포함됩니다.</translation>
<translation id="3226128629678568754">페이지 로드에 필요한 데이터를 다시 제출하려면 새로고침 버튼을 누릅니다.</translation>
<translation id="3227137524299004712">마이크</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">검색결과 없음</translation>
<translation id="3305707030755673451"><ph name="TIME" />에 동기화 암호로 데이터가 암호화되었습니다. 동기화를 시작하려면 입력하세요.</translation>
<translation id="3320021301628644560">청구지 주소 추가</translation>
-<translation id="3329013043687509092">채도</translation>
<translation id="333371639341676808">이 페이지가 추가적인 대화를 생성하지 않도록 차단합니다.</translation>
<translation id="3338095232262050444">안전함</translation>
<translation id="3340978935015468852">설정</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">클라이언트 ID:</translation>
<translation id="3391030046425686457">배송지 주소</translation>
<translation id="3395827396354264108">수령 방법</translation>
+<translation id="3399952811970034796">배달 주소</translation>
<translation id="3422248202833853650">다른 프로그램을 종료하여 메모리를 확보하세요.</translation>
<translation id="3422472998109090673">현재 <ph name="HOST_NAME" />에 연결할 수 없습니다.</translation>
<translation id="3427092606871434483">허용(기본값)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" />에 캡처된 비정상 종료 보고서가 <ph name="UPLOAD_TIME" />에 업로드됨</translation>
<translation id="3681007416295224113">인증서 정보</translation>
<translation id="3690164694835360974">로그인이 안전하지 않음</translation>
+<translation id="3704162925118123524">사용 중인 네트워크에서 로그인 페이지 방문을 요청할 수 있습니다.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">로드 중...</translation>
<translation id="3712624925041724820">라이선스 만료됨</translation>
<translation id="3714780639079136834">모바일 데이터 또는 Wi-Fi 사용 설정</translation>
+<translation id="3715597595485130451">Wi-Fi 연결</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />프록시, 방화벽, DNS 설정 확인<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">보안 관련 위험을 이해한다면 위험한 프로그램이 삭제되기 전에 <ph name="BEGIN_LINK" />안전하지 않은 사이트<ph name="END_LINK" />에 방문해도 됩니다.</translation>
<translation id="3739623965217189342">복사한 링크</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">추가 실행 취소(&amp;U)</translation>
<translation id="404928562651467259">경고</translation>
<translation id="4058922952496707368">'<ph name="SUBKEY" />' 키: <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">유효한 주소 추가</translation>
<translation id="4072486802667267160">주문을 처리하는 중에 오류가 발생했습니다. 다시 시도하세요.</translation>
<translation id="4075732493274867456">클라이언트와 서버가 일반적인 SSL 프로토콜 버전 또는 암호화 제품군을 지원하지 않습니다.</translation>
<translation id="4079302484614802869">프록시 설정이 고정 프록시 서버가 아닌 .pac 스크립트 URL을 사용하도록 설정됩니다.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">기기 일련번호가 잘못됨</translation>
<translation id="410351446219883937">자동재생</translation>
<translation id="4103763322291513355">차단된 URL 및 시스템 관리자가 설정한 기타 정책 목록을 확인하려면 &lt;strong&gt;chrome://policy&lt;/strong&gt;를 방문하세요.</translation>
-<translation id="4115378294792113321">자홍색</translation>
<translation id="4116663294526079822">이 사이트에서 항상 허용</translation>
<translation id="4117700440116928470">지원되지 않는 정책 범위입니다.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{외 1개}other{외 #개}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" />에 접속하려 했으나 발행기관에서 서버가 전달한 인증서를 폐기했습니다. 이는 서버가 제시한 보안 자격증명 정보를 신뢰할 수 없음을 의미합니다. 사용자는 현재 공격자와 통신 중일 수도 있습니다.</translation>
<translation id="4394049700291259645">사용 중지</translation>
<translation id="4406896451731180161">검색결과</translation>
+<translation id="4415426530740016218">픽업 주소</translation>
<translation id="4424024547088906515">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 Chrome에서 신뢰하는 보안 인증서가 아닙니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />에서 로그인 인증서를 승인하지 않았거나 로그인 인증서가 제공되지 않았을 수 있습니다.</translation>
<translation id="443673843213245140">프록시 사용은 중지되었지만 명시적 프록시 설정이 지정되어 있습니다.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">확장 프로그램 사용 중지해 보기</translation>
<translation id="457875822857220463">배송</translation>
+<translation id="4582800630050655161">Google 계정에 액세스할 수 없게 되거나 신원 도용이 발생할 수도 있습니다. 따라서 지금 비밀번호를 변경하는 것이 좋습니다.</translation>
<translation id="4587425331216688090">Chrome에서 주소를 삭제하시겠습니까?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" />에 대한 연결은 최신 암호화 기술을 사용하여 암호화됩니다.</translation>
<translation id="4594403342090139922">삭제 실행 취소(&amp;U)</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 서버의 보안 인증서에 오류가 있습니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
<translation id="4690462567478992370">유효하지 않은 인증서 사용 중단</translation>
+<translation id="4690954380545377795">Google 계정에 액세스할 수 없게 되거나 신원 도용이 발생할 수도 있습니다. 따라서 지금 비밀번호를 변경하는 것이 좋습니다.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">연결이 끊김</translation>
<translation id="471880041731876836">이 사이트에 방문할 수 있는 권한이 없습니다.</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows 네트워크 진단 프로그램 실행<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">내 결제</translation>
<translation id="4726672564094551039">정책 새로고침</translation>
<translation id="4728558894243024398">플랫폼</translation>
<translation id="4736825316280949806">Chromium 다시 시작</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">보조 기억 장치 상태가 잘못됨</translation>
<translation id="5023310440958281426">관리자 정책을 확인하세요.</translation>
<translation id="5029568752722684782">사본 지우기</translation>
+<translation id="503069730517007720">'<ph name="SOFTWARE_NAME" />'의 루트 인증서가 필요하지만 설치되어 있지 않습니다. IT 관리자가 '<ph name="SOFTWARE_NAME" />'의 설정 안내에 따라 이 문제를 해결해야 합니다. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google 번역 정보</translation>
<translation id="5039804452771397117">허용</translation>
<translation id="5040262127954254034">개인정보</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">실험실 기능</translation>
<translation id="5205222826937269299">이름은 필수입니다.</translation>
<translation id="5222812217790122047">이메일은 필수입니다.</translation>
+<translation id="522700295135997067">이 사이트에서 비밀번호를 도용했을 수 있음</translation>
+<translation id="5230733896359313003">배송지 주소</translation>
<translation id="5251803541071282808">클라우드</translation>
<translation id="5277279256032773186">직장에서 Chrome을 사용하시나요? 기업은 직원의 Chrome 설정을 관리할 수 있습니다. 자세히 알아보기</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />소프트웨어를 일시적으로 사용 중지하여 웹에 접속하려면 다음 단계를 따르세요. 관리자 권한이 필요합니다.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">이 사이트에 대한 연결은 비공개가 아닙니다. 언제든지 VR 모드를 종료하려면 헤드셋을 제거한 후 뒤로를 누르세요.</translation>
<translation id="5299298092464848405">정책을 파싱하는 중 오류 발생</translation>
+<translation id="5308380583665731573">연결</translation>
<translation id="5308689395849655368">비정상 종료 보고가 사용 중지되었습니다.</translation>
<translation id="5317780077021120954">저장</translation>
<translation id="5327248766486351172">이름</translation>
+<translation id="5332219387342487447">배송 방법</translation>
<translation id="5355557959165512791">인증서가 취소되었기 때문에 현재 <ph name="SITE" />에 방문할 수 없습니다. 네트워크 오류와 공격은 대부분 일시적이므로 나중에 이 페이지가 정상적으로 작동할 수 있습니다.</translation>
<translation id="536296301121032821">정책 설정 저장 실패</translation>
<translation id="5386426401304769735">이 사이트의 인증서 체인은 SHA-1을 사용하여 서명된 인증서를 포함합니다.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">회사, 조직, 학교 인트라넷의 해당 사이트가 외부 웹사이트와 동일한 URL을 갖고 있습니다.
<ph name="LINE_BREAK" />
시스템 관리자에게 문의하세요.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" />의 보안 코드를 입력하세요. 이 코드는 저장되지 않습니다.</translation>
<translation id="5509780412636533143">관리 북마크</translation>
<translation id="5510766032865166053">이동되었거나 삭제되었을 수 있습니다.</translation>
<translation id="5523118979700054094">정책 이름</translation>
<translation id="552553974213252141">텍스트가 올바로 추출되었습니까?</translation>
<translation id="5540224163453853">요청한 글을 찾지 못했습니다.</translation>
+<translation id="5541546772353173584">이메일 추가</translation>
<translation id="5544037170328430102"><ph name="SITE" />에 삽입된 페이지 내용:</translation>
+<translation id="5545756402275714221">추천 기사</translation>
<translation id="5556459405103347317">새로고침</translation>
<translation id="5560088892362098740">만료일</translation>
<translation id="5565735124758917034">활성</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">이메일</translation>
<translation id="5669703222995421982">내게 맞는 콘텐츠 추천 받기</translation>
<translation id="5675650730144413517">페이지가 작동하지 않습니다.</translation>
+<translation id="5689199277474810259">JSON 형식으로 내보내기</translation>
<translation id="5710435578057952990">이 웹사이트의 주소가 확인되지 않았습니다.</translation>
<translation id="5719499550583120431">선불카드를 사용할 수 있습니다.</translation>
<translation id="5720705177508910913">현재 사용자</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" />에 대한 연결이 더 이상 사용되지 않는 암호화 기술을 사용하여 암호화됩니다.</translation>
<translation id="5813119285467412249">추가 다시 실행(&amp;R)</translation>
<translation id="5838278095973806738">공격자에 의해 도난당할 수 있으므로 이 사이트에 비밀번호나 신용카드 등 민감한 정보를 입력해서는 안 됩니다.</translation>
+<translation id="5866257070973731571">전화번호 추가</translation>
<translation id="5869405914158311789">사이트에 연결할 수 없음</translation>
<translation id="5869522115854928033">저장된 비밀번호</translation>
<translation id="5872918882028971132">상위 추천</translation>
<translation id="5893752035575986141">신용카드를 사용할 수 있습니다.</translation>
-<translation id="5901630391730855834">노란색</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(동기화됨)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1개 사용 중}other{#개 사용 중}}</translation>
<translation id="5959728338436674663">위험한 앱과 사이트를 감지할 수 있도록 일부 <ph name="BEGIN_WHITEPAPER_LINK" />시스템 정보와 페이지 콘텐츠<ph name="END_WHITEPAPER_LINK" />를 Google로 자동 전송합니다. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">연락처 정보 수정</translation>
<translation id="5967867314010545767">기록에서 삭제</translation>
<translation id="5975083100439434680">축소</translation>
+<translation id="597552863672748783">보안 코드 확인</translation>
<translation id="598637245381783098">결제 앱을 열 수 없습니다.</translation>
<translation id="5989320800837274978">고정 프록시 서버와 .pac 스크립트 URL이 모두 지정되지 않았습니다.</translation>
<translation id="5990559369517809815">서버에 대한 요청이 확장 프로그램에 의해 차단되었습니다.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1페이지}other{#페이지}}</translation>
-<translation id="6017514345406065928">녹색</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" />(동기화됨)</translation>
<translation id="6027201098523975773">이름을 입력하세요.</translation>
<translation id="6040143037577758943">닫기</translation>
-<translation id="6042308850641462728">더보기</translation>
<translation id="6047233362582046994">유해한 앱이 삭제되기 전에 <ph name="BEGIN_LINK" />이 사이트를 방문<ph name="END_LINK" />하는 경우 보안상 위험을 반드시 이해하시기 바랍니다.</translation>
<translation id="6047927260846328439">이 콘텐츠는 사용자를 속여 소프트웨어를 설치하거나 개인정보를 유출할 수도 있습니다. <ph name="BEGIN_LINK" />표시하기<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">현재 <ph name="SITE" />에서 인증서 고정을 사용하기 때문에 방문할 수 없습니다. 네트워크 오류와 공격은 대부분 일시적이므로 나중에 이 페이지가 정상적으로 작동할 수 있습니다.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">확장 프로그램 페이지를 보는 중</translation>
<translation id="6596325263575161958">암호화 옵션</translation>
<translation id="662080504995468778">머무르기</translation>
+<translation id="6624427990725312378">연락처 정보</translation>
<translation id="6626291197371920147">유효한 카드 번호 추가</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> 검색</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />의 공격자가 사용자 정보(예: 사진, 비밀번호, 메시지, 신용카드)를 도용하거나 삭제하는 위험한 프로그램을 Mac에 설치하려고 시도할 수 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />자세히 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">이전</translation>
<translation id="6710594484020273272">&lt;검색어 입력&gt;</translation>
<translation id="6711464428925977395">프록시 서버에 문제가 발생했거나 주소가 잘못되었습니다.</translation>
-<translation id="6727102863431372879">설정</translation>
<translation id="674375294223700098">알 수 없는 서버 인증서 오류입니다.</translation>
<translation id="6753269504797312559">정책 값</translation>
<translation id="6757797048963528358">기기가 절전 모드 상태입니다.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">프로필 경로</translation>
<translation id="7424977062513257142">이 웹페이지에 삽입된 페이지 내용:</translation>
+<translation id="7437289804838430631">연락처 정보 추가</translation>
<translation id="7441627299479586546">잘못된 정책 주체</translation>
<translation id="7444046173054089907">차단된 사이트</translation>
<translation id="7445762425076701745">연결하려는 서버 ID를 확인할 수 없습니다. 외부 인증 기관에서 소유권을 확인할 수 없으므로 네트워크에서 유효한 이름을 사용하여 서버에 연결됩니다. 일부 인증 기관에서는 이러한 이름에 대해 관계없이 인증서를 발급하기 때문에 공격자가 아니라 의도한 웹사이트에 연결되어 있는지 확인할 수 없습니다.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">앞으로</translation>
<translation id="7485870689360869515">데이터 없음</translation>
<translation id="7508255263130623398">반환된 정책 기기 ID가 비었거나 현재 기기 ID와 일치하지 않음</translation>
+<translation id="7511955381719512146">사용 중인 Wi-Fi에서 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> 방문을 요청할 수 있습니다.</translation>
<translation id="7514365320538308">다운로드</translation>
<translation id="7518003948725431193">다음 웹 주소(<ph name="URL" />)에 대해 발견된 웹페이지가 없습니다.</translation>
<translation id="7521387064766892559">자바스크립트</translation>
<translation id="7526934274050461096">이 사이트로의 연결은 비공개가 아닙니다.</translation>
-<translation id="7535087603100972091">값</translation>
<translation id="7537536606612762813">필수</translation>
<translation id="7542403920425041731">확인하면 카드 세부정보가 이 사이트와 공유됩니다.</translation>
<translation id="7542995811387359312">양식에 보안 연결이 사용되지 않아 신용카드 자동 채우기가 사용 중지되었습니다.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 서버의 보안 인증서가 부정한 방식으로 발행되었을 수 있습니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
<translation id="7568593326407688803">이 페이지는<ph name="ORIGINAL_LANGUAGE" />로 되어 있습니다. 번역하시겠습니까?</translation>
<translation id="7569952961197462199">Chrome에서 신용카드를 삭제하시겠습니까?</translation>
-<translation id="7569983096843329377">검정색</translation>
<translation id="7578104083680115302">Google에 저장한 카드를 사용하여 어떤 기기에서든지 사이트 및 앱에서 빠르게 지불할 수 있습니다.</translation>
<translation id="7588950540487816470">피지컬 웹</translation>
<translation id="7592362899630581445">서버의 인증서가 이름 제약 조건을 위반합니다.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">이 사이트의 공격자가 인터넷 사용 환경에 악영향을 미치는 프로그램을 설치하도록 속임수(예를 들어, 방문하는 사이트의 홈페이지를 변경하거나 추가로 광고를 표시)를 시도할 수 있습니다.</translation>
<translation id="7674629440242451245">Chrome의 멋진 새 기능에 관심이 있으십니까? chrome.com/dev 페이지에서 개발자 채널에 방문해 보세요.</translation>
<translation id="7682287625158474539">배송</translation>
+<translation id="7699293099605015246">지금은 기사를 가져올 수 없음</translation>
<translation id="7701040980221191251">없음</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" />(안전하지 않음)<ph name="END_LINK" />(으)로 이동</translation>
<translation id="7714464543167945231">인증서</translation>
<translation id="7716147886133743102">관리자가 차단함</translation>
<translation id="7716424297397655342">이 사이트를 캐시에서 로드할 수 없음</translation>
+<translation id="7723047071702270851">카드 수정</translation>
<translation id="774634243536837715">위험한 콘텐츠 차단됨</translation>
<translation id="7752995774971033316">관리되지 않음</translation>
<translation id="7755287808199759310">부모님이 차단 해제할 수 있습니다.</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">주소 추가</translation>
<translation id="777702478322588152">도</translation>
<translation id="7791543448312431591">추가</translation>
+<translation id="7793553086574152071">이후에 더 빠르게 결제할 수 있도록 Google 계정에 카드를 저장하세요.</translation>
<translation id="7793809570500803535"><ph name="SITE" />의 웹페이지가 일시적으로 다운되었거나 새 웹 주소로 완전히 이동했을 수 있습니다.</translation>
<translation id="7800304661137206267">메시지 인증(<ph name="MAC" />)과 키 교환 메커니즘(<ph name="KX" />)을 설정하고 <ph name="CIPHER" />을(를) 사용하여 연결이 암호화되어 있습니다.</translation>
+<translation id="7802523362929240268">정상적인 사이트</translation>
<translation id="780301667611848630">아니요, 괜찮습니다.</translation>
<translation id="7805768142964895445">상태</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome에서 추천검색어를 삭제하시겠습니까?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'에 대해 <ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" />개의 검색 결과를 찾았습니다.</translation>
+<translation id="782886543891417279">사용 중인 Wi-Fi(<ph name="WIFI_NAME" />)에서 로그인 페이지 방문을 요청할 수 있습니다.</translation>
<translation id="785549533363645510">하지만 흔적이 아예 남지 않는 것은 아닙니다. 시크릿 모드로 탐색해도 회사, 인터넷 서비스 제공업체 또는 방문한 웹사이트에 저장된 흔적까지 없앨 수는 없습니다.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">직불카드 및 선불카드를 사용할 수 있습니다.</translation>
+<translation id="7878562273885520351">비밀번호가 도용될 수도 있음</translation>
<translation id="7887683347370398519">CVC를 확인한 후 다시 시도하세요.</translation>
<translation id="79338296614623784">올바른 전화번호를 입력하세요.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">서버 인증서가 유효하지 않습니다.</translation>
-<translation id="7942349550061667556">빨간색</translation>
<translation id="7947285636476623132">유효기간 연도를 확인한 후 다시 시도해 주세요.</translation>
<translation id="7951415247503192394">(32비트)</translation>
<translation id="7956713633345437162">모바일 북마크</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">요청(기본값)</translation>
<translation id="8041089156583427627">의견 보내기</translation>
<translation id="8041940743680923270">전체 기본값 사용(요청)</translation>
+<translation id="8057711352706143257">'<ph name="SOFTWARE_NAME" />이(가) 올바르게 설정되지 않았습니다. 일반적으로 '<ph name="SOFTWARE_NAME" />'을(를) 제거하면 문제가 해결됩니다. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">글을 조회하지 못했습니다.</translation>
<translation id="8091372947890762290">활성화 요청이 서버에서 대기 중</translation>
+<translation id="8094917007353911263">사용 중인 네트워크에서 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> 방문을 요청할 수 있습니다.</translation>
+<translation id="8103161714697287722">결제 수단</translation>
<translation id="8118489163946903409">결제 수단</translation>
+<translation id="8127301229239896662">'<ph name="SOFTWARE_NAME" />'이(가) 컴퓨터 또는 네트워크에 제대로 설치되지 않았습니다. IT 관리자에게 문제 해결을 요청해 보세요.</translation>
<translation id="8131740175452115882">확인</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />의 서버 <ph name="BEGIN_ABBR" />DNS 주소<ph name="END_ABBR" />를 찾을 수 없습니다.</translation>
<translation id="8149426793427495338">컴퓨터가 절전 모드 상태입니다.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">잘 모르는 경우 네트워크 관리자에게 문의하시기 바랍니다.</translation>
<translation id="8293206222192510085">북마크 추가</translation>
<translation id="8294431847097064396">출처</translation>
+<translation id="8298115750975731693">사용 중인 Wi-Fi(<ph name="WIFI_NAME" />)에서 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> 방문을 요청할 수 있습니다.</translation>
<translation id="8306404619377842860">기기의 날짜와 시간(<ph name="DATE_AND_TIME" />)이 잘못되었으므로 <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />에 비공개로 연결할 수 없습니다. <ph name="BEGIN_LEARN_MORE_LINK" />자세히 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">네트워크 연결 문제로 인해 번역에 실패했습니다.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />에 대한 액세스가 거부됨</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">최근에 닫은 탭</translation>
<translation id="8874824191258364635">올바른 카드 번호를 입력하세요.</translation>
<translation id="8876793034577346603">네트워크 설정을 파싱하지 못했습니다.</translation>
-<translation id="8889402386540077796">색조</translation>
<translation id="8891727572606052622">프록시 모드가 잘못되었습니다.</translation>
<translation id="889901481107108152">죄송합니다. 현재 플랫폼에서 사용할 수 없는 실험실 기능입니다.</translation>
<translation id="8903921497873541725">확대</translation>
<translation id="8931333241327730545">이 카드를 Google 계정에 저장하시겠습니까?</translation>
<translation id="8932102934695377596">시간이 너무 먼 과거로 설정되어 있습니다.</translation>
+<translation id="893332455753468063">이름 추가</translation>
<translation id="8938939909778640821">사용 가능한 신용카드 및 선불카드</translation>
+<translation id="8957210676456822347">캡티브 포털 승인</translation>
<translation id="8971063699422889582">서버 인증서가 만료되었습니다.</translation>
-<translation id="8986494364107987395">사용 통계 및 비정상 종료 보고서를 Google에 자동으로 보내기</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">방문하려는 사이트에 유해한 프로그램이 있습니다.</translation>
<translation id="8997023839087525404">서버에서 인증서 투명성 정책을 사용하여 공개되지 않은 인증서를 제시했습니다. 인증서 투명성 정책은 인증서가 신뢰할 수 있으며 공격자로부터 사용자를 보호하고 있음을 보장하기 위한 것으로 일부 인증서의 경우 필수사항입니다.</translation>
<translation id="9001074447101275817">프록시 <ph name="DOMAIN" />에 사용자 이름 및 비밀번호를 입력해야 합니다.</translation>
<translation id="9005998258318286617">PDF 문서를 로드하지 못했습니다.</translation>
+<translation id="9008201768610948239">무시</translation>
<translation id="901974403500617787">시스템 전체에 적용되는 플래그는 소유자(<ph name="OWNER_EMAIL" />)만 설정할 수 있습니다.</translation>
<translation id="9020200922353704812">카드 청구서 수신 주소가 필요함</translation>
<translation id="9020542370529661692">이 페이지는 <ph name="TARGET_LANGUAGE" />로 번역되었습니다.</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619"><ph name="DOMAIN" />에 접속하려 했지만 서버가 잘못된 인증서를 전달했습니다.</translation>
<translation id="9050666287014529139">암호</translation>
<translation id="9065203028668620118">수정</translation>
-<translation id="9068849894565669697">색상 선택</translation>
<translation id="9069693763241529744">확장 프로그램에서 차단함</translation>
<translation id="9076283476770535406">성인용 콘텐츠가 포함되어 있을 수 있습니다.</translation>
<translation id="9078964945751709336">자세한 정보 필요</translation>
+<translation id="9080712759204168376">주문 요약</translation>
<translation id="9103872766612412690"><ph name="SITE" />에서는 사용자 정보를 보호하기 위해 일반적으로 암호화를 사용합니다. 이번에 Chromium에서 <ph name="SITE" />에 연결을 시도했을 때 웹사이트에서 비정상적이고 잘못된 사용자 인증 정보를 반환했습니다. 이는 공격자가 <ph name="SITE" />인 것처럼 가장하려고 하거나 Wi-Fi 로그인 화면이 연결을 방해했기 때문일 수 있습니다. 데이터 교환이 발생하기 전에 Chromium에서 연결을 중단했으므로 사용자 정보는 안전합니다.</translation>
+<translation id="9106062320799175032">청구서 주소 추가</translation>
+<translation id="910908805481542201">이 문제 해결에 도움을 주세요.</translation>
+<translation id="9128870381267983090">네트워크에 연결</translation>
<translation id="9137013805542155359">원본 보기</translation>
<translation id="9137248913990643158">이 앱을 사용하기 전에 Chrome을 시작하고 로그인하세요.</translation>
<translation id="9148507642005240123">수정 실행 취소(&amp;U)</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" />에서 지원되지 않는 프로토콜을 사용합니다.</translation>
<translation id="9205078245616868884">동기화 암호로 데이터가 암호화되어 있습니다. 동기화를 시작하려면 입력하세요.</translation>
<translation id="9207861905230894330">글을 추가하지 못했습니다.</translation>
+<translation id="9215416866750762878">애플리케이션으로 인해 Chrome이 안전하게 이 사이트에 접속할 수 없음</translation>
<translation id="9219103736887031265">이미지</translation>
<translation id="933612690413056017">인터넷에 연결되지 않음</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{없음}=1{항목 1개}other{항목 #개}}</translation>
<translation id="981121421437150478">오프라인</translation>
<translation id="988159990683914416">개발자 빌드</translation>
+<translation id="989988560359834682">주소 수정</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">'<ph name="SOFTWARE_NAME" />'이(가) 컴퓨터 또는 네트워크에 제대로 설치되지 않았습니다.
+ &lt;ul&gt;
+ &lt;li&gt;'<ph name="SOFTWARE_NAME" />'을(를) 제거하거나 사용 중지해 보세요.&lt;/li&gt;
+ &lt;li&gt;다른 네트워크에 연결해 보세요.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index 82a7e6d142b..f8df39e846a 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Žymės staliniame kompiuteryje</translation>
<translation id="1074497978438210769">Nesaugi</translation>
<translation id="1080116354587839789">Pritaikyti pagal plotį</translation>
+<translation id="1088860948719068836">Kortelėje nurodytų vardo ir pavardės pridėjimas</translation>
<translation id="1103523840287552314">Visada versti <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Rodyti visus išsaugotus slaptažodžius...</translation>
<translation id="1107591249535594099">Jei pažymėta, „Chrome“ išsaugos kortelės kopiją įrenginyje, kad galėtumėte greičiau užpildyti formas.</translation>
<translation id="1111153019813902504">Naujausios žymės</translation>
<translation id="1113869188872983271">&amp;Anuliuoti pertvarkymą</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sinchronizuota)</translation>
<translation id="1263231323834454256">Skaitymo sąrašas</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> užfiksuota strigčių ataskaita (dar neįkelta ar nepaisoma)</translation>
+<translation id="1270502636509132238">Paėmimo metodas</translation>
<translation id="1281526147609854549">Išdavė „<ph name="ISSUER" />“</translation>
<translation id="1285320974508926690">Niekada neversti šios svetainės</translation>
<translation id="129553762522093515">Neseniai uždarytas</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Laukiama ryšio…</translation>
<translation id="153384715582417236">Kol kas tiek</translation>
<translation id="1549470594296187301">Norint naudoti šią funkciją, reikia įgalinti „JavaScript“.</translation>
-<translation id="1555130319947370107">Mėlyna</translation>
<translation id="1559528461873125649">Nėra tokio failo ar katalogo</translation>
<translation id="1583429793053364125">Rodant šį tinklalapį įvyko nenumatyta klaida.</translation>
<translation id="1592005682883173041">Prieiga prie vietinių duomenų</translation>
<translation id="1594030484168838125">Pasirinkti</translation>
-<translation id="161042844686301425">Žydra</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Ar norite, kad „Chrome“ išsaugotų šią kortelę?</translation>
<translation id="1639239467298939599">Įkeliama</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Turite gauti <ph name="NAME" /> leidimą apsilankyti šioje svetainėje</translation>
<translation id="1721424275792716183">* Būtina užpildyti lauką</translation>
+<translation id="1727741090716970331">Tinkamo kortelės numerio pridėjimas</translation>
<translation id="1728677426644403582">Peržiūrite tinklalapio šaltinį</translation>
<translation id="173080396488393970">Šio tipo kortelė nepalaikoma</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serijinio rengimo klaida</translation>
<translation id="1974060860693918893">Išplėstiniai</translation>
<translation id="1978555033938440688">Programinės aparatinės įrangos versija</translation>
-<translation id="1995859865337580572">Patvirtinkite kortelės saugos kodą (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ir dar 1}one{ir dar #}few{ir dar #}many{ir dar #}other{ir dar #}}</translation>
<translation id="2025186561304664664">Nustatytas automatinis įgaliotojo serverio konfigūravimas.</translation>
<translation id="2030481566774242610">Ar turėjote omenyje <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Jei norite gauti „Google“ siūlomo suasmeninto turinio, prisijunkite prie „Chrome“.</translation>
+<translation id="2091887806945687916">Garsas</translation>
<translation id="2094505752054353250">Domeno neatitikimas</translation>
<translation id="2096368010154057602">Departamentas</translation>
<translation id="2108755909498034140">Iš naujo paleiskite kompiuterį</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Nepaisoma, nes buvo pakeista taikant „<ph name="POLICY_NAME" />“.</translation>
<translation id="2138201775715568214">Ieškoma fizinių tinklalapių netoliese</translation>
<translation id="213826338245044447">Žymės mobiliesiems</translation>
+<translation id="214556005048008348">Atšaukti mokėjimą</translation>
<translation id="2147827593068025794">Fono sinchronizavimas</translation>
+<translation id="2148613324460538318">Pridėti kortelę</translation>
<translation id="2154054054215849342">Sinchronizavimo paslauga nepasiekiama jūsų domenui</translation>
<translation id="2154484045852737596">Kortelės informacijos redagavimas</translation>
<translation id="2166049586286450108">Visateisė administratoriaus prieiga</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresas}one{# adresas}few{# adresai}many{# adreso}other{# adresų}}</translation>
<translation id="2187317261103489799">Aptikti (numatytoji parinktis)</translation>
<translation id="2202020181578195191">Įveskite tinkamus galiojimo laiko pabaigos metus</translation>
+<translation id="2209523182407020534">Ši klaida galėjo įvykti dėl antivirusinės, užkardos ar žiniatinklio filtravimo programos arba tarpinio serverio programinės įrangos.</translation>
<translation id="2212735316055980242">Politika nerasta</translation>
<translation id="2213606439339815911">Gaunami įrašai...</translation>
<translation id="2218879909401188352">Šiuo metu užpuolikai svetainėje <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> gali įdiegti pavojingų programų, kurios gali būti žalingos įrenginiui, atlikti nepageidaujamų veiksmų, dėl kurių padidės mobiliojo telefono sąskaita, arba pavogti asmens informaciją. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Grįžti</translation>
<translation id="2503184589641749290">Tinkamos debeto ir išankstinio mokėjimo kortelės</translation>
<translation id="2515629240566999685">Patikrinti signalo stiprumą savo srityje</translation>
+<translation id="2524461107774643265">Daugiau informacijos pridėjimas</translation>
+<translation id="2536110899380797252">Pridėti adresą</translation>
<translation id="2539524384386349900">Aptikti</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> išsiuntė netinkamą atsaką.</translation>
<translation id="2556876185419854533">&amp;Anuliuoti redagavimą</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Šiuo metu „Chromium“ negali patvirtinti jūsų kortelės. Vėliau bandykite dar kartą.</translation>
<translation id="2705137772291741111">Išsaugotos (talpykloje esančios) šios svetainės kopijos negalima skaityti.</translation>
<translation id="2709516037105925701">Automatinis pildymas</translation>
+<translation id="2710942282213947212">Programinė įranga jūsų kompiuteryje neleidžia „Chromium“ saugiai prisijungti prie žiniatinklio</translation>
<translation id="2712173769900027643">Prašyti leidimo</translation>
-<translation id="2713444072780614174">Balta</translation>
<translation id="2720342946869265578">Netoliese</translation>
<translation id="2721148159707890343">Užklausa sėkminga</translation>
<translation id="2728127805433021124">Serverio sertifikatas pasirašytas naudojant nepatikimą parašo algoritmą.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Aptiktas tinklo pasikeitimas.</translation>
<translation id="2916038427272391327">Uždarykite kitas programas</translation>
<translation id="2922350208395188000">Neįmanoma patikrinti serverio sertifikato.</translation>
+<translation id="2925673989565098301">Pristatymo metodas</translation>
<translation id="2928905813689894207">Atsiskaitymo adresas</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas yra iš <ph name="DOMAIN2" />. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Netinkamas politikos tipas</translation>
<translation id="3032412215588512954">Ar norite iš naujo įkelti šią svetainę?</translation>
<translation id="3037605927509011580">Oi!</translation>
+<translation id="3039538478787849737">Išsaugoti kortelę sistemoje „Google“?</translation>
<translation id="3041612393474885105">Sertifikato informacija</translation>
<translation id="3063697135517575841">Šiuo metu „Chrome“ negali patvirtinti jūsų kortelės. Vėliau bandykite dar kartą.</translation>
<translation id="3064966200440839136">Išjungiate inkognito režimą, kad galėtumėte sumokėti naudodami išorinę programą. Tęsti?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Laikina serverio klaida</translation>
<translation id="3154506275960390542">Šiame puslapyje yra forma, kurios negalima saugiai pateikti. Siunčiamus duomenis gali peržiūrėti kiti asmenys juos perduodant arba juos gali modifikuoti atakuojanti programa, siekianti pakeisti serverio gaunamą informaciją.</translation>
<translation id="3157931365184549694">Atkurti</translation>
+<translation id="3162559335345991374">Naudojant šį „Wi-Fi“ tinklą gali būti prašoma apsilankyti prisijungimo puslapyje.</translation>
<translation id="3167968892399408617">Puslapiai, kuriuos peržiūrite inkognito skirtukų lapuose, nebus rodomi naršyklės istorijoje, slapukų saugykloje ar paieškos istorijoje, kai uždarysite visus inkognito skirtukų lapus. Visi atsisiųsti failai ar sukurtos žymės išliks.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Sala</translation>
@@ -288,6 +298,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Atšaukti mokėjimą</translation>
<translation id="3207960819495026254">Pažymėta</translation>
+<translation id="3211223744486044430">Kad kitą kartą galėtumėte greičiau atlikti mokėjimą, išsaugokite kortelę „Google“ paskyroje ir šiame įrenginyje.</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>
<translation id="3226128629678568754">Spustelėkite įkėlimo iš naujo mygtuką, kad iš naujo pateiktumėte duomenis, reikalingus puslapiui įkelti.</translation>
<translation id="3227137524299004712">Mikrofonas</translation>
@@ -302,7 +313,6 @@
<translation id="3303855915957856445">Nerasta jokių paieškos rezultatų</translation>
<translation id="3305707030755673451"><ph name="TIME" /> duomenys buvo užšifruoti naudojant sinchronizavimo slaptafrazę. Įveskite ją, kad pradėtumėte sinchronizuoti.</translation>
<translation id="3320021301628644560">Atsiskaitymo adreso pridėjimas</translation>
-<translation id="3329013043687509092">Spalvų sodrumas</translation>
<translation id="333371639341676808">Neleiskite šiam puslapiui kurti papildomų dialogo langų.</translation>
<translation id="3338095232262050444">Saugi</translation>
<translation id="3340978935015468852">nustatymų</translation>
@@ -321,6 +331,7 @@
<translation id="3380864720620200369">Kliento ID:</translation>
<translation id="3391030046425686457">Pristatymo adresas</translation>
<translation id="3395827396354264108">Paėmimo metodas</translation>
+<translation id="3399952811970034796">Pristatymo adresas</translation>
<translation id="3422248202833853650">Pabandykite išeiti iš kitų programų, kad atlaisvintumėte atminties.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> šiuo metu nepasiekiama.</translation>
<translation id="3427092606871434483">Leisti (numatytoji parinktis)</translation>
@@ -366,10 +377,12 @@
<translation id="3679803492151881375">Strigčių ataskaita užfiksuota <ph name="CRASH_TIME" />, įkelta <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikato informacija</translation>
<translation id="3690164694835360974">Prisijungimas nesaugus</translation>
+<translation id="3704162925118123524">Naudojant šį tinklą gali būti prašoma apsilankyti prisijungimo puslapyje.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Įkeliama...</translation>
<translation id="3712624925041724820">Licencijos baigėsi</translation>
<translation id="3714780639079136834">Įjungti mobiliojo ryšio duomenis arba „Wi-Fi“</translation>
+<translation id="3715597595485130451">Prisijungimas prie „Wi-Fi“</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Patikrinti tarpinio serverio, užkardos ir DNS konfigūraciją<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Jei suprantate, kokia rizika gali kilti jūsų saugai, galite <ph name="BEGIN_LINK" />apsilankyti šioje nesaugioje svetainėje<ph name="END_LINK" />, kol iš jos dar nepašalintos pavojingos programos.</translation>
<translation id="3739623965217189342">Nukopijuota nuoroda</translation>
@@ -404,6 +417,7 @@
<translation id="4030383055268325496">&amp;Anuliuoti pridėjimą</translation>
<translation id="404928562651467259">ĮSPĖJIMAS</translation>
<translation id="4058922952496707368">Raktas „<ph name="SUBKEY" />“: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Įgaliotojo serverio konfigūracijoje nustatyta naudoti .pac scenarijaus URL, o ne fiksuotus įgaliotuosius serverius.</translation>
@@ -411,7 +425,6 @@
<translation id="4103249731201008433">Netinkamas įrenginio serijos numeris</translation>
<translation id="410351446219883937">Automatinis paleidimas</translation>
<translation id="4103763322291513355">Apsilankykite &lt;strong&gt;chrome://policy&lt;/strong&gt;, kad peržiūrėtumėte į juodąjį sąrašą įtrauktų URL sąrašą ir kitą politiką, kurią priverstinai paleido sistemos administratorius.</translation>
-<translation id="4115378294792113321">Purpurinė</translation>
<translation id="4116663294526079822">Visada leisti šioje svetainėje</translation>
<translation id="4117700440116928470">Politikos aprėptis nepalaikoma.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{Dar 1}one{Dar #}few{Dar #}many{Dar #}other{Dar #}}</translation>
@@ -449,6 +462,7 @@
<translation id="4377125064752653719">Bandėte pasiekti svetainę „<ph name="DOMAIN" />“, bet sertifikatą, kurį pateikė serveris, anuliavo jo išdavėjas. Tai reiškia, kad saugos kredencialais, kuriuos pateikė serveris, visiškai negalima pasitikėti. Galbūt bendraujate su užpuoliku.</translation>
<translation id="4394049700291259645">Neleisti</translation>
<translation id="4406896451731180161">paieškos rezultatai</translation>
+<translation id="4415426530740016218">Paėmimo adresas</translation>
<translation id="4424024547088906515">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas „Chrome“. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepriėmė jūsų prisijungimo sertifikato arba prisijungimo sertifikatas nebuvo pateiktas.</translation>
<translation id="443673843213245140">Įgaliotojo serverio naudojimas neleidžiamas, bet nurodyta aiški įgaliotojo serverio konfigūracija.</translation>
@@ -461,6 +475,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Pabandykite išjungti plėtinius.</translation>
<translation id="457875822857220463">Pristatymas</translation>
+<translation id="4582800630050655161">Galite prarasti prieigą prie „Google“ paskyros arba susidurti su tapatybės vagyste. „Chromium“ rekomenduoja pakeisti slaptažodį dabar.</translation>
<translation id="4587425331216688090">Pašalinti adresą iš „Chrome“?</translation>
<translation id="4592951414987517459">Ryšys su <ph name="DOMAIN" /> užšifruotas naudojant modernų šifravimo paketą.</translation>
<translation id="4594403342090139922">&amp;Anuliuoti ištrynimą</translation>
@@ -469,10 +484,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Nebenaudoti negaliojančio sertifikato</translation>
+<translation id="4690954380545377795">Galite prarasti prieigą prie „Google“ paskyros arba susidurti su tapatybės vagyste. „Chrome“ rekomenduoja pakeisti slaptažodį dabar.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Ryšys nutrauktas</translation>
<translation id="471880041731876836">Neturite leidimo, kad galėtumėte apsilankykite šioje svetainėje</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Paleistas įrankis „Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
+<translation id="472349245089439925">Jūsų mokėjimas</translation>
<translation id="4726672564094551039">Iš naujo įkelti politiką</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Iš naujo paleiskite „Chromium“</translation>
@@ -511,6 +528,7 @@
<translation id="5019198164206649151">Bloga atsarginio atminties įrenginio būsena</translation>
<translation id="5023310440958281426">Patikrinkite savo administratoriaus politiką</translation>
<translation id="5029568752722684782">Išvalyti kopiją</translation>
+<translation id="503069730517007720">Reikalingas „<ph name="SOFTWARE_NAME" />“ šakninis sertifikatas, bet jis nėra įdiegtas. Jūsų IT administratorius turėtų peržiūrėti „<ph name="SOFTWARE_NAME" />“ konfigūravimo instrukcijas, kad išspręstų šią problemą. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Apie „Google“ vertėją</translation>
<translation id="5039804452771397117">Leisti</translation>
<translation id="5040262127954254034">Privatumas</translation>
@@ -534,6 +552,8 @@
<translation id="5199729219167945352">Bandymai</translation>
<translation id="5205222826937269299">Būtina nurodyti pavadinimą</translation>
<translation id="5222812217790122047">Būtina nurodyti el. paštą</translation>
+<translation id="522700295135997067">Gali būti, kad ši svetainė ką tik pavogė jūsų slaptažodį</translation>
+<translation id="5230733896359313003">Pristatymo adresas</translation>
<translation id="5251803541071282808">Debesis</translation>
<translation id="5277279256032773186">Naudojate „Chrome“ darbe? Įmonės gali tvarkyti darbuotojų „Chrome“ nustatymus. Sužinokite daugiau</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Jei norite laikinai išjungti programinę įrangą, kad galėtumėte pasiekti žiniatinklį, atlikite nurodytus veiksmus. Jums reikės administratoriaus teisių.<ph name="END_PARAGRAPH" />
@@ -548,9 +568,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Ryšys su šia svetaine nėra privatus. Kad galėtumėte bet kada išeiti iš virtualiosios realybės režimo, pašalinkite ausines ir paspauskite „Atgal“.</translation>
<translation id="5299298092464848405">Analizuojant politiką įvyko klaida</translation>
+<translation id="5308380583665731573">Prisijungti</translation>
<translation id="5308689395849655368">Strigčių ataskaitų teikimas neleidžiamas.</translation>
<translation id="5317780077021120954">Išsaugoti</translation>
<translation id="5327248766486351172">Pavadinimas</translation>
+<translation id="5332219387342487447">Pristatymo metodas</translation>
<translation id="5355557959165512791">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes jos sertifikatas buvo anuliuotas. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
<translation id="536296301121032821">Išsaugant politikos nustatymus įvyko klaida</translation>
<translation id="5386426401304769735">Šios svetainės sertifikatų grandinėje yra sertifikatas, pasirašytas naudojant SHA-1.</translation>
@@ -570,12 +592,15 @@
<translation id="5492298309214877701">Šios svetainės URL įmonės, organizacijos ar mokyklos intranete toks pat kaip išorinės svetainės URL.
<ph name="LINE_BREAK" />
Pabandykite susisiekti su sistemos administratoriumi.</translation>
+<translation id="5499929369096410817">Įveskite kortelės „<ph name="CREDIT_CARD" />“ saugos kodą. Šis kodas nebus išsaugotas.</translation>
<translation id="5509780412636533143">Tvarkomos žymės</translation>
<translation id="5510766032865166053">Galbūt jis perkeltas arba ištrintas.</translation>
<translation id="5523118979700054094">Politikos pavadinimas</translation>
<translation id="552553974213252141">Ar tekstas tinkamai ištrauktas?</translation>
<translation id="5540224163453853">Nepavyko rasti straipsnio, dėl kurio pateikta užklausa.</translation>
+<translation id="5541546772353173584">El. pašto adreso pridėjimas</translation>
<translation id="5544037170328430102"><ph name="SITE" /> įterptame puslapyje sakoma:</translation>
+<translation id="5545756402275714221">Jums skirti straipsniai</translation>
<translation id="5556459405103347317">Įkelti iš naujo</translation>
<translation id="5560088892362098740">Galiojimo laiko pabaigos data</translation>
<translation id="5565735124758917034">Aktyvus</translation>
@@ -597,6 +622,7 @@
<translation id="5659593005791499971">El. paštas</translation>
<translation id="5669703222995421982">Suasmeninto turinio gavimas</translation>
<translation id="5675650730144413517">Šis puslapis neveikia</translation>
+<translation id="5689199277474810259">Eksportuoti kaip JSON</translation>
<translation id="5710435578057952990">Šio tinklalapio tapatybė nenustatyta.</translation>
<translation id="5719499550583120431">Išankstinio mokėjimo kortelės tinkamos.</translation>
<translation id="5720705177508910913">Dabartinis naudotojas</translation>
@@ -611,27 +637,27 @@
<translation id="5810442152076338065">Ryšys su <ph name="DOMAIN" /> užšifruotas naudojant pasenusį šifravimo paketą.</translation>
<translation id="5813119285467412249">&amp;Pridėti dar kartą</translation>
<translation id="5838278095973806738">Šioje svetainėje neturėtumėte pateikti neskelbtinos informacijos (pvz., slaptažodžių ar kredito kortelių numerių), nes ją gali pavogti užpuolikai.</translation>
+<translation id="5866257070973731571">Telefono numerio pridėjimas</translation>
<translation id="5869405914158311789">Nepavyksta pasiekti šios svetainės</translation>
<translation id="5869522115854928033">Išsaugoti slaptažodžiai</translation>
<translation id="5872918882028971132">Pasiūlymai tėvams</translation>
<translation id="5893752035575986141">Kredito kortelės tinkamos.</translation>
-<translation id="5901630391730855834">Geltona</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinchronizuota)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Naudojamas 1 slapukas}one{Naudojamas # slapukas}few{Naudojami # slapukai}many{Naudojama # slapuko}other{Naudojama # slapukų}}</translation>
<translation id="5959728338436674663">Automatiškai siųsti tam tikrą <ph name="BEGIN_WHITEPAPER_LINK" />sistemos informaciją ir puslapio turinį<ph name="END_WHITEPAPER_LINK" /> į sistemą „Google“ siekiant padėti aptikti pavojingas programas ir svetaines. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Kontaktinės informacijos redagavimas</translation>
<translation id="5967867314010545767">Pašalinti iš istorijos</translation>
<translation id="5975083100439434680">Tolinti</translation>
+<translation id="597552863672748783">Patvirtinkite saugos kodą</translation>
<translation id="598637245381783098">Nepavyksta atidaryti mokėjimo programos</translation>
<translation id="5989320800837274978">Nenurodyti nei fiksuoti įgaliotieji serveriai, nei .pac scenarijaus URL.</translation>
<translation id="5990559369517809815">Plėtinys užblokavo serveriui teikiamas užklausas.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1 puslapis}one{# puslapis}few{# puslapiai}many{# puslapio}other{# puslapių}}</translation>
-<translation id="6017514345406065928">Žalia</translation>
<translation id="6017850046339264347">Užgrobėjai svetainėje <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> gali įdiegti klaidinančių programų, kurios apsimeta kitomis programomis, arba rinkti duomenis, naudojamus jums stebėti. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sinchronizuota)</translation>
<translation id="6027201098523975773">Įveskite pavadinimą</translation>
<translation id="6040143037577758943">Uždaryti</translation>
-<translation id="6042308850641462728">Daugiau</translation>
<translation id="6047233362582046994">Jei suprantate, kokia rizika gali kilti jūsų saugai, galite <ph name="BEGIN_LINK" />apsilankyti šioje svetainėje<ph name="END_LINK" />, kol iš jos dar nepašalintos kenkėjiškos programos.</translation>
<translation id="6047927260846328439">Šiuo turiniu gali būti bandoma apgaule priversti jus įdiegti programinę įrangą arba atskleisti asmens informaciją. <ph name="BEGIN_LINK" />Rodyti vis tiek<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Šiuo metu negalite apsilankyti <ph name="SITE" />, nes svetainėje naudojamas sertifikatų prisegimas. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
@@ -698,6 +724,7 @@
<translation id="6569060085658103619">Peržiūrite plėtinio puslapį</translation>
<translation id="6596325263575161958">Šifravimo parinktys</translation>
<translation id="662080504995468778">Likti</translation>
+<translation id="6624427990725312378">Kontaktinė informacija</translation>
<translation id="6626291197371920147">Galiojančios kortelės numerio pridėjimas</translation>
<translation id="6628463337424475685">„<ph name="ENGINE" />“ paieška</translation>
<translation id="6630809736994426279">Šiuo metu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> užpuolikai gali jūsų „Mac“ įrenginyje bandyti įdiegti pavojingas programas, kurios vagia arba ištrina informaciją (pvz., nuotraukas, slaptažodžius, pranešimus ir kredito kortelių duomenis). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -708,7 +735,6 @@
<translation id="6710213216561001401">Ankstesnis</translation>
<translation id="6710594484020273272">&lt;Įveskite paieškos terminą&gt;</translation>
<translation id="6711464428925977395">Kažkas negerai su tarpiniu serveriu arba adresas netinkamas.</translation>
-<translation id="6727102863431372879">Nustatyti</translation>
<translation id="674375294223700098">Nežinoma serverio sertifikato klaida.</translation>
<translation id="6753269504797312559">Politikos vertė</translation>
<translation id="6757797048963528358">Įjungta įrenginio miego būsena.</translation>
@@ -777,6 +803,7 @@
<translation id="7400418766976504921">URL adresas</translation>
<translation id="7419106976560586862">Profilio kelias</translation>
<translation id="7424977062513257142">Šiame tinklalapyje įterptame puslapyje sakoma:</translation>
+<translation id="7437289804838430631">Pridėti kontaktinę informaciją</translation>
<translation id="7441627299479586546">Netinkamas politikos objektas</translation>
<translation id="7444046173054089907">Ši svetainė užblokuota</translation>
<translation id="7445762425076701745">Nepavyksta visiškai patvirtinti serverio, prie kurio esate prisijungę, tapatybės. Prie serverio esate prisijungę naudodami tik tinklui galiojantį vardą, kurio nuosavybės teisių išorinė sertifikatą išduodanti institucija negali patvirtinti. Nors kai kurios sertifikatus išduodančios institucijos vis tiek išduos sertifikatus pagal šiuos vardus, niekaip nebus galima užtikrinti, kad būsite prisijungę prie numatytos svetainės, o ne prie užpuolėjo.</translation>
@@ -787,11 +814,11 @@
<translation id="7481312909269577407">Persiųsti</translation>
<translation id="7485870689360869515">Nerasta jokių duomenų.</translation>
<translation id="7508255263130623398">Sugrąžinto politikos įrenginio ID nenurodytas arba neatitinka dabartinio įrenginio ID</translation>
+<translation id="7511955381719512146">Naudojant šį „Wi-Fi“ tinklą gali būti prašoma apsilankyti <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Atsisiųsti</translation>
<translation id="7518003948725431193">Nerasta nė vieno tinklalapio šiuo žiniatinklio adresu: <ph name="URL" /></translation>
<translation id="7521387064766892559">„JavaScript“</translation>
<translation id="7526934274050461096">Jūsų ryšys su šia svetaine nėra privatus</translation>
-<translation id="7535087603100972091">Reikšmė</translation>
<translation id="7537536606612762813">Privaloma</translation>
<translation id="7542403920425041731">Kai patvirtinsite, išsami kortelės informacija bus bendrinama su šia svetaine.</translation>
<translation id="7542995811387359312">Automatinis kredito kortelės informacijos pildymas neleidžiamas, nes šiai formai nenaudojamas saugus ryšys.</translation>
@@ -802,7 +829,6 @@
<translation id="7567204685887185387">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas gali būti neteisėtai išduotas. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="7568593326407688803">Šis puslapis yra<ph name="ORIGINAL_LANGUAGE" />Ar norėtumėte jį išversti?</translation>
<translation id="7569952961197462199">Pašalinti kredito kortelės informaciją iš „Chrome“?</translation>
-<translation id="7569983096843329377">Juoda</translation>
<translation id="7578104083680115302">Greitai mokėkite svetainėse ir programose įvairiuose įrenginiuose naudodami korteles, kurias išsaugojote „Google“.</translation>
<translation id="7588950540487816470">Fizinis žiniatinklis</translation>
<translation id="7592362899630581445">Serverio sertifikatas pažeidžia pavadinimų apribojimus.</translation>
@@ -821,11 +847,13 @@
<translation id="7669271284792375604">Šios svetainės užgrobėjai gali bandyti apgaule priversti jus įdiegti naršymo funkcijas trikdančių programų (pvz., pakeitę pagrindinį puslapį ar rodydami papildomų skelbimų svetainėse, kuriose lankotės).</translation>
<translation id="7674629440242451245">Domina naujos „Chrome“ funkcijos? Išbandykite mūsų kuriamą kanalą adresu chrome.com/dev.</translation>
<translation id="7682287625158474539">Pristatymas</translation>
+<translation id="7699293099605015246">Straipsniai šiuo metu negalimi</translation>
<translation id="7701040980221191251">Nieko</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Eiti į svetainę <ph name="SITE" /> (nesaugu)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifikatas</translation>
<translation id="7716147886133743102">Užblokavo jūsų administratorius</translation>
<translation id="7716424297397655342">Nepavyksta įkelti šios svetainės iš talpyklos</translation>
+<translation id="7723047071702270851">Kortelės redagavimas</translation>
<translation id="774634243536837715">Pavojingas turinys užblokuotas.</translation>
<translation id="7752995774971033316">Netvarkoma</translation>
<translation id="7755287808199759310">Jūsų tėtis ar mama gali ją atblokuoti už jus</translation>
@@ -836,21 +864,24 @@
<translation id="7764225426217299476">Pridėti adresą</translation>
<translation id="777702478322588152">Prefektūra</translation>
<translation id="7791543448312431591">Pridėti</translation>
+<translation id="7793553086574152071">Kad kitą kartą galėtumėte greičiau atlikti mokėjimą, išsaugokite kortelę „Google“ paskyroje.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> tinklalapis gali laikinai neveikti arba visam laikui būti perkeltas nauju žiniatinklio adresu.</translation>
<translation id="7800304661137206267">Ryšys užšifruotas naudojant <ph name="CIPHER" /> su <ph name="MAC" /> pranešimo tapatybei nustatyti ir <ph name="KX" /> kaip pagrindinį mainų mechanizmą.</translation>
+<translation id="7802523362929240268">Svetainė yra teisėta</translation>
<translation id="780301667611848630">Ačiū, ne</translation>
<translation id="7805768142964895445">Būsena</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Pašalinti formos pasiūlymą iš „Chrome“?</translation>
<translation id="7815407501681723534">Pagal terminą „<ph name="SEARCH_STRING" />“ surasta tiek <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" /></translation>
+<translation id="782886543891417279">Naudojant šį „Wi-Fi“ tinklą („<ph name="WIFI_NAME" />“) gali būti prašoma apsilankyti prisijungimo puslapyje.</translation>
<translation id="785549533363645510">Tačiau nesate nematomi. Įjungus inkognito režimą, naršymo veiksmai vis tiek matomi darbdaviui, interneto paslaugų teikėjui ar svetainėms, kuriose lankotės.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Debeto ir išankstinio mokėjimo kortelės tinkamos.</translation>
+<translation id="7878562273885520351">Jūsų slaptažodis gali būti pažeistas</translation>
<translation id="7887683347370398519">Patikrinkite kortelės saugos kodą (CVC) ir bandykite dar kartą</translation>
<translation id="79338296614623784">Įveskite tinkamą telefono numerį</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Serverio sertifikatas dar negalioja.</translation>
-<translation id="7942349550061667556">Raudona</translation>
<translation id="7947285636476623132">Patikrinkite galiojimo pabaigos metus ir bandykite dar kartą</translation>
<translation id="7951415247503192394">(32 bitų)</translation>
<translation id="7956713633345437162">Žymės mobiliesiems</translation>
@@ -864,9 +895,13 @@
<translation id="8037357227543935929">Klausti (numatytoji parinktis)</translation>
<translation id="8041089156583427627">Siųsti atsiliepimą</translation>
<translation id="8041940743680923270">Naudoti visuotinį numatytąjį nustatymą (klausti)</translation>
+<translation id="8057711352706143257">„<ph name="SOFTWARE_NAME" />“ netinkamai sukonfigūruota. Pašalinus „<ph name="SOFTWARE_NAME" />“ paprastai pavyksta išspręsti šią problemą. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Nepavyko peržiūrėti straipsnio.</translation>
<translation id="8091372947890762290">Laukiama aktyvinimo serveryje</translation>
+<translation id="8094917007353911263">Naudojant šį tinklą gali būti prašoma apsilankyti <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Mokėjimo metodas</translation>
<translation id="8118489163946903409">Mokėjimo metodas</translation>
+<translation id="8127301229239896662">„<ph name="SOFTWARE_NAME" />“ nebuvo tinkamai įdiegta kompiuteryje ar tinkle. Kreipkitės į IT administratorių, kad ši problema būtų išspręsta.</translation>
<translation id="8131740175452115882">Patvirtinti</translation>
<translation id="8134994873729925007">Nepavyko rasti <ph name="HOST_NAME" /> serverio <ph name="BEGIN_ABBR" />DNS adreso<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Įjungta kompiuterio miego būsena.</translation>
@@ -889,6 +924,7 @@
<translation id="8289355894181816810">Jei nesate tikri, ką tai reiškia, susisiekite su tinklo administratoriumi.</translation>
<translation id="8293206222192510085">Pridėti žymę</translation>
<translation id="8294431847097064396">Šaltinis</translation>
+<translation id="8298115750975731693">Naudojant šį „Wi-Fi“ tinklą („<ph name="WIFI_NAME" />“) gali būti prašoma apsilankyti <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Nepavyko 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. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Vertimas nepavyko dėl tinklo ryšio problemos.</translation>
<translation id="8332188693563227489">Prieiga prie <ph name="HOST_NAME" /> atmesta</translation>
@@ -942,20 +978,21 @@
<translation id="8870413625673593573">Neseniai uždaryta</translation>
<translation id="8874824191258364635">Įveskite tinkamą kortelės numerį</translation>
<translation id="8876793034577346603">Analizuojant tinklo konfigūraciją įvyko klaida.</translation>
-<translation id="8889402386540077796">Spalva</translation>
<translation id="8891727572606052622">Netinkamas įgaliotojo serverio režimas.</translation>
<translation id="889901481107108152">Deja, šis eksperimentas negalimas platformoje.</translation>
<translation id="8903921497873541725">Artinti</translation>
<translation id="8931333241327730545">Ar norite išsaugoti šios kortelės informaciją „Google“ paskyroje?</translation>
<translation id="8932102934695377596">Jūsų laikrodis atsilieka</translation>
+<translation id="893332455753468063">Vardo ir pavardės pridėjimas</translation>
<translation id="8938939909778640821">Tinkamos kredito ir išankstinio mokėjimo kortelės</translation>
+<translation id="8957210676456822347">Fiksuotojo portalo autorizavimas</translation>
<translation id="8971063699422889582">Baigėsi serverio sertifikato galiojimo laikas.</translation>
-<translation id="8986494364107987395">Automatiškai siųsti naudojimo statistiką ir strigčių ataskaitas „Google“</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Pateiktoje svetainėje yra kenkėjiškų programų</translation>
<translation id="8997023839087525404">Serveris pateikė sertifikatą, kuris nebuvo viešai atskleistas naudojant sertifikato skaidrumo politiką. Tai yra tam tikriems sertifikatams taikomas reikalavimas, siekiant užtikrinti, jog jie patikimi ir apsaugo nuo įsilaužėlių.</translation>
<translation id="9001074447101275817">Tarpiniame serveryje <ph name="DOMAIN" /> būtina įvesti naudotojo vardą ir slaptažodį.</translation>
<translation id="9005998258318286617">PDF dokumento įkelti nepavyko.</translation>
+<translation id="9008201768610948239">Nepaisyti</translation>
<translation id="901974403500617787">Visoje sistemoje taikomas žymas gali nustatyti tik savininkas: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Būtina pateikti kortelės atsiskaitymo adresą</translation>
<translation id="9020542370529661692">Šis puslapis išverstas į <ph name="TARGET_LANGUAGE" /></translation>
@@ -965,11 +1002,14 @@
<translation id="9049981332609050619">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė neteisingą sertifikatą.</translation>
<translation id="9050666287014529139">Slaptafrazė</translation>
<translation id="9065203028668620118">Redaguoti</translation>
-<translation id="9068849894565669697">Pasirinkite spalvą</translation>
<translation id="9069693763241529744">Užblokuota pagal plėtinį</translation>
<translation id="9076283476770535406">Joje gali būti suaugusiesiems skirto turinio</translation>
<translation id="9078964945751709336">Būtina pateikti daugiau informacijos</translation>
+<translation id="9080712759204168376">Užsakymų suvestinė</translation>
<translation id="9103872766612412690">Svetainėje <ph name="SITE" /> įprastai naudojama šifruotė informacijai apsaugoti. Šį kartą „Chromium“ bandant prisijungti prie <ph name="SITE" />, ji pateikė neįprastus ir netinkamus prisijungimo duomenis. Gali būti, kad užpuolėjas bando apsimesti svetaine <ph name="SITE" /> arba „Wi-Fi“ prisijungimo ekrane nutrūko ryšys. Jūsų informacija vis tiek liko apsaugota, nes „Chromium“ sustabdė prisijungimą prieš apsikeitimą bet kokiais duomenimis.</translation>
+<translation id="9106062320799175032">Atsiskaitymo adreso pridėjimas</translation>
+<translation id="910908805481542201">Padėkite man tai išspręsti</translation>
+<translation id="9128870381267983090">Prisijungti prie tinklo</translation>
<translation id="9137013805542155359">Rodyti originalą</translation>
<translation id="9137248913990643158">Prieš naudodami šią programą prisijunkite prie „Chrome“.</translation>
<translation id="9148507642005240123">&amp;Anuliuoti redagavimą</translation>
@@ -981,6 +1021,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> naudojamas nepalaikomas protokolas.</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="9215416866750762878">Programa neleidžia „Chrome“ saugiai prisijungti prie svetainės</translation>
<translation id="9219103736887031265">Vaizdai</translation>
<translation id="933612690413056017">Nėra interneto ryšio</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -990,5 +1031,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Nėra}=1{1 elementas}one{# elementas}few{# elementai}many{# elemento}other{# elementų}}</translation>
<translation id="981121421437150478">Neprisijungus</translation>
<translation id="988159990683914416">Vykdymo programa sukurta</translation>
+<translation id="989988560359834682">Adreso redagavimas</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">„<ph name="SOFTWARE_NAME" />“ nebuvo tinkamai įdiegta kompiuteryje ar tinkle.
+ &lt;ul&gt;
+ &lt;li&gt;Pabandykite pašalinti arba išjungti „<ph name="SOFTWARE_NAME" />“.&lt;/li&gt;
+ &lt;li&gt;Pabandykite prisijungti prie kito tinklo.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index 766fb396fd6..70debfbb6a4 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Datora grāmatzīmes</translation>
<translation id="1074497978438210769">Nav droša</translation>
<translation id="1080116354587839789">Ietilpināt pēc platuma</translation>
+<translation id="1088860948719068836">Uz kartes norādītā vārda pievienošana</translation>
<translation id="1103523840287552314">Vienmēr tulkot <ph name="LANGUAGE" /> valodas saturu</translation>
+<translation id="1103778128462718200">Rādīt visas saglabātās paroles...</translation>
<translation id="1107591249535594099">Ja šī izvēles rūtiņa ir atzīmēta, pārlūks Chrome saglabās jūsu kartes kopiju šajā ierīcē, lai nodrošinātu ātrāku veidlapu aizpildi.</translation>
<translation id="1111153019813902504">Nesenas grāmatzīmes</translation>
<translation id="1113869188872983271">&amp;Atsaukt pārkārtošanu</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (veikta sinhronizācija)</translation>
<translation id="1263231323834454256">Lasīšanas saraksts</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> notverts ziņojums par avāriju (vēl nav augšupielādēts vai ignorēts)</translation>
+<translation id="1270502636509132238">Saņemšanas veids</translation>
<translation id="1281526147609854549">Izsniedza <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nekad netulkot šo vietni</translation>
<translation id="129553762522093515">Nesen aizvērtas</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Tiek gaidīta savienojuma izveide...</translation>
<translation id="153384715582417236">Pagaidām tas arī viss!</translation>
<translation id="1549470594296187301">Lai izmantotu šo funkciju, ir jābūt iespējotai valodai JavaScript.</translation>
-<translation id="1555130319947370107">Zila</translation>
<translation id="1559528461873125649">Nav tāda faila vai direktorija</translation>
<translation id="1583429793053364125">Šīs tīmekļa lapas rādīšanas laikā radās kļūda.</translation>
<translation id="1592005682883173041">Piekļuve lokālajiem datiem</translation>
<translation id="1594030484168838125">Izvēlēties</translation>
-<translation id="161042844686301425">Ciānzila</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Vai vēlaties, lai Chrome saglabātu šo karti?</translation>
<translation id="1639239467298939599">Notiek ielāde</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Operētājsistēma</translation>
<translation id="1721312023322545264">Jums ir nepieciešama atļauja no <ph name="NAME" />, lai apmeklētu šo vietni</translation>
<translation id="1721424275792716183">* Obligāts lauks</translation>
+<translation id="1727741090716970331">Derīga kartes numura pievienošana</translation>
<translation id="1728677426644403582">Jūs skatāt tīmekļa lapas avotu.</translation>
<translation id="173080396488393970">Šis kartes veids netiek atbalstīts</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Radās serializēšanas kļūda.</translation>
<translation id="1974060860693918893">Papildu</translation>
<translation id="1978555033938440688">Pogrammaparatūras versija</translation>
-<translation id="1995859865337580572">Lūdzu, apstipriniet savu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{un vēl 1}zero{un vēl #}one{un vēl #}other{un vēl #}}</translation>
<translation id="2025186561304664664">Starpniekserverim ir iestatīta autokonfigurācija.</translation>
<translation id="2030481566774242610">Vai domājāt <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Lai saņemtu Google ieteikto personalizēto saturu, pierakstieties pārlūkā Chrome.</translation>
+<translation id="2091887806945687916">Signāls</translation>
<translation id="2094505752054353250">Domēni nesaskan</translation>
<translation id="2096368010154057602">Departaments</translation>
<translation id="2108755909498034140">Restartējiet datoru</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorēta, jo to atcēla politika <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Notiek tuvumā esošu fiziskā tīmekļa lapu meklēšana</translation>
<translation id="213826338245044447">Mobilās grāmatzīmes</translation>
+<translation id="214556005048008348">Atcelt maksājumu</translation>
<translation id="2147827593068025794">Sinhronizācija fonā</translation>
+<translation id="2148613324460538318">Pievienot karti</translation>
<translation id="2154054054215849342">Sinhronizācija jūsu domēnam nav pieejama.</translation>
<translation id="2154484045852737596">Kartes informācijas rediģēšana</translation>
<translation id="2166049586286450108">Pilna administratora piekļuve</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adrese}zero{# adreses}one{# adrese}other{# adreses}}</translation>
<translation id="2187317261103489799">Noteikt (pēc noklusējuma)</translation>
<translation id="2202020181578195191">Ievadiet derīgu gadu</translation>
+<translation id="2209523182407020534">Šo kļūdu var izraisīt tādas lietojumprogrammas kā pretvīrusu, ugunsmūra, tīmekļa filtrēšanas vai starpniekservera programmatūra.</translation>
<translation id="2212735316055980242">Politika netika atrasta.</translation>
<translation id="2213606439339815911">Notiek ierakstu ienešana...</translation>
<translation id="2218879909401188352">Uzbrucēji vietnē <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> varētu instalēt bīstamas lietotnes, kas bojā jūsu ierīci, rada slēptas izmaksas mobilā tālruņa rēķinā vai zog jūsu personas informāciju. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Doties atpakaļ</translation>
<translation id="2503184589641749290">Atbalstītās debetkartes un priekšapmaksas kartes</translation>
<translation id="2515629240566999685">Pārbaudiet signālu savā apkaimē.</translation>
+<translation id="2524461107774643265">Papildu informācijas pievienošana</translation>
+<translation id="2536110899380797252">Pievienot adresi</translation>
<translation id="2539524384386349900">Noteikt</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> nosūtīja nederīgu atbildi.</translation>
<translation id="2556876185419854533">&amp;Labojuma atsaukšana</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Pārlūkā Chromium pašlaik nevar apstiprināt jūsu karti. Lūdzu, vēlāk mēģiniet vēlreiz.</translation>
<translation id="2705137772291741111">Nevar nolasīt šīs vietnes saglabāto (kešatmiņā ievietoto) kopiju.</translation>
<translation id="2709516037105925701">Automātiskā aizpilde</translation>
+<translation id="2710942282213947212">Programmatūra jūsu datorā, kuras dēļ pārlūkā Chromium nevar izveidot drošu tīmekļa savienojumu</translation>
<translation id="2712173769900027643">Lūgt atļauju</translation>
-<translation id="2713444072780614174">Balta</translation>
<translation id="2720342946869265578">Tuvumā</translation>
<translation id="2721148159707890343">Pieprasījums bija veiksmīgs.</translation>
<translation id="2728127805433021124">Servera sertifikāts ir parakstīts, izmantojot vāju paraksta algoritmu.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Konstatētas tīkla izmaiņas.</translation>
<translation id="2916038427272391327">Aizveriet citas programmas</translation>
<translation id="2922350208395188000">Servera sertifikātu nevar pārbaudīt.</translation>
+<translation id="2925673989565098301">Piegādes veids</translation>
<translation id="2928905813689894207">Norēķinu adrese</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}zero{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Šis serveris nevarēja pierādīt, ka šī ir vietne <ph name="DOMAIN" />; tās drošības sertifikāts ir saistīts ar domēnu <ph name="DOMAIN2" />. Iespējams, tas ir nepareizas konfigurācijas dēļ vai arī kāds ir ļaunprātīgi izmantojis jūsu savienojumu.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Politikas tips nav pareizs.</translation>
<translation id="3032412215588512954">Vai vēlaties atkārtoti ielādēt šo vietni?</translation>
<translation id="3037605927509011580">Cilnes avārija.</translation>
+<translation id="3039538478787849737">Vai saglabāt kartes datus Google tīklā?</translation>
<translation id="3041612393474885105">Sertifikāta informācija</translation>
<translation id="3063697135517575841">Pārlūkā Chrome pašlaik nevar apstiprināt jūsu karti. Lūdzu, vēlāk mēģiniet vēlreiz.</translation>
<translation id="3064966200440839136">Ja maksāšanai tiks izmantota ārēja lietojumprogramma, tiks aizvērts inkognito režīms. Vai turpināt?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Īslaicīga servera kļūda</translation>
<translation id="3154506275960390542">Šajā lapā ir veidlapa, ko, iespējams, nevar droši iesniegt. Kamēr šie dati tiek pārsūtīti, tos var aplūkot citi, un uzbrucējs tos varētu pārveidot, lai mainītu datus, ko saņem serveris.</translation>
<translation id="3157931365184549694">Atjaunot</translation>
+<translation id="3162559335345991374">Iespējams, izmantotajā Wi-Fi tīklā tiks pieprasīts apmeklēt pieteikšanās lapu.</translation>
<translation id="3167968892399408617">Lapas, ko skatāt inkognito režīma cilnēs, nebūs redzamas pārlūka vēsturē, sīkfailu krātuvē vai meklēšanas vēsturē, kad aizvērsiet visas inkognito režīma cilnes. Tomēr tiks saglabāti visi lejupielādētie faili un izveidotās grāmatzīmes.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Sala</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Atcelt maksājumu</translation>
<translation id="3207960819495026254">Atzīmēts kā grāmatzīme</translation>
+<translation id="3211223744486044430">Lai nākamreiz veiktu maksājumu ērtāk, saglabājiet šīs kartes datus savā Google kontā un šajā ierīcē.</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>
<translation id="3226128629678568754">Nospiediet atkārtotas ielādes pogu, lai atkārtoti iesniegtu datus, kas nepieciešami lapas ielādei.</translation>
<translation id="3227137524299004712">Mikrofons</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Netika atrasts neviens meklēšanas rezultāts.</translation>
<translation id="3305707030755673451">Jūsu dati tika šifrēti, izmantojot jūsu sinhronizācijas ieejas frāzi šādā datumā: <ph name="TIME" />. Lai sāktu sinhronizāciju, ievadiet ieejas frāzi.</translation>
<translation id="3320021301628644560">Norēķinu adreses pievienošana</translation>
-<translation id="3329013043687509092">Piesātinājums</translation>
<translation id="333371639341676808">Neļaujiet šai lapai veidot papildu dialogus.</translation>
<translation id="3338095232262050444">Droši</translation>
<translation id="3340978935015468852">Iestatījumi</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Klienta ID:</translation>
<translation id="3391030046425686457">Piegādes adrese</translation>
<translation id="3395827396354264108">Saņemšanas veids</translation>
+<translation id="3399952811970034796">Piegādes adrese</translation>
<translation id="3422248202833853650">Aizveriet citas programmas, lai atbrīvotu vietu atmiņā.</translation>
<translation id="3422472998109090673">Vietne <ph name="HOST_NAME" /> pašlaik nav sasniedzama.</translation>
<translation id="3427092606871434483">Atļaut (pēc noklusējuma)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375">Avāriju pārskats tverts: <ph name="CRASH_TIME" />; augšupielādēts: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikāta informācija</translation>
<translation id="3690164694835360974">Pieteikšanās nav droša</translation>
+<translation id="3704162925118123524">Iespējams, izmantotajā tīklā tiks pieprasīts apmeklēt pieteikšanās lapu.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Notiek ielāde...</translation>
<translation id="3712624925041724820">Nav pietiekami daudz licenču.</translation>
<translation id="3714780639079136834">Ieslēdziet mobilo datu savienojumu vai Wi-Fi.</translation>
+<translation id="3715597595485130451">Savienojuma izveide ar Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Pārbaudiet starpniekserveri, ugunsmūri un DNS konfigurāciju<ph name="END_LINK" />.</translation>
<translation id="3736520371357197498">Ja apzināties drošības risku, varat <ph name="BEGIN_LINK" />apmeklēt šo nedrošo vietni<ph name="END_LINK" />, pirms ir noņemtas bīstamās programmas.</translation>
<translation id="3739623965217189342">Jūsu kopētā saite</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;Atsaukt pievienošanu</translation>
<translation id="404928562651467259">BRĪDINĀJUMS</translation>
<translation id="4058922952496707368">Atslēga <ph name="SUBKEY" />: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Starpniekserveris ir iestatīts, lai tas lietotu .pac skripta URL, nevis fiksētus starpniekserverus.</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">Ierīces sērijas numurs nav derīgs.</translation>
<translation id="410351446219883937">Automātiskā atskaņošana</translation>
<translation id="4103763322291513355">Apmeklējiet vietni &lt;strong&gt;chrome://policy&lt;/strong&gt;, lai skatītu melnajā sarakstā iekļautos vietrāžus URL, kā arī citas politikas, ko noteicis sistēmas administrators.</translation>
-<translation id="4115378294792113321">Fuksīnsarkana</translation>
<translation id="4116663294526079822">Vienmēr atļaut šajā vietnē</translation>
<translation id="4117700440116928470">Politikas diapazons netiek atbalstīts.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{vēl 1}zero{vēl #}one{vēl #}other{vēl #}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719">Jūs mēģinājāt sasniegt <ph name="DOMAIN" />, bet izdevējs atsauca servera uzrādīto sertifikātu. Tas nozīmē, ka servera uzrādītie drošības akreditācijas dati itin nemaz nav uzticami. Iespējams, jūs sazināties ar uzbrucēju.</translation>
<translation id="4394049700291259645">Atspējot</translation>
<translation id="4406896451731180161">meklēšanas rezultāti</translation>
+<translation id="4415426530740016218">Saņemšanas adrese</translation>
<translation id="4424024547088906515">Šis serveris nevarēja pierādīt, ka šī ir vietne <ph name="DOMAIN" />; tās drošības sertifikāts netiek uzskatīts par uzticamu pārlūkā Chrome. Iespējams, tas ir nepareizas konfigurācijas dēļ vai arī kāds ir ļaunprātīgi izmantojis jūsu savienojumu.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepieņēma jūsu pieteikšanās sertifikātu, vai arī pieteikšanās sertifikāts netika iesniegts.</translation>
<translation id="443673843213245140">Starpniekservera lietošana ir atspējota, bet ir norādīta atklāta starpniekservera konfigurācija.</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Atspējojiet paplašinājumus.</translation>
<translation id="457875822857220463">Piegāde</translation>
+<translation id="4582800630050655161">Varat zaudēt piekļuvi savam Google kontam, vai jūsu identitāte var tikt nozagta. Chromium iesaka nekavējoties nomainīt paroli.</translation>
<translation id="4587425331216688090">Vai noņemt adresi no pārlūka Chrome?</translation>
<translation id="4592951414987517459">Savienojums ar domēnu <ph name="DOMAIN" /> ir šifrēts, izmantojot mūsdienīgu šifra komplektu.</translation>
<translation id="4594403342090139922">&amp;Dzēšanas atsaukšana</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Pārtraukt nederīga sertifikāta izmantošanu</translation>
+<translation id="4690954380545377795">Varat zaudēt piekļuvi savam Google kontam, vai jūsu identitāte var tikt nozagta. Chrome iesaka nekavējoties nomainīt paroli.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Savienojums tika pārtraukts</translation>
<translation id="471880041731876836">Jums nav atļaujas apmeklēt šo vietni</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Palaist Windows tīkla diagnostiku<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Jūsu maksājums</translation>
<translation id="4726672564094551039">Atkārtoti ielādēt politikas</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Restartējiet pārlūku Chromium</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">Dublējumu krātuve nav labā stāvoklī.</translation>
<translation id="5023310440958281426">Administratora politiku pārbaude</translation>
<translation id="5029568752722684782">Dzēst kopiju</translation>
+<translation id="503069730517007720">Programmatūrai <ph name="SOFTWARE_NAME" /> ir nepieciešams saknes sertifikāts, taču tas nav instalēts. Lai novērstu šo problēmu, tīkla administratoram ir jāapskata <ph name="SOFTWARE_NAME" /> konfigurācijas norādījumi. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Par Google tulkotāju</translation>
<translation id="5039804452771397117">Atļaut</translation>
<translation id="5040262127954254034">Konfidencialitāte</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">Eksperimenti</translation>
<translation id="5205222826937269299">Jānorāda vārds vai nosaukums.</translation>
<translation id="5222812217790122047">Jānorāda e-pasta adrese.</translation>
+<translation id="522700295135997067">Iespējams, šajā vietnē tikko tika nozagta jūsu parole</translation>
+<translation id="5230733896359313003">Piegādes adrese</translation>
<translation id="5251803541071282808">Mākonis</translation>
<translation id="5277279256032773186">Vai izmantojat Chrome darbā? Uzņēmumi var pārvaldīt darbinieku Chrome iestatījumus. Uzziniet vairāk.</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Lai īslaicīgi atspējotu programmatūru un piekļūtu tīmeklim, veiciet tālāk norādītās darbības. Nepieciešamas administratora privilēģijas.<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Savienojums ar šo vietni nav privāts. Lai izietu no virtuālās realitātes režīma, noņemiet austiņas un nospiediet Atpakaļ.</translation>
<translation id="5299298092464848405">Parsējot politiku, radās kļūda.</translation>
+<translation id="5308380583665731573">Pievienošana</translation>
<translation id="5308689395849655368">Avāriju pārskatu izveide ir atspējota.</translation>
<translation id="5317780077021120954">Saglabāt</translation>
<translation id="5327248766486351172">Nosaukums</translation>
+<translation id="5332219387342487447">Piegādes veids</translation>
<translation id="5355557959165512791">Pašlaik nevarat apmeklēt vietni <ph name="SITE" />, jo tās sertifikāts ir atsaukts. Tā kā tīkla kļūdas un uzbrukumi parasti ir īslaicīgi, visticamāk, šī lapa vēlāk darbosies.</translation>
<translation id="536296301121032821">Neizdevās saglabāt politikas iestatījumus.</translation>
<translation id="5386426401304769735">Šīs vietnes sertifikātu ķēdē ir iekļauts sertifikāts, kas ir parakstīts, izmantojot SHA-1.</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">Šai vietnei uzņēmuma, organizācijas vai skolas iekštīklā ir tāds pats URL kā ārējai vietnei.
<ph name="LINE_BREAK" />
Sazinieties ar sistēmas administratoru.</translation>
+<translation id="5499929369096410817">Ievadiet kartes <ph name="CREDIT_CARD" /> drošības kodu. Šis kods netiks saglabāts.</translation>
<translation id="5509780412636533143">Pārvaldītās grāmatzīmes</translation>
<translation id="5510766032865166053">Iespējams, tas ir pārvietots vai izdzēsts.</translation>
<translation id="5523118979700054094">Politikas nosaukums</translation>
<translation id="552553974213252141">Vai iegūtais teksts bija pareizs?</translation>
<translation id="5540224163453853">Pieprasīto rakstu nevarēja atrast.</translation>
+<translation id="5541546772353173584">E-pasta adreses pievienošana</translation>
<translation id="5544037170328430102">Vietnē <ph name="SITE" /> iegultā lapā ir rakstīts:</translation>
+<translation id="5545756402275714221">Ieteiktie raksti</translation>
<translation id="5556459405103347317">Pārlādēt</translation>
<translation id="5560088892362098740">Derīguma termiņš</translation>
<translation id="5565735124758917034">Aktīvs</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">E-pasts</translation>
<translation id="5669703222995421982">Saņemiet personalizētu saturu</translation>
<translation id="5675650730144413517">Šī lapa nedarbojas</translation>
+<translation id="5689199277474810259">Eksportēt JSON formātā</translation>
<translation id="5710435578057952990">Tīmekļa vietnes identitāte nav apstiprināta.</translation>
<translation id="5719499550583120431">Tiek pieņemtas priekšapmaksas kartes.</translation>
<translation id="5720705177508910913">Pašreizējais lietotājs</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065">Savienojums ar domēnu <ph name="DOMAIN" /> ir šifrēts, izmantojot novecojušu šifra komplektu.</translation>
<translation id="5813119285467412249">&amp;Pievienošanas atsaukuma atcelšana</translation>
<translation id="5838278095973806738">Neievadiet šajā vietnē sensitīvu informāciju (piemēram, paroles vai kredītkartes), jo to var nozagt uzbrucēji.</translation>
+<translation id="5866257070973731571">Tālruņa numura pievienošana</translation>
<translation id="5869405914158311789">Šī vietne nav sasniedzama</translation>
<translation id="5869522115854928033">Saglabātās paroles</translation>
<translation id="5872918882028971132">Vecāku ieteikumi</translation>
<translation id="5893752035575986141">Tiek pieņemtas kredītkartes.</translation>
-<translation id="5901630391730855834">Dzeltena</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (veikta sinhronizācija)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 tiek lietots}zero{# tiek lietoti}one{# tiek lietots}other{# tiek lietoti}}</translation>
<translation id="5959728338436674663">Automātiski sūtīt Google serveriem noteiktu <ph name="BEGIN_WHITEPAPER_LINK" />sistēmas informāciju un lapu saturu<ph name="END_WHITEPAPER_LINK" />, lai palīdzētu noteikt bīstamas lietotnes un vietnes. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Kontaktinformācijas rediģēšana</translation>
<translation id="5967867314010545767">Noņemt no vēstures</translation>
<translation id="5975083100439434680">Tālināt</translation>
+<translation id="597552863672748783">Drošības koda apstiprināšana</translation>
<translation id="598637245381783098">Nevar atvērt maksājumu lietotni</translation>
<translation id="5989320800837274978">Nav norādīti nedz fiksēti starpniekserveri, nedz .pac skripta URL.</translation>
<translation id="5990559369517809815">Paplašinājums ir bloķējis pieprasījumus serverim.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. lapa}zero{#. lapa}one{#. lapa}other{#. lapa}}</translation>
-<translation id="6017514345406065928">Zaļa</translation>
<translation id="6017850046339264347">Uzbrucēji vietnē <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> varētu instalēt maldinošas lietotnes, kas uzdodas par citu saturu, vai ievākt datus, ko izmantot jūsu izsekošanai. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (veikta sinhronizācija)</translation>
<translation id="6027201098523975773">Ievadiet vārdu</translation>
<translation id="6040143037577758943">Aizvērt</translation>
-<translation id="6042308850641462728">Vairāk</translation>
<translation id="6047233362582046994">Ja apzināties drošības risku, varat arī <ph name="BEGIN_LINK" />apmeklēt šo vietni<ph name="END_LINK" />, pirms ir noņemtas kaitīgās lietotnes.</translation>
<translation id="6047927260846328439">Ar šo saturu jūs var maldināt un panākt, ka instalējat programmatūru vai atklājat personas informāciju. <ph name="BEGIN_LINK" />Tāpat rādīt<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">Pašlaik nevarat apmeklēt vietni <ph name="SITE" />, jo tajā tiek izmantota sertifikātu piespraušana. Tā kā tīkla kļūdas un uzbrukumi parasti ir īslaicīgi, visticamāk, šī lapa vēlāk darbosies.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">Jūs skatāt paplašinājumu lapu.</translation>
<translation id="6596325263575161958">Šifrēšanas opcijas</translation>
<translation id="662080504995468778">Palikt</translation>
+<translation id="6624427990725312378">Kontaktinformācija</translation>
<translation id="6626291197371920147">Derīga kartes numura pievienošana</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> meklēšana</translation>
<translation id="6630809736994426279">Uzbrucēji vietnē <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> var mēģināt jūsu Mac datorā instalēt bīstamas programmas, kas zog vai izdzēš informāciju (piemēram, fotoattēlus, paroles, ziņojumus un kredītkaršu datus). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">Iepriekšējais</translation>
<translation id="6710594484020273272">&lt;Ierakstiet meklēšanas vienumu&gt;</translation>
<translation id="6711464428925977395">Starpniekserverī radās kļūda, vai arī adrese nav pareiza.</translation>
-<translation id="6727102863431372879">Iestatīt</translation>
<translation id="674375294223700098">Nezināma servera sertifikāta kļūda.</translation>
<translation id="6753269504797312559">Politikas vērtība</translation>
<translation id="6757797048963528358">Ierīce tika pārslēgta miega režīmā.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profila ceļš</translation>
<translation id="7424977062513257142">Šajā vietnē iegultā lapā ir rakstīts:</translation>
+<translation id="7437289804838430631">Pievienot kontaktinformāciju</translation>
<translation id="7441627299479586546">Politikas subjekts nav pareizs.</translation>
<translation id="7444046173054089907">Šī vietne ir bloķēta</translation>
<translation id="7445762425076701745">Nevar pilnībā apstiprināt servera identifikācijas datus, ar kuru esat savienots. Jums ir izveidots savienojums ar serveri, izmantojot nosaukumu, kas ir derīgs tikai jūsu tīklā, kam ārējā sertifikāta izdevējiestāde nekādā veidā nevar apstiprināt īpašumtiesības. Tā kā dažas sertifikāta izdevējiestādes tāpat izsniegs sertifikātus šādiem nosaukumiem, nav iespējams garantēt, ka jūs esat savienots ar vajadzīgo vietni, nevis uzbrucēju.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">Pārsūtīt</translation>
<translation id="7485870689360869515">Dati netika atrasti.</translation>
<translation id="7508255263130623398">Atgrieztais politikas ierīces ID ir tukšs vai neatbilst pašreizējam ierīces ID.</translation>
+<translation id="7511955381719512146">Iespējams, izmantotajā Wi-Fi tīklā tiks pieprasīts apmeklēt vietni <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Lejupielādēt</translation>
<translation id="7518003948725431193">Šādā tīmekļa adresē netika atrasta neviena tīmekļa lapa: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Jūsu savienojums ar šo vietni nav privāts.</translation>
-<translation id="7535087603100972091">Vērtība</translation>
<translation id="7537536606612762813">Obligāti</translation>
<translation id="7542403920425041731">Pēc apstiprinājuma jūsu kartes informācija tiks kopīgota ar šo vietni.</translation>
<translation id="7542995811387359312">Automātiska kredītkartes numura ievadīšana ir atspējota, jo šai veidlapai netiek izmantots drošs savienojums.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">Šis serveris nevarēja pierādīt, ka šī ir vietne <ph name="DOMAIN" />; tās drošības sertifikāts, iespējams, ir izveidots krāpnieciski. Iespējams, tas ir nepareizas konfigurācijas dēļ vai arī kāds ir ļaunprātīgi izmantojis jūsu savienojumu.</translation>
<translation id="7568593326407688803">Šī lapa ir rakstīta<ph name="ORIGINAL_LANGUAGE" />valodā. Vai vēlaties to tulkot?</translation>
<translation id="7569952961197462199">Vai noņemt kredītkarti no pārlūka Chrome?</translation>
-<translation id="7569983096843329377">Melna</translation>
<translation id="7578104083680115302">Ātri apmaksājiet pirkumus vietnēs un lietotnēs no dažādām ierīcēm, izmantojot kartes, ko esat saglabājis Google sistēmā.</translation>
<translation id="7588950540487816470">Fiziskais tīmeklis</translation>
<translation id="7592362899630581445">Servera sertifikātā ir pārkāpti nosaukuma ierobežojumi.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">Uzbrucēji šajā vietnē var mudināt jūs uz tādu programmu instalēšanu, kuras traucē pārlūkošanu (piemēram, mainot sākumlapu vai apmeklētajās vietnēs rādot papildu reklāmas).</translation>
<translation id="7674629440242451245">Vai jūs interesē jaunas Chrome funkcijas? Izmēģiniet izstrādātāja versiju vietnē chrome.com/dev.</translation>
<translation id="7682287625158474539">Piegāde</translation>
+<translation id="7699293099605015246">Raksti pašlaik nav pieejami</translation>
<translation id="7701040980221191251">Neviens</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Apmeklēt vietni <ph name="SITE" /> (nav droša)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifikāts</translation>
<translation id="7716147886133743102">Bloķēja jūsu administrators</translation>
<translation id="7716424297397655342">Šo vietni nevar ielādēt no kešatmiņas</translation>
+<translation id="7723047071702270851">Kartes informācijas rediģēšana</translation>
<translation id="774634243536837715">Bloķēts bīstams saturs</translation>
<translation id="7752995774971033316">Netiek pārvaldīts</translation>
<translation id="7755287808199759310">Lai atbloķētu, vēsieties pie vecāka</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">Pievienot adresi</translation>
<translation id="777702478322588152">Prefektūra</translation>
<translation id="7791543448312431591">Pievienot</translation>
+<translation id="7793553086574152071">Lai nākamreiz veiktu maksājumu ātrāk, saglabājiet šīs kartes datus savā Google kontā.</translation>
<translation id="7793809570500803535">Tīmekļa lapa vietnē <ph name="SITE" /> var īslaicīgi nebūt pieejama, vai tā var būt pārvietota uz jaunu tīmekļa adresi.</translation>
<translation id="7800304661137206267">Savienojums ir šifrēts, izmantojot <ph name="CIPHER" />, ar <ph name="MAC" /> ziņojumu autentifikācijai un <ph name="KX" /> kā atslēgu apmaiņas mehānismu.</translation>
+<translation id="7802523362929240268">Vietne ir uzticama</translation>
<translation id="780301667611848630">Nē, paldies</translation>
<translation id="7805768142964895445">Statuss</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vai noņemt veidlapas ieteikumu no pārlūka Chrome?</translation>
<translation id="7815407501681723534">Meklējot pēc virknes “<ph name="SEARCH_STRING" />”, tika atrasti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
+<translation id="782886543891417279">Iespējams, izmantotajā Wi-Fi tīklā (<ph name="WIFI_NAME" />) tiks pieprasīts apmeklēt pieteikšanās lapu.</translation>
<translation id="785549533363645510">Tomēr jūs neesat neredzams. Pārlūkojot inkognito režīmā, jūsu pārlūkošanas darbības netiek slēptas no jūsu darba devēja, interneta pakalpojumu sniedzēja vai apmeklētajām vietnēm.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Tiek pieņemtas debetkartes un priekšapmaksas kartes.</translation>
+<translation id="7878562273885520351">Iespējams, jūsu parole ir apdraudēta</translation>
<translation id="7887683347370398519">Pārbaudiet CVC kodu un mēģiniet vēlreiz.</translation>
<translation id="79338296614623784">Ievadiet derīgu tālruņa numuru</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Servera sertifikāts vēl nav apstiprināts.</translation>
-<translation id="7942349550061667556">Sarkana</translation>
<translation id="7947285636476623132">Pārbaudiet derīguma termiņa gadu un mēģiniet vēlreiz.</translation>
<translation id="7951415247503192394">(32 bitu)</translation>
<translation id="7956713633345437162">Mobilās grāmatzīmes</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">Vaicāt (pēc noklusējuma)</translation>
<translation id="8041089156583427627">Sūtīt atsauksmes</translation>
<translation id="8041940743680923270">Izmantot globālo noklusējumu (Vaicāt)</translation>
+<translation id="8057711352706143257">Programmatūra <ph name="SOFTWARE_NAME" /> nav pareizi konfigurēta. Atinstalējot programmatūru <ph name="SOFTWARE_NAME" />, parasti problēma tiek novērsta. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Rakstu neizdevās skatīt.</translation>
<translation id="8091372947890762290">Aktivizācija vēl nav apstiprināta serverī.</translation>
+<translation id="8094917007353911263">Iespējams, izmantotajā tīklā tiks pieprasīts apmeklēt vietni <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Maksājuma veids</translation>
<translation id="8118489163946903409">Maksājuma veids</translation>
+<translation id="8127301229239896662">Programmatūra <ph name="SOFTWARE_NAME" /> netika pareizi instalēta datorā vai tīklā. Lūdziet IT administratoram atrisināt šo problēmu.</translation>
<translation id="8131740175452115882">Apstiprināt</translation>
<translation id="8134994873729925007">Nevarēja atrast <ph name="HOST_NAME" /> servera <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Dators tika pārslēgts miega režīmā.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">Sazinieties ar tīkla administratoru, ja neesat pārliecināts, ko tas nozīmē.</translation>
<translation id="8293206222192510085">Pievienot grāmatzīmi</translation>
<translation id="8294431847097064396">Avots</translation>
+<translation id="8298115750975731693">Iespējams, izmantotajā Wi-Fi tīklā (<ph name="WIFI_NAME" />) tiks pieprasīts apmeklēt vietni <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Nevar izveidot privātu savienojumu ar <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, jo jūsu ierīcē iestatītais datums un laiks (<ph name="DATE_AND_TIME" />) nav pareizs. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8308427013383895095">Tulkošana neizdevās, jo radās problēma ar tīkla savienojumu.</translation>
<translation id="8332188693563227489">Piekļuve vietnei <ph name="HOST_NAME" /> tika noraidīta</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Nesen aizvērtas</translation>
<translation id="8874824191258364635">Ievadiet derīgu kartes numuru</translation>
<translation id="8876793034577346603">Neizdevās parsēt tīkla konfigurāciju.</translation>
-<translation id="8889402386540077796">Nokrāsa</translation>
<translation id="8891727572606052622">Nederīgs starpniekservera režīms.</translation>
<translation id="889901481107108152">Diemžēl šis eksperiments nav pieejams jūsu platformā.</translation>
<translation id="8903921497873541725">Tuvināt</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>
+<translation id="893332455753468063">Vārda pievienošana</translation>
<translation id="8938939909778640821">Atbalstītās kredītkartes un priekšapmaksas kartes</translation>
+<translation id="8957210676456822347">Caurlaides lapas autorizācija</translation>
<translation id="8971063699422889582">Servera sertifikātam ir beidzies derīguma termiņš.</translation>
-<translation id="8986494364107987395">Automātiski sūtīt lietošanas statistiku un avāriju pārskatus uzņēmumam Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Vietnē, kura tiks atvērta, ir kaitīgas programmas</translation>
<translation id="8997023839087525404">Serveris uzrādīja sertifikātu, kas netika publiski atklāts, izmantojot Certificate Transparency politiku. Šī ir prasība noteiktiem sertifikātiem, lai nodrošinātu to uzticamību un aizsardzību pret uzbrucējiem.</translation>
<translation id="9001074447101275817">Starpniekserveris <ph name="DOMAIN" /> pieprasa lietotājvārdu un paroli.</translation>
<translation id="9005998258318286617">Neizdevās ielādēt PDF dokumentu.</translation>
+<translation id="9008201768610948239">Ignorēt</translation>
<translation id="901974403500617787">Atzīmes, kas attiecas uz visu sistēmu, var iestatīt tikai īpašnieks: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Jānorāda kartes norēķinu adrese</translation>
<translation id="9020542370529661692">Šī lapa ir tulkota <ph name="TARGET_LANGUAGE" /> valodā.</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Jūs centāties piekļūt <ph name="DOMAIN" />, bet serveris piedāvāja nederīgu sertifikātu.</translation>
<translation id="9050666287014529139">Ieejas frāze</translation>
<translation id="9065203028668620118">Labot</translation>
-<translation id="9068849894565669697">Krāsas izvēle</translation>
<translation id="9069693763241529744">Bloķēja paplašinājums</translation>
<translation id="9076283476770535406">Vietnē var būt pieaugušajiem paredzēts saturs</translation>
<translation id="9078964945751709336">Nepieciešama plašāka informācija.</translation>
+<translation id="9080712759204168376">Pasūtījuma kopsavilkums</translation>
<translation id="9103872766612412690">Vietnē <ph name="SITE" /> informācijas aizsargāšanai parasti tiek izmantota šifrēšana. Kad pārlūkā Chromium tika mēģināts izveidot savienojumu ar vietni <ph name="SITE" />, šoreiz tā nosūtīja neparastus un nepareizus akreditācijas datus. Iespējams, tas notika, jo uzbrucējs mēģināja uzdoties par vietni <ph name="SITE" />, vai arī Wi-Fi pierakstīšanās ekrāns pārtrauca savienojumu. Jūsu informācija joprojām ir drošībā, jo pārlūks Chromium pārtrauca savienojumu, pirms tika veikta jebkādu datu apmaiņa.</translation>
+<translation id="9106062320799175032">Norēķinu adreses pievienošana</translation>
+<translation id="910908805481542201">Palīdzēt man novērst problēmu</translation>
+<translation id="9128870381267983090">Izveidot savienojumu ar tīklu</translation>
<translation id="9137013805542155359">Rādīt oriģinālo</translation>
<translation id="9137248913990643158">Pirms šīs lietotnes izmantošanas, lūdzu, palaidiet pārlūku Chrome un pierakstieties tajā.</translation>
<translation id="9148507642005240123">&amp;Atsaukt labojumu</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> izmanto neatbalstītu protokolu.</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="9215416866750762878">Lietojumprogrammas darbības dēļ pārlūkā Chrome nevar izveidot drošu savienojumu ar šo vietni</translation>
<translation id="9219103736887031265">Attēli</translation>
<translation id="933612690413056017">Nav interneta savienojuma</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Nav}=1{1 vienums}zero{# vienumi}one{# vienums}other{# vienumi}}</translation>
<translation id="981121421437150478">Bezsaistē</translation>
<translation id="988159990683914416">Attīstītāja konstrukcija</translation>
+<translation id="989988560359834682">Rediģēt adresi</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Programmatūra <ph name="SOFTWARE_NAME" /> netika pareizi instalēta datorā vai tīklā.
+ &lt;ul&gt;
+ &lt;li&gt;Mēģiniet atinstalēt vai atspējot programmatūru <ph name="SOFTWARE_NAME" />.&lt;/li&gt;
+ &lt;li&gt;Mēģiniet izveidot savienojumu ar citu tīklu.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index 69d7d4e6469..3d317da2c61 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">ഡെസ്‌ക്‌ടോപ്പ് ബുക്ക്‌മാർക്കുകൾ</translation>
<translation id="1074497978438210769">സുരക്ഷിതമല്ല</translation>
<translation id="1080116354587839789">അനുയോജ്യമായ വീതിയിലാക്കുക</translation>
+<translation id="1088860948719068836">കാർഡിലെ പേര് ചേർക്കുക</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> എല്ലായ്പ്പോഴും വിവര്‍ത്തനം ചെയ്യുക </translation>
+<translation id="1103778128462718200">സംരക്ഷിച്ച എല്ലാ പാസ്‌വേഡുകളും കാണിക്കുക...</translation>
<translation id="1107591249535594099">പരിശോധിച്ചെങ്കിൽ, വേഗതേറിയ ഫോം പൂരിപ്പിക്കലിനായി ഈ ഉപകരണത്തിൽ നിങ്ങളുടെ കാർഡിന്റെ ഒരു പകർപ്പ് Chrome സംഭരിക്കും.</translation>
<translation id="1111153019813902504">അടുത്തിടെ ഉപയോഗിച്ച ബുക്ക്‌മാർക്കുകൾ</translation>
<translation id="1113869188872983271">&amp;പുനഃക്രമീകരിക്കുന്നത് പഴയപടിയാക്കുക</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (സമന്വയിപ്പിച്ചു)</translation>
<translation id="1263231323834454256">വായനാ ലിസ്റ്റ്</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />-ന് ക്യാപ്‌ച്ചർ ചെയ്‌ത ക്രാഷ് റിപ്പോർട്ട് (ഇതുവരെ അപ്‌ലോഡുചെയ്‌തിട്ടോ അവഗണിച്ചിട്ടോ ഇല്ല)</translation>
+<translation id="1270502636509132238">പിക്കപ്പ് രീതി</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> ഇഷ്യൂ ചെയ്‌തത്</translation>
<translation id="1285320974508926690">ഈ സൈറ്റ് ഒരിക്കലും വിവര്‍‌ത്തനം ചെയ്യരുത്</translation>
<translation id="129553762522093515">സമീപകാലത്ത് അടച്ചവ</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">കണക്ഷനുവേണ്ടി കാക്കുന്നു…</translation>
<translation id="153384715582417236">ഇപ്പോൾ ഇത്രമാത്രമേ ലഭ്യമായിട്ടുള്ളൂ</translation>
<translation id="1549470594296187301">ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ JavaScript പ്രവർത്തനക്ഷമമാക്കിയിരിക്കണം.</translation>
-<translation id="1555130319947370107">നീല</translation>
<translation id="1559528461873125649">അത്തരത്തിലുള്ള ഫയലോ ഡയറക്ടറിയോ ഇല്ല</translation>
<translation id="1583429793053364125">ഈ വെബ്‌പേജ് പ്രദർശിപ്പിക്കുമ്പോൾ എന്തോ കുഴപ്പം സംഭവിച്ചു.</translation>
<translation id="1592005682883173041">പ്രാദേശിക ഡാറ്റ ആക്‌സസ്സ്</translation>
<translation id="1594030484168838125">തിരഞ്ഞെടുക്കുക</translation>
-<translation id="161042844686301425">സിയാൻ</translation>
<translation id="1620510694547887537">ക്യാമറ</translation>
<translation id="1629803312968146339">Chrome ഈ കാർഡ് സംരക്ഷിക്കണോ?</translation>
<translation id="1639239467298939599">ലോഡുചെയ്യുന്നു</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ഈ സൈറ്റ് സന്ദർശിക്കാൻ നിങ്ങൾക്ക് <ph name="NAME" /> എന്നയാളിൽ നിന്നുള്ള അനുമതി ആവശ്യമാണ്</translation>
<translation id="1721424275792716183">* ഫീൽഡ് ആവശ്യമാണ്</translation>
+<translation id="1727741090716970331">ശരിയായ കാർഡ് നമ്പർ ചേർക്കുക</translation>
<translation id="1728677426644403582">നിങ്ങൾ ഒരു വെബ് പേജിന്റെ ഉറവിടമാണ് കാണുന്നത്</translation>
<translation id="173080396488393970">ഇത്തരത്തിലുള്ള കാർഡ് അനുയോജ്യമല്ല</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">സീരിയലൈസേഷൻ പിശക്</translation>
<translation id="1974060860693918893">നൂതനം</translation>
<translation id="1978555033938440688">ഫേംവെയർ പതിപ്പ്</translation>
-<translation id="1995859865337580572">നിങ്ങളുടെ CVC പരിശോധിച്ചുറപ്പിക്കുക</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{കൂടാതെ 1 കൂടി}other{എന്നിവയും # എണ്ണവും കൂടി}}</translation>
<translation id="2025186561304664664">പ്രോക്സി സ്വയമേവ കോൺഫിഗർ ചെയ്യാൻ സജ്ജമാക്കി.</translation>
<translation id="2030481566774242610">നിങ്ങൾ ഉദ്ദേശിച്ചത് <ph name="LINK" /> ആണോ?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">പഴയപടിയാക്കുക</translation>
<translation id="20817612488360358">സിസ്റ്റം പ്രോക്‌സി ക്രമീകരണം ഉപയോഗിക്കുന്നതിനായി സജ്ജമാക്കി, പക്ഷെ ഒരു സ്‌പഷ്‌ടമായ പ്രോക്‌സി കോൺഫിഗറേഷനും അതോടൊപ്പം നിർദ്ദേശിച്ചിരിക്കുന്നു.</translation>
<translation id="2086652334978798447">Google നിർദ്ദേശിച്ച, വ്യക്തിപരമാക്കിയ ഉള്ളടക്കം സ്വന്തമാക്കാൻ, Chrome-ൽ സൈൻ ഇൻ ചെയ്യുക.</translation>
+<translation id="2091887806945687916">ശബ്‌ദം</translation>
<translation id="2094505752054353250">ഡൊമെയ്‌ൻ പൊരുത്തമില്ലായ്‌മ</translation>
<translation id="2096368010154057602">വകുപ്പ്</translation>
<translation id="2108755909498034140">നിങ്ങളുടെ കമ്പ്യൂട്ടർ റീസ്‌റ്റാർട്ടുചെയ്യുക</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"> <ph name="POLICY_NAME" /> എന്നതിനാൽ മറികടന്നതിനാൽ ഇത് അവഗണിച്ചു.</translation>
<translation id="2138201775715568214">വിളിപ്പാടരികെയുള്ള ഫിസിക്കൽ വെബ് പേജുകൾ തിരയുന്നു</translation>
<translation id="213826338245044447">മൊബൈൽ ബുക്ക്‌മാർക്കുകൾ</translation>
+<translation id="214556005048008348">പേയ്‌മെന്‍റ് റദ്ദാക്കുക</translation>
<translation id="2147827593068025794">പശ്ചാത്തലം സമന്വയിപ്പിക്കൽ</translation>
+<translation id="2148613324460538318">കാർഡ് ചേർക്കുക</translation>
<translation id="2154054054215849342">നിങ്ങളുടെ ഡൊമെയ്‌നിന് വേണ്ടി സമന്വയം ലഭ്യമല്ല</translation>
<translation id="2154484045852737596">കാർഡ് എഡിറ്റുചെയ്യുക</translation>
<translation id="2166049586286450108">പൂർണ്ണമായ അഡ്‌മിൻ ആക്‌സസ്സ്</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{ഒരു വിലാസം}other{# വിലാസങ്ങൾ}}</translation>
<translation id="2187317261103489799">കണ്ടെത്തുക (ഡിഫോൾട്ട്)</translation>
<translation id="2202020181578195191">കാലഹരണപ്പെടുന്ന ശരിയായ വർഷം നല്‍കുക</translation>
+<translation id="2209523182407020534">ആന്‍റിവൈറസ്, ഫയർവാൾ, വെബ് ഫിൽട്ടറിംഗ് ഉൾപ്പെടെയുള്ള ആപ്പുകൾ അല്ലെങ്കിൽ പ്രോക്‌സി സോഫ്റ്റ്‌വെയർ ഈ പിശകിന് കാരണമാകുന്നു.</translation>
<translation id="2212735316055980242">നയം കണ്ടെത്തിയില്ല</translation>
<translation id="2213606439339815911">എൻട്രികൾ ലഭ്യമാക്കുന്നു...</translation>
<translation id="2218879909401188352">നിലവിൽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> എന്നതിലുള്ള അക്രമികൾക്ക് നിങ്ങളുടെ ഉപകരണം കേടുവരുത്തുന്ന ആപ്പുകൾ ഇൻസ്‌റ്റാൾ ചെയ്യാനോ മൊബൈൽ ബില്ലിലേക്ക് നിങ്ങളറിയാതെ നിരക്കുകൾ ചേർക്കാനോ നിങ്ങളുടെ വ്യക്തിഗത വിവരങ്ങൾ മോഷ്‌ടിക്കാനോ കഴിയും. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടുതലറിയുക<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">പിന്നിലേക്ക് പോകുക</translation>
<translation id="2503184589641749290">ഡെബിറ്റ് കാർഡുകളും പ്രീപെയ്ഡ് കാർഡുകളും സ്വീകരിക്കുന്നു</translation>
<translation id="2515629240566999685">നിങ്ങളുടെ ഏരിയയിലെ സിഗ്‌നൽ പരിശോധിക്കുന്നു</translation>
+<translation id="2524461107774643265">കൂടുതൽ വിവരങ്ങൾ ചേർക്കുക</translation>
+<translation id="2536110899380797252">വിലാസം ചേർക്കുക</translation>
<translation id="2539524384386349900">കണ്ടെത്തുക</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" />, അസാധുവായ ഒരു പ്രതികരണം അയച്ചു.</translation>
<translation id="2556876185419854533">&amp;എഡിറ്റുചെയ്യുന്നത് പഴയപടിയാക്കുക</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium-ത്തിന് ഇപ്പോൾ നിങ്ങളുടെ കാർഡ് സ്ഥിരീകരിക്കാനായില്ല. പിന്നീട് വീണ്ടും ശ്രമിക്കുക.</translation>
<translation id="2705137772291741111">ഈ സൈറ്റിന്റെ സംരക്ഷിച്ച (കാഷെ ചെയ്‌ത) പതിപ്പ് വായിക്കാനാകാത്തതാണ്.</translation>
<translation id="2709516037105925701">ഓട്ടോഫില്‍</translation>
+<translation id="2710942282213947212">വെബിലേക്ക് സുരക്ഷിതമായി കണക്റ്റുചെയ്യുന്നതിൽ നിന്ന് Chromium-ത്തിനെ നിങ്ങളുടെ കമ്പ്യൂട്ടറിലെ സോഫ്റ്റ്‌വെയർ തടയുന്നു</translation>
<translation id="2712173769900027643">അനുമതി ചോദിക്കുക</translation>
-<translation id="2713444072780614174">വെള്ള</translation>
<translation id="2720342946869265578">സമീപമുള്ളവ</translation>
<translation id="2721148159707890343">അഭ്യർത്ഥന വിജയിച്ചു</translation>
<translation id="2728127805433021124">ഒരു ദുര്‍ബ്ബല സിഗ്നേച്ചര്‍ അല്‍ഗോരിതം ഉപയോഗിച്ചുകൊണ്ട് സെര്‍വറിന്‍റെ സര്‍ട്ടിഫിക്കറ്റ് ഒപ്പുവച്ചു.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">ഒരു നെറ്റ്‌വർക്ക് മാറ്റം കണ്ടെത്തി.</translation>
<translation id="2916038427272391327">മറ്റ് പ്രോഗ്രാമുകൾ അടയ്‌ക്കുക</translation>
<translation id="2922350208395188000">സെര്‍വറിന്‍റെ സര്‍ട്ടിഫിക്കറ്റ് പരിശോധിക്കാന്‍ കഴിയില്ല.</translation>
+<translation id="2925673989565098301">ഡെലിവറി രീതി</translation>
<translation id="2928905813689894207">ബില്ലിംഗ് വിലാസം</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> എണ്ണവും}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> എണ്ണവും}}</translation>
<translation id="2941952326391522266">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; <ph name="DOMAIN2" /> എന്നതിൽ നിന്നുള്ളതാണ് അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റ്. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">തെറ്റായ നയ തരം</translation>
<translation id="3032412215588512954">ഈ സൈറ്റ് റീലോഡുചെയ്യണോ?</translation>
<translation id="3037605927509011580">കഷ്ടം!</translation>
+<translation id="3039538478787849737">Google-ൽ കാർഡ് സംരക്ഷിക്കണോ?</translation>
<translation id="3041612393474885105">സര്‍‌ട്ടിഫിക്കറ്റ് വിവരങ്ങള്‍‌</translation>
<translation id="3063697135517575841">Chrome-ന് ഇപ്പോൾ നിങ്ങളുടെ കാർഡ് സ്ഥിരീകരിക്കാനായില്ല. പിന്നീട് വീണ്ടും ശ്രമിക്കുക.</translation>
<translation id="3064966200440839136">ഒരു എക്‌സ്‌റ്റേണൽ അപ്ലിക്കേഷൻ വഴി പണമടയ്‌ക്കാൻ അദൃശ്യതാ സംവിധാനം ഒഴിവാക്കുന്നു. തുടരണോ?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">താൽക്കാലികമായ സെർവർ പിശക്</translation>
<translation id="3154506275960390542">സുരക്ഷിതമായി സമർപ്പിക്കാൻ സാധിക്കാത്ത ഒരു ഫോം ഈ പേജിൽ ഉ‌ണ്ട്. അയയ്ക്കുന്ന സമയത്ത് നിങ്ങളുടെ ഡാറ്റ മറ്റുള്ളവര്‍‌ക്ക് കാണാനാകും, അല്ലെങ്കിൽ സെർവറിലേക്ക് എത്തും ‌മുമ്പ് ‌ഒരു അക്രമിക്ക് പരിഷ്‌ക്കരിക്കാൻ കഴിയും.</translation>
<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
+<translation id="3162559335345991374">നിങ്ങൾ ഉപയോഗിക്കുന്ന Wi-Fi അതിന്റെ ലോഗിൻ പേജ് സന്ദർശിക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടാം.</translation>
<translation id="3167968892399408617">ആൾമാറാട്ട ടാബുകളിൽ നിങ്ങൾ കാണുന്ന പേജുകൾ, ആൾമാറാട്ട ടാബുകൾ എല്ലാം അടച്ചതിനുശേഷം ബ്രൗസർ ചരിത്രത്തിലോ കുക്കി സ്റ്റോറിലോ തിരയൽ ചരിത്രത്തിലോ ഉണ്ടാകില്ല. നിങ്ങൾ ഡൗൺലോഡുചെയ്യുന്ന ഫയലുകളോ സൃഷ്‌ടിക്കുന്ന ബുക്ക്‌മാർക്കുകളോ എല്ലാം സൂക്ഷിക്കും.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">ഐലന്‍ഡ്</translation>
@@ -286,6 +296,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">പേയ്‌മെന്റ് റദ്ദാക്കുക</translation>
<translation id="3207960819495026254">ബുക്ക്‌മാർക്കുചെയ്‌തു</translation>
+<translation id="3211223744486044430">അടുത്ത പ്രാവശ്യം വേഗത്തിൽ പണമടയ്ക്കാൻ, നിങ്ങളുടെ Google അക്കൗണ്ടിലും ഈ ഉപകരണത്തിലും കാർഡ് സംരക്ഷിക്കുക.</translation>
<translation id="3225919329040284222">ബിൽട്ട്-ഇൻ പ്രതീക്ഷകള്‍ക്ക് പൊരുത്തപ്പെടാത്ത സര്‍ട്ടിഫിക്കറ്റാണ് സെര്‍വര്‍ അവതരിപ്പിച്ചത്. നിങ്ങളെ സംരക്ഷിക്കുന്നതിലേക്കായുള്ള നിശ്ചിത, ഉന്നത-സുരക്ഷാ വെബ്‌സൈറ്റുകൾക്കായാണ് ഈ പ്രതീക്ഷകൾ ഉൾപ്പെടുത്തിയിരിക്കുന്നത്.</translation>
<translation id="3226128629678568754">പേജ് ലോഡുചെയ്യുന്നതിനാവശ്യമായ ഡാറ്റ വീണ്ടും സമർപ്പിക്കാൻ വീണ്ടും ലോഡുചെയ്യുക ബട്ടൺ അമർത്തുക.</translation>
<translation id="3227137524299004712">മൈക്രോഫോൺ</translation>
@@ -300,7 +311,6 @@
<translation id="3303855915957856445">തിരയൽ ഫലങ്ങളൊന്നും കണ്ടെത്തിയില്ല</translation>
<translation id="3305707030755673451"><ph name="TIME" />-ന് നിങ്ങളുടെ സമന്വയ പാസ്‌ഫ്രെയ്‌സ് ഉപയോഗിച്ച് ഡാറ്റ എൻക്രിപ്‌റ്റുചെയ്‌തു. സമന്വയം ആരംഭിക്കുന്നതിന് ഇത് നൽകുക.</translation>
<translation id="3320021301628644560">ബില്ലിംഗ് വിലാസം ചേർക്കുക</translation>
-<translation id="3329013043687509092">സാച്ചുറേഷൻ</translation>
<translation id="333371639341676808">അധികമുള്ള ഡയലോഗുകള്‍ സൃഷ്ടിക്കുന്നതില്‍ നിന്ന് ഈ പേജിനെ തടയൂ.</translation>
<translation id="3338095232262050444">സുരക്ഷിതം</translation>
<translation id="3340978935015468852">ക്രമീകരണങ്ങൾ</translation>
@@ -319,6 +329,7 @@
<translation id="3380864720620200369">ക്ലയന്റ് ID:</translation>
<translation id="3391030046425686457">ഡെലിവർ ചെയ്യേണ്ട വിലാസം</translation>
<translation id="3395827396354264108">പിക്കപ്പ് രീതി</translation>
+<translation id="3399952811970034796">ഡെലിവറി നൽകേണ്ട വിലാസം</translation>
<translation id="3422248202833853650">ഇടം സൃഷ്‌ടിക്കാൻ മറ്റ് പ്രോഗ്രാമുകളിൽ നിന്ന് പുറത്തുകടക്കുന്നത് പരീക്ഷിക്കൂ.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> നിലവിൽ ലഭ്യമല്ല.</translation>
<translation id="3427092606871434483">അനുവദിക്കുക (ഡിഫോൾട്ട്)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375">ക്രാഷ് റിപ്പോർട്ട് <ph name="CRASH_TIME" />-ന് ക്യാപ്‌ചർ ചെയ്‌ത്, <ph name="UPLOAD_TIME" />-ന് അപ്‌ലോഡുചെയ്‌തു</translation>
<translation id="3681007416295224113">സര്‍‌ട്ടിഫിക്കറ്റ് വിവരങ്ങള്‍‌</translation>
<translation id="3690164694835360974">ലോഗിൻ ചെയ്യുന്നത് സുരക്ഷിതമല്ല</translation>
+<translation id="3704162925118123524">നിങ്ങൾ ഉപയോഗിക്കുന്ന നെറ്റ്‌വർക്കിനായി, ഇതിന്റെ ലോഗിൻ പേജ് സന്ദർശിക്കേണ്ടിവരാം.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ലോഡ്ചെയ്യുന്നു...</translation>
<translation id="3712624925041724820">ലൈസൻസുകൾ കാലഹരണപ്പെട്ടു</translation>
<translation id="3714780639079136834">മൊബൈൽ ഡാറ്റ അല്ലെങ്കിൽ Wi-Fi ഓണാക്കുന്നു</translation>
+<translation id="3715597595485130451">Wi-Fi-യിലേക്ക് കണക്റ്റുചെയ്യുക</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />പ്രോക്‌സിയും ഫയർവാളും DNS കോൺഫിഗറേഷനും പരിശോധിക്കുന്നു<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">നിങ്ങളുടെ സുരക്ഷയെ ബാധിച്ചേക്കാവുന്ന അപകട സാധ്യതകളെക്കുറിച്ച് മനസ്സിലാക്കുകയാണെങ്കിൽപ്പോലും, പ്രോഗ്രാമുകൾ നീക്കംചെയ്യുന്നതിനു മുമ്പ് <ph name="BEGIN_LINK" />ഈ സുരക്ഷിതമല്ലാത്ത സൈറ്റ്<ph name="END_LINK" /> നിങ്ങൾക്ക് സന്ദർശിക്കാം (ശുപാർശചെയ്യുന്നില്ല).</translation>
<translation id="3739623965217189342">നിങ്ങൾ പകർത്തിയ ലിങ്ക്</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;ചേർക്കുന്നത് പഴയപടിയാക്കുക</translation>
<translation id="404928562651467259">മുന്നറിയിപ്പ്</translation>
<translation id="4058922952496707368">കീ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">ശരിയായ വിലാസം ചേർക്കുക</translation>
<translation id="4072486802667267160">നിങ്ങളുടെ ഓർഡർ പ്രോസസ്സ് ചെയ്യുന്നതിൽ ഒരു പിശകുണ്ടായി. വീണ്ടും ശ്രമിച്ചുനോക്കൂ.</translation>
<translation id="4075732493274867456">ഒരു സാധാരണ SSL പ്രോട്ടോക്കോൾ പതിപ്പിനെയോ സൈഫർ സ്യൂട്ടിനെയോ ക്ലയന്റും സെർവറും പിന്തുണയ്‌ക്കില്ല.</translation>
<translation id="4079302484614802869">പ്രോക്‌സി കോൺഫിഗറേഷൻ .pac സ്‌ക്രിപ്റ്റ് URL ഉപയോഗിക്കുന്നതിനായി സജ്ജീകരിച്ചിരിക്കുന്നു, സ്ഥിരമായ പ്രോക്‌സി സെർവറുകൾ ഉപയോഗിക്കുന്നതിനായല്ല.</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">ഉപകരണ സീരിയൽ നമ്പർ അസാധുവാണ്</translation>
<translation id="410351446219883937">സ്വയം പ്ലേചെയ്യൽ</translation>
<translation id="4103763322291513355">ബ്ലാക്ക്‌ലിസ്റ്റിൽപ്പെട്ട URL-കളുടെ ലിസ്റ്റും നിങ്ങളുടെ സിസ്റ്റം അഡ്‌മിനിസ്‌ട്രേറ്റർ നടപ്പിലാക്കിയ മറ്റ് നയങ്ങളും കാണുന്നതിന് &lt;strong&gt;chrome://policy&lt;/strong&gt; സന്ദർശിക്കുക.</translation>
-<translation id="4115378294792113321">മജന്ത</translation>
<translation id="4116663294526079822">ഈ സൈറ്റിൽ എല്ലായ്‌പ്പോഴും അനുവദിക്കുക</translation>
<translation id="4117700440116928470">നയ സ്‌കോപ്പ് പിന്തുണയ്ക്കുന്നില്ല.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{മറ്റൊരെണ്ണം}other{മറ്റ് # എണ്ണം}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719">നിങ്ങള്‍‌ <ph name="DOMAIN" /> എന്നതില്‍‌ എത്താന്‍‌ ശ്രമിച്ചു, പക്ഷേ സെര്‍‌വര്‍‌ നൽകിയ സര്‍‌ട്ടിഫിക്കറ്റ് അത് നല്‍‌കിയ ആള്‍‌ അസാധുവാക്കി. സെര്‍‌വര്‍‌ നല്‍‌കിയ സുരക്ഷാ ക്രെഡന്‍‌ഷ്യലുകള്‍‌ തികച്ചും വിശ്വാ‍സയോഗ്യമല്ല എന്നാണ് ഇതിനര്‍‌ത്ഥം. നിങ്ങള്‍‌ ഒരു ആക്രമണകാരിയുമായിട്ടാകാം ആശയവിനിമയം നടത്തുന്നത്.</translation>
<translation id="4394049700291259645">അപ്രാപ്‌തമാക്കുക</translation>
<translation id="4406896451731180161">തിരയൽ ഫലങ്ങൾ</translation>
+<translation id="4415426530740016218">പിക്കപ്പ് വിലാസം</translation>
<translation id="4424024547088906515">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റ് Chrome-ന് പരിചയമില്ലാത്തതാണ്. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />, നിങ്ങളുടെ ലോഗിൻ സർട്ടിഫിക്കറ്റിന് അംഗീകരിച്ചിട്ടില്ല, അല്ലെങ്കിൽ അങ്ങനെയൊരെണ്ണം നൽകിയിട്ടില്ലായിരിക്കാം.</translation>
<translation id="443673843213245140">പ്രോക്‌സി ഉപയോഗം അപ്രാപ്‌തമാക്കി പക്ഷെ ഒരു വ്യക്തമായ പ്രോക്‌സി കോൺഫിഗറേഷൻ നിർദ്ദേശിച്ചു.</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">ഫ്ലാഷ്</translation>
<translation id="4558551763791394412">നിങ്ങളുടെ വിപുലീകരണങ്ങൾ പ്രവർത്തനരഹിതമാക്കുന്നത് പരീക്ഷിക്കുക.</translation>
<translation id="457875822857220463">ഡെലിവറി വിവരങ്ങൾ</translation>
+<translation id="4582800630050655161">നിങ്ങളുടെ Google അക്കൗണ്ടിലേക്കുള്ള ആക്‌സസ് നഷ്‌ടമാകാനോ നിങ്ങളുടെ ഐഡന്‍റിറ്റി മോഷ്ടിക്കപ്പെടാനോ സാധ്യതയുണ്ട്. ഇപ്പോൾ തന്നെ പാസ്‍വേഡ് മാറ്റാൻ Chromium നിർദ്ദേശിക്കുന്നു.</translation>
<translation id="4587425331216688090">Chrome-ൽ നിന്ന് വിലാസം നീക്കംചെയ്യണോ?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> എന്നതിലേക്കുള്ള നിങ്ങളുടെ കണക്ഷനെ ആധുനിക സൈഫർ സ്യൂട്ട് ഉപയോഗിച്ച് എൻക്രിപ്റ്റുചെയ്‌തിരിക്കുന്നു.</translation>
<translation id="4594403342090139922">&amp;ഇല്ലാതാക്കുന്നത് പഴയപടിയാക്കുക</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റിൽ പിശകുകൾ അടങ്ങിയിരിക്കുന്നു. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
<translation id="4690462567478992370">അസാധുവായ ഒരു സർട്ടിഫിക്കറ്റ് ഉപയോഗിക്കുന്നത് നിർത്തുക</translation>
+<translation id="4690954380545377795">നിങ്ങളുടെ Google അക്കൗണ്ടിലേക്കുള്ള ആക്‌സസ് നഷ്‌ടമാകാനോ നിങ്ങളുടെ ഐഡന്‍റിറ്റി മോഷ്ടിക്കപ്പെടാനോ സാധ്യതയുണ്ട്. ഇപ്പോൾ തന്നെ പാസ്‍വേഡ് മാറ്റാൻ Chrome നിർദ്ദേശിക്കുന്നു.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">നിങ്ങളുടെ കണക്ഷൻ തടസ്സപ്പെട്ടു</translation>
<translation id="471880041731876836">ഈ സൈറ്റ് സന്ദർശിക്കാൻ നിങ്ങൾക്ക് അനുമതി ആവശ്യമില്ല</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows നെറ്റ്‌വർക്ക് ഡയഗണോസ്‌റ്റിക്‌സ് റൺ ചെയ്യുന്നു<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">നിങ്ങളുടെ പേയ്മെന്റ്</translation>
<translation id="4726672564094551039">നയങ്ങൾ വീണ്ടും ലോഡുചെയ്യുക</translation>
<translation id="4728558894243024398">പ്ലാറ്റ്ഫോം</translation>
<translation id="4736825316280949806">Chromium റീസ്‌റ്റാർട്ടുചെയ്യുക</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">ബാക്കിംഗ് സംഭരണം മോശം അവസ്ഥയിലാണ്</translation>
<translation id="5023310440958281426">നിങ്ങളുടെ അഡ്‌മിനിസ്ട്രേറ്ററുടെ നയങ്ങൾ പരിശോധിക്കുക</translation>
<translation id="5029568752722684782">പകർപ്പ് മായ്‌ക്കുക</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" സോഫ്റ്റ്‌വെയറിന് ഒരു റൂട്ട് സർട്ടിഫിക്കറ്റ് ആവശ്യമാണ്, എന്നാൽ അത് ഇൻസ്‌റ്റാൾ ചെയ്‌‌തിട്ടില്ല. ഈ പ്രശ്‌നം പരിഹരിക്കാൻ, "<ph name="SOFTWARE_NAME" />" സോഫ്റ്റ്‌വെയറിനുള്ള കോൺഫിഗറേഷൻ നിർദ്ദേശങ്ങൾ ഐടി അഡ്‌മിനിസ്‌ട്രേറ്റർ പരിശോധിക്കേണ്ടതുണ്ട്. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google വിവര്‍ത്തനം എന്നതിനെക്കുറിച്ച് </translation>
<translation id="5039804452771397117">അനുവദിക്കൂ</translation>
<translation id="5040262127954254034">സ്വകാര്യത</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">പരീക്ഷണങ്ങള്‍</translation>
<translation id="5205222826937269299">പേര് ആവശ്യമാണ്</translation>
<translation id="5222812217790122047">ഇമെയിൽ ആവശ്യമാണ്</translation>
+<translation id="522700295135997067">നിങ്ങളുടെ പാസ്‍വേഡ് ഈ സൈറ്റ് ഇപ്പോൾ മോഷ്‌ടിച്ചിരിക്കാം</translation>
+<translation id="5230733896359313003">ഷിപ്പിംഗ് വിലാസം</translation>
<translation id="5251803541071282808">ക്ലൗഡ്</translation>
<translation id="5277279256032773186">ജോലിസ്ഥലത്തുള്ള Chrome ഉപയോഗിക്കുകയാണോ? ബിസിനസ് സ്ഥാപനങ്ങൾക്ക് അവരുടെ ജീവനക്കാർക്ക് വേണ്ടി Chrome ക്രമീകരണം മാനേജുചെയ്യാനാകും. കൂടുതലറിയുക</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />നിങ്ങൾക്ക് വെബിൽ കണക്റ്റുചെയ്യാൻ കഴിയുന്ന തരത്തിൽ താൽക്കാലികമായി സോഫ്റ്റ്‌വെയർ പ്രവർത്തനരഹിതമാക്കുന്നതിന് ഈ ഘട്ടങ്ങൾ പിന്തുടരുക. നിങ്ങൾക്ക് അഡ്‌മിനിസ്ട്രേറ്ററുടെ സവിശേഷാധികാരങ്ങൾ ആവശ്യമായിവരും.<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">ഈ സൈറ്റിലെ നിങ്ങളുടെ കണക്ഷൻ സ്വകാര്യമല്ല. എപ്പോൾ വേണമെങ്കിലും VR മോഡിൽ നിന്ന് പുറത്തുകടക്കാൻ, ഹെഡ്‌സെറ്റ് നീക്കംചെയ്‌ത ശേഷം 'തിരികെ പോകുക' അമർത്തുക.</translation>
<translation id="5299298092464848405">നയം പാഴ്‌സുചെയ്യുന്നതിൽ പിശക്</translation>
+<translation id="5308380583665731573">കണക്‌റ്റുചെയ്യുക</translation>
<translation id="5308689395849655368">ക്രാഷ് റിപ്പോര്‍ട്ടുചെയ്യല്‍ അപ്രാപ്തമാക്കി.</translation>
<translation id="5317780077021120954">സംരക്ഷിക്കുക</translation>
<translation id="5327248766486351172">പേര്</translation>
+<translation id="5332219387342487447">ഷിപ്പിംഗ് രീതി</translation>
<translation id="5355557959165512791">സർട്ടിഫിക്കറ്റ് റദ്ദാക്കിയതിനാൽ നിങ്ങൾക്കിപ്പോൾ <ph name="SITE" /> സന്ദർശിക്കാനാകില്ല. നെറ്റ്‌വർക്ക് പിശകുകളും ആക്രമണങ്ങളും സാധാരണ താൽക്കാലികമായിരിക്കും, അതിനാൽ ഈ പേജ് മിക്കവാറും പിന്നീട് പ്രവർത്തിക്കും.</translation>
<translation id="536296301121032821">നയ ക്രമീകരണങ്ങൾ സംഭരിക്കുന്നതിൽ പരാജയപ്പെട്ടു</translation>
<translation id="5386426401304769735">ഈ സൈറ്റിന്റെ സർട്ടിഫിക്കറ്റ് ചെയിനിൽ SHA-1 ഉപയോഗിച്ച് സൈൻ ചെയ്‌ത ഒരു സർട്ടിഫിക്കറ്റ് അടങ്ങിയിരിക്കുന്നു.</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">കമ്പനി, ഓർഗനൈസേഷൻ അല്ലെങ്കിൽ സ്‌കൂൾ ഇൻട്രാനെറ്റിലെ ഈ സൈറ്റിന്, ബാഹ്യ വെബ്‌സൈറ്റിന് സമാനമായ URL ആണുള്ളത്.
<ph name="LINE_BREAK" />
നിങ്ങളുടെ സിസ്‌റ്റം അഡ്‌മിനിസ്‌ട്രേറ്ററുമായി ബന്ധപ്പെടാൻ ശ്രമിക്കുക.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> കാർഡിനുള്ള സുരക്ഷാ കോഡ് നൽകുക. ഈ കോഡ് സംരക്ഷിക്കപ്പെടില്ല.</translation>
<translation id="5509780412636533143">നിയന്ത്രിത ബുക്കുമാർക്കുകൾ</translation>
<translation id="5510766032865166053">ഇത് നീക്കുകയോ ഇല്ലാതാക്കുകയോ ചെയ്‌തിരിക്കാം.</translation>
<translation id="5523118979700054094">നയത്തിന്റെ പേര്</translation>
<translation id="552553974213252141">വാചകം ശരിയായി എക്‌സ്‌ട്രാക്റ്റുചെയ്‌തോ?</translation>
<translation id="5540224163453853">അഭ്യർത്ഥിച്ച ലേഖനം കണ്ടെത്താനായില്ല.</translation>
+<translation id="5541546772353173584">ഇമെയില്‍‌ ചേര്‍‌ക്കുക</translation>
<translation id="5544037170328430102"><ph name="SITE" /> സൈറ്റിലെ ഒരു എംബഡ് ചെയ്‌ത പേജ് പറയുന്നത്:</translation>
+<translation id="5545756402275714221">നിങ്ങൾക്കുള്ള ലേഖനങ്ങൾ</translation>
<translation id="5556459405103347317">വീണ്ടും ലോഡുചെയ്യുക</translation>
<translation id="5560088892362098740">കാലഹരണപ്പെടല്‍ തീയതി</translation>
<translation id="5565735124758917034">സജീവമാണ്</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">ഇമെയില്‍</translation>
<translation id="5669703222995421982">വ്യക്തിപരമാക്കിയ ഉള്ളടക്കം സ്വന്തമാക്കുക</translation>
<translation id="5675650730144413517">ഈ പേജ് പ്രവർത്തിക്കുന്നില്ല</translation>
+<translation id="5689199277474810259">JSON-ലേക്ക് ‌എക്‌സ്‌പോർട്ട് ചെയ്യുക</translation>
<translation id="5710435578057952990">ഈ വെബ്സൈറ്റിന്റെ വ്യക്തിത്വം പരിശോധിച്ചിട്ടില്ല.</translation>
<translation id="5719499550583120431">പ്രീപെയ്ഡ് കാർഡുകൾ സ്വീകരിക്കുന്നു.</translation>
<translation id="5720705177508910913">നിലവിലെ ഉപയോക്താവ്</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" /> എന്നതിലേക്കുള്ള നിങ്ങളുടെ കണക്ഷൻ കാലഹരണപ്പെട്ട സൈഫർ സ്യൂട്ട് ഉപയോഗിച്ച് എൻക്രിപ്റ്റുചെയ്‌തിരിക്കുന്നു.</translation>
<translation id="5813119285467412249">&amp;ചേർക്കുന്നത് വീണ്ടും ചെയ്യുക</translation>
<translation id="5838278095973806738">അക്രമകാരികൾ മോഷ്‌ടിക്കാൻ സാധ്യതയുള്ളതിനാൽ ഈ സൈറ്റിൽ നിങ്ങളുടെ രഹസ്യ വിവരങ്ങളൊന്നും (ഉദാഹരണത്തിന്, പാസ്‌വേഡുകളോ ക്രെഡിറ്റ് കാർഡുകളോ പോലുള്ളവ) നൽകരുത്.</translation>
+<translation id="5866257070973731571">ഫോണ്‍ നമ്പര്‍ ചേര്‍ക്കുക</translation>
<translation id="5869405914158311789">ഈ സൈറ്റ് ലഭ്യമാക്കാനാകുന്നില്ല</translation>
<translation id="5869522115854928033">സംരക്ഷിച്ച പാസ്‌വേഡുകള്‍</translation>
<translation id="5872918882028971132">പാരന്റ് നിർദ്ദേശങ്ങൾ</translation>
<translation id="5893752035575986141">ക്രെഡിറ്റ് കാർഡുകൾ സ്വീകരിക്കുന്നു.</translation>
-<translation id="5901630391730855834">മഞ്ഞ</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (സമന്വയിപ്പിച്ചത്)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{ഒരെണ്ണം ഉപയോഗത്തിലുണ്ട്}other{# എണ്ണം ഉപയോഗത്തിലുണ്ട്}}</translation>
<translation id="5959728338436674663">അപകടകരമായ ആപ്‌സുകളും സൈറ്റുകളും കണ്ടെത്താൻ സഹായിക്കുന്നതിന്‌ ചില <ph name="BEGIN_WHITEPAPER_LINK" />സിസ്‌റ്റം വിവരങ്ങളും പേജ്‌ ഉള്ളടക്കവും<ph name="END_WHITEPAPER_LINK" /> Google-ന്‌ സ്വയമേവ അയയ്‌ക്കുക. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">കോൺടാക്‌റ്റ് വിവരം എഡിറ്റുചെയ്യുക</translation>
<translation id="5967867314010545767">ചരിത്രത്തിൽ നിന്നും നീക്കംചെയ്യുക</translation>
<translation id="5975083100439434680">സൂം ഔട്ട്</translation>
+<translation id="597552863672748783">സുരക്ഷാ കോഡ് സ്ഥിരീകരിക്കുക</translation>
<translation id="598637245381783098">പേയ്‌മെന്റ് ആപ്പ് തുറക്കാനായില്ല</translation>
<translation id="5989320800837274978">ഒരു സ്ഥിരമായ പ്രോക്സി സെർവർ അല്ലെങ്കിൽ ഒരു .pac സ്‌ക്രിപ്റ്റ് URL വ്യക്തമാക്കിയിട്ടില്ല.</translation>
<translation id="5990559369517809815">സെർവറിലേക്കുള്ള അഭ്യർത്ഥനകൾ ഒരു വിപുലീകരണം തടഞ്ഞു.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{പേജ് 1}other{പേജ് #}}</translation>
-<translation id="6017514345406065928">പച്ച</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (സമന്വയിപ്പിച്ചത്)</translation>
<translation id="6027201098523975773">ഒരു പേര് നൽകുക</translation>
<translation id="6040143037577758943">അടയ്ക്കുക</translation>
-<translation id="6042308850641462728">കൂടുതൽ</translation>
<translation id="6047233362582046994">നിങ്ങളുടെ സുരക്ഷയെ ബാധിക്കാനിടയുണ്ടെന്ന് മനസ്സിലാക്കുകയാണെങ്കിൽ, ദോഷകരമായ ആപ്പുകൾ നീക്കംചെയ്യുന്നതിനു മുമ്പ് <ph name="BEGIN_LINK" />ഈ സൈറ്റ് സന്ദർശിക്കുക<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">സോഫ്‌റ്റ്‌വെയർ ഇൻസ്‌റ്റാൾ ചെയ്യുന്നതിലേക്കോ വ്യക്തിഗത വിവരങ്ങൾ വെളിപ്പെടുത്തുന്നതിലേക്കോ നിങ്ങളെ തന്ത്രപൂർവ്വം നയിച്ചുകൊണ്ട്, ഈ ഉള്ളടക്കം നിങ്ങളെ കബളിപ്പിക്കാൻ ശ്രമിച്ചേക്കാം. <ph name="BEGIN_LINK" />എന്തായാലും കാണിക്കുക<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> എന്ന വെബ്‌സൈറ്റ് സർട്ടിഫിക്കറ്റ് പിന്നിംഗ് ഉപയോഗിക്കുന്നതിനാൽ നിങ്ങൾക്കിപ്പോൾ അത് സന്ദർശിക്കാനാകില്ല. നെറ്റ്‌വർക്ക് പിശകുകളും ആക്രമണങ്ങളും സാധാരണയായി താൽക്കാലികമായിരിക്കും, അതിനാൽ ഈ പേജ് മിക്കവാറും പിന്നീട് പ്രവർത്തിക്കും.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">നിങ്ങൾ ഒരു വിപുലീകരണ പേജാണ് കാണുന്നത്</translation>
<translation id="6596325263575161958">എൻക്രിപ്‌ഷൻ ഓപ്‌ഷനുകൾ</translation>
<translation id="662080504995468778">തുടരുക</translation>
+<translation id="6624427990725312378">കോണ്‍ടാക്റ്റ് വിവരം</translation>
<translation id="6626291197371920147">ശരിയായ കാർഡ് നമ്പർ ചേർക്കുക</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> തിരയൽ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> എന്ന സൈറ്റിലെ നിലവിലുള്ള ആക്രമികൾ നിങ്ങളുടെ വിവരങ്ങൾ ഇല്ലാതാക്കാനോ മോഷ്‌ടിക്കാനോ ഇടയുള്ള (ഉദാഹരണത്തിന്, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ, ക്രെഡിറ്റ് കാർഡുകൾ മുതലായവ) അപകടകരമായ പ്രോഗ്രാമുകൾ Mac-ൽ ഇൻസ്‌റ്റാളുചെയ്യാൻ ശ്രമിച്ചേക്കാം. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടുതലറിയുക<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">കഴിഞ്ഞ</translation>
<translation id="6710594484020273272">&lt;തിരയൽ പദം നൽകുക&gt;</translation>
<translation id="6711464428925977395">പ്രോക്‌സി സെർവറിൽ എന്തോ പ്രശ്‌നമുണ്ട്, അല്ലെങ്കിൽ വിലാസം തെറ്റാണ്.</translation>
-<translation id="6727102863431372879">സജ്ജമാക്കുക</translation>
<translation id="674375294223700098">അറിയപ്പെടാത്ത സെര്‍വര്‍ സര്‍ട്ടിഫിക്കറ്റ് പിശക്.</translation>
<translation id="6753269504797312559">നയ മൂല്യം</translation>
<translation id="6757797048963528358">നിങ്ങളുടെ ഉപകരണം സുഷുപ്‌തിയിലായി.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">പ്രൊഫൈൽ പാത</translation>
<translation id="7424977062513257142">ഈ വെബ്‌സൈറ്റിലെ ഒരു എംബഡ് ചെയ്‌ത പേജ് പറയുന്നത്:</translation>
+<translation id="7437289804838430631">ബന്ധപ്പെടാനുള്ള വിവരങ്ങൾ ചേർക്കുക</translation>
<translation id="7441627299479586546">തെറ്റായ നയ വിഷയം</translation>
<translation id="7444046173054089907">ഈ സൈറ്റ് ബ്ലോക്കുചെയ്‌തു</translation>
<translation id="7445762425076701745">നിങ്ങള്‍ ബന്ധിപ്പിച്ച സെര്‍വറിന്‍റെ ഐഡന്‍റിറ്റി പൂര്‍ണ്ണമായി സാധൂകരിക്കാന്‍ കഴിയില്ല. നിങ്ങളുടെ നെറ്റ്‍വര്‍ക്കില്‍ മാത്രം സാധുവായ ഒരു നാമം ഉപയോഗിക്കുന്ന സെര്‍വറിലേക്ക് നിങ്ങള്‍ ബന്ധിപ്പിച്ചിരിക്കുന്നു, അതിന്‍റെ ഉടമസ്ഥാവകാശം ഒരു ബാഹ്യ അതോറിറ്റിയ്ക്ക് ഒരിക്കലും സാധൂകരിക്കാന്‍ കഴിയില്ല. ചില സാക്‍ഷ്യപത്ര അതോറിറ്റികള്‍ ഈ നാമങ്ങളെ കണക്കാക്കാതെ സാക്‍ഷ്യപത്രങ്ങള്‍ നല്‍കുന്നതിനാല്‍, ഉദ്ദേശിച്ച വെബ്സൈറ്റിലേക്കാണ് നിങ്ങള്‍ ബന്ധിപ്പിച്ചിരിക്കുന്നതെന്നും ഒരു ആക്രമണകാരിയല്ലെന്നും ഉറപ്പാക്കാന്‍ ഒരു മാര്‍ഗ്ഗവുമില്ല.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">മുന്നോട്ട്</translation>
<translation id="7485870689360869515">ഡാറ്റകളൊന്നും കണ്ടെത്തിയില്ല.</translation>
<translation id="7508255263130623398">നൽകിയ നയ ഉപകരണ ഐഡി ശൂന്യമാണ് അല്ലെങ്കിൽ നിലവിലെ ഉപകരണ ഐഡിയുമായി യോജിക്കുന്നില്ല</translation>
+<translation id="7511955381719512146">നിങ്ങൾ ഉപയോഗിക്കുന്ന Wi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> സന്ദർശിക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടാം.</translation>
<translation id="7514365320538308">ഡൗൺലോഡുചെയ്യുക</translation>
<translation id="7518003948725431193">വെബ് വിലാസത്തിനായി വെബ്‌പേജൊന്നും കണ്ടെത്തിയില്ല: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">ഈ സൈറ്റിലേക്കുള്ള നിങ്ങളുടെ കണക്ഷൻ സ്വകാര്യമല്ല</translation>
-<translation id="7535087603100972091">മൂല്യം</translation>
<translation id="7537536606612762813">നിർബന്ധിതം</translation>
<translation id="7542403920425041731">സ്ഥിരീകരിച്ചുകഴിഞ്ഞാൽ, നിങ്ങളുടെ കാർഡ് വിശദാംശങ്ങൾ ഈ സൈറ്റുമായി പങ്കിടും.</translation>
<translation id="7542995811387359312">ഈ ഫോം ഒരു സുരക്ഷിത കണക്ഷന്‍ ഉപയോഗിക്കാത്തതിനാല്‍ സ്വപ്രേരിത ക്രെഡിറ്റ് കാര്‍ഡ് പൂരിപ്പിക്കല്‍ അപ്രാപ്തമാക്കി.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; സെർവറിന്റെ സുരക്ഷ സർട്ടിഫിക്കറ്റ് വഞ്ചനാപരമായി ഇഷ്യൂ ചെയ്‌തിരിക്കാം. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
<translation id="7568593326407688803">ഈ പേജ്<ph name="ORIGINAL_LANGUAGE" />ലാണ് നിങ്ങളത് വിവര്‍‌ത്തനം ചെയ്യാന്‍‌ താല്‍‌പ്പര്യപ്പെടുന്നോ?</translation>
<translation id="7569952961197462199">Chrome-ൽ നിന്ന് ക്രെഡിറ്റ് കാർഡ് നീക്കംചെയ്യണോ?</translation>
-<translation id="7569983096843329377">കറുപ്പ്</translation>
<translation id="7578104083680115302">നിങ്ങൾ Google-ൽ സംരക്ഷിച്ച കാർഡുകൾ ഉപയോഗിച്ച് ഉപകരണങ്ങളിലുടനീളമുള്ള സൈറ്റുകളിലും ആപ്‌സിലും പെട്ടെന്ന് പണമടയ്‌ക്കുക.</translation>
<translation id="7588950540487816470">ഫിസിക്കൽ വെബ്</translation>
<translation id="7592362899630581445">സെർവറിന്റെ സർട്ടിഫിക്കറ്റ് പേരിന്റെ പരിധി ലംഘിക്കുന്നു.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">ഈ സൈറ്റിലെ ആക്രമണകാരികൾ, ബ്രൗസർ അനുഭവത്തെ ദോഷകരമായി ബാധിക്കുന്ന പ്രോഗ്രാമുകൾ ഇൻസ്‌റ്റാൾ ചെയ്യിക്കുന്ന വിധത്തിൽ നിങ്ങളെ കബളിപ്പിക്കാൻ ശ്രമിച്ചേക്കും (ഉദാഹരണത്തിന്, നിങ്ങളുടെ ഹോംപേജ് മാറ്റുന്നതിലൂടെയോ അല്ലെങ്കിൽ സന്ദർശിക്കുന്ന സൈറ്റുകളിൽ കൂടുതൽ പരസ്യങ്ങൾ കാണിക്കുന്നതിലൂടെയോ).</translation>
<translation id="7674629440242451245">പുതിയ Chrome-ന്റെ രസകരമായ സവിശേഷതകളിൽ താൽപ്പര്യമുണ്ടോ? chrome.com/dev-ൽ ഞങ്ങളുടെ ഡെവലപ്പർ ചാനൽ പരീക്ഷിച്ചുനോക്കുക.</translation>
<translation id="7682287625158474539">ഷിപ്പിംഗ്</translation>
+<translation id="7699293099605015246">ഇപ്പോൾ ലേഖനങ്ങൾ ലഭ്യമല്ല</translation>
<translation id="7701040980221191251">ഒന്നുമില്ല</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> എന്നതിലേക്ക് പോകുക (സുരക്ഷിതമല്ല)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">സര്‍‌ട്ടിഫിക്കറ്റ്</translation>
<translation id="7716147886133743102">നിങ്ങളുടെ അ‌ഡ്‌മിനി‌സ്‌ട്രേറ്റർ ബ്ലോക്കുചെയ്‌തു</translation>
<translation id="7716424297397655342">ഈ സൈറ്റ് കാഷെയിൽ നിന്ന് ലോഡുചെയ്യാനാകില്ല</translation>
+<translation id="7723047071702270851">കാർഡ് എഡിറ്റുചെയ്യുക</translation>
<translation id="774634243536837715">അപകടകരമായ ഉള്ളടക്കം ബ്ലോക്കുചെയ്‌തു.</translation>
<translation id="7752995774971033316">നിയന്ത്രിക്കാനാകാത്തത്</translation>
<translation id="7755287808199759310">നിങ്ങൾക്ക് വേണ്ടി ഇത് അൺബ്ലോക്കുചെയ്യാൻ രക്ഷിതാവിന് കഴിയും</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">വിലാസം ചേർക്കുക</translation>
<translation id="777702478322588152">പ്രിഫെക്‌ചർ</translation>
<translation id="7791543448312431591">ചേര്‍ക്കൂ</translation>
+<translation id="7793553086574152071">അടുത്ത പ്രാവശ്യം വേഗത്തിൽ പണമടയ്ക്കാൻ, നിങ്ങളുടെ Google അക്കൗണ്ടിൽ ഈ കാർഡ് സംരക്ഷിക്കുക.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> എന്നതിലെ വെബ്‌പേജ് താല്‍‌ക്കാലികമായി പ്രവര്‍‌ത്തനരഹിതമായിരിക്കാം, അല്ലെങ്കില്‍‌ ഒരു പുതിയ വെബ് വിലാസത്തിലേക്ക് ശാശ്വതമായി നീക്കിയിരിക്കാം.</translation>
<translation id="7800304661137206267">സന്ദേശ പ്രാമാണീകരണത്തിനും <ph name="KX" /> നും കീ എക്സേഞ്ച് മെക്കാനിസമായി <ph name="CIPHER" /> ഉപയോഗിച്ച് ഈ കണക്ഷനെ <ph name="MAC" /> എന്നതുമായി എന്‍‌ക്രിപ്റ്റ് ചെയ്തിരിക്കുന്നു.</translation>
+<translation id="7802523362929240268">സൈറ്റ് നിയമാനുസൃതമാണ്</translation>
<translation id="780301667611848630">വേണ്ട നന്ദി</translation>
<translation id="7805768142964895445">നില</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome-ൽ നിന്നുള്ള നിർദ്ദേശം നീക്കംചെയ്യണോ?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' എന്നതിന്റെ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> കണ്ടു</translation>
+<translation id="782886543891417279">നിങ്ങൾ ഉപയോഗിക്കുന്ന Wi-Fi (<ph name="WIFI_NAME" />) അതിന്റെ ലോഗിൻ പേജ് സന്ദർശിക്കാൻ ആവശ്യപ്പെടാം..</translation>
<translation id="785549533363645510">എന്നിരുന്നാലും നിങ്ങൾ അദൃശ്യനല്ല. ആൾമാറാട്ടത്തിലേയ്‌ക്ക് പോകുന്നത്, നിങ്ങളുടെ തൊഴിൽ ദാതാവിൽ നിന്നോ ഇന്റർനെറ്റ് സേവന ദാതാവിൽ നിന്നോ നിങ്ങൾ സന്ദർശിക്കുന്ന വെബ്‌സൈറ്റുകളിൽ നിന്നോ ഉള്ള ബ്രൗസിംഗിനെ മറയ്‌ക്കില്ല.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">ഡെബിറ്റ് കാർഡുകളും പ്രീപെയ്ഡ് കാർഡുകളും സ്വീകരിക്കുന്നു.</translation>
+<translation id="7878562273885520351">നിങ്ങളുടെ പാസ്‍വേഡ് അപഹരിക്കപ്പെട്ടേക്കാം</translation>
<translation id="7887683347370398519">നിങ്ങളുടെ CVC പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക</translation>
<translation id="79338296614623784">ശരിയായ ഒരു ഫോൺ നമ്പർ നൽകുക</translation>
<translation id="7935318582918952113">DOM ഡിസ്‌റ്റിലർ</translation>
<translation id="7938958445268990899">സെര്‍വറിന്‍റെ സര്‍ട്ടിഫിക്കറ്റ് ഇതുവരെയും സാധുവല്ല.</translation>
-<translation id="7942349550061667556">ചുവപ്പ്</translation>
<translation id="7947285636476623132">കാലാവധി തീരുന്ന വർഷം പരിശോധിച്ച് വീണ്ടും ശ്രമിച്ചുനോക്കൂ</translation>
<translation id="7951415247503192394">(32-ബിറ്റ്)</translation>
<translation id="7956713633345437162">മൊബൈൽ ബുക്ക്‌മാർക്കുകൾ</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">ചോദിക്കുക (ഡിഫോൾട്ട്)</translation>
<translation id="8041089156583427627">ഫീഡ്ബാക്ക് അയയ്ക്കുക</translation>
<translation id="8041940743680923270">ഗ്ലോബൽ ഡിഫോൾട്ട് ഉപയോഗിക്കുക (ചോദിക്കുക)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ശരിയായി കോൺഫിഗർ ചെയ്‌‌തിട്ടില്ല. സാധാരണഗതിയിൽ "<ph name="SOFTWARE_NAME" />" അൺഇൻസ്‌റ്റാൾ ചെയ്യുന്നതിലൂടെ ഈ പ്രശ്‌നം പരിഹരിക്കാം. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">ലേഖനം കാണുന്നത് പരാജയപ്പെട്ടു.</translation>
<translation id="8091372947890762290">സെർവറിൽ സജീവമാക്കൽ തീർപ്പാക്കിയിട്ടില്ല</translation>
+<translation id="8094917007353911263">നിങ്ങൾക്ക് ഉപയോഗിക്കുന്ന നെറ്റ്‌വർക്ക് <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> സന്ദർശിക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടാം.</translation>
+<translation id="8103161714697287722">പേയ്‌മെന്റ് രീതി</translation>
<translation id="8118489163946903409">പേയ്‌മെന്റ് രീതി</translation>
+<translation id="8127301229239896662">നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ അല്ലെങ്കിൽ നെറ്റ്‍വര്‍ക്കിൽ "<ph name="SOFTWARE_NAME" />" ശരിയായി ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടില്ല. ഈ പ്രശ്‌നം പരിഹരിക്കാൻ നിങ്ങളുടെ ഐടി അഡ്‌മിനിസ്‌ട്രേറ്ററോട് ആവശ്യപ്പെടുക.</translation>
<translation id="8131740175452115882">സ്ഥിരീകരിക്കുക</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> എന്നതിന്റെ സെർവർ <ph name="BEGIN_ABBR" />DNS വിലാസം<ph name="END_ABBR" /> കണ്ടെത്താനായില്ല.</translation>
<translation id="8149426793427495338">നിങ്ങളുടെ കമ്പ്യൂട്ടർ സുഷുപ്‌തിയിലായി.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">ഇത് അർത്ഥമാക്കുന്നത് എന്താണെന്ന് നിങ്ങൾക്ക് ഉറപ്പില്ലെങ്കിൽ നെറ്റ്‌വർക്ക് അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക.</translation>
<translation id="8293206222192510085">ബുക്ക്‌മാര്‍‌ക്ക് ചേര്‍‌ക്കുക</translation>
<translation id="8294431847097064396">ഉറവിടം</translation>
+<translation id="8298115750975731693">നിങ്ങൾ ഉപയോഗിക്കുന്ന Wi-Fi (<ph name="WIFI_NAME" />), <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> സന്ദർശിക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടാം.</translation>
<translation id="8306404619377842860">നിങ്ങളുടെ ഉപകരണത്തിന്റെ തീയതിയും സമയവും <ph name="DATE_AND_TIME" /> തെറ്റായതിനാൽ, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> എന്നതിലേക്കുള്ള ഒരു സ്വകാര്യ കണക്‌ഷൻ സ്ഥാപിക്കാനായില്ല. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടുതലറിയുക<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">നെറ്റ്വര്‍ക്ക് കണക്ഷനിലെ ഒരു പിശക് കാരണം വിവര്‍ത്തനം പരാജയപ്പെട്ടു.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ഹോസ്‌റ്റിലേക്കുള്ള ആക്‌സസ്സ് നിരസിച്ചു</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">സമീപകാലത്ത് അടച്ചവ</translation>
<translation id="8874824191258364635">ശരിയായ കാർഡ് നമ്പർ നൽകുക</translation>
<translation id="8876793034577346603">നെറ്റ്‌വർക്ക് കോൺഫിഗറേഷൻ പാഴ്‌സുചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു</translation>
-<translation id="8889402386540077796">ഹ്യൂ</translation>
<translation id="8891727572606052622">അസാധുവായ പ്രോക്സി മോഡ്</translation>
<translation id="889901481107108152">ക്ഷമിക്കണം, ഈ പരീക്ഷണം നിങ്ങളുടെ പ്ലാറ്റ്ഫോമിൽ ലഭ്യമല്ല.</translation>
<translation id="8903921497873541725">സൂം ഇന്‍</translation>
<translation id="8931333241327730545">ഈ കാർഡ് നിങ്ങളുടെ Google അക്കൗണ്ടിൽ സംരക്ഷിക്കണോ?</translation>
<translation id="8932102934695377596">നിങ്ങളുടെ ക്ലോക്ക് വളരെ പിന്നിലാണ്</translation>
+<translation id="893332455753468063">പേര് ചേർക്കുക</translation>
<translation id="8938939909778640821">ക്രെഡിറ്റ് കാർഡുകളും പ്രീപെയ്ഡ് കാർഡുകളും സ്വീകരിക്കുന്നു</translation>
+<translation id="8957210676456822347">ക്യാപ്‌റ്റീവ് പോർട്ടൽ അംഗീകരിക്കൽ</translation>
<translation id="8971063699422889582">സെര്‍വറിന്‍റെ സര്‍ട്ടിഫിക്കറ്റ് കാലഹരണപ്പെട്ടു.</translation>
-<translation id="8986494364107987395">Google ലേക്ക് സ്വപ്രേരിതമായി ഉപയോഗ സ്ഥിതിവിവരക്കണക്കുകളും ക്രാഷ് റിപ്പോര്‍ട്ടുകളും അയയ്ക്കുക</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">നിങ്ങൾ പോകാനിരിക്കുന്ന സൈറ്റിൽ ദോഷകരമായ പ്രോഗ്രാമുകളുണ്ട്</translation>
<translation id="8997023839087525404">സർട്ടിഫിക്കറ്റ് സുതാര്യതാ നയം ഉപയോഗിച്ച് സെർവർ, എല്ലാവർക്കുമായി വെളുപ്പെടുത്തിയിട്ടില്ലാത്ത ഒരു സർട്ടിഫിക്കറ്റ് ലഭ്യമാക്കി. ചില സർട്ടിഫിക്കറ്റുകൾ വിശ്വാസയോഗ്യമാണെന്നും അക്രമകാരികളിൽ നിന്നും പരിരക്ഷിക്കുന്നതാണെന്നും ഉറപ്പാക്കാൻ അവയ്‌ക്ക് ഇത് ആവശ്യമാണ്.</translation>
<translation id="9001074447101275817">പ്രോക്‌സി <ph name="DOMAIN" /> ഡൊമെയ്‌നിന് ഉപയോക്തൃനാമവും പാസ്‌വേഡും ആവശ്യമാണ്.</translation>
<translation id="9005998258318286617">PDF ഡോക്യുമെന്റ് ലോഡുചെയ്യാനായില്ല.</translation>
+<translation id="9008201768610948239">അവഗണിക്കുക</translation>
<translation id="901974403500617787">ഉടമയ്‌ക്ക് മാത്രമേ സിസ്റ്റത്തിലാകമാനം ബാധകമാക്കാവുന്ന ഫ്ലാഗ് സജ്ജമാക്കാനാകൂ: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">കാർഡ് ബില്ലിംഗ് വിലാസം ആവശ്യമാണ്</translation>
<translation id="9020542370529661692">ഈ പേജ് <ph name="TARGET_LANGUAGE" />-ലേക്ക് വിവർത്തനം ചെയ്‌തു</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">നിങ്ങള്‍ <ph name="DOMAIN" /> എന്നതില്‍ എത്താന്‍ ശ്രമിച്ചു, പക്ഷേ സെര്‍വര്‍ ഒരു അസാധുവായ സര്‍ട്ടിഫിക്കറ്റ് അവതരിപ്പിച്ചു.</translation>
<translation id="9050666287014529139">പാസ്ഫ്രെയ്സ്</translation>
<translation id="9065203028668620118">എഡിറ്റുചെയ്യുക</translation>
-<translation id="9068849894565669697">വർണ്ണം തിരഞ്ഞെടുക്കുക</translation>
<translation id="9069693763241529744">ഒരു വിപുലീകരണം മുഖേന ബ്ലോക്കുചെയ്‌തു</translation>
<translation id="9076283476770535406">ഇതിൽ മുതിർന്നവർക്കുള്ള ഉള്ളടക്കം ഉണ്ടായിരിക്കാം</translation>
<translation id="9078964945751709336">കൂടുതൽ വിവരങ്ങൾ ആവശ്യമാണ്</translation>
+<translation id="9080712759204168376">ഓർഡർ സംഗ്രഹം</translation>
<translation id="9103872766612412690">നിങ്ങളുടെ വിവരങ്ങൾ പരിരക്ഷിക്കാൻ സാധാരണയായി <ph name="SITE" />, എൻക്രിപ്‌ഷൻ ഉപയോഗിക്കുന്നു. ഇപ്പോൾ <ph name="SITE" /> സൈറ്റിലേക്ക് കണക്‌റ്റുചെയ്യാൻ Chromium ശ്രമിച്ചപ്പോൾ, അസാധാരണമായതും തെറ്റായതുമായ ക്രെഡൻഷ്യലുകൾ വെബ്‌സൈറ്റ് തിരികെ അയച്ചു. ഒരു ആക്രമണകാരി <ph name="SITE" /> എന്നതായി ഭാവിക്കാൻ ശ്രമിക്കുമ്പോഴോ Wi-Fi സൈൻ ഇൻ സ്‌ക്രീൻ, കണക്ഷനെ തടസ്സപ്പെടുത്തുമ്പോഴോ ആണ് ഇങ്ങനെ സംഭവിക്കാനിടയുള്ളത്. ഏതെങ്കിലും ഡാറ്റ കൈമാറുന്നതിനുമുമ്പ് Chromium കണക്ഷൻ അവസാനിപ്പിച്ചതിനാൽ, നിങ്ങളുടെ വിവരങ്ങൾ തുടർന്നും സുരക്ഷിതമായിരിക്കും.</translation>
+<translation id="9106062320799175032">ബില്ലിംഗ് വിലാസം ചേർക്കുക</translation>
+<translation id="910908805481542201">ഇത് പരിഹരിക്കാൻ എന്നെ സഹായിക്കുക</translation>
+<translation id="9128870381267983090">നെറ്റ്വര്‍ക്കിലേക്ക് ബന്ധിപ്പിക്കുക</translation>
<translation id="9137013805542155359">യഥാര്‍ത്ഥമായത് കാണിക്കുക</translation>
<translation id="9137248913990643158">ഈ ആപ്പ് ഉപയോഗിക്കുന്നതിന് മുമ്പ് ആരംഭിച്ച് Chrome-ൽ സൈൻ ഇൻ ചെയ്യുക.</translation>
<translation id="9148507642005240123">&amp;എഡിറ്റുചെയ്യുന്നത് പഴയപടിയാക്കുക</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> പിന്തുണയ്‌ക്കാത്ത ഒരു പ്രോട്ടോക്കോളാണ് ഉപയോഗിക്കുന്നത്.</translation>
<translation id="9205078245616868884">നിങ്ങളുടെ സമന്വയ പാസ്‌ഫ്രെയ്‌സ് ഉപയോഗിച്ച് ഡാറ്റ എൻക്രിപ്‌റ്റുചെയ്‌തു. സമന്വയം ആരംഭിക്കുന്നതിന് ഇത് നൽകുക.</translation>
<translation id="9207861905230894330">ലേഖനം ചേർക്കുന്നത് പരാജയപ്പെട്ടു.</translation>
+<translation id="9215416866750762878">ഈ സൈറ്റിലേക്ക് സുരക്ഷിതമായി കണക്റ്റുചെയ്യുന്നതിൽ നിന്ന് Chrome-നെ ഒരു ആപ്പ് തടയുന്നു</translation>
<translation id="9219103736887031265">ചിത്രങ്ങൾ‌</translation>
<translation id="933612690413056017">ഇന്റർനെറ്റ്‌ കണക്ഷനില്ല</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{ഒന്നുമില്ല}=1{ഒരു ഇനം}other{# ഇനങ്ങൾ}}</translation>
<translation id="981121421437150478">ഓഫ്‌ലൈൻ</translation>
<translation id="988159990683914416">വികാസക പതിപ്പ്</translation>
+<translation id="989988560359834682">വിലാസം എഡിറ്റുചെയ്യുക</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ അല്ലെങ്കിൽ നെറ്റ്‍വര്‍ക്കിൽ "<ph name="SOFTWARE_NAME" />" ശരിയായി ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടില്ല:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" അൺഇൻസ്‌റ്റാൾ ചെയ്യുന്നതോ പ്രവർത്തനരഹിതമാക്കുന്നതോ പരീക്ഷിക്കുക&lt;/li&gt;
+ &lt;li&gt;മറ്റൊരു നെറ്റ്‍വര്‍ക്കിലേക്ക് കണക്റ്റുചെയ്യുന്നത് പരീക്ഷിക്കുക&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index 4364c895636..8a986517b10 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">डेस्‍कटॉप बुकमार्क</translation>
<translation id="1074497978438210769">सुरक्षित नाही</translation>
<translation id="1080116354587839789">रूंदीत फिट करा</translation>
+<translation id="1088860948719068836">कार्डवर नाव जोडा</translation>
<translation id="1103523840287552314">नेहमी भाषांतर करा <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">सर्व सेव्ह केलेले पासवर्ड दाखवा...</translation>
<translation id="1107591249535594099">चेक केल्यास, अधिक जलद फॉर्म भरण्यासाठी या डिव्हाइसवर Chrome आपल्या कार्डची एक प्रत संचयित करेल.</translation>
<translation id="1111153019813902504">अलीकडील बुकमार्क</translation>
<translation id="1113869188872983271">&amp;पुनर्क्रमित करा पूर्ववत करा</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (सिंक केलेले)</translation>
<translation id="1263231323834454256">वाचन सूची</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> वाजता क्रॅश अहवाल कॅप्चर केला (अद्याप अपलोड केलेला नाही किंवा दुर्लक्ष केले)</translation>
+<translation id="1270502636509132238">घेण्याची पद्धत</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> ने दिलेले</translation>
<translation id="1285320974508926690">या साइटचा कधीही भाषांतर करु नका</translation>
<translation id="129553762522093515">अलीकडे बंद केलेले</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">कनेक्शनची वाट पाहत आहे...</translation>
<translation id="153384715582417236">सध्या इतकेच</translation>
<translation id="1549470594296187301">हे वैशिष्‍ट्य वापरण्‍यासाठी JavaScript सक्षम करणे आवश्‍यक आहे.</translation>
-<translation id="1555130319947370107">निळा</translation>
<translation id="1559528461873125649">अशी कोणतीही फाइल किंवा निर्देशिका नाही</translation>
<translation id="1583429793053364125">हे वेबपृष्‍ठ प्रदर्शित करताना काहीतरी चूक झाली.</translation>
<translation id="1592005682883173041">स्थानिक डेटा प्रवेश</translation>
<translation id="1594030484168838125">निवडा</translation>
-<translation id="161042844686301425">निळसर</translation>
<translation id="1620510694547887537">कॅमेरा</translation>
<translation id="1629803312968146339">Chrome ने हे कार्ड जतन करावे असे आपण इच्छिता?</translation>
<translation id="1639239467298939599">लोड करीत आहे</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">या साइटला भेट देण्यासाठी आपल्याला <ph name="NAME" /> कडील परवानगी आवश्यक आहे</translation>
<translation id="1721424275792716183">* फील्ड आवश्यक आहे</translation>
+<translation id="1727741090716970331">वैध कार्ड नंबर जोडा</translation>
<translation id="1728677426644403582">आपण वेब पृष्ठाचा स्रोत पाहत आहात</translation>
<translation id="173080396488393970">या प्रकारच्या कार्डला सहाय्य नाही</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">क्रमीकरण त्रुटी</translation>
<translation id="1974060860693918893">प्रगत</translation>
<translation id="1978555033938440688">फर्मवेयर आवृत्ती</translation>
-<translation id="1995859865337580572">कृपया तुमच्या CVC ची पडताळणी करा</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{आणि 1 अधिक}one{आणि # अधिक}other{आणि # अधिक}}</translation>
<translation id="2025186561304664664">प्रॉक्सी स्वयंचलित ‍कॉन्फिगरेशनवर सेट करण्‍यात आली.</translation>
<translation id="2030481566774242610">आपल्याला असे म्हणायचे होते <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">पूर्ववत करा</translation>
<translation id="20817612488360358">सिस्टम प्रॉक्सी सेटिंग्ज वापरण्‍यास सेट करण्‍यात आल्या परंतु एक सुस्पष्‍ट प्रॉक्सी कॉन्फिगरेशन देखील निर्दिष्‍ट करण्‍यात आले.</translation>
<translation id="2086652334978798447">Google ने सुचविलेली वैयक्तीकृत सामग्री मिळविण्यासाठी, Chrome मध्ये साइन इन करा.</translation>
+<translation id="2091887806945687916">ध्वनी</translation>
<translation id="2094505752054353250">डोमेन जुळत नाही</translation>
<translation id="2096368010154057602">विभाग</translation>
<translation id="2108755909498034140">आपला संगणक रीस्टार्ट करा</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">दुर्लक्ष केले कारण ते <ph name="POLICY_NAME" /> कडून अधिलिखित झाले होते.</translation>
<translation id="2138201775715568214">जवळपासची वास्तविक वेब पृष्ठे शोधत आहात</translation>
<translation id="213826338245044447">Mobile बुकमार्क</translation>
+<translation id="214556005048008348">पेमेंट रद्द करा</translation>
<translation id="2147827593068025794">पार्श्वभूमी संकालन</translation>
+<translation id="2148613324460538318">कार्ड जोडा</translation>
<translation id="2154054054215849342">आपल्या डोमेनसाठी संकालन उपलब्ध नाही</translation>
<translation id="2154484045852737596">कार्ड संपादित करा</translation>
<translation id="2166049586286450108">पूर्ण प्रशासन प्रवेश</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 पत्ता}one{# पत्ता}other{# पत्ते}}</translation>
<translation id="2187317261103489799">शोधा (डीफॉल्ट)</translation>
<translation id="2202020181578195191">वैध समाप्ती वर्ष प्रविष्ट करा</translation>
+<translation id="2209523182407020534">या एररला कारणीभूत असणार्‍या अ‍ॅप्लिकेशनमध्ये अँटिव्हायरस, फायरवॉल आणि वेब-फिल्टरिंग किंवा प्रॉक्सी सॉफ्टवेअरचा समावेश आहे.</translation>
<translation id="2212735316055980242">धोरण आढळले नाही</translation>
<translation id="2213606439339815911">प्रविष्ट्या आणत आहे...</translation>
<translation id="2218879909401188352">सध्या <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />वर असलेले आक्रमणकर्ता तुमच्या डिव्हाइसला हानी पोहोचवणारे धोकादायक अॅप इंस्टॉल करू शकतात, तुमच्या मोबाइल बिलामध्ये लपलेले शुल्क जोडू शकतात किंवा तुमची वैयक्तिक माहिती चोरू शकतात. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घ्या<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">परत जा</translation>
<translation id="2503184589641749290">स्वीकारली जाणारी डेबिट आणि प्रीपेड कार्डे</translation>
<translation id="2515629240566999685">आपल्या क्षेत्रातील सिग्नल तपासणे</translation>
+<translation id="2524461107774643265">अधिक माहिती जोडा</translation>
+<translation id="2536110899380797252">पत्ता जोडा</translation>
<translation id="2539524384386349900">शोधा</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> नी एक अवैध प्रतिसाद पाठविला.</translation>
<translation id="2556876185419854533">&amp; संपादित करा पूर्ववत करा</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium यावेळी आपल्या कार्डची पुष्टी करण्यात अक्षम होते. कृपया नंतर पुन्हा प्रयत्न करा.</translation>
<translation id="2705137772291741111">या साइटची जतन (कॅश केलेली) केलेली प्रत वाचण्याजोगी नव्हती.</translation>
<translation id="2709516037105925701">ऑटोफिल</translation>
+<translation id="2710942282213947212">तुमच्या काँप्युटरवरील सॉफ्टवेअर Chromium ला वेबशी सुरक्षितपणे कनेक्ट होण्यापासून थांबवत आहे</translation>
<translation id="2712173769900027643">परवानगी मागा</translation>
-<translation id="2713444072780614174">पांढरा</translation>
<translation id="2720342946869265578">जवळपास</translation>
<translation id="2721148159707890343">विनंती यशस्वी</translation>
<translation id="2728127805433021124">सर्व्हरचे प्रमाणपत्र कमकुवत स्वाक्षरी अल्गोरिदम वापरून स्वाक्षरित केले आहे.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">एक नेटवर्क बदल आढळला.</translation>
<translation id="2916038427272391327">अन्य प्रोग्राम बंद करा</translation>
<translation id="2922350208395188000">सर्व्हरचे प्रमाणपत्र तपासणे शक्य नाही.</translation>
+<translation id="2925673989565098301">वितरण पद्धत</translation>
<translation id="2928905813689894207">बिलिंग पत्ता</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> आणखी}one{<ph name="SHIPPING_ADDRESS_PREVIEW" />आणि <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> आणखी}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> आणखी}}</translation>
<translation id="2941952326391522266">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षितता प्रमाणपत्र <ph name="DOMAIN2" /> वरील आहे. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">चुकीचा धोरण प्रकार</translation>
<translation id="3032412215588512954">आपण ही साइट पुन्हा रीलोड करू इच्छिता?</translation>
<translation id="3037605927509011580">च्चक!</translation>
+<translation id="3039538478787849737">Google वर कार्ड सेव्ह करायचे?</translation>
<translation id="3041612393474885105">प्रमाणपत्र माहिती...</translation>
<translation id="3063697135517575841">Chrome यावेळी आपल्या कार्डची पुष्टी करण्यात अक्षम होते. कृपया नंतर पुन्हा प्रयत्न करा.</translation>
<translation id="3064966200440839136">बाह्य अॅप्लिकेशन द्वारे देय देण्यासाठी गुप्त मोड सोडत आहे. सुरु ठेवायचे?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">तात्पुरती सर्व्हर त्रुटी</translation>
<translation id="3154506275960390542">या पृष्ठावर एक फॉर्म आहे जो कदाचित सुरक्षितपणे सबमिट होणार नाही. आपण पाठविलेला डेटा प्रवासादरम्यान इतर पाहू शकतात किंवा सर्व्हर प्राप्त करत असलेल्या आक्रमणकर्त्याद्वारे सुधारित केले जाऊ शकते.</translation>
<translation id="3157931365184549694">पुनर्संचयित करा</translation>
+<translation id="3162559335345991374">आपण वापरत असलेल्या Wi-Fi च्या लॉग इन पृष्ठास आपल्याला भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="3167968892399408617">गुप्त मोडमध्‍ये आपण पाहता ती पृष्‍ठे आपण आपले सर्व गुप्त टॅब बंद केल्‍यानंतर आपला ब्राउझर इतिहास, कुकी स्टोअर किंवा शोध इतिहासामध्‍ये असणार नाहीत. आपण डाउनलोड करता त्या कोणत्याही फायली किंवा आपण केलेले बुकमार्क ठेवले जातील.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">बेट</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">पेमेंट रद्द करा</translation>
<translation id="3207960819495026254">बुकमार्क केलेली</translation>
+<translation id="3211223744486044430">पुढील वेळी जलद पेमेंट देण्यासाठी, तुमच्या Google खात्यावर आणि या डीव्हाइसवर हे कार्ड सेव्ह करा.</translation>
<translation id="3225919329040284222">सर्व्हरने असे प्रमाणपत्र सादर केले आहे जे अंगभूत अपेक्षांशी जुळत नाही. या अपेक्षा आपल्याला संरक्षित करण्यासाठी विशिष्ट, उच्च-सुरक्षिततेच्या वेबसाइटसाठी समाविष्ट केल्या आहेत.</translation>
<translation id="3226128629678568754">पृष्ठ लोड करण्यास आवश्यक असलेला डेटा पुन्हा सबमिट करण्यासाठी रीलोड बटण दाबा.</translation>
<translation id="3227137524299004712">मायक्रोफोन</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">कोणतेही शोध परिणाम आढळले नाहीत</translation>
<translation id="3305707030755673451">आपला डेटा आपल्या संकालन सांकेतिक वाक्यांशासह <ph name="TIME" /> वाजता कूटबद्ध केला होता. संकालन सुरु करण्यासाठी तो प्रविष्ट करा.</translation>
<translation id="3320021301628644560">बिलिंग पत्ता जोडा</translation>
-<translation id="3329013043687509092">संपृक्तता</translation>
<translation id="333371639341676808">अतिरिक्त संवाद तयार करण्यापासून या पृष्ठाला प्रतिबंधित करा.</translation>
<translation id="3338095232262050444">सुरक्षित</translation>
<translation id="3340978935015468852">सेटिंग्ज</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">क्लायंट आयडी:</translation>
<translation id="3391030046425686457">वितरण पत्ता</translation>
<translation id="3395827396354264108">पिकअप पद्धत</translation>
+<translation id="3399952811970034796">वितरण पत्ता</translation>
<translation id="3422248202833853650">मेमरी मोकळी करण्‍यासाठी अन्य प्रोग्राम मधून बाहर पडण्याचा प्रयत्न करा.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> सध्या आवाक्याबाहेर आहे.</translation>
<translation id="3427092606871434483">अनुमती द्या (डीफॉल्ट)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">क्रॅश अहवाल <ph name="CRASH_TIME" /> वाजता कॅप्चर केला, <ph name="UPLOAD_TIME" /> वाजता अपलोड केला</translation>
<translation id="3681007416295224113">प्रमाणपत्र माहिती...</translation>
<translation id="3690164694835360974">लॉग इन सुरक्षित नाही</translation>
+<translation id="3704162925118123524">आपण वापरत असलेल्या नेटवर्कला आपण त्याच्या लॉग इन पृष्ठास भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड करीत आहे...</translation>
<translation id="3712624925041724820">परवाने संपुष्टात</translation>
<translation id="3714780639079136834">मोबाइल डेटा किंवा Wi-Fi चालू करणे</translation>
+<translation id="3715597595485130451">Wi-Fi वर कनेक्ट करा</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />प्रॉक्सी, फायरवॉल आणि DNS कॉन्फिगरेशन तपासणे<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">आपल्याला आपल्या सुरक्षिततेच्या जोखमी समजत असल्यास, धोकादायक प्रोग्राम काढण्यापूर्वी आपण <ph name="BEGIN_LINK" />या असुरक्षित साइटला भेट देऊ शकता<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">आपण कॉपी केलेल्याचा दुवा जोडा</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;जोडा पूर्ववत करा</translation>
<translation id="404928562651467259">चेतावणी:</translation>
<translation id="4058922952496707368">की "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">वैध पत्ता जोडा</translation>
<translation id="4072486802667267160">आपल्या मागणीवर प्रक्रिया करताना त्रुटी आली, कृपया पुन्हा प्रयत्न करा.</translation>
<translation id="4075732493274867456">क्लायंट आणि सर्व्हर एक सामान्य SSL प्रोटोकॉल आवृत्ती किंवा सायफर संचाचे समर्थन करीत नाही.</translation>
<translation id="4079302484614802869">प्रॉक्सी कॉन्फिगरेशन .pac स्क्रिप्ट URL वापरण्‍यास सेट करण्‍यात आले आहे, निश्चित प्रॉक्सी सर्व्हर नव्हे.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">डिव्हाइस सिरीयल क्रमांक अवैध आहे</translation>
<translation id="410351446219883937">ऑटोप्ले</translation>
<translation id="4103763322291513355">आपल्या सिस्टम प्रशासकाद्वारे प्रवर्तित काळ्यासूचीतील URLs आणि अन्य धोरणांची सूची पाहण्यासाठी &lt;strong&gt;chrome://policy&lt;/strong&gt; ला भेट द्या.</translation>
-<translation id="4115378294792113321">किरमिजी</translation>
<translation id="4116663294526079822">या साइटवर नेहमी अनुमती द्या</translation>
<translation id="4117700440116928470">धोरण कक्षा समर्थित नाही.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{अन्य 1}one{अन्य #}other{अन्य #}}</translation>
@@ -420,7 +433,7 @@
<translation id="4151403195736952345">जागतिक डीफॉल्‍ट (शोधणे) वापरा</translation>
<translation id="4165986682804962316">साइट सेटिंग्ज</translation>
<translation id="4169947484918424451">Chromium ने हे कार्ड जतन करावे असे आपण इच्छिता?</translation>
-<translation id="4171400957073367226">खराब सत्यापन स्वाक्षरी</translation>
+<translation id="4171400957073367226">खराब पडताळणी स्वाक्षरी</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{आणखी <ph name="ITEM_COUNT" /> आयटम}one{आणखी <ph name="ITEM_COUNT" /> आयटम}other{आणखी <ph name="ITEM_COUNT" /> आयटम}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
<translation id="4196861286325780578">&amp;हलवा पुन्हा करा</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">आपण <ph name="DOMAIN" /> वर पोहोचण्याचा प्रयत्न केला, परंतु सर्व्हरने सादर केलेले प्रमाणपत्र त्याच्या जारीकर्त्याद्वारे मागे घेतले गेले आहे. याचा अर्थ सर्व्हरने सादर केलेल्या सुरक्षा क्रेडेन्शियलवर अजिबात ठेवला जाऊ नये. आपण कदाचित आक्रमणकर्त्याशी संप्रेषण करत आहात.</translation>
<translation id="4394049700291259645">अक्षम करा</translation>
<translation id="4406896451731180161">शोध परिणाम</translation>
+<translation id="4415426530740016218">घेण्याचा पत्ता</translation>
<translation id="4424024547088906515">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षितता प्रमाणपत्र Chrome द्वारे विश्वसनीय नाही. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपले लॉग इन प्रमाणपत्र स्वीकारले नाही किंवा कदाचित प्रदान केले गेले नसावे.</translation>
<translation id="443673843213245140">प्रॉक्सीचा वापर अक्षम करण्‍यात आला आहे पण एक सुस्पष्‍ट प्रॉक्सी कॉन्‍फिगरेशन निर्दिष्‍ट करण्‍यात आले आहे.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">फ्लॅश</translation>
<translation id="4558551763791394412">आपले विस्तार अक्षम करून पहा.</translation>
<translation id="457875822857220463">वितरण</translation>
+<translation id="4582800630050655161">तुम्ही तुमच्या Google खात्याचा अॅक्सेस गमावू शकता किंवा तुमची संवेदनशील माहिती चोरीला जाऊ शकते. Chromium लगेच तुमचा पासवर्ड बदलण्याची शिफारस करत आहे.</translation>
<translation id="4587425331216688090">Chrome मधून पत्ता काढायचा?</translation>
<translation id="4592951414987517459">आपले <ph name="DOMAIN" /> वरील कनेक्शन आधुनिक सायफर सूट वापरून कूटबद्ध केलेले आहे.</translation>
<translation id="4594403342090139922">&amp;हटवा पूर्ववत करा</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याच्या सुरक्षितता प्रमाणपत्रात त्रुटी आहेत. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
<translation id="4690462567478992370">अवैध प्रमाणपत्र वापरणे थांबवा</translation>
+<translation id="4690954380545377795">तुम्ही तुमच्या Google खात्याचा अॅक्सेस गमावू शकता किंवा तुमची संवेदनशील माहिती चोरीला जाऊ शकते. Chrome लगेच तुमचा पासवर्ड बदलण्याची शिफारस करत आहे.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">आपल्या कनेक्शनमध्ये व्यत्यय आला</translation>
<translation id="471880041731876836">या साइटला भेट देण्याची तुम्हाला परवानगी नाही</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवर्क निदान चालविणे<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">आपले पेमेंट</translation>
<translation id="4726672564094551039">धोरणे रीलोड करा</translation>
<translation id="4728558894243024398">प्लॅटफॉर्म</translation>
<translation id="4736825316280949806">Chromium रीस्टार्ट करा</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">समर्थन संचयन खराब स्थितीत</translation>
<translation id="5023310440958281426">आपल्या प्रशासकाची धोरणे तपासा</translation>
<translation id="5029568752722684782">कॉपी साफ करा</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" साठी मूळ सर्टिफिकेट आवश्यक आहे परंतु ते इंस्टॉल केलेले नाही. तुमच्या IT अ‍ॅडमिनिस्ट्रेटरने ही समस्या सोडण्यासाठी "<ph name="SOFTWARE_NAME" />" साठीच्या कॉन्फिगरेशन सूचना पहाव्यात. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google भाषांतर बद्दल</translation>
<translation id="5039804452771397117">परवानगी द्या</translation>
<translation id="5040262127954254034">गोपनीयता</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">प्रयोग</translation>
<translation id="5205222826937269299">नाव आवश्यक आहे</translation>
<translation id="5222812217790122047">ईमेल आवश्यक आहे</translation>
+<translation id="522700295135997067">या साइटने कदाचित तुमचा पासवर्ड चोरला असेल</translation>
+<translation id="5230733896359313003">पाठविण्याचा पत्ता</translation>
<translation id="5251803541071282808">क्लाउड</translation>
<translation id="5277279256032773186">कार्यस्थानी Chrome वापरत आहात? व्यवसाय त्यांच्या कर्मचार्‍यांंसाठी Chrome सेटिंग्ज व्यवस्थापित करू शकतात. अधिक जाणनू घ्या</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />सॉफ्टवेअर तात्पुरते बंद करून ठेवण्यासाठी खालील पायर्‍यांचे अनुसरण करा, ज्यामुळे तुम्ही वेबशी कनेक्ट होऊ शकाल. तुम्हाला प्रशासकीय हक्क असणे आवश्यक असेल.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">या साइटवरील आपले कनेक्शन खाजगी नाही. VR मोड मधून बाहेर पडण्‍यासाठी, हेडसेट काढा आणि मागे दाबा.</translation>
<translation id="5299298092464848405">धोरण विश्लेषित करताना त्रुटी</translation>
+<translation id="5308380583665731573">कनेक्‍ट करा</translation>
<translation id="5308689395849655368">क्रॅश अहवाल अक्षम केला गेला आहे.</translation>
<translation id="5317780077021120954">जतन करा</translation>
<translation id="5327248766486351172">नाव</translation>
+<translation id="5332219387342487447">पाठविण्‍याची पद्धत</translation>
<translation id="5355557959165512791">तुम्ही आत्ता <ph name="SITE" /> ला भेट देऊ शकत नाही कारण तिचे प्रमाणपत्र निरस्त केले गेले आहे. नेटवर्क एरर आणि आक्रमणे शक्यतो तात्पुरती असतात, त्यामुळे हे पेज नंतर पाहता येईल.</translation>
<translation id="536296301121032821">धोरण सेटिंग्ज संचयित करण्यात अयशस्वी</translation>
<translation id="5386426401304769735">या साइटसाठी असलेल्या प्रमाणपत्र श्रृंखलेत SHA-1 वापरून स्वाक्षरी केलेले प्रमाणपत्र असते.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">कंपनी, संस्था किंवा शाळा इंट्रानेट वरील या साइटची URL बाह्य वेबसाइटसारखीच आहे.
<ph name="LINE_BREAK" />
सिस्टम प्रशासकाशी संपर्क साधण्याचा प्रयत्न करा.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> साठी सुरक्षा कोड टाका. हा कोड सेव्ह केला जाणार नाही.</translation>
<translation id="5509780412636533143">व्यवस्थापित केलेले बुकमार्क</translation>
<translation id="5510766032865166053">ती कदाचित हलविली किंवा हटविली गेली आहे.</translation>
<translation id="5523118979700054094">धोरणाचे नाव</translation>
<translation id="552553974213252141">मजकूर योग्यरितीने काढला होता?</translation>
<translation id="5540224163453853">विनंती केलेला लेख शोधू शकलो नाही.</translation>
+<translation id="5541546772353173584">ईमेल जोडा</translation>
<translation id="5544037170328430102"><ph name="SITE" /> वरील एम्बेड केलेले पृष्ठ म्हणते:</translation>
+<translation id="5545756402275714221">तुमच्यासाठी लेख</translation>
<translation id="5556459405103347317">रीलोड करा</translation>
<translation id="5560088892362098740">एक्सपायर होण्याची तारीख</translation>
<translation id="5565735124758917034">सक्रिय</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">ईमेल</translation>
<translation id="5669703222995421982">वैयक्तीकृत सामग्री मिळवा</translation>
<translation id="5675650730144413517">हे पृष्ठ कार्य करीत नाही</translation>
+<translation id="5689199277474810259">JSON वर निर्यात करा</translation>
<translation id="5710435578057952990">या वेबसाइटची ओळख सत्यापित केली गेली नाही.</translation>
<translation id="5719499550583120431">प्रीपेड कार्डे स्वीकारली जातात.</translation>
<translation id="5720705177508910913">वर्तमान वापरकर्ता</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">आपले <ph name="DOMAIN" /> वरील कनेक्शन अप्रचलित सायफर सूट वापरून कूटबद्ध केलेले आहे.</translation>
<translation id="5813119285467412249">&amp;जोडा पुन्हा करा</translation>
<translation id="5838278095973806738">या साइटवर कोणतीही संवेदनशील माहिती (उदाहरणार्थ, संकेतशब्द किंवा क्रेडिट कार्ड) प्रविष्ट करू नका, कारण आक्रमणकर्ते ती चोरू शकतात.</translation>
+<translation id="5866257070973731571">फोन नंबर जोडा</translation>
<translation id="5869405914158311789">या साइटवर पोहचणे शक्य नाही</translation>
<translation id="5869522115854928033">जतन केलेले संकेतशब्द</translation>
<translation id="5872918882028971132">पालक सूचना</translation>
<translation id="5893752035575986141">क्रेडिट कार्डे स्वीकारली जातात.</translation>
-<translation id="5901630391730855834">पिवळा</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (सिंक केलेले)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 वापरात आहे}one{# वापरात आहे}other{# वापरात आहेत}}</translation>
<translation id="5959728338436674663">धोकादायक अॅप्स आणि साइट शोधण्यात मदत करण्‍यासाठी काही <ph name="BEGIN_WHITEPAPER_LINK" />सिस्टम माहिती आणि पृष्ठ सामग्री<ph name="END_WHITEPAPER_LINK" /> स्वयंचलितपणे Google कडे पाठवा. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">संपर्क माहिती संपादित करा</translation>
<translation id="5967867314010545767">इतिहासातून काढा</translation>
<translation id="5975083100439434680">झूम कमी करा</translation>
+<translation id="597552863672748783">सुरक्षा कोड निश्चित करा</translation>
<translation id="598637245381783098">पेमेंट अॅप उघडू शकत नाही</translation>
<translation id="5989320800837274978">निश्चित प्रॉक्‍सी सर्व्हर किंवा .pac स्क्रिप्ट URL देखील निर्दिष्‍ट केलेली नाही.</translation>
<translation id="5990559369517809815">सर्व्हरला केल्या जाणार्‍या विनंत्या एका विस्ताराने अवरोधित केल्या गेल्या आहेत.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{पृष्ठ 1}one{पृष्ठ #}other{पृष्ठे #}}</translation>
-<translation id="6017514345406065928">हिरवा</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (सिंक केलेले)</translation>
<translation id="6027201098523975773">नाव प्रविष्ट करा</translation>
<translation id="6040143037577758943">बंद करा</translation>
-<translation id="6042308850641462728">अधिक</translation>
<translation id="6047233362582046994">तुम्हाला तुमच्या सुरक्षेला असणारा धोका समजत असल्यास, हानिकारक अॅप्स काढले जाण्यापूर्वी तुम्ही <ph name="BEGIN_LINK" />या साइटला भेट देऊ शकता<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">हा आशय तुम्हाला सॉफ्टवेअर इंस्टॉल करण्याचा किंवा वैयक्तिक माहिती उघड करण्याचा फसवा प्रयत्न करू शकेल. <ph name="BEGIN_LINK" />तरीही दाखवा<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ही वेबसाइट प्रमाणपत्र पिनिंग वापरत असल्यामुळे तुम्ही आत्ता <ph name="SITE" /> पाहू शकणार नाही. नेटवर्क एरर आणि आक्रमणे शक्यतो तात्पुरती असतात, त्यामुळे हे पेज नंतर पाहता येईल.</translation>
@@ -698,6 +724,7 @@
<translation id="6569060085658103619">आपण एक विस्तार पृष्ठ पाहत आहात</translation>
<translation id="6596325263575161958">कूटबद्धता पर्याय</translation>
<translation id="662080504995468778">यावर रहा</translation>
+<translation id="6624427990725312378">संपर्क माहिती</translation>
<translation id="6626291197371920147">वैध कार्ड नंबर जोडा</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> शोध</translation>
<translation id="6630809736994426279">सध्या <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> वर असलेले हल्लेखोर कदाचित तुमच्या मॅकमधील तुमची माहिती चोरू किंवा हटवू शकणारे धोकादायक प्रोग्राम (उदाहरणार्थ, फोटो, पासवर्ड, संदेश आणि क्रेडिट कार्डे) इंस्टॉल करण्याचा प्रयत्न करू शकतील. <ph name="BEGIN_LEARN_MORE_LINK" />आणखी जाणून घ्या<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -708,7 +735,6 @@
<translation id="6710213216561001401">मागील</translation>
<translation id="6710594484020273272">&lt;शोध संज्ञा प्रविष्ट करा&gt;</translation>
<translation id="6711464428925977395">प्रॉक्सी सर्व्हरमध्ये काहीतरी चुकीचे आहे किंवा पत्ता चुकीचा आहे.</translation>
-<translation id="6727102863431372879">सेट करा</translation>
<translation id="674375294223700098">अज्ञात सर्व्हर प्रमाणपत्र त्रुटी.</translation>
<translation id="6753269504797312559">धोरण मूल्य</translation>
<translation id="6757797048963528358">आपले डिव्हाइस निष्क्रीय झाले.</translation>
@@ -777,6 +803,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">प्रोफाइल पथ</translation>
<translation id="7424977062513257142">या वेबपृष्ठावरील एम्बेड केलेले पृष्ठ म्हणते:</translation>
+<translation id="7437289804838430631">संपर्क माहिती जोडा</translation>
<translation id="7441627299479586546">चुकीचे धोरण विषय</translation>
<translation id="7444046173054089907">ही साइट अवरोधित केली आहे</translation>
<translation id="7445762425076701745">आपण कनेक्ट केलेल्या सर्व्हरची ओळख पूर्णपणे सत्यापित करणे शक्य नाही. आपण सर्व्हरशी फक्त आपल्‍या डोमेनमध्ये वैध असलेले नाव वापरून कनेक्ट केलेले आहे, ज्याची मालकी सत्यापित करण्यासाठी बाह्य प्रमाणपत्र अधिकृततेला परवानगी नाही. काही प्रमाणपत्र अधिकारी तरीही या नावांसाठी प्रमाणपत्र जारी करतील, हे सुनिश्चित करण्याचा काहीही मार्ग नाही की आपण इच्छित वेबसाइटशी कनेक्ट केले आहे आणि आक्रमणकर्त्याशी नाही.</translation>
@@ -787,11 +814,11 @@
<translation id="7481312909269577407">पुढील</translation>
<translation id="7485870689360869515">डेटा आढळला नाही.</translation>
<translation id="7508255263130623398">परत केलेला धोरण डिव्हाइस आयडी रिक्त आहे किंवा वर्तमान डिव्हाइस आयडी शी जुळत नाही</translation>
+<translation id="7511955381719512146">आपण वापरत असलेल्या Wi-Fi ला आपण <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ला भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="7514365320538308">डाउनलोड करा</translation>
<translation id="7518003948725431193">या वेबपत्त्यासाठी वेबपृष्ठ आढळले नाही: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">या साइटवर तुमचे कनेक्शन खाजगी नाही</translation>
-<translation id="7535087603100972091">मूल्य</translation>
<translation id="7537536606612762813">अनिवार्य</translation>
<translation id="7542403920425041731">तुम्ही निश्चित केल्यावर, तुमचे कार्ड तपशील या साइटसह शेअर केले जातील.</translation>
<translation id="7542995811387359312">स्वयंचलित क्रेडिट कार्ड भरणे अक्षम झाले आहे कारण हा फॉर्म सुरक्षित कनेक्शन वापरत नाही.</translation>
@@ -802,7 +829,6 @@
<translation id="7567204685887185387">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षितता प्रमाणपत्र कदाचित लबाडीने जारी केले असावे. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
<translation id="7568593326407688803">हे पृष्ठ<ph name="ORIGINAL_LANGUAGE" />मध्ये आहे आपण याचा भाषांतर करु इच्छिता?</translation>
<translation id="7569952961197462199">Chrome मधून क्रेडिट कार्ड काढायचे?</translation>
-<translation id="7569983096843329377">काळा</translation>
<translation id="7578104083680115302">आपण Google सह जतन केलेल्या कार्डचा वापर करून डिव्‍हाइसेसवरून द्रुतपणे साइट आणि अॅप्सवर देय द्या.</translation>
<translation id="7588950540487816470">भौतिक वेब</translation>
<translation id="7592362899630581445">सर्व्हरचे प्रमाणपत्र नाव मर्यादांचे उल्लंघन करते.</translation>
@@ -821,11 +847,13 @@
<translation id="7669271284792375604">या साइट वरील आक्रमणकर्ते कदाचित आपल्या ब्राउझिंग अनुभवास हानी पोहोचविणारे प्रोग्राम (उदाहरणार्थ, आपले मुख्यपृष्ठ बदलून किंवा आपण भेट देता त्या साइटवर अतिरिक्त जाहिराती दर्शवून) इंस्टॉल करून आपली फसवणूक करण्‍याचा प्रयत्न करू शकतात.</translation>
<translation id="7674629440242451245">छान नवीन Chrome वैशिष्ट्यांमध्ये स्वारस्य आहे? chrome.com/dev येथे आमचे dev चॅनेल वापरून पहा.</translation>
<translation id="7682287625158474539">शिपिंग</translation>
+<translation id="7699293099605015246">लेख आत्ता उपलब्ध नाहीत</translation>
<translation id="7701040980221191251">काहीही नाही</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> (असुरक्षित) वर सुरु ठेवा<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">प्रमाणपत्र</translation>
<translation id="7716147886133743102">तुमच्या प्रशासकाने ब्लॉक केलेले</translation>
<translation id="7716424297397655342">ही साइट कॅश मधून लोड करणे शक्य नाही</translation>
+<translation id="7723047071702270851">कार्ड संपादित करा</translation>
<translation id="774634243536837715">धोकादायक आशय ब्लॉक केला.</translation>
<translation id="7752995774971033316">व्यवस्थापित न केलेले</translation>
<translation id="7755287808199759310">आपले पालक आपल्यासाठी ती अनावरोधित करू शकतात</translation>
@@ -836,21 +864,24 @@
<translation id="7764225426217299476">पत्ता जोडा</translation>
<translation id="777702478322588152">परफेक्चुअर</translation>
<translation id="7791543448312431591">जोडा</translation>
+<translation id="7793553086574152071">पुढील वेळी जलद पेमेंट देण्यासाठी, तुमच्या Google खात्यावर हे कार्ड सेव्ह करा.</translation>
<translation id="7793809570500803535"><ph name="SITE" />येथील वेबपृष्ठ कदाचित तात्पुरते बंद आहे किंवा ते कदाचित नवीन वेब पत्त्यावर कायमचे हलवले आहे.</translation>
<translation id="7800304661137206267">संदेश प्रमाणीकरणासाठी <ph name="MAC" /> आणि की विनिमय तंत्र महणून <ph name="KX" /> सह <ph name="CIPHER" /> वापरून कनेक्शन कूटबद्ध केले आहे.</translation>
+<translation id="7802523362929240268">साइट कायदेशीर आहे</translation>
<translation id="780301667611848630">नाही, नको</translation>
<translation id="7805768142964895445">स्थिती</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome मधून सूचना फॉर्म काढायचा?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' साठी <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> सापडले</translation>
+<translation id="782886543891417279">आपण वापरत असलेल्या (<ph name="WIFI_NAME" />) Wi-Fi च्या लॉग इन पृष्ठास आपल्याला भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="785549533363645510">तथापि, आपण अदृश्य नाही. गुप्त झाल्याने आपले ब्राउझिंग आपला नियोक्ता, आपला इंटरनेट सेवा प्रदाता, किंवा आपण भेट देता त्या वेबसाइटपासून लपत नाही.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">डेबिट आणि प्रीपेड कार्डे स्वीकरली जातात.</translation>
+<translation id="7878562273885520351">तुमच्या पासवर्डशी तडजोड होत असल्याची शक्यता आहे</translation>
<translation id="7887683347370398519">आपले CVC तपासा आणि पुन्हा प्रयत्न करा</translation>
<translation id="79338296614623784">वैध फोन नंबर प्रविष्ट करा</translation>
<translation id="7935318582918952113">DOM डिस्टिलर</translation>
<translation id="7938958445268990899">सर्व्हरचे प्रमाणपत्र अद्याप वैध नाही.</translation>
-<translation id="7942349550061667556">लाल</translation>
<translation id="7947285636476623132">आपले कालबाह्यता वर्ष तपासा आणि पुन्हा प्रयत्न करा</translation>
<translation id="7951415247503192394">(32-बिट)</translation>
<translation id="7956713633345437162">Mobile बुकमार्क</translation>
@@ -864,9 +895,13 @@
<translation id="8037357227543935929">विचारा (डीफॉल्ट)</translation>
<translation id="8041089156583427627">अभिप्राय पाठवा</translation>
<translation id="8041940743680923270">सार्वत्रिक डीफॉल्‍ट वापरा (विचारा)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" योग्य रीतीने कॉन्फिगर केलेले नाही. "<ph name="SOFTWARE_NAME" />" अनइंस्टॉल केल्याने सहसा समस्या सुटते. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">लेख पाहण्यात अयशस्वी.</translation>
<translation id="8091372947890762290">सक्रियकरण सर्व्हरवर प्रलंबित आहे</translation>
+<translation id="8094917007353911263">आपण वापरत असलेल्या नेटवर्कला आपण <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ला भेट देण्याची आवश्यकता आहे.</translation>
+<translation id="8103161714697287722">पेमेंट पद्धत</translation>
<translation id="8118489163946903409">पेमेंट पद्धत</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" तुमच्या काँप्युटरवर किंवा नेटवर्कवर योग्य रीतीने इंस्टॉल केले नव्हते. तुमच्या अ‍ॅडमिनिस्ट्रेटरला ही समस्या सोडवण्यास सांगा.</translation>
<translation id="8131740175452115882">पुष्टी करा</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />चे सर्व्हर <ph name="BEGIN_ABBR" />DNS पत्ता<ph name="END_ABBR" /> शोधणे शक्य झाले नाही.</translation>
<translation id="8149426793427495338">आपला संगणक निष्क्रीय झाला.</translation>
@@ -889,6 +924,7 @@
<translation id="8289355894181816810">याचा निश्चित अर्थ आपल्याला माहिती नसल्यास आपल्या नेटवर्क प्रशासकाशी संपर्क साधा.</translation>
<translation id="8293206222192510085">बुकमार्क जोडा</translation>
<translation id="8294431847097064396">स्रोत</translation>
+<translation id="8298115750975731693">आपण वापरत असलेल्या (<ph name="WIFI_NAME" />) Wi-Fi ला आपण <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ला भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="8306404619377842860">तुमच्या डीव्हाइसची तारीख आणि वेळ (<ph name="DATE_AND_TIME" />)चुकीची असल्यामुळे <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> साठी खाजगी कनेक्शन तयार करू शकत नाही. <ph name="BEGIN_LEARN_MORE_LINK" />आणखी जाणून घ्या<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">नेटवर्क कनेक्शनसह समस्या असल्यामुळे भाषांतर अयशस्वी झाला.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> मधील प्रवेश नाकारला</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">अलीकडे बंद</translation>
<translation id="8874824191258364635">वैध कार्ड नंबर प्रविष्ट करा</translation>
<translation id="8876793034577346603">विश्लेषण करण्यात नेटवर्क कॉन्फिगरेशन अयशस्वी.</translation>
-<translation id="8889402386540077796">रंगछटा</translation>
<translation id="8891727572606052622">अवैध प्रॉक्सी मोड.</translation>
<translation id="889901481107108152">क्षमस्व, हा प्रयोग आपल्या प्लॅटफॉर्मवर उपलब्ध नाही.</translation>
<translation id="8903921497873541725">झूम वाढवा</translation>
<translation id="8931333241327730545">आपण आपल्या Google खात्यात हे कार्ड जतन करू इच्छिता?</translation>
<translation id="8932102934695377596">आपले घड्याळ मागे आहे</translation>
+<translation id="893332455753468063">नाव जोडा</translation>
<translation id="8938939909778640821">स्वीकारलेली क्रेडिट आणि प्रीपेड कार्डे</translation>
+<translation id="8957210676456822347">बंद पोर्टल प्राधिकृतता</translation>
<translation id="8971063699422889582">सर्व्हरचे प्रमाणपत्र कालबाह्य झाले आहे.</translation>
-<translation id="8986494364107987395">Google ला वापर आकडेवारी आणि क्रॅश अहवाल स्वयंचलितपणे पाठवा</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">पुढे असणार्‍या साइटमध्ये हानिकारक प्रोग्राम आहेत</translation>
<translation id="8997023839087525404">सर्व्हरने प्रमाणपत्र पारदर्शकता धोरणाचा वापर करून सार्वजनिकरीत्या उघड न केलेले एक प्रमाणपत्र सादर केले. काही प्रमाणपत्रे विश्वसनीय आहेत आणि आक्रमणकर्त्यांविरूद्ध संरक्षण करतात हे सुनिश्चित करण्‍यासाठी त्यांच्यासाठी ही एक आवश्यकता आहे.</translation>
<translation id="9001074447101275817">प्रॉक्सी <ph name="DOMAIN" /> ला वापरकर्तानाव आणि संकेतशब्द आवश्यक आहेत.</translation>
<translation id="9005998258318286617">PDF दस्तऐवज लोड करण्यात अपयश आले.</translation>
+<translation id="9008201768610948239">दुर्लक्ष करा</translation>
<translation id="901974403500617787">सिस्टम-व्याप्त लागू होणारी ध्वजांकने केवळ मालकाद्वारे सेट केली जाऊ शकतात: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">कार्ड बिलिंग पत्ता आवश्यक आहे</translation>
<translation id="9020542370529661692">हे पृष्ठ <ph name="TARGET_LANGUAGE" /> मध्ये भाषांतरित केले गेले आहे.</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">आपण <ph name="DOMAIN" /> वर पोहोचण्याचा प्रयत्न केला, परंतु सर्व्हरने अवैध प्रमाणपत्र सादर केले आहे.</translation>
<translation id="9050666287014529139">सांकेतिक वाक्यांश</translation>
<translation id="9065203028668620118">संपादन</translation>
-<translation id="9068849894565669697">रंग निवडा</translation>
<translation id="9069693763241529744">एक विस्ताराने ब्लॉक केलेले</translation>
<translation id="9076283476770535406">कदाचित तिच्यामध्ये प्रौढ सामग्री असू शकते</translation>
<translation id="9078964945751709336">अधिक माहिती आवश्यक आहे</translation>
+<translation id="9080712759204168376">मागणी सारांश</translation>
<translation id="9103872766612412690"><ph name="SITE" /> आपली माहिती संरक्षित करण्यासाठी सामान्यतः कूटबद्धीकरण वापरते. Chromium ने यावेळी <ph name="SITE" /> शी कनेक्‍ट करण्‍याचा प्रयत्न केला तेव्‍हा, वेबसाइटने असामान्य आणि अयोग्य क्रेडेन्शियल परत पाठविले. एकतर आक्रमणकर्ता <ph name="SITE" /> असल्याची बतावणी करण्याचा प्रयत्न करतो तेव्‍हा किंवा Wi-Fi साइन इन स्क्रीनने कनेक्शनमध्ये व्यत्यय आणले तेव्‍हा हे घडू शकते. कोणत्याही डेटाची अदलाबदल करण्यापूर्वी Chromium ने कनेक्शन थांबविल्यामुळे आपली माहिती अद्याप सुरक्षित आहे.</translation>
+<translation id="9106062320799175032">बिलिंग पत्ता जोडा</translation>
+<translation id="910908805481542201">याचे निराकरण करण्यात माझी मदत करा</translation>
+<translation id="9128870381267983090">नेटवर्कशी कनेक्ट करा</translation>
<translation id="9137013805542155359">मूळ दर्शवा</translation>
<translation id="9137248913990643158">कृपया हा अॅप वापरण्‍यापूर्वी प्रारंभ करा आणि Chrome मध्‍ये साइन इन करा.</translation>
<translation id="9148507642005240123">&amp;संपादित करा पूर्ववत करा</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> असमर्थित प्रोटोकॉल वापरतो.</translation>
<translation id="9205078245616868884">आपला डेटा आपल्या संकालन सांकेतिक वाक्यांशासह कूटबद्ध केला जातो. संकालन सुरु करण्यासाठी तो प्रविष्ट करा.</translation>
<translation id="9207861905230894330">लेख जोडण्यात अयशस्वी.</translation>
+<translation id="9215416866750762878">एक अॅप्लिकेशन Chrome ला या साइटशी सुरक्षितपणे कनेक्ट करण्यापासून थांबवत आहे</translation>
<translation id="9219103736887031265">प्रतिमा</translation>
<translation id="933612690413056017">इंटरनेट कनेक्शन नाही</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{काहीही नाही}=1{1 आयटम}one{# आयटम}other{# आयटम}}</translation>
<translation id="981121421437150478">ऑफलाइन</translation>
<translation id="988159990683914416">विकसक बिल्ड</translation>
+<translation id="989988560359834682">पत्ता संपादित करा</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" तुमच्या काँप्युटरवर किंवा नेटवर्कवर योग्य रीतीने इंस्टॉल केले नव्हते:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" अनइंस्टॉल किंवा बंद करून पहा&lt;/li&gt;
+ &lt;li&gt;दुसर्‍या वाय-फाय नेटवर्कशी कनेक्ट करून पहा&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index d6b5ec986b0..b239ccc1ffb 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Penanda Halaman Desktop</translation>
<translation id="1074497978438210769">Tidak selamat</translation>
<translation id="1080116354587839789">Muat ikut lebar</translation>
+<translation id="1088860948719068836">Tambahkan Nama pada Kad</translation>
<translation id="1103523840287552314">Sentiasa terjemahkan <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Tunjukkan semua kata laluan yang disimpan...</translation>
<translation id="1107591249535594099">Jika ditandai, Chrome akan menyimpan salinan kad anda pada peranti ini untuk pengisian borang yang lebih cepat.</translation>
<translation id="1111153019813902504">Penanda halaman terbaharu dilawati</translation>
<translation id="1113869188872983271">&amp;Buat asal susun semula</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (disegerakkan)</translation>
<translation id="1263231323834454256">Senarai bacaan</translation>
<translation id="1264126396475825575">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" /> (belum dimuat naik atau diabaikan)</translation>
+<translation id="1270502636509132238">Kaedah Pengambilan</translation>
<translation id="1281526147609854549">Dikeluarkan oleh <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Jangan sekali-kali menterjemahkan tapak ini</translation>
<translation id="129553762522093515">Ditutup baru-baru ini</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Menunggu sambungan...</translation>
<translation id="153384715582417236">Itu sahaja buat masa ini</translation>
<translation id="1549470594296187301">Javascript mesti didayakan untuk menggunakan ciri ini.</translation>
-<translation id="1555130319947370107">Biru</translation>
<translation id="1559528461873125649">Tiada fail atau direktori sedemikian</translation>
<translation id="1583429793053364125">Kesilapan berlaku semasa memaparkan halaman web ini.</translation>
<translation id="1592005682883173041">Akses Data Setempat</translation>
<translation id="1594030484168838125">Pilih</translation>
-<translation id="161042844686301425">Sian</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Adakah anda mahu Chrome menyimpan kad ini?</translation>
<translation id="1639239467298939599">Memuatkan</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Anda memerlukan kebenaran daripada <ph name="NAME" /> untuk melawat tapak ini</translation>
<translation id="1721424275792716183">* Medan perlu diisi</translation>
+<translation id="1727741090716970331">Tambahkan Nombor Kad yang Sah</translation>
<translation id="1728677426644403582">Anda sedang melihat sumber halaman web</translation>
<translation id="173080396488393970">Jenis kad ini tidak disokong</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Ralat penyirian</translation>
<translation id="1974060860693918893">Lanjutan</translation>
<translation id="1978555033938440688">Versi Perisian Tegar</translation>
-<translation id="1995859865337580572">Sila sahkan CVC anda</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lagi}other{dan # lagi}}</translation>
<translation id="2025186561304664664">Proksi ditetapkan kepada auto konfigurasi.</translation>
<translation id="2030481566774242610">Adakah anda maksudkan <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Buat asal</translation>
<translation id="20817612488360358">Tetapan proksi sistem telah sedia untuk digunakan tetapi konfigurasi proksi jelas juga telah ditentukan.</translation>
<translation id="2086652334978798447">Untuk mendapatkan kandungan diperibadikan yang dicadangkan oleh Google, log masuk ke Chrome.</translation>
+<translation id="2091887806945687916">Bunyi</translation>
<translation id="2094505752054353250">Domain tidak padan</translation>
<translation id="2096368010154057602">Jabatan</translation>
<translation id="2108755909498034140">Mulakan semula komputer anda</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Diabaikan kerana ia telah diatasi oleh <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Mencari halaman Web Fizikal yang berdekatan</translation>
<translation id="213826338245044447">Penanda Halaman Mudah Alih</translation>
+<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Penyegerakan Latar Belakang</translation>
+<translation id="2148613324460538318">Tambahkan Kad</translation>
<translation id="2154054054215849342">Penyegerakan tidak tersedia untuk domain anda</translation>
<translation id="2154484045852737596">Edit kad</translation>
<translation id="2166049586286450108">Akses Penuh Pentadbir</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
<translation id="2187317261103489799">Kesan (lalai)</translation>
<translation id="2202020181578195191">Masukkan tahun tamat tempoh yang sah</translation>
+<translation id="2209523182407020534">Aplikasi yang boleh menyebabkan ralat ini termasuk antivirus, tembok api dan perisian penapisan web atau proksi.</translation>
<translation id="2212735316055980242">Dasar tidak dijumpai</translation>
<translation id="2213606439339815911">Mengambil entri…</translation>
<translation id="2218879909401188352">Penyerang yang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> boleh memasang apl berbahaya yang boleh merosakkan peranti anda, menambahkan caj yang tersembunyi pada bil mudah alih anda atau mencuri maklumat peribadi anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Kembali</translation>
<translation id="2503184589641749290">Kad debit dan prabayar yang diterima</translation>
<translation id="2515629240566999685">Semak isyarat di kawasan anda</translation>
+<translation id="2524461107774643265">Tambahkan Maklumat Lanjut</translation>
+<translation id="2536110899380797252">Tambahkan Alamat</translation>
<translation id="2539524384386349900">Kesan</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> menghantar balasan yang tidak sah.</translation>
<translation id="2556876185419854533">&amp;Buat Asal Edit</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium tidak dapat mengesahkan kad anda pada masa ini. Sila cuba lagi nanti.</translation>
<translation id="2705137772291741111">Salinan tapak ini yang disimpan (cache) tidak boleh dibaca.</translation>
<translation id="2709516037105925701">Autoisi</translation>
+<translation id="2710942282213947212">Perisian pada komputer anda menghalang Chromium daripada menyambung ke web dengan selamat</translation>
<translation id="2712173769900027643">Minta kebenaran</translation>
-<translation id="2713444072780614174">Putih</translation>
<translation id="2720342946869265578">Berdekatan</translation>
<translation id="2721148159707890343">Permintaan berjaya</translation>
<translation id="2728127805433021124">Sijil pelayan ditandatangani menggunakan algoritma tandatangan yang lemah.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Perubahan rangkaian dikesan.</translation>
<translation id="2916038427272391327">Tutup atur cara lain</translation>
<translation id="2922350208395188000">Sijil pelayan tidak boleh diperiksa.</translation>
+<translation id="2925673989565098301">Kaedah Penghantaran</translation>
<translation id="2928905813689894207">Alamat Pengebilan</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lagi}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> lagi}}</translation>
<translation id="2941952326391522266">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya adalah dari <ph name="DOMAIN2" />. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Jenis dasar salah</translation>
<translation id="3032412215588512954">Adakah anda ingin memuat semula tapak ini?</translation>
<translation id="3037605927509011580">Oh, Tidak!</translation>
+<translation id="3039538478787849737">Simpan kad ke Google?</translation>
<translation id="3041612393474885105">Maklumat Sijil</translation>
<translation id="3063697135517575841">Chrome tidak dapat mengesahkan kad anda pada masa ini. Sila cuba sebentar lagi.</translation>
<translation id="3064966200440839136">Meninggalkan mod inkognito untuk membayar melalui aplikasi luar. Teruskan?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Ralat pelayan sementara</translation>
<translation id="3154506275960390542">Halaman ini mengandungi borang yang mungkin tidak diserahkan secara selamat. Data yang dihantar boleh dilihat oleh orang lain semasa dihantar atau boleh diubah suai oleh penyerang untuk mengubah data yang diterima oleh pelayan.</translation>
<translation id="3157931365184549694">Pulihkan</translation>
+<translation id="3162559335345991374">Wi-Fi yang anda gunakan mungkin memerlukan anda untuk melawat halaman log masuknya.</translation>
<translation id="3167968892399408617">Halaman yang anda lihat dalam tab inkognito tidak akan kekal dalam sejarah, simpanan kuki atau sejarah carian penyemak imbas anda selepas anda menutup semua tab inkognito anda. Sebarang fail yang anda muat turun atau penanda halaman yang anda buat akan disimpan.</translation>
<translation id="3169472444629675720">Temui</translation>
<translation id="3174168572213147020">Pulau</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Batal Pembayaran</translation>
<translation id="3207960819495026254">Ditandai halaman</translation>
+<translation id="3211223744486044430">Untuk membayar dengan lebih cepat selepas ini, simpan kad ini ke Akaun Google anda dan peranti ini.</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>
<translation id="3226128629678568754">Tekan butang muat semula untuk menyerahkan kembali data yang diperlukan untuk memuatkan halaman.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Tiada hasil carian ditemui</translation>
<translation id="3305707030755673451">Data anda disulitkan dengan ungkapan laluan segerak anda pada <ph name="TIME" />. Masukkannya untuk memulakan penyegerakan.</translation>
<translation id="3320021301628644560">Tambahkan alamat pengebilan</translation>
-<translation id="3329013043687509092">Ketepuan</translation>
<translation id="333371639341676808">Halang halaman ini daripada mencipta dialog tambahan.</translation>
<translation id="3338095232262050444">Selamat</translation>
<translation id="3340978935015468852">tetapan</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID Pelanggan:</translation>
<translation id="3391030046425686457">Alamat penghantaran</translation>
<translation id="3395827396354264108">Kaedah pengambilan</translation>
+<translation id="3399952811970034796">Alamat Penghantaran</translation>
<translation id="3422248202833853650">Cuba keluar daripada atur cara lain untuk mengosongkan memori.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> tidak dapat dicapai pada masa ini.</translation>
<translation id="3427092606871434483">Benarkan (lalai)</translation>
@@ -366,10 +377,12 @@
<translation id="3679803492151881375">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" />, dimuat naik pada <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Maklumat sijil</translation>
<translation id="3690164694835360974">Log masuk tidak selamat</translation>
+<translation id="3704162925118123524">Rangkaian yang anda gunakan mungkin memerlukan anda untuk melawat halaman log masuknya.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Memuatkan...</translation>
<translation id="3712624925041724820">Kehabisan lesen</translation>
<translation id="3714780639079136834">Menghidupkan data mudah alih atau Wi-Fi</translation>
+<translation id="3715597595485130451">Sambung ke Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Menyemak proksi, tembok api dan konfigurasi DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Jika anda memahami risiko terhadap keselamatan anda, anda boleh <ph name="BEGIN_LINK" />melawati tapak web yang tidak selamat ini<ph name="END_LINK" /> sebelum program berbahaya dialih keluar.</translation>
<translation id="3739623965217189342">Pautan yang anda salin</translation>
@@ -404,6 +417,7 @@
<translation id="4030383055268325496">&amp;Buat asal tambahkan</translation>
<translation id="404928562651467259">AMARAN</translation>
<translation id="4058922952496707368">Kekunci "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfigurasi proksi ditetapkan kepada penggunaaan URL skrip .pac, bukannya pelayan proksi tetap.</translation>
@@ -411,7 +425,6 @@
<translation id="4103249731201008433">Nombor siri peranti tidak sah</translation>
<translation id="410351446219883937">Automain</translation>
<translation id="4103763322291513355">Lawati &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat senarai URL yang disenarai hitam dan dasar lain yang dikuatkuasakan oleh pentadbir sistem anda.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Sentiasa benarkan di tapak ini</translation>
<translation id="4117700440116928470">Skop dasar tidak disokong.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 yang lain}other{# yang lain}}</translation>
@@ -449,6 +462,7 @@
<translation id="4377125064752653719">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi sijil yang diberi pelayan telah dibatalkan oleh pengeluarnya. Ini bermakna bahawa bukti kelayakan keselamatan yang diberi pelayan sememangnya tidak harus dipercayai. Anda mungkin berkomunikasi dengan penyerang.</translation>
<translation id="4394049700291259645">Lumpuhkan</translation>
<translation id="4406896451731180161">hasil carian</translation>
+<translation id="4415426530740016218">Alamat Pengambilan</translation>
<translation id="4424024547088906515">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chrome. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang memintasi sambungan anda.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sijil log masuk anda atau sijil log masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proksi dilumpuhkan tetapi konfigurasi proksi yang jelas dinyatakan.</translation>
@@ -461,6 +475,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Cuba lumpuhkan sambungan anda.</translation>
<translation id="457875822857220463">Penghantaran</translation>
+<translation id="4582800630050655161">Anda boleh kehilangan akses kepada Akaun Google anda atau mengalami kecurian identiti. Chromium mengesyorkan supaya kata laluan anda ditukar sekarang.</translation>
<translation id="4587425331216688090">Alih keluar alamat daripada Chrome?</translation>
<translation id="4592951414987517459">Sambungan anda ke <ph name="DOMAIN" /> disulitkan menggunakan suit sifer moden.</translation>
<translation id="4594403342090139922">&amp;Buat asal Pemadaman</translation>
@@ -469,10 +484,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Berhenti menggunakan sijil tidak sah</translation>
+<translation id="4690954380545377795">Anda boleh kehilangan akses kepada Akaun Google anda atau mengalami kecurian identiti. Chrome mengesyorkan supaya kata laluan anda ditukar sekarang.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Sambungan anda tergendala</translation>
<translation id="471880041731876836">Anda tiada kebenaran untuk melawat tapak ini</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Pembayaran anda</translation>
<translation id="4726672564094551039">Muat semula dasar</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Mulakan semula Chromium</translation>
@@ -511,6 +528,7 @@
<translation id="5019198164206649151">Simpanan penyandaran dalam keadaan buruk</translation>
<translation id="5023310440958281426">Semak dasar pentadbir anda</translation>
<translation id="5029568752722684782">Hapuskan salinan</translation>
+<translation id="503069730517007720">Sijil akar bagi "<ph name="SOFTWARE_NAME" />" diperlukan tetapi tidak dipasang. Pentadbir IT anda harus melihat arahan konfigurasi "<ph name="SOFTWARE_NAME" />" untuk menyelesaikan masalah ini. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Perihal Google Terjemah</translation>
<translation id="5039804452771397117">Benarkan</translation>
<translation id="5040262127954254034">Privasi</translation>
@@ -534,6 +552,8 @@
<translation id="5199729219167945352">Eksperimen</translation>
<translation id="5205222826937269299">Nama diperlukan</translation>
<translation id="5222812217790122047">E-mel diperlukan</translation>
+<translation id="522700295135997067">Tapak ini mungkin baru sahaja mencuri kata laluan anda</translation>
+<translation id="5230733896359313003">Alamat Penghantaran</translation>
<translation id="5251803541071282808">Awan</translation>
<translation id="5277279256032773186">Menggunakan Chrome di tempat kerja? Perniagaan boleh mengurus tetapan Chrome untuk pekerja mereka. Ketahui lebih lanjut</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Ikut langkah ini untuk melumpuhkan perisian buat sementara waktu supaya anda boleh memasuki web. Anda memerlukan keistimewaan pentadbir.<ph name="END_PARAGRAPH" />
@@ -548,9 +568,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Sambungan anda ke tapak ini tidak peribadi. Untuk keluar daripada mod VR pada bila-bila masa, tanggalkan set kepala dan tekan kembali.</translation>
<translation id="5299298092464848405">Ralat semasa menghuraikan dasar</translation>
+<translation id="5308380583665731573">Sambung</translation>
<translation id="5308689395849655368">Pelaporan nahas dilumpuhkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
<translation id="5327248766486351172">Nama</translation>
+<translation id="5332219387342487447">Kaedah Penghantaran</translation>
<translation id="5355557959165512791">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana sijil tapak ini telah ditarik balik. Ralat dan serangan rangkaian biasanya bersifat sementara. Oleh sebab itu, halaman ini mungkin akan berfungsi semula kemudian.</translation>
<translation id="536296301121032821">Gagal menyimpan tetapan dasar</translation>
<translation id="5386426401304769735">Rantaian sijil untuk tapak ini mengandungi sijil yang ditandatangani menggunakan SHA-1.</translation>
@@ -570,12 +592,15 @@
<translation id="5492298309214877701">Tapak ini yang berada di intranet syarikat, organisasi atau sekolah mempunyai URL yang sama dengan tapak web luar.
<ph name="LINE_BREAK" />
Cuba hubungi pentadbir sistem anda.</translation>
+<translation id="5499929369096410817">Masukkan kod keselamatan untuk <ph name="CREDIT_CARD" />. Kod ini tidak akan disimpan.</translation>
<translation id="5509780412636533143">Penanda halaman terurus</translation>
<translation id="5510766032865166053">Fail mungkin telah dipindahkan atau dipadamkan.</translation>
<translation id="5523118979700054094">Nama dasar</translation>
<translation id="552553974213252141">Adakah teks diekstrak dengan betul?</translation>
<translation id="5540224163453853">Tidak menemui artikel yang diminta.</translation>
+<translation id="5541546772353173584">Tambahkan E-mel</translation>
<translation id="5544037170328430102">Halaman terbenam di <ph name="SITE" /> menyatakan:</translation>
+<translation id="5545756402275714221">Artikel untuk Anda</translation>
<translation id="5556459405103347317">Muat Semula</translation>
<translation id="5560088892362098740">Tarikh Tamat Tempoh</translation>
<translation id="5565735124758917034">Aktif</translation>
@@ -597,6 +622,7 @@
<translation id="5659593005791499971">E-mel</translation>
<translation id="5669703222995421982">Dapatkan kandungan yang diperibadikan</translation>
<translation id="5675650730144413517">Halaman ini tidak berfungsi</translation>
+<translation id="5689199277474810259">Eksport ke JSON</translation>
<translation id="5710435578057952990">Identiti tapak web ini belum disahkan.</translation>
<translation id="5719499550583120431">Kad prabayar diterima.</translation>
<translation id="5720705177508910913">Pengguna semasa</translation>
@@ -611,27 +637,27 @@
<translation id="5810442152076338065">Sambungan anda ke <ph name="DOMAIN" /> disulitkan menggunakan suit sifer yang sudah usang.</translation>
<translation id="5813119285467412249">&amp;Buat Semula Tambahkan</translation>
<translation id="5838278095973806738">Anda tidak seharusnya memasukkan sebarang maklumat sensitif pada tapak ini (contohnya, kata laluan atau maklumat kad kredit) kerana maklumat ini boleh dicuri oleh penyerang.</translation>
+<translation id="5866257070973731571">Tambahkan Nombor Telefon</translation>
<translation id="5869405914158311789">Tapak ini tidak dapat dicapai</translation>
<translation id="5869522115854928033">Kata laluan disimpan</translation>
<translation id="5872918882028971132">Cadangan Ibu Bapa</translation>
<translation id="5893752035575986141">Kad kredit diterima.</translation>
-<translation id="5901630391730855834">Kuning</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (disegerakkan)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 sedang digunakan}other{# sedang digunakan}}</translation>
<translation id="5959728338436674663">Hantar secara automatik beberapa <ph name="BEGIN_WHITEPAPER_LINK" />maklumat sistem dan kandungan halaman<ph name="END_WHITEPAPER_LINK" /> kepada Google untuk membantu anda mengesan apl dan tapak yang berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edit Maklumat Hubungan</translation>
<translation id="5967867314010545767">Buang daripada sejarah</translation>
<translation id="5975083100439434680">Zum keluar</translation>
+<translation id="597552863672748783">Sahkan kod keselamatan</translation>
<translation id="598637245381783098">Tidak dapat membuka apl pembayaran</translation>
<translation id="5989320800837274978">Pelayan proksi tetap begitu juga URL skrip .pac, kedua-duanya tidak ditetapkan.</translation>
<translation id="5990559369517809815">Permintaan pada pelayan telah disekat oleh sambungan.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Halaman 1}other{Halaman #}}</translation>
-<translation id="6017514345406065928">Hijau</translation>
<translation id="6017850046339264347">Penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> boleh memasang apl yang mengelirukan yang menyamar menjadi sesuatu yang lain atau mengumpul data yang boleh digunakan untuk menjejak anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (disegerakkan)</translation>
<translation id="6027201098523975773">Masukkan nama</translation>
<translation id="6040143037577758943">Tutup</translation>
-<translation id="6042308850641462728">Lagi</translation>
<translation id="6047233362582046994">Jika anda memahami risiko terhadap keselamatan anda, anda boleh <ph name="BEGIN_LINK" />melawat tapak ini<ph name="END_LINK" /> sebelum program yang berbahaya ini dialih keluar.</translation>
<translation id="6047927260846328439">Kandungan ini mungkin menggunakan tipu muslihat supaya anda memasang perisian atau mendedahkan maklumat peribadi. <ph name="BEGIN_LINK" />Tunjukkan juga<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menggunakan penyematan sijil. Ralat dan serangan rangkaian biasanya bersifat sementara. Oleh sebab itu, halaman ini mungkin akan berfungsi semula kemudian.</translation>
@@ -698,6 +724,7 @@
<translation id="6569060085658103619">Anda sedang melihat halaman sambungan</translation>
<translation id="6596325263575161958">Pilihan penyulitan</translation>
<translation id="662080504995468778">Kekal di sini</translation>
+<translation id="6624427990725312378">Maklumat Hubungan</translation>
<translation id="6626291197371920147">Tambahkan nombor kad yang sah</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Carian</translation>
<translation id="6630809736994426279">Penyerang yang sedang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin cuba memasang atur cara berbahaya pada komputer Mac anda. Atur cara tersebut boleh mencuri atau memadamkan maklumat anda (contohnya, foto, kata laluan, mesej dan kad kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -708,7 +735,6 @@
<translation id="6710213216561001401">Sebelumnya</translation>
<translation id="6710594484020273272">&lt;Taip istilah carian&gt;</translation>
<translation id="6711464428925977395">Ada sesuatu yang tidak kena dengan pelayan proksi atau alamat tidak betul.</translation>
-<translation id="6727102863431372879">Tetapkan</translation>
<translation id="674375294223700098">Ralat sijil pelayan tidak diketahui.</translation>
<translation id="6753269504797312559">Nilai dasar</translation>
<translation id="6757797048963528358">Peranti anda tidak aktif.</translation>
@@ -777,6 +803,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Laluan Profil</translation>
<translation id="7424977062513257142">Halaman terbenam pada halaman web ini menyatakan:</translation>
+<translation id="7437289804838430631">Tambahkan Maklumat Hubungan</translation>
<translation id="7441627299479586546">Subjek dasar salah</translation>
<translation id="7444046173054089907">Tapak ini disekat</translation>
<translation id="7445762425076701745">Identiti pelayan yang disambungkan kepada anda tidak dapat disahkan sepenuhnya. Anda disambungkan ke pelayan menggunakan nama yang sah dalam rangkaian anda sahaja, apabila pihak berkuasa sijil luaran tiada cara untuk mengesahkan pemilikan. Oleh kerana beberapa pihak berkuasa sijil juga akan terus mengeluarkan sijil untuk nama ini, tiada cara untuk memastikan anda disambungkan ke tapak web yang diingini dan bukannya penyerang.</translation>
@@ -787,11 +814,11 @@
<translation id="7481312909269577407">Majukan</translation>
<translation id="7485870689360869515">Tiada data dijumpai.</translation>
<translation id="7508255263130623398">Id peranti yang dikembalikan kosong atau tidak sepadan dengan id peranti semasa</translation>
+<translation id="7511955381719512146">Wi-Fi yang anda gunakan mungkin memerlukan anda untuk melawat <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Muat Turun</translation>
<translation id="7518003948725431193">Tiada halaman web dijumpai untuk alamat web: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Sambungan anda ke tapak ini tidak berciri peribadi</translation>
-<translation id="7535087603100972091">Nilai</translation>
<translation id="7537536606612762813">Wajib</translation>
<translation id="7542403920425041731">Setelah anda mengesahkan, butiran kad anda akan dikongsi dengan tapak ini.</translation>
<translation id="7542995811387359312">Pengisian kad kredit automatik dilumpuhkan kerana borang ini tidak menggunakan sambungan selamat.</translation>
@@ -802,7 +829,6 @@
<translation id="7567204685887185387">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mungkin telah dikeluarkan melalui penipuan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="7568593326407688803">Halaman ini adalah dalam<ph name="ORIGINAL_LANGUAGE" />Adakah anda ingin menterjemahkannya?</translation>
<translation id="7569952961197462199">Alih keluar kad kredit daripada Chrome?</translation>
-<translation id="7569983096843329377">Hitam</translation>
<translation id="7578104083680115302">Bayar dengan cepat di tapak dan apl merentas peranti menggunakan kad yang telah disimpan dengan Google.</translation>
<translation id="7588950540487816470">Web Fizikal</translation>
<translation id="7592362899630581445">Sijil pelayan melanggar kekangan nama.</translation>
@@ -821,11 +847,13 @@
<translation id="7669271284792375604">Penyerang pada tapak ini mungkin cuba menipu dengan meminta anda memasang atur cara yang membahayakan pengalaman penyemakan imbas anda (contohnya, dengan menukar halaman utama anda atau menunjukkan iklan tambahan pada laman yang anda lawati).</translation>
<translation id="7674629440242451245">Berminat dengan ciri Chrome baharu yang hebat? Cuba saluran pembangun kami di chrome.com/dev.</translation>
<translation id="7682287625158474539">Penghantaran</translation>
+<translation id="7699293099605015246">Artikel tidak tersedia sekarang</translation>
<translation id="7701040980221191251">Tiada</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Teruskan ke <ph name="SITE" /> (tidak selamat)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sijil</translation>
<translation id="7716147886133743102">Disekat oleh pentadbir anda</translation>
<translation id="7716424297397655342">Tapak ini tidak dapat dimuatkan daripada cache</translation>
+<translation id="7723047071702270851">Edit Kad</translation>
<translation id="774634243536837715">Kandungan berbahaya disekat.</translation>
<translation id="7752995774971033316">Tidak Diurus</translation>
<translation id="7755287808199759310">Ibu bapa anda boleh menyahsekatnya untuk anda</translation>
@@ -836,21 +864,24 @@
<translation id="7764225426217299476">Tambahkan alamat</translation>
<translation id="777702478322588152">Wilayah</translation>
<translation id="7791543448312431591">Tambah</translation>
+<translation id="7793553086574152071">Untuk membayar dengan lebih cepat selepas ini, simpan kad ini ke Akaun Google anda.</translation>
<translation id="7793809570500803535">Halaman web di <ph name="SITE" /> mungkin tergendala buat sementara waktu atau ia mungkin dpindahkan secara kekal ke alamat web baharu.</translation>
<translation id="7800304661137206267">Sambungan disulitkan menggunakan <ph name="CIPHER" />, dengan <ph name="MAC" /> untuk pengesahan mesej dan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
+<translation id="7802523362929240268">Tapak ini sah</translation>
<translation id="780301667611848630">Tidak, terima kasih</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Alih keluar cadangan borang daripada Chrome?</translation>
<translation id="7815407501681723534">Menemui <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> untuk '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Wi-Fi yang anda gunakan (<ph name="WIFI_NAME" />) mungkin memerlukan anda melawat halaman log masuknya.</translation>
<translation id="785549533363645510">Walau bagaimanapun, anda tidak halimunan. Apabila anda menggunakan mod inkognito, penyemakan imbas anda tidak akan disembunyikan daripada majikan anda, penyedia perkhidmatan Internet anda atau tapak web yang anda lawati.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Kad debit dan prabayar diterima.</translation>
+<translation id="7878562273885520351">Kata laluan anda mungkin terjejas</translation>
<translation id="7887683347370398519">Semak CVC anda dan cuba lagi</translation>
<translation id="79338296614623784">Masukkan nombor telefon yang sah</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Sijil pelayan masih belum sah.</translation>
-<translation id="7942349550061667556">Merah</translation>
<translation id="7947285636476623132">Semak tahun tamat tempoh anda dan cuba lagi</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Penanda halaman mudah alih</translation>
@@ -864,9 +895,13 @@
<translation id="8037357227543935929">Tanya (lalai)</translation>
<translation id="8041089156583427627">Hantar Maklum Balas</translation>
<translation id="8041940743680923270">Gunakan lalai global (Tanya)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" tidak dikonfigurasi dengan betul. Tindakan menyahpasang "<ph name="SOFTWARE_NAME" />" biasanya dapat menyelesaikan masalah ini. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
<translation id="8091372947890762290">Pengaktifan belum selesai pada pelayan</translation>
+<translation id="8094917007353911263">Rangkaian yang anda gunakan mungkin memerlukan anda melawat <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Kaedah Pembayaran</translation>
<translation id="8118489163946903409">Kaedah pembayaran</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" tidak dipasang dengan betul pada komputer atau rangkaian anda. Minta pentadbir IT anda menyelesaikan isu ini.</translation>
<translation id="8131740175452115882">Sahkan</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> pelayan <ph name="HOST_NAME" /> tidak ditemui.</translation>
<translation id="8149426793427495338">Komputer anda dalam mod tidur.</translation>
@@ -889,6 +924,7 @@
<translation id="8289355894181816810">Hubungi pentadbir rangkaian anda jika anda tidak pasti apa yang dimaksudkan ini.</translation>
<translation id="8293206222192510085">Tambah Penanda Halaman</translation>
<translation id="8294431847097064396">Sumber</translation>
+<translation id="8298115750975731693">Wi-Fi yang anda gunakan (<ph name="WIFI_NAME" />) mungkin memerlukan anda untuk melawat <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Sambungan peribadi kepada <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat diwujudkan kerana tarikh dan masa peranti anda (<ph name="DATE_AND_TIME" />) tidak betul. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Gagal terjemahan kerana masalah dengan sambungan rangkaian.</translation>
<translation id="8332188693563227489">Akses ke <ph name="HOST_NAME" /> dinafikan</translation>
@@ -942,20 +978,21 @@
<translation id="8870413625673593573">Ditutup Baru-baru Ini</translation>
<translation id="8874824191258364635">Masukkan nombor kad yang sah</translation>
<translation id="8876793034577346603">Konfigurasi rangkaian gagal dihuraikan.</translation>
-<translation id="8889402386540077796">Rona</translation>
<translation id="8891727572606052622">Mod proksi tidak sah.</translation>
<translation id="889901481107108152">Maaf, eksperimen ini tidak tersedia pada platform anda.</translation>
<translation id="8903921497873541725">Zum masuk</translation>
<translation id="8931333241327730545">Adakah anda mahu menyimpan kad ini ke Akaun Google anda?</translation>
<translation id="8932102934695377596">Jam anda di belakang</translation>
+<translation id="893332455753468063">Tambahkan Nama</translation>
<translation id="8938939909778640821">Kad kredit dan prabayar yang diterima</translation>
+<translation id="8957210676456822347">Keizinan Portal Tawanan</translation>
<translation id="8971063699422889582">Sijil pelayan telah tamat tempoh.</translation>
-<translation id="8986494364107987395">Hantar statistik penggunaan dan laporan nahas kepada Google secara automatik</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Laman web yang akan dilayari mengandungi atur cara berbahaya</translation>
<translation id="8997023839087525404">Pelayan memberikan sijil yang tidak didedahkan kepada umum menggunakan dasar Ketelusan Sijil. Ini merupakan keperluan bagi sesetengah sijil untuk memastikan sijil itu boleh dipercayai dan untuk melindungi pengguna daripada penyerang.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> proksi memerlukan nama pengguna dan kata laluan.</translation>
<translation id="9005998258318286617">Gagal memuatkan dokumen PDF.</translation>
+<translation id="9008201768610948239">Abaikan</translation>
<translation id="901974403500617787">Bendera yang diguna pakai di seluruh sistem hanya boleh ditetapkan oleh pemilik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Alamat pengebilan kad diperlukan</translation>
<translation id="9020542370529661692">Halaman ini telah diterjemahkan kepada <ph name="TARGET_LANGUAGE" /></translation>
@@ -965,11 +1002,14 @@
<translation id="9049981332609050619">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil tidak sah.</translation>
<translation id="9050666287014529139">Frasa laluan</translation>
<translation id="9065203028668620118">Edit</translation>
-<translation id="9068849894565669697">Pilih warna</translation>
<translation id="9069693763241529744">Disekat oleh sambungan</translation>
<translation id="9076283476770535406">Tapak mungkin mengandungi kandungan dewasa</translation>
<translation id="9078964945751709336">Maklumat lanjut diperlukan</translation>
+<translation id="9080712759204168376">Ringkasan Pesanan</translation>
<translation id="9103872766612412690"><ph name="SITE" /> biasanya menggunakan penyulitan untuk melindungi maklumat anda. Apabila Chromium cuba menyambung ke <ph name="SITE" /> pada kali ini, tapak web tersebut mengembalikan bukti kelayakan yang luar biasa dan salah. Hal ini boleh berlaku apabila penyerang sedang cuba menyamar sebagai <ph name="SITE" /> atau skrin log masuk Wi-Fi telah memutuskan sambungan. Maklumat anda masih selamat kerana Chromium menghentikan sambungan sebelum sebarang pertukaran data berlaku.</translation>
+<translation id="9106062320799175032">Tambahkan Alamat Pengebilan</translation>
+<translation id="910908805481542201">Bantu saya menyelesaikan masalah ini</translation>
+<translation id="9128870381267983090">Sambung ke rangkaian</translation>
<translation id="9137013805542155359">Paparkan asal</translation>
<translation id="9137248913990643158">Sila mulakan dan log masuk ke Chrome sebelum menggunakan apl ini.</translation>
<translation id="9148507642005240123">&amp;Buat asal edit</translation>
@@ -981,6 +1021,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> menggunakan protokol yang tidak disokong.</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="9215416866750762878">Satu aplikasi menghalang Chrome daripada menyambung ke tapak ini dengan selamat</translation>
<translation id="9219103736887031265">Imej</translation>
<translation id="933612690413056017">Tiada sambungan Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -990,5 +1031,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Tiada}=1{1 item}other{# item}}</translation>
<translation id="981121421437150478">Luar talian</translation>
<translation id="988159990683914416">Binaan Pemaju</translation>
+<translation id="989988560359834682">Edit Alamat</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" tidak dipasang dengan betul pada komputer atau rangkaian anda:
+ &lt;ul&gt;
+ &lt;li&gt;Cuba nyahpasang atau lumpuhkan "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Cuba sambung ke rangkaian lain&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index 33f609e48ce..428f4a38f35 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Desktopbladwijzers</translation>
<translation id="1074497978438210769">Niet veilig</translation>
<translation id="1080116354587839789">Aanpassen aan breedte</translation>
+<translation id="1088860948719068836">Naam op kaart toevoegen</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> altijd vertalen</translation>
+<translation id="1103778128462718200">Alle opgeslagen wachtwoorden weergeven…</translation>
<translation id="1107591249535594099">Als deze optie is aangevinkt, bewaart Chrome een exemplaar van je kaart op dit apparaat om formulieren sneller te kunnen invullen.</translation>
<translation id="1111153019813902504">Onlangs bezochte bladwijzers</translation>
<translation id="1113869188872983271">&amp;Volgorde wijzigen ongedaan maken</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (gesynchroniseerd)</translation>
<translation id="1263231323834454256">Leeslijst</translation>
<translation id="1264126396475825575">Crashrapport vastgelegd op <ph name="CRASH_TIME" /> (nog niet geüpload of genegeerd)</translation>
+<translation id="1270502636509132238">Ophaalmethode</translation>
<translation id="1281526147609854549">Uitgegeven door <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Deze site nooit vertalen</translation>
<translation id="129553762522093515">Recent gesloten</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Wachten op verbinding...</translation>
<translation id="153384715582417236">Dat is voorlopig alles</translation>
<translation id="1549470594296187301">JavaScript moet zijn ingeschakeld om deze functie te kunnen gebruiken.</translation>
-<translation id="1555130319947370107">Blauw</translation>
<translation id="1559528461873125649">Dit bestand of deze directory bestaat niet</translation>
<translation id="1583429793053364125">Er is iets misgegaan met het weergeven van deze webpagina.</translation>
<translation id="1592005682883173041">Lokale gegevenstoegang</translation>
<translation id="1594030484168838125">Kiezen</translation>
-<translation id="161042844686301425">Cyaan</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1629803312968146339">Wil je dat Chrome deze kaart opslaat?</translation>
<translation id="1639239467298939599">Laden</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Besturingssysteem</translation>
<translation id="1721312023322545264">Je hebt toestemming van <ph name="NAME" /> nodig om deze site te bezoeken</translation>
<translation id="1721424275792716183">* Verplicht veld</translation>
+<translation id="1727741090716970331">Een geldig kaartnummer toevoegen</translation>
<translation id="1728677426644403582">Je bekijkt de bron van een webpagina</translation>
<translation id="173080396488393970">Dit type kaart wordt niet ondersteund</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serialisatiefout</translation>
<translation id="1974060860693918893">Geavanceerd</translation>
<translation id="1978555033938440688">Firmwareversie</translation>
-<translation id="1995859865337580572">Verifieer je CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{en 1 andere}other{en # andere}}</translation>
<translation id="2025186561304664664">Proxy is ingesteld op automatische configuratie.</translation>
<translation id="2030481566774242610">Bedoelde je <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Log in bij Chrome om suggesties met gepersonaliseerde content van Google te ontvangen.</translation>
+<translation id="2091887806945687916">Geluid</translation>
<translation id="2094505752054353250">Domeinen komen niet overeen</translation>
<translation id="2096368010154057602">Departement</translation>
<translation id="2108755909498034140">Je computer opnieuw opstarten</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Genegeerd omdat het werd overschreven door <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Bezig met zoeken naar Fysieke webpagina's in de buurt</translation>
<translation id="213826338245044447">Mobiele bladwijzers</translation>
+<translation id="214556005048008348">Betaling annuleren</translation>
<translation id="2147827593068025794">Synchronisatie op de achtergrond</translation>
+<translation id="2148613324460538318">Kaart toevoegen</translation>
<translation id="2154054054215849342">De synchronisatieservice is niet beschikbaar voor je domein</translation>
<translation id="2154484045852737596">Kaart bewerken</translation>
<translation id="2166049586286450108">Volledige beheerderstoegang</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adressen}}</translation>
<translation id="2187317261103489799">Detecteren (standaard)</translation>
<translation id="2202020181578195191">Geef een geldig vervaljaar op</translation>
+<translation id="2209523182407020534">Apps die deze fout kunnen veroorzaken, omvatten antivirussoftware, firewalls en webfilter- of proxysoftware.</translation>
<translation id="2212735316055980242">Beleid niet gevonden</translation>
<translation id="2213606439339815911">Items ophalen…</translation>
<translation id="2218879909401188352">Aanvallers die zich momenteel op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> bevinden, kunnen gevaarlijke apps installeren die je apparaat beschadigen, verborgen kosten toevoegen aan je mobiele telefoonrekening of je persoonlijke gegevens stelen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Terug</translation>
<translation id="2503184589641749290">Geaccepteerde betaalpassen en prepaidkaarten</translation>
<translation id="2515629240566999685">Controleer het signaal in je omgeving</translation>
+<translation id="2524461107774643265">Meer informatie toevoegen</translation>
+<translation id="2536110899380797252">Adres toevoegen</translation>
<translation id="2539524384386349900">Detecteren</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> heeft een ongeldige reactie verzonden.</translation>
<translation id="2556876185419854533">&amp;Bewerken ongedaan maken</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
<translation id="2705137772291741111">De in het cachegeheugen opgeslagen versie van deze site is niet bereikbaar.</translation>
<translation id="2709516037105925701">Automatisch aanvullen</translation>
+<translation id="2710942282213947212">Software op je computer voorkomt dat Chromium veilig verbinding kan maken met internet</translation>
<translation id="2712173769900027643">Toestemming vragen</translation>
-<translation id="2713444072780614174">Wit</translation>
<translation id="2720342946869265578">In de buurt</translation>
<translation id="2721148159707890343">Verzoek geslaagd</translation>
<translation id="2728127805433021124">Het certificaat van de server is ondertekend met een zwak ondertekeningsalgoritme.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Er is een netwerkwijziging gedetecteerd.</translation>
<translation id="2916038427272391327">Andere programma's sluiten</translation>
<translation id="2922350208395188000">Het servercertificaat kan niet worden gecontroleerd.</translation>
+<translation id="2925673989565098301">Bezorgingsmethode</translation>
<translation id="2928905813689894207">Factuuradres</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is afkomstig van <ph name="DOMAIN2" />. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Onjuist beleidstype</translation>
<translation id="3032412215588512954">Wil je deze site opnieuw laden?</translation>
<translation id="3037605927509011580">Helaas.</translation>
+<translation id="3039538478787849737">Kaart opslaan op Google?</translation>
<translation id="3041612393474885105">Certificaatgegevens</translation>
<translation id="3063697135517575841">Chrome kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
<translation id="3064966200440839136">Je verlaat de incognitomodus om te betalen via een externe app. Doorgaan?</translation>
@@ -278,12 +287,14 @@
<translation id="3150653042067488994">Tijdelijke serverfout</translation>
<translation id="3154506275960390542">Deze pagina bevat een formulier dat mogelijk niet beveiligd wordt verzonden. Gegevens die je verzendt, kunnen tijdens de overdracht worden bekeken door anderen of kunnen worden aangepast door een aanvaller om te wijzigen wat de server ontvangt.</translation>
<translation id="3157931365184549694">Herstellen</translation>
+<translation id="3162559335345991374">Het is mogelijk dat je de inlogpagina moet bezoeken van het wifi-netwerk dat je gebruikt.</translation>
<translation id="3167968892399408617">De pagina's die je op incognitotabbladen weergeeft, worden niet bewaard in je browsergeschiedenis, cookie-opslag of zoekgeschiedenis nadat je al je incognitotabbladen hebt gesloten. Alle bestanden die je hebt gedownload of bladwijzers die je hebt gemaakt, blijven behouden.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Eiland</translation>
<translation id="3176929007561373547">Controleer je proxyinstellingen of neem contact op met je netwerkbeheerder om te controleren of de proxyserver werkt. Als je denkt dat je geen proxyserver zou moeten gebruiken: <ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Betaling annuleren</translation>
<translation id="3207960819495026254">Toegevoegd aan 'Bladwijzers'</translation>
+<translation id="3211223744486044430">Sla deze kaart op in je Google-account en op dit apparaat zodat je de volgende keer sneller kunt betalen.</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>
<translation id="3226128629678568754">Klik op de knop 'Opnieuw laden' om de gegevens opnieuw te verzenden die nodig zijn om de pagina te laden.</translation>
<translation id="3227137524299004712">Microfoon</translation>
@@ -298,7 +309,6 @@
<translation id="3303855915957856445">Geen zoekresultaten gevonden</translation>
<translation id="3305707030755673451">Je gegevens zijn op <ph name="TIME" /> versleuteld met je wachtwoordzin voor synchronisatie. Geef deze op om de synchronisatie te starten.</translation>
<translation id="3320021301628644560">Factuuradres toevoegen</translation>
-<translation id="3329013043687509092">Verzadiging</translation>
<translation id="333371639341676808">Voorkom dat deze pagina extra dialoogvensters weergeeft.</translation>
<translation id="3338095232262050444">Veilig</translation>
<translation id="3340978935015468852">instellingen</translation>
@@ -317,6 +327,7 @@
<translation id="3380864720620200369">Klant-ID:</translation>
<translation id="3391030046425686457">Afleveradres</translation>
<translation id="3395827396354264108">Ophaalmethode</translation>
+<translation id="3399952811970034796">Bezorgadres</translation>
<translation id="3422248202833853650">Probeer andere programma's af te sluiten om geheugen vrij te maken.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is momenteel niet bereikbaar.</translation>
<translation id="3427092606871434483">Toestaan (standaard)</translation>
@@ -361,10 +372,12 @@
<translation id="3679803492151881375">Crashrapport vastgelegd op <ph name="CRASH_TIME" />, geüpload op <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certificaatgegevens</translation>
<translation id="3690164694835360974">Inloggen niet veilig</translation>
+<translation id="3704162925118123524">Het is mogelijk dat je de inlogpagina moet bezoeken van het netwerk dat je gebruikt.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Bezig met laden...</translation>
<translation id="3712624925041724820">Licenties zijn verbruikt</translation>
<translation id="3714780639079136834">Schakel mobiele data of wifi in</translation>
+<translation id="3715597595485130451">Verbinding maken met wifi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controleer de proxy, firewall en DNS-configuratie<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Als je de beveiligingsrisico's begrijpt, kun je <ph name="BEGIN_LINK" />deze onveilige site bezoeken<ph name="END_LINK" /> voordat de gevaarlijke programma's zijn verwijderd.</translation>
<translation id="3739623965217189342">Link die je hebt gekopieerd</translation>
@@ -399,6 +412,7 @@
<translation id="4030383055268325496">&amp;Toevoegen ongedaan maken</translation>
<translation id="404928562651467259">WAARSCHUWING</translation>
<translation id="4058922952496707368">Sleutel '<ph name="SUBKEY" />': <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxyconfiguratie is ingesteld op het gebruik van een pac-script-URL, niet op het gebruik van vaste proxyservers.</translation>
@@ -406,7 +420,6 @@
<translation id="4103249731201008433">Serienummer van apparaat is ongeldig</translation>
<translation id="410351446219883937">Automatisch afspelen</translation>
<translation id="4103763322291513355">Ga naar &lt;strong&gt;chrome://policy&lt;/strong&gt; om de lijst met URL's op de zwarte lijst en andere beleidsregels te bekijken die worden afgedwongen door je systeembeheerder.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Altijd toestaan op deze site</translation>
<translation id="4117700440116928470">Beleidsbereik wordt niet ondersteund.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 andere persoon}other{# andere mensen}}</translation>
@@ -444,6 +457,7 @@
<translation id="4377125064752653719">Je probeert <ph name="DOMAIN" /> te bereiken, maar het certificaat dat de server heeft geretourneerd, is ingetrokken door de uitgever. Dat betekent dat de veiligheidsgaranties die de server heeft geretourneerd, absoluut niet kunnen worden vertrouwd. Het kan zijn dat je met een hacker aan het communiceren bent.</translation>
<translation id="4394049700291259645">Uitschakelen</translation>
<translation id="4406896451731180161">zoekresultaten</translation>
+<translation id="4415426530740016218">Ophaaladres</translation>
<translation id="4424024547088906515">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chrome. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> heeft je inlogcertificaat niet geaccepteerd of er is geen inlogcertificaat geleverd.</translation>
<translation id="443673843213245140">Het gebruik van een proxy is uitgeschakeld, maar er is wel een expliciete proxyconfiguratie opgegeven.</translation>
@@ -456,6 +470,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Probeer je extensies uit te schakelen.</translation>
<translation id="457875822857220463">Bezorging</translation>
+<translation id="4582800630050655161">Je kunt de toegang tot je Google-account kwijtraken of slachtoffer worden van identiteitsdiefstal. Chromium raadt je aan je wachtwoord nu te wijzigen.</translation>
<translation id="4587425331216688090">Adres verwijderen uit Chrome?</translation>
<translation id="4592951414987517459">Je verbinding met <ph name="DOMAIN" /> is versleuteld via een moderne Cipher Suite.</translation>
<translation id="4594403342090139922">&amp;Verwijderen ongedaan maken</translation>
@@ -464,10 +479,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Stoppen met het gebruik van een ongeldig certificaat</translation>
+<translation id="4690954380545377795">Je kunt de toegang tot je Google-account kwijtraken of slachtoffer worden van identiteitsdiefstal. Chrome raadt je aan je wachtwoord nu te wijzigen.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Je verbinding is onderbroken</translation>
<translation id="471880041731876836">Je hebt geen toestemming om deze site te bezoeken</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Je betaling</translation>
<translation id="4726672564094551039">Beleid opnieuw laden</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Chromium opnieuw starten</translation>
@@ -506,6 +523,7 @@
<translation id="5019198164206649151">Backend-opslag in slechte staat</translation>
<translation id="5023310440958281426">Neem het beleid van je beheerder door</translation>
<translation id="5029568752722684782">Kopie wissen</translation>
+<translation id="503069730517007720">Er is een rootcertificaat voor '<ph name="SOFTWARE_NAME" />' vereist, maar niet geïnstalleerd. Je IT-beheerder moet de configuratie-instructies voor '<ph name="SOFTWARE_NAME" />' raadplegen om dit probleem op te lossen. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Over Google Translate</translation>
<translation id="5039804452771397117">Toestaan</translation>
<translation id="5040262127954254034">Privacy</translation>
@@ -529,6 +547,8 @@
<translation id="5199729219167945352">Experimenten</translation>
<translation id="5205222826937269299">Naam vereist</translation>
<translation id="5222812217790122047">E-mailadres vereist</translation>
+<translation id="522700295135997067">Deze site heeft mogelijk zojuist je wachtwoord gestolen</translation>
+<translation id="5230733896359313003">Verzendadres</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Gebruik je Chrome op het werk? Bedrijven kunnen Chrome-instellingen beheren voor hun werknemers. Meer informatie</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Volg deze stappen om de software tijdelijk uit te schakelen zodat je verbinding met internet kunt maken. Je hebt beheerdersrechten nodig.<ph name="END_PARAGRAPH" />
@@ -543,9 +563,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Je verbinding met deze site is niet privé. Je kunt de VR-modus op elk gewenst moment afsluiten door de headset af te zetten en op Terug te drukken.</translation>
<translation id="5299298092464848405">Fout bij het parseren van het beleid</translation>
+<translation id="5308380583665731573">Verbinding maken</translation>
<translation id="5308689395849655368">Crashrapportage is uitgeschakeld.</translation>
<translation id="5317780077021120954">Opslaan</translation>
<translation id="5327248766486351172">Naam</translation>
+<translation id="5332219387342487447">Verzendmethode</translation>
<translation id="5355557959165512791">Je kunt <ph name="SITE" /> momenteel niet bezoeken, omdat het bijbehorende certificaat is ingetrokken. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
<translation id="536296301121032821">Opslaan van beleidsinstellingen is mislukt</translation>
<translation id="5386426401304769735">De certificaatketen voor deze site bevat een certificaat dat is ondertekend met SHA-1.</translation>
@@ -565,12 +587,15 @@
<translation id="5492298309214877701">Deze site op het intranet van het bedrijf, de organisatie of de school heeft dezelfde URL als een externe website.
<ph name="LINE_BREAK" />
Neem contact op met je systeembeheerder.</translation>
+<translation id="5499929369096410817">Geef de beveiligingscode voor <ph name="CREDIT_CARD" /> op. Deze code wordt niet opgeslagen.</translation>
<translation id="5509780412636533143">Beheerde bladwijzers</translation>
<translation id="5510766032865166053">Het bestand is mogelijk verplaatst of verwijderd.</translation>
<translation id="5523118979700054094">Beleidsnaam</translation>
<translation id="552553974213252141">Is de tekst correct geëxtraheerd?</translation>
<translation id="5540224163453853">Kan het gevraagde artikel niet vinden.</translation>
+<translation id="5541546772353173584">E-mailadres toevoegen</translation>
<translation id="5544037170328430102">Een ingesloten pagina op <ph name="SITE" /> meldt het volgende:</translation>
+<translation id="5545756402275714221">Artikelen voor jou</translation>
<translation id="5556459405103347317">Opnieuw laden</translation>
<translation id="5560088892362098740">Vervaldatum</translation>
<translation id="5565735124758917034">Actief</translation>
@@ -592,6 +617,7 @@
<translation id="5659593005791499971">E-mailadres</translation>
<translation id="5669703222995421982">Gepersonaliseerde content ontvangen</translation>
<translation id="5675650730144413517">Deze pagina werkt niet</translation>
+<translation id="5689199277474810259">Exporteren naar JSON</translation>
<translation id="5710435578057952990">De identiteit van deze website is niet geverifieerd.</translation>
<translation id="5719499550583120431">Prepaidkaarten worden geaccepteerd.</translation>
<translation id="5720705177508910913">Huidige gebruiker</translation>
@@ -606,27 +632,27 @@
<translation id="5810442152076338065">Je verbinding met <ph name="DOMAIN" /> is versleuteld via een verouderde Cipher Suite.</translation>
<translation id="5813119285467412249">&amp;Opnieuw toevoegen</translation>
<translation id="5838278095973806738">Je moet geen gevoelige gegevens (zoals wachtwoorden of creditcards) opgeven op deze site omdat ze kunnen worden gestolen door aanvallers.</translation>
+<translation id="5866257070973731571">Telefoonnummer toevoegen</translation>
<translation id="5869405914158311789">Deze site is niet bereikbaar</translation>
<translation id="5869522115854928033">Opgeslagen wachtwoorden</translation>
<translation id="5872918882028971132">Bovenliggende suggesties</translation>
<translation id="5893752035575986141">Creditcards worden geaccepteerd.</translation>
-<translation id="5901630391730855834">Geel</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (gesynchroniseerd)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 in gebruik}other{# in gebruik}}</translation>
<translation id="5959728338436674663">Bepaalde <ph name="BEGIN_WHITEPAPER_LINK" />systeeminformatie en paginacontent<ph name="END_WHITEPAPER_LINK" /> automatisch verzenden naar Google om te helpen bij de detectie van gevaarlijke apps en sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Contactgegevens bewerken</translation>
<translation id="5967867314010545767">Verwijderen uit geschiedenis</translation>
<translation id="5975083100439434680">Uitzoomen</translation>
+<translation id="597552863672748783">Beveiligingscode bevestigen</translation>
<translation id="598637245381783098">Kan betaal-app niet openen</translation>
<translation id="5989320800837274978">Er worden geen vaste proxyservers en geen pac-script-URL gespecificeerd.</translation>
<translation id="5990559369517809815">Verzoeken aan de server zijn door een extensie geblokkeerd.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}other{Pagina #}}</translation>
-<translation id="6017514345406065928">Groen</translation>
<translation id="6017850046339264347">Aanvallers op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kunnen misleidende apps installeren die zich voordoen als iets anders of gegevens verzamelen die kunnen worden gebruikt om je te volgen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (gesynchroniseerd)</translation>
<translation id="6027201098523975773">Geef een naam op</translation>
<translation id="6040143037577758943">Sluiten</translation>
-<translation id="6042308850641462728">Meer</translation>
<translation id="6047233362582046994">Als je de beveiligingsrisico's begrijpt, kun je <ph name="BEGIN_LINK" />deze site bezoeken<ph name="END_LINK" /> voordat de schadelijke apps zijn verwijderd.</translation>
<translation id="6047927260846328439">Deze content probeert je mogelijk te misleiden om software te installeren of persoonlijke gegevens openbaar te maken. <ph name="BEGIN_LINK" />Toch weergeven<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Je kunt <ph name="SITE" /> momenteel niet bezoeken, omdat de website gebruikmaakt van certificaatpinning. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
@@ -692,6 +718,7 @@
<translation id="6569060085658103619">Je bekijkt een extensiepagina</translation>
<translation id="6596325263575161958">Opties voor encryptie</translation>
<translation id="662080504995468778">Blijven</translation>
+<translation id="6624427990725312378">Contactgegevens</translation>
<translation id="6626291197371920147">Een geldig kaartnummer toevoegen</translation>
<translation id="6628463337424475685">Zoeken via <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Cybercriminelen op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> proberen mogelijk gevaarlijke programma's op je Mac te installeren waarmee je gegevens kunnen worden gestolen of verwijderd (bijvoorbeeld foto's, wachtwoorden, berichten en creditcardgegevens). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -702,7 +729,6 @@
<translation id="6710213216561001401">Vorige</translation>
<translation id="6710594484020273272">&lt;Typ een zoekterm&gt;</translation>
<translation id="6711464428925977395">Er is iets mis met de proxyserver of het adres is onjuist.</translation>
-<translation id="6727102863431372879">Instellen</translation>
<translation id="674375294223700098">Onbekende fout met servercertificaat.</translation>
<translation id="6753269504797312559">Beleidswaarde</translation>
<translation id="6757797048963528358">De slaapstand van je apparaat is geactiveerd.</translation>
@@ -771,6 +797,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profielpad</translation>
<translation id="7424977062513257142">Een ingesloten pagina op deze webpagina meldt het volgende:</translation>
+<translation id="7437289804838430631">Contactgegevens toevoegen</translation>
<translation id="7441627299479586546">Onjuist beleidsonderwerp</translation>
<translation id="7444046173054089907">Deze site is geblokkeerd</translation>
<translation id="7445762425076701745">De identiteit van de server waarmee je verbinding maakt, kan niet volledig worden geverifieerd. Je hebt verbinding gemaakt met een server die een naam gebruikt die alleen binnen je netwerk geldig is. Een externe certificeringsinstantie kan hiervoor nooit het eigendom verifiëren. Aangezien sommige certificeringsinstanties toch certificaten voor deze namen verlenen, kun je nooit zeker weten of je verbinding hebt met de bedoelde website en niet met een aanvaller.</translation>
@@ -781,11 +808,11 @@
<translation id="7481312909269577407">Vooruit</translation>
<translation id="7485870689360869515">Geen gegevens gevonden.</translation>
<translation id="7508255263130623398">Geretourneerde apparaat-ID voor beleid is leeg of komt niet overeen met de huidige apparaat-ID</translation>
+<translation id="7511955381719512146">Het is mogelijk dat je <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> moet bezoeken van het wifi-netwerk dat je gebruikt.</translation>
<translation id="7514365320538308">Downloaden</translation>
<translation id="7518003948725431193">Er is geen webpagina gevonden voor het webadres: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Je verbinding met deze site is niet privé</translation>
-<translation id="7535087603100972091">Waarde</translation>
<translation id="7537536606612762813">Verplicht</translation>
<translation id="7542403920425041731">Zodra je bevestigt, worden je creditcardgegevens gedeeld met deze site.</translation>
<translation id="7542995811387359312">Het automatisch invullen van creditcardnummers is uitgeschakeld, omdat dit formulier geen beveiligde verbinding gebruikt.</translation>
@@ -796,7 +823,6 @@
<translation id="7567204685887185387">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk frauduleus verstrekt. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="7568593326407688803">Deze pagina is geschreven in het<ph name="ORIGINAL_LANGUAGE" />Wil je deze laten vertalen?</translation>
<translation id="7569952961197462199">Creditcard verwijderen uit Chrome?</translation>
-<translation id="7569983096843329377">Zwart</translation>
<translation id="7578104083680115302">Betaal op verschillende apparaten snel op sites en in apps met kaarten die je hebt opgeslagen via Google.</translation>
<translation id="7588950540487816470">Fysieke web</translation>
<translation id="7592362899630581445">Het certificaat van de server is in strijd met naambeperkingen.</translation>
@@ -815,11 +841,13 @@
<translation id="7669271284792375604">Cybercriminelen op deze site proberen je mogelijk over te halen om programma's te installeren die schadelijk zijn voor de browsefunctionaliteit (door bijvoorbeeld je homepage te wijzigen of extra advertenties weer te geven op sites die je bezoekt).</translation>
<translation id="7674629440242451245">Ben je geïnteresseerd in nieuwe, coole Chrome-functies? Probeer ons ontwikkelaarskanaal op chrome.com/dev.</translation>
<translation id="7682287625158474539">Verzendadres</translation>
+<translation id="7699293099605015246">Er zijn op dit moment geen artikelen beschikbaar</translation>
<translation id="7701040980221191251">Geen</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Doorgaan naar <ph name="SITE" /> (onveilig)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificaat</translation>
<translation id="7716147886133743102">Geblokkeerd door je beheerder</translation>
<translation id="7716424297397655342">Deze site kan niet worden geladen vanuit het cachegeheugen</translation>
+<translation id="7723047071702270851">Kaart bewerken</translation>
<translation id="774634243536837715">Gevaarlijke content geblokkeerd.</translation>
<translation id="7752995774971033316">Niet-beheerd</translation>
<translation id="7755287808199759310">Je ouder of voogd kan de blokkering van deze site opheffen</translation>
@@ -830,21 +858,24 @@
<translation id="7764225426217299476">Adres toevoegen</translation>
<translation id="777702478322588152">Prefectuur</translation>
<translation id="7791543448312431591">Toevoegen</translation>
+<translation id="7793553086574152071">Sla deze kaart op in je Google-account zodat je de volgende keer sneller kunt betalen.</translation>
<translation id="7793809570500803535">De webpagina op <ph name="SITE" /> is mogelijk tijdelijk uitgeschakeld of permanent verplaatst naar een nieuw webadres.</translation>
<translation id="7800304661137206267">De verbinding is geëncrypt met <ph name="CIPHER" />, met <ph name="MAC" /> voor berichtverificatie en <ph name="KX" /> als mechanisme voor sleuteluitwisseling.</translation>
+<translation id="7802523362929240268">Site is legitiem</translation>
<translation id="780301667611848630">Nee, bedankt</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Formuliersuggestie verwijderen uit Chrome?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> gevonden voor '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Het is mogelijk dat je de inlogpagina moet bezoeken van het wifi-netwerk (<ph name="WIFI_NAME" />) dat je gebruikt.</translation>
<translation id="785549533363645510">Je bent echter niet onzichtbaar. Als je incognito bent, wordt je browsegeschiedenis niet verborgen voor je werkgever, je internetprovider of de websites die je bezoekt.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Betaalpassen en prepaidkaarten worden geaccepteerd.</translation>
+<translation id="7878562273885520351">Je wachtwoord is mogelijk gehackt</translation>
<translation id="7887683347370398519">Controleer je CVC-code en probeer het opnieuw</translation>
<translation id="79338296614623784">Geef een geldig telefoonnummer op</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Het servercertificaat is nog niet geldig.</translation>
-<translation id="7942349550061667556">Rood</translation>
<translation id="7947285636476623132">Controleer het vervaljaar en probeer het opnieuw</translation>
<translation id="7951415247503192394">(32-bits)</translation>
<translation id="7956713633345437162">Mobiele bladwijzers</translation>
@@ -858,9 +889,13 @@
<translation id="8037357227543935929">Vragen (standaard)</translation>
<translation id="8041089156583427627">Feedback verzenden</translation>
<translation id="8041940743680923270">Algemene standaardinstelling gebruiken (Vragen)</translation>
+<translation id="8057711352706143257">'<ph name="SOFTWARE_NAME" />' is niet correct geconfigureerd. Als je '<ph name="SOFTWARE_NAME" />' verwijdert, wordt het probleem meestal opgelost. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Kan artikel niet bekijken.</translation>
<translation id="8091372947890762290">Activering is in behandeling op de server</translation>
+<translation id="8094917007353911263">Het is mogelijk dat je <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> moet bezoeken van het netwerk dat je gebruikt.</translation>
+<translation id="8103161714697287722">Betaalmethode</translation>
<translation id="8118489163946903409">Betaalmethode</translation>
+<translation id="8127301229239896662">'<ph name="SOFTWARE_NAME" />' is niet correct geïnstalleerd op je computer of netwerk. Neem contact op met je IT-beheerder om dit probleem op te lossen.</translation>
<translation id="8131740175452115882">Bevestigen</translation>
<translation id="8134994873729925007">Het <ph name="BEGIN_ABBR" />DNS-adres<ph name="END_ABBR" /> van de server van <ph name="HOST_NAME" /> kan niet worden gevonden.</translation>
<translation id="8149426793427495338">De slaapstand van je computer is geactiveerd.</translation>
@@ -883,6 +918,7 @@
<translation id="8289355894181816810">Neem contact op met je netwerkbeheerder als je niet zeker weet wat dit betekent.</translation>
<translation id="8293206222192510085">Bladwijzer toevoegen</translation>
<translation id="8294431847097064396">Bron</translation>
+<translation id="8298115750975731693">Het is mogelijk dat je <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> moet bezoeken van het wifi-netwerk (<ph name="WIFI_NAME" />) dat je gebruikt.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">De vertaling is mislukt omdat er een probleem is opgetreden met de netwerkverbinding.</translation>
<translation id="8332188693563227489">Toegang tot <ph name="HOST_NAME" /> is geweigerd</translation>
@@ -935,20 +971,21 @@
<translation id="8870413625673593573">Recent gesloten</translation>
<translation id="8874824191258364635">Geef een geldig kaartnummer op</translation>
<translation id="8876793034577346603">Netwerkconfiguratie kan niet worden geparseerd.</translation>
-<translation id="8889402386540077796">Kleurtoon</translation>
<translation id="8891727572606052622">Ongeldige proxymodus.</translation>
<translation id="889901481107108152">Dit experiment is niet beschikbaar op je platform.</translation>
<translation id="8903921497873541725">Inzoomen</translation>
<translation id="8931333241327730545">Wil je deze kaart opslaan in je Google-account?</translation>
<translation id="8932102934695377596">Je klok loopt achter</translation>
+<translation id="893332455753468063">Naam toevoegen</translation>
<translation id="8938939909778640821">Geaccepteerde creditcards en prepaidkaarten</translation>
+<translation id="8957210676456822347">Autorisatie van captive portal</translation>
<translation id="8971063699422889582">Het servercertificaat is verlopen.</translation>
-<translation id="8986494364107987395">Automatisch gebruiksstatistieken en crashrapporten naar Google verzenden</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">De volgende site bevat schadelijke programma's</translation>
<translation id="8997023839087525404">De server heeft een certificaat gepresenteerd dat niet openbaar bekend is gemaakt via het beleid voor Certificaattransparantie. Dit is voor bepaalde certificaten een vereiste om er zeker van te zijn dat ze betrouwbaar zijn en bescherming bieden tegen aanvallers.</translation>
<translation id="9001074447101275817">Voor de proxy <ph name="DOMAIN" /> zijn een gebruikersnaam en wachtwoord vereist.</translation>
<translation id="9005998258318286617">Kan pdf-document niet laden</translation>
+<translation id="9008201768610948239">Negeren</translation>
<translation id="901974403500617787">Markeringen die op het hele systeem van toepassing zijn, kunnen alleen worden ingesteld door de eigenaar: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Factuuradres voor creditcard vereist</translation>
<translation id="9020542370529661692">Deze pagina is vertaald naar het <ph name="TARGET_LANGUAGE" /></translation>
@@ -958,11 +995,14 @@
<translation id="9049981332609050619">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een ongeldig certificaat geretourneerd.</translation>
<translation id="9050666287014529139">Wachtwoordzin</translation>
<translation id="9065203028668620118">Bewerken</translation>
-<translation id="9068849894565669697">Kleur selecteren</translation>
<translation id="9069693763241529744">Geblokkeerd door een extensie</translation>
<translation id="9076283476770535406">De site kan content voor volwassenen bevatten</translation>
<translation id="9078964945751709336">Meer informatie vereist</translation>
+<translation id="9080712759204168376">Besteloverzicht</translation>
<translation id="9103872766612412690"><ph name="SITE" /> gebruikt gewoonlijk versleuteling om je gegevens te beschermen. Toen Chromium deze keer probeerde verbinding te maken met <ph name="SITE" />, retourneerde de website ongewone en onjuiste inloggegevens. Dit gebeurt wanneer een aanvaller probeert zich als <ph name="SITE" /> voor te doen of wanneer een wifi-inlogscherm de verbinding heeft verbroken. Je gegevens zijn nog steeds veilig omdat Chromium de verbinding heeft beëindigd voordat er gegevens konden worden uitgewisseld.</translation>
+<translation id="9106062320799175032">Factuuradres toevoegen</translation>
+<translation id="910908805481542201">Help me dit op te lossen</translation>
+<translation id="9128870381267983090">Verbinding maken met netwerk</translation>
<translation id="9137013805542155359">Origineel weergeven</translation>
<translation id="9137248913990643158">Start Chrome en log in voordat je deze app gebruikt.</translation>
<translation id="9148507642005240123">&amp;Bewerken ongedaan maken</translation>
@@ -974,6 +1014,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> gebruikt een niet-ondersteund protocol.</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="9215416866750762878">Een app voorkomt dat Chrome veilig verbinding kan maken met deze site</translation>
<translation id="9219103736887031265">Afbeeldingen</translation>
<translation id="933612690413056017">Er is geen internetverbinding beschikbaar</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -983,5 +1024,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Geen}=1{1 item}other{# items}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Ontwikkelaarsbuild</translation>
+<translation id="989988560359834682">Adres bewerken</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">'<ph name="SOFTWARE_NAME" />' is niet correct geïnstalleerd op je computer of het netwerk:
+ &lt;ul&gt;
+ &lt;li&gt;Probeer '<ph name="SOFTWARE_NAME" />' te verwijderen of uit te schakelen&lt;/li&gt;
+ &lt;li&gt;Maak verbinding met een ander netwerk&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index 995cace762d..91b260aaf24 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Bokmerker på datamaskinen</translation>
<translation id="1074497978438210769">Ikke sikker</translation>
<translation id="1080116354587839789">Tilpass til vindusbredden</translation>
+<translation id="1088860948719068836">Legg til navnet på kortet</translation>
<translation id="1103523840287552314">Oversett alltid <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Vis alle lagrede passord ...</translation>
<translation id="1107591249535594099">Hvis det er merket av for dette alternativet, lagrer Chrome en kopi av kortet ditt på denne enheten, slik at det går raskere å fylle ut skjemaer.</translation>
<translation id="1111153019813902504">Nylige bokmerker</translation>
<translation id="1113869188872983271">&amp;Angre omorganiseringen</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" /> og <ph name="TYPE_2" /> (synkronisert)</translation>
<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Programstopprapport fra <ph name="CRASH_TIME" /> (ignorert eller ikke lastet opp ennå)</translation>
+<translation id="1270502636509132238">Hentemåte</translation>
<translation id="1281526147609854549">Utstedt av <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Oversett aldri dette nettstedet</translation>
<translation id="129553762522093515">Nylig lukket</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Venter på tilkobling …</translation>
<translation id="153384715582417236">Det var alt for denne gangen</translation>
<translation id="1549470594296187301">Denne funksjonen kan ikke brukes når JavaScript er slått av.</translation>
-<translation id="1555130319947370107">Blå</translation>
<translation id="1559528461873125649">Finner ingen slik fil eller katalog</translation>
<translation id="1583429793053364125">Noe gikk galt under åpningen av denne nettsiden.</translation>
<translation id="1592005682883173041">Tilgang til lokale data</translation>
<translation id="1594030484168838125">Velg</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Vil du at Chrome skal lagre dette kortet?</translation>
<translation id="1639239467298939599">Laster inn</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du trenger tillatelse fra <ph name="NAME" /> for å besøke dette nettstedet</translation>
<translation id="1721424275792716183">* Feltet er obligatorisk</translation>
+<translation id="1727741090716970331">Legg til et gyldig kortnummer</translation>
<translation id="1728677426644403582">Du ser på kildekoden for en nettside</translation>
<translation id="173080396488393970">Denne korttypen støttes ikke</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serialiseringsfeil</translation>
<translation id="1974060860693918893">Avansert</translation>
<translation id="1978555033938440688">Fastvareversjon</translation>
-<translation id="1995859865337580572">Bekreft CVC-koden din</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{og 1 til}other{og # til}}</translation>
<translation id="2025186561304664664">Mellomtjeneren er innstilt på automatisk konfigurasjon.</translation>
<translation id="2030481566774242610">Mener du <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Angre</translation>
<translation id="20817612488360358">Innstillinger for systemmellomtjener er stilt inn på å brukes, men en uttrykkelig mellomtjenerkonfigurasjon er også angitt.</translation>
<translation id="2086652334978798447">For å få forslag om personlig tilpasset innhold fra Google, logg på Chrome.</translation>
+<translation id="2091887806945687916">Lyd</translation>
<translation id="2094505752054353250">Domenene samsvarer ikke</translation>
<translation id="2096368010154057602">Avdeling</translation>
<translation id="2108755909498034140">Start datamaskinen på nytt.</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorert fordi det ble overstyrt av <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Leter etter Fysisk nett-sider i nærheten</translation>
<translation id="213826338245044447">Bokmerker for mobil</translation>
+<translation id="214556005048008348">Avbryt betalingen</translation>
<translation id="2147827593068025794">Bakgrunnssynkronisering</translation>
+<translation id="2148613324460538318">Legg til et kort</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgjengelig for domenet ditt</translation>
<translation id="2154484045852737596">Endre kortet</translation>
<translation id="2166049586286450108">Full administratortilgang</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}other{# adresser}}</translation>
<translation id="2187317261103489799">Oppdag (standard)</translation>
<translation id="2202020181578195191">Angi et gyldig utløpsår</translation>
+<translation id="2209523182407020534">Programmer som kan forårsake denne feilen, kan være antivirusprogrammer, brannmurprogrammer og programvare for proxy-tjenere og filtrering på nettet.</translation>
<translation id="2212735316055980242">Innstillingene ble ikke funnet</translation>
<translation id="2213606439339815911">Henter oppføringer …</translation>
<translation id="2218879909401188352">Angripere som for øyeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apper som skader enheten din, legge til skjulte belastninger på mobilregningen din eller stjele personopplysningene dine. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Gå tilbake</translation>
<translation id="2503184589641749290">Godkjente debetkort og forhåndsbetalte kort</translation>
<translation id="2515629240566999685">Sjekk signalet i området ditt</translation>
+<translation id="2524461107774643265">Legg til mer informasjon</translation>
+<translation id="2536110899380797252">Legg til adresse</translation>
<translation id="2539524384386349900">Oppdag</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> sendte et ugyldig svar.</translation>
<translation id="2556876185419854533">&amp;Angre endringen</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium kunne ikke bekrefte kortet ditt akkurat nå. Prøv igjen senere.</translation>
<translation id="2705137772291741111">Den lagrede (bufrede) kopien av dette nettstedet kunne ikke leses.</translation>
<translation id="2709516037105925701">Autofyll</translation>
+<translation id="2710942282213947212">Det er programvare på datamaskinen din som hindrer Chromium i å koble trygt til nettet</translation>
<translation id="2712173769900027643">Be om tillatelse</translation>
-<translation id="2713444072780614174">Hvit</translation>
<translation id="2720342946869265578">Like ved</translation>
<translation id="2721148159707890343">Forespørselen var vellykket</translation>
<translation id="2728127805433021124">Tjenerens sertifikat er signert med en usikker signaturalgoritme.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">En nettverksendring ble oppdaget.</translation>
<translation id="2916038427272391327">Lukk andre programmer</translation>
<translation id="2922350208395188000">Tjenerens sertifikat kan ikke kontrolleres.</translation>
+<translation id="2925673989565098301">Leveringsmåte</translation>
<translation id="2928905813689894207">Faktureringsadresse</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> til}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> til}}</translation>
<translation id="2941952326391522266">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat er fra <ph name="DOMAIN2" />. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Feil type enhetsinnstillinger</translation>
<translation id="3032412215588512954">Vil du laste inn dette nettstedet på nytt?</translation>
<translation id="3037605927509011580">Æsj!</translation>
+<translation id="3039538478787849737">Vil du lagre kortet i Google?</translation>
<translation id="3041612393474885105">Sertifikatinformasjon</translation>
<translation id="3063697135517575841">Chrome kunne ikke bekrefte kortet ditt akkurat nå. Prøv igjen senere.</translation>
<translation id="3064966200440839136">Går ut av inkognitomodus for å betale via en ekstern app. Vil du fortsette?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Midlertidig tjenerfeil</translation>
<translation id="3154506275960390542">Denne siden inneholder et skjema som kanskje ikke sendes på en sikker måte. Data du sender, kan bli sett av andre mens de overføres, eller de kan endres av en angriper slik at tjeneren mottar noe annet enn det du sender.</translation>
<translation id="3157931365184549694">Gjenopprett</translation>
+<translation id="3162559335345991374">Det kan hende at Wi-Fi-nettverket du bruker, krever at du besøker en påloggingsside.</translation>
<translation id="3167968892399408617">Sider du går til i inkognitofaner, blir ikke værende i nettleserloggen, lageret for informasjonskapsler eller søkeloggen etter at du har lukket alle inkognitofanene. Filer du laster ned eller bokmerker du oppretter, blir lagret.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Øy</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Avbryt betalingen</translation>
<translation id="3207960819495026254">Bokmerket</translation>
+<translation id="3211223744486044430">For å betale raskere neste gang, lagre dette kortet i Google-kontoen din og på denne enheten.</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>
<translation id="3226128629678568754">Trykk på knappen for å laste inn på nytt, for å sende inn dataene som trengs for å laste inn siden på nytt.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Søket ga ingen treff</translation>
<translation id="3305707030755673451">Dataene dine er kryptert med passordfrasen din for synkronisering <ph name="TIME" />. Skriv den inn for å starte synkroniseringen.</translation>
<translation id="3320021301628644560">Legg til faktureringsadresse</translation>
-<translation id="3329013043687509092">Metning</translation>
<translation id="333371639341676808">Hindre denne siden i å opprette flere dialogbokser.</translation>
<translation id="3338095232262050444">Sikker</translation>
<translation id="3340978935015468852">innstillinger</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Klient-ID:</translation>
<translation id="3391030046425686457">Leveringsadresse</translation>
<translation id="3395827396354264108">Hentemetode</translation>
+<translation id="3399952811970034796">Leveringsadresse</translation>
<translation id="3422248202833853650">Prøv å lukke andre programmer for å frigjøre minne.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> er ikke tilgjengelig for øyeblikket.</translation>
<translation id="3427092606871434483">Tillat (standard)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Programstopprapport generert <ph name="CRASH_TIME" /> og lastet opp <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikatinformasjon</translation>
<translation id="3690164694835360974">Påloggingen er ikke trygg</translation>
+<translation id="3704162925118123524">Det kan hende at det er et krav for nettverket du bruker, at du besøker påloggingssiden for nettverket.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laster inn ...</translation>
<translation id="3712624925041724820">Lisensene er oppbrukt</translation>
<translation id="3714780639079136834">Slå på mobildata eller Wi-Fi</translation>
+<translation id="3715597595485130451">Tilkobling til Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sjekk proxy-tjener-, brannmur- og DNS-konfigurasjonen<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Hvis du forstår sikkerhetsrisikoen, kan du <ph name="BEGIN_LINK" />gå til det usikre nettstedet<ph name="END_LINK" /> før de farlige programmene er fjernet.</translation>
<translation id="3739623965217189342">En link du kopierte</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Angre tilleggingen</translation>
<translation id="404928562651467259">ADVARSEL</translation>
<translation id="4058922952496707368">Nøkkel – «<ph name="SUBKEY" />»: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfigurasjonen av proxytjeneren er angitt til å bruke en nettadresse med .pac-skript, ikke statiske proxytjenere.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Enhetens serienummer er ugyldig</translation>
<translation id="410351446219883937">Autoavspilling</translation>
<translation id="4103763322291513355">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for å se listen over sperrede nettadresser og andre innstillinger aktivert av systemadministratoren din.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Tillat alltid på dette nettstedet</translation>
<translation id="4117700440116928470">Omfanget for innstillingen støttes ikke.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 til}other{# til}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Du forsøkte å gå til <ph name="DOMAIN" />, men sertifikatet tjeneren presenterte har blitt trukket tilbake av utstederen. Dette innebærer at sikkerhetsinformasjonen tjeneren presenterte ikke er klarert. Det kan hende at du kommuniserer med en angriper.</translation>
<translation id="4394049700291259645">Slå av</translation>
<translation id="4406896451731180161">søkeresultater</translation>
+<translation id="4415426530740016218">Henteadresse</translation>
<translation id="4424024547088906515">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av Chrome. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="4432688616882109544">Enten godtok ikke <ph name="HOST_NAME" /> påloggingssertifikatet ditt, eller så ble det ikke oppgitt.</translation>
<translation id="443673843213245140">Bruk av mellomtjener er deaktivert, men det er angitt en uttrykkelig mellomtjenerkonfigurasjon.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Prøv å slå av utvidelsene dine.</translation>
<translation id="457875822857220463">Levering</translation>
+<translation id="4582800630050655161">Du kan miste tilgangen til Google-kontoen din eller bli utsatt for identitetstyveri. Chromium anbefaler at du endrer passordet ditt nå.</translation>
<translation id="4587425331216688090">Vil du fjerne adressen fra Chrome?</translation>
<translation id="4592951414987517459">Tilkoblingen til <ph name="DOMAIN" /> er kryptert med en moderne chifferserie.</translation>
<translation id="4594403342090139922">&amp;Angre slettingen</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Slutt å bruke et ugyldig sertifikat</translation>
+<translation id="4690954380545377795">Du kan miste tilgangen til Google-kontoen din eller bli utsatt for identitetstyveri. Chrome anbefaler at du endrer passordet ditt nå.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Tilkoblingen ble avbrutt</translation>
<translation id="471880041731876836">Du har ikke tillatelse til å besøke dette nettstedet</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kjør Windows Nettverksdiagnose<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Betalingen din</translation>
<translation id="4726672564094551039">Last inn retningslinjer på nytt</translation>
<translation id="4728558894243024398">Plattform</translation>
<translation id="4736825316280949806">Start Chromium på nytt</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Ugyldig funksjonalitet for sikkerhetskopiering</translation>
<translation id="5023310440958281426">Kontrollér retningslinjene til administratoren din</translation>
<translation id="5029568752722684782">Slett kopi</translation>
+<translation id="503069730517007720">Et rotsertifikat for «<ph name="SOFTWARE_NAME" />» kreves, men er ikke installert. IT-administratoren din bør se på konfigurasjonsveiledningen for «<ph name="SOFTWARE_NAME" />» for å løse dette problemet. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Om Google Oversett</translation>
<translation id="5039804452771397117">Tillat</translation>
<translation id="5040262127954254034">Personvern</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Eksperimenter</translation>
<translation id="5205222826937269299">Navn er obligatorisk</translation>
<translation id="5222812217790122047">E-post er obligatorisk</translation>
+<translation id="522700295135997067">Dette nettstedet stjal muligens nettopp passordet ditt</translation>
+<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5251803541071282808">Nettsky</translation>
<translation id="5277279256032773186">Bruker du Chrome på jobben? Bedrifter kan administrere Chrome-innstillingene for de ansatte. Finn ut mer</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Følg disse trinnene for å deaktivere programvaren midlertidig, sånn at du kan komme deg på nettet. Du må ha administratorrettigheter.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Tilkoblingen til dette nettstedet er ikke privat. For å gå ut av VR-modus, fjern brillene og trykk på tilbake.</translation>
<translation id="5299298092464848405">Feil under analysen av enhetsinnstillingene</translation>
+<translation id="5308380583665731573">Koble til</translation>
<translation id="5308689395849655368">Rapportering av programstopp er deaktivert.</translation>
<translation id="5317780077021120954">Lagre</translation>
<translation id="5327248766486351172">Navn</translation>
+<translation id="5332219387342487447">Leveringsmetode</translation>
<translation id="5355557959165512791">Du kan ikke gå til <ph name="SITE" /> akkurat nå, siden sertifikatet for nettstedet er trukket tilbake. Nettverksfeil- og angrep er vanligvis midlertidige, så denne siden fungerer sannsynligvis senere.</translation>
<translation id="536296301121032821">Kunne ikke lagre angivelsen for enhetsinnstillinger</translation>
<translation id="5386426401304769735">Sertifikatkjeden for dette nettstedet inneholder et sertifikat som er signert med SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Dette nettstedet på selskapets, organisasjonens eller skolens intranett har samme nettadresse som et eksternt nettsted.
<ph name="LINE_BREAK" />
Prøv å kontakte systemadministratoren din.</translation>
+<translation id="5499929369096410817">Skriv inn sikkerhetskoden for <ph name="CREDIT_CARD" />. Denne koden lagres ikke.</translation>
<translation id="5509780412636533143">Administrerte bokmerker</translation>
<translation id="5510766032865166053">Den kan ha blitt flyttet eller slettet.</translation>
<translation id="5523118979700054094">Navn på retningslinje</translation>
<translation id="552553974213252141">Ble tekstutdraget riktig?</translation>
<translation id="5540224163453853">Den forespurte artikkelen ble ikke funnet.</translation>
+<translation id="5541546772353173584">Legg til e-post</translation>
<translation id="5544037170328430102">En innebygd side på <ph name="SITE" /> sier:</translation>
+<translation id="5545756402275714221">Artikler for deg</translation>
<translation id="5556459405103347317">Last inn på nytt</translation>
<translation id="5560088892362098740">Utløpsdato</translation>
<translation id="5565735124758917034">Aktiv</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-post</translation>
<translation id="5669703222995421982">Få innhold med et personlig preg</translation>
<translation id="5675650730144413517">Denne siden fungerer ikke</translation>
+<translation id="5689199277474810259">Eksportér til JSON</translation>
<translation id="5710435578057952990">Identiteten til dette nettstedet er ikke verifisert.</translation>
<translation id="5719499550583120431">Forhåndsbetalte kort godtas.</translation>
<translation id="5720705177508910913">Gjeldende bruker</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Tilkoblingen til <ph name="DOMAIN" /> er kryptert med en foreldet chifferserie.</translation>
<translation id="5813119285467412249">&amp;Legg til likevel</translation>
<translation id="5838278095973806738">Du bør ikke oppgi sensitiv informasjon på dette nettstedet (for eksempel passord eller kredittkort) fordi den kan bli stjålet av angripere.</translation>
+<translation id="5866257070973731571">Legg til telefonnummer</translation>
<translation id="5869405914158311789">Dette nettstedet er ikke tilgjengelig</translation>
<translation id="5869522115854928033">Lagrede passord</translation>
<translation id="5872918882028971132">Overordnede forslag</translation>
<translation id="5893752035575986141">Kredittkort godtas.</translation>
-<translation id="5901630391730855834">Gul</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkronisert)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 er i bruk}other{# er i bruk}}</translation>
<translation id="5959728338436674663">Send automatisk noe <ph name="BEGIN_WHITEPAPER_LINK" />systeminformasjon og sideinnhold<ph name="END_WHITEPAPER_LINK" /> til Google for å bidra til å oppdage farlige apper og nettsteder. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Endre kontaktinformasjonen</translation>
<translation id="5967867314010545767">Fjern fra loggen</translation>
<translation id="5975083100439434680">Zoom ut</translation>
+<translation id="597552863672748783">Bekreft sikkerhetskoden</translation>
<translation id="598637245381783098">Kan ikke åpne betalingsappen</translation>
<translation id="5989320800837274978">Verken statiske proxytjenere eller en nettadresse med .pac-skript er angitt.</translation>
<translation id="5990559369517809815">Forespørsler til tjeneren har blitt blokkert av en utvidelse.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Side 1}other{Side #}}</translation>
-<translation id="6017514345406065928">Grønn</translation>
<translation id="6017850046339264347">Angripere på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan installere villedende apper som ser ut til å være noe annet, eller samle inn data som kan brukes til å spore deg. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" /> og <ph name="TYPE_3" /> (synkronisert)</translation>
<translation id="6027201098523975773">Skriv inn et navn</translation>
<translation id="6040143037577758943">Lukk</translation>
-<translation id="6042308850641462728">Mer</translation>
<translation id="6047233362582046994">Hvis du forstår sikkerhetsrisikoen, kan du <ph name="BEGIN_LINK" />gå til dette nettstedet<ph name="END_LINK" /> før de skadelige appene er fjernet.</translation>
<translation id="6047927260846328439">Dette innholdet kan prøve å lure deg til å installere programvare eller oppgi personopplysninger. <ph name="BEGIN_LINK" />Vis det likevel<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan ikke gå til <ph name="SITE" /> akkurat nå, siden nettstedet bruker sertifikatfesting. Nettverksfeil og -angrep er vanligvis midlertidige, så denne siden fungerer sannsynligvis senere.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Du ser på en utvidelsesside</translation>
<translation id="6596325263575161958">Krypteringsalternativer</translation>
<translation id="662080504995468778">Bli her</translation>
+<translation id="6624427990725312378">Kontaktinformasjon</translation>
<translation id="6626291197371920147">Legg til et gyldig kortnummer</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Søk</translation>
<translation id="6630809736994426279">Angripere som for øyeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan prøve å installere farlige programmer på Macen du bruker, for å stjele eller slette informasjonen din (for eksempel bilder, passord, meldinger og kredittkortinformasjon). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Forrige</translation>
<translation id="6710594484020273272">&lt;Skriv inn en søketerm&gt;</translation>
<translation id="6711464428925977395">Det er noe galt med proxy-tjeneren, eller adressen er feil.</translation>
-<translation id="6727102863431372879">Angi</translation>
<translation id="674375294223700098">Ukjent feil med tjenersertifikat.</translation>
<translation id="6753269504797312559">Retningslinjeverdi</translation>
<translation id="6757797048963528358">Enheten din gikk inn i hvilemodus.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">Nettadresse</translation>
<translation id="7419106976560586862">Profilbane</translation>
<translation id="7424977062513257142">En innebygd side på denne nettsiden sier:</translation>
+<translation id="7437289804838430631">Legg til kontaktinformasjon</translation>
<translation id="7441627299479586546">Feil emne for innstillinger</translation>
<translation id="7444046173054089907">Dette nettstedet er blokkert</translation>
<translation id="7445762425076701745">Identiteten til tjernen du er tilkoblet kan ikke valideres. Du er tilkoblet en tjener som bruker et navn som kun er gyldig i ditt nettverk, som en ekstern sertifiseringsinstans ikke har noen mulighet til å validere eierskap for. Siden enkelte sertifiseringsinstanser likevel utsteder sertifikater for disse navnene, er det umulig å sikre at du er tilkoblet ønsket nettsted og ikke en angriper.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Ingen data ble funnet.</translation>
<translation id="7508255263130623398">Den returnerte enhets-ID-en for regelen er tom eller samsvarer ikke med den faktiske enhets-ID-en</translation>
+<translation id="7511955381719512146">Det kan hende at Wi-Fi-nettverket du bruker, krever at du besøker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Last ned</translation>
<translation id="7518003948725431193">Finner ingen nettside for denne nettadressen: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Tilkoblingen til dette nettstedet er ikke privat</translation>
-<translation id="7535087603100972091">Verdi</translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542403920425041731">Når du bekrefter, deles kortinformasjonen din med dette nettstedet.</translation>
<translation id="7542995811387359312">Automatisk utfylling av kredittkort er deaktivert fordi dette skjemaet ikke bruker en sikker tilkobling.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat kan ha blitt utstedt på uredelig vis. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="7568593326407688803">Denne siden er på<ph name="ORIGINAL_LANGUAGE" />Vil du ha den oversatt?</translation>
<translation id="7569952961197462199">Vil du fjerne kredittkortet fra Chrome?</translation>
-<translation id="7569983096843329377">Svart</translation>
<translation id="7578104083680115302">Når du lagrer kort med Google, kan du bruke dem til å betale raskt på nettsteder og i apper – uansett hvilken enhet du bruker.</translation>
<translation id="7588950540487816470">Fysisk nett</translation>
<translation id="7592362899630581445">Tjenerens sertifikat bryter navnereglene.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Angripere på dette nettstedet kan forsøke å lure deg til å installere programmer som ødelegger surfeopplevelsen din (for eksempel ved å endre startsiden din eller vise ekstra annonser på nettstedene du besøker).</translation>
<translation id="7674629440242451245">Interessert i nye kule Chrome-funksjoner? Prøv utviklerkanalen vår på chrome.com/dev</translation>
<translation id="7682287625158474539">Forsendelse</translation>
+<translation id="7699293099605015246">Artikler er ikke tilgjengelige for øyeblikket</translation>
<translation id="7701040980221191251">Ingen</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsett til <ph name="SITE" /> (usikker side)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifikat</translation>
<translation id="7716147886133743102">Blokkert av administratoren din</translation>
<translation id="7716424297397655342">Dette nettstedet kan ikke lastes inn fra bufferen</translation>
+<translation id="7723047071702270851">Endre kortet</translation>
<translation id="774634243536837715">Farlig innhold er blokkert.</translation>
<translation id="7752995774971033316">Administreres ikke</translation>
<translation id="7755287808199759310">Forelderen din kan oppheve blokkeringen for deg</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Legg til adresse</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Legg til</translation>
+<translation id="7793553086574152071">For å betale raskere neste gang, lagre dette kortet i Google-kontoen din.</translation>
<translation id="7793809570500803535">Det kan hende at nettsiden på <ph name="SITE" /> er midlertidig nede eller flyttet permanent til en ny nettadresse.</translation>
<translation id="7800304661137206267">Tilkoblingen er kryptert ved hjelp av <ph name="CIPHER" />, med <ph name="MAC" /> for autentisering av meldinger og <ph name="KX" /> som nøkkelutvekslingsmekanisme.</translation>
+<translation id="7802523362929240268">Nettstedet er legitimt</translation>
<translation id="780301667611848630">Nei takk</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vil du fjerne skjemaforslaget fra Chrome?</translation>
<translation id="7815407501681723534">Fant <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for «<ph name="SEARCH_STRING" />»</translation>
+<translation id="782886543891417279">Det kan hende at Wi-Fi-nettverket du bruker (<ph name="WIFI_NAME" />), krever at du besøker en påloggingsside.</translation>
<translation id="785549533363645510">Du er imidlertid ikke usynlig. Inkognitomodus skjuler ikke surfingen din for arbeidsgiveren din, Internett-leverandøren eller nettstedene du besøker.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Debetkort og forhåndsbetalte kort godtas.</translation>
+<translation id="7878562273885520351">Passordet ditt kan være kompromittert</translation>
<translation id="7887683347370398519">Kontrollér CVC-koden din, og prøv igjen.</translation>
<translation id="79338296614623784">Angi et gyldig telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Tjenerens sertifikat er ikke gyldig ennå.</translation>
-<translation id="7942349550061667556">Rød</translation>
<translation id="7947285636476623132">Kontrollér utløpsdatoen, og prøv igjen</translation>
<translation id="7951415247503192394">(32-bit)</translation>
<translation id="7956713633345437162">Bokmerker for mobil</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Spør (standard)</translation>
<translation id="8041089156583427627">Send tilbakemelding</translation>
<translation id="8041940743680923270">Bruk global standardinnstilling (Spør)</translation>
+<translation id="8057711352706143257">«<ph name="SOFTWARE_NAME" />» er ikke riktig konfigurert. Avinstallering av «<ph name="SOFTWARE_NAME" />» løser vanligvis problemet. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Kunne ikke åpne artikkelen.</translation>
<translation id="8091372947890762290">Aktivering venter på tjeneren</translation>
+<translation id="8094917007353911263">Det kan hende at nettverket du bruker, krever at du besøker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Betalingsmåte</translation>
<translation id="8118489163946903409">Betalingsmåte</translation>
+<translation id="8127301229239896662">«<ph name="SOFTWARE_NAME" />» er ikke riktig installert på datamaskinen eller på nettverket. Be IT-administratoren din om å løse problemet.</translation>
<translation id="8131740175452115882">Bekreft</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />-tjenerens <ph name="BEGIN_ABBR" />DNS-adresse<ph name="END_ABBR" /> ble ikke funnet.</translation>
<translation id="8149426793427495338">Datamaskinen din gikk inn i hvilemodus.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Kontakt nettverksadministratoren hvis du ikke er sikker på hva dette betyr.</translation>
<translation id="8293206222192510085">Legg til bokmerke</translation>
<translation id="8294431847097064396">Kilde</translation>
+<translation id="8298115750975731693">Det kan hende at Wi-Fi-nettverket du bruker (<ph name="WIFI_NAME" />), krever at du besøker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Det kan ikke opprettes noen privat tilkobling til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, siden datoen og klokkeslettet (<ph name="DATE_AND_TIME" />) på enheten du bruker, er feil. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Oversettelsen mislyktes på grunn av et problem med nettverksforbindelsen.</translation>
<translation id="8332188693563227489">Forsøket på å koble til <ph name="HOST_NAME" /> ble avvist</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Nylig lukket</translation>
<translation id="8874824191258364635">Angi et gyldig kortnummer</translation>
<translation id="8876793034577346603">Nettverkskonfigurasjon kunne ikke analyseres.</translation>
-<translation id="8889402386540077796">Fargetone</translation>
<translation id="8891727572606052622">Ugyldig modus for mellomtjener.</translation>
<translation id="889901481107108152">Beklager, dette eksperimentet er ikke er tilgjengelig på plattformen din.</translation>
<translation id="8903921497873541725">Zoom inn</translation>
<translation id="8931333241327730545">Vil du lagre dette kortet i Google-kontoen din?</translation>
<translation id="8932102934695377596">Klokken går for sent</translation>
+<translation id="893332455753468063">Legg til navn</translation>
<translation id="8938939909778640821">Godkjente kredittkort og forhåndsbetalte kort</translation>
+<translation id="8957210676456822347">Captive Portal-autorisasjon</translation>
<translation id="8971063699422889582">Tjenerens sertifikat er utløpt.</translation>
-<translation id="8986494364107987395">Send bruksstatistikk og programstopprapporter automatisk til Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Nettstedet du er i ferd med å åpne, inneholder skadelige programmer</translation>
<translation id="8997023839087525404">Tjeneren har presentert et sertifikat som ikke er offentlig vist i henhold til regelen om sertifikatåpenhet. Dette er et krav for enkelte sertifikater for å sikre at de er pålitelige, og bidrar til å beskytte mot angrep.</translation>
<translation id="9001074447101275817">Proxy-tjeneren <ph name="DOMAIN" /> krever brukernavn og passord.</translation>
<translation id="9005998258318286617">Kunne ikke laste inn PDF-dokumentet.</translation>
+<translation id="9008201768610948239">Ignorer</translation>
<translation id="901974403500617787">Rapporteringer som gjelder for hele systemet kan bare angis av eieren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Faktureringsadressen for kortet er obligatorisk</translation>
<translation id="9020542370529661692">Denne siden har blitt oversatt til <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Du forsøkte å nå <ph name="DOMAIN" />, men tjeneren oppga et ugyldig sertifikat.</translation>
<translation id="9050666287014529139">Passordfrase</translation>
<translation id="9065203028668620118">Endre</translation>
-<translation id="9068849894565669697">Velg farge</translation>
<translation id="9069693763241529744">Blokkert av en utvidelse</translation>
<translation id="9076283476770535406">Det kan ha voksent innhold</translation>
<translation id="9078964945751709336">Mer informasjon er nødvendig</translation>
+<translation id="9080712759204168376">Bestillingssammendrag</translation>
<translation id="9103872766612412690"><ph name="SITE" /> bruker vanligvis kryptering for å beskytte informasjonen din. Da Chromium prøvde å koble til <ph name="SITE" /> denne gangen, sendte nettstedet tilbake uvanlig og feil legitimasjon. Dette kan skje hvis en angriper prøver å utgi seg for å være <ph name="SITE" />, eller hvis en Wi-Fi-påloggingsskjerm har avbrutt tilkoblingen. Informasjonen din er likevel sikker fordi Chromium stoppet tilkoblingen før det ble utvekslet noen data.</translation>
+<translation id="9106062320799175032">Legg til faktureringsadresse</translation>
+<translation id="910908805481542201">Hjelp meg med å fikse dette</translation>
+<translation id="9128870381267983090">Koble til nettverk</translation>
<translation id="9137013805542155359">Vis original</translation>
<translation id="9137248913990643158">Du må starte og logge på Chrome før du bruker denne appen.</translation>
<translation id="9148507642005240123">&amp;Angre endringen</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> bruker en protokoll som ikke støttes.</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="9215416866750762878">Et program hindrer Chrome i å koble trygt til dette nettstedet.</translation>
<translation id="9219103736887031265">Bilder</translation>
<translation id="933612690413056017">Du er ikke koblet til Internett</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ingen}=1{1 element}other{# elementer}}</translation>
<translation id="981121421437150478">Uten nett</translation>
<translation id="988159990683914416">Utviklerversjon</translation>
+<translation id="989988560359834682">Rediger adresse</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">«<ph name="SOFTWARE_NAME" />» er ikke riktig installert på datamaskinen eller på nettverket:
+ &lt;ul&gt;
+ &lt;li&gt;Prøv å avinstallere eller slå av «<ph name="SOFTWARE_NAME" />»&lt;/li&gt;
+ &lt;li&gt;Prøv å koble til et annet nettverk&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index 5236cc93d89..32181d99bcf 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Zakładki na komputerze</translation>
<translation id="1074497978438210769">Niezabezpieczona</translation>
<translation id="1080116354587839789">Dopasuj do szerokości</translation>
+<translation id="1088860948719068836">Dodaj imię i nazwisko z karty</translation>
<translation id="1103523840287552314">Zawsze tłumacz z języka: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Pokaż wszystkie zapisane hasła…</translation>
<translation id="1107591249535594099">Po zaznaczeniu tej opcji Chrome będzie zapisywać kopię danych karty na tym urządzeniu, by szybciej wypełniać formularze.</translation>
<translation id="1111153019813902504">Ostatnio używane zakładki</translation>
<translation id="1113869188872983271">&amp;Cofnij zmianę kolejności</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (zsynchronizowane)</translation>
<translation id="1263231323834454256">Do przeczytania</translation>
<translation id="1264126396475825575">Utworzono raport o awarii w dniu: <ph name="CRASH_TIME" /> (nie został jeszcze przesłany ani zignorowany)</translation>
+<translation id="1270502636509132238">Metoda odbioru</translation>
<translation id="1281526147609854549">Wystawca: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nigdy nie tłumacz tej witryny</translation>
<translation id="129553762522093515">Ostatnio zamknięte</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Czekam na połączenie…</translation>
<translation id="153384715582417236">Na razie to wszystko</translation>
<translation id="1549470594296187301">Aby można było korzystać z tej funkcji, musi być włączony JavaScript.</translation>
-<translation id="1555130319947370107">Niebieski</translation>
<translation id="1559528461873125649">Brak takiego pliku lub katalogu</translation>
<translation id="1583429793053364125">Podczas wyświetlania strony wystąpił błąd.</translation>
<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="1629803312968146339">Czy Chrome ma zapisać tę kartę?</translation>
<translation id="1639239467298939599">Wczytuję</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">System operacyjny</translation>
<translation id="1721312023322545264">Aby wejść na tę stronę, musisz uzyskać pozwolenie od użytkownika <ph name="NAME" /></translation>
<translation id="1721424275792716183">* Pole jest wymagane</translation>
+<translation id="1727741090716970331">Dodaj prawidłowy numer karty</translation>
<translation id="1728677426644403582">Przeglądasz źródło strony internetowej</translation>
<translation id="173080396488393970">Ten typ karty nie jest obsługiwany</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Podczas przekształcania do postaci szeregowej wystąpił błąd</translation>
<translation id="1974060860693918893">Zaawansowane</translation>
<translation id="1978555033938440688">Wersja oprogramowania</translation>
-<translation id="1995859865337580572">Sprawdź kod CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{i jeszcze 1}few{i jeszcze #}many{i jeszcze #}other{i jeszcze #}}</translation>
<translation id="2025186561304664664">Ustawiono automatyczne konfigurowanie proxy.</translation>
<translation id="2030481566774242610">Czy chodziło Ci o <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Cofnij</translation>
<translation id="20817612488360358">Skonfigurowano używanie systemowych ustawień proxy, ale podano też jawną konfigurację proxy.</translation>
<translation id="2086652334978798447">Aby uzyskać dostęp do spersonalizowanej treści proponowanej przez Google, zaloguj się w Chrome.</translation>
+<translation id="2091887806945687916">Dźwięk</translation>
<translation id="2094505752054353250">Niewłaściwa domena</translation>
<translation id="2096368010154057602">Departament</translation>
<translation id="2108755909498034140">Uruchom ponownie komputer</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorowana, ponieważ jest zastąpiona przez <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Szukam stron internetu rzeczy w pobliżu</translation>
<translation id="213826338245044447">Zakładki na komórce</translation>
+<translation id="214556005048008348">Anuluj płatność</translation>
<translation id="2147827593068025794">Synchronizacja w tle</translation>
+<translation id="2148613324460538318">Dodaj kartę</translation>
<translation id="2154054054215849342">Synchronizacja nie jest dostępna w Twojej domenie.</translation>
<translation id="2154484045852737596">Edytowanie karty</translation>
<translation id="2166049586286450108">Pełny dostęp administratora</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}few{# adresy}many{# adresów}other{# adresu}}</translation>
<translation id="2187317261103489799">Wykrywaj (domyślnie)</translation>
<translation id="2202020181578195191">Wpisz rok w prawidłowym formacie</translation>
+<translation id="2209523182407020534">Aplikacje, które mogą wywoływać ten błąd, to na przykład programy antywirusowe, zapory sieciowe oraz oprogramowanie do filtrowania ruchu w sieci lub obsługi serwera proxy.</translation>
<translation id="2212735316055980242">Nie znaleziono zasady</translation>
<translation id="2213606439339815911">Pobieram wpisy...</translation>
<translation id="2218879909401188352">Osoby obecnie atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą instalować niebezpieczne aplikacje, które mogą uszkodzić Twoje urządzenie, dodać ukryte opłaty do rachunku za usługi telefoniczne lub wykraść Twoje dane osobowe. <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Wróć</translation>
<translation id="2503184589641749290">Akceptowane karty debetowe i przedpłacone</translation>
<translation id="2515629240566999685">Sprawdź sygnał w swojej okolicy</translation>
+<translation id="2524461107774643265">Dodaj więcej informacji</translation>
+<translation id="2536110899380797252">Dodaj adres</translation>
<translation id="2539524384386349900">Wykrywaj</translation>
<translation id="255002559098805027">Serwer <ph name="HOST_NAME" /> wysłał nieprawidłową odpowiedź.</translation>
<translation id="2556876185419854533">&amp;Cofnij edycję</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium nie może obecnie potwierdzić karty. Spróbuj ponownie później.</translation>
<translation id="2705137772291741111">Zapisana w pamięci podręcznej kopia tej strony jest uszkodzona.</translation>
<translation id="2709516037105925701">Autouzupełnianie</translation>
+<translation id="2710942282213947212">Oprogramowanie na Twoim komputerze uniemożliwia Chromium bezpieczne połączenie się z internetem</translation>
<translation id="2712173769900027643">Poproś o pozwolenie</translation>
-<translation id="2713444072780614174">Biały</translation>
<translation id="2720342946869265578">W pobliżu</translation>
<translation id="2721148159707890343">Żądanie wykonane pomyślnie</translation>
<translation id="2728127805433021124">Certyfikat serwera został podpisany przy użyciu słabego algorytmu podpisu.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Wykryto zmianę sieci.</translation>
<translation id="2916038427272391327">Zamknij inne programy</translation>
<translation id="2922350208395188000">Nie można sprawdzić certyfikatu serwera.</translation>
+<translation id="2925673989565098301">Metoda dostawy</translation>
<translation id="2928905813689894207">Adres rozliczeniowy</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat pochodzi z <ph name="DOMAIN2" />. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Nieprawidłowy typ zasady</translation>
<translation id="3032412215588512954">Chcesz ponownie załadować tę stronę?</translation>
<translation id="3037605927509011580">Kurza twarz!</translation>
+<translation id="3039538478787849737">Zapisać kartę w Google?</translation>
<translation id="3041612393474885105">Informacje o certyfikacie</translation>
<translation id="3063697135517575841">Chrome nie może obecnie potwierdzić karty. Spróbuj ponownie później.</translation>
<translation id="3064966200440839136">Opuszczasz tryb incognito, by zapłacić w aplikacji zewnętrznej. Kontynuować?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Tymczasowy błąd serwera</translation>
<translation id="3154506275960390542">Strona zawiera formularz, którego nie można przesłać bezpiecznie. Podczas przesyłania dane mogą zobaczyć inni użytkownicy, a hakerzy mogą je zmodyfikować, by na serwer dotarły zmienione dane.</translation>
<translation id="3157931365184549694">Przywróć</translation>
+<translation id="3162559335345991374">Sieć Wi-Fi, której używasz, może wymagać otwarcia strony logowania.</translation>
<translation id="3167968892399408617">Po zamknięciu wszystkich kart incognito wyświetlane na nich strony nie pozostawią żadnych śladów w historii przeglądarki, magazynie plików cookie ani historii wyszukiwania. Pobrane pliki i utworzone zakładki zostaną jednak zachowane.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Wyspa</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Anuluj płatność</translation>
<translation id="3207960819495026254">Dodano do zakładek</translation>
+<translation id="3211223744486044430">Aby następnym razem zapłacić szybciej, zapisz tę kartę na swoim koncie Google i na tym urządzeniu.</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>
<translation id="3226128629678568754">Naciśnij przycisk ponownego załadowania, by przesłać dane wymagane do wczytania strony.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Brak wyników wyszukiwania</translation>
<translation id="3305707030755673451">Twoje dane zostały zaszyfrowane z użyciem hasła synchronizacji w dniu <ph name="TIME" />. Wpisz je, by rozpocząć synchronizację.</translation>
<translation id="3320021301628644560">Dodaj adres rozliczeniowy</translation>
-<translation id="3329013043687509092">Nasycenie</translation>
<translation id="333371639341676808">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie.</translation>
<translation id="3338095232262050444">Bezpieczna</translation>
<translation id="3340978935015468852">ustawienia</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Identyfikator klienta:</translation>
<translation id="3391030046425686457">Adres dostawy</translation>
<translation id="3395827396354264108">Metoda odbioru</translation>
+<translation id="3399952811970034796">Adres dostawy</translation>
<translation id="3422248202833853650">Zamknij inne programy, by zwolnić pamięć.</translation>
<translation id="3422472998109090673">Strona <ph name="HOST_NAME" /> jest obecnie nieosiągalna.</translation>
<translation id="3427092606871434483">Zezwalaj (domyślnie)</translation>
@@ -361,14 +372,16 @@
<translation id="3655670868607891010">Jeśli często widzisz ten komunikat, przeczytaj <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Wersja</translation>
<translation id="3678029195006412963">Nie udało się podpisać żądania</translation>
-<translation id="3678529606614285348">Otwórz stronę w nowym oknie incognito (Ctrl-Shift-N)</translation>
+<translation id="3678529606614285348">Otwórz stronę w nowym oknie incognito (Ctrl+Shift+N)</translation>
<translation id="3679803492151881375">Raport o awarii zarejestrowano: <ph name="CRASH_TIME" />, przesłano: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informacje o certyfikacie</translation>
<translation id="3690164694835360974">Logowanie nie jest bezpieczne</translation>
+<translation id="3704162925118123524">Sieć, której używasz, może wymagać otwarcia strony logowania.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Ładuję...</translation>
<translation id="3712624925041724820">Brak wolnych licencji</translation>
<translation id="3714780639079136834">Włącz komórkową transmisję danych lub Wi-Fi</translation>
+<translation id="3715597595485130451">Połączenie z siecią Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sprawdź serwer proxy, zaporę sieciową i konfigurację DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Jeśli rozumiesz zagrożenie, możesz <ph name="BEGIN_LINK" />odwiedzić tę niebezpieczną stronę<ph name="END_LINK" />, zanim niebezpieczne programy zostaną usunięte.</translation>
<translation id="3739623965217189342">Skopiowany link</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Cofnij dodanie</translation>
<translation id="404928562651467259">OSTRZEŻENIE</translation>
<translation id="4058922952496707368">Klucz „<ph name="SUBKEY" />”: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxy skonfigurowano do używania URL-a skryptu PAC, a nie ustalonych serwerów proxy.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Numer seryjny urządzenia jest nieprawidłowy</translation>
<translation id="410351446219883937">Autoodtwarzanie</translation>
<translation id="4103763322291513355">Wejdź na stronę &lt;strong&gt;chrome://policy&lt;/strong&gt;, aby wyświetlić czarną listę URL-i oraz inne zasady egzekwowane przez administratora systemu.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Zawsze zezwalaj w tej witrynie</translation>
<translation id="4117700440116928470">Ten zakres zasad nie jest obsługiwany.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 inny wpis}few{# inne wpisy}many{# innych wpisów}other{# innego wpisu}}</translation>
@@ -418,7 +431,7 @@
<translation id="413544239732274901">Więcej informacji</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Użyj globalnego ustawienia domyślnego (Wykrywaj)</translation>
-<translation id="4165986682804962316">Ustawienia witryny</translation>
+<translation id="4165986682804962316">Ustawienia witryn</translation>
<translation id="4169947484918424451">Czy Chromium ma zapisać tę kartę?</translation>
<translation id="4171400957073367226">Nieprawidłowy podpis weryfikujący</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Jeszcze <ph name="ITEM_COUNT" /> element}few{Jeszcze <ph name="ITEM_COUNT" /> elementy}many{Jeszcze <ph name="ITEM_COUNT" /> elementów}other{Jeszcze <ph name="ITEM_COUNT" /> elementu}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Próbujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawił certyfikat unieważniony przez wystawcę. Oznacza to, że dane uwierzytelniające podane przez serwer są zupełnie niewiarygodne. Możliwe, że komunikujesz się z intruzem.</translation>
<translation id="4394049700291259645">Wyłącz</translation>
<translation id="4406896451731180161">wyniki wyszukiwania</translation>
+<translation id="4415426530740016218">Adres odbioru</translation>
<translation id="4424024547088906515">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest zaufany w Chrome. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="4432688616882109544">Serwer <ph name="HOST_NAME" /> nie zaakceptował lub nie otrzymał Twojego certyfikatu logowania.</translation>
<translation id="443673843213245140">Korzystanie z serwera proxy jest wyłączone, ale podano konfigurację proxy.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Spróbuj wyłączyć rozszerzenia.</translation>
<translation id="457875822857220463">Dostawa</translation>
+<translation id="4582800630050655161">Możesz stracić dostęp do swojego konta Google lub paść ofiarą kradzieży tożsamości. Chromium zaleca natychmiastową zmianę hasła.</translation>
<translation id="4587425331216688090">Usunąć ten adres z Chrome?</translation>
<translation id="4592951414987517459">Połączenie z <ph name="DOMAIN" /> jest szyfrowane przy użyciu nowoczesnego zestawu szyfrów.</translation>
<translation id="4594403342090139922">&amp;Cofnij usunięcie</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Przestań używać nieprawidłowego certyfikatu</translation>
+<translation id="4690954380545377795">Możesz stracić dostęp do swojego konta Google lub paść ofiarą kradzieży tożsamości. Chrome zaleca natychmiastową zmianę hasła.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Połączenie zostało przerwane</translation>
<translation id="471880041731876836">Nie masz pozwolenia, by wejść na tę stronę</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Uruchom Diagnostykę sieci systemu Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Twoja płatność</translation>
<translation id="4726672564094551039">Odśwież zasady</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Uruchom ponownie Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Nieprawidłowy stan magazynu wspomagającego</translation>
<translation id="5023310440958281426">Sprawdź zasady administratora</translation>
<translation id="5029568752722684782">Usuń kopię</translation>
+<translation id="503069730517007720">Certyfikat główny oprogramowania „<ph name="SOFTWARE_NAME" />” jest wymagany, ale nie został zainstalowany. Aby rozwiązać ten problem, administrator powinien przeczytać instrukcje dotyczące konfiguracji oprogramowania „<ph name="SOFTWARE_NAME" />”. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Tłumacz Google – informacje</translation>
<translation id="5039804452771397117">Zezwalaj</translation>
<translation id="5040262127954254034">Prywatność</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Eksperymenty</translation>
<translation id="5205222826937269299">Nazwa jest wymagana</translation>
<translation id="5222812217790122047">E-mail jest wymagany</translation>
+<translation id="522700295135997067">Możliwe, że ta strona właśnie wykradła Twoje hasło</translation>
+<translation id="5230733896359313003">Adres wysyłki</translation>
<translation id="5251803541071282808">Chmura</translation>
<translation id="5277279256032773186">Korzystasz z Chrome w pracy? Firmy mogą zarządzać ustawieniami Chrome swoich pracowników. Więcej informacji</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Wykonaj te czynności, by tymczasowo wyłączyć to oprogramowanie i połączyć się z internetem. Będziesz potrzebować uprawnień administratora.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Połączenie z tą stroną nie jest prywatne. Aby w dowolnym momencie zamknąć tryb VR, zdejmij gogle i naciśnij Wstecz.</translation>
<translation id="5299298092464848405">Podczas przetwarzania zasady wystąpił błąd</translation>
+<translation id="5308380583665731573">Połącz</translation>
<translation id="5308689395849655368">Funkcja zgłaszania awarii jest wyłączona.</translation>
<translation id="5317780077021120954">Zapisz</translation>
<translation id="5327248766486351172">Nazwa</translation>
+<translation id="5332219387342487447">Metoda wysyłki</translation>
<translation id="5355557959165512791">Nie możesz teraz otworzyć strony <ph name="SITE" />, bo jej certyfikat został unieważniony. Błędy sieci i ataki są zazwyczaj przejściowe, więc prawdopodobnie strona będzie wkrótce działać.</translation>
<translation id="536296301121032821">Zapisanie ustawień zasady nie powiodło się</translation>
<translation id="5386426401304769735">Łańcuch certyfikatów tej witryny zawiera certyfikat podpisany za pomocą SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Ta witryna w intranecie firmy, organizacji czy szkoły ma ten sam URL co zewnętrzna strona internetowa.
<ph name="LINE_BREAK" />
Skontaktuj się z administratorem systemu.</translation>
+<translation id="5499929369096410817">Podaj kod zabezpieczający dla karty <ph name="CREDIT_CARD" />. Nie zostanie on zapisany.</translation>
<translation id="5509780412636533143">Zakładki zarządzane</translation>
<translation id="5510766032865166053">Mógł zostać przeniesiony lub usunięty.</translation>
<translation id="5523118979700054094">Nazwa zasady</translation>
<translation id="552553974213252141">Czy tekst został prawidłowo wyodrębniony?</translation>
<translation id="5540224163453853">Nie udało się znaleźć tego artykułu.</translation>
+<translation id="5541546772353173584">Dodaj adres e-mail</translation>
<translation id="5544037170328430102">Komunikat z elementu umieszczonego na stronie <ph name="SITE" />:</translation>
+<translation id="5545756402275714221">Artykuły dla Ciebie</translation>
<translation id="5556459405103347317">Odśwież</translation>
<translation id="5560088892362098740">Data ważności</translation>
<translation id="5565735124758917034">Aktywny</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Otrzymywanie spersonalizowanych treści</translation>
<translation id="5675650730144413517">Ta strona nie działa</translation>
+<translation id="5689199277474810259">Eksportuj w formacie JSON</translation>
<translation id="5710435578057952990">Tożsamość witryny nie została zweryfikowana.</translation>
<translation id="5719499550583120431">Karty przedpłacone są akceptowane.</translation>
<translation id="5720705177508910913">Bieżący użytkownik</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Połączenie z <ph name="DOMAIN" /> jest szyfrowane przy użyciu przestarzałego zestawu szyfrów.</translation>
<translation id="5813119285467412249">&amp;Ponów dodanie</translation>
<translation id="5838278095973806738">Nie podawaj żadnych informacji poufnych (takich jak hasła czy karty kredytowe) w tej witrynie, bo osoby atakujące będą mogły je wykraść.</translation>
+<translation id="5866257070973731571">Dodaj numer telefonu</translation>
<translation id="5869405914158311789">Ta witryna jest nieosiągalna</translation>
<translation id="5869522115854928033">Zapisane hasła</translation>
<translation id="5872918882028971132">Propozycje rodziców</translation>
<translation id="5893752035575986141">Karty kredytowe są akceptowane.</translation>
-<translation id="5901630391730855834">Żółty</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (zsynchronizowane)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{W użyciu: 1}few{W użyciu: #}many{W użyciu: #}other{W użyciu: #}}</translation>
<translation id="5959728338436674663">Automatycznie wysyłaj do Google niektóre <ph name="BEGIN_WHITEPAPER_LINK" />informacje o systemie i część zawartości stron<ph name="END_WHITEPAPER_LINK" />, by pomóc w wykrywaniu niebezpiecznych aplikacji i witryn. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edytuj dane kontaktowe</translation>
<translation id="5967867314010545767">Usuń z historii</translation>
<translation id="5975083100439434680">Pomniejsz</translation>
+<translation id="597552863672748783">Potwierdź kod zabezpieczający</translation>
<translation id="598637245381783098">Nie można otworzyć aplikacji do płatności</translation>
<translation id="5989320800837274978">Nie określono ani stałych serwerów proxy, ani adresu URL skryptu PAC.</translation>
<translation id="5990559369517809815">Żądania do serwera zostały zablokowane przez rozszerzenie.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Strona 1}few{Strona #}many{Strona #}other{Strona #}}</translation>
-<translation id="6017514345406065928">Zielony</translation>
<translation id="6017850046339264347">Osoby atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą instalować 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_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (zsynchronizowane)</translation>
<translation id="6027201098523975773">Wpisz imię i nazwisko</translation>
<translation id="6040143037577758943">Zamknij</translation>
-<translation id="6042308850641462728">Więcej</translation>
<translation id="6047233362582046994">Jeśli rozumiesz zagrożenie, możesz <ph name="BEGIN_LINK" />wejść na tę stronę<ph name="END_LINK" />, zanim szkodliwe aplikacje zostaną usunięte.</translation>
<translation id="6047927260846328439">Te treści mogą próbować podstępem nakłonić Cię do zainstalowania oprogramowania lub ujawnienia danych osobowych. <ph name="BEGIN_LINK" />Wyświetl mimo to<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Nie możesz teraz otworzyć strony <ph name="SITE" />, ponieważ stosuje ona przypinanie certyfikatów. Błędy sieciowe i ataki są zazwyczaj tymczasowe, więc prawdopodobnie strona będzie dostępna później.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Przeglądasz stronę rozszerzenia</translation>
<translation id="6596325263575161958">Opcje szyfrowania</translation>
<translation id="662080504995468778">Zostań</translation>
+<translation id="6624427990725312378">Dane kontaktowe</translation>
<translation id="6626291197371920147">Dodaj prawidłowy numer karty</translation>
<translation id="6628463337424475685">Wyszukiwarka <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Osoby obecnie atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą próbować zainstalować na Twoim komputerze Mac niebezpieczne programy wykradające lub usuwające informacje (na przykład zdjęcia, hasła, wiadomości lub dane kart kredytowych). <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Wstecz</translation>
<translation id="6710594484020273272">&lt;Wpisz wyszukiwane słowa&gt;</translation>
<translation id="6711464428925977395">Serwer proxy działa nieprawidłowo albo adres jest błędny.</translation>
-<translation id="6727102863431372879">Ustaw</translation>
<translation id="674375294223700098">Nieznany błąd certyfikatu serwera.</translation>
<translation id="6753269504797312559">Wartość zasady</translation>
<translation id="6757797048963528358">Twoje urządzenie przeszło w tryb uśpienia.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">Adres URL</translation>
<translation id="7419106976560586862">Ścieżka profilu</translation>
<translation id="7424977062513257142">Komunikat z elementu umieszczonego na bieżącej stronie internetowej:</translation>
+<translation id="7437289804838430631">Dodaj dane kontaktowe</translation>
<translation id="7441627299479586546">Nieprawidłowy podmiot zasady</translation>
<translation id="7444046173054089907">Ta strona jest zablokowana</translation>
<translation id="7445762425076701745">Nie można w pełni zweryfikować tożsamości serwera, z którym nawiązano połączenie. Nawiązano połączenie z serwerem przy użyciu nazwy obowiązującej jedynie w Twojej sieci i której własności zewnętrzny urząd certyfikacji nie jest w stanie zweryfikować. Niektóre urzędy certyfikacji wydają certyfikaty dla takich nazw bez względu na to, że nie można upewnić się, iż nawiązano połączenie z witryną, z którą zamierzano, a nie z intruzem.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Dalej</translation>
<translation id="7485870689360869515">Nie znaleziono danych.</translation>
<translation id="7508255263130623398">Zwrócony identyfikator urządzenia dla zasad jest pusty lub nie pasuje do bieżącego identyfikatora urządzenia</translation>
+<translation id="7511955381719512146">Sieć Wi-Fi, której używasz, może wymagać otwarcia strony <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Pobierz</translation>
<translation id="7518003948725431193">Nie znaleziono strony internetowej pod adresem <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Twoje połączenie z tą stroną nie jest prywatne</translation>
-<translation id="7535087603100972091">Wartość</translation>
<translation id="7537536606612762813">Obowiązkowe</translation>
<translation id="7542403920425041731">Po potwierdzeniu szczegółowe dane karty zostaną udostępnione tej stronie.</translation>
<translation id="7542995811387359312">Automatyczne wypełnianie danych karty kredytowej jest wyłączone, ponieważ ten formularz nie korzysta z bezpiecznego połączenia.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa mógł zostać wydany w celu oszustwa. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="7568593326407688803">Język strony:<ph name="ORIGINAL_LANGUAGE" />Chcesz ją przetłumaczyć?</translation>
<translation id="7569952961197462199">Usunąć tę kartę kredytową z Chrome?</translation>
-<translation id="7569983096843329377">Czarny</translation>
<translation id="7578104083680115302">Używaj swoich kart zapisanych w Google, by łatwiej dokonywać płatności na stronach i w aplikacjach na różnych urządzeniach.</translation>
<translation id="7588950540487816470">Internet rzeczy</translation>
<translation id="7592362899630581445">Certyfikat serwera narusza ograniczenia dotyczące nazw.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Osoby atakujące tę stronę mogą podstępem próbować nakłonić Cię do zainstalowania programów utrudniających przeglądanie internetu (np. zmieniających stronę główną lub wyświetlających dodatkowe reklamy na stronach, na które wchodzisz).</translation>
<translation id="7674629440242451245">Interesują Cię nowe, przydatne funkcje Chrome? Wypróbuj wersję deweloperską ze strony chrome.com/dev.</translation>
<translation id="7682287625158474539">Adres wysyłkowy</translation>
+<translation id="7699293099605015246">Artykuły nie są obecnie dostępne</translation>
<translation id="7701040980221191251">Brak</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Otwórz stronę <ph name="SITE" /> (niebezpieczną)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certyfikat</translation>
<translation id="7716147886133743102">Zablokowane przez administratora</translation>
<translation id="7716424297397655342">Nie można załadować tej strony z pamięci podręcznej</translation>
+<translation id="7723047071702270851">Edytuj kartę</translation>
<translation id="774634243536837715">Zablokowano niebezpieczne treści.</translation>
<translation id="7752995774971033316">Niezarządzany</translation>
<translation id="7755287808199759310">Może ją dla Ciebie odblokować Twój rodzic</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Dodaj adres</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
+<translation id="7793553086574152071">Aby następnym razem zapłacić szybciej, zapisz tę kartę na swoim koncie Google.</translation>
<translation id="7793809570500803535">Strona <ph name="SITE" /> może być tymczasowo niedostępna lub została na stałe przeniesiona pod nowy adres internetowy.</translation>
<translation id="7800304661137206267">Przesyłane dane są szyfrowane za pomocą algorytmu <ph name="CIPHER" />. Metoda uwierzytelniania komunikatów to <ph name="MAC" />, a mechanizm wymiany kluczy to <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Strona spełnia wymagania prawne</translation>
<translation id="780301667611848630">Nie, dziękuję</translation>
<translation id="7805768142964895445">Stan</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Usunąć tę podpowiedź do formularza z Chrome?</translation>
<translation id="7815407501681723534">Znalezione <ph name="SEARCH_RESULTS" /> dla zapytania „<ph name="SEARCH_STRING" />”: <ph name="NUMBER_OF_RESULTS" /></translation>
+<translation id="782886543891417279">Sieć Wi-Fi (<ph name="WIFI_NAME" />), której używasz, może wymagać otwarcia strony logowania.</translation>
<translation id="785549533363645510">To jednak nie znaczy, że Cię nie widać. Nawet gdy przejdziesz w tryb incognito, Twój pracodawca, dostawca usług internetowych czy webmasterzy stron, na które wchodzisz, mogą dowiedzieć się, co przeglądasz.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Karty debetowe i przedpłacone są akceptowane.</translation>
+<translation id="7878562273885520351">Ktoś mógł poznać Twoje hasło</translation>
<translation id="7887683347370398519">Sprawdź kod CVC i spróbuj ponownie</translation>
<translation id="79338296614623784">Wpisz prawidłowy numer telefonu</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certyfikat serwera nie jest jeszcze ważny.</translation>
-<translation id="7942349550061667556">Czerwony</translation>
<translation id="7947285636476623132">Sprawdź rok ważności i spróbuj ponownie</translation>
<translation id="7951415247503192394">(32-bitowa)</translation>
<translation id="7956713633345437162">Zakładki na komórce</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Pytaj (domyślnie)</translation>
<translation id="8041089156583427627">Prześlij opinię</translation>
<translation id="8041940743680923270">Użyj globalnej wartości domyślnej (Pytaj)</translation>
+<translation id="8057711352706143257">Oprogramowanie „<ph name="SOFTWARE_NAME" />” nie jest prawidłowo skonfigurowane. Odinstalowanie oprogramowania „<ph name="SOFTWARE_NAME" />” zwykle rozwiązuje problem. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Nie udało się wyświetlić artykułu.</translation>
<translation id="8091372947890762290">Aktywacja oczekuje na serwerze</translation>
+<translation id="8094917007353911263">Sieć, której używasz, może wymagać otwarcia strony <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Forma płatności</translation>
<translation id="8118489163946903409">Forma płatności</translation>
+<translation id="8127301229239896662">Oprogramowanie „<ph name="SOFTWARE_NAME" />” nie zostało prawidłowo zainstalowane na komputerze lub w sieci. Poproś administratora o rozwiązanie tego problemu.</translation>
<translation id="8131740175452115882">Potwierdź</translation>
<translation id="8134994873729925007">Nie udało się znaleźć <ph name="BEGIN_ABBR" />adresu DNS<ph name="END_ABBR" /> serwera <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Twój komputer przeszedł w tryb uśpienia.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Jeśli nie masz pewności, co to oznacza, skontaktuj się z administratorem sieci.</translation>
<translation id="8293206222192510085">Dodaj zakładkę</translation>
<translation id="8294431847097064396">Źródło</translation>
+<translation id="8298115750975731693">Sieć Wi-Fi (<ph name="WIFI_NAME" />), której używasz, może wymagać otwarcia strony <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Nie można nawiązać prywatnego połączenia z <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, ponieważ data i godzina ustawione na urządzeniu (<ph name="DATE_AND_TIME" />) są nieprawidłowe. <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Tłumaczenie nie powiodło się z powodu problemu z połączeniem sieciowym.</translation>
<translation id="8332188693563227489">Odmowa dostępu do <ph name="HOST_NAME" /></translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Ostatnio zamknięte</translation>
<translation id="8874824191258364635">Wpisz prawidłowy numer karty</translation>
<translation id="8876793034577346603">Przetwarzanie konfiguracji sieci nie powiodło się.</translation>
-<translation id="8889402386540077796">Odcień</translation>
<translation id="8891727572606052622">Nieprawidłowy tryb proxy</translation>
<translation id="889901481107108152">Eksperyment jest niedostępny na Twojej platformie.</translation>
<translation id="8903921497873541725">Powiększ</translation>
<translation id="8931333241327730545">Chcesz zapisać tę kartę na swoim koncie Google?</translation>
<translation id="8932102934695377596">Twój zegar się spóźnia</translation>
+<translation id="893332455753468063">Dodaj imię i nazwisko lub nazwę firmy</translation>
<translation id="8938939909778640821">Akceptowane karty kredytowe i przedpłacone</translation>
+<translation id="8957210676456822347">Autoryzacja portalu przechwytującego</translation>
<translation id="8971063699422889582">Ważność certyfikatu serwera wygasła.</translation>
-<translation id="8986494364107987395">Automatycznie przesyłaj do Google statystyki użytkowania i raporty o awariach</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Na następnej stronie znajdują się szkodliwe programy</translation>
<translation id="8997023839087525404">Certyfikat przesłany przez serwer nie został publicznie ujawniony przez protokół Certificate Transparency. Jest to wymagane w przypadku niektórych certyfikatów jako potwierdzenie, że są one zaufane i zabezpieczone przed atakami.</translation>
<translation id="9001074447101275817">Serwer proxy <ph name="DOMAIN" /> wymaga nazwy użytkownika i hasła.</translation>
<translation id="9005998258318286617">Nie udało się wczytać dokumentu PDF.</translation>
+<translation id="9008201768610948239">Ignoruj</translation>
<translation id="901974403500617787">Flagi stosowane w całym systemie może ustawić tylko właściciel: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Wymagany jest adres rozliczeniowy karty kredytowej</translation>
<translation id="9020542370529661692">Ta strona została przetłumaczona na <ph name="TARGET_LANGUAGE" />.</translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Podjęto próbę nawiązania połączenia z witryną <ph name="DOMAIN" />, jednak serwer przedstawił nieprawidłowy certyfikat.</translation>
<translation id="9050666287014529139">Hasło</translation>
<translation id="9065203028668620118">Edycja</translation>
-<translation id="9068849894565669697">Wybierz kolor</translation>
<translation id="9069693763241529744">Zablokowane przez rozszerzenie</translation>
<translation id="9076283476770535406">Może zawierać treści dla dorosłych</translation>
<translation id="9078964945751709336">Potrzebujemy więcej informacji</translation>
+<translation id="9080712759204168376">Podsumowanie zamówienia</translation>
<translation id="9103872766612412690"><ph name="SITE" /> zazwyczaj używa szyfrowania do ochrony Twoich informacji. Gdy tym razem przeglądarka Chromium próbowała połączyć się ze stroną <ph name="SITE" />, odesłała ona nietypowe i nieprawidłowe dane logowania. Może się tak zdarzyć, gdy pod stronę <ph name="SITE" /> podszywa się osoba atakująca albo gdy ekran logowania do sieci Wi-Fi przerwie połączenie. Twoje informacje są nadal bezpieczne, bo połączenie w Chromium zakończyło się przed wymianą jakichkolwiek danych.</translation>
+<translation id="9106062320799175032">Dodaj adres rozliczeniowy</translation>
+<translation id="910908805481542201">Pomóż mi to naprawić</translation>
+<translation id="9128870381267983090">Połącz z siecią</translation>
<translation id="9137013805542155359">Pokaż tekst oryginalny</translation>
<translation id="9137248913990643158">Aby użyć tej aplikacji, najpierw uruchom Chrome i zaloguj się w nim.</translation>
<translation id="9148507642005240123">&amp;Cofnij edycję</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">Serwer <ph name="HOST_NAME" /> używa nieobsługiwanego protokołu.</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="9215416866750762878">Aplikacja uniemożliwia Chrome bezpieczne połączenie się z tą stroną</translation>
<translation id="9219103736887031265">Grafika</translation>
<translation id="933612690413056017">Brak połączenia z internetem</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Brak}=1{1 element}few{# elementy}many{# elementów}other{# elementu}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Build</translation>
+<translation id="989988560359834682">Edytuj adres</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Oprogramowanie „<ph name="SOFTWARE_NAME" />” nie zostało prawidłowo zainstalowane na komputerze lub w sieci:
+ &lt;ul&gt;
+ &lt;li&gt;Odinstaluj lub wyłącz oprogramowanie „<ph name="SOFTWARE_NAME" />”.&lt;/li&gt;
+ &lt;li&gt;Połącz się z inną siecią.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index a4cc4e8b960..15b463f0c09 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Favoritos em computador</translation>
<translation id="1074497978438210769">Não seguro</translation>
<translation id="1080116354587839789">Ajustar à largura</translation>
+<translation id="1088860948719068836">Adicionar Nome como consta no Cartão</translation>
<translation id="1103523840287552314">Sempre traduzir do <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostrar todas as senhas salvas…</translation>
<translation id="1107591249535594099">Se esta opção for selecionada, o Chrome armazenará uma cópia do seu cartão neste dispositivo para preenchimento de formulários mais rapidamente.</translation>
<translation id="1111153019813902504">Favoritos recentes</translation>
<translation id="1113869188872983271">&amp;Desfazer reordenar</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizados)</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de erros registrado em <ph name="CRASH_TIME" /> (ainda não enviado ou ignorado)</translation>
+<translation id="1270502636509132238">Método de Retirada</translation>
<translation id="1281526147609854549">Publicado por <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
<translation id="129553762522093515">Recentemente fechadas</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Aguardando conexão...</translation>
<translation id="153384715582417236">Isso é tudo por enquanto</translation>
<translation id="1549470594296187301">O JavaScript deve ser ativado para usar este recurso.</translation>
-<translation id="1555130319947370107">Azul</translation>
<translation id="1559528461873125649">Arquivo ou diretório não encontrado</translation>
<translation id="1583429793053364125">Algo deu errado ao exibir esta página da Web.</translation>
<translation id="1592005682883173041">Acesso a dados locais</translation>
<translation id="1594030484168838125">Escolher</translation>
-<translation id="161042844686301425">Ciano</translation>
<translation id="1620510694547887537">Câmera</translation>
<translation id="1629803312968146339">Deseja que o Chrome salve este cartão?</translation>
<translation id="1639239467298939599">Carregando</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">É necessário pedir a permissão de <ph name="NAME" /> para visitar este site</translation>
<translation id="1721424275792716183">* Campo obrigatório</translation>
+<translation id="1727741090716970331">Adicione um Número de Cartão Válido</translation>
<translation id="1728677426644403582">Você está vendo o código-fonte de uma página da Web.</translation>
<translation id="173080396488393970">Esse tipo de cartão não é aceito</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Erro de serialização</translation>
<translation id="1974060860693918893">Avançado</translation>
<translation id="1978555033938440688">Versão do firmware</translation>
-<translation id="1995859865337580572">Verifique seu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{e mais um}one{e mais #}other{e mais #}}</translation>
<translation id="2025186561304664664">O proxy está configurado em configuração automática.</translation>
<translation id="2030481566774242610">Você quis dizer <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Para receber conteúdo personalizado sugerido pelo Google, faça login no Chrome.</translation>
+<translation id="2091887806945687916">Som</translation>
<translation id="2094505752054353250">Incompatibilidade de domínio</translation>
<translation id="2096368010154057602">Departamento</translation>
<translation id="2108755909498034140">Reiniciar seu computador</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorado porque foi substituído por <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Procurando páginas da Web física nas proximidades</translation>
<translation id="213826338245044447">Favoritos de dispositivos móveis</translation>
+<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
+<translation id="2148613324460538318">Adicionar Cartão</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="2166049586286450108">Acesso completo de administrador</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# endereço}other{# endereços}}</translation>
<translation id="2187317261103489799">Detectar (padrão)</translation>
<translation id="2202020181578195191">Informe um ano de validade válido</translation>
+<translation id="2209523182407020534">Entre os aplicativos que podem causar esse erro estão antivírus, firewall e softwares de filtros ou proxy da Web.</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">Buscando entradas...</translation>
<translation id="2218879909401188352">Os invasores que estão em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> no momento podem instalar apps perigosos que danificam seu dispositivo, acrescentam cobranças ocultas junto à operadora ou roubam suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Voltar</translation>
<translation id="2503184589641749290">Cartões de débito e pré-pagos aceitos</translation>
<translation id="2515629240566999685">Verificar o sinal na sua área</translation>
+<translation id="2524461107774643265">Adicione Mais Informações</translation>
+<translation id="2536110899380797252">Adicionar Endereço</translation>
<translation id="2539524384386349900">Detectar</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> enviou uma resposta inválida.</translation>
<translation id="2556876185419854533">&amp;Desfazer editar</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Não foi possível confirmar seu cartão com o Chromium no momento. Tente novamente mais tarde.</translation>
<translation id="2705137772291741111">Não foi possível ler a cópia armazenada em cache deste site.</translation>
<translation id="2709516037105925701">Preenchimento automático</translation>
+<translation id="2710942282213947212">Algum software no seu computador está impedindo o Chromium de se conectar com segurança à Web</translation>
<translation id="2712173769900027643">Pedir permissão</translation>
-<translation id="2713444072780614174">Branco</translation>
<translation id="2720342946869265578">Por perto</translation>
<translation id="2721148159707890343">Solicitação bem-sucedida</translation>
<translation id="2728127805433021124">O certificado do servidor é assinado com um algoritmo de assinatura fraco.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Foi detectada uma alteração na rede.</translation>
<translation id="2916038427272391327">Fechar outros programas</translation>
<translation id="2922350208395188000">O certificado do servidor não pode ser verificado.</translation>
+<translation id="2925673989565098301">Método de Exibição</translation>
<translation id="2928905813689894207">Endereço de cobrança</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança é de <ph name="DOMAIN2" />. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3032412215588512954">Deseja atualizar este site?</translation>
<translation id="3037605927509011580">Ah, não!</translation>
+<translation id="3039538478787849737">Salvar cartão no Google?</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">Não foi possível confirmar seu cartão com o Chrome no momento. Tente novamente mais tarde.</translation>
<translation id="3064966200440839136">Saindo do modo sem rastros para pagar usando um aplicativo externo. Continuar?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Erro temporário do servidor</translation>
<translation id="3154506275960390542">Essa página inclui um formulário que pode não ser enviado de forma segura. Os dados que você envia podem ser vistos por outras pessoas enquanto elas navegam ou ser modificados por um invasor para alterar o que o servidor recebe.</translation>
<translation id="3157931365184549694">Restaurar</translation>
+<translation id="3162559335345991374">O Wi-Fi que você está usando pode exigir a visita a uma página de login.</translation>
<translation id="3167968892399408617">Quando você está no modo invisível, as páginas que você visita não aparecem no seu histórico de navegação e de pesquisa, nem armazenam arquivos "cookies". Mas os downloads e os favoritos continuam funcionando normalmente.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ilha</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancelar pagamento</translation>
<translation id="3207960819495026254">Adicionada aos favoritos</translation>
+<translation id="3211223744486044430">Para agilizar o pagamento na próxima vez, salve este cartão na sua Conta do Google e neste dispositivo.</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>
<translation id="3226128629678568754">Pressione o botão "Atualizar" para reenviar os dados necessários para carregar a página.</translation>
<translation id="3227137524299004712">Microfone</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Nenhum resultado de pesquisa encontrado</translation>
<translation id="3305707030755673451">Seus dados foram criptografados com sua senha longa de sincronização no dia <ph name="TIME" />. Informe-a para começar a sincronização.</translation>
<translation id="3320021301628644560">Adicionar endereço de faturamento</translation>
-<translation id="3329013043687509092">Saturação</translation>
<translation id="333371639341676808">Impedir que esta página crie caixas de diálogo adicionais.</translation>
<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">configurações</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID do cliente:</translation>
<translation id="3391030046425686457">Endereço de entrega</translation>
<translation id="3395827396354264108">Método de retirada</translation>
+<translation id="3399952811970034796">Endereço de Entrega</translation>
<translation id="3422248202833853650">Tente sair de outros programas para liberar memória.</translation>
<translation id="3422472998109090673">No momento, não é possível acessar <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Permitir (padrão)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Relatório de erros registrado em <ph name="CRASH_TIME" />, enviado em <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informações do certificado</translation>
<translation id="3690164694835360974">Login não seguro</translation>
+<translation id="3704162925118123524">A rede que você está usando pode exigir que você visite a página de login.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Carregando...</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
<translation id="3714780639079136834">Ativar os dados da rede celular ou o Wi-Fi</translation>
+<translation id="3715597595485130451">Conectar-se ao Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuração de DNS, proxy e firewall<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Se você entende os riscos à sua segurança, pode <ph name="BEGIN_LINK" />acessar este site inseguro<ph name="END_LINK" /> antes de os programas perigosos serem removidos.</translation>
<translation id="3739623965217189342">Link que você copiou</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Desfazer adicionar</translation>
<translation id="404928562651467259">AVISO</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">A configuração do proxy definida utiliza um URL de script .pac, e não servidores proxy fixos.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">O número de série do dispositivo é inválido</translation>
<translation id="410351446219883937">Reprodução automática</translation>
<translation id="4103763322291513355">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista de URLs adicionados à lista negra e outras políticas aplicadas pelo administrador do seu sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Sempre permitir neste site</translation>
<translation id="4117700440116928470">O escopo da política não é suportado.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{mais 1}one{mais #}other{mais #}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Você tentou acessar <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo seu emissor. Isso significa que as credenciais de segurança que o servidor apresentou não são nem um pouco seguras. Talvez você esteja se comunicando com um invasor.</translation>
<translation id="4394049700291259645">Desativar</translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
+<translation id="4415426530740016218">Endereço de Retirada</translation>
<translation id="4424024547088906515">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança não é confiável para o Chrome. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="4432688616882109544">O certificado de login não foi aceito por <ph name="HOST_NAME" /> ou não foi fornecido.</translation>
<translation id="443673843213245140">O uso de um proxy está desativado, mas uma configuração explícita de proxy é especificada.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Tente desativar suas extensões.</translation>
<translation id="457875822857220463">Entrega</translation>
+<translation id="4582800630050655161">Você pode perder o acesso à sua Conta do Google ou ter sua identidade roubada. O Chromium recomenda a alteração da sua senha agora.</translation>
<translation id="4587425331216688090">Remover endereço do Chrome?</translation>
<translation id="4592951414987517459">Sua conexão com <ph name="DOMAIN" /> foi criptografada usando um pacote de criptografia moderno.</translation>
<translation id="4594403342090139922">&amp;Desfazer exclusão</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Suspender o uso de um certificado inválido</translation>
+<translation id="4690954380545377795">Você pode perder o acesso à sua Conta do Google ou ter sua identidade roubada. O Chrome recomenda a alteração da sua senha agora.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">A conexão foi interrompida</translation>
<translation id="471880041731876836">Você não tem permissão para visitar este site</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o Diagnóstico de Rede do Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Seu pagamento</translation>
<translation id="4726672564094551039">Atualizar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4736825316280949806">Reiniciar o Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Armazenamento de backup em estado inválido</translation>
<translation id="5023310440958281426">Verifique as políticas do administrador</translation>
<translation id="5029568752722684782">Limpar cópia</translation>
+<translation id="503069730517007720">Um certificado raiz para "<ph name="SOFTWARE_NAME" />" é necessário, mas não está instalado. O administrador de TI deve revisar as instruções de configuração do "<ph name="SOFTWARE_NAME" />" para corrigir esse problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Sobre o Google Tradutor</translation>
<translation id="5039804452771397117">Permitir</translation>
<translation id="5040262127954254034">Privacidade</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5205222826937269299">Nome obrigatório</translation>
<translation id="5222812217790122047">E-mail obrigatório</translation>
+<translation id="522700295135997067">Este site pode ter acabado de roubar sua senha</translation>
+<translation id="5230733896359313003">Endereço para envio</translation>
<translation id="5251803541071282808">Nuvem</translation>
<translation id="5277279256032773186">Você usa o Chrome no trabalho? As empresas podem gerenciar as configurações do Chrome para seus funcionários. Saiba mais</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Siga estas etapas para desativar temporariamente o software e entrar na Web. Para isso, você precisará de privilégios de administrador.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Sua conexão com este site não é particular. Para sair do modo de RV a qualquer momento, remova o fone de ouvido e pressione "Voltar".</translation>
<translation id="5299298092464848405">Política de análise de erros</translation>
+<translation id="5308380583665731573">Conectar-se</translation>
<translation id="5308689395849655368">O relatório de erros está desativado.</translation>
<translation id="5317780077021120954">Salvar</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5332219387342487447">Forma de envio</translation>
<translation id="5355557959165512791">Não é possível acessar <ph name="SITE" /> neste momento, porque o certificado dele foi revogado. Como os ataques e erros de rede são geralmente temporários, esta página provavelmente funcionará mais tarde.</translation>
<translation id="536296301121032821">Falha ao armazenar as configurações da política</translation>
<translation id="5386426401304769735">A cadeia de certificados desse site contém um certificado assinado usando SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Esse site na intranet da empresa, organização ou escola tem o mesmo URL de um website externo.
<ph name="LINE_BREAK" />
Tente entrar em contato com o administrador do sistema.</translation>
+<translation id="5499929369096410817">Insira o código de segurança do <ph name="CREDIT_CARD" />. Este código não será salvo.</translation>
<translation id="5509780412636533143">Favoritos gerenciados</translation>
<translation id="5510766032865166053">Talvez tenha sido movido ou excluído.</translation>
<translation id="5523118979700054094">Nome da política</translation>
<translation id="552553974213252141">O texto foi extraído corretamente?</translation>
<translation id="5540224163453853">Não foi possível encontrar o artigo solicitado.</translation>
+<translation id="5541546772353173584">Adicione um E-mail</translation>
<translation id="5544037170328430102">Uma página incorporada em <ph name="SITE" /> diz:</translation>
+<translation id="5545756402275714221">Artigos para você</translation>
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5560088892362098740">Data de validade</translation>
<translation id="5565735124758917034">Ativo</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Receber conteúdo personalizado</translation>
<translation id="5675650730144413517">Esta página não está funcionando</translation>
+<translation id="5689199277474810259">Exportar para JSON</translation>
<translation id="5710435578057952990">A identidade deste site não foi confirmada.</translation>
<translation id="5719499550583120431">Cartões pré-pagos são aceitos.</translation>
<translation id="5720705177508910913">Usuário atual</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Sua conexão com <ph name="DOMAIN" /> está criptografada com um pacote de criptografia obsoleto.</translation>
<translation id="5813119285467412249">&amp;Refazer adicionar</translation>
<translation id="5838278095973806738">Você não deve fornecer nenhuma informação confidencial nesse site (por exemplo, senhas ou cartões de crédito), porque elas podem ser roubadas por invasores.</translation>
+<translation id="5866257070973731571">Adicione um Número de Telefone</translation>
<translation id="5869405914158311789">Não é possível acessar esse site</translation>
<translation id="5869522115854928033">Senhas salvas</translation>
<translation id="5872918882028971132">Sugestões para pais</translation>
<translation id="5893752035575986141">Cartões de crédito são aceitos.</translation>
-<translation id="5901630391730855834">Amarelo</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 em uso}one{# em uso}other{# em uso}}</translation>
<translation id="5959728338436674663">Enviar automaticamente <ph name="BEGIN_WHITEPAPER_LINK" />algumas informações do sistema e conteúdos de página<ph name="END_WHITEPAPER_LINK" /> ao Google para ajudar a detectar sites e apps perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Edite as Informações de Contato</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
<translation id="5975083100439434680">Diminuir zoom</translation>
+<translation id="597552863672748783">Confirme o código de segurança</translation>
<translation id="598637245381783098">Não foi possível abrir app de pagamento</translation>
<translation id="5989320800837274978">Nem os servidores proxy fixos nem o URL de script .pac foram especificados.</translation>
<translation id="5990559369517809815">Solicitações ao servidor foram bloqueadas por uma extensão.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}one{Página #}other{Página #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Invasores em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem instalar apps enganosos que fingem ser outra pessoa ou coletam dados que podem ser usados para rastrear você. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizados)</translation>
<translation id="6027201098523975773">Insira um nome</translation>
<translation id="6040143037577758943">Fechar</translation>
-<translation id="6042308850641462728">Mais</translation>
<translation id="6047233362582046994">Se você conhece os riscos para sua segurança, pode <ph name="BEGIN_LINK" />visitar este site<ph name="END_LINK" /> antes de os apps prejudiciais serem removidos.</translation>
<translation id="6047927260846328439">Este conteúdo pode tentar enganar você para que instale um software ou revele informações pessoais. <ph name="BEGIN_LINK" />Mostrar mesmo assim<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Não é possível acessar <ph name="SITE" /> no momento, porque o site usa bloqueio de certificados. Como os ataques e erros de rede são geralmente temporários, esta pagina provavelmente funcionará mais tarde.</translation>
@@ -657,7 +683,7 @@
<translation id="6264485186158353794">Voltar à segurança</translation>
<translation id="6276112860590028508">As páginas da sua lista de leitura são exibidas aqui</translation>
<translation id="6280223929691119688">Não é possível entregar nesse endereço. Selecione um endereço diferente.</translation>
-<translation id="6282194474023008486">Código postal</translation>
+<translation id="6282194474023008486">CEP</translation>
<translation id="6290238015253830360">Os artigos sugeridos aparecerão aqui</translation>
<translation id="6305205051461490394">Não é possível acessar <ph name="URL" />.</translation>
<translation id="6319915415804115995">Usado pela última vez há mais de um ano</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Você está vendo uma página de extensões</translation>
<translation id="6596325263575161958">Opções de criptografia</translation>
<translation id="662080504995468778">Ficar</translation>
+<translation id="6624427990725312378">Informações de Contato</translation>
<translation id="6626291197371920147">Adicionar número de cartão de crédito válido</translation>
<translation id="6628463337424475685">Pesquisa do <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Invasores presentes no momento em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar programas perigosos no seu Mac e roubar ou excluir suas informações (por exemplo, fotos, senhas, mensagens e cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Digitar termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">Há algo errado com o servidor proxy, ou o endereço está incorreto.</translation>
-<translation id="6727102863431372879">Definir</translation>
<translation id="674375294223700098">Erro, certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da política</translation>
<translation id="6757797048963528358">O dispositivo entrou em modo de suspensão.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Caminho de perfil</translation>
<translation id="7424977062513257142">Uma página incorporada nessa página da Web diz:</translation>
+<translation id="7437289804838430631">Adicionar Informações de Contato</translation>
<translation id="7441627299479586546">Assunto da política incorreto</translation>
<translation id="7444046173054089907">Este site está bloqueado</translation>
<translation id="7445762425076701745">A identidade do servidor ao qual você está conectado não pode ser validada completamente. Você está conectado ao servidor com um nome válido somente na sua rede e que, portanto, uma autoridade de certificação externa não consegue validar a propriedade. Como algumas autoridades de certificação emitem certificados para esses nomes mesmo assim, não é possível garantir que você esteja conectado ao site que gostaria e não a um invasor.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">Nenhum dado encontrado</translation>
<translation id="7508255263130623398">O código do dispositivo da política retornado está em branco ou não corresponde ao código do dispositivo atual</translation>
+<translation id="7511955381719512146">O Wi-Fi que você está usando pode exigir a visita a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Fazer o download</translation>
<translation id="7518003948725431193">Nenhuma página da web foi encontrada para o endereço da Web:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Sua conexão a este site não é particular</translation>
-<translation id="7535087603100972091">Valor</translation>
<translation id="7537536606612762813">Obrigatória</translation>
<translation id="7542403920425041731">Depois da confirmação, os detalhes do cartão serão compartilhados com esse site.</translation>
<translation id="7542995811387359312">O preenchimento automático do cartão de crédito está desativado porque este formulário não usa uma conexão segura.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança pode ter sido emitido de forma fraudulenta. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="7568593326407688803">Esta página está em<ph name="ORIGINAL_LANGUAGE" />Deseja traduzi-la?</translation>
<translation id="7569952961197462199">Remover cartão de crédito do Chrome?</translation>
-<translation id="7569983096843329377">Preto</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicativos em vários dispositivos usando os cards que você salvou com o Google.</translation>
<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Invasores nesse site podem tentar enganar você para que instale programas que prejudicam sua experiência de navegação (por exemplo, alterando sua página inicial ou mostrando mais anúncios nos sites que você visita).</translation>
<translation id="7674629440242451245">Interessado em novos recursos interessantes do Google Chrome? Veja nosso Canal Dev em chrome.com/dev.</translation>
<translation id="7682287625158474539">Entrega</translation>
+<translation id="7699293099605015246">Os artigos não estão disponíveis no momento</translation>
<translation id="7701040980221191251">Nenhum</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Ir para <ph name="SITE" /> (não seguro)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificado</translation>
<translation id="7716147886133743102">Bloqueada pelo administrador</translation>
<translation id="7716424297397655342">Não é possível carregar este site a partir do cache</translation>
+<translation id="7723047071702270851">Edite o Cartão</translation>
<translation id="774634243536837715">Conteúdo perigoso bloqueado.</translation>
<translation id="7752995774971033316">Não gerenciado</translation>
<translation id="7755287808199759310">Seu responsável pode desbloqueá-lo para você</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Adicionar endereço</translation>
<translation id="777702478322588152">Prefeitura</translation>
<translation id="7791543448312431591">Adicionar</translation>
+<translation id="7793553086574152071">Para agilizar o pagamento na próxima vez, salve este cartão na sua Conta do Google.</translation>
<translation id="7793809570500803535">A página da web em <ph name="SITE" /> pode estar temporariamente indisponível ou pode ter sido movida permanentemente para um novo endereço da Web.</translation>
<translation id="7800304661137206267">A conexão foi criptografada utilizando <ph name="CIPHER" />, com <ph name="MAC" /> para mensagem de autenticação e <ph name="KX" /> como o mecanismo de troca de chaves.</translation>
+<translation id="7802523362929240268">O site é legítimo</translation>
<translation id="780301667611848630">Não</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Remover sugestão de formulário do Chrome?</translation>
<translation id="7815407501681723534">Localizados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">O Wi-Fi que você está usando (<ph name="WIFI_NAME" />) pode exigir a visita a uma página de login.</translation>
<translation id="785549533363645510">O modo invisível NÃO oculta seus dados de navegação. Seu empregador, seu provedor de Internet e os websites visitados continuam tendo acesso a essas informações.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Cartões de débito e pré-pagos são aceitos.</translation>
+<translation id="7878562273885520351">Sua senha pode estar comprometida</translation>
<translation id="7887683347370398519">Verifique seu CVC e tente novamente</translation>
<translation id="79338296614623784">Informe um número de telefone válido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">O certificado do servidor ainda não é válido.</translation>
-<translation id="7942349550061667556">Vermelho</translation>
<translation id="7947285636476623132">Verifique o ano de validade e tente novamente</translation>
<translation id="7951415247503192394">32 bits</translation>
<translation id="7956713633345437162">Favoritos de dispositivos móveis</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Perguntar (padrão)</translation>
<translation id="8041089156583427627">Enviar comentários</translation>
<translation id="8041940743680923270">Usar padrão global (Perguntar)</translation>
+<translation id="8057711352706143257">O software "<ph name="SOFTWARE_NAME" />" não foi configurado corretamente. A desinstalação do "<ph name="SOFTWARE_NAME" />" costuma resolver o problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Falha ao exibir artigo.</translation>
<translation id="8091372947890762290">A ativação está pendente no servidor</translation>
+<translation id="8094917007353911263">A rede que você está usando pode exigir uma visita a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Forma de Pagamento</translation>
<translation id="8118489163946903409">Método de pagamento</translation>
+<translation id="8127301229239896662">O software "<ph name="SOFTWARE_NAME" />" não foi instalado corretamente no computador ou na rede. Peça ao administrador de TI para resolver o problema.</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">Não foi possível encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Seu computador entrou em modo de suspensão.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Entre em contato com seu administrador de rede se não souber o que isso significa.</translation>
<translation id="8293206222192510085">Adicionar favorito</translation>
<translation id="8294431847097064396">Origem</translation>
+<translation id="8298115750975731693">O Wi-Fi que você está usando (<ph name="WIFI_NAME" />) pode exigir a visita a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Não é possível estabelecer uma conexão particular com <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e hora do dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">A tradução falhou devido a um problema com a conexão de rede.</translation>
<translation id="8332188693563227489">O acesso a <ph name="HOST_NAME" /> foi negado</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Recentemente fechadas</translation>
<translation id="8874824191258364635">Informe um número de cartão válido</translation>
<translation id="8876793034577346603">Falha ao analisar a configuração de rede.</translation>
-<translation id="8889402386540077796">Matiz</translation>
<translation id="8891727572606052622">Modo de proxy inválido.</translation>
<translation id="889901481107108152">Esta experiência não está disponível na sua plataforma.</translation>
<translation id="8903921497873541725">Aumentar zoom</translation>
<translation id="8931333241327730545">Deseja salvar este cartão na sua Conta do Google?</translation>
<translation id="8932102934695377596">Seu relógio está atrasado</translation>
+<translation id="893332455753468063">Adicione um Nome</translation>
<translation id="8938939909778640821">Cartões de crédito e pré-pagos aceitos</translation>
+<translation id="8957210676456822347">Autorização de portal cativo</translation>
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
-<translation id="8986494364107987395">Enviar estatísticas de uso e relatórios de erros ao Google automaticamente</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">O site a seguir contém programas prejudiciais</translation>
<translation id="8997023839087525404">O servidor apresentou um certificado que não foi divulgado publicamente usando a política de Transparência dos certificados. Esse é um requisito para alguns certificados, a fim de garantir que eles sejam confiáveis e protejam você contra invasores.</translation>
<translation id="9001074447101275817">O proxy <ph name="DOMAIN" /> exige um nome de usuário e uma senha.</translation>
<translation id="9005998258318286617">Falha ao carregar documento PDF.</translation>
+<translation id="9008201768610948239">Ignorar</translation>
<translation id="901974403500617787">Sinalizações aplicáveis a todo o sistema podem ser definidas apenas pelo proprietário: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">O endereço de cobrança do cartão é obrigatório</translation>
<translation id="9020542370529661692">Esta página foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,12 +1001,15 @@
<translation id="9049981332609050619">Você tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado inválido.</translation>
<translation id="9050666287014529139">Senha</translation>
<translation id="9065203028668620118">Editar</translation>
-<translation id="9068849894565669697">Selecionar cor</translation>
<translation id="9069693763241529744">Bloqueada por uma extensão</translation>
<translation id="9076283476770535406">Pode apresentar conteúdo adulto</translation>
<translation id="9078964945751709336">São necessárias mais informações</translation>
+<translation id="9080712759204168376">Resumo do pedido</translation>
<translation id="9103872766612412690">O site <ph name="SITE" /> geralmente usa criptografia para proteger suas informações. Quando o Chromium tentou se conectar a <ph name="SITE" /> dessa vez, o website retornou credenciais
incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser <ph name="SITE" /> ou quando uma tela de login por Wi-Fi interrompeu a conexão. Suas informações ainda estão protegidas, porque o Chromium interrompeu a conexão antes que os dados fossem trocados.</translation>
+<translation id="9106062320799175032">Adicione um Endereço de Faturamento</translation>
+<translation id="910908805481542201">Ajude-me a corrigir isso</translation>
+<translation id="9128870381267983090">Conectar-se à rede</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Inicie e faça login no Chrome antes de usar este app.</translation>
<translation id="9148507642005240123">&amp;Desfazer editar</translation>
@@ -981,6 +1021,7 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="9183425211371246419"><ph name="HOST_NAME" /> usa um protocolo incompatível.</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="9215416866750762878">Um aplicativo está impedindo que o Chrome se conecte com segurança a este site</translation>
<translation id="9219103736887031265">Imagens</translation>
<translation id="933612690413056017">Não há conexão com a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -990,5 +1031,11 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="975560348586398090">{COUNT,plural, =0{Nenhum}=1{1 item}one{# item}other{# itens}}</translation>
<translation id="981121421437150478">Off-line</translation>
<translation id="988159990683914416">Versão do desenvolvedor</translation>
+<translation id="989988560359834682">Editar endereço</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">O software "<ph name="SOFTWARE_NAME" />" não foi instalado corretamente no computador ou na rede:
+ &lt;ul&gt;
+ &lt;li&gt;Tente desinstalar ou desativar o "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Tente conectar-se a outra rede&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index 6ac1725cf40..f987bc8422e 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Marcadores do Ambiente de Trabalho</translation>
<translation id="1074497978438210769">Inseguro</translation>
<translation id="1080116354587839789">Ajustar à largura</translation>
+<translation id="1088860948719068836">Adicionar nome no cartão</translation>
<translation id="1103523840287552314">Traduzir sempre <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Mostrar todas as palavras-passe guardadas…</translation>
<translation id="1107591249535594099">Se marcada, o Chrome armazena uma cópia do seu cartão neste dispositivo para preencher formulários mais rapidamente.</translation>
<translation id="1111153019813902504">Marcadores recentes</translation>
<translation id="1113869188872983271">&amp;Anular reordenação</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizados)</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de falhas capturado <ph name="CRASH_TIME" /> (ainda não carregado ou ignorado)</translation>
+<translation id="1270502636509132238">Método de recolha</translation>
<translation id="1281526147609854549">Emitido por <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
<translation id="129553762522093515">Fechados recentemente</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">A aguardar ligação…</translation>
<translation id="153384715582417236">É tudo por agora</translation>
<translation id="1549470594296187301">É necessário ativar o JavaScript para utilizar esta funcionalidade.</translation>
-<translation id="1555130319947370107">Azul</translation>
<translation id="1559528461873125649">Esse ficheiro ou diretório não existe</translation>
<translation id="1583429793053364125">Ocorreu um erro ao apresentar esta página Web.</translation>
<translation id="1592005682883173041">Acesso aos dados locais</translation>
<translation id="1594030484168838125">Escolher</translation>
-<translation id="161042844686301425">Turquesa</translation>
<translation id="1620510694547887537">Câmara</translation>
<translation id="1629803312968146339">Pretende que o Chrome guarde este cartão?</translation>
<translation id="1639239467298939599">A carregar</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">SO</translation>
<translation id="1721312023322545264">Precisa da autorização de <ph name="NAME" /> para visitar este site</translation>
<translation id="1721424275792716183">* Campo de preenchimento obrigatório</translation>
+<translation id="1727741090716970331">Adicionar número de cartão válido</translation>
<translation id="1728677426644403582">Está a ver a fonte de uma página Web</translation>
<translation id="173080396488393970">Este tipo de cartão não é suportado</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Erro de serialização</translation>
<translation id="1974060860693918893">Avançadas</translation>
<translation id="1978555033938440688">Versão do firmware</translation>
-<translation id="1995859865337580572">Valide o seu CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}one{and # more}other{e mais #}}</translation>
<translation id="2025186561304664664">O proxy está definido para configuração automática.</translation>
<translation id="2030481566774242610">Será que quis dizer <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Para obter conteúdo personalizado sugerido pelo Google, inicie sessão no Chrome.</translation>
+<translation id="2091887806945687916">Som</translation>
<translation id="2094505752054353250">Falta de correspondência de domínio</translation>
<translation id="2096368010154057602">Departamento</translation>
<translation id="2108755909498034140">Reiniciar o computador</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorada porque foi substituída por <ph name="POLICY_NAME" /> .</translation>
<translation id="2138201775715568214">A procurar páginas da Web física próximas</translation>
<translation id="213826338245044447">Marcadores de Telemóvel</translation>
+<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
+<translation id="2148613324460538318">Adicionar cartão</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="2166049586286450108">Acesso de administrador total</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# addresses}other{# endereços}}</translation>
<translation id="2187317261103489799">Detetar (predefinição)</translation>
<translation id="2202020181578195191">Introduza um ano de expiração válido</translation>
+<translation id="2209523182407020534">As aplicações que podem causar este erro incluem antivírus, firewalls e software de filtragem Web ou proxy.</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">A obter entradas...</translation>
<translation id="2218879909401188352">Os utilizadores mal-intencionados que se encontram em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem instalar aplicações perigosas que danificam o dispositivo, adicionam cobranças ocultas à fatura de dados móveis ou roubam as suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Retroceder</translation>
<translation id="2503184589641749290">Cartões de débito e pré-pagos admitidos</translation>
<translation id="2515629240566999685">Verificar o sinal na área</translation>
+<translation id="2524461107774643265">Adicionar mais informações</translation>
+<translation id="2536110899380797252">Adicionar endereço</translation>
<translation id="2539524384386349900">Detetar</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> enviou uma resposta inválida.</translation>
<translation id="2556876185419854533">&amp;Anular edição</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">O Chromium não conseguiu confirmar o seu cartão neste momento. Tente novamente mais tarde.</translation>
<translation id="2705137772291741111">A cópia guardada (em cache) deste site era ilegível.</translation>
<translation id="2709516037105925701">Preenchimento automático</translation>
+<translation id="2710942282213947212">Existe software no computador que está a impedir que o Chromium se ligue à Web em segurança</translation>
<translation id="2712173769900027643">Pedir autorização</translation>
-<translation id="2713444072780614174">Branco</translation>
<translation id="2720342946869265578">Próximo</translation>
<translation id="2721148159707890343">Pedido com êxito</translation>
<translation id="2728127805433021124">O certificado do servidor foi assinado utilizando um algoritmo de assinatura fraco.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Foi detetada uma alteração de rede.</translation>
<translation id="2916038427272391327">Fechar outros programas</translation>
<translation id="2922350208395188000">Não é possível verificar o certificado do servidor.</translation>
+<translation id="2925673989565098301">Método de fornecimento</translation>
<translation id="2928905813689894207">Endereço de faturação</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o respetivo certificado de segurança é do domínio <ph name="DOMAIN2" />. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3032412215588512954">Pretende atualizar este site?</translation>
<translation id="3037605927509011580">Ah, bolas!!</translation>
+<translation id="3039538478787849737">Pretende guardar o cartão na Conta Google?</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">O Chrome não conseguiu confirmar o seu cartão neste momento. Tente novamente mais tarde.</translation>
<translation id="3064966200440839136">Está a sair do modo de navegação anónima para pagar através de uma aplicação externa. Pretende continuar?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Erro temporário do servidor</translation>
<translation id="3154506275960390542">Esta página inclui um formulário que pode não ser enviado em segurança. Os dados que enviar podem ser vistos por outros utilizadores em trânsito ou podem ser modificados por um utilizador mal intencionado para alterar o que é recebido pelo servidor.</translation>
<translation id="3157931365184549694">Restaurar</translation>
+<translation id="3162559335345991374">A rede Wi-Fi que está a utilizar pode exigir que visite a respetiva página de início de sessão.</translation>
<translation id="3167968892399408617">As páginas que visualizar em separadores de navegação anónima não são memorizadas no histórico do navegador, no armazenamento de cookies ou no histórico de pesquisas depois de fechar todos os separadores de navegação anónima. Todos os ficheiros transferidos ou os marcadores criados são guardados.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ilha</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Cancelar pagamento</translation>
<translation id="3207960819495026254">Adicionado aos marcadores</translation>
+<translation id="3211223744486044430">Para pagar mais rapidamente da próxima vez, guarde este cartão na sua Conta Google e neste dispositivo.</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>
<translation id="3226128629678568754">Prima o botão de atualização para enviar novamente os dados necessários para carregar a página.</translation>
<translation id="3227137524299004712">Microfone</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Não foram encontrados resultados da pesquisa</translation>
<translation id="3305707030755673451">Os dados foram encriptados com a sua frase de acesso de sincronização em <ph name="TIME" />. Introduza-a para iniciar a sincronização.</translation>
<translation id="3320021301628644560">Adicionar endereço de faturação</translation>
-<translation id="3329013043687509092">Saturação</translation>
<translation id="333371639341676808">Evitar que esta página crie caixas de diálogo adicionais.</translation>
<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">definições</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID do Cliente:</translation>
<translation id="3391030046425686457">Endereço de entrega</translation>
<translation id="3395827396354264108">Método de recolha</translation>
+<translation id="3399952811970034796">Endereço de entrega</translation>
<translation id="3422248202833853650">Experimente fechar outros programas para libertar memória.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> está inacessível de momento.</translation>
<translation id="3427092606871434483">Permitir (predefinição)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Relatório de falhas capturado no(a) <ph name="CRASH_TIME" /> e carregado no(a) <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informações do certificado</translation>
<translation id="3690164694835360974">Início de sessão não seguro</translation>
+<translation id="3704162925118123524">A rede que está a utilizar pode exigir que visite a respetivapágina de início de sessão.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">A carregar...</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
<translation id="3714780639079136834">Ativar os dados móveis ou o Wi-Fi</translation>
+<translation id="3715597595485130451">Estabelecer ligação a redes Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuração do proxy, da firewall e de DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Se compreende os riscos para a sua segurança, pode <ph name="BEGIN_LINK" />visitar este site não seguro<ph name="END_LINK" /> antes de os programas perigosos terem sido removidos.</translation>
<translation id="3739623965217189342">Link copiado por si</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Anular adição</translation>
<translation id="404928562651467259">AVISO</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">A configuração do proxy está definida para utilizar um URL de script .pac e não servidores proxy fixos.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Número de série do dispositivo é inválido</translation>
<translation id="410351446219883937">Reprodução automática</translation>
<translation id="4103763322291513355">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver os URLs que foram colocados na lista negra e outras políticas aplicadas pelo administrador do sistema.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Permitir sempre neste Website</translation>
<translation id="4117700440116928470">O âmbito da política não é suportado.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}one{# others}other{# outros}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Tentou aceder a <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo emissor. Isto significa que as credenciais de segurança apresentadas pelo servidor não deverão, em circunstância alguma, ser consideradas fidedignas. Pode estar a comunicar com um utilizador mal intencionado.</translation>
<translation id="4394049700291259645">Desactivar</translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
+<translation id="4415426530740016218">Endereço de recolha</translation>
<translation id="4424024547088906515">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o Chrome não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> não aceitou o seu certificado de início de sessão ou este pode não ter sido fornecido.</translation>
<translation id="443673843213245140">A utilização de um proxy está desativada, mas existe uma configuração de proxy explícita especificada.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Experimente desativar as extensões.</translation>
<translation id="457875822857220463">Entrega</translation>
+<translation id="4582800630050655161">Pode perder o acesso à sua Conta Google ou ser vítima de roubo de identidade. O Chromium recomenda a alteração da palavra-passe agora.</translation>
<translation id="4587425331216688090">Pretende remover o endereço do Chrome?</translation>
<translation id="4592951414987517459">A sua ligação a <ph name="DOMAIN" /> está encriptada através de um conjunto de cifras moderno.</translation>
<translation id="4594403342090139922">&amp;Anular eliminação</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Parar de utilizar um certificado inválido</translation>
+<translation id="4690954380545377795">Pode perder o acesso à sua Conta Google ou ser vítima de roubo de identidade. O Chrome recomenda a alteração da palavra-passe agora.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">A ligação foi interrompida</translation>
<translation id="471880041731876836">Não tem autorização para aceder a este site</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o Diagnóstico de rede do Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">O seu pagamento</translation>
<translation id="4726672564094551039">Recarregar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4736825316280949806">Reiniciar o Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Armazenamento de segurança em mau estado</translation>
<translation id="5023310440958281426">Verificar as políticas do administrador</translation>
<translation id="5029568752722684782">Limpar cópia</translation>
+<translation id="503069730517007720">É necessário um certificado de raiz para o "<ph name="SOFTWARE_NAME" />", que não está instalado. O administrador de TI deve consultar as instruções de configuração do "<ph name="SOFTWARE_NAME" />" para corrigir este problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Acerca do Google Tradutor</translation>
<translation id="5039804452771397117">Permitir</translation>
<translation id="5040262127954254034">Privacidade</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experiências</translation>
<translation id="5205222826937269299">Nome obrigatório</translation>
<translation id="5222812217790122047">Email obrigatório</translation>
+<translation id="522700295135997067">Este site pode ter roubado a sua palavra-passe</translation>
+<translation id="5230733896359313003">Endereço de envio</translation>
<translation id="5251803541071282808">Nuvem</translation>
<translation id="5277279256032773186">Utiliza o Chrome no trabalho? As empresas podem gerir as definições do Chrome para os seus funcionários. Saiba mais</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Siga estes passos para desativar temporariamente o software para que possa aceder à Web. Precisa de privilégios de administrador.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">A sua ligação a este site não é privada. Para sair do modo de RV a qualquer momento, remova os auscultadores com microfone integrado e prima Anterior.</translation>
<translation id="5299298092464848405">Erro ao analisar a política</translation>
+<translation id="5308380583665731573">Ligar</translation>
<translation id="5308689395849655368">O relatório de falha está desativado.</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5332219387342487447">Método de envio</translation>
<translation id="5355557959165512791">Não pode visitar <ph name="SITE" /> neste momento, porque o certificado foi revogado. Os erros de rede e os ataques são geralmente temporários, pelo que esta página deverá funcionar mais tarde.</translation>
<translation id="536296301121032821">Falha ao armazenar as definições da política</translation>
<translation id="5386426401304769735">A cadeia de certificados inclui um certificado assinado através de SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Este site na intranet da empresa, da entidade ou da escola tem o mesmo URL que um Website externo.
<ph name="LINE_BREAK" />
Experimente contactar o administrador do sistema.</translation>
+<translation id="5499929369096410817">Introduza o código de segurança para o <ph name="CREDIT_CARD" />. Este código não é guardado.</translation>
<translation id="5509780412636533143">Marcadores geridos</translation>
<translation id="5510766032865166053">Pode ter sido movido ou eliminado.</translation>
<translation id="5523118979700054094">Nome da política</translation>
<translation id="552553974213252141">O texto foi extraído corretamente?</translation>
<translation id="5540224163453853">Não foi possível encontrar o artigo solicitado.</translation>
+<translation id="5541546772353173584">Adicionar email</translation>
<translation id="5544037170328430102">Uma página incorporada em <ph name="SITE" /> diz:</translation>
+<translation id="5545756402275714221">Artigos para si</translation>
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5560088892362098740">Data de validade</translation>
<translation id="5565735124758917034">Ativo</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Obter conteúdo personalizado</translation>
<translation id="5675650730144413517">Esta página não está a funcionar</translation>
+<translation id="5689199277474810259">Exportar para JSON</translation>
<translation id="5710435578057952990">A identidade deste Web site não foi verificada.</translation>
<translation id="5719499550583120431">Os cartões pré-pagos são admitidos.</translation>
<translation id="5720705177508910913">Utilizador atual</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">A sua ligação a <ph name="DOMAIN" /> está encriptada através de um conjunto de cifras obsoleto.</translation>
<translation id="5813119285467412249">&amp;Refazer adição</translation>
<translation id="5838278095973806738">Não deve introduzir informações confidenciais neste site (por exemplo, palavras-passe ou números de cartões de crédito), porque podem ser roubadas por atacantes.</translation>
+<translation id="5866257070973731571">Adicionar número de telefone</translation>
<translation id="5869405914158311789">Não é possível aceder a este site</translation>
<translation id="5869522115854928033">Palavras-passe guardadas</translation>
<translation id="5872918882028971132">Sugestões superiores</translation>
<translation id="5893752035575986141">Os cartões de crédito são admitidos.</translation>
-<translation id="5901630391730855834">Amarelo</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizados)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 em utilização}one{# in use}other{# em utilização}}</translation>
<translation id="5959728338436674663">Enviar automaticamente algumas <ph name="BEGIN_WHITEPAPER_LINK" />informações do sistema e conteúdos de páginas<ph name="END_WHITEPAPER_LINK" /> para a Google de modo a ajudar a detetar aplicações e sites perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Editar informações de contacto</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
<translation id="5975083100439434680">Reduzir</translation>
+<translation id="597552863672748783">Confirmar o código de segurança</translation>
<translation id="598637245381783098">Não é possível abrir a aplicação de pagamento</translation>
<translation id="5989320800837274978">Não foram especificados servidores proxy fixos nem um URL de script .pac.</translation>
<translation id="5990559369517809815">Os pedidos para o servidor foram bloqueados por uma extensão.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Página 1}one{Page #}other{Página #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Os utilizadores mal-intencionados em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem instalar aplicações fraudulentas que se fazem passar por algo diferente ou recolhem dados que podem ser utilizados para o monitorizar. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizados)</translation>
<translation id="6027201098523975773">Introduza um nome</translation>
<translation id="6040143037577758943">Fechar</translation>
-<translation id="6042308850641462728">Mais</translation>
<translation id="6047233362582046994">Se compreende os riscos para a sua segurança, pode <ph name="BEGIN_LINK" />visitar este site<ph name="END_LINK" /> antes de as aplicações prejudiciais terem sido removidas.</translation>
<translation id="6047927260846328439">Este conteúdo pode tentar enganá-lo de forma a que instale software ou revele informações pessoais. <ph name="BEGIN_LINK" />Mostrar mesmo assim<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Não pode visitar <ph name="SITE" /> neste momento, porque o Website utiliza a afixação de certificados. Os erros de rede e os ataques são geralmente temporários, pelo que esta página deverá funcionar mais tarde.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Está a ver a página de uma extensão</translation>
<translation id="6596325263575161958">Opções de encriptação</translation>
<translation id="662080504995468778">Ficar</translation>
+<translation id="6624427990725312378">Informações de contacto</translation>
<translation id="6626291197371920147">Adicionar número de cartão válido</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Pesquisar</translation>
<translation id="6630809736994426279">Os atacantes atualmente em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar programas perigosos no seu Mac que roubam ou eliminam as suas informações (por exemplo, fotos, palavras-passe, mensagens e cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Introduzir termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">Existe um problema com o servidor proxy ou o endereço está incorreto.</translation>
-<translation id="6727102863431372879">Definir</translation>
<translation id="674375294223700098">Erro de certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da política</translation>
<translation id="6757797048963528358">O dispositivo entrou em suspensão.</translation>
@@ -724,7 +750,7 @@
<translation id="6895330447102777224">O seu cartão foi confirmado</translation>
<translation id="6897140037006041989">Agente do utilizador</translation>
<translation id="6915804003454593391">Utilizador:</translation>
-<translation id="6945221475159498467">Seleccionar</translation>
+<translation id="6945221475159498467">Selecionar</translation>
<translation id="6948701128805548767">Para ver os métodos de recolha e os requisitos, selecione um endereço</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser uma falsificação.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -738,7 +764,7 @@
<translation id="7050187094878475250">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo período de validade é demasiado longo para ser fidedigno.</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7064851114919012435">Informações de contacto</translation>
-<translation id="7079718277001814089">Este site contém um programa malicioso</translation>
+<translation id="7079718277001814089">Este site contém um software malicioso</translation>
<translation id="7087282848513945231">Condado</translation>
<translation id="7090678807593890770">Pesquisar <ph name="LINK" /> no Google</translation>
<translation id="7108819624672055576">Permitida por uma extensão</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Caminho do Perfil</translation>
<translation id="7424977062513257142">Uma página incorporada nesta página Web diz:</translation>
+<translation id="7437289804838430631">Adicionar informações de contacto</translation>
<translation id="7441627299479586546">Assunto da política incorreto</translation>
<translation id="7444046173054089907">Este site está bloqueado</translation>
<translation id="7445762425076701745">Não é possível validar totalmente a identidade do servidor ao qual está ligado. Está ligado a um servidor com um nome que apenas é válido na sua rede, que não permite que uma autoridade de certificação externa valide a respectiva propriedade. Ainda assim, algumas autoridades emitem certificados para esses nomes, pelo que não há forma de garantir que está ligado ao Web site que pretende e não a um site pirata.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">Não foram encontrados dados.</translation>
<translation id="7508255263130623398">O ID do dispositivo da política devolvido está vazio ou não corresponde ao ID do dispositivo atual</translation>
+<translation id="7511955381719512146">A rede Wi-Fi que está a utilizar pode exigir que visite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Transferir</translation>
<translation id="7518003948725431193">Não foi encontrada qualquer página Web para o endereço Web: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">A sua ligação a este site não é privada.</translation>
-<translation id="7535087603100972091">Valor</translation>
<translation id="7537536606612762813">Obrigatório</translation>
<translation id="7542403920425041731">Ao confirmar, os detalhes do cartão são partilhados com este site.</translation>
<translation id="7542995811387359312">O preenchimento automático de cartões de crédito está desactivado, porque este formulário não utiliza uma ligação segura.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o respetivo certificado de segurança poderá ter sido emitido de forma fraudulenta. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="7568593326407688803">Esta página está em<ph name="ORIGINAL_LANGUAGE" />Pretende traduzi-la?</translation>
<translation id="7569952961197462199">Pretende remover o cartão de crédito do Chrome?</translation>
-<translation id="7569983096843329377">Preto</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicações em todos os dispositivos com cartões que tenha guardado com o Google.</translation>
<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Os utilizadores mal intencionados neste site podem tentar enganá-lo para instalar programas que são prejudiciais para a sua experiência de navegação (por exemplo, ao alterar a sua página inicial ou ao mostrar anúncios adicionais em sites que visita).</translation>
<translation id="7674629440242451245">Está interessado nas novas e fantásticas funcionalidades do Chrome? Experimente o nosso canal para programadores em chrome.com/dev.</translation>
<translation id="7682287625158474539">Envio</translation>
+<translation id="7699293099605015246">De momento, não estão disponíveis artigos</translation>
<translation id="7701040980221191251">Nenhum</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Prosseguir para <ph name="SITE" /> (não seguro)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificado</translation>
<translation id="7716147886133743102">Bloqueada pelo administrador</translation>
<translation id="7716424297397655342">Não é possível carregar este site a partir da cache</translation>
+<translation id="7723047071702270851">Editar cartão</translation>
<translation id="774634243536837715">Conteúdo perigoso bloqueado.</translation>
<translation id="7752995774971033316">Não gerido</translation>
<translation id="7755287808199759310">O teu pai/a tua mãe pode desbloquear-te</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Adicionar endereço</translation>
<translation id="777702478322588152">Prefeitura</translation>
<translation id="7791543448312431591">Adicionar</translation>
+<translation id="7793553086574152071">Para pagar mais rapidamente da próxima vez, guarde este cartão na sua Conta Google.</translation>
<translation id="7793809570500803535">A página Web de <ph name="SITE" /> poderá estar temporariamente inativa ou poderá ter sido movida permanentemente para um novo endereço Web.</translation>
<translation id="7800304661137206267">A ligação é encriptada utilizando <ph name="CIPHER" />, com <ph name="MAC" /> para autenticação de mensagens e <ph name="KX" /> como mecanismo de troca de chaves.</translation>
+<translation id="7802523362929240268">O site é legítimo</translation>
<translation id="780301667611848630">Não, obrigado</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Pretende remover a sugestão do formulário do Chrome?</translation>
<translation id="7815407501681723534">Encontrados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">A rede Wi-Fi que está a utilizar (<ph name="WIFI_NAME" />) pode exigir que visite a respetiva página de início de sessão.</translation>
<translation id="785549533363645510">No entanto, a navegação não é invisível. Passar para o modo de navegação anónima não oculta a navegação do empregador ou do fornecedor de serviços de Internet, nem dos Sites que visitar.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Os cartões de débito e pré-pagos são admitidos.</translation>
+<translation id="7878562273885520351">A palavra-passe pode estar comprometida</translation>
<translation id="7887683347370398519">Verifique o Código de Segurança/CVC e tente novamente</translation>
<translation id="79338296614623784">Introduza um número de telefone válido</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">O certificado do servidor ainda não é válido.</translation>
-<translation id="7942349550061667556">Vermelho</translation>
<translation id="7947285636476623132">Verifique o ano de validade e tente novamente</translation>
<translation id="7951415247503192394">32 bits</translation>
<translation id="7956713633345437162">Marcadores do telemóvel</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Pedir (predefinição)</translation>
<translation id="8041089156583427627">Enviar comentários</translation>
<translation id="8041940743680923270">Utilizar predefinição global (Perguntar)</translation>
+<translation id="8057711352706143257">O "<ph name="SOFTWARE_NAME" />" não está configurado corretamente. Normalmente, a desinstalação do "<ph name="SOFTWARE_NAME" />" resolve o problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Falha ao ver o artigo.</translation>
<translation id="8091372947890762290">Ativação pendente no servidor</translation>
+<translation id="8094917007353911263">A rede que está a utilizar pode exigir que visite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Método de pagamento</translation>
<translation id="8118489163946903409">Método de pagamento</translation>
+<translation id="8127301229239896662">O "<ph name="SOFTWARE_NAME" />" não foi instalado corretamente no computador ou na rede. Peça ao administrador de TI que resolva este problema.</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">Não foi possível encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">O computador entrou em suspensão.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Se não tiver a certeza do que isto significa, contacte o administrador de rede.</translation>
<translation id="8293206222192510085">Adicionar marcador</translation>
<translation id="8294431847097064396">Origem</translation>
+<translation id="8298115750975731693">A rede Wi-Fi que está a utilizar (<ph name="WIFI_NAME" />) pode exigir que visite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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 erradas. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">A tradução falhou devido a um problema com a ligação de rede.</translation>
<translation id="8332188693563227489">O acesso a <ph name="HOST_NAME" /> foi recusado</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Fechadas recentemente</translation>
<translation id="8874824191258364635">Introduza um número de cartão válido</translation>
<translation id="8876793034577346603">Falha ao analisar a configuração de rede.</translation>
-<translation id="8889402386540077796">Tonalidade</translation>
<translation id="8891727572606052622">Modo de proxy inválido.</translation>
<translation id="889901481107108152">Infelizmente, esta experiência não está disponível na sua plataforma.</translation>
<translation id="8903921497873541725">Ampliar</translation>
<translation id="8931333241327730545">Pretende guardar este cartão na sua Conta Google?</translation>
<translation id="8932102934695377596">O seu relógio está atrasado</translation>
+<translation id="893332455753468063">Adicionar nome</translation>
<translation id="8938939909778640821">Cartões de crédito e pré-pagos admitidos</translation>
+<translation id="8957210676456822347">Autorização de portal cativo</translation>
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
-<translation id="8986494364107987395">Enviar automaticamente estatísticas de utilização e relatórios de falhas para a Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">O site que se segue contém programas prejudiciais</translation>
<translation id="8997023839087525404">O servidor apresentou um certificado que não foi divulgado publicamente através da política de Transparência de certificados. Trata-se de um requisito para alguns certificados de modo a assegurar que são fidedignos e protegem contra utilizadores mal intencionados.</translation>
<translation id="9001074447101275817">O proxy <ph name="DOMAIN" /> necessita de um nome de utilizador e de uma palavra-passe.</translation>
<translation id="9005998258318286617">Falha ao carregar o documento PDF.</translation>
+<translation id="9008201768610948239">Ignorar</translation>
<translation id="901974403500617787">Os sinalizadores que se aplicam a todo o sistema apenas podem ser definidos pelo proprietário: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Endereço de faturação do cartão necessário</translation>
<translation id="9020542370529661692">Esta página foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado inválido.</translation>
<translation id="9050666287014529139">Frase de acesso</translation>
<translation id="9065203028668620118">Editar</translation>
-<translation id="9068849894565669697">Selecionar cor</translation>
<translation id="9069693763241529744">Bloqueada por uma extensão</translation>
<translation id="9076283476770535406">Pode ter conteúdo para adultos</translation>
<translation id="9078964945751709336">São necessárias mais informações</translation>
+<translation id="9080712759204168376">Resumo da encomenda</translation>
<translation id="9103872766612412690">Normalmente, o site <ph name="SITE" /> utiliza a encriptação para proteger as suas informações. Quando o Chromium tentou estabelecer ligação a <ph name="SITE" /> desta vez, o Website devolveu credenciais invulgares e incorretas. Isto pode acontecer quando um utilizador mal intencionado tenta simular ser <ph name="SITE" /> ou quando um ecrã de início de sessão Wi-Fi interrompe a ligação. As suas informações continuam seguras porque o Chromium interrompeu a ligação antes de qualquer troca de dados.</translation>
+<translation id="9106062320799175032">Adicionar endereço de faturação</translation>
+<translation id="910908805481542201">Ajudar-me a corrigir isto</translation>
+<translation id="9128870381267983090">Ligar à rede</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9137248913990643158">Comece e inicie sessão no Chrome antes de utilizar esta aplicação.</translation>
<translation id="9148507642005240123">&amp;Anular edição</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utiliza um protocolo não suportado.</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="9215416866750762878">Uma aplicação está a impedir que o Chrome se ligue a este site em segurança</translation>
<translation id="9219103736887031265">Imagens</translation>
<translation id="933612690413056017">Não existe ligação à Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Nenhum}=1{1 item}one{# itens}other{# itens}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Compilação de programador</translation>
+<translation id="989988560359834682">Editar endereço</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">O "<ph name="SOFTWARE_NAME" />" não foi instalado corretamente no computador ou na rede:
+ &lt;ul&gt;
+ &lt;li&gt;Experimente desinstalar ou desativar o "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Experimente estabelecer ligação a outra rede&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index af27b788855..ca30e889da6 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Marcaje desktop</translation>
<translation id="1074497978438210769">Nesecurizat</translation>
<translation id="1080116354587839789">Încadrează pe lățime</translation>
+<translation id="1088860948719068836">Adaugă numele de pe card</translation>
<translation id="1103523840287552314">Tradu întotdeauna din <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Afișează toate parolele salvate...</translation>
<translation id="1107591249535594099">Dacă este bifată opțiunea, Chrome va stoca o copie a cardului pe dispozitiv pentru a completa formularul mai rapid.</translation>
<translation id="1111153019813902504">Marcaje accesate recent</translation>
<translation id="1113869188872983271">&amp;Anulați reordonarea</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sincronizate)</translation>
<translation id="1263231323834454256">Lista de lectură</translation>
<translation id="1264126396475825575">Raport de blocare creat <ph name="CRASH_TIME" /> (nu a fost încă încărcat sau ignorat)</translation>
+<translation id="1270502636509132238">Metodă de preluare</translation>
<translation id="1281526147609854549">Emis de <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nu traduce niciodată acest site</translation>
<translation id="129553762522093515">Închise recent</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Se așteaptă conectarea…</translation>
<translation id="153384715582417236">Asta este tot</translation>
<translation id="1549470594296187301">Trebuie să activezi JavaScript pentru a folosi această funcție.</translation>
-<translation id="1555130319947370107">Albastru</translation>
<translation id="1559528461873125649">Nu există un astfel de fișier sau director</translation>
<translation id="1583429793053364125">A apărut o eroare la afișarea paginii web.</translation>
<translation id="1592005682883173041">Accesul la datele locale</translation>
<translation id="1594030484168838125">Alegeți</translation>
-<translation id="161042844686301425">Cyan</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1629803312968146339">Dorești ca acest card să fie salvat în Chrome?</translation>
<translation id="1639239467298939599">Se încarcă</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Sistem de operare</translation>
<translation id="1721312023322545264">Ai nevoie de permisiunea utilizatorului <ph name="NAME" /> ca să accesezi acest site</translation>
<translation id="1721424275792716183">* Câmp obligatoriu</translation>
+<translation id="1727741090716970331">Adaugă un număr de card valid</translation>
<translation id="1728677426644403582">Se afișează sursa unei pagini web</translation>
<translation id="173080396488393970">Acest tip de card nu este acceptat</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Eroare de serializare</translation>
<translation id="1974060860693918893">Avansate</translation>
<translation id="1978555033938440688">Versiune de firmware</translation>
-<translation id="1995859865337580572">Confirmă codul CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{și încă una}few{și încă #}other{și încă #}}</translation>
<translation id="2025186561304664664">Proxy-ul este setat la Configurat automat.</translation>
<translation id="2030481566774242610">Ați dorit să scrieți <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Pentru a obține sugestii de conținut personalizat de la Google, conectează-te la Chrome.</translation>
+<translation id="2091887806945687916">Sunet</translation>
<translation id="2094505752054353250">Nepotrivire domeniu</translation>
<translation id="2096368010154057602">Departament</translation>
<translation id="2108755909498034140">repornește computerul;</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Politica este ignorată, deoarece a fost înlocuită de <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Se caută pagini din Webul material din apropiere</translation>
<translation id="213826338245044447">Marcaje mobile</translation>
+<translation id="214556005048008348">Anulează plata</translation>
<translation id="2147827593068025794">Sincronizare în fundal</translation>
+<translation id="2148613324460538318">Adaugă un card</translation>
<translation id="2154054054215849342">Sincronizarea nu este disponibilă pentru domeniul tău</translation>
<translation id="2154484045852737596">Editează cardul</translation>
<translation id="2166049586286450108">Acces complet de administrare</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresă}few{# adrese}other{# de adrese}}</translation>
<translation id="2187317261103489799">Detectează (în mod prestabilit)</translation>
<translation id="2202020181578195191">Introdu un an de expirare valid</translation>
+<translation id="2209523182407020534">Aplicațiile care pot genera această eroare includ software-ul antivirus, firewall, de filtrare web sau proxy.</translation>
<translation id="2212735316055980242">Politica nu a fost găsită</translation>
<translation id="2213606439339815911">Se preiau intrările...</translation>
<translation id="2218879909401188352">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ar putea să instaleze aplicații periculoase care deteriorează dispozitivul, adaugă costuri ascunse pe factura de telefonie mobilă sau îți fură informațiile cu caracter personal. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Înapoi</translation>
<translation id="2503184589641749290">Carduri de debit și preplătite acceptate</translation>
<translation id="2515629240566999685">să verifici semnalul din zona ta;</translation>
+<translation id="2524461107774643265">Adaugă mai multe informații</translation>
+<translation id="2536110899380797252">Adaugă o adresă</translation>
<translation id="2539524384386349900">Detectează</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> a trimis un răspuns nevalid.</translation>
<translation id="2556876185419854533">&amp;Anulați editarea</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Momentan, Chromium nu a putut confirma cardul. Încearcă din nou mai târziu.</translation>
<translation id="2705137772291741111">Copia salvată (în memoria cache) a acestui site nu a putut fi citită.</translation>
<translation id="2709516037105925701">Completare automată</translation>
+<translation id="2710942282213947212">Pe computer există software care împiedică Chromium să se conecteze în siguranță la internet</translation>
<translation id="2712173769900027643">Solicită permisiunea</translation>
-<translation id="2713444072780614174">Alb</translation>
<translation id="2720342946869265578">În apropiere</translation>
<translation id="2721148159707890343">Solicitarea a reușit</translation>
<translation id="2728127805433021124">Certificatul serverului este semnat utilizând un algoritm de semnătură slab.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">A fost detectată o schimbare a rețelei.</translation>
<translation id="2916038427272391327">închide celelalte programe;</translation>
<translation id="2922350208395188000">Certificatul serverului nu poate fi verificat.</translation>
+<translation id="2925673989565098301">Metodă de livrare</translation>
<translation id="2928905813689894207">Adresă de facturare</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate provine de la <ph name="DOMAIN2" />. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Tip de politică greșit</translation>
<translation id="3032412215588512954">Dorești să reîncarci acest site?</translation>
<translation id="3037605927509011580">Of, nu mai merge!</translation>
+<translation id="3039538478787849737">Salvezi cardul pe Google?</translation>
<translation id="3041612393474885105">Informații despre certificat</translation>
<translation id="3063697135517575841">Momentan, Chrome nu a putut confirma cardul. Încearcă din nou mai târziu.</translation>
<translation id="3064966200440839136">Vei părăsi modul incognito pentru a plăti folosind o aplicație externă. Continui?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Eroare temporară de server</translation>
<translation id="3154506275960390542">Pagina include un formular care este posibil să nu fie trimis în siguranță. Alți utilizatori pot vedea datele trimise în timpul transferului sau acestea ar putea fi modificate de un atacator pentru a schimba conținutul primit de server.</translation>
<translation id="3157931365184549694">Restabilește</translation>
+<translation id="3162559335345991374">Rețeaua Wi-Fi pe care o folosești poate solicita accesarea paginii de conectare.</translation>
<translation id="3167968892399408617">Paginile pe care le accesezi în filele incognito nu vor fi înregistrate în istoricul browserului, nu vor stoca cookie-uri și nu vor rămâne în istoricul de căutare după ce închizi toate filele incognito. Fișierele descărcate și marcajele create vor fi păstrate.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Insulă</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Anulează plata</translation>
<translation id="3207960819495026254">Marcată</translation>
+<translation id="3211223744486044430">Pentru a plăti mai rapid data viitoare, salvează cardul în Contul Google și pe acest dispozitiv.</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>
<translation id="3226128629678568754">Apăsați butonul de reîncărcare pentru a retrimite datele necesare pentru încărcarea paginii.</translation>
<translation id="3227137524299004712">Microfon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Nu s-au găsit rezultate de căutare</translation>
<translation id="3305707030755673451">Datele au fost criptate cu expresia de acces pentru sincronizare la <ph name="TIME" />. Introdu-o pentru a începe sincronizarea.</translation>
<translation id="3320021301628644560">Adaugă o adresă de facturare</translation>
-<translation id="3329013043687509092">Saturație</translation>
<translation id="333371639341676808">Împiedică această pagină să creeze alte casete de dialog.</translation>
<translation id="3338095232262050444">Securizat</translation>
<translation id="3340978935015468852">setări</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Cod de client:</translation>
<translation id="3391030046425686457">Adresă de livrare</translation>
<translation id="3395827396354264108">Metodă de preluare</translation>
+<translation id="3399952811970034796">Adresă de livrare</translation>
<translation id="3422248202833853650">Încearcă să ieși din celelalte programe pentru a elibera memoria.</translation>
<translation id="3422472998109090673">Momentan, <ph name="HOST_NAME" /> nu poate fi accesat.</translation>
<translation id="3427092606871434483">Permite (în mod prestabilit)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Raport de blocare creat <ph name="CRASH_TIME" /> și încărcat <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informații despre certificat</translation>
<translation id="3690164694835360974">Conectarea nu este securizată</translation>
+<translation id="3704162925118123524">Rețeaua pe care o folosești poate solicita accesarea paginii de conectare.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Se încarcă…</translation>
<translation id="3712624925041724820">Licențe epuizate</translation>
<translation id="3714780639079136834">să activezi datele mobile sau conexiunea Wi-Fi;</translation>
+<translation id="3715597595485130451">Conectează-te la o rețea Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />să verifici configurarea pentru proxy, firewall și DNS;<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Dacă înțelegeți riscurile de securitate, puteți să <ph name="BEGIN_LINK" />accesați acest site nesigur<ph name="END_LINK" /> înainte ca programele periculoase să fie eliminate.</translation>
<translation id="3739623965217189342">Linkul copiat de tine</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Anulați adăugarea</translation>
<translation id="404928562651467259">AVERTISMENT</translation>
<translation id="4058922952496707368">Cheie „<ph name="SUBKEY" />”: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Configurația pentru proxy este setată să utilizeze o adresă URL pentru scripturi .pac, și nu servere proxy fixe.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Numărul de serie al gadgetului este nevalid</translation>
<translation id="410351446219883937">Redare automată</translation>
<translation id="4103763322291513355">Accesați &lt;strong&gt;chrome://policy&lt;/strong&gt; pentru a vedea adresele URL introduse pe lista neagră și alte politici impuse de către administratorul de sistem.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Permiteți întotdeauna pe acest site</translation>
<translation id="4117700440116928470">Domeniul politicii nu este acceptat.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{încă 1}few{încă #}other{încă #}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Ați încercat să accesați <ph name="DOMAIN" />, dar certificatul furnizat de server a fost revocat de emitentul său. Aceasta înseamnă că acreditările de securitate furnizate de server nu sunt deloc de încredere. Este posibil să comunicați cu un atacator.</translation>
<translation id="4394049700291259645">Dezactivează</translation>
<translation id="4406896451731180161">rezultate ale căutării</translation>
+<translation id="4415426530740016218">Adresă de preluare</translation>
<translation id="4424024547088906515">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; Chrome nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nu a acceptat certificatul de conectare sau un astfel de certificat nu a fost oferit.</translation>
<translation id="443673843213245140">Utilizarea unui proxy este dezactivată, dar o configurare proxy este specificată în mod explicit.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Dezactivează extensiile.</translation>
<translation id="457875822857220463">Livrare</translation>
+<translation id="4582800630050655161">Este posibil să pierzi accesul la Contul Google sau să fii victima unui furt de identitate. Chromium îți recomandă să îți schimbi acum parola.</translation>
<translation id="4587425331216688090">Elimini adresa din Chrome?</translation>
<translation id="4592951414987517459">Conexiunea la <ph name="DOMAIN" /> este criptată folosind o suită de codificare modernă.</translation>
<translation id="4594403342090139922">&amp;Anulați ștergerea</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Nu mai folosi un certificat nevalid</translation>
+<translation id="4690954380545377795">Este posibil să pierzi accesul la Contul Google sau să fii victima unui furt de identitate. Chrome îți recomandă să îți schimbi acum parola.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Conexiunea a fost întreruptă</translation>
<translation id="471880041731876836">Nu ai permisiunea să accesezi acest site</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea Windows<ph name="END_LINK" />;</translation>
+<translation id="472349245089439925">Plata</translation>
<translation id="4726672564094551039">Reîncărcați politicile</translation>
<translation id="4728558894243024398">Platformă</translation>
<translation id="4736825316280949806">repornește Chromium;</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Depozit de fundal în stare nevalidă</translation>
<translation id="5023310440958281426">Consultați politicile administratorului</translation>
<translation id="5029568752722684782">Șterge copia</translation>
+<translation id="503069730517007720">Un certificat rădăcină pentru „<ph name="SOFTWARE_NAME" />” este necesar, dar nu este instalat. Administratorul IT trebuie să verifice instrucțiunile de configurare pentru „<ph name="SOFTWARE_NAME" />” ca să remedieze problema. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Despre Google Traducere</translation>
<translation id="5039804452771397117">Permite</translation>
<translation id="5040262127954254034">Confidențialitate</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experimente</translation>
<translation id="5205222826937269299">Numele este obligatoriu</translation>
<translation id="5222812217790122047">Adresa de e-mail este obligatorie</translation>
+<translation id="522700295135997067">Este posibil ca acest site să îți fi furat chiar acum parola</translation>
+<translation id="5230733896359313003">Adresă de expediere</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Folosești Chrome la serviciu? Companiile pot gestiona setările Chrome pentru angajații lor. Află mai multe</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Urmează acești pași ca să dezactivezi temporar software-ul, astfel încât să poți accesa internetul. Vei avea nevoie de privilegii de administrator.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Conexiunea la acest site nu este privată. Pentru a ieși oricând din modul RV, scoate vizualizatorul și apasă pe Înapoi.</translation>
<translation id="5299298092464848405">Eroare la analizarea politicii</translation>
+<translation id="5308380583665731573">Conectează-te</translation>
<translation id="5308689395849655368">Raportarea blocărilor este dezactivată.</translation>
<translation id="5317780077021120954">Salvează</translation>
<translation id="5327248766486351172">Nume</translation>
+<translation id="5332219387342487447">Metoda de expediere</translation>
<translation id="5355557959165512791">Nu poți accesa <ph name="SITE" /> acum, deoarece certificatul său a fost revocat. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu.</translation>
<translation id="536296301121032821">Setările pentru politică nu au putut fi stocate</translation>
<translation id="5386426401304769735">Lanțul de certificate pentru acest site conține un certificat semnat folosind SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Acest site din rețeaua intranet a companiei, organizației sau școlii are aceeași adresă URL folosită de un site extern.
<ph name="LINE_BREAK" />
Contactează administratorul sistemului.</translation>
+<translation id="5499929369096410817">Introdu codul de securitate pentru <ph name="CREDIT_CARD" />. Acest cod nu va fi salvat.</translation>
<translation id="5509780412636533143">Marcaje gestionate</translation>
<translation id="5510766032865166053">Este posibil să fi fost mutat sau șters.</translation>
<translation id="5523118979700054094">Numele politicii</translation>
<translation id="552553974213252141">Textul a fost extras corect?</translation>
<translation id="5540224163453853">Articolul solicitat nu poate fi găsit.</translation>
+<translation id="5541546772353173584">Adaugă o adresă de e-mail</translation>
<translation id="5544037170328430102">O pagină încorporată de pe <ph name="SITE" /> afișează mesajul:</translation>
+<translation id="5545756402275714221">Articole pentru tine</translation>
<translation id="5556459405103347317">Reîncarcă</translation>
<translation id="5560088892362098740">Data expirării</translation>
<translation id="5565735124758917034">Activ</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Adresă de e-mail</translation>
<translation id="5669703222995421982">Obține conținut personalizat</translation>
<translation id="5675650730144413517">Pagina nu funcționează</translation>
+<translation id="5689199277474810259">Exportă în format JSON</translation>
<translation id="5710435578057952990">Identitatea acestui site nu a fost confirmată.</translation>
<translation id="5719499550583120431">Se acceptă carduri preplătite.</translation>
<translation id="5720705177508910913">Utilizator curent</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Conexiunea la <ph name="DOMAIN" /> este criptată folosind o suită de codificare învechită.</translation>
<translation id="5813119285467412249">&amp;Repetați adăugarea</translation>
<translation id="5838278095973806738">Nu ar trebui să introduci informații sensibile pe acest site (de exemplu, parole sau carduri de credit), deoarece ar putea fi furate de atacatori.</translation>
+<translation id="5866257070973731571">Adaugă un număr de telefon</translation>
<translation id="5869405914158311789">Acest site nu poate fi accesat</translation>
<translation id="5869522115854928033">Parole salvate</translation>
<translation id="5872918882028971132">Sugestii parentale</translation>
<translation id="5893752035575986141">Se acceptă carduri de credit.</translation>
-<translation id="5901630391730855834">Galben</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizat)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 în uz}few{# în uz}other{# în uz}}</translation>
<translation id="5959728338436674663">Trimite automat anumite <ph name="BEGIN_WHITEPAPER_LINK" />informații despre sistem și conținutul paginii<ph name="END_WHITEPAPER_LINK" /> la Google pentru a detecta aplicațiile și site-urile periculoase. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Editează informațiile de contact</translation>
<translation id="5967867314010545767">Eliminați din istoric</translation>
<translation id="5975083100439434680">Micșorează</translation>
+<translation id="597552863672748783">Confirmă codul de securitate</translation>
<translation id="598637245381783098">Nu se poate deschide aplicația de plată</translation>
<translation id="5989320800837274978">Nu sunt specificate nici servere proxy fixe și nici o adresă URL pentru scripturi .pac.</translation>
<translation id="5990559369517809815">Solicitările trimise la server au fost blocate de o extensie.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Pagina 1}few{Pagina #}other{Pagina #}}</translation>
-<translation id="6017514345406065928">Verde</translation>
<translation id="6017850046339264347">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ar putea instala aplicații înșelătoare care pretind a fi altceva sau culeg date care pot fi folosite pentru a te urmări. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sincronizate)</translation>
<translation id="6027201098523975773">Introdu un nume</translation>
<translation id="6040143037577758943">Închide</translation>
-<translation id="6042308850641462728">Mai multe</translation>
<translation id="6047233362582046994">Dacă îți asumi riscurile de securitate, poți să <ph name="BEGIN_LINK" />accesezi acest site<ph name="END_LINK" /> înainte ca aplicațiile dăunătoare să fie eliminate.</translation>
<translation id="6047927260846328439">Acest conținut ar putea încerca să te păcălească să instalezi software sau să dezvălui informații cu caracter personal. <ph name="BEGIN_LINK" />Afișează oricum<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Nu poți accesa <ph name="SITE" /> acum, deoarece site-ul folosește fixarea certificatelor. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Se afișează pagina unei extensii</translation>
<translation id="6596325263575161958">Opțiuni de criptare</translation>
<translation id="662080504995468778">Rămâi pe pagină</translation>
+<translation id="6624427990725312378">Informații de contact</translation>
<translation id="6626291197371920147">Adaugă un număr de card valid</translation>
<translation id="6628463337424475685">Căutare <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pot încerca să instaleze programe periculoase pe computerul tău Mac, care să îți fure sau să îți șteargă informațiile (de exemplu, fotografii, parole, mesaje sau date despre cardurile de credit). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Înapoi</translation>
<translation id="6710594484020273272">&lt;Introdu termenul de căutare&gt;</translation>
<translation id="6711464428925977395">A apărut o problemă la serverul proxy sau adresa nu este corectă.</translation>
-<translation id="6727102863431372879">Setează</translation>
<translation id="674375294223700098">Eroare de certificat de server necunoscută.</translation>
<translation id="6753269504797312559">Valoarea politicii</translation>
<translation id="6757797048963528358">Dispozitivul este inactiv.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">Adresă URL</translation>
<translation id="7419106976560586862">Calea profilului</translation>
<translation id="7424977062513257142">O pagină încorporată de pe această pagină web afișează mesajul:</translation>
+<translation id="7437289804838430631">Adaugă informații de contact</translation>
<translation id="7441627299479586546">Subiectul politicii este greșit</translation>
<translation id="7444046173054089907">Acest site este blocat</translation>
<translation id="7445762425076701745">Identitatea serverului la care te-ai conectat nu poate fi validată complet. Ești conectat(ă) la un server folosind un nume valid numai în rețeaua ta, pentru care o autoritate de certificare externă nu are nici o modalitate de a-l valida. Deoarece unele autorități de certificare vor emite certificate pentru aceste nume oricum, nu există nicio modalitate de a te asigura că ești conectat(ă) la site-ul corect și nu la un atacator.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Înainte</translation>
<translation id="7485870689360869515">Nu s-au găsit date.</translation>
<translation id="7508255263130623398">ID-ul de dispozitiv returnat pentru politică este gol sau nu corespunde cu ID-ul de dispozitiv actual</translation>
+<translation id="7511955381719512146">Rețeaua Wi-Fi pe care o folosești poate solicita accesarea adresei <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Descarcă</translation>
<translation id="7518003948725431193">Nu a fost găsită nicio pagină web pentru adresa: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Conexiunea la acest site nu este privată</translation>
-<translation id="7535087603100972091">Valoare</translation>
<translation id="7537536606612762813">Obligatorie</translation>
<translation id="7542403920425041731">După ce confirmi, acest site va avea acces la detaliile cardului tău.</translation>
<translation id="7542995811387359312">Completarea automată a cardului de credit este dezactivată, deoarece acest formular nu utilizează o conexiune sigură.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; este posibil ca certificatul său de securitate să fi fost emis fraudulos. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="7568593326407688803">Această pagină este în <ph name="ORIGINAL_LANGUAGE" /> Vrei să fie tradusă?</translation>
<translation id="7569952961197462199">Elimini cardul de credit din Chrome?</translation>
-<translation id="7569983096843329377">Negru</translation>
<translation id="7578104083680115302">Plătește rapid pe site-uri și în aplicații pe diferite dispozitive folosind cardurile pe care le-ai salvat pe Google.</translation>
<translation id="7588950540487816470">Web material</translation>
<translation id="7592362899630581445">Certificatul serverului încalcă limitările privind numele.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Atacatorii de pe acest site pot încerca să te înșele pentru a instala programe care dăunează experienței de navigare (de exemplu, schimbând pagina de pornire sau afișând anunțuri suplimentare pe site-urile pe care le accesezi).</translation>
<translation id="7674629440242451245">Doriți să utilizați funcții Chrome noi și interesante? Încercați canalul nostru pentru dezvoltatori, de la chrome.com/dev.</translation>
<translation id="7682287625158474539">Expediere</translation>
+<translation id="7699293099605015246">Articolele nu sunt disponibile în acest moment</translation>
<translation id="7701040980221191251">Niciuna</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Accesați <ph name="SITE" /> (nesigur)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certificat</translation>
<translation id="7716147886133743102">Blocată de administrator</translation>
<translation id="7716424297397655342">Acest site nu poate fi încărcat din memoria cache</translation>
+<translation id="7723047071702270851">Editează cardul</translation>
<translation id="774634243536837715">Conținutul periculos a fost blocat.</translation>
<translation id="7752995774971033316">Negestionat</translation>
<translation id="7755287808199759310">Părintele tău îl poate debloca pentru tine</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Adaugă o adresă</translation>
<translation id="777702478322588152">Prefectură</translation>
<translation id="7791543448312431591">Adaugă</translation>
+<translation id="7793553086574152071">Pentru a plăti mai rapid data viitoare, salvează acest card în Contul Google.</translation>
<translation id="7793809570500803535">Pagina web de la <ph name="SITE" /> poate fi temporar nefuncțională sau a fost mutată definitiv la o nouă adresă web.</translation>
<translation id="7800304661137206267">Conexiunea este criptată utilizând <ph name="CIPHER" />, cu <ph name="MAC" /> pentru autentificarea mesajelor și <ph name="KX" /> ca mecanism de schimb al cheii.</translation>
+<translation id="7802523362929240268">Site-ul este legitim</translation>
<translation id="780301667611848630">Nu, mulțumesc</translation>
<translation id="7805768142964895445">Stare</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Elimini sugestia pentru formular din Chrome?</translation>
<translation id="7815407501681723534">S-au găsit <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> pentru „<ph name="SEARCH_STRING" />”</translation>
+<translation id="782886543891417279">Rețeaua Wi-Fi pe care o folosești (<ph name="WIFI_NAME" />) poate solicita accesarea paginii de conectare.</translation>
<translation id="785549533363645510">Cu toate acestea, nu ești invizibil(ă). Trecerea în modul incognito nu ascunde activitatea de navigare față de angajator, față de furnizorul de servicii de internet sau față de site-urile pe care le accesezi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Se acceptă carduri de debit și preplătite.</translation>
+<translation id="7878562273885520351">Este posibil ca parola să fie compromisă</translation>
<translation id="7887683347370398519">Verifică codul CVC și încearcă din nou</translation>
<translation id="79338296614623784">Introdu un număr de telefon valid</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certificatul serverului nu este încă valid.</translation>
-<translation id="7942349550061667556">Roșu</translation>
<translation id="7947285636476623132">Verifică anul în care expiră și încearcă din nou</translation>
<translation id="7951415247503192394">(32 de biți)</translation>
<translation id="7956713633345437162">Marcaje mobile</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Solicită (în mod prestabilit)</translation>
<translation id="8041089156583427627">Trimiteți feedback</translation>
<translation id="8041940743680923270">Utilizați setarea prestabilită la nivel global (Întrebați)</translation>
+<translation id="8057711352706143257">„<ph name="SOFTWARE_NAME" />” nu este configurat corect. De obicei, problema se remediază dezinstalând „<ph name="SOFTWARE_NAME" />” <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Articolul nu a fost vizualizat.</translation>
<translation id="8091372947890762290">Se așteaptă activarea pe server</translation>
+<translation id="8094917007353911263">Rețeaua pe care o folosești poate solicita accesarea adresei <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Metodă de plată</translation>
<translation id="8118489163946903409">Metodă de plată</translation>
+<translation id="8127301229239896662">„<ph name="SOFTWARE_NAME" />” nu a fost instalat corect pe computer sau în rețea. Contactează administratorul IT pentru a remedia această problemă.</translation>
<translation id="8131740175452115882">Confirmați</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> pentru serverul <ph name="HOST_NAME" /> nu a putut fi găsită.</translation>
<translation id="8149426793427495338">Computerul este inactiv.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Dacă nu știți sigur ce înseamnă aceasta, contactați administratorul de rețea.</translation>
<translation id="8293206222192510085">Adăugați marcaj</translation>
<translation id="8294431847097064396">Sursă</translation>
+<translation id="8298115750975731693">Rețeaua Wi-Fi pe care o folosești (<ph name="WIFI_NAME" />) poate solicita accesarea adresei <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Traducerea nu a reușit din cauza unei probleme cu conexiunea la rețea.</translation>
<translation id="8332188693563227489">Accesul la <ph name="HOST_NAME" /> nu este permis</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Închise recent</translation>
<translation id="8874824191258364635">Introdu un număr de card valid</translation>
<translation id="8876793034577346603">Configurația rețelei nu a putut fi analizată.</translation>
-<translation id="8889402386540077796">Nuanță</translation>
<translation id="8891727572606052622">Mod proxy nevalid.</translation>
<translation id="889901481107108152">Ne pare rău, acest experiment nu este disponibil pe platforma dvs.</translation>
<translation id="8903921497873541725">Mărește</translation>
<translation id="8931333241327730545">Dorești să salvezi acest card în Contul Google?</translation>
<translation id="8932102934695377596">Ora este setată în trecut</translation>
+<translation id="893332455753468063">Adaugă un nume</translation>
<translation id="8938939909778640821">Carduri de credit și preplătite acceptate</translation>
+<translation id="8957210676456822347">Autorizarea prin portalul captiv</translation>
<translation id="8971063699422889582">Certificatul serverului a expirat.</translation>
-<translation id="8986494364107987395">Trimite automat la Google statistici de utilizare și rapoarte de blocare</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Site-ul pe care urmează să îl accesezi conține programe dăunătoare</translation>
<translation id="8997023839087525404">Serverul a prezentat un certificat care nu a fost dezvăluit public folosind politica privind Transparența certificatului. Aceasta este o cerință pentru anumite certificate, pentru a se asigura că sunt de încredere și pentru protecție împotriva atacatorilor.</translation>
<translation id="9001074447101275817">Pentru a accesa proxy-ul <ph name="DOMAIN" />, trebuie să introduci un nume de utilizator și o parolă.</translation>
<translation id="9005998258318286617">Documentul PDF nu a fost încărcat.</translation>
+<translation id="9008201768610948239">Ignorați</translation>
<translation id="901974403500617787">Marcajele care se aplică la nivel de sistem pot fi create numai de proprietar: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Este necesară adresa de facturare a cardului</translation>
<translation id="9020542370529661692">Această pagină a fost tradusă în <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Ai încercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat nevalid.</translation>
<translation id="9050666287014529139">Expresie de acces</translation>
<translation id="9065203028668620118">Editează</translation>
-<translation id="9068849894565669697">Selectați culoarea</translation>
<translation id="9069693763241529744">Blocată de o extensie</translation>
<translation id="9076283476770535406">Poate include conținut destinat adulților</translation>
<translation id="9078964945751709336">Sunt necesare mai multe informații</translation>
+<translation id="9080712759204168376">Rezumatul comenzii</translation>
<translation id="9103872766612412690">Site-ul <ph name="SITE" /> folosește în mod obișnuit criptarea pentru a-ți proteja informațiile. Când Chromium a încercat să se conecteze la <ph name="SITE" /> de această dată, site-ul a returnat date de conectare neobișnuite și incorecte. Acest lucru s-a întâmplat fie pentru că un atacator încearcă să falsifice site-ul <ph name="SITE" />, fie pentru că un ecran de conectare Wi-Fi a întrerupt conexiunea. Securitatea informațiilor tale nu a fost afectată, deoarece Chromium a oprit conexiunea înainte ca datele să fie transferate.</translation>
+<translation id="9106062320799175032">Adaugă o adresă de facturare</translation>
+<translation id="910908805481542201">Ajută-mă să remediez această eroare</translation>
+<translation id="9128870381267983090">Conectați-vă la rețea</translation>
<translation id="9137013805542155359">Afișează originalul</translation>
<translation id="9137248913990643158">Pornește și conectează-te la Chrome înainte de a folosi această aplicație.</translation>
<translation id="9148507642005240123">&amp;Anulați editarea</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> folosește un protocol neacceptat.</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="9215416866750762878">O aplicație împiedică browserul Chrome să se conecteze în siguranță la acest site</translation>
<translation id="9219103736887031265">Imagini</translation>
<translation id="933612690413056017">Nu există conexiune la internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Niciunul}=1{1 element}few{# elemente}other{# de elemente}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Versiune de programare</translation>
+<translation id="989988560359834682">Editați adresa</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">„<ph name="SOFTWARE_NAME" />” nu a fost instalat corect pe computer sau în rețea:
+ &lt;ul&gt;
+ &lt;li&gt;încearcă să dezinstalezi sau să dezactivezi „<ph name="SOFTWARE_NAME" />”&lt;/li&gt;;
+ &lt;li&gt;încearcă să te conectezi la altă rețea Wi-Fi.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index 128c0ea414d..970b145c85f 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Закладки на компьютере</translation>
<translation id="1074497978438210769">Не защищено</translation>
<translation id="1080116354587839789">Выровнять по ширине окна</translation>
+<translation id="1088860948719068836">Укажите имя владельца карты</translation>
<translation id="1103523840287552314">Всегда переводить <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Показать все сохраненные пароли...</translation>
<translation id="1107591249535594099">Если флажок установлен, Chrome будет хранить на этом устройстве данные карты для быстрого заполнения форм.</translation>
<translation id="1111153019813902504">Недавние закладки</translation>
<translation id="1113869188872983271">&amp;Отменить изменение порядка</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (данные синхронизируются)</translation>
<translation id="1263231323834454256">Список для чтения</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />: получен отчет о сбое (ещё не загружен или не отклонен)</translation>
+<translation id="1270502636509132238">Способ получения</translation>
<translation id="1281526147609854549">Выдан <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Никогда не переводить этот сайт</translation>
<translation id="129553762522093515">Недавно закрытые</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Ожидание подключения…</translation>
<translation id="153384715582417236">Пока это всё</translation>
<translation id="1549470594296187301">Для использования этой функции необходимо включить JavaScript.</translation>
-<translation id="1555130319947370107">Синий</translation>
<translation id="1559528461873125649">Данный файл или каталог не существует</translation>
<translation id="1583429793053364125">При загрузке этой страницы возникли неполадки.</translation>
<translation id="1592005682883173041">Доступ к данным на устройстве</translation>
<translation id="1594030484168838125">Выбрать</translation>
-<translation id="161042844686301425">Голубой</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1629803312968146339">Сохранить эту карту в Chrome?</translation>
<translation id="1639239467298939599">Загрузка</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Для доступа к этой странице требуется разрешение пользователя <ph name="NAME" /></translation>
<translation id="1721424275792716183">*Обязательное поле</translation>
+<translation id="1727741090716970331">Введите правильный номер карты</translation>
<translation id="1728677426644403582">Вы просматриваете код страницы</translation>
<translation id="173080396488393970">Этот тип карты не поддерживается.</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Не удалось выполнить сериализацию</translation>
<translation id="1974060860693918893">Дополнительные</translation>
<translation id="1978555033938440688">Версия ПО</translation>
-<translation id="1995859865337580572">Подтвердите CVC-код</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{и ещё 1}one{и ещё #}few{и ещё #}many{и ещё #}other{и ещё #}}</translation>
<translation id="2025186561304664664">Прокси-сервер настраивается автоматически.</translation>
<translation id="2030481566774242610">Возможно, вы имели в виду <ph name="LINK" />.</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Отмена</translation>
<translation id="20817612488360358">Включены системные настройки прокси-сервера, но при этом его конфигурация задана явным образом.</translation>
<translation id="2086652334978798447">Чтобы мы могли рекомендовать вам интересный контент, войдите в свой аккаунт в Chrome.</translation>
+<translation id="2091887806945687916">Звук</translation>
<translation id="2094505752054353250">Несоответствие домена</translation>
<translation id="2096368010154057602">Округ</translation>
<translation id="2108755909498034140">Перезагрузите компьютер.</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Игнорируется, так как правило <ph name="POLICY_NAME" /> имеет приоритет.</translation>
<translation id="2138201775715568214">Поиск веб-страниц…</translation>
<translation id="213826338245044447">Закладки на мобильном</translation>
+<translation id="214556005048008348">Отменить оплату</translation>
<translation id="2147827593068025794">Фоновая синхронизация</translation>
+<translation id="2148613324460538318">Добавить карту</translation>
<translation id="2154054054215849342">В вашем домене синхронизация недоступна</translation>
<translation id="2154484045852737596">Изменение данных карты</translation>
<translation id="2166049586286450108">Доступ администратора ко всем данным</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 адрес}one{# адрес}few{# адреса}many{# адресов}other{# адреса}}</translation>
<translation id="2187317261103489799">Определять (по умолчанию)</translation>
<translation id="2202020181578195191">Недопустимый формат года.</translation>
+<translation id="2209523182407020534">Эта ошибка может возникать из-за антивирусных приложений, брандмауэра, программ для веб-фильтрации или прокси-сервера.</translation>
<translation id="2212735316055980242">Политика для устройства не найдена</translation>
<translation id="2213606439339815911">Извлечение записей…</translation>
<translation id="2218879909401188352">Злоумышленники могут использовать сайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, чтобы установить опасные приложения, которые причиняют вред устройствам, увеличивают расходы на мобильную связь и крадут личные данные. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Назад</translation>
<translation id="2503184589641749290">Дебетовые карты и карты предоплаты, которые принимаются к оплате</translation>
<translation id="2515629240566999685">Проверьте уровень сигнала сети.</translation>
+<translation id="2524461107774643265">Укажите дополнительную информацию</translation>
+<translation id="2536110899380797252">Добавить адрес</translation>
<translation id="2539524384386349900">Определять</translation>
<translation id="255002559098805027">Сайт <ph name="HOST_NAME" /> отправил недействительный ответ.</translation>
<translation id="2556876185419854533">&amp;Отменить изменения</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Не удалось подтвердить данные карты. Повторите попытку позже.</translation>
<translation id="2705137772291741111">Невозможно прочитать копию сайта, сохраненную в кеше.</translation>
<translation id="2709516037105925701">Автозаполнение</translation>
+<translation id="2710942282213947212">ПО, установленное на компьютере, не позволяет Chromium безопасно подключиться к Интернету</translation>
<translation id="2712173769900027643">Попросить разрешения</translation>
-<translation id="2713444072780614174">Белый</translation>
<translation id="2720342946869265578">Мое окружение</translation>
<translation id="2721148159707890343">Запрос выполнен успешно</translation>
<translation id="2728127805433021124">Сертификат сервера подписан с использованием ненадежного алгоритма.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Похоже, вы подключились к другой сети.</translation>
<translation id="2916038427272391327">Закройте другие программы.</translation>
<translation id="2922350208395188000">Не удается проверить сертификат сервера.</translation>
+<translation id="2925673989565098301">Способ доставки</translation>
<translation id="2928905813689894207">Платежный адрес</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адрес}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адрес}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адреса}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адресов}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> адреса}}</translation>
<translation id="2941952326391522266">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности относится к <ph name="DOMAIN2" />. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Неверный тип политики</translation>
<translation id="3032412215588512954">Обновить эту страницу?</translation>
<translation id="3037605927509011580">Опаньки...</translation>
+<translation id="3039538478787849737">Сохранить карту в Google?</translation>
<translation id="3041612393474885105">Данные сертификата</translation>
<translation id="3063697135517575841">Не удалось подтвердить данные карты. Повторите попытку позже.</translation>
<translation id="3064966200440839136">Вы выйдете из режима инкогнито, чтобы произвести оплату во внешнем приложении. Продолжить?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Временные неполадки на сервере</translation>
<translation id="3154506275960390542">Эта страница содержит форму, которая может быть не защищена. Отправленные вами данные могут быть просмотрены третьими лицами во время передачи, а также могут быть изменены злоумышленником до получения сервером.</translation>
<translation id="3157931365184549694">Восстановить</translation>
+<translation id="3162559335345991374">Возможно, вам нужно перейти на страницу входа сети Wi-Fi.</translation>
<translation id="3167968892399408617">Страницы, открытые в этом окне, не останутся в истории браузера или поиска. Они не оставят на компьютере следов, таких как файлы cookie, после того как вы закроете все вкладки инкогнито. Скачанные вами файлы и добавленные закладки будут сохранены.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Остров</translation>
@@ -286,6 +296,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Отменить оплату</translation>
<translation id="3207960819495026254">Добавлено в закладки</translation>
+<translation id="3211223744486044430">Чтобы ускорить процесс оплаты в будущем, сохраните карту в аккаунте Google и на этом устройстве.</translation>
<translation id="3225919329040284222">Сертификат не соответствует встроенным параметрам определенных сайтов с высоким уровнем безопасности.</translation>
<translation id="3226128629678568754">Чтобы повторно ввести данные, необходимые для загрузки страницы, нажмите "Обновить".</translation>
<translation id="3227137524299004712">Микрофон</translation>
@@ -300,7 +311,6 @@
<translation id="3303855915957856445">Ничего не найдено</translation>
<translation id="3305707030755673451">Данные были зашифрованы с помощью кодовой фразы <ph name="TIME" />. Введите ее, чтобы начать синхронизацию.</translation>
<translation id="3320021301628644560">Добавьте платежный адрес</translation>
-<translation id="3329013043687509092">Насыщенность</translation>
<translation id="333371639341676808">Предотвратить создание дополнительных диалоговых окон на этой странице.</translation>
<translation id="3338095232262050444">Надежный</translation>
<translation id="3340978935015468852">настройках</translation>
@@ -319,6 +329,7 @@
<translation id="3380864720620200369">Идентификатор клиента:</translation>
<translation id="3391030046425686457">Адрес доставки</translation>
<translation id="3395827396354264108">Способ выдачи</translation>
+<translation id="3399952811970034796">Адрес доставки</translation>
<translation id="3422248202833853650">Закройте другие программы, чтобы освободить память.</translation>
<translation id="3422472998109090673">Сайт <ph name="HOST_NAME" /> недоступен.</translation>
<translation id="3427092606871434483">Разрешать (по умолчанию)</translation>
@@ -364,10 +375,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" />: отчет о сбоях сохранен. <ph name="UPLOAD_TIME" />: отчет о сбоях загружен.</translation>
<translation id="3681007416295224113">Данные сертификата</translation>
<translation id="3690164694835360974">Небезопасный вход</translation>
+<translation id="3704162925118123524">Возможно, вам нужно перейти на страницу входа используемой сети.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Загрузка...</translation>
<translation id="3712624925041724820">Недостаточно лицензий</translation>
<translation id="3714780639079136834">Включите Wi-Fi или передачу данных по мобильной сети.</translation>
+<translation id="3715597595485130451">Подключение к Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Проверьте настройки прокси-сервера, брандмауэра и DNS<ph name="END_LINK" />.</translation>
<translation id="3736520371357197498">Если вы готовы подвергнуть риску ваши личные данные, вы можете <ph name="BEGIN_LINK" />перейти на зараженный сайт<ph name="END_LINK" />, не дожидаясь удаления вредоносного ПО.</translation>
<translation id="3739623965217189342">Скопированная ссылка</translation>
@@ -402,6 +415,7 @@
<translation id="4030383055268325496">&amp;Отменить добавление</translation>
<translation id="404928562651467259">Внимание!</translation>
<translation id="4058922952496707368">Ключ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">Введите действительный адрес</translation>
<translation id="4072486802667267160">При обработке заказа произошла ошибка. Повторите попытку.</translation>
<translation id="4075732493274867456">Клиент и сервер поддерживают разные версии протокола SSL или набора шифров.</translation>
<translation id="4079302484614802869">Конфигурация прокси-сервера предусматривает использование URL PAC-скриптов вместо фиксированных прокси-серверов.</translation>
@@ -409,7 +423,6 @@
<translation id="4103249731201008433">Серийный номер устройства недействителен</translation>
<translation id="410351446219883937">Автовоспроизведение</translation>
<translation id="4103763322291513355">Чтобы просмотреть URL, внесенные в черный список, и другие правила, заданные системным администратором, перейдите по адресу: &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
-<translation id="4115378294792113321">Пурпурный</translation>
<translation id="4116663294526079822">Всегда разрешать на этом сайте</translation>
<translation id="4117700440116928470">Область действия правил не поддерживается.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{ещё 1 вариант}one{ещё # вариант}few{ещё # варианта}many{ещё # вариантов}other{ещё # варианта}}</translation>
@@ -447,6 +460,7 @@
<translation id="4377125064752653719">Вы попытались перейти на сайт <ph name="DOMAIN" />, однако сертификат, предоставленный сервером, был отозван издателем. Это означает, что учетные данные безопасности, предоставленные сервером, не заслуживают доверия. Возможно, вы имеете дело со злоумышленниками.</translation>
<translation id="4394049700291259645">Отключить</translation>
<translation id="4406896451731180161">Результаты поиска</translation>
+<translation id="4415426530740016218">Адрес получения</translation>
<translation id="4424024547088906515">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Chrome не доверяет его сертификату безопасности. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
<translation id="4432688616882109544">Ваш сертификат отклонен сайтом <ph name="HOST_NAME" /> или не был выдан.</translation>
<translation id="443673843213245140">Прокси-сервер отключен, но при этом его конфигурация задана явным образом.</translation>
@@ -459,6 +473,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Отключите расширения.</translation>
<translation id="457875822857220463">Доставка</translation>
+<translation id="4582800630050655161">Кто-то посторонний мог получить доступ к вашим личным данным или аккаунту Google. Рекомендуем немедленно сменить пароль.</translation>
<translation id="4587425331216688090">Удалить адрес из Chrome?</translation>
<translation id="4592951414987517459">Соединение с <ph name="DOMAIN" /> зашифровано с помощью современных наборов шифров.</translation>
<translation id="4594403342090139922">&amp;Отменить удаление</translation>
@@ -467,10 +482,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности содержит ошибки. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
<translation id="4690462567478992370">Прекратить использование недействительного сертификата</translation>
+<translation id="4690954380545377795">Кто-то посторонний мог получить доступ к вашим личным данным или аккаунту Google. Рекомендуем немедленно сменить пароль.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Соединение прервано</translation>
<translation id="471880041731876836">Доступ запрещен</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Выполните диагностику сети в Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Ваш платеж</translation>
<translation id="4726672564094551039">Повторно загрузить политики</translation>
<translation id="4728558894243024398">Платформа</translation>
<translation id="4736825316280949806">Перезапустите Chromium.</translation>
@@ -509,6 +526,7 @@
<translation id="5019198164206649151">Данные в хранилище повреждены</translation>
<translation id="5023310440958281426">Проверьте правила, установленные администратором</translation>
<translation id="5029568752722684782">Удалить данные</translation>
+<translation id="503069730517007720">Необходимый корневой сертификат для программы "<ph name="SOFTWARE_NAME" />" не установлен. Чтобы устранить проблему, попросите системного администратора ознакомиться с инструкциями по настройке программы "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">О Переводчике Google</translation>
<translation id="5039804452771397117">Разрешить</translation>
<translation id="5040262127954254034">Личные данные</translation>
@@ -532,6 +550,8 @@
<translation id="5199729219167945352">Экспериментальные функции</translation>
<translation id="5205222826937269299">Введите имя или название</translation>
<translation id="5222812217790122047">Введите адрес электронной почты</translation>
+<translation id="522700295135997067">Через этот сайт могли похитить ваш пароль</translation>
+<translation id="5230733896359313003">Адрес доставки</translation>
<translation id="5251803541071282808">Облако</translation>
<translation id="5277279256032773186">Используете Chrome на работе? Узнайте, как компании могут управлять настройками Chrome на корпоративных устройствах.</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Чтобы временно отключить ПО и установить соединение с Интернетом, следуйте инструкциям ниже. Вам потребуются права администратора.<ph name="END_PARAGRAPH" />
@@ -546,9 +566,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Подключение к веб-сайту не защищено. Чтобы выйти из VR-режима, снимите гарнитуру и нажмите кнопку "Назад".</translation>
<translation id="5299298092464848405">Не удалось выполнить анализ политики</translation>
+<translation id="5308380583665731573">Подключение</translation>
<translation id="5308689395849655368">Отчеты о сбоях отключены.</translation>
<translation id="5317780077021120954">Сохранить</translation>
<translation id="5327248766486351172">Название</translation>
+<translation id="5332219387342487447">Способ доставки</translation>
<translation id="5355557959165512791">Сертификат веб-сайта <ph name="SITE" /> отозван. Открыть сайт в настоящее время нельзя. Сбой мог быть вызван сетевой ошибкой или действиями злоумышленников. Скорее всего, сайт заработает через некоторое время.</translation>
<translation id="536296301121032821">Не удалось сохранить настройки политики</translation>
<translation id="5386426401304769735">В цепочке сертификатов этого сайта есть сертификат, подписанный с помощью алгоритма SHA-1.</translation>
@@ -568,12 +590,15 @@
<translation id="5492298309214877701">Этот сайт в интранете организации или учебного заведения имеет тот же URL, что и сайт в Интернете.
<ph name="LINE_BREAK" />
Обратитесь к системному администратору.</translation>
+<translation id="5499929369096410817">Введите защитный код для карты <ph name="CREDIT_CARD" />. Он не будет сохранен.</translation>
<translation id="5509780412636533143">Управляемые закладки</translation>
<translation id="5510766032865166053">Возможно, он был перемещен или удален.</translation>
<translation id="5523118979700054094">Название правила</translation>
<translation id="552553974213252141">Правильно ли извлечен текст?</translation>
<translation id="5540224163453853">Не удалось найти указанную статью</translation>
+<translation id="5541546772353173584">Добавьте адрес электронной почты</translation>
<translation id="5544037170328430102">Подтвердите действие на <ph name="SITE" />:</translation>
+<translation id="5545756402275714221">Новости для вас</translation>
<translation id="5556459405103347317">Перезагрузить</translation>
<translation id="5560088892362098740">Дата окончания срока действия</translation>
<translation id="5565735124758917034">Активен</translation>
@@ -595,6 +620,7 @@
<translation id="5659593005791499971">Электронная почта</translation>
<translation id="5669703222995421982">Получение персонализированного контента</translation>
<translation id="5675650730144413517">Страница недоступна</translation>
+<translation id="5689199277474810259">Экспортировать как JSON</translation>
<translation id="5710435578057952990">Идентификационные данные этого сайта не проверены.</translation>
<translation id="5719499550583120431">Принимаются карты предоплаты.</translation>
<translation id="5720705177508910913">Текущий пользователь</translation>
@@ -609,27 +635,27 @@
<translation id="5810442152076338065">Соединение с <ph name="DOMAIN" /> зашифровано с помощью устаревшего набора шифров.</translation>
<translation id="5813119285467412249">&amp;Повторить добавление</translation>
<translation id="5838278095973806738">Не сообщайте этому сайту конфиденциальную информацию (например, пароли и номера банковских карт). К ней могут получить доступ злоумышленники.</translation>
+<translation id="5866257070973731571">Добавьте номер телефона</translation>
<translation id="5869405914158311789">Не удается получить доступ к сайту</translation>
<translation id="5869522115854928033">Сайты с сохраненными паролями</translation>
<translation id="5872918882028971132">Подсказки для родительских элементов</translation>
<translation id="5893752035575986141">Принимаются кредитные карты.</translation>
-<translation id="5901630391730855834">Желтый</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (данные синхронизируются)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Используется 1 файл cookie}one{Используется # файл cookie}few{Используется # файла cookie}many{Используется # файлов cookie}other{Используется # файла cookie}}</translation>
<translation id="5959728338436674663">Автоматически отправлять <ph name="BEGIN_WHITEPAPER_LINK" />системную информацию и контент страниц<ph name="END_WHITEPAPER_LINK" /> в Google, чтобы улучшить распознавание опасных приложений и сайтов. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Измените контактную информацию</translation>
<translation id="5967867314010545767">Удалить из истории</translation>
<translation id="5975083100439434680">Уменьшить</translation>
+<translation id="597552863672748783">Подтвердите защитный код</translation>
<translation id="598637245381783098">Не удалось открыть Payments</translation>
<translation id="5989320800837274978">Ни фиксированные прокси-серверы, ни URL PAC-скриптов не указаны.</translation>
<translation id="5990559369517809815">Расширение заблокировало отправку запроса на сервер.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Страница 1}one{Страница #}few{Страница #}many{Страница #}other{Страница #}}</translation>
-<translation id="6017514345406065928">Зеленый</translation>
<translation id="6017850046339264347">Злоумышленники могут использовать сайт <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (данные синхронизируются)</translation>
<translation id="6027201098523975773">Введите имя.</translation>
<translation id="6040143037577758943">Закрыть</translation>
-<translation id="6042308850641462728">Подробнее...</translation>
<translation id="6047233362582046994">Если вы осознаете, что можете подвергнуть риску свои личные данные, то можете <ph name="BEGIN_LINK" />перейти на зараженный сайт<ph name="END_LINK" />, не дожидаясь удаления вредоносных приложений.</translation>
<translation id="6047927260846328439">Посещение этой страницы может привести к установке вредоносной программы или хищению вашей личной информации. <ph name="BEGIN_LINK" />Все равно продолжить<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Веб-сайт <ph name="SITE" /> использует механизм Certificate Pinning, поэтому на нем могла произойти подмена сертификата. Открыть сайт в настоящее время нельзя. Сбой мог быть вызван сетевой ошибкой или действиями злоумышленников. Скорее всего, сайт заработает через некоторое время.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">Вы просматриваете страницу расширения</translation>
<translation id="6596325263575161958">Параметры шифрования</translation>
<translation id="662080504995468778">Остаться</translation>
+<translation id="6624427990725312378">Контактная информация</translation>
<translation id="6626291197371920147">Введите номер действующей карты</translation>
<translation id="6628463337424475685">Поиск <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Сайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> может установить на ваш компьютер Mac вредоносное ПО, которое крадет или удаляет личную информацию (например, фотографии, пароли, сообщения и реквизиты банковских карт). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">Назад</translation>
<translation id="6710594484020273272">&lt;Введите поисковый запрос&gt;</translation>
<translation id="6711464428925977395">На прокси-сервере возникла проблема или адрес указан неверно.</translation>
-<translation id="6727102863431372879">Установить</translation>
<translation id="674375294223700098">Неизвестная ошибка сертификата сервера.</translation>
<translation id="6753269504797312559">Значение правила</translation>
<translation id="6757797048963528358">Устройство находится в спящем режиме.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Путь к профилю</translation>
<translation id="7424977062513257142">Подтвердите действие:</translation>
+<translation id="7437289804838430631">Добавить контактные данные</translation>
<translation id="7441627299479586546">Неверный субъект политики</translation>
<translation id="7444046173054089907">Сайт заблокирован</translation>
<translation id="7445762425076701745">Идентификация сервера, к которому вы подключились, не может быть полностью подтверждена. Вы подключились к серверу, используя название, которое действительно только в вашей сети; владелец этого сервера не может быть проверен или подтвержден внешним центром сертификации. Так как некоторые центры сертификации могут выдавать сертификаты для подобных названий, отсутствуют гарантии в том, что это действительно нужный вам сайт, а не сайт злоумышленника.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">Вперед</translation>
<translation id="7485870689360869515">Данные не найдены.</translation>
<translation id="7508255263130623398">Возвращенный идентификатор устройства пуст или не соответствует имеющемуся</translation>
+<translation id="7511955381719512146">Возможно, вам нужно перейти на страницу <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> сети Wi-Fi.</translation>
<translation id="7514365320538308">Скачать</translation>
<translation id="7518003948725431193">Не найдена страница для веб-адреса <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Подключение к сайту не защищено</translation>
-<translation id="7535087603100972091">Значение</translation>
<translation id="7537536606612762813">Обязательная</translation>
<translation id="7542403920425041731">После этого данные вашей карты будут переданы сайту.</translation>
<translation id="7542995811387359312">Автозаполнение отключено – незащищенное подключение.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Его сертификат безопасности мог быть выдан обманным путем. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
<translation id="7568593326407688803">Язык этой страницы<ph name="ORIGINAL_LANGUAGE" />Хотите перевести ее?</translation>
<translation id="7569952961197462199">Удалить кредитную карту из Chrome?</translation>
-<translation id="7569983096843329377">Черный</translation>
<translation id="7578104083680115302">Быстро оплачивайте покупки на сайтах и в приложениях с помощью карт, сохраненных в Google Payments. Настройка будет действовать на всех ваших устройствах.</translation>
<translation id="7588950540487816470">Интернет вокруг нас</translation>
<translation id="7592362899630581445">Сертификат сервера не соответствует ограничениям в отношении имен.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">Посещение этого сайта может привести к установке вредоносного ПО, которое будет мешать работе браузера (например, меняя стартовую страницу или показывая дополнительную рекламу на сайтах).</translation>
<translation id="7674629440242451245">Хотите быть в курсе новинок Chrome? Выберите канал обновления для разработчиков на странице "chrome.com/dev".</translation>
<translation id="7682287625158474539">Адрес доставки</translation>
+<translation id="7699293099605015246">Статьи пока недоступны</translation>
<translation id="7701040980221191251">Нет</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Перейти на сайт <ph name="SITE" /> (небезопасно)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Сертификат</translation>
<translation id="7716147886133743102">Заблокировано администратором</translation>
<translation id="7716424297397655342">Не удалось загрузить сайт из кеша</translation>
+<translation id="7723047071702270851">Измените данные карты</translation>
<translation id="774634243536837715">Опасный контент заблокирован</translation>
<translation id="7752995774971033316">Не управляется</translation>
<translation id="7755287808199759310">Для разблокировки обратитесь к родителю.</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">Добавить адрес</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Добавить</translation>
+<translation id="7793553086574152071">Чтобы ускорить процесс оплаты в будущем, сохраните карту в аккаунте Google.</translation>
<translation id="7793809570500803535">Веб-страница по адресу <ph name="SITE" />, возможно, временно недоступна или перемещена на новый адрес.</translation>
<translation id="7800304661137206267">Соединение зашифровано с помощью <ph name="CIPHER" />, для аутентификации сообщений используется <ph name="MAC" />, для обмена ключами используется <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Сайт безопасен</translation>
<translation id="780301667611848630">Спасибо, не надо</translation>
<translation id="7805768142964895445">Состояние</translation>
<translation id="7812922009395017822">Мир</translation>
<translation id="7813600968533626083">Удалить подсказку из Chrome?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> по запросу "<ph name="SEARCH_STRING" />" (<ph name="NUMBER_OF_RESULTS" />)</translation>
+<translation id="782886543891417279">Возможно, вам нужно перейти на страницу входа сети Wi-Fi (<ph name="WIFI_NAME" />).</translation>
<translation id="785549533363645510">Тем не менее ваши действия будут видны системному администратору и интернет-провайдеру, а также доступны веб-сайтам, которые вы посещаете.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Принимаются дебетовые карты и карты предоплаты.</translation>
+<translation id="7878562273885520351">Злоумышленники могли узнать ваш пароль</translation>
<translation id="7887683347370398519">Проверьте CVC-код и повторите попытку</translation>
<translation id="79338296614623784">Укажите действительный номер телефона.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификат сервера еще не действителен.</translation>
-<translation id="7942349550061667556">Красный</translation>
<translation id="7947285636476623132">Проверьте год в сроке действия карты и повторите попытку</translation>
<translation id="7951415247503192394">(32 бит)</translation>
<translation id="7956713633345437162">Закладки на мобильном</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">Спрашивать (по умолчанию)</translation>
<translation id="8041089156583427627">Отправить отзыв</translation>
<translation id="8041940743680923270">Использовать глобальный параметр по умолчанию (спрашивать)</translation>
+<translation id="8057711352706143257">Программа "<ph name="SOFTWARE_NAME" />" настроена неправильно. Чтобы устранить проблему, удалите программу "<ph name="SOFTWARE_NAME" />". <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Не удалось показать статью</translation>
<translation id="8091372947890762290">Активация управления устройствами не завершена</translation>
+<translation id="8094917007353911263">Возможно, вам нужно перейти на страницу <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> используемой сети.</translation>
+<translation id="8103161714697287722">Способ оплаты</translation>
<translation id="8118489163946903409">Способ оплаты</translation>
+<translation id="8127301229239896662">Программа "<ph name="SOFTWARE_NAME" />" была установлена неправильно. Обратитесь за помощью к системному администратору.</translation>
<translation id="8131740175452115882">Подтвердить</translation>
<translation id="8134994873729925007">Не удается найти <ph name="BEGIN_ABBR" />DNS-адрес<ph name="END_ABBR" /> сервера <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ваш компьютер перешел в спящий режим.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">Уточните информацию у администратора сети.</translation>
<translation id="8293206222192510085">Добавление закладки</translation>
<translation id="8294431847097064396">Источник</translation>
+<translation id="8298115750975731693">Возможно, вам нужно перейти на страницу <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> сети Wi-Fi (<ph name="WIFI_NAME" />).</translation>
<translation id="8306404619377842860">Не удалось установить защищенное соединение с доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-за неверных настроек системных часов и календаря (<ph name="DATE_AND_TIME" />). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Перевод не завершен из-за проблем с сетевым подключением.</translation>
<translation id="8332188693563227489">Доступ к <ph name="HOST_NAME" /> запрещен</translation>
@@ -939,20 +975,21 @@
<translation id="8870413625673593573">Недавно закрытые</translation>
<translation id="8874824191258364635">Введите действительный номер карты.</translation>
<translation id="8876793034577346603">Не удалось выполнить анализ конфигурации сети.</translation>
-<translation id="8889402386540077796">Тон</translation>
<translation id="8891727572606052622">Недопустимый режим работы прокси-сервера.</translation>
<translation id="889901481107108152">К сожалению, данное действие невозможно выполнить на этой платформе.</translation>
<translation id="8903921497873541725">Увеличить</translation>
<translation id="8931333241327730545">Сохранить эту карту в аккаунте Google?</translation>
<translation id="8932102934695377596">Часы отстают</translation>
+<translation id="893332455753468063">Добавьте имя</translation>
<translation id="8938939909778640821">Кредитные карты и карты предоплаты, которые принимаются к оплате</translation>
+<translation id="8957210676456822347">Авторизация через адаптивный портал</translation>
<translation id="8971063699422889582">Сертификат сервера устарел.</translation>
-<translation id="8986494364107987395">Автоматически отправлять в Google статистику использования и отчеты о сбоях</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Сайт содержит нежелательное ПО</translation>
<translation id="8997023839087525404">Предоставленный сервером сертификат не проходил проверку безопасности. Она необходима в некоторых случаях, чтобы доказать, что сертификат надежен и защищает от злоумышленников.</translation>
<translation id="9001074447101275817">Для доступа на прокси-сервер <ph name="DOMAIN" /> требуется указать имя пользователя и пароль.</translation>
<translation id="9005998258318286617">Не удалось загрузить PDF-документ.</translation>
+<translation id="9008201768610948239">Пропустить</translation>
<translation id="901974403500617787">Системные флаги может устанавливать только владелец (<ph name="OWNER_EMAIL" />).</translation>
<translation id="9020200922353704812">Необходимо указать платежный адрес карты</translation>
<translation id="9020542370529661692">Эта страница переведена на <ph name="TARGET_LANGUAGE" />.</translation>
@@ -962,11 +999,14 @@
<translation id="9049981332609050619">Вы попытались открыть <ph name="DOMAIN" />, однако представленный сервером сертификат недействителен.</translation>
<translation id="9050666287014529139">Кодовая фраза</translation>
<translation id="9065203028668620118">Изменить</translation>
-<translation id="9068849894565669697">Выберите цвет</translation>
<translation id="9069693763241529744">Заблокировано расширением</translation>
<translation id="9076283476770535406">Может содержать контент для взрослых</translation>
<translation id="9078964945751709336">Информации недостаточно</translation>
+<translation id="9080712759204168376">Информация о заказе</translation>
<translation id="9103872766612412690">На сайте <ph name="SITE" /> для защиты ваших данных обычно используется шифрование. Однако учетные данные, которые мы получили от сайта <ph name="SITE" /> сейчас, отличаются от тех, которые он отправляет обычно. Вероятно, вредоносный сайт пытается выдать себя за <ph name="SITE" />, либо страница подключения к сети Wi-Fi прервала соединение. Ваша информация по-прежнему в безопасности, так как браузер Chromium разорвал соединение до того, как произошел обмен данными.</translation>
+<translation id="9106062320799175032">Добавьте платежный адрес</translation>
+<translation id="910908805481542201">Получить помощь</translation>
+<translation id="9128870381267983090">Подключиться к сети</translation>
<translation id="9137013805542155359">Показать оригинал</translation>
<translation id="9137248913990643158">Войдите в Chrome, прежде чем использовать это приложение.</translation>
<translation id="9148507642005240123">&amp;Отменить изменения</translation>
@@ -978,6 +1018,7 @@
<translation id="9183425211371246419">На сайте <ph name="HOST_NAME" /> используется неподдерживаемый протокол.</translation>
<translation id="9205078245616868884">Данные зашифрованы с помощью кодовой фразы. Введите ее, чтобы начать синхронизацию.</translation>
<translation id="9207861905230894330">Не удалось добавить статью</translation>
+<translation id="9215416866750762878">Приложение не позволяет Chrome безопасно подключиться к этому сайту</translation>
<translation id="9219103736887031265">Картинки</translation>
<translation id="933612690413056017">Нет подключения к Интернету</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -987,5 +1028,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Нет}=1{1 запись}one{# запись}few{# записи}many{# записей}other{# записи}}</translation>
<translation id="981121421437150478">Офлайн</translation>
<translation id="988159990683914416">Сборка для разработчиков</translation>
+<translation id="989988560359834682">Изменение адреса</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Программа "<ph name="SOFTWARE_NAME" />" была установлена неправильно.
+ &lt;ul&gt;
+ &lt;li&gt;Попробуйте удалить или отключить программу "<ph name="SOFTWARE_NAME" />".&lt;/li&gt;
+ &lt;li&gt;Попробуйте подключиться к другой сети.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index c2b871d13c3..2cb4625ed2f 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Záložky v počítači</translation>
<translation id="1074497978438210769">Nezabezpečené</translation>
<translation id="1080116354587839789">Prispôsobiť šírke</translation>
+<translation id="1088860948719068836">Pridanie mena na karte</translation>
<translation id="1103523840287552314">Vždy preložiť nasledujúci jazyk: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Zobraziť všetky uložené heslá…</translation>
<translation id="1107591249535594099">Ak je toto nastavenie začiarknuté, Chrome uloží kópiu karty na toto zariadenie, aby ste mohli vypĺňať formuláre rýchlejšie.</translation>
<translation id="1111153019813902504">Najnovšie záložky</translation>
<translation id="1113869188872983271">&amp;Vrátiť späť zmenu poradia</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synchronizované)</translation>
<translation id="1263231323834454256">Čitateľský zoznam</translation>
<translation id="1264126396475825575">Správa o zlyhaní bola zaznamenaná v čase <ph name="CRASH_TIME" /> (ešte nebola nahraná ani ignorovaná)</translation>
+<translation id="1270502636509132238">Spôsob vyzdvihnutia</translation>
<translation id="1281526147609854549">Vydavateľ: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nikdy neprekladať tieto webové stránky</translation>
<translation id="129553762522093515">Naposledy zatvorené</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Čaká sa na pripojenie...</translation>
<translation id="153384715582417236">To je zatiaľ všetko</translation>
<translation id="1549470594296187301">Ak chcete použiť túto funkciu, musíte povoliť JavaScript.</translation>
-<translation id="1555130319947370107">Modrá</translation>
<translation id="1559528461873125649">Neexistuje žiadny takýto súbor ani priečinok</translation>
<translation id="1583429793053364125">Pri zobrazovaní tejto webovej stránky sa vyskytla chyba.</translation>
<translation id="1592005682883173041">Prístup k miestnym údajom</translation>
<translation id="1594030484168838125">Zvoliť</translation>
-<translation id="161042844686301425">Azúrová</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Chcete, aby Chrome uložil túto kartu?</translation>
<translation id="1639239467298939599">Prebieha načítavanie</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Ak chcete navštíviť tento web, potrebujete povolenie od správcu <ph name="NAME" /></translation>
<translation id="1721424275792716183">* Toto pole je povinné</translation>
+<translation id="1727741090716970331">Pridanie platného čísla karty</translation>
<translation id="1728677426644403582">Prezeráte si zdrojový kód webovej stránky</translation>
<translation id="173080396488393970">Tento typ karty nie je podporovaný</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Chyba serializácie</translation>
<translation id="1974060860693918893">Rozšírené</translation>
<translation id="1978555033938440688">Verzia firmvéru</translation>
-<translation id="1995859865337580572">Overte svoje číslo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{a 1 ďalšia}few{a # ďalšie}many{a # ďalšej}other{a # ďalších}}</translation>
<translation id="2025186561304664664">Proxy je nastavené na automatickú konfiguráciu.</translation>
<translation id="2030481566774242610">Mysleli ste stránku <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Ak chcete získavať prispôsobený obsah navrhnutý Googlom, prihláste sa do Chromu.</translation>
+<translation id="2091887806945687916">Zvuk</translation>
<translation id="2094505752054353250">Domény sa nezhodujú</translation>
<translation id="2096368010154057602">Správna oblasť</translation>
<translation id="2108755909498034140">Reštartujte počítač</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignorované, pretože bolo prepísané pravidlom <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Vyhľadávajú sa stránky Fyzického webu v okolí</translation>
<translation id="213826338245044447">Záložky v mobile</translation>
+<translation id="214556005048008348">Zrušiť platbu</translation>
<translation id="2147827593068025794">Synchronizácia na pozadí</translation>
+<translation id="2148613324460538318">Pridať kartu</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="2166049586286450108">Úplný prístup správcu</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adries}}</translation>
<translation id="2187317261103489799">Rozpoznávať (predvolené)</translation>
<translation id="2202020181578195191">Zadajte platný rok vypršania platnosti</translation>
+<translation id="2209523182407020534">Medzi aplikácie, ktoré môžu túto chybu spôsobiť, patria okrem iných antivírusové programy, brány firewall, softvér na filtrovanie webu alebo proxy softvér.</translation>
<translation id="2212735316055980242">Pravidlo sa nenašlo</translation>
<translation id="2213606439339815911">Načítavanie záznamov...</translation>
<translation id="2218879909401188352">Útočníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> by mohli nainštalovať nebezpečné aplikácie, ktoré poškodia vaše zariadenia, pridať skryté poplatky do vašej faktúry za mobilné služby alebo ukradnúť vaše osobné informácie. <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Prejsť späť</translation>
<translation id="2503184589641749290">Akceptované debetné a predplatené karty</translation>
<translation id="2515629240566999685">Skontrolovať signál vo vašej oblasti</translation>
+<translation id="2524461107774643265">Pridanie ďalších informácií</translation>
+<translation id="2536110899380797252">Pridať adresu</translation>
<translation id="2539524384386349900">Rozpoznávať</translation>
<translation id="255002559098805027">Web <ph name="HOST_NAME" /> odoslal neplatnú odpoveď.</translation>
<translation id="2556876185419854533">&amp;Vrátiť späť úpravu</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Prehliadaču Chromium sa nepodarilo overiť vašu kartu. Skúste to znova neskôr.</translation>
<translation id="2705137772291741111">Uložená kópia tohto webu (vo vyrovnávacej pamäti) bola nečitateľná.</translation>
<translation id="2709516037105925701">Automatické dopĺňanie</translation>
+<translation id="2710942282213947212">Softvér vo vašom počítači bráni prehliadaču Chromium bezpečne sa pripojiť k webu</translation>
<translation id="2712173769900027643">Požiadať o povolenie</translation>
-<translation id="2713444072780614174">Biela</translation>
<translation id="2720342946869265578">Nablízku</translation>
<translation id="2721148159707890343">Žiadosť bola úspešná</translation>
<translation id="2728127805433021124">Certifikát servera je podpísaný pomocou slabého podpisového algoritmu.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Zistila sa zmena siete.</translation>
<translation id="2916038427272391327">Zavrite ostatné programy</translation>
<translation id="2922350208395188000">Certifikát servera sa nedá overiť.</translation>
+<translation id="2925673989565098301">Spôsob doručenia</translation>
<translation id="2928905813689894207">Fakturačná adresa</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšia}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšie}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalšej}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> ďalších}}</translation>
<translation id="2941952326391522266">Server nedokáže overiť, či ide o doménu <ph name="DOMAIN" />, jej bezpečnostný certifikát pochádza z domény <ph name="DOMAIN2" />. Môže to byť spôsobené nesprávnou konfiguráciou alebo tým, že vaše pripojenie zachytil útočník.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Chybný typ pravidla</translation>
<translation id="3032412215588512954">Chcete tento web načítať znova?</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
+<translation id="3039538478787849737">Uložiť kartu do Googlu?</translation>
<translation id="3041612393474885105">Informácie o certifikáte</translation>
<translation id="3063697135517575841">Chromu sa nepodarilo overiť vašu kartu. Skúste to znova neskôr.</translation>
<translation id="3064966200440839136">Ak zaplatíte pomocou externej aplikácie, opustíte režim inkognito. Chcete pokračovať?</translation>
@@ -278,12 +287,14 @@
<translation id="3150653042067488994">Dočasná chyba servera</translation>
<translation id="3154506275960390542">Táto stránka obsahuje formulár, ktorý zrejme nebude možné bezpečne odoslať. Odoslané dáta si môžu pri prenose zobraziť iní používatelia a prípadný útočník ich môže zmeniť. Server preto môže prijať niečo iné, než ste odoslali.</translation>
<translation id="3157931365184549694">Obnoviť</translation>
+<translation id="3162559335345991374">Sieť Wi‑Fi, ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku</translation>
<translation id="3167968892399408617">Keď zavriete všetky karty inkognito, po stránkach, ktoré ste na nich zobrazili, nezostane v histórii prehliadania, úložisku súborov cookie a histórii vyhľadávania ani stopa. Všetky stiahnuté súbory a vytvorené záložky zostanú zachované.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ostrov</translation>
<translation id="3176929007561373547">Skontrolujte nastavenia proxy servera alebo kontaktujte správcu siete a požiadajte ho, aby skontroloval, či proxy server funguje. Ak sa domnievate, že by ste nemali používať proxy server: <ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Zrušiť platbu</translation>
<translation id="3207960819495026254">Pridané medzi záložky</translation>
+<translation id="3211223744486044430">Ak chcete nabudúce zaplatiť rýchlejšie, uložte si túto kartu do účtu Google a tohto zariadenia.</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>
<translation id="3226128629678568754">Stlačením tlačidla opakovaného spustenia znova odošlete údaje potrebné na načítanie stránky.</translation>
<translation id="3227137524299004712">Mikrofón</translation>
@@ -298,7 +309,6 @@
<translation id="3303855915957856445">Nenašli sa žiadne výsledky vyhľadávania</translation>
<translation id="3305707030755673451">Vaše údaje boli <ph name="TIME" /> zašifrované pomocou vlastnej prístupovej frázy synchronizácie. Keď ju zadáte, synchronizácia sa spustí.</translation>
<translation id="3320021301628644560">Pridanie fakturačnej adresy</translation>
-<translation id="3329013043687509092">Sýtosť</translation>
<translation id="333371639341676808">Zakázať tejto stránke otvárať ďalšie dialógové okná.</translation>
<translation id="3338095232262050444">Zabezpečené</translation>
<translation id="3340978935015468852">nastavenia</translation>
@@ -317,6 +327,7 @@
<translation id="3380864720620200369">ID klienta:</translation>
<translation id="3391030046425686457">Doručovacia adresa</translation>
<translation id="3395827396354264108">Spôsob vyzdvihnutia</translation>
+<translation id="3399952811970034796">Doručovacia adresa</translation>
<translation id="3422248202833853650">Skúste ukončiť ostatné programy a uvoľniť tak miesto v pamäti.</translation>
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> nie je momentálne k dispozícii.</translation>
<translation id="3427092606871434483">Povoliť (predvolené)</translation>
@@ -361,10 +372,12 @@
<translation id="3679803492151881375">Správa o zlyhaní zaznamenaná v čase <ph name="CRASH_TIME" /> bola nahraná o <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informácie o certifikáte</translation>
<translation id="3690164694835360974">Prihlásenie nie je zabezpečené</translation>
+<translation id="3704162925118123524">Sieť, ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Načítava sa...</translation>
<translation id="3712624925041724820">Vyčerpané licencie</translation>
<translation id="3714780639079136834">Zapnúť mobilné dáta alebo Wi‑Fi</translation>
+<translation id="3715597595485130451">Pripojenie k sieti Wi‑Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Skontrolovať proxy server, bránu firewall a konfiguráciu DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Ak si uvedomujete bezpečnostné riziko, môžete <ph name="BEGIN_LINK" />tieto nebezpečné stránky navštíviť<ph name="END_LINK" /> ešte skôr, ako budú nebezpečné programy odstránené.</translation>
<translation id="3739623965217189342">Skopírovaný odkaz</translation>
@@ -399,6 +412,7 @@
<translation id="4030383055268325496">&amp;Vrátiť späť pridanie</translation>
<translation id="404928562651467259">UPOZORNENIE</translation>
<translation id="4058922952496707368">Kľúč <ph name="SUBKEY" />: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfigurácia proxy je nastavená na použitie skriptu PAC webovej adresy, nie pevne daných serverov proxy.</translation>
@@ -406,7 +420,6 @@
<translation id="4103249731201008433">Sériové číslo zariadenia je neplatné</translation>
<translation id="410351446219883937">Automatické prehrávanie</translation>
<translation id="4103763322291513355">Na stránke &lt;strong&gt;chrome://policy&lt;/strong&gt; nájdete zoznam zakázaných webových adries a ďalšie pravidlá vynútené vaším správcom systému.</translation>
-<translation id="4115378294792113321">Purpurová</translation>
<translation id="4116663294526079822">Vždy povoliť na tomto webe</translation>
<translation id="4117700440116928470">Rozsah pravidla nie je podporovaný.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 ďalšia}few{# ďalšie}many{# ďalšej}other{# ďalších}}</translation>
@@ -444,6 +457,7 @@
<translation id="4377125064752653719">Pokúsili ste sa o prístup na stránky <ph name="DOMAIN" />, avšak certifikát poskytnutý serverom bol vydavateľom zrušený. Znamená to, že povereniam zabezpečenia, ktoré predložil server, sa celkom nedá dôverovať. Je možné, že komunikujete s útočníkom.</translation>
<translation id="4394049700291259645">Zakázať</translation>
<translation id="4406896451731180161">výsledky vyhľadávania</translation>
+<translation id="4415426530740016218">Adresa vyzdvihnutia</translation>
<translation id="4424024547088906515">Server nedokáže overiť, či ide o doménu <ph name="DOMAIN" />, Chrome nedôveruje jej bezpečnostnému certifikátu. Môže to byť spôsobené nesprávnou konfiguráciou alebo tým, že vaše pripojenie zachytil útočník.</translation>
<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> neakceptoval váš prihlasovací certifikát alebo nebol žiadny poskytnutý.</translation>
<translation id="443673843213245140">Použitie servera proxy je zakázané, ale je určená explicitná konfigurácia servera proxy.</translation>
@@ -456,6 +470,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Skúste deaktivovať rozšírenia.</translation>
<translation id="457875822857220463">Doručenie</translation>
+<translation id="4582800630050655161">Môžete stratiť prístup do účtu Google alebo vám môže ukradnúť identitu. Chromium odporúča, aby ste si ihneď zmenili heslo.</translation>
<translation id="4587425331216688090">Chcete adresu odstrániť z prehliadača Chrome?</translation>
<translation id="4592951414987517459">Vaše pripojenie k doméne <ph name="DOMAIN" /> je šifrované pomocou modernej šifrovacej súpravy.</translation>
<translation id="4594403342090139922">&amp;Vrátiť späť odstránenie</translation>
@@ -464,10 +479,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Nepoužívať neplatné certifikáty</translation>
+<translation id="4690954380545377795">Môžete stratiť prístup do účtu Google alebo vám môže ukradnúť identitu. Chrome odporúča, aby ste si ihneď zmenili heslo.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Pripojenie bolo prerušené</translation>
<translation id="471880041731876836">Nemáte povolenie na návštevu tohto webu</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Spustiť nástroj Diagnostika siete systému Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Vaša platba</translation>
<translation id="4726672564094551039">Znova načítať pravidlá</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4736825316280949806">Reštartujte Chromium</translation>
@@ -506,6 +523,7 @@
<translation id="5019198164206649151">Zlý stav záložného ukladacieho priestoru</translation>
<translation id="5023310440958281426">Skontrolujte pravidlá správcu</translation>
<translation id="5029568752722684782">Vymazať kópiu</translation>
+<translation id="503069730517007720">Vyžaduje sa koreňový certifikát softvéru <ph name="SOFTWARE_NAME" />, ale nie je nainštalovaný. Váš správca IT by si mal prezrieť pokyny na konfiguráciu softvéru <ph name="SOFTWARE_NAME" /> a tento problém vyriešiť. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">O službe Prekladač Google</translation>
<translation id="5039804452771397117">Povoliť</translation>
<translation id="5040262127954254034">Ochrana súkromia</translation>
@@ -529,6 +547,8 @@
<translation id="5199729219167945352">Experimenty</translation>
<translation id="5205222826937269299">Meno je povinný údaj</translation>
<translation id="5222812217790122047">E-mailová adresa je povinný údaj</translation>
+<translation id="522700295135997067">Tento web možno práve ukradol vaše heslo</translation>
+<translation id="5230733896359313003">Dodacia adresa</translation>
<translation id="5251803541071282808">Cloud</translation>
<translation id="5277279256032773186">Používate Chrome v práci? Firmy môžu spravovať nastavenia prehliadača Chrome pre svojich zamestnancov. Ďalšie informácie</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Postupujte podľa týchto krokov a softvér dočasne zakážte, aby ste mohli prejsť na daný web. Budete potrebovať oprávnenia správcu.<ph name="END_PARAGRAPH" />
@@ -543,9 +563,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Vaše pripojenie k týmto stránkam nie je súkromné. Režim VR môžete kedykoľvek ukončiť, stačí odpojiť náhlavnú súpravu a stlačiť možnosť Späť.</translation>
<translation id="5299298092464848405">Pri analýze pravidla sa vyskytla chyba</translation>
+<translation id="5308380583665731573">Pripojenie</translation>
<translation id="5308689395849655368">Hlásenie zlyhaní je zakázané.</translation>
<translation id="5317780077021120954">Uložiť</translation>
<translation id="5327248766486351172">Názov</translation>
+<translation id="5332219387342487447">Spôsob dodania</translation>
<translation id="5355557959165512791">Web <ph name="SITE" /> momentálne nemôžete navštíviť, pretože tento certifikát bol odvolaný. Chyby siete a útoky sú zvyčajne dočasné, takže by táto stránka mala neskôr pravdepodobne fungovať.</translation>
<translation id="536296301121032821">Nastavenia pravidla sa nepodarilo uložiť</translation>
<translation id="5386426401304769735">Reťazec certifikátu pre tento web obsahuje certifikát podpísaný pomocou funkcie SHA-1.</translation>
@@ -565,12 +587,15 @@
<translation id="5492298309214877701">Tento web v intranete danej spoločnosti, organizácie či školy má rovnakú webovú adresu ako externý web.
<ph name="LINE_BREAK" />
Skúste kontaktovať správcu systému.</translation>
+<translation id="5499929369096410817">Zadajte bezpečnostný kód karty <ph name="CREDIT_CARD" />. Tento kód sa neuloží.</translation>
<translation id="5509780412636533143">Spravované záložky</translation>
<translation id="5510766032865166053">Mohol byť prenesený alebo odstránený.</translation>
<translation id="5523118979700054094">Názov pravidla</translation>
<translation id="552553974213252141">Bol text vyňatý správne?</translation>
<translation id="5540224163453853">Požadovaný článok sa nepodarilo nájsť.</translation>
+<translation id="5541546772353173584">Pridanie e-mailu</translation>
<translation id="5544037170328430102">Vložená stránka na webe <ph name="SITE" /> hovorí:</translation>
+<translation id="5545756402275714221">Články pre vás</translation>
<translation id="5556459405103347317">Obnoviť</translation>
<translation id="5560088892362098740">Dátum vypršania platnosti</translation>
<translation id="5565735124758917034">Aktívne</translation>
@@ -592,6 +617,7 @@
<translation id="5659593005791499971">E-mail</translation>
<translation id="5669703222995421982">Ako získať prispôsobený obsah</translation>
<translation id="5675650730144413517">Táto stránka nefunguje</translation>
+<translation id="5689199277474810259">Exportovať vo formáte JSON</translation>
<translation id="5710435578057952990">Identita tejto webovej stránky nebola overená.</translation>
<translation id="5719499550583120431">Predplatené karty sú akceptované.</translation>
<translation id="5720705177508910913">Aktuálny používateľ</translation>
@@ -606,27 +632,27 @@
<translation id="5810442152076338065">Vaše pripojenie k doméne <ph name="DOMAIN" /> je šifrované pomocou zastaranej šifrovacej súpravy.</translation>
<translation id="5813119285467412249">&amp;Znova pridať</translation>
<translation id="5838278095973806738">Na tomto webe by ste nemali zadávať citlivé informácie (napríklad heslá alebo kreditné karty), pretože by ich mohli ukradnúť útočníci.</translation>
+<translation id="5866257070973731571">Pridanie telefónneho čísla</translation>
<translation id="5869405914158311789">K tomuto webu sa nedá pripojiť</translation>
<translation id="5869522115854928033">Uložené heslá</translation>
<translation id="5872918882028971132">Návrhy rodiča</translation>
<translation id="5893752035575986141">Kreditné karty sú akceptované.</translation>
-<translation id="5901630391730855834">Žltá</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronizované)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Používa sa 1}few{Používajú sa #}many{Používa sa #}other{Používa sa #}}</translation>
<translation id="5959728338436674663">Automaticky odosielať <ph name="BEGIN_WHITEPAPER_LINK" />niektoré informácie o systéme a obsah stránok<ph name="END_WHITEPAPER_LINK" /> do Googlu s cieľom pomôcť rozpoznávať nebezpečné aplikácie a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Úprava kontaktných informácií</translation>
<translation id="5967867314010545767">Odstrániť z histórie</translation>
<translation id="5975083100439434680">Oddialiť</translation>
+<translation id="597552863672748783">Potvrdenie bezpečnostného kódu</translation>
<translation id="598637245381783098">Nie je možné otvoriť platobnú aplikáciu</translation>
<translation id="5989320800837274978">Nie sú určené pevne dané servery proxy ani skript PAC webovej adresy.</translation>
<translation id="5990559369517809815">Žiadosti odoslané serveru boli zablokované rozšírením.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Strana 1}few{Strana #}many{Strana #}other{Strana #}}</translation>
-<translation id="6017514345406065928">Zelená</translation>
<translation id="6017850046339264347">Útočníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> by mohli nainštalovať klamlivé aplikácie vydávajúce sa za iné aplikácie alebo zhromažďujúce údaje, ktoré sa dajú použiť na sledovanie vašej osoby. <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synchronizované)</translation>
<translation id="6027201098523975773">Zadajte meno</translation>
<translation id="6040143037577758943">Zavrieť</translation>
-<translation id="6042308850641462728">Viac</translation>
<translation id="6047233362582046994">Ak si uvedomujete bezpečnostné riziko, môžete <ph name="BEGIN_LINK" />tento web navštíviť<ph name="END_LINK" /> ešte skôr, ako budú škodlivé aplikácie odstránené.</translation>
<translation id="6047927260846328439">Tento obsah sa vás môže podvodom pokúsiť presvedčiť, aby ste si nainštalovali softvér alebo poskytli osobné informácie. <ph name="BEGIN_LINK" />Napriek tomu zobraziť<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Web <ph name="SITE" /> momentálne nemôžete navštíviť, pretože používa pripínanie certifikátov. Chyby siete a útoky sú zvyčajne dočasné, takže by táto stránka mala neskôr pravdepodobne fungovať.</translation>
@@ -692,6 +718,7 @@
<translation id="6569060085658103619">Prezeráte si stránku s rozšíreniami</translation>
<translation id="6596325263575161958">Možnosti šifrovania</translation>
<translation id="662080504995468778">Zostať</translation>
+<translation id="6624427990725312378">Kontaktné informácie</translation>
<translation id="6626291197371920147">Pridanie platného čísla karty</translation>
<translation id="6628463337424475685">Vyhľadávanie <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Útočníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sa môžu pokúsiť vo vašom počítači Mac nainštalovať nebezpečné programy, pomocou ktorých ukradnú alebo odstránia informácie (napríklad fotky, heslá, správy a kreditné karty). <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -702,7 +729,6 @@
<translation id="6710213216561001401">Dozadu</translation>
<translation id="6710594484020273272">&lt;Zadajte hľadaný výraz&gt;</translation>
<translation id="6711464428925977395">Vyskytol sa problém s proxy serverom alebo je adresa nesprávna.</translation>
-<translation id="6727102863431372879">Nastaviť</translation>
<translation id="674375294223700098">Neznáma chyba spôsobená certifikátom servera.</translation>
<translation id="6753269504797312559">Hodnota pravidla</translation>
<translation id="6757797048963528358">Vaše zariadenie prešlo do režimu spánku.</translation>
@@ -771,6 +797,7 @@
<translation id="7400418766976504921">Webová adresa</translation>
<translation id="7419106976560586862">Cesta profilu</translation>
<translation id="7424977062513257142">Vložená stránka na tejto webstránke hovorí:</translation>
+<translation id="7437289804838430631">Pridať kontaktné informácie</translation>
<translation id="7441627299479586546">Chybný predmet pravidla</translation>
<translation id="7444046173054089907">Tento web je blokovaný</translation>
<translation id="7445762425076701745">Identita servera, ku ktorému ste pripojení, sa nedá úplne overiť. Ste pripojení k serveru, ktorý používa názov platný iba v rámci vašej siete. Externá certifikačná autorita nemôže vlastníctvo názvu nijakým spôsobom overiť. Niektoré certifikačné autority však vydajú certifikát aj pre takéto názvy, a preto sa nedá zaručiť, že ste pripojení k požadovaným webovým stránkam a nie k stránkam útočníka.</translation>
@@ -781,11 +808,11 @@
<translation id="7481312909269577407">Dopredu</translation>
<translation id="7485870689360869515">Nenašli sa žiadne údaje.</translation>
<translation id="7508255263130623398">Identifikátor zariadenia vráteného v rámci záruky je prázdny alebo sa nezhoduje s identifikátorom aktuálneho zariadenia</translation>
+<translation id="7511955381719512146">Sieť Wi‑Fi, ktorú používate, môže vyžadovať, aby ste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
<translation id="7514365320538308">Stiahnuť</translation>
<translation id="7518003948725431193">Na webovej adrese <ph name="URL" /> sa nepodarilo nájsť žiadne webové stránky</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Vaše pripojenie k tomuto webu nie je súkromné</translation>
-<translation id="7535087603100972091">Hodnota</translation>
<translation id="7537536606612762813">Povinné</translation>
<translation id="7542403920425041731">Po potvrdení budú údaje karty zdieľané s týmto webom.</translation>
<translation id="7542995811387359312">Automatické dopĺňanie údajov o kreditnej karte je zakázané, pretože tento formulár nepoužíva zabezpečené pripojenie.</translation>
@@ -796,7 +823,6 @@
<translation id="7567204685887185387">Server nedokáže overiť, či ide o doménu <ph name="DOMAIN" />, bol zrejme vydaný falošný bezpečnostný certifikát. Môže to byť spôsobené nesprávnou konfiguráciou alebo tým, že vaše pripojenie zachytil útočník.</translation>
<translation id="7568593326407688803">Táto stránka je v jazyku<ph name="ORIGINAL_LANGUAGE" />Chceli by ste ju preložiť?</translation>
<translation id="7569952961197462199">Chcete kreditnú kartu odstrániť z prehliadača Chrome?</translation>
-<translation id="7569983096843329377">Čierna</translation>
<translation id="7578104083680115302">Zaplaťte rýchlejšie na stránkach a v aplikáciách v rôznych službách pomocou kariet, ktoré ste si uložili na Googli.</translation>
<translation id="7588950540487816470">Fyzický web</translation>
<translation id="7592362899630581445">Certifikát servera porušuje obmedzenia názvov.</translation>
@@ -815,11 +841,13 @@
<translation id="7669271284792375604">Útočníci na tomto webe sa vás môžu pokúsiť podvodom presvedčiť, aby ste si nainštalovali programy poškodzujúce vaše prostredie prehliadania (napríklad zmenou domovskej stránky alebo zobrazovaním ďalších reklám na weboch, ktoré navštevujete).</translation>
<translation id="7674629440242451245">Máte záujem o skvelé nové funkcie prehliadača Chrome? Vyskúšajte verziu pre vývojárov na stránke chrome.com/dev.</translation>
<translation id="7682287625158474539">Dodacia</translation>
+<translation id="7699293099605015246">Články nie sú momentálne k dispozícii</translation>
<translation id="7701040980221191251">Žiadne</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Prejsť na stránky <ph name="SITE" /> (nebezpečné)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certifikát</translation>
<translation id="7716147886133743102">Blokované správcom</translation>
<translation id="7716424297397655342">Tento web nie je možné načítať z vyrovnávacej pamäte</translation>
+<translation id="7723047071702270851">Úprava karty</translation>
<translation id="774634243536837715">Nebezpečný obsah bol zablokovaný.</translation>
<translation id="7752995774971033316">Nespravované</translation>
<translation id="7755287808199759310">Váš rodič ho môže pre vás odblokovať</translation>
@@ -830,21 +858,24 @@
<translation id="7764225426217299476">Pridať adresu</translation>
<translation id="777702478322588152">Prefektúra</translation>
<translation id="7791543448312431591">Pridať</translation>
+<translation id="7793553086574152071">Ak chcete nabudúce zaplatiť rýchlejšie, uložte si túto kartu do účtu Google.</translation>
<translation id="7793809570500803535">Webové stránky na adrese <ph name="SITE" /> môžu byť dočasne nedostupné alebo sa mohli natrvalo premiestniť na novú webovú adresu.</translation>
<translation id="7800304661137206267">Pripojenie je šifrované pomocou štandardu <ph name="CIPHER" /> s algoritmom <ph name="MAC" /> pre overovanie správ a mechanizmom výmeny kľúčov <ph name="KX" />.</translation>
+<translation id="7802523362929240268">Web je legitímny</translation>
<translation id="780301667611848630">Nie, ďakujem</translation>
<translation id="7805768142964895445">Stav</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chcete návrh odstrániť z prehliadača Chrome?</translation>
<translation id="7815407501681723534">Nájdené výsledky (počet: <ph name="NUMBER_OF_RESULTS" />) pre dopyt „<ph name="SEARCH_STRING" />“: <ph name="SEARCH_RESULTS" /></translation>
+<translation id="782886543891417279">Sieť Wi‑Fi (<ph name="WIFI_NAME" />), ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku</translation>
<translation id="785549533363645510">Nie ste však neviditeľný/-á. Prejdením do režimu inkognito neskryjete svoje prehliadanie pred zamestnávateľom, poskytovateľom internetových služieb ani pred navštívenými webmi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Debetné a predplatené karty sú akceptované.</translation>
+<translation id="7878562273885520351">Vaše heslo mohlo byť napadnuté</translation>
<translation id="7887683347370398519">Skontrolujte svoj kód CVC a skúste to znova</translation>
<translation id="79338296614623784">Zadajte platné telefónne číslo</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Certifikát servera ešte nie je platný.</translation>
-<translation id="7942349550061667556">Červená</translation>
<translation id="7947285636476623132">Skontrolujte rok vypršania platnosti a skúste to znova</translation>
<translation id="7951415247503192394">(32-bitová verzia)</translation>
<translation id="7956713633345437162">Záložky v mobile</translation>
@@ -858,9 +889,13 @@
<translation id="8037357227543935929">Opýtať sa (predvolené)</translation>
<translation id="8041089156583427627">Odoslať spätnú väzbu</translation>
<translation id="8041940743680923270">Použiť predvolené všeobecné nastavenie (Opýtať sa)</translation>
+<translation id="8057711352706143257">Softvér <ph name="SOFTWARE_NAME" /> nie je správne nakonfigurovaný. Tento problém sa zvyčajne odstráni odinštalovaním softvéru <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Článok sa nepodarilo zobraziť.</translation>
<translation id="8091372947890762290">Aktivácia čaká na server</translation>
+<translation id="8094917007353911263">Sieť, ktorú používate, môže vyžadovať, aby ste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
+<translation id="8103161714697287722">Spôsob platby</translation>
<translation id="8118489163946903409">Spôsob platby</translation>
+<translation id="8127301229239896662">Softvér <ph name="SOFTWARE_NAME" /> nebol v počítači alebo sieti riadne nainštalovaný. Požiadajte správcu IT, aby tento problém vyriešil.</translation>
<translation id="8131740175452115882">Potvrdiť</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresu DNS<ph name="END_ABBR" /> servera <ph name="HOST_NAME" /> sa nepodarilo nájsť.</translation>
<translation id="8149426793427495338">Váš počítač prešiel do režimu spánku.</translation>
@@ -883,6 +918,7 @@
<translation id="8289355894181816810">Ak neviete, čo to znamená, kontaktujte správcu siete.</translation>
<translation id="8293206222192510085">Pridať záložku</translation>
<translation id="8294431847097064396">Zdroj</translation>
+<translation id="8298115750975731693">Sieť Wi‑Fi (<ph name="WIFI_NAME" />), ktorú používate, môže vyžadovať, aby ste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
<translation id="8306404619377842860">S doménou <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> sa nedá nadviazať súkromné pripojenie, pretože dátum a čas (<ph name="DATE_AND_TIME" />) vo vašom zariadení sú nesprávne. <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Preklad zlyhal v dôsledku problému so sieťovým pripojením.</translation>
<translation id="8332188693563227489">Prístup k webu <ph name="HOST_NAME" /> bol zamietnutý</translation>
@@ -936,20 +972,21 @@
<translation id="8870413625673593573">Naposledy zatvorené</translation>
<translation id="8874824191258364635">Zadajte platné číslo karty</translation>
<translation id="8876793034577346603">Konfiguráciu siete sa nepodarilo analyzovať.</translation>
-<translation id="8889402386540077796">Odtieň</translation>
<translation id="8891727572606052622">Neplatný režim proxy.</translation>
<translation id="889901481107108152">Je nám ľúto, ale tento experiment nie je na vašej platforme k dispozícii.</translation>
<translation id="8903921497873541725">Priblížiť</translation>
<translation id="8931333241327730545">Chcete túto kartu uložiť do svojho účtu Google?</translation>
<translation id="8932102934695377596">Vaše hodiny idú pozadu</translation>
+<translation id="893332455753468063">Pridanie mena</translation>
<translation id="8938939909778640821">Akceptované kreditné a predplatené karty</translation>
+<translation id="8957210676456822347">Autorizácia portálu na prihlásenie do siete</translation>
<translation id="8971063699422889582">Platnosť certifikátu servera vypršala.</translation>
-<translation id="8986494364107987395">Automaticky odosielať Googlu štatistiky používania a správy o zlyhaní</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Webové stránky, ktoré sa chystáte navštíviť, obsahujú škodlivé programy</translation>
<translation id="8997023839087525404">Server prezentoval certifikát, ktorý nebol zverejnený pomocou pravidla transparentnosti certifikátov. V prípade niektorých certifikátov sa táto podmienka vyžaduje s cieľom zaistiť ich dôveryhodnosť a ochranu proti útočníkom.</translation>
<translation id="9001074447101275817">Proxy server <ph name="DOMAIN" /> vyžaduje používateľské meno a heslo.</translation>
<translation id="9005998258318286617">Dokument PDF sa nepodarilo načítať.</translation>
+<translation id="9008201768610948239">Ignorovať</translation>
<translation id="901974403500617787">Príznaky, ktoré platia v celom systéme, môže nastaviť iba vlastník: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Fakturačná adresa karty je povinná</translation>
<translation id="9020542370529661692">Táto stránka bola preložená do jazyka <ph name="TARGET_LANGUAGE" /></translation>
@@ -959,11 +996,14 @@
<translation id="9049981332609050619">Pokúšate sa otvoriť doménu <ph name="DOMAIN" />, ale server predložil neplatný certifikát.</translation>
<translation id="9050666287014529139">Prístupová fráza</translation>
<translation id="9065203028668620118">Upraviť</translation>
-<translation id="9068849894565669697">Výber farby</translation>
<translation id="9069693763241529744">Blokované rozšírením</translation>
<translation id="9076283476770535406">Môže zahŕňať obsah pre dospelých</translation>
<translation id="9078964945751709336">Treba zadať ďalšie informácie</translation>
+<translation id="9080712759204168376">Súhrn objednávky</translation>
<translation id="9103872766612412690">Web <ph name="SITE" /> zvyčajne chráni vaše informácie pomocou šifrovania. Keď sa prehliadač Chromium tentokrát pokúsil pripojiť k webu <ph name="SITE" />, odoslal späť nezvyčajné a nesprávne poverenia. Môže sa to stať vtedy, keď sa za web <ph name="SITE" /> snaží vydávať útočník alebo keď pripojenie preruší prihlasovacia obrazovka siete Wi‑Fi. Vaše informácie sú stále zabezpečené, pretože prehliadač Chromium zastavil pripojenie ešte pred výmenou dát.</translation>
+<translation id="9106062320799175032">Pridanie fakturačnej adresy</translation>
+<translation id="910908805481542201">Pomôžte mi to vyriešiť</translation>
+<translation id="9128870381267983090">Pripojiť k sieti</translation>
<translation id="9137013805542155359">Zobraziť originál</translation>
<translation id="9137248913990643158">Začnite a prihláste sa do Chromu ešte predtým, ako použijete túto aplikáciu.</translation>
<translation id="9148507642005240123">&amp;Vrátiť späť úpravu</translation>
@@ -975,6 +1015,7 @@
<translation id="9183425211371246419">Web <ph name="HOST_NAME" /> využíva nepodporovaný protokol.</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="9215416866750762878">Bezpečnému pripojeniu Chromu k tomuto webu bráni aplikácia</translation>
<translation id="9219103736887031265">Obrázky</translation>
<translation id="933612690413056017">Žiadne internetové pripojenie</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -984,5 +1025,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Žiadne}=1{1 položka}few{# položky}many{# položky}other{# položiek}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Zostavenie pre vývojárov</translation>
+<translation id="989988560359834682">Úprava adresy</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Softvér <ph name="SOFTWARE_NAME" /> nebol v počítači alebo sieti riadne nainštalovaný:
+ &lt;ul&gt;
+ &lt;li&gt;skúste softvér <ph name="SOFTWARE_NAME" /> odinštalovať alebo vypnúť,&lt;/li&gt;
+ &lt;li&gt;skúste sa pripojiť k inej sieti Wi-Fi.&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index 2582c4d7372..79f8411a952 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Zaznamki namizja</translation>
<translation id="1074497978438210769">Ni varno</translation>
<translation id="1080116354587839789">Prilagoditev prikaza širini</translation>
+<translation id="1088860948719068836">Dodajanje imena na kartico</translation>
<translation id="1103523840287552314">Vedno prevedi ta jezik: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Prikaži vsa shranjena gesla ...</translation>
<translation id="1107591249535594099">Če je izbrana ta možnost, bo shranil kopijo kartice v tej napravi za hitrejše izpolnjevanje obrazcev.</translation>
<translation id="1111153019813902504">Nedavni zaznamki</translation>
<translation id="1113869188872983271">&amp;Razveljavi razvrstitev</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (sinhronizirano)</translation>
<translation id="1263231323834454256">Bralni seznam</translation>
<translation id="1264126396475825575">Poročilo o zrušitvi je bilo zajeto takrat: <ph name="CRASH_TIME" /> (ni še naloženo ali je prezrto)</translation>
+<translation id="1270502636509132238">Način prevzema</translation>
<translation id="1281526147609854549">Izdal: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Nikoli ne prevedi tega spletnega mesta</translation>
<translation id="129553762522093515">Nedavno zaprto</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Čakanje na povezavo ...</translation>
<translation id="153384715582417236">To je vse za zdaj</translation>
<translation id="1549470594296187301">Če želite uporabljati to funkcijo, mora biti omogočen JavaScript.</translation>
-<translation id="1555130319947370107">Modra</translation>
<translation id="1559528461873125649">Taka datoteka ali imenik ne obstaja</translation>
<translation id="1583429793053364125">Med prikazom spletne strani je prišlo do napake.</translation>
<translation id="1592005682883173041">Dostop do lokalnih podatkov</translation>
<translation id="1594030484168838125">Izberi</translation>
-<translation id="161042844686301425">Cianova</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Ali želite, da Chrome shrani to kartico?</translation>
<translation id="1639239467298939599">Nalaganje</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">Operacijski sistem</translation>
<translation id="1721312023322545264"><ph name="NAME" /> vam mora odobriti obisk tega spletnega mesta</translation>
<translation id="1721424275792716183">*Polje je obvezno</translation>
+<translation id="1727741090716970331">Dodajanje veljavne številke kartice</translation>
<translation id="1728677426644403582">Ogledujete si izvorno kodo spletne strani</translation>
<translation id="173080396488393970">Ta vrsta kartice ni podprta</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Napaka pri serializaciji</translation>
<translation id="1974060860693918893">Dodatno</translation>
<translation id="1978555033938440688">Različica vdelane programske opreme</translation>
-<translation id="1995859865337580572">Preverite kodo CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{in še 1}one{in še #}two{in še #}few{in še #}other{in še #}}</translation>
<translation id="2025186561304664664">Strežnik proxy je nastavljen na samodejno konfiguriranje.</translation>
<translation id="2030481566774242610">Ali ste mislili <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Če želite prejemati prilagojeno vsebino, ki jo predlaga Google, se prijavite v Chrome.</translation>
+<translation id="2091887806945687916">Zvok</translation>
<translation id="2094505752054353250">Neujemanje domen</translation>
<translation id="2096368010154057602">Departma</translation>
<translation id="2108755909498034140">Znova zaženite računalnik</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Prezrto, ker je to preglasil pravilnik <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Iskanje strani za Fizični splet v bližini</translation>
<translation id="213826338245044447">Zaznamki mobilne naprave</translation>
+<translation id="214556005048008348">Prekliči plačilo</translation>
<translation id="2147827593068025794">Sinhroniziranje v ozadju</translation>
+<translation id="2148613324460538318">Dodaj kartico</translation>
<translation id="2154054054215849342">Sinhronizacija ni na voljo za vašo domeno</translation>
<translation id="2154484045852737596">Urejanje kartice</translation>
<translation id="2166049586286450108">Polni skrbniški dostop</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 naslov}one{# naslov}two{# naslova}few{# naslovi}other{# naslovov}}</translation>
<translation id="2187317261103489799">Zaznava (privzeto)</translation>
<translation id="2202020181578195191">Vnesite veljavno leto poteka veljavnosti</translation>
+<translation id="2209523182407020534">Aplikacije, ki lahko povzročijo to napako, so med drugim protivirusni program, požarni zid, programska oprema za spletno filtriranje ali strežnik proxy.</translation>
<translation id="2212735316055980242">Pravilnika ni mogoče najti</translation>
<translation id="2213606439339815911">Prenos vnosov ...</translation>
<translation id="2218879909401188352">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, bi lahko namestili nevarne aplikacije, ki poškodujejo napravo, dodali skrite stroške na račun za mobilno napravo ali ukradli osebne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Nazaj</translation>
<translation id="2503184589641749290">Sprejete debetne in predplačniške kartice</translation>
<translation id="2515629240566999685">preveriti signal na svojem območju</translation>
+<translation id="2524461107774643265">Dodajanje več podatkov</translation>
+<translation id="2536110899380797252">Dodaj naslov</translation>
<translation id="2539524384386349900">Zaznava</translation>
<translation id="255002559098805027">Spletno mesto <ph name="HOST_NAME" /> je poslalo neveljaven odgovor.</translation>
<translation id="2556876185419854533">&amp;Razveljavi urejanje</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
<translation id="2705137772291741111">Shranjena (predpomnjena) kopija tega spletnega mesta je bila neberljiva.</translation>
<translation id="2709516037105925701">Samodejno izpolnjevanje</translation>
+<translation id="2710942282213947212">Programska oprema v računalniku Chromiumu preprečuje vzpostavitev varne povezave s spletom</translation>
<translation id="2712173769900027643">Zahtevaj dovoljenje</translation>
-<translation id="2713444072780614174">Bela</translation>
<translation id="2720342946869265578">V bližini</translation>
<translation id="2721148159707890343">Zahteva je uspela</translation>
<translation id="2728127805433021124">Strežnikovo potrdilo je podpisano s šibkim podpisnim algoritmom.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Zaznana je bila sprememba omrežja.</translation>
<translation id="2916038427272391327">Zaprite druge programe</translation>
<translation id="2922350208395188000">Potrdila strežnika ni mogoče preveriti.</translation>
+<translation id="2925673989565098301">Način dostave</translation>
<translation id="2928905813689894207">Naslov za izstavitev računa</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}two{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Strežniku ni uspelo dokazati, da je res <ph name="DOMAIN" />; njegovo varnostno potrdilo je od <ph name="DOMAIN2" />. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Napačna vrsta pravilnika</translation>
<translation id="3032412215588512954">Ali želite znova naložiti to spletno mesto?</translation>
<translation id="3037605927509011580">Ti šment!</translation>
+<translation id="3039538478787849737">Želite shraniti kartico v Googlu?</translation>
<translation id="3041612393474885105">Informacije o potrdilu</translation>
<translation id="3063697135517575841">Chrome trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
<translation id="3064966200440839136">Zaradi plačila v zunanji aplikaciji boste zapustili način brez beleženja zgodovine. Želite nadaljevati?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Začasna napaka strežnika</translation>
<translation id="3154506275960390542">Na tej strani je tudi obrazec, ki morda ne bo poslan varno. Podatke, ki jih pošljete, si lahko med prenosom ogledujejo drugi, ali pa jih lahko spremeni morebitni napadalec, tako da strežnik prejme spremenjene podatke.</translation>
<translation id="3157931365184549694">Obnovi</translation>
+<translation id="3162559335345991374">Omrežje Wi-Fi, ki ga uporabljate, morda zahteva, da obiščete stran za prijavo.</translation>
<translation id="3167968892399408617">Strani, ki si jih ogledujete na zavihkih brez beleženja zgodovine, se ne bodo ohranile v zgodovini brskalnika, hrambi piškotkov ali zgodovini iskanja, ko boste zaprli vse zavihke brez beleženja zgodovine. Datoteke, ki jih prenesete, ali zaznamki, ki jih ustvarite, se bodo ohranili.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Otok</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Prekliči plačilo</translation>
<translation id="3207960819495026254">Zaznamovano</translation>
+<translation id="3211223744486044430">Če želite naslednjič hitreje plačati, shranite to kartico v Google Računu in v tej napravi.</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>
<translation id="3226128629678568754">Pritisnite gumb za vnovično nalaganje, da znova pošljete podatke za nalaganje strani.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Ni rezultatov iskanja</translation>
<translation id="3305707030755673451">Podatki so bili šifrirani z vašim geslom za sinhronizacijo <ph name="TIME" />. Vnesite ga, če želite začeti sinhronizacijo.</translation>
<translation id="3320021301628644560">Dodajanje naslova za izstavitev računa</translation>
-<translation id="3329013043687509092">Nasičenost</translation>
<translation id="333371639341676808">Tej strani preprečite, da bi ustvarila dodatna pogovorna okna.</translation>
<translation id="3338095232262050444">Varno</translation>
<translation id="3340978935015468852">nastavitve</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID odjemalca:</translation>
<translation id="3391030046425686457">Naslov za dostavo</translation>
<translation id="3395827396354264108">Način prevzema</translation>
+<translation id="3399952811970034796">Naslov za dostavo</translation>
<translation id="3422248202833853650">Poskusite zapreti druge programe, da boste tako sprostili pomnilnik.</translation>
<translation id="3422472998109090673">Spletno mesto <ph name="HOST_NAME" /> trenutno ni dosegljivo.</translation>
<translation id="3427092606871434483">Dovoli (privzeto)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Poročilo o zrušitvi je bilo zajeto takrat: <ph name="CRASH_TIME" />, naloženo takrat: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informacije o potrdilu</translation>
<translation id="3690164694835360974">Prijava ni varna</translation>
+<translation id="3704162925118123524">Omrežje, ki ga uporabljate, morda zahteva, da obiščete stran za prijavo.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Nalaganje ...</translation>
<translation id="3712624925041724820">Ni dovolj licenc</translation>
<translation id="3714780639079136834">vklopiti prenos podatkov v mobilnih omrežjih ali Wi-Fi</translation>
+<translation id="3715597595485130451">Vzpostavljanje povezave z omrežjem Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />preveriti strežnik proxy, požarni zid in konfiguracijo DNS-ja<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Če se zavedate varnostnega tveganja, lahko <ph name="BEGIN_LINK" />obiščete to spletno mesto, ki ni varno<ph name="END_LINK" />, preden bodo nevarni programi odstranjeni.</translation>
<translation id="3739623965217189342">Povezava, ki ste jo kopirali</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Razveljavi dodajanje</translation>
<translation id="404928562651467259">OPOZORILO</translation>
<translation id="4058922952496707368">Ključ »<ph name="SUBKEY" />«: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Konfiguracija strežnika proxy je nastavljena na uporabo URL-ja skripta .pac, ne na stalne strežnike proxy.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Neveljavna serijska številka naprave</translation>
<translation id="410351446219883937">Samodejno predvajanje</translation>
<translation id="4103763322291513355">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="4115378294792113321">Škrlatna</translation>
<translation id="4116663294526079822">Vedno dovoli na tem spletnem mestu</translation>
<translation id="4117700440116928470">Obseg pravilnika ni podprt.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{in še 1 drug}one{in še # drug}two{in še # druga}few{in še # drugi}other{in še # drugih}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je izdajatelj preklical potrdilo, ki ga je poslal strežnik. To pomeni, da varnostnim poverilnicam, ki jih je poslal strežnik, nikakor ne smete zaupati. Morda komunicirate z napadalcem.</translation>
<translation id="4394049700291259645">Onemogoči</translation>
<translation id="4406896451731180161">rezultati iskanja</translation>
+<translation id="4415426530740016218">Naslov za prevzem</translation>
<translation id="4424024547088906515">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; Chrome ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.</translation>
<translation id="4432688616882109544">Spletno mesto <ph name="HOST_NAME" /> ni sprejelo potrdila za prijavo ali pa to ni bilo posredovano.</translation>
<translation id="443673843213245140">Uporaba strežnika proxy je onemogočena, vendar je njegova konfiguracija izrecno določena.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Poskusite onemogočiti razširitve.</translation>
<translation id="457875822857220463">Dostava</translation>
+<translation id="4582800630050655161">Izgubite lahko dostop do Google Računa ali postanete žrtev kraje identitete. Chromium priporoča, da spremenite geslo.</translation>
<translation id="4587425331216688090">Želite odstraniti naslov iz Chroma?</translation>
<translation id="4592951414987517459">Povezava z domeno <ph name="DOMAIN" /> je šifrirana s sodobno šifrirno zbirko.</translation>
<translation id="4594403342090139922">&amp;Razveljavi izbris</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Prenehaj uporabljati neveljavno potrdilo</translation>
+<translation id="4690954380545377795">Izgubite lahko dostop do Google Računa ali postanete žrtev kraje identitete. Chrome priporoča, da spremenite geslo.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Povezava je bila prekinjena</translation>
<translation id="471880041731876836">Nimate dovoljenja za obisk tega spletnega mesta</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Izvajanje orodja Omrežna diagnostika Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Plačilo</translation>
<translation id="4726672564094551039">Znova naloži pravilnike</translation>
<translation id="4728558894243024398">Okolje</translation>
<translation id="4736825316280949806">Znova zaženite Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Neprimerno stanje rezervne shrambe</translation>
<translation id="5023310440958281426">Preverite skrbnikove pravilnike</translation>
<translation id="5029568752722684782">Počisti kopijo</translation>
+<translation id="503069730517007720">Korensko potrdilo za programsko opremo »<ph name="SOFTWARE_NAME" />« je obvezno, vendar ni nameščeno. Skrbnik za IT lahko za odpravo te težave upošteva navodila za konfiguracijo za programsko opremo »<ph name="SOFTWARE_NAME" />«. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google Prevajalnik – vizitka</translation>
<translation id="5039804452771397117">Dovoli</translation>
<translation id="5040262127954254034">Zasebnost</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Poskusi</translation>
<translation id="5205222826937269299">Ime je obvezno</translation>
<translation id="5222812217790122047">E-poštni naslov je obvezen</translation>
+<translation id="522700295135997067">To spletno mesto vam je morda pravkar ukradlo geslo</translation>
+<translation id="5230733896359313003">Naslov za pošiljanje</translation>
<translation id="5251803541071282808">Oblak</translation>
<translation id="5277279256032773186">Uporabljate Chrome v službi? Podjetja lahko upravljajo nastavitve Chroma za zaposlene. Preberite več o tem.</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Upoštevajte ta navodila, če želite začasno onemogočiti programsko opremo, da se boste lahko povezali v splet. Potrebujete skrbniške pravice.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Povezava s tem spletnim mestom ni zasebna. Če želite kadar koli zapustiti način navidezne resničnosti, snemite naglavni komplet in pritisnite tipko za nazaj.</translation>
<translation id="5299298092464848405">Napaka pri razčlenjevanju pravilnika</translation>
+<translation id="5308380583665731573">Povezovanje</translation>
<translation id="5308689395849655368">Poročanje o zrušitvah je onemogočeno.</translation>
<translation id="5317780077021120954">Shrani</translation>
<translation id="5327248766486351172">Ime</translation>
+<translation id="5332219387342487447">Način pošiljanja</translation>
<translation id="5355557959165512791">Spletnega mesta <ph name="SITE" /> trenutno ni mogoče obiskati, saj je to potrdilo preklicano. Napake omrežja in napadi na omrežje so običajno začasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="536296301121032821">Nastavitev pravilnika ni bilo mogoče shraniti</translation>
<translation id="5386426401304769735">Veriga potrdil za to spletno mesto vsebuje potrdilo, podpisano z algoritmom SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">To spletno mesto v intranetu podjetja, organizacije ali šole ima enak URL kot zunanje spletno mesto.
<ph name="LINE_BREAK" />
Poskusite se obrniti na skrbnika sistema.</translation>
+<translation id="5499929369096410817">Vnesite varnostno kodo za kartico <ph name="CREDIT_CARD" />. Ta koda ne bo shranjena.</translation>
<translation id="5509780412636533143">Upravljani zaznamki</translation>
<translation id="5510766032865166053">Morda je premaknjena ali izbrisana.</translation>
<translation id="5523118979700054094">Ime pravilnika</translation>
<translation id="552553974213252141">Ali je bilo besedilo pravilno izvlečeno?</translation>
<translation id="5540224163453853">Zahtevanega članka ni bilo mogoče najti.</translation>
+<translation id="5541546772353173584">Dodajanje e-poštnega naslova</translation>
<translation id="5544037170328430102">Vdelana stran na spletnem mestu <ph name="SITE" /> sporoča:</translation>
+<translation id="5545756402275714221">Članki za vas</translation>
<translation id="5556459405103347317">Ponovno naloži</translation>
<translation id="5560088892362098740">Datum poteka</translation>
<translation id="5565735124758917034">Aktivno</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-pošta</translation>
<translation id="5669703222995421982">Prilagojena vsebina</translation>
<translation id="5675650730144413517">Ta stran ne deluje</translation>
+<translation id="5689199277474810259">Izvozi v JSON</translation>
<translation id="5710435578057952990">Identiteta tega spletnega mesta ni bila potrjena.</translation>
<translation id="5719499550583120431">Sprejema predplačniške kartice.</translation>
<translation id="5720705177508910913">Trenutni uporabnik</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Povezava z domeno <ph name="DOMAIN" /> je šifrirana z zastarelo šifrirno zbirko.</translation>
<translation id="5813119285467412249">&amp;Uveljavi dodajanje</translation>
<translation id="5838278095973806738">Na tem spletnem mestu ne vnašajte občutljivih informacij (npr. gesel ali številk kreditnih kartic), ker jih lahko ukradejo napadalci.</translation>
+<translation id="5866257070973731571">Dodajanje telefonske številke</translation>
<translation id="5869405914158311789">Tega spletnega mesta ni mogoče doseči</translation>
<translation id="5869522115854928033">Shranjena gesla</translation>
<translation id="5872918882028971132">Predlogi staršev</translation>
<translation id="5893752035575986141">Sprejema kreditne kartice.</translation>
-<translation id="5901630391730855834">Rumena</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinhronizirano)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 v uporabi}one{# v uporabi}two{# v uporabi}few{# v uporabi}other{# v uporabi}}</translation>
<translation id="5959728338436674663">Samodejno pošlji Googlu nekatere <ph name="BEGIN_WHITEPAPER_LINK" />sistemske podatke in vsebino strani<ph name="END_WHITEPAPER_LINK" /> zaradi zaznavanja nevarnih aplikacij in spletnih mest. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Urejanje podatkov o stiku</translation>
<translation id="5967867314010545767">Odstrani iz zgodovine</translation>
<translation id="5975083100439434680">Pomanjšaj</translation>
+<translation id="597552863672748783">Potrditev varnostne kode</translation>
<translation id="598637245381783098">Plačilne aplikacije ni mogoče odpreti</translation>
<translation id="5989320800837274978">Določeni niso ne stalni strežniki proxy ne URL skripta .pac.</translation>
<translation id="5990559369517809815">Zahteve za strežnik je blokirala razširitev.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Stran 1}one{Stran #}two{Stran #}few{Stran #}other{Stran #}}</translation>
-<translation id="6017514345406065928">Zelena</translation>
<translation id="6017850046339264347">Napadalci na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> bi lahko namestili zavajajoče aplikacije, ki se pretvarjajo, da so nekaj drugega, ali zbirajo podatke, s katerimi vas lahko spremljajo. <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (sinhronizirano)</translation>
<translation id="6027201098523975773">Vnesite ime</translation>
<translation id="6040143037577758943">Zapri</translation>
-<translation id="6042308850641462728">Več</translation>
<translation id="6047233362582046994">Če se zavedate varnostnega tveganja, lahko <ph name="BEGIN_LINK" />obiščete to spletno mesto<ph name="END_LINK" />, preden bodo škodljive aplikacije odstranjene.</translation>
<translation id="6047927260846328439">Ta vsebina vas morda poskuša zavesti, da namestite programsko opremo ali razkrijete osebne podatke. <ph name="BEGIN_LINK" />Vseeno prikaži<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Spletnega mesta <ph name="SITE" /> trenutno ni mogoče obiskati, ker uporablja pripenjanje potrdil. Napake omrežja in napadi na omrežje so običajno začasni, zato bo ta stran verjetno delovala pozneje.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Ogledujete si stran razširitve</translation>
<translation id="6596325263575161958">Možnosti šifriranja</translation>
<translation id="662080504995468778">Ostani</translation>
+<translation id="6624427990725312378">Podatki o stiku</translation>
<translation id="6626291197371920147">Dodajanje veljavne številke kartice</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Iskanje</translation>
<translation id="6630809736994426279">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, lahko poskusijo v vašem računalniku Mac namestiti nevarne programe, ki kradejo ali brišejo podatke (na primer fotografije, gesla, sporočila in podatke kreditnih kartic). <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Nazaj</translation>
<translation id="6710594484020273272">&lt;Vnesite iskalno poizvedbo&gt;</translation>
<translation id="6711464428925977395">Nekaj je narobe s strežnikom proxy ali pa naslov ni pravilen.</translation>
-<translation id="6727102863431372879">Nastavi</translation>
<translation id="674375294223700098">Neznana napaka potrdila strežnika.</translation>
<translation id="6753269504797312559">Vrednost pravilnika</translation>
<translation id="6757797048963528358">Naprava je preklopila v stanje pripravljenosti.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Pot profila</translation>
<translation id="7424977062513257142">Vdelana stran na tej spletni strani sporoča:</translation>
+<translation id="7437289804838430631">Dodaj podatke o stiku</translation>
<translation id="7441627299479586546">Napačen subjekt pravilnika</translation>
<translation id="7444046173054089907">To spletno mesto je blokirano</translation>
<translation id="7445762425076701745">Identitete strežnika, s katerim ste povezani, ni mogoče v celoti preveriti. S strežnikom ste povezani z uporabo imena, ki je veljavno samo v vašem omrežju, zato zunanji overitelj potrdil ne more preveriti njegovega lastništva. Ker nekateri overitelji potrdil kljub temu izdajajo potrdila za takšna imena, ni mogoče zagotoviti, da ste povezani z želenim spletnim mestom in ne z napadalcem.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Naprej</translation>
<translation id="7485870689360869515">Ni podatkov.</translation>
<translation id="7508255263130623398">Vrnjen ID naprave pravilnika je prazen ali se ne ujema s trenutnim ID-jem naprave</translation>
+<translation id="7511955381719512146">Omrežje Wi-Fi, ki ga uporabljate, morda zahteva, da obiščete <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Prenos</translation>
<translation id="7518003948725431193">Za ta spletni naslov in bilo mogoče najti nobene spletne strani:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Povezava s tem mestom ni zasebna</translation>
-<translation id="7535087603100972091">Vrednost</translation>
<translation id="7537536606612762813">Obvezen</translation>
<translation id="7542403920425041731">Ko potrdite, bodo temu spletnemu mestu razkriti podatki o kartici.</translation>
<translation id="7542995811387359312">Samodejno izpolnjevanje podatkov o kreditni kartici je onemogočeno, ker ta obrazec ne uporablja varne povezave.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda izdano z goljufijo. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.</translation>
<translation id="7568593326407688803">Ta stran je v jeziku:<ph name="ORIGINAL_LANGUAGE" />Jo želite prevesti?</translation>
<translation id="7569952961197462199">Želite odstraniti kreditno kartico iz Chroma?</translation>
-<translation id="7569983096843329377">Črna</translation>
<translation id="7578104083680115302">Hitro plačevanje na spletnih mestih in v aplikacijah v vseh napravah s karticami, ki ste jih shranili v Googlu.</translation>
<translation id="7588950540487816470">Fizični splet</translation>
<translation id="7592362899630581445">Strežnikovo potrdilo krši omejitve imen.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Napadalci na tem spletnem mestu vas bodo morda poskusili zavesti, da bi namestili programe, ki škodljivo vplivajo na brskanje (na primer tako, da spremenijo vašo domačo stran ali na spletnih mestih, ki jih obiščete, prikazujejo dodatne oglase).</translation>
<translation id="7674629440242451245">Vas zanimajo super nove funkcije Chroma? Preskusite naš kanal za razvijalce na chrome.com/dev.</translation>
<translation id="7682287625158474539">Pošiljanje</translation>
+<translation id="7699293099605015246">Članki trenutno niso na voljo</translation>
<translation id="7701040980221191251">Brez</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Nadaljuj na spletno mesto <ph name="SITE" /> (ni varno)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Potrdilo</translation>
<translation id="7716147886133743102">Blokiral skrbnik</translation>
<translation id="7716424297397655342">Tega spletnega mesta ni mogoče naložiti iz predpomnilnika</translation>
+<translation id="7723047071702270851">Urejanje kartice</translation>
<translation id="774634243536837715">Nevarna vsebina blokirana.</translation>
<translation id="7752995774971033316">Odstranjen iz uporabe</translation>
<translation id="7755287808199759310">Starš ga lahko odblokira</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Dodaj naslov</translation>
<translation id="777702478322588152">Prefektura</translation>
<translation id="7791543448312431591">Dodaj</translation>
+<translation id="7793553086574152071">Če želite naslednjič hitreje plačati, shranite to kartico v Google Računu.</translation>
<translation id="7793809570500803535">Spletna stran na <ph name="SITE" /> morda začasno ne deluje ali pa je trajno premaknjena na nov spletni naslov.</translation>
<translation id="7800304661137206267">Povezava je šifrirana s <ph name="CIPHER" /> in uporablja <ph name="MAC" /> za preverjanje pristnosti sporočil ter <ph name="KX" /> kot mehanizem za izmenjavo ključev.</translation>
+<translation id="7802523362929240268">Spletno mesto je legitimno</translation>
<translation id="780301667611848630">Ne, hvala</translation>
<translation id="7805768142964895445">Stanje</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Želite odstraniti predlog obrazca iz Chroma?</translation>
<translation id="7815407501681723534">Za »<ph name="SEARCH_STRING" />« je bilo najdenih toliko <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" />.</translation>
+<translation id="782886543891417279">Omrežje Wi-Fi, ki ga uporabljate (<ph name="WIFI_NAME" />), morda zahteva, da obiščete stran za prijavo.</translation>
<translation id="785549533363645510">Kljub temu pa niste nevidni. Z uporabo načina brez beleženja zgodovine brskanja ne skrijete pred delodajalcem, ponudnikom internetnih storitev ali spletnimi mesti, ki jih obiščete.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Sprejema debetne in kreditne kartice.</translation>
+<translation id="7878562273885520351">Geslo je morda ogroženo</translation>
<translation id="7887683347370398519">Preverite CVC in poskusite znova</translation>
<translation id="79338296614623784">Vnesite veljavno telefonsko številko</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Potrdilo strežnika še ni veljavno.</translation>
-<translation id="7942349550061667556">Rdeča</translation>
<translation id="7947285636476623132">Preverite leto poteka veljavnosti in poskusite znova</translation>
<translation id="7951415247503192394">(32-bitno)</translation>
<translation id="7956713633345437162">Zaznamki mobilne naprave</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Zahteva (privzeto)</translation>
<translation id="8041089156583427627">Pošlji povratne informacije</translation>
<translation id="8041940743680923270">Uporabi globalno privzeto (Vprašaj)</translation>
+<translation id="8057711352706143257">Programska oprema »<ph name="SOFTWARE_NAME" />« ni pravilno konfigurirana. Običajno težavo odpravite tako, da odstranite programsko opremo »<ph name="SOFTWARE_NAME" />«. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Članka si ni bilo mogoče ogledati.</translation>
<translation id="8091372947890762290">Čakanje na aktivacijo v strežniku</translation>
+<translation id="8094917007353911263">Omrežje, ki ga uporabljate, morda zahteva, da obiščete <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Plačilno sredstvo</translation>
<translation id="8118489163946903409">Plačilno sredstvo</translation>
+<translation id="8127301229239896662">Programska oprema »<ph name="SOFTWARE_NAME" />« ni bila pravilno nameščena v računalniku ali omrežju. Obrnite se na skrbnika za IT glede odpravljanja te težave.</translation>
<translation id="8131740175452115882">Potrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Naslova DNS<ph name="END_ABBR" /> strežnika spletnega mesta <ph name="HOST_NAME" /> ni bilo mogoče najti.</translation>
<translation id="8149426793427495338">Računalnik je preklopil v stanje pripravljenosti.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Če niste prepričani, kaj to pomeni, se obrnite na skrbnika omrežja.</translation>
<translation id="8293206222192510085">Dodaj zaznamek</translation>
<translation id="8294431847097064396">Vir</translation>
+<translation id="8298115750975731693">Omrežje Wi-Fi, ki ga uporabljate (<ph name="WIFI_NAME" />), morda zahteva, da obiščete <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Prevod ni uspel zaradi težave s povezavo omrežja.</translation>
<translation id="8332188693563227489">Dostop do spletnega mesta <ph name="HOST_NAME" /> je bil zavrnjen</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Nedavno zaprto</translation>
<translation id="8874824191258364635">Vnesite veljavno številko kartice</translation>
<translation id="8876793034577346603">Omrežne konfiguracije ni bilo mogoče razčleniti.</translation>
-<translation id="8889402386540077796">Odtenek</translation>
<translation id="8891727572606052622">Neveljaven način strežnika proxy.</translation>
<translation id="889901481107108152">Oprostite, ta poskus ni na voljo za vaše okolje.</translation>
<translation id="8903921497873541725">Povečaj</translation>
<translation id="8931333241327730545">Ali želite to kartico shraniti v Google Račun?</translation>
<translation id="8932102934695377596">Ura zaostaja</translation>
+<translation id="893332455753468063">Dodajanje imena</translation>
<translation id="8938939909778640821">Sprejete kreditne in predplačniške kartice</translation>
+<translation id="8957210676456822347">Odobritev prestreznega portala</translation>
<translation id="8971063699422889582">Potrdilo strežnika je poteklo.</translation>
-<translation id="8986494364107987395">Samodejno pošlji statistične podatke o uporabi in poročila o zrušitvah Googlu</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Pozor: Spletno mesto vsebuje škodljive programe.</translation>
<translation id="8997023839087525404">Strežnik je posredoval potrdilo, ki ni bilo javno razkrito na podlagi pravilnika o preglednosti potrdila. To je obvezno za nekatera potrdila zaradi zagotavljanja, da so zaupanja vredna in ščitijo pred napadalci.</translation>
<translation id="9001074447101275817">Strežnik proxy <ph name="DOMAIN" /> zahteva uporabniško ime in geslo.</translation>
<translation id="9005998258318286617">Dokumenta PDF ni bilo mogoče naložiti.</translation>
+<translation id="9008201768610948239">Prezri</translation>
<translation id="901974403500617787">Zastavice, ki se uporabijo v celotnem sistemu, lahko nastavi samo lastnik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Naslov kreditne kartice za račune je obvezen</translation>
<translation id="9020542370529661692">Ta stran je prevedena v jezik <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Skušali ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik predložil neveljavno potrdilo.</translation>
<translation id="9050666287014529139">Geslo</translation>
<translation id="9065203028668620118">Uredi</translation>
-<translation id="9068849894565669697">Izbira barve</translation>
<translation id="9069693763241529744">Blokirala razširitev</translation>
<translation id="9076283476770535406">Morda vsebuje vsebino za odrasle</translation>
<translation id="9078964945751709336">Vnesti morate več podatkov</translation>
+<translation id="9080712759204168376">Povzetek naročila</translation>
<translation id="9103872766612412690">Spletno mesto <ph name="SITE" /> za zaščito vaših podatkov običajno uporablja šifriranje. Ko se je Chromium tokrat poskusil povezati s spletnim mestom <ph name="SITE" />, je to vrnilo nenavadne in nepravilne poverilnice. Do tega lahko pride, če se napadalec lažno predstavlja za spletno mesto <ph name="SITE" /> ali če je povezavo prekinil zaslon za prijavo v omrežje Wi-Fi. Vaši podatki so še vedno varni, saj je Chromium pred izmenjavo podatkov prekinil povezavo.</translation>
+<translation id="9106062320799175032">Dodajanje naslova za izstavitev računa</translation>
+<translation id="910908805481542201">Pomagajte mi odpraviti težavo</translation>
+<translation id="9128870381267983090">Vzpostavi povezavo z omrežjem</translation>
<translation id="9137013805542155359">Pokaži izvirno besedilo</translation>
<translation id="9137248913990643158">Začnite s prijavo v Chrome, preden začnete uporabljati to aplikacijo.</translation>
<translation id="9148507642005240123">&amp;Razveljavi urejanje</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">Spletno mesto <ph name="HOST_NAME" /> uporablja nepodprt protokol.</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="9215416866750762878">Aplikacija Chromu preprečuje vzpostavitev varne povezave s tem mestom</translation>
<translation id="9219103736887031265">Slike</translation>
<translation id="933612690413056017">Ni internetne povezave</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Brez}=1{1 element}one{# element}two{# elementa}few{# elementi}other{# elementov}}</translation>
<translation id="981121421437150478">Brez povezave</translation>
<translation id="988159990683914416">Različica za razvijalce</translation>
+<translation id="989988560359834682">Uredi naslov</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Programska oprema »<ph name="SOFTWARE_NAME" />« ni bila pravilno nameščena v računalniku ali omrežju:
+ &lt;ul&gt;
+ &lt;li&gt;Poskusite odstraniti »<ph name="SOFTWARE_NAME" />«&lt;/li&gt;
+ &lt;li&gt;Poskusite se povezati z drugim omrežjem&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index 7c4c6831c00..e638a1d0327 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Обележивачи на рачунару</translation>
<translation id="1074497978438210769">Није безбедно</translation>
<translation id="1080116354587839789">Уклопите по ширини</translation>
+<translation id="1088860948719068836">Додајте име са картице</translation>
<translation id="1103523840287552314">Увек преводи <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Прикажи све сачуване лозинке…</translation>
<translation id="1107591249535594099">Ако означите ову опцију, Chrome ће складиштити копију картице на овом уређају ради бржег попуњавања образаца.</translation>
<translation id="1111153019813902504">Недавно коришћени обележивачи</translation>
<translation id="1113869188872983271">&amp;Опозови промену редоследа</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (синхронизовано)</translation>
<translation id="1263231323834454256">Листа за читање</translation>
<translation id="1264126396475825575">Извештај о отказивању је снимљен <ph name="CRASH_TIME" /> (још увек није отпремљен или игнорисан)</translation>
+<translation id="1270502636509132238">Начин преузимања</translation>
<translation id="1281526147609854549">Издавач: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Никад не преводи овај сајт</translation>
<translation id="129553762522093515">Недавно затворено</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Чека се веза…</translation>
<translation id="153384715582417236">То је све за сада</translation>
<translation id="1549470594296187301">JavaScript мора да буде омогућен да бисте користили ову функцију.</translation>
-<translation id="1555130319947370107">Плава</translation>
<translation id="1559528461873125649">Нема такве датотеке или директоријума</translation>
<translation id="1583429793053364125">Дошло је до грешке при приказивању ове веб-странице.</translation>
<translation id="1592005682883173041">Приступ локалним подацима</translation>
<translation id="1594030484168838125">Одабери</translation>
-<translation id="161042844686301425">Плавозелена</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1629803312968146339">Желите ли да Chrome сачува ову картицу?</translation>
<translation id="1639239467298939599">Учитавање</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Потребна вам је дозвола корисника <ph name="NAME" /> да бисте посетили овај сајт</translation>
<translation id="1721424275792716183">* Поље је обавезно</translation>
+<translation id="1727741090716970331">Додајте важећи број картице</translation>
<translation id="1728677426644403582">Прегледате извор веб-странице.</translation>
<translation id="173080396488393970">Овај тип картице није подржан</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Грешка при серијализацији</translation>
<translation id="1974060860693918893">Напредне опције</translation>
<translation id="1978555033938440688">Верзија фирмвера</translation>
-<translation id="1995859865337580572">Верификујте CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ и још 1}one{и још #}few{и још #}other{и још #}}</translation>
<translation id="2025186561304664664">Прокси је подешен да буде аутоматски конфигурисан.</translation>
<translation id="2030481566774242610">Да ли сте мислили <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Опозови</translation>
<translation id="20817612488360358">Подешено је да се користе системска подешавања проксија, али је наведена експлицитна конфигурација проксија.</translation>
<translation id="2086652334978798447">Да бисте добијали персонализовани садржај који предлаже Google, пријавите се у Chrome.</translation>
+<translation id="2091887806945687916">Звук</translation>
<translation id="2094505752054353250">Домени се не подударају</translation>
<translation id="2096368010154057602">Департман</translation>
<translation id="2108755909498034140">Поново покрените рачунар</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Занемарују се јер су замењене смерницама <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Тражимо странице Интернета око нас у околини</translation>
<translation id="213826338245044447">Обележивачи на мобилном уређају</translation>
+<translation id="214556005048008348">Откажи плаћање</translation>
<translation id="2147827593068025794">Синхронизација у позадини</translation>
+<translation id="2148613324460538318">Додај картицу</translation>
<translation id="2154054054215849342">Синхронизација није доступна за домен</translation>
<translation id="2154484045852737596">Измените картицу</translation>
<translation id="2166049586286450108">Потпуни администраторски приступ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреса}one{# адреса}few{# адресе}other{# адреса}}</translation>
<translation id="2187317261103489799">Откриј (подразумевано)</translation>
<translation id="2202020181578195191">Унесите важећу годину истека</translation>
+<translation id="2209523182407020534">Апликације које могу да доведу до ове грешке обухватају антивирусни програм, заштитни зид и веб-филтрирање или прокси софтвер.</translation>
<translation id="2212735316055980242">Смернице нису пронађене</translation>
<translation id="2213606439339815911">Преузимање уноса...</translation>
<translation id="2218879909401188352">Нападачи који су тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могу да инсталирају опасне апликације које ће вам оштетити уређај, додати нежељене трошкове код мобилног оператера или украсти личне податке. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Иди назад</translation>
<translation id="2503184589641749290">Дебитне и припејд картице које се прихватају</translation>
<translation id="2515629240566999685">да проверите сигнал у својој области</translation>
+<translation id="2524461107774643265">Додајте још информација</translation>
+<translation id="2536110899380797252">Додај адресу</translation>
<translation id="2539524384386349900">Откриј</translation>
<translation id="255002559098805027">Хост <ph name="HOST_NAME" /> је послао неважећи одговор.</translation>
<translation id="2556876185419854533">&amp;Опозови измену</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium није успео да потврди картицу. Пробајте поново касније.</translation>
<translation id="2705137772291741111">Сачувана (кеширана) копија овог сајта није могла да се чита.</translation>
<translation id="2709516037105925701">Аутоматско попуњавање</translation>
+<translation id="2710942282213947212">Софтвер на вашем рачунару онемогућава Chromium-у да се безбедно повеже на веб</translation>
<translation id="2712173769900027643">Затражи дозволу</translation>
-<translation id="2713444072780614174">Бела</translation>
<translation id="2720342946869265578">У близини</translation>
<translation id="2721148159707890343">Захтев је успео</translation>
<translation id="2728127805433021124">Сертификат сервера је потписан слабим алгоритмом.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Откривена је промена на мрежи.</translation>
<translation id="2916038427272391327">Затворите друге програме</translation>
<translation id="2922350208395188000">Није могуће проверити сертификат сервера.</translation>
+<translation id="2925673989565098301">Начин испоруке</translation>
<translation id="2928905813689894207">Адреса за обрачун</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат је са домена <ph name="DOMAIN2" />. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Погрешан тип смерница</translation>
<translation id="3032412215588512954">Желите ли поново да учитате овај сат?</translation>
<translation id="3037605927509011580">О, не!</translation>
+<translation id="3039538478787849737">Желите ли да сачувате картицу на Google-у?</translation>
<translation id="3041612393474885105">Информације о сертификату</translation>
<translation id="3063697135517575841">Chrome није успео да потврди картицу. Пробајте поново касније.</translation>
<translation id="3064966200440839136">Напустићете режим без архивирања да бисте платили у спољној апликацији. Желите ли да наставите?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Привремена грешка на серверу</translation>
<translation id="3154506275960390542">Ова страница садржи образац чије слање може да буде небезбедно. Податке које пошаљете могу да виде и други док су у пролазу и нападач може да их измени да би променио садржај који сервер прима.</translation>
<translation id="3157931365184549694">Поново отвори</translation>
+<translation id="3162559335345991374">Wi-Fi мрежа коју користите ће можда захтевати да посетите страницу за пријављивање.</translation>
<translation id="3167968892399408617">Странице које прегледате на картицама без архивирања се неће задржавати у историји прегледача, складишту колачића или историји претраге када затворите све картице без архивирања. Сачуваћемо све преузете датотеке или направљене обележиваче.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Острво</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Откажи плаћање</translation>
<translation id="3207960819495026254">Обележено</translation>
+<translation id="3211223744486044430">Да бисте следећи пут плаћали брже, сачувајте ову картицу на Google налогу и овом уређају.</translation>
<translation id="3225919329040284222">Сервер је приказао сертификат који се не подудара са уграђеним очекивањима. Та очекивања су обухваћена за одређене веб-сајтове са јаким безбедносним мерама како би вас заштитила.</translation>
<translation id="3226128629678568754">Притисните дугме Поново учитај да бисте поново послали податке потребне за учитавање странице.</translation>
<translation id="3227137524299004712">Микрофон</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Нису пронађени резултати претраге</translation>
<translation id="3305707030755673451">Подаци су шифровани помоћу приступне фразе за синхронизацију <ph name="TIME" />. Унесите је да бисте започели синхронизацију.</translation>
<translation id="3320021301628644560">Додајте адресу за обрачун</translation>
-<translation id="3329013043687509092">Засићеност боја</translation>
<translation id="333371639341676808">Спречите ову страницу да прави додатне дијалоге.</translation>
<translation id="3338095232262050444">Безбедан</translation>
<translation id="3340978935015468852">подешавања</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ИД клијента:</translation>
<translation id="3391030046425686457">Адреса испоруке</translation>
<translation id="3395827396354264108">Начин преузимања</translation>
+<translation id="3399952811970034796">Адреса испоруке</translation>
<translation id="3422248202833853650">Пробајте да изађете из других програма да бисте ослободили меморију.</translation>
<translation id="3422472998109090673">Хост <ph name="HOST_NAME" /> тренутно није доступан.</translation>
<translation id="3427092606871434483">Дозволи (подразумевано)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Извештај о отказивању је снимљен <ph name="CRASH_TIME" />, а отпремљен <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Информације о сертификату</translation>
<translation id="3690164694835360974">Пријављивање није безбедно</translation>
+<translation id="3704162925118123524">Мрежа коју користите ће можда захтевати да посетите страницу за пријављивање.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Учитава се...</translation>
<translation id="3712624925041724820">Нема више лиценци</translation>
<translation id="3714780639079136834">да укључите податке за мобилне уређаје или Wi-Fi</translation>
+<translation id="3715597595485130451">Повезивање са Wi-Fi мрежом</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />да проверите конфигурацију проксија, заштитног зида и DNS-а<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Ако разумете безбедносне ризике, можете да <ph name="BEGIN_LINK" />посетите овај небезбедни сајт<ph name="END_LINK" /> пре него што уклонимо опасне програме.</translation>
<translation id="3739623965217189342">Линк који сте копирали</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Опозови додавање</translation>
<translation id="404928562651467259">УПОЗОРЕЊЕ</translation>
<translation id="4058922952496707368">Кључ „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">Додајте важећу адресу</translation>
<translation id="4072486802667267160">Дошло је до грешке при обради поруџбине. Пробајте поново.</translation>
<translation id="4075732493274867456">Клијент и сервер не подржавају исту верзију SSL протокола или пакет за шифровање.</translation>
<translation id="4079302484614802869">Конфигурација проксија је подешена да користи URL адресу .pac скрипте, а не фиксне прокси сервере.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Серијски број уређаја је неважећи</translation>
<translation id="410351446219883937">Аутоплеј</translation>
<translation id="4103763322291513355">Посетите &lt;strong&gt;chrome://policy&lt;/strong&gt; да бисте видели листу URL-ова стављених на црну листу и друге смернице које је наметнуо администратор система.</translation>
-<translation id="4115378294792113321">Циклама</translation>
<translation id="4116663294526079822">Увек дозволи на овом сајту</translation>
<translation id="4117700440116928470">Опсег смерница није подржан.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{још 1}one{још #}few{још #}other{још #}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Покушали сте да контактирате <ph name="DOMAIN" />, али је издавач опозвао сертификат који је сервер навео. То значи да никако не треба имати поверења у безбедносне акредитиве које је сервер навео. Могуће је да комуницирате са нападачем.</translation>
<translation id="4394049700291259645">Онемогући</translation>
<translation id="4406896451731180161">резултати претраге</translation>
+<translation id="4415426530740016218">Адреса преузимања</translation>
<translation id="4424024547088906515">Овај сервер не може да докаже да је <ph name="DOMAIN" />; Chrome нема поверења у његов безбедносни сертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> није прихватио сертификат за пријављивање или сертификат за пријављивање није приложен.</translation>
<translation id="443673843213245140">Коришћење проксија је онемогућено, али је наведена експлицитна конфигурација проксија.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Покушајте да онемогућите додатке.</translation>
<translation id="457875822857220463">Испорука</translation>
+<translation id="4582800630050655161">Могли бисте да изгубите приступ Google налогу или би могло да дође до крађе идентитета. Chromium препоручује да одмах промените лозинку.</translation>
<translation id="4587425331216688090">Желите ли да уклоните адресу из Chrome-а?</translation>
<translation id="4592951414987517459">Веза са доменом <ph name="DOMAIN" /> је шифрована помоћу модерног пакета за шифровање.</translation>
<translation id="4594403342090139922">&amp;Опозови брисање</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат садржи грешке. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="4690462567478992370">Обустави коришћење неважећег сертификата</translation>
+<translation id="4690954380545377795">Могли бисте да изгубите приступ Google налогу или би могло да дође до крађе идентитета. Chrome препоручује да одмах промените лозинку.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Веза је прекинута</translation>
<translation id="471880041731876836">Немате дозволу да посетите овај сајт</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />да покренете Windows дијагностику мреже<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Плаћање</translation>
<translation id="4726672564094551039">Поново учитај смернице</translation>
<translation id="4728558894243024398">Платформа</translation>
<translation id="4736825316280949806">Поново покрените Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Складиште тока података је у лошем стању</translation>
<translation id="5023310440958281426">Проверите смернице администратора</translation>
<translation id="5029568752722684782">Обриши копију</translation>
+<translation id="503069730517007720">Основни сертификат за софтвер „<ph name="SOFTWARE_NAME" />“ је обавезан, али није инсталиран. ИТ администратор треба да прегледа упутства за конфигурацију софтвера „<ph name="SOFTWARE_NAME" />“ да би решио овај проблем. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">О Google преводиоцу</translation>
<translation id="5039804452771397117">Дозволи</translation>
<translation id="5040262127954254034">Приватност</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Експерименти</translation>
<translation id="5205222826937269299">Име је обавезно</translation>
<translation id="5222812217790122047">Имејл је обавезан</translation>
+<translation id="522700295135997067">Овај сајт вам је можда управо украо лозинку</translation>
+<translation id="5230733896359313003">Адреса за слање</translation>
<translation id="5251803541071282808">Клауд</translation>
<translation id="5277279256032773186">Да ли користите Chrome на послу? Предузеће може да управља подешавањима Chrome-а за запослене. Сазнајте више</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Пратите ове кораке да бисте привремено онемогућили софтвер и приступили вебу. Требаће вам привилегије администратора.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Веза са овим сајтом није приватна. Да бисте у било ком тренутку изашли из ВР режима, уклоните хедсет и притисните Назад.</translation>
<translation id="5299298092464848405">Грешка при рашчлањивању смерница</translation>
+<translation id="5308380583665731573">Повезивање</translation>
<translation id="5308689395849655368">Извештавање о отказивању је онемогућено.</translation>
<translation id="5317780077021120954">Сачувај</translation>
<translation id="5327248766486351172">Назив</translation>
+<translation id="5332219387342487447">Начин испоруке</translation>
<translation id="5355557959165512791">Тренутно не можете да посетите <ph name="SITE" /> јер је његов сертификат опозван. Грешке и напади на мрежи су обично привремени, па ће ова страница вероватно функционисати касније.</translation>
<translation id="536296301121032821">Складиштење подешавања смерница није успело</translation>
<translation id="5386426401304769735">Ланац сертификата за овај сајт садржи сертификат потписан помоћу алгоритма SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Овај сајт на интранету компаније, организације или школе има исти URL као и један спољни веб-сајт.
<ph name="LINE_BREAK" />
Покушајте да се обратите администратору система.</translation>
+<translation id="5499929369096410817">Унесите безбедносни кôд за картицу <ph name="CREDIT_CARD" />. Овај кôд се не чува.</translation>
<translation id="5509780412636533143">Обележивачи којим се управља</translation>
<translation id="5510766032865166053">Можда је премештен или избрисан.</translation>
<translation id="5523118979700054094">Назив смерница</translation>
<translation id="552553974213252141">Да ли је текст правилно издвојен?</translation>
<translation id="5540224163453853">Нисмо пронашли захтевани чланак.</translation>
+<translation id="5541546772353173584">Додајте имејл</translation>
<translation id="5544037170328430102">Уграђена страница на <ph name="SITE" /> каже:</translation>
+<translation id="5545756402275714221">Чланци за вас</translation>
<translation id="5556459405103347317">Учитај поново</translation>
<translation id="5560088892362098740">Датум истека</translation>
<translation id="5565735124758917034">Активно</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Имејл</translation>
<translation id="5669703222995421982">Добијте персонализовани садржај</translation>
<translation id="5675650730144413517">Ова страница не функционише</translation>
+<translation id="5689199277474810259">Извези у JSON</translation>
<translation id="5710435578057952990">Идентитет овог веб-сајта није верификован.</translation>
<translation id="5719499550583120431">Прихватају се припејд картице.</translation>
<translation id="5720705177508910913">Тренутни корисник</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Веза са доменом <ph name="DOMAIN" /> је шифрована помоћу застарелог пакета за шифровање.</translation>
<translation id="5813119285467412249">&amp;Понови додавање</translation>
<translation id="5838278095973806738">Немојте да уносите осетљиве информације на овом сајту (на пример, лозинке или кредитне картице) јер нападачи могу да их украду.</translation>
+<translation id="5866257070973731571">Додајте број телефона</translation>
<translation id="5869405914158311789">Овај сајт није доступан</translation>
<translation id="5869522115854928033">Сачуване лозинке</translation>
<translation id="5872918882028971132">Предлози родитеља</translation>
<translation id="5893752035575986141">Прихватају се кредитне картице.</translation>
-<translation id="5901630391730855834">Жута</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (синхронизовано)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Користи се 1}one{Користи се #}few{Користе се #}other{Користи се #}}</translation>
<translation id="5959728338436674663">Аутоматски шаљите одређене <ph name="BEGIN_WHITEPAPER_LINK" />информације о систему и садржај страница<ph name="END_WHITEPAPER_LINK" /> Google-у да бисте нам помогли да откријемо опасне апликације и сајтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Измените контакт информације</translation>
<translation id="5967867314010545767">Уклони из историје</translation>
<translation id="5975083100439434680">Умањивање</translation>
+<translation id="597552863672748783">Потврдите безбедносни кôд</translation>
<translation id="598637245381783098">Отварање апликације за плаћање није успело</translation>
<translation id="5989320800837274978">Нису наведени ни фиксни прокси сервери нити URL адреса .pac скрипте.</translation>
<translation id="5990559369517809815">Додатак је блокирао захтеве упућене серверу.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. страница}one{#. страница}few{#. страница}other{#. страница}}</translation>
-<translation id="6017514345406065928">Зелена</translation>
<translation id="6017850046339264347">Нападачи који су на <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (синхронизовано)</translation>
<translation id="6027201098523975773">Унесите назив</translation>
<translation id="6040143037577758943">Затвори</translation>
-<translation id="6042308850641462728">Више</translation>
<translation id="6047233362582046994">Ако разумете безбедносне ризике, можете да <ph name="BEGIN_LINK" />посетите овај сајт<ph name="END_LINK" /> пре него што уклонимо штетне апликације.</translation>
<translation id="6047927260846328439">Овај садржај ће покушати да вас превари да инсталирате софтвер или откријете личне податке. <ph name="BEGIN_LINK" />Ипак прикажи<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Тренутно не можете да посетите <ph name="SITE" /> јер веб-сајт користи проверу сертификата. Грешке и напади на мрежи су обично привремени, па ће ова страница вероватно функционисати касније.</translation>
@@ -696,6 +722,7 @@
<translation id="6569060085658103619">Прегледате страницу додатка.</translation>
<translation id="6596325263575161958">Опције шифровања</translation>
<translation id="662080504995468778">Не затварај</translation>
+<translation id="6624427990725312378">Контакт информације</translation>
<translation id="6626291197371920147">Додајте важећи број картице</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> претрага</translation>
<translation id="6630809736994426279">Нападачи који су тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ће можда покушати да инсталирају опасне програме на Mac-у који краду или бришу податке (на пример, слике, лозинке, поруке и бројеве кредитних картица). <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -706,7 +733,6 @@
<translation id="6710213216561001401">Претходно</translation>
<translation id="6710594484020273272">&lt;Унесите термин за претрагу&gt;</translation>
<translation id="6711464428925977395">Нешто није у реду са прокси сервером или је адреса нетачна.</translation>
-<translation id="6727102863431372879">Постави</translation>
<translation id="674375294223700098">Непозната грешка сертификата сервера.</translation>
<translation id="6753269504797312559">Вредност смерница</translation>
<translation id="6757797048963528358">Уређај је прешао у режим спавања.</translation>
@@ -775,6 +801,7 @@
<translation id="7400418766976504921">URL адреса</translation>
<translation id="7419106976560586862">Путања профила</translation>
<translation id="7424977062513257142">Уграђена страница на овој веб-страници каже:</translation>
+<translation id="7437289804838430631">Додај контакт информације</translation>
<translation id="7441627299479586546">Погрешан субјекат смерница</translation>
<translation id="7444046173054089907">Овај сајт је блокиран</translation>
<translation id="7445762425076701745">Није могуће у потпуности потврдити идентитет сервера са којим сте повезани. Повезани сте са сервером који користи назив који је важећи само у вашој мрежи, а којем спољни ауторитет за издавање сертификата не може да провери власништво. Будући да неки ауторитети за издавање сертификата упркос томе издају сертификате за ове називе, ни на који начин не можете да будете сигурни да сте повезани са жељеним веб-сајтом, а не са нападачем.</translation>
@@ -785,11 +812,11 @@
<translation id="7481312909269577407">Проследи</translation>
<translation id="7485870689360869515">Нису пронађени подаци.</translation>
<translation id="7508255263130623398">Враћени ИД уређаја за смернице је празан или се не подудара са актуелним ИД-ом уређаја</translation>
+<translation id="7511955381719512146">Wi-Fi мрежа коју користите ће можда захтевати да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Преузми</translation>
<translation id="7518003948725431193">Ниједна веб-страница није пронађена за веб адресу: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Веза са овим сајтом није приватна</translation>
-<translation id="7535087603100972091">Вредност</translation>
<translation id="7537536606612762813">Обавезно</translation>
<translation id="7542403920425041731">Када будете потврдили, подаци о картици ће бити послати овом сајту.</translation>
<translation id="7542995811387359312">Онемогућено је аутоматско попуњавање кредитне картице зато што овај образац не користи безбедну везу.</translation>
@@ -800,7 +827,6 @@
<translation id="7567204685887185387">Овај сервер не може да докаже да је <ph name="DOMAIN" />; његов безбедносни сертификат је можда лажно издат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="7568593326407688803">Ова страница је на језику:<ph name="ORIGINAL_LANGUAGE" />Желите ли да је преведете?</translation>
<translation id="7569952961197462199">Желите ли да уклоните кредитну картицу из Chrome-а?</translation>
-<translation id="7569983096843329377">Црна</translation>
<translation id="7578104083680115302">Плаћајте брзо на сајтовима и у апликацијама на свим уређајима помоћу картица које сте сачували на Google-у.</translation>
<translation id="7588950540487816470">Интернет око нас</translation>
<translation id="7592362899630581445">Сертификат сервера крши ограничења за име.</translation>
@@ -819,11 +845,13 @@
<translation id="7669271284792375604">Нападачи на овом сајту могу да покушају да вас преваре да бисте инсталирали програме који штете доживљају прегледања (на пример, тако што мењају почетну страницу или приказују додатне огласе на сајтовима које посећујете).</translation>
<translation id="7674629440242451245">Интересују вас нове занимљиве Chrome функције? Испробајте програмерски канал на chrome.com/dev.</translation>
<translation id="7682287625158474539">Испорука</translation>
+<translation id="7699293099605015246">Чланци тренутно нису доступни</translation>
<translation id="7701040980221191251">Ниједна</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Настави на <ph name="SITE" /> (није безбедно)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Сертификат</translation>
<translation id="7716147886133743102">Блокира администратор</translation>
<translation id="7716424297397655342">Није могуће учитати овај сајт из кеша</translation>
+<translation id="7723047071702270851">Измените картицу</translation>
<translation id="774634243536837715">Опасан садржај је блокиран.</translation>
<translation id="7752995774971033316">Не управља</translation>
<translation id="7755287808199759310">Родитељ може да га деблокира за тебе</translation>
@@ -834,21 +862,24 @@
<translation id="7764225426217299476">Додајте адресу</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Додај</translation>
+<translation id="7793553086574152071">Да бисте следећи пут плаћали брже, сачувајте ову картицу на Google налогу.</translation>
<translation id="7793809570500803535">Могуће је да веб-страница на сајту <ph name="SITE" /> привремено не функционише или да је трајно премештена на нову веб адресу.</translation>
<translation id="7800304661137206267">Веза је шифрована помоћу <ph name="CIPHER" />, са <ph name="MAC" /> за потврду идентитета поруке и <ph name="KX" /> као механизмом за размену кључева.</translation>
+<translation id="7802523362929240268">Сајт је легитиман</translation>
<translation id="780301667611848630">Не, хвала</translation>
<translation id="7805768142964895445">Статус</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Желите ли да уклоните предлог из Chrome-а?</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="785549533363645510">Али, нисте невидљиви. Преласком у режим без архивирања нећете сакрити прегледање од послодавца, интернет провајдера или веб-сајтова које посећујете.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Прихватају се дебитне и припејд картице.</translation>
+<translation id="7878562273885520351">Лозинка је можда компромитована</translation>
<translation id="7887683347370398519">Проверите CVC и покушајте поново</translation>
<translation id="79338296614623784">Унесите важећи број телефона</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Сертификат сервера још увек није важећи.</translation>
-<translation id="7942349550061667556">Црвена</translation>
<translation id="7947285636476623132">Проверите годину истека и пробајте поново</translation>
<translation id="7951415247503192394">(32-битни)</translation>
<translation id="7956713633345437162">Обележивачи на мобилном уређају</translation>
@@ -862,9 +893,13 @@
<translation id="8037357227543935929">Питај (подразумевано)</translation>
<translation id="8041089156583427627">Пошаљи повратне информације</translation>
<translation id="8041940743680923270">Користи глобалну подразумевану вредност (Питај)</translation>
+<translation id="8057711352706143257">Софтвер „<ph name="SOFTWARE_NAME" />“ није правилно конфигурисан. Деинсталирање софтвера „<ph name="SOFTWARE_NAME" />“ обично решава проблем. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Прегледање чланка није успело.</translation>
<translation id="8091372947890762290">Активација је на чекању на серверу</translation>
+<translation id="8094917007353911263">Мрежа коју користите ће можда захтевати да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Начин плаћања</translation>
<translation id="8118489163946903409">Начин плаћања</translation>
+<translation id="8127301229239896662">Софтвер „<ph name="SOFTWARE_NAME" />“ није правилно инсталиран на рачунару или мрежи. Затражите од ИТ администратора да реши овај проблем.</translation>
<translation id="8131740175452115882">Потврди</translation>
<translation id="8134994873729925007">Нисмо успели да пронађемо <ph name="BEGIN_ABBR" />DNS адресу<ph name="END_ABBR" /> сервера хоста <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Рачунар је прешао у режим спавања.</translation>
@@ -887,6 +922,7 @@
<translation id="8289355894181816810">Контактирајте администратора мреже ако нисте сигурни шта то значи.</translation>
<translation id="8293206222192510085">Додавање обележивача</translation>
<translation id="8294431847097064396">Извор</translation>
+<translation id="8298115750975731693">Wi-Fi мрежа коју користите (<ph name="WIFI_NAME" />) ће можда захтевати да посетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Успостављање приватне везе са доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> није успело јер су датум и време уређаја (<ph name="DATE_AND_TIME" />) нетачни. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Превођење није успело због проблема са мрежном везом.</translation>
<translation id="8332188693563227489">Приступ хосту <ph name="HOST_NAME" /> је одбијен</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">Недавно затворено</translation>
<translation id="8874824191258364635">Унесите важећи број картице</translation>
<translation id="8876793034577346603">Рашчлањивање конфигурације мреже није успело.</translation>
-<translation id="8889402386540077796">Нијанса</translation>
<translation id="8891727572606052622">Неважећи режим проксија.</translation>
<translation id="889901481107108152">Жао нам је, овај експеримент није доступан на платформи.</translation>
<translation id="8903921497873541725">Увећавање</translation>
<translation id="8931333241327730545">Да ли желите да сачувате ову картицу на Google налог?</translation>
<translation id="8932102934695377596">Сат вам касни</translation>
+<translation id="893332455753468063">Додајте име</translation>
<translation id="8938939909778640821">Прихватају се кредитне и припејд картице</translation>
+<translation id="8957210676456822347">Овлашћење на улазном порталу</translation>
<translation id="8971063699422889582">Сертификат сервера је истекао.</translation>
-<translation id="8986494364107987395">Аутоматски шаљи Google-у статистичке податке о коришћењу и извештаје о отказивању</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Сајт који ћете посетити садржи штетне програме</translation>
<translation id="8997023839087525404">Сервер је приказао сертификат који није јавно откривен помоћу смерница Транспарентност сертификата. То је обавезно за неке сертификате да бисмо се уверили да су поуздани и да штите од нападача.</translation>
<translation id="9001074447101275817">Прокси <ph name="DOMAIN" /> захтева корисничко име и лозинку.</translation>
<translation id="9005998258318286617">Учитавање PDF документа није успело.</translation>
+<translation id="9008201768610948239">Игнориши</translation>
<translation id="901974403500617787">Ознаке које се примењују у целом систему може да подеси само власник: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Адреса за обрачун за картицу је обавезна</translation>
<translation id="9020542370529661692">Ова страница је преведена на <ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">Покушали сте да дођете до домена <ph name="DOMAIN" />, али сервер је послао неважећи сертификат.</translation>
<translation id="9050666287014529139">Приступна фраза</translation>
<translation id="9065203028668620118">Измени</translation>
-<translation id="9068849894565669697">Изаберите боју</translation>
<translation id="9069693763241529744">Блокира додатак</translation>
<translation id="9076283476770535406">Можда обухвата садржај за одрасле</translation>
<translation id="9078964945751709336">Потребно је више информација</translation>
+<translation id="9080712759204168376">Резиме поруџбине</translation>
<translation id="9103872766612412690"><ph name="SITE" /> обично користи шифровање да би заштитио информације. Када је Chromium овог пута покушао да се повеже са <ph name="SITE" />, веб-сајт је вратио необичне и нетачне акредитиве. Или нападач покушава да се представи као <ph name="SITE" /> или је екран за Wi-Fi пријављивање прекинуо везу. Информације су и даље безбедне зато што је Chromium прекинуо везу пре него што су размењени било какви подаци.</translation>
+<translation id="9106062320799175032">Додајте адресу за обрачун</translation>
+<translation id="910908805481542201">Помозите ми да решим ово</translation>
+<translation id="9128870381267983090">Повезивање са мрежом</translation>
<translation id="9137013805542155359">Прикажи оригинал</translation>
<translation id="9137248913990643158">Пријавите се у Chrome пре коришћења ове апликације.</translation>
<translation id="9148507642005240123">&amp;Опозови измену</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419">Хост <ph name="HOST_NAME" /> користи неподржани протокол.</translation>
<translation id="9205078245616868884">Подаци се шифрују помоћу приступне фразе за синхронизацију. Унесите је да бисте започели синхронизацију.</translation>
<translation id="9207861905230894330">Додавање чланка није успело.</translation>
+<translation id="9215416866750762878">Апликација онемогућава Chrome-у да се безбедно повеже са овим сајтом</translation>
<translation id="9219103736887031265">Слике</translation>
<translation id="933612690413056017">Није успостављена веза са интернетом</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{None}=1{1 ставка}one{# ставка}few{# ставке}other{# ставки}}</translation>
<translation id="981121421437150478">Офлајн</translation>
<translation id="988159990683914416">Верзија за програмере</translation>
+<translation id="989988560359834682">Измена адресе</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">Софтвер „<ph name="SOFTWARE_NAME" />“ није правилно инсталиран на рачунару или мрежи:
+ &lt;ul&gt;
+ &lt;li&gt;Пробајте да деинсталирате или онемогућите „<ph name="SOFTWARE_NAME" />“&lt;/li&gt;
+ &lt;li&gt;Пробајте да се повежете са другом мрежом&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index 4870f0daa0f..1e2a55825ab 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Bokmärken på skrivbordet</translation>
<translation id="1074497978438210769">Inte säker</translation>
<translation id="1080116354587839789">Anpassa till fönstrets bredd</translation>
+<translation id="1088860948719068836">Lägg till namnet på kortet</translation>
<translation id="1103523840287552314">Översätt alltid <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Visa alla sparade lösenord …</translation>
<translation id="1107591249535594099">Om alternativet är markerat sparas en kopia av kortet på enheten så att det går snabbare att fylla i formulär.</translation>
<translation id="1111153019813902504">Nya bokmärken</translation>
<translation id="1113869188872983271">&amp;Ångra Ändra ordning</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synkroniserade)</translation>
<translation id="1263231323834454256">Läslista</translation>
<translation id="1264126396475825575">Felrapport skapades <ph name="CRASH_TIME" /> (har ännu inte laddats upp eller ignorerats)</translation>
+<translation id="1270502636509132238">Alternativ för utlämning</translation>
<translation id="1281526147609854549">Utfärdades av <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Översätt aldrig den här webbplatsen</translation>
<translation id="129553762522093515">Nyligen stängda</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Väntar på anslutning …</translation>
<translation id="153384715582417236">Det var allt för den här gången</translation>
<translation id="1549470594296187301">JavaScript måste aktiveras för att du ska kunna använda den här funktionen.</translation>
-<translation id="1555130319947370107">Blå</translation>
<translation id="1559528461873125649">Filen eller katalogen finns inte</translation>
<translation id="1583429793053364125">Ett fel uppstod när webbsidan skulle visas.</translation>
<translation id="1592005682883173041">Lokal dataåtkomst</translation>
<translation id="1594030484168838125">Välj</translation>
-<translation id="161042844686301425">Cyanblå</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Vill du att Chrome sparar det här kortet?</translation>
<translation id="1639239467298939599">Läser in</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Du behöver tillstånd från <ph name="NAME" /> om du vill besöka den här webbplatsen</translation>
<translation id="1721424275792716183">* Fältet är obligatoriskt</translation>
+<translation id="1727741090716970331">Lägg till ett giltigt kortnummer</translation>
<translation id="1728677426644403582">Du visar källkoden till en webbsida</translation>
<translation id="173080396488393970">Denna korttyp stöds inte</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serieproduktionsfel</translation>
<translation id="1974060860693918893">Avancerat</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
-<translation id="1995859865337580572">Verifiera CVC-koden</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{och 1 till}other{och # till}}</translation>
<translation id="2025186561304664664">Proxyn är inställd på automatisk konfiguration.</translation>
<translation id="2030481566774242610">Menade du <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Logga in i Chrome om du vill få förslag på anpassat innehåll från Google.</translation>
+<translation id="2091887806945687916">Ljud</translation>
<translation id="2094505752054353250">Domänen matchar inte</translation>
<translation id="2096368010154057602">Departement</translation>
<translation id="2108755909498034140">Starta om datorn</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Ignoreras eftersom den åsidosätts av <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Söker efter Physical Web-sidor i närheten</translation>
<translation id="213826338245044447">Bokmärken i mobilen</translation>
+<translation id="214556005048008348">Avbryt betalningen</translation>
<translation id="2147827593068025794">Bakgrundssynkronisering</translation>
+<translation id="2148613324460538318">Lägg till kort</translation>
<translation id="2154054054215849342">Synkronisering är inte tillgänglig för din domän</translation>
<translation id="2154484045852737596">Redigera kortet</translation>
<translation id="2166049586286450108">Fullständig administrativ åtkomst</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adress}other{# adresser}}</translation>
<translation id="2187317261103489799">Identifiera (standard)</translation>
<translation id="2202020181578195191">Ange ett giltigt utgångsår</translation>
+<translation id="2209523182407020534">Det här problemet kan orsakas av bland annat antivirusprogram, brandväggar, webbfiltrerings- och proxyprogram.</translation>
<translation id="2212735316055980242">Policyn hittades inte</translation>
<translation id="2213606439339815911">Hämtar poster …</translation>
<translation id="2218879909401188352">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> skulle kunna installera farliga appar som skadar enheten, lägger till dolda avgifter på din mobilfaktura eller stjäl personliga uppgifter. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Föregående</translation>
<translation id="2503184589641749290">Godkända betalkort och förbetalda kort</translation>
<translation id="2515629240566999685">kontrollera mottagningen i området</translation>
+<translation id="2524461107774643265">Lägg till mer information</translation>
+<translation id="2536110899380797252">Lägg till adress</translation>
<translation id="2539524384386349900">Identifiera</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> skickade ett ogiltigt svar.</translation>
<translation id="2556876185419854533">&amp;Ånga Redigera</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium kunde inte bekräfta kortet. Försök igen senare.</translation>
<translation id="2705137772291741111">Det gick inte att läsa den sparade (cachelagrade) kopian av webbplatsen.</translation>
<translation id="2709516037105925701">Autofyll</translation>
+<translation id="2710942282213947212">Programvara på datorn förhindrar att Chromium ansluts till internet på ett säkert sätt</translation>
<translation id="2712173769900027643">Begär behörighet</translation>
-<translation id="2713444072780614174">Vit</translation>
<translation id="2720342946869265578">I närheten</translation>
<translation id="2721148159707890343">Begäran genomfördes</translation>
<translation id="2728127805433021124">Serverns certifikat är signerat med en svag signaturalgoritm.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">En nätverksförändring upptäcktes.</translation>
<translation id="2916038427272391327">Stäng andra program</translation>
<translation id="2922350208395188000">Servercertifikatet kan inte kontrolleras.</translation>
+<translation id="2925673989565098301">Leveranssätt</translation>
<translation id="2928905813689894207">Faktureringsadress</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> till}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> till}}</translation>
<translation id="2941952326391522266">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kommer från <ph name="DOMAIN2" />. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Felaktig policytyp</translation>
<translation id="3032412215588512954">Vill du läsa in den här webbplatsen igen?</translation>
<translation id="3037605927509011580">Oj, ett fel har uppstått!</translation>
+<translation id="3039538478787849737">Vill du spara kortet hos Google?</translation>
<translation id="3041612393474885105">Certifikatinformation</translation>
<translation id="3063697135517575841">Det gick inte att bekräfta kortet. Försök igen senare.</translation>
<translation id="3064966200440839136">Om du betalar i ett externt program sker inte det i inkognitoläge. Vill du fortsätta?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Tillfälligt serverfel</translation>
<translation id="3154506275960390542">Den här sidan innehåller ett formulär som kanske inte kan skickas säkert. Data som skickas kan visas av andra vid överföringen eller modifieras av en obehörig innan den tas emot av servern.</translation>
<translation id="3157931365184549694">Återställ</translation>
+<translation id="3162559335345991374">Wi-Fi-nätverket du använder kanske kräver att du besöker dess inloggningssida.</translation>
<translation id="3167968892399408617">Sidor som visas på flikar i inkognitoläget försvinner från webbhistoriken, från dina cookies och från sökhistoriken när alla inkognitoflikar har stängts. Alla filer som du laddar ned eller bokmärken som du skapar sparas.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ö</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Avbryt betalningen</translation>
<translation id="3207960819495026254">Bokmärkt</translation>
+<translation id="3211223744486044430">Spara det här kortet i Google-kontot och på enheten så går det snabbare att betala nästa gång.</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>
<translation id="3226128629678568754">Om du på nytt vill skicka datan som behövs för att läsa in sidan trycker du på knappen Läs in igen.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Inga sökresultat hittades</translation>
<translation id="3305707030755673451">Din data krypterades med din lösenfras för synkronisering den <ph name="TIME" />. Ange den om du vill starta synkroniseringen.</translation>
<translation id="3320021301628644560">Lägg till faktureringsadress</translation>
-<translation id="3329013043687509092">Mättnad</translation>
<translation id="333371639341676808">Förhindra att den här sidan öppnar ytterligare dialogrutor.</translation>
<translation id="3338095232262050444">Säker</translation>
<translation id="3340978935015468852">inställningar</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Klient-ID:</translation>
<translation id="3391030046425686457">Leveransadress</translation>
<translation id="3395827396354264108">Alternativ för utlämning</translation>
+<translation id="3399952811970034796">Leveransadress</translation>
<translation id="3422248202833853650">Testa att stänga andra program för att frigöra minne.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan inte nås för tillfället.</translation>
<translation id="3427092606871434483">Tillåt (standard)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Kraschrapporten skapades den <ph name="CRASH_TIME" /> och laddades upp den <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certifikatinformation</translation>
<translation id="3690164694835360974">Osäker inloggning</translation>
+<translation id="3704162925118123524">Nätverket du använder kanske kräver att du besöker dess inloggningssida.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Läser in...</translation>
<translation id="3712624925041724820">Licenserna har tagit slut</translation>
<translation id="3714780639079136834">aktivera mobildata eller Wi-Fi</translation>
+<translation id="3715597595485130451">Anslut till Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />kontrollera proxyn, brandväggen och DNS-konfigureringen<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Om du är medveten om säkerhetsriskerna kan du <ph name="BEGIN_LINK" />besöka den här osäkra webbplatsen<ph name="END_LINK" /> innan de skadliga programmen har tagits bort.</translation>
<translation id="3739623965217189342">Länk som du har kopierat</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Ångra Lägg till</translation>
<translation id="404928562651467259">VARNING</translation>
<translation id="4058922952496707368">Nyckel <ph name="SUBKEY" />: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxykonfigurationen är inställd på att använda en webbadress med PAC-skript, inte fasta proxyservrar.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Enhetens serienummer är ogiltigt</translation>
<translation id="410351446219883937">Automatisk uppspelning</translation>
<translation id="4103763322291513355">Besök &lt;strong&gt;chrome://policy&lt;/strong&gt; om du vill visa listan med webbadresser som inte är godkända och andra policyer som angetts av systemadministratören.</translation>
-<translation id="4115378294792113321">Magenta</translation>
<translation id="4116663294526079822">Tillåt alltid på den här webbplatsen</translation>
<translation id="4117700440116928470">Principens omfattning stöds inte.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 till}other{# till}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Du försökte öppna <ph name="DOMAIN" />, men servern visade ett certifikat som har återkallats av utfärdaren. Det innebär att säkerhetsuppgifterna som servern visar inte är absolut tillförlitliga. Du kanske kommunicerar med en skadlig server.</translation>
<translation id="4394049700291259645">Inaktivera</translation>
<translation id="4406896451731180161">sökresultat</translation>
+<translation id="4415426530740016218">Hämtningsadress</translation>
<translation id="4424024547088906515">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom Chrome inte litar på dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller så har inget inloggningscertifikat angetts.</translation>
<translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Testa att inaktivera tilläggen.</translation>
<translation id="457875822857220463">Leverans</translation>
+<translation id="4582800630050655161">Du kan förlora tillgången till Google-kontot eller bli utsatt för identitetsstöld. Du rekommenderas att ändra lösenordet nu.</translation>
<translation id="4587425331216688090">Vill du ta bort adressen från Chrome?</translation>
<translation id="4592951414987517459">Anslutningen till <ph name="DOMAIN" /> är krypterad med en modern krypteringssvit.</translation>
<translation id="4594403342090139922">&amp;Ångra Ta bort</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Sluta använda ett ogiltigt certifikat</translation>
+<translation id="4690954380545377795">Du kan förlora tillgången till Google-kontot eller bli utsatt för identitetsstöld. Du rekommenderas att ändra lösenordet nu.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Anslutningen avbröts</translation>
<translation id="471880041731876836">Du har inte behörighet att besöka den här webbplatsen.</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" /> köra nätverksdiagnostik för Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Din betalning</translation>
<translation id="4726672564094551039">Läs in policyer på nytt</translation>
<translation id="4728558894243024398">Plattform</translation>
<translation id="4736825316280949806">Starta om Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Säkerhetskopian har dålig status</translation>
<translation id="5023310440958281426">Kontrollera administratörsprinciperna</translation>
<translation id="5029568752722684782">Ta bort kopia</translation>
+<translation id="503069730517007720">Ett rotcertifikat för <ph name="SOFTWARE_NAME" /> krävs men har inte installerats. IT-administratören bör granska konfigurationsanvisningarna för <ph name="SOFTWARE_NAME" /> och åtgärda problemet. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Om Google Översätt</translation>
<translation id="5039804452771397117">Tillåt</translation>
<translation id="5040262127954254034">Sekretess</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Experiment</translation>
<translation id="5205222826937269299">Namn måste anges</translation>
<translation id="5222812217790122047">E-postadress måste anges</translation>
+<translation id="522700295135997067">Webbplatsen kan ha stulit ditt lösenord</translation>
+<translation id="5230733896359313003">Leveransadress</translation>
<translation id="5251803541071282808">Moln</translation>
<translation id="5277279256032773186">Använder du Chrome på jobbet? Företag kan hantera de anställdas inställningar i Chrome. Läs mer</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Följ stegen nedan för att inaktivera programvaran tillfälligt så att du kan komma ut på internet. Du måste ha administratörsbehörighet.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Din anslutning till webbplatsen är inte privat. Du kan när som helst avsluta VR-läget genom att ta av headsetet och trycka på bakåt.</translation>
<translation id="5299298092464848405">Det uppstod ett fel när policyn analyserades</translation>
+<translation id="5308380583665731573">Ansluta</translation>
<translation id="5308689395849655368">Krashrapportering har inaktiverats.</translation>
<translation id="5317780077021120954">Spara</translation>
<translation id="5327248766486351172">Namn</translation>
+<translation id="5332219387342487447">Fraktmetod</translation>
<translation id="5355557959165512791">Det går inte att besöka <ph name="SITE" /> just nu eftersom dess certifikat har återkallats. Nätverksfel och attacker är ofta tillfälliga, så sidan kommer förmodligen att fungera senare.</translation>
<translation id="536296301121032821">Det gick inte att spara policyinställningarna</translation>
<translation id="5386426401304769735">Certifikatkedjan för den här webbplatsen innehåller ett certifikat som signerades med SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Webbplatsen på företagets, organisationens eller skolans intranät har samma webbadress som en extern webbplats.
<ph name="LINE_BREAK" />
Testa med att kontakta systemadministratören.</translation>
+<translation id="5499929369096410817">Ange säkerhetskoden för <ph name="CREDIT_CARD" />. Koden sparas inte.</translation>
<translation id="5509780412636533143">Hanterade bokmärken</translation>
<translation id="5510766032865166053">Den kan ha flyttats eller tagits bort.</translation>
<translation id="5523118979700054094">Policynamn</translation>
<translation id="552553974213252141">Extraherades texten korrekt?</translation>
<translation id="5540224163453853">Det gick inte att hitta den önskade artikeln.</translation>
+<translation id="5541546772353173584">Lägg till e-postadress</translation>
<translation id="5544037170328430102">På en inbäddad sida på <ph name="SITE" /> står det:</translation>
+<translation id="5545756402275714221">Artiklar för dig</translation>
<translation id="5556459405103347317">Hämta igen</translation>
<translation id="5560088892362098740">Sista giltighetsdatum</translation>
<translation id="5565735124758917034">Aktiv</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-post</translation>
<translation id="5669703222995421982">Få anpassat innehåll</translation>
<translation id="5675650730144413517">Sidan fungerar inte</translation>
+<translation id="5689199277474810259">Exportera som JSON</translation>
<translation id="5710435578057952990">Webbplatsens identitet har inte verifierats.</translation>
<translation id="5719499550583120431">Förbetalda kort kan användas.</translation>
<translation id="5720705177508910913">Aktuell användare</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Anslutningen till <ph name="DOMAIN" /> är krypterad med en gammal krypteringssvit.</translation>
<translation id="5813119285467412249">&amp;Gör om Lägg till</translation>
<translation id="5838278095973806738">Du bör inte ange några känsliga uppgifter på den här webbplatsen (till exempel lösenord eller kreditkortsuppgifter) eftersom hackare kan stjäla dem.</translation>
+<translation id="5866257070973731571">Ange telefonnummer</translation>
<translation id="5869405914158311789">Webbplatsen kan inte nås</translation>
<translation id="5869522115854928033">Sparade lösenord</translation>
<translation id="5872918882028971132">Föräldratips</translation>
<translation id="5893752035575986141">Kreditkort får användas.</translation>
-<translation id="5901630391730855834">Gul</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkroniserade)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 används}other{# används}}</translation>
<translation id="5959728338436674663">Skicka automatiskt viss <ph name="BEGIN_WHITEPAPER_LINK" />information om systemet och innehåll på sidan<ph name="END_WHITEPAPER_LINK" /> för att hjälpa Google att identifiera skadliga appar och webbplatser. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Redigera kontaktuppgifter</translation>
<translation id="5967867314010545767">Ta bort från historiken</translation>
<translation id="5975083100439434680">Zooma ut</translation>
+<translation id="597552863672748783">Bekräfta säkerhetskoden</translation>
<translation id="598637245381783098">Det gick inte att öppna betalningsappen</translation>
<translation id="5989320800837274978">Varken fasta proxyservrar eller en webbadress med PAC-skript har angetts.</translation>
<translation id="5990559369517809815">Förfrågningar till servern har blockerats av ett tillägg.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Sida 1}other{Sida #}}</translation>
-<translation id="6017514345406065928">Grön</translation>
<translation id="6017850046339264347">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> skulle kunna installera bedrägliga appar som inte gör vad de påstås göra eller samla in data som används för att spåra dig. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synkroniserade)</translation>
<translation id="6027201098523975773">Ange ett namn</translation>
<translation id="6040143037577758943">Stäng</translation>
-<translation id="6042308850641462728">Mer</translation>
<translation id="6047233362582046994">Om du är medveten om säkerhetsriskerna kan du <ph name="BEGIN_LINK" />besöka webbplatsen<ph name="END_LINK" /> innan de skadliga apparna har tagits bort.</translation>
<translation id="6047927260846328439">Sidan kan ha till syfte att försöka lura dig att installera programvara eller avslöja personliga uppgifter. <ph name="BEGIN_LINK" />Visa ändå<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan inte besöka <ph name="SITE" /> just nu eftersom tekniken att fästa certifikat används på webbplatsen. Nätverksfel och attacker är ofta tillfälliga, så sidan kommer förmodligen att fungera senare.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Du visar en tilläggssida</translation>
<translation id="6596325263575161958">Krypteringsalternativ</translation>
<translation id="662080504995468778">Stanna kvar</translation>
+<translation id="6624427990725312378">Kontaktuppgifter</translation>
<translation id="6626291197371920147">Lägg till ett giltigt kortnummer</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Sök</translation>
<translation id="6630809736994426279">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan försöka installera skadliga program som stjäl eller raderar information (t.ex. foton, lösenord, meddelanden och kreditkortsuppgifter) på din Mac. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Föregående</translation>
<translation id="6710594484020273272">&lt;Ange sökterm&gt;</translation>
<translation id="6711464428925977395">Något är fel med proxyservern eller så är adressen felaktig.</translation>
-<translation id="6727102863431372879">Ange</translation>
<translation id="674375294223700098">Fel - okänt servercertifikat.</translation>
<translation id="6753269504797312559">Policyvärde</translation>
<translation id="6757797048963528358">Enheten gick i viloläge.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">Webbadress</translation>
<translation id="7419106976560586862">Profilsökväg</translation>
<translation id="7424977062513257142">På en inbäddad sida på den här webbplatsen står det:</translation>
+<translation id="7437289804838430631">Lägg till kontaktuppgifter</translation>
<translation id="7441627299479586546">Felaktigt policyämne</translation>
<translation id="7444046173054089907">Webbplatsen är blockerad</translation>
<translation id="7445762425076701745">Det går inte att fastställa identiteten hos servern som du är ansluten till. Servernamnet som du angav vid anslutningen är bara giltigt inom ditt nätverk och externa certifikatutfärdare kan inte fastställa dess ägarskap. Vissa certifikatutfärdare utfärdar certifikat oavsett namn och därför går det inte att säkerställa att du är ansluten till den avsedda webbplatsen och inte till en skadlig server.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Framåt</translation>
<translation id="7485870689360869515">Ingen data hittades.</translation>
<translation id="7508255263130623398">Enhets-id för returnerad princip är tomt eller matchar inte nuvarande enhets-id</translation>
+<translation id="7511955381719512146">Wi-Fi-nätverket du använder kanske kräver att du besöker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Ladda ned</translation>
<translation id="7518003948725431193">Det fanns ingen webbsida på webbadressen: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Din anslutning till webbplatsen är inte privat</translation>
-<translation id="7535087603100972091">Värde</translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542403920425041731">När du bekräftar delas kortuppgifterna med den här webbplatsen.</translation>
<translation id="7542995811387359312">Automatisk ifyllning av kreditkort har inaktiverats eftersom formulärets anslutning inte är säker.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha utfärdats utan behörighet. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="7568593326407688803">Den här sidan är på<ph name="ORIGINAL_LANGUAGE" />Vill du översätta den?</translation>
<translation id="7569952961197462199">Vill du ta bort kreditkortet från Chrome?</translation>
-<translation id="7569983096843329377">Svart</translation>
<translation id="7578104083680115302">Betala snabbt på webbplatser och i appar på olika enheter med kort som du har sparat hos Google.</translation>
<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Serverns certifikat strider mot namnrestriktionerna.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Angripare på den här webbplatsen kan försöka lura dig att installera program som skadar din webbupplevelse (till exempel genom att byta ut din startsida eller visa extra annonser på webbplatser som du besöker).</translation>
<translation id="7674629440242451245">Är du intresserad av häftiga nya funktioner i Chrome? Pröva vår utvecklarkanal på chrome.com/dev.</translation>
<translation id="7682287625158474539">Frakt</translation>
+<translation id="7699293099605015246">Inga artiklar är tillgängliga just nu</translation>
<translation id="7701040980221191251">Inget</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsätt till <ph name="SITE" /> (osäkert)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Certifikat</translation>
<translation id="7716147886133743102">Blockerades av administratören</translation>
<translation id="7716424297397655342">Det går inte att läsa in webbplatsen från cachelagringen</translation>
+<translation id="7723047071702270851">Redigera kortet</translation>
<translation id="774634243536837715">Farligt innehåll har blockerats.</translation>
<translation id="7752995774971033316">Hanteras inte</translation>
<translation id="7755287808199759310">En förälder kan ta bort blockeringen</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Lägg till adress</translation>
<translation id="777702478322588152">Prefektur</translation>
<translation id="7791543448312431591">Lägg till</translation>
+<translation id="7793553086574152071">Spara det här kortet i Google-kontot så går det snabbare att betala nästa gång.</translation>
<translation id="7793809570500803535">Webbsidan på <ph name="SITE" /> kan ligga nere för tillfället eller så kan den ha flyttats permanent till en ny webbadress.</translation>
<translation id="7800304661137206267">Anslutningen är krypterad med <ph name="CIPHER" />, med <ph name="MAC" /> för meddelandeautentisering och <ph name="KX" /> som mekanism för nyckelutbyte.</translation>
+<translation id="7802523362929240268">Legitim webbplats</translation>
<translation id="780301667611848630">Nej tack</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vill du ta bort formulärförslaget från Chrome?</translation>
<translation id="7815407501681723534">Hittade <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> för <ph name="SEARCH_STRING" /></translation>
+<translation id="782886543891417279">Wi-Fi-nätverket du använder (<ph name="WIFI_NAME" />) kanske kräver att du besöker dess inloggningssida.</translation>
<translation id="785549533363645510">Men du är inte osynlig. Inkognitoläget döljer inte webbhistoriken för din arbetsgivare, internetleverantören eller webbplatserna du besöker.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Betalkort och förbetalda kort får användas.</translation>
+<translation id="7878562273885520351">Lösenordet kan vara utsatt för risk</translation>
<translation id="7887683347370398519">Kontrollera CVC-koden och försök igen</translation>
<translation id="79338296614623784">Ange ett giltigt telefonnummer</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Servercertifikatet är inte giltigt ännu.</translation>
-<translation id="7942349550061667556">Röd</translation>
<translation id="7947285636476623132">Kontrollera utgångsår och försök igen</translation>
<translation id="7951415247503192394">(32 bitar)</translation>
<translation id="7956713633345437162">Bokmärken i mobilen</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Fråga (standard)</translation>
<translation id="8041089156583427627">Skicka feedback</translation>
<translation id="8041940743680923270">Använd global standardinställning (Fråga)</translation>
+<translation id="8057711352706143257"><ph name="SOFTWARE_NAME" /> har inte konfigurerats korrekt. Ofta hjälper det att avinstallera <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Det gick inte att visa artikeln.</translation>
<translation id="8091372947890762290">Aktiveringen väntar på servern</translation>
+<translation id="8094917007353911263">Nätverket du använder kanske kräver att du besöker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Betalningsmetod</translation>
<translation id="8118489163946903409">Betalningsmetod</translation>
+<translation id="8127301229239896662"><ph name="SOFTWARE_NAME" /> har inte installerats korrekt på datorn eller nätverket. Be IT-administratören om hjälp med problemet.</translation>
<translation id="8131740175452115882">Bekräfta</translation>
<translation id="8134994873729925007">Det gick inte att hitta <ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> till servern för <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Datorn gick i viloläge.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Kontakta din nätverksadministratör om du är osäker på vad det här innebär.</translation>
<translation id="8293206222192510085">Lägg till bokmärke</translation>
<translation id="8294431847097064396">Källa</translation>
+<translation id="8298115750975731693">Wi-Fi-nätverket du använder (<ph name="WIFI_NAME" />) kanske kräver att du besöker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Det gick inte att upprätta en privat anslutning till <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> eftersom datum och tid på enheten (<ph name="DATE_AND_TIME" />) inte stämmer. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Det gick inte att översätta på grund av ett nätverksfel.</translation>
<translation id="8332188693563227489">Åtkomst nekades till <ph name="HOST_NAME" />.</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Nyligen stängda</translation>
<translation id="8874824191258364635">Ange ett giltigt kortnummer</translation>
<translation id="8876793034577346603">Det gick inte att tolka nätverkskonfigurationen.</translation>
-<translation id="8889402386540077796">Nyans</translation>
<translation id="8891727572606052622">Ogiltigt proxyläge.</translation>
<translation id="889901481107108152">Experimentet finns tyvärr inte på din plattform.</translation>
<translation id="8903921497873541725">Zooma in</translation>
<translation id="8931333241327730545">Vill du spara det här kortet i ditt Google-konto?</translation>
<translation id="8932102934695377596">Klockan går efter</translation>
+<translation id="893332455753468063">Lägg till namn</translation>
<translation id="8938939909778640821">Godkända kreditkort och förbetalda kort</translation>
+<translation id="8957210676456822347">Auktorisering av infångstportal</translation>
<translation id="8971063699422889582">Servercertifikatet har gått ut.</translation>
-<translation id="8986494364107987395">Skicka användningsstatistik och kraschrapporter till Google automatiskt</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Webbplatsen som öppnas innehåller skadliga program</translation>
<translation id="8997023839087525404">Servern visade ett certifikat som inte lämnats ut via principen Certifikattransparens. Detta är ett krav för vissa certifikat för att säkerställa att de är pålitliga och skyddar mot hackare.</translation>
<translation id="9001074447101275817">Proxyservern <ph name="DOMAIN" /> kräver användarnamn och lösenord.</translation>
<translation id="9005998258318286617">Det gick inte att läsa in PDF-dokumentet.</translation>
+<translation id="9008201768610948239">Ignorera</translation>
<translation id="901974403500617787">Flaggor som gäller hela systemet kan endast ställas in av ägaren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Kortets faktureringsadress måste anges</translation>
<translation id="9020542370529661692">Den här sidan har översatts till <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Du försökte nå <ph name="DOMAIN" /> men servern angav ett ogiltigt certifikat.</translation>
<translation id="9050666287014529139">Lösenfras</translation>
<translation id="9065203028668620118">Redigera</translation>
-<translation id="9068849894565669697">Välj färg</translation>
<translation id="9069693763241529744">Blockerades av ett tillägg</translation>
<translation id="9076283476770535406">Den kan innehålla barnförbjudet innehåll</translation>
<translation id="9078964945751709336">Mer information krävs</translation>
+<translation id="9080712759204168376">Sammanfattning av beställningen</translation>
<translation id="9103872766612412690">På <ph name="SITE" /> används normalt kryptering (SSL) för att skydda din information. När Chromium försökte ansluta till <ph name="SITE" /> den här gången skickade webbplatsen tillbaka ovanliga och felaktiga uppgifter. Sådant kan hända när en angripare utger sig för att vara <ph name="SITE" /> eller när anslutningen har avbrutits av en Wi-Fi-inloggningsskärm. Din information är fortfarande säker eftersom Chromium avbröt anslutningen innan någon data utbyttes.</translation>
+<translation id="9106062320799175032">Lägg till faktureringsadress</translation>
+<translation id="910908805481542201">Hjälp mig att åtgärda detta</translation>
+<translation id="9128870381267983090">Anslut till ett nätverk</translation>
<translation id="9137013805542155359">Visa original</translation>
<translation id="9137248913990643158">Logga in på Chrome innan du använder den här appen.</translation>
<translation id="9148507642005240123">&amp;Ångra Redigera</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> använder ett protokoll som inte stöds.</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="9215416866750762878">Ett program förhindrar att Chrome ansluter till den här webbplatsen på ett säkert sätt</translation>
<translation id="9219103736887031265">Bilder</translation>
<translation id="933612690413056017">Det finns ingen internetanslutning</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Ingen}=1{1 objekt}other{# objekt}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="988159990683914416">Utvecklarversion</translation>
+<translation id="989988560359834682">Redigera adress</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401"><ph name="SOFTWARE_NAME" /> har inte installerats korrekt på datorn eller nätverket:
+ &lt;ul&gt;
+ &lt;li&gt;Testa att avinstallera eller inaktivera <ph name="SOFTWARE_NAME" />&lt;/li&gt;
+ &lt;li&gt;Testa att ansluta till ett annat nätverk&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index ca5e4ea1d97..6c572771927 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Alamisho za Eneokazi</translation>
<translation id="1074497978438210769">Si salama</translation>
<translation id="1080116354587839789">Fanya itoshe kwenye upana</translation>
+<translation id="1088860948719068836">Ongeza Jina kwenye Kadi</translation>
<translation id="1103523840287552314">Tafsiri <ph name="LANGUAGE" /> kila wakati</translation>
+<translation id="1103778128462718200">Onyesha manenosiri yote yaliyohifadhiwa...</translation>
<translation id="1107591249535594099">Ikiteuliwa, Chrome itahifadhi nakala ya kadi yako kwenye kifaa hiki kwa ajili ya kujaza fomu haraka.</translation>
<translation id="1111153019813902504">Alamisho za hivi majuzi</translation>
<translation id="1113869188872983271">Tendua kupanga upya</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (zimesawazishwa)</translation>
<translation id="1263231323834454256">Orodha ya kusoma</translation>
<translation id="1264126396475825575">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> (haijapakiwa au imepuuzwa)</translation>
+<translation id="1270502636509132238">Mbinu ya Kuchukua</translation>
<translation id="1281526147609854549">Imetolewa na <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Kamwe usitafsiri tovuti hii</translation>
<translation id="129553762522093515">Vilivyofungwa hivi karibuni</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Inasubiri muunganisho...</translation>
<translation id="153384715582417236">Hayo yanatosha kwa sasa</translation>
<translation id="1549470594296187301">Lazima JavaScript iwashwe ili utumie kipengele hiki.</translation>
-<translation id="1555130319947370107">Samawati</translation>
<translation id="1559528461873125649">Hakuna faili au saraka kama hiyo</translation>
<translation id="1583429793053364125">Hitilafu ilitokea wakati wa kuonyesha ukurasa huu wa wavuti.</translation>
<translation id="1592005682883173041">Ufikiaji wa Data Iliyo Katika Kifaa Chako</translation>
<translation id="1594030484168838125">Chagua</translation>
-<translation id="161042844686301425">Samawati-Kijani</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Je, unataka Chrome ihifadhi kadi hii?</translation>
<translation id="1639239467298939599">Inapakia</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Unahitaji ruhusa kutoka kwa <ph name="NAME" /> ili utembelee tovuti hii</translation>
<translation id="1721424275792716183">* Unahitaji kujaza sehemu hii</translation>
+<translation id="1727741090716970331">Ongeza Nambari Sahihi ya Kadi</translation>
<translation id="1728677426644403582">Unaangalia chanzo cha ukurasa wa wavuti</translation>
<translation id="173080396488393970">Aina hii ya kadi haitumiki</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Hitilafu ya namba tambulishi</translation>
<translation id="1974060860693918893">Mipangilio ya kina</translation>
<translation id="1978555033938440688">Toleo la Programu dhibiti</translation>
-<translation id="1995859865337580572">Tafadhali thibitisha CVC yako</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{na nyingine 1}other{na nyingine #}}</translation>
<translation id="2025186561304664664">Proksi imewekwa katika usanidi otomatiki.</translation>
<translation id="2030481566774242610">Je, ulimaanisha <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Tendua</translation>
<translation id="20817612488360358">Mipangilio ya mfumo ya proksi imewekwa ili kutumiwa lakini usanidi dhahiri wa proksi pia umebainishwa.</translation>
<translation id="2086652334978798447">Ili Google ikupendekezee maudhui yanayokufaa, ingia katika Chrome.</translation>
+<translation id="2091887806945687916">Sauti</translation>
<translation id="2094505752054353250">Kitolingana kwa kikoa</translation>
<translation id="2096368010154057602">Idara</translation>
<translation id="2108755909498034140">Zima na uwashe kompyuta yako</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Imepuuzwa kwa sababu ilifutwa na <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Inatafuta kurasa za Wavuti Kila Mahali zilizo karibu</translation>
<translation id="213826338245044447">Alamisho kwenye Simu</translation>
+<translation id="214556005048008348">Ghairi malipo</translation>
<translation id="2147827593068025794">Usawazishaji wa Chini Chini</translation>
+<translation id="2148613324460538318">Ongeza Kadi</translation>
<translation id="2154054054215849342">Huduma ya usawazishaji haipatikani kwa ajili ya kikoa chako</translation>
<translation id="2154484045852737596">Badilisha kadi</translation>
<translation id="2166049586286450108">Idhini Kamili ya Kufikia ya Msimamizi</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{Anwani 1}other{Anwani #}}</translation>
<translation id="2187317261103489799">Gundua (chaguo-msingi)</translation>
<translation id="2202020181578195191">Andika mwaka sahihi wa kuisha kwa muda wa matumizi</translation>
+<translation id="2209523182407020534">Programu zinazoweza kusababisha hitilafu hii ni pamoja na kinga virusi, kinga-mtandao, kichujio cha wavuti au programu ya seva mbadala.</translation>
<translation id="2212735316055980242">Sera haikupatikana</translation>
<translation id="2213606439339815911">Inachukua viingizo...</translation>
<translation id="2218879909401188352">Wavamizi walio kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hivi sasa, wanaweza kusakinisha programu hatari zinazoweza kukiharibu kifaa chako, kuongeza gharama fiche kwenye malipo yako ya simu, au kuiba maelezo yako ya binafsi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Rudi nyuma</translation>
<translation id="2503184589641749290">Kadi za malipo na za kulipia awali zinazokubaliwa</translation>
<translation id="2515629240566999685">Kuangalia uthabiti wa mawimbi katika eneo lako</translation>
+<translation id="2524461107774643265">Ongeza Maelezo Zaidi</translation>
+<translation id="2536110899380797252">Ongeza Anwani</translation>
<translation id="2539524384386349900">Gundua</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> imetuma jibu ambalo si sahihi.</translation>
<translation id="2556876185419854533">Tendua Kuhariri</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
<translation id="2705137772291741111">Nakala iliyohifadhiwa (iliyowekwa katika akiba) ya tovuti hii haikusomeka.</translation>
<translation id="2709516037105925701">Kujaza Kiotomatiki</translation>
+<translation id="2710942282213947212">Programu iliyo katika kompyuta yako inaizuia Chromium kuunganisha kwenye wavuti kwa njia salama</translation>
<translation id="2712173769900027643">Omba ruhusa</translation>
-<translation id="2713444072780614174">Nyeupe</translation>
<translation id="2720342946869265578">Uhamishaji wa Karibu</translation>
<translation id="2721148159707890343">Ombi limefanikiwa</translation>
<translation id="2728127805433021124">Cheti cha seva kimetiwa sahihi kwa kutumia algoriti dhaifu ya sahihi.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Mabadiliko ya mtandao yamegunduliwa.</translation>
<translation id="2916038427272391327">Funga programu nyingine</translation>
<translation id="2922350208395188000">Cheti cha seva hakiwezi kukaguliwa.</translation>
+<translation id="2925673989565098301">Njia ya Kusafirisha</translation>
<translation id="2928905813689894207">Anwani ya kutuma Bili</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kinatoka <ph name="DOMAIN2" />. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Aina mbaya ya sera</translation>
<translation id="3032412215588512954">Ungependa kupakia upya tovuti hii?</translation>
<translation id="3037605927509011580">Lo!</translation>
+<translation id="3039538478787849737">Ungependa kuhifadhi kadi hii kwenye Google?</translation>
<translation id="3041612393474885105">Maelezo ya Cheti</translation>
<translation id="3063697135517575841">Chrome haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
<translation id="3064966200440839136">Inaacha hali fiche ili kulipa kupitia programu ya nje. Je, ungependa kuendelea?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Hitilfau ya muda ya seva</translation>
<translation id="3154506275960390542">Ukurasa huu una fomu ambayo haiwezi kuwasilishwa kwa njia salama. Data unayotuma inaweza kusomwa na watu wengine inapotumwa au inaweza kurekebishwa na mvamizi ili kubadilisha data ambayo seva inapokea.</translation>
<translation id="3157931365184549694">Rejesha</translation>
+<translation id="3162559335345991374">Wi-Fi unayotumia inaweza kukuhitaji kutembelea ukurasa wake wa kuingia katika akaunti.</translation>
<translation id="3167968892399408617">Kurasa unazoziangalia katika vichupo fiche hazitaendelea kuwepo katika historia ya kivinjari, hifadhi ya vidakuzi, au historia yako ya utafutaji ukishafunga vichupo vyako vyote fiche. Faili zozote unazopakua au alamisho unazounda hazitafutwa.</translation>
<translation id="3169472444629675720">Gundua</translation>
<translation id="3174168572213147020">Kisiwa</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Ghairi Malipo</translation>
<translation id="3207960819495026254">Imealamishwa</translation>
+<translation id="3211223744486044430">Ili ulipe kwa haraka wakati ujao, hifadhi kadi hii kwenye Akaunti yako ya Google na kwenye kifaa hiki.</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>
<translation id="3226128629678568754">Bonyeza kitufe cha kupakia upya ili kuwasilisha upya data inayohitajika kupakia ukurasa.</translation>
<translation id="3227137524299004712">Maikrofoni</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Hakuna matokeo ya utafutaji yaliyopatikana</translation>
<translation id="3305707030755673451">Data yako ilisimbwa kwa njia fiche kwa kauli yako ya siri ya kusawazisha mnamo <ph name="TIME" />. Iweke ili uanze kusawazisha.</translation>
<translation id="3320021301628644560">Ongeza anwani ya kutuma bili</translation>
-<translation id="3329013043687509092">Kukolea</translation>
<translation id="333371639341676808">Zuia ukurasa huu usiulize maswali zaidi.</translation>
<translation id="3338095232262050444">Salama</translation>
<translation id="3340978935015468852">mipangilio</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Kitambulisho cha Mteja:</translation>
<translation id="3391030046425686457">Mahali pa kupeleka</translation>
<translation id="3395827396354264108">Mbinu ya kuchukua</translation>
+<translation id="3399952811970034796">Mahali Bidhaa Itapelekwa</translation>
<translation id="3422248202833853650">Jaribu kuondoka kwenye programu nyingine ili upate nafasi zaidi.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> haiwezi kufikiwa kwa sasa.</translation>
<translation id="3427092606871434483">Ruhusu (chaguo-msingi)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Ripoti ya kuacha kufanya kazi ilitolewa <ph name="CRASH_TIME" /> na kupakiwa <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Maelezo ya cheti</translation>
<translation id="3690164694835360974">Kuingia katika akaunti si salama</translation>
+<translation id="3704162925118123524">Mtandao unaotumia unaweza kukuhitaji kuutembelea ukurasa wake wa kuingia katika akaunti.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Inapakia...</translation>
<translation id="3712624925041724820">Leseni zimekwisha</translation>
<translation id="3714780639079136834">Kuwasha data ya simu au Wi-Fi</translation>
+<translation id="3715597595485130451">Unganisha kwenye Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kuangalia seva mbadala, kinga-mtandao na mipangilio ya DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Ikiwa unaelewa kiwango cha hatari kinachoweza kutokea, unaweza <ph name="BEGIN_LINK" />kutembelea tovuti hii isiyo salama<ph name="END_LINK" /> kabla programu hatari hazijaondolewa.</translation>
<translation id="3739623965217189342">Kiungo ulichonakili</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">Tendua kuongeza</translation>
<translation id="404928562651467259">ONYO</translation>
<translation id="4058922952496707368">Kitufe "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Usanidi wa proksi umewekwa kutumia URL hati ya .pac, siyo seva proksi za kudumu.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Namabari tambulishi ya kifaa ni batili</translation>
<translation id="410351446219883937">Kucheza kiotomatiki</translation>
<translation id="4103763322291513355">Tembelea &lt;strong&gt;chrome://policy&lt;/strong&gt; ili kuona orodha ya URL zilizoondolewa idhini na sera zingine zinazosimamiwa na msimamizi wako wa mfumo.</translation>
-<translation id="4115378294792113321">Rangi ya damu ya mzee</translation>
<translation id="4116663294526079822">Ruhusu mara kwa mara kwenye tovuti hii</translation>
<translation id="4117700440116928470">Upeo wa sera hauwezi kutumika.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{Nyingine 1 }other{Nyingine #}}</translation>
@@ -431,7 +444,7 @@
<translation id="4235360514405112390">Halali</translation>
<translation id="4250431568374086873">Muunganisho wako kwenye tovuti hii si salama kabisa</translation>
<translation id="4250680216510889253">La</translation>
-<translation id="425582637250725228">Huenda mabadiliko uliyofanya yasihifadhiwe.</translation>
+<translation id="425582637250725228">Huenda mabadiliko uliyofanya hayatahifadhiwa.</translation>
<translation id="4258748452823770588">Sahihi mbaya</translation>
<translation id="4265872034478892965">Imeruhusiwa na msimamizi wako</translation>
<translation id="4269787794583293679">(Hakuna jina la mtumiaji)</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Ulijaribu kufikia <ph name="DOMAIN" />, lakini cheti kilichowasilishwa na seva kimebatilishwa na mtoaji wacho. Huku ni kumaanisha kuwa stakabadhi za usalama zilizowasilishwa na seva hii hazifai kuaminiwa kabisa. Huenda ukawa unawasiliana na mshabulizi.</translation>
<translation id="4394049700291259645">Zima</translation>
<translation id="4406896451731180161">matokeo ya utafutaji</translation>
+<translation id="4415426530740016218">Anwani ya Mahali pa Kuchukulia Bidhaa</translation>
<translation id="4424024547088906515">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chrome. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> haikukubali cheti chako cha kuingia katika akaunti, au huenda hukutoa cheti.</translation>
<translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Mmweko</translation>
<translation id="4558551763791394412">Jaribu kuzima viendelezi vyako.</translation>
<translation id="457875822857220463">Usafirishaji</translation>
+<translation id="4582800630050655161">Unaweza kupoteza uwezo wa kufikia Akaunti yako ya Google au kuibiwa utambulisho. Chromium inapendekeza ubadilishe nenosiri lako la sasa.</translation>
<translation id="4587425331216688090">Ungependa kuondoa anwani kutoka kwenye Chrome?</translation>
<translation id="4592951414987517459">Muunganisho wako kwenye <ph name="DOMAIN" /> umesimbwa kwa njia fiche kwa kutumia mipangilio ya kriptografia ya kisasa.</translation>
<translation id="4594403342090139922">Tendua Kufuta</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Acha kutumia cheti kisicho sahihi</translation>
+<translation id="4690954380545377795">Unaweza kupoteza uwezo wa kufikia Akaunti yako ya Google au kuibiwa utambulisho. Chrome inapendekeza ubadilishe nenosiri lako sasa.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Muunganisho wako umekatizwa</translation>
<translation id="471880041731876836">Huna ruhusa ya kutembelea tovuti hii</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kuendesha Zana ya Windows ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Malipo yako</translation>
<translation id="4726672564094551039">Pakia sera upya</translation>
<translation id="4728558894243024398">Mfumo wa uendeshaji</translation>
<translation id="4736825316280949806">Zima na uwashe Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Hifadhi la kucheleza liko katika hali mbaya</translation>
<translation id="5023310440958281426">Angalia sera za msimamizi wako</translation>
<translation id="5029568752722684782">Futa nakala</translation>
+<translation id="503069730517007720">Cheti cha msingi cha "<ph name="SOFTWARE_NAME" />" kinahitajika lakini hakijasakinishwa. Ni lazima msimamizi wako wa TEHAMA asome mipangilio ya "<ph name="SOFTWARE_NAME" />" ili atatue tatizo hili. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Kuhusu Google Tafsiri</translation>
<translation id="5039804452771397117">Ruhusu</translation>
<translation id="5040262127954254034">Faragha</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Majaribio</translation>
<translation id="5205222826937269299">Jina linahitajika</translation>
<translation id="5222812217790122047">Anwani ya barua pepe inahitajika</translation>
+<translation id="522700295135997067">Huenda tovuti hii imeiba nenosiri lako</translation>
+<translation id="5230733896359313003">Anwani ya Mahali Bidhaa Zitakapopelekwa</translation>
<translation id="5251803541071282808">Wingu</translation>
<translation id="5277279256032773186">Je, unatumia Chrome kazini? Kampuni zinaweza kudhibiti mipangilio ya Chrome ya wafanyikazi wao. Pata maelezo zaidi</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Zifuate hatua hizi za kuisitisha programu kwa muda ili ufike kwenye wavuti. Utahitaji mamlaka ya msimamizi.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Muunganisho wako kwenye tovuti hii si wa faragha. Ili uondoke kwenye hali ya VR wakati wowote, ondoa vifaa vya kutazama uhalisia pepe na ubonyeze tena.</translation>
<translation id="5299298092464848405">Hitilafu wakati wa kuchanganua sera</translation>
+<translation id="5308380583665731573">Unganisha</translation>
<translation id="5308689395849655368">Kuripoti uharibifu kumelemazwa.</translation>
<translation id="5317780077021120954">Hifadhi</translation>
<translation id="5327248766486351172">Jina</translation>
+<translation id="5332219387342487447">Mbinu ya Usafirishaji</translation>
<translation id="5355557959165512791">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu cheti chake kimebatilishwa. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo huenda ukurasa huu utafanya kazi baadaye.</translation>
<translation id="536296301121032821">Imeshindwa kuhifadhi mipangilio ya sera</translation>
<translation id="5386426401304769735">Msururu wa cheti wa tovuti hii una cheti kilichotiwa sahihi kwa kutumia SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Tovuti hii kwenye intraneti ya kampuni, shirika au shule ina URL sawa na tovuti ya nje.
<ph name="LINE_BREAK" />
Jaribu kuwasiliana na msimamizi wa mfumo wako.</translation>
+<translation id="5499929369096410817">Weka msimbo wa usalama wa <ph name="CREDIT_CARD" />. Msimbo huu hautahifadhiwa.</translation>
<translation id="5509780412636533143">Alamisho zinazosimamiwa</translation>
<translation id="5510766032865166053">Huenda imehamishwa au imefutwa.</translation>
<translation id="5523118979700054094">Jina la sera</translation>
<translation id="552553974213252141">Je, maandishi yalitolewa kwa njia sahihi?</translation>
<translation id="5540224163453853">Haikuweza kupata makala yaliyoitishwa.</translation>
+<translation id="5541546772353173584">Ongeza Anwani ya Barua Pepe</translation>
<translation id="5544037170328430102">Ukurasa uliopachikwa kwenye <ph name="SITE" /> unasema:</translation>
+<translation id="5545756402275714221">Makala Tunayokupendekezea</translation>
<translation id="5556459405103347317">Pakia upya</translation>
<translation id="5560088892362098740">Tarehe ya Mwisho wa Matumizi</translation>
<translation id="5565735124758917034">Inatumika</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Barua pepe</translation>
<translation id="5669703222995421982">Pata maudhui yanayokufaa</translation>
<translation id="5675650730144413517">Ukurasa huu haufanyi kazi</translation>
+<translation id="5689199277474810259">Tuma katika mfumo wa JSON</translation>
<translation id="5710435578057952990">Utambulisho wa tovuti hii haujathibitishwa.</translation>
<translation id="5719499550583120431">Kadi za kulipia awali zinakubaliwa.</translation>
<translation id="5720705177508910913">Mtumiaji wa sasa</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Muunganisho wako kwenye <ph name="DOMAIN" /> umesimbwa kwa njia fiche kwa kutumia mipangilio ya kriptografia ya zamani.</translation>
<translation id="5813119285467412249">Rudia Kuongeza</translation>
<translation id="5838278095973806738">Hupaswi kuweka maelezo nyeti kwenye tovuti hii (kwa mfano, manenosiri au kadi za mikopo), kwa sababu wavamizi wanaweza kuyaiba.</translation>
+<translation id="5866257070973731571">Ongeza Nambari ya Simu</translation>
<translation id="5869405914158311789">Tovuti hii haiwezi kufikiwa</translation>
<translation id="5869522115854928033">Manenosiri yaliyohifadhiwa</translation>
<translation id="5872918882028971132">Mapendekezo ya Wazazi</translation>
<translation id="5893752035575986141">Kadi za mikopo zinakubaliwa.</translation>
-<translation id="5901630391730855834">Manjano</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (imesawazishwa)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 kinatumika}other{ # vinatumika}}</translation>
<translation id="5959728338436674663">Tuma kiotomatiki <ph name="BEGIN_WHITEPAPER_LINK" />maelezo ya mfumo na maudhui kadha ya ukurasa<ph name="END_WHITEPAPER_LINK" /> kwa Google ili kusaidia kugundua programu na tovuti hatari. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">Badilisha Maelezo ya Mawasiliano</translation>
<translation id="5967867314010545767">Ondoa kwenye historia</translation>
<translation id="5975083100439434680">Fifiza</translation>
+<translation id="597552863672748783">Thibitisha nambari ya usalama</translation>
<translation id="598637245381783098">Imeshindwa kufungua programu ya kulipa</translation>
<translation id="5989320800837274978">Siyo seva proksi za kudumu wala URL ya hati ya .pac zimebainishwa.</translation>
<translation id="5990559369517809815">Maombi katika seva yamezuiwa kwa kiendelezi.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Ukurasa wa 1}other{Ukurasa wa #}}</translation>
-<translation id="6017514345406065928">Kijani</translation>
<translation id="6017850046339264347">Wavamizi walio kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> wanaweza kusakinisha programu za udanganyifu zinazojifanya kuwa kitu kingine au kukusanya data inayoweza kutumika kukufuatilia. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (imesawazishwa)</translation>
<translation id="6027201098523975773">Andika jina</translation>
<translation id="6040143037577758943">Funga</translation>
-<translation id="6042308850641462728">Zaidi</translation>
<translation id="6047233362582046994">Ikiwa unaelewa hatari kwa usalama wako, unaweza <ph name="BEGIN_LINK" />kuitembelea tovuti hii<ph name="END_LINK" /> kabla programu hasidi hazijaondolewa.</translation>
<translation id="6047927260846328439">Maudhui haya yanaweza kukuhadaa kusakinisha programu au kuonyesha maelezo yako ya binafsi. <ph name="BEGIN_LINK" />Onyesha tu<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hii inatumia ubandikaji cheti. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Unaangalia ukurasa wa kiendelezi</translation>
<translation id="6596325263575161958">Chaguo za usimbaji fiche</translation>
<translation id="662080504995468778">Usiondoke</translation>
+<translation id="6624427990725312378">Maelezo ya Mawasiliano</translation>
<translation id="6626291197371920147">Ongeza nambari sahihi ya kadi</translation>
<translation id="6628463337424475685">Utafutaji wa <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Wavamizi ambao sasa wako kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> huenda wakajaribu kusakinisha programu hatari kwenye Mac yako ambazo zinaiba au kufuta maelezo yako (kwa mfano, picha, manenosiri, ujumbe na kadi za mikopo). <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Iliyotangulia</translation>
<translation id="6710594484020273272">&lt;Andika neno unalotaka kutafuta&gt;</translation>
<translation id="6711464428925977395">Kuna hitilafu katika seva mbadala, au anwani siyo sahihi.</translation>
-<translation id="6727102863431372879">Weka</translation>
<translation id="674375294223700098">Hitilafu isiyojulikana ya cheti cha seva.</translation>
<translation id="6753269504797312559">Thamani ya sera</translation>
<translation id="6757797048963528358">Kifaa chako kiko katika hali tuli.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Kijia cha Maelezo mafupi</translation>
<translation id="7424977062513257142">Ukurasa uliopachikwa kwenye ukurasa huu wa wavuti unasema:</translation>
+<translation id="7437289804838430631">Ongeza Maelezo ya Mawasiliano</translation>
<translation id="7441627299479586546">Kichwa cha sera kisichofaa</translation>
<translation id="7444046173054089907">Tovuti hii imezuiwa</translation>
<translation id="7445762425076701745">Utambulisho wa seva ambayo umejiunga kwayo hauwezi kuhalalishwa kikamilifu. Umeunganishwa kwenye seva kwa kutumia jina ambalo ni halali tu katika mtandao wako, ambalo mamlaka ya cheti cha nje hayana njia ya kuhalalisha umiliki wake. Kama baadhi ya mamlaka ya cheti yatatoa vyeti vya majina haya bila kujali, hakuna njia ya kuhakikisha umeunganishwa kwenye tovuti inayohitajika na sio mshambulizi.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Mbele</translation>
<translation id="7485870689360869515">Hakuna data iliyopatikana.</translation>
<translation id="7508255263130623398">Kitambulisho cha sera ya kifaa kilichorejeshwa hakina kitu au hakilingani na kitambulisho cha kifaa kilichopo</translation>
+<translation id="7511955381719512146">Wi-Fi unayotumia inaweza kukuhitaji kutembelea <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Pakua</translation>
<translation id="7518003948725431193">Hakuna ukurasa wa wavuti uliopatikana kwa anwani hii ya wavuti: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Muunganisho wako kwenye tovuti hii si wa faragha</translation>
-<translation id="7535087603100972091">Thamani</translation>
<translation id="7537536606612762813">Lazima</translation>
<translation id="7542403920425041731">Baada ya kuthibitisha, maelezo ya kadi yako yatashirikiwa na tovuti hii.</translation>
<translation id="7542995811387359312">Mjazo otomatiki wa kadi ya mkopo umelemazwa kwa sababu fomu hii haitumii muunganisho salama.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kimetolewa kwa njia ya ulaghai. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="7568593326407688803">Ukurasa huu umeandikwa kwa<ph name="ORIGINAL_LANGUAGE" />Je, ungependa kuutafsiri?</translation>
<translation id="7569952961197462199">Ungependa kuondoa kadi ya malipo kutoka kwenye Chrome?</translation>
-<translation id="7569983096843329377">Nyeusi</translation>
<translation id="7578104083680115302">Lipa haraka kwenye tovuti na programu katika vifaa vyote ukitumia kadi ulizohifadhi kwenye Google.</translation>
<translation id="7588950540487816470">Wavuti Kila Mahali</translation>
<translation id="7592362899630581445">Cheti cha seva kinakiuka vikwazo vya jina.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Wavamizi kwenye tovuti hii wanaweza kujaribu kukulaghai kusakinisha programu zinazoathiri hali yako ya kuvinjari (kwa mfano, kwa kubadilisha ukurasa wako wa kwanza au kwa kuonyesha matangazo ya ziada kwenye tovuti unazotembelea).</translation>
<translation id="7674629440242451245">Unavutiwa na vipengee vipya vizuri vya Chrome? Jaribu kituo chetu cha dev katika chrome.com/dev.</translation>
<translation id="7682287625158474539">Anwani ya Kufikishia</translation>
+<translation id="7699293099605015246">Makala hayapatikani kwa sasa</translation>
<translation id="7701040980221191251">Hamna</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Nenda kwenye <ph name="SITE" /> (isiyo salama)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Cheti</translation>
<translation id="7716147886133743102">Imezuiwa na msimamizi</translation>
<translation id="7716424297397655342">Faili hii haiwezi kupakiwa kutoka akiba</translation>
+<translation id="7723047071702270851">Badilisha Kadi</translation>
<translation id="774634243536837715">Maudhui hatari yamezuiwa.</translation>
<translation id="7752995774971033316">Haidhibitiwi</translation>
<translation id="7755287808199759310">Mzazi wako anaweza kukuondolea kizuizi</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Ongeza anwani</translation>
<translation id="777702478322588152">Wilaya</translation>
<translation id="7791543448312431591">Ongeza</translation>
+<translation id="7793553086574152071">Ili ulipe kwa haraka wakati ujao, hifadhi kadi hii kwenye Akaunti yako ya Google.</translation>
<translation id="7793809570500803535">Ukurasa wa wavuti ulio kwenye <ph name="SITE" /> unaweza kuwa haupatikani kwa muda au huenda umehamishwa kabisa hadi kwenye anwani mpya ya wavuti.</translation>
<translation id="7800304661137206267">Muunganisho umesimbwa fiche kwa kutumia <ph name="CIPHER" />, kwa <ph name="MAC" /> ya uthibitishaji wa ujumbe na <ph name="KX" /> kama utaratibu muhimu wa ubadilishanaji.</translation>
+<translation id="7802523362929240268">Tovuti hii ni sahihi</translation>
<translation id="780301667611848630">La, asante</translation>
<translation id="7805768142964895445">Hali</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Ungependa kuondoa pendekezo la fomu kutoka kwenye Chrome?</translation>
<translation id="7815407501681723534">Imepata matokeo <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ya '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Wi-Fi unayotumia (<ph name="WIFI_NAME" />) inaweza kukuhitaji kutembelea ukurasa wake wa kuingia katika akaunti.</translation>
<translation id="785549533363645510">Hata hivyo, huonekani. Kuvinjari katika hali fiche hakufichi kuvinjari kwako kusionekane na mwajiri, mtoaji huduma wako wa intaneti, au tovuti unazotembelea.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Kadi za malipo na za kulipia awali zinakubaliwa.</translation>
+<translation id="7878562273885520351">Huenda nenosiri lako limetambulika</translation>
<translation id="7887683347370398519">Angalia CVC yako na ujaribu tena</translation>
<translation id="79338296614623784">Andika nambari sahihi ya simu</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Cheti cha seva bado sio halali.</translation>
-<translation id="7942349550061667556">Nyekundu</translation>
<translation id="7947285636476623132">Angalia mwaka kuisha kwa muda wa matumizi halafu ujajibu tena</translation>
<translation id="7951415247503192394">(biti 32)</translation>
<translation id="7956713633345437162">Alamisho kwenye simu</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Uliza (chaguo-msingi)</translation>
<translation id="8041089156583427627">Tuma Maoni</translation>
<translation id="8041940743680923270">Tumia chaguo-msingi la duniani (Uliza)</translation>
+<translation id="8057711352706143257">Haikuweka mipangilio ya "<ph name="SOFTWARE_NAME" />" kwa njia sahihi. Kwa kawaida, kuondoa "<ph name="SOFTWARE_NAME" />" hurekebisha tatizo hili. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Haikufaulu kuangalia makala.</translation>
<translation id="8091372947890762290">Uwashaji unasubiri kwenye seva</translation>
+<translation id="8094917007353911263">Mtandao unaotumia unaweza kukuhitaji kutembelea <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Njia ya Kulipa</translation>
<translation id="8118489163946903409">Njia ya kulipa</translation>
+<translation id="8127301229239896662">Haikusakinisha "<ph name="SOFTWARE_NAME" />" kwa njia sahihi kwenye mtandao au kompyuta yako. Mweleze msimamizi wako wa TEHAMA asuluhishe tatizo hili.</translation>
<translation id="8131740175452115882">Thibitisha</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Anwani ya DNS <ph name="END_ABBR" /> ya seva ya <ph name="HOST_NAME" /> haikupatikana.</translation>
<translation id="8149426793427495338">Kompyuta yako iko katika hali tuli.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Wasiliana na msimamizi wako wa mtandao iwapo huna uhakika kile ambacho hiki kinamaanisha.</translation>
<translation id="8293206222192510085">Ongeza Alamisho</translation>
<translation id="8294431847097064396">Chanzo</translation>
+<translation id="8298115750975731693">Wi-Fi unayotumia (<ph name="WIFI_NAME" />) inaweza kukuhitaji kutembelea <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> haujatambuliwa kwa sababu tarehe na saa za kifaa chako (<ph name="DATE_AND_TIME" />) si sahihi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Utafsiri haukufanikiwa kwa sababu ya hitilafu ya seva.</translation>
<translation id="8332188693563227489">Ufikiaji wa <ph name="HOST_NAME" /> umekataliwa</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Zilizofungwa Hivi Karibuni</translation>
<translation id="8874824191258364635">Andika nambari sahihi ya kadi</translation>
<translation id="8876793034577346603">Usanidi wa mtandao umekosa kuchanganuliwa.</translation>
-<translation id="8889402386540077796">Rangi</translation>
<translation id="8891727572606052622">Modi batili ya proksi.</translation>
<translation id="889901481107108152">Samahani, jaribio hili halipatikani kwenye mfumo wako wa uendeshaji.</translation>
<translation id="8903921497873541725">Kuza karibu</translation>
<translation id="8931333241327730545">Je, ungependa kuhifadhi kadi hii katika Akaunti yako ya Google?</translation>
<translation id="8932102934695377596">Saa yako iko nyuma</translation>
+<translation id="893332455753468063">Ongeza Jina</translation>
<translation id="8938939909778640821">Kadi za mikopo na za kulipia awali zinazokubaliwa</translation>
+<translation id="8957210676456822347">Uidhinishaji wa Ukurasa wa Wavuti</translation>
<translation id="8971063699422889582">Cheti cha seva kimechina.</translation>
-<translation id="8986494364107987395">Tumia Google takwimu za matumizi na ripoti za mara ambazo kivinjari kinaacha kufanya kazi, moja kwa moja</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Tovuti unayoelekea kufungua ina programu zinazodhuru</translation>
<translation id="8997023839087525404">Seva imewasilisha cheti ambacho hakikufichuliwa hadharani kwa kutumia sera ya Uwazi wa Cheti. Hili ni hitaji kwa baadhi ya vyeti, ili kuhakikisha kwamba ni cha kuaminika na kulinda dhidi ya wavamizi.</translation>
<translation id="9001074447101275817">Seva mbadala ya <ph name="DOMAIN" /> inahitaji jina la mtumiaji na nenosiri.</translation>
<translation id="9005998258318286617">Imeshindwa kupakia hati ya PDF.</translation>
+<translation id="9008201768610948239">Puuza</translation>
<translation id="901974403500617787">Alama zinazotumika katika mfumo mzima zinaweza kuwekwa na mmiliki pekee: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Anwani ya kutuma bili ya kadi sharti iandikwe</translation>
<translation id="9020542370529661692">Ukurasa huu umetafsiriwa kwenda <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Ulijaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti batili.</translation>
<translation id="9050666287014529139">Kaulisiri</translation>
<translation id="9065203028668620118">Badilisha</translation>
-<translation id="9068849894565669697">Chagua rangi</translation>
<translation id="9069693763241529744">Imezuiwa na kiendelezi</translation>
<translation id="9076283476770535406">Huenda ina maudhui ya ngono</translation>
<translation id="9078964945751709336">Maelezo zaidi yanahitajika</translation>
+<translation id="9080712759204168376">Muhtasari wa Agizo</translation>
<translation id="9103872766612412690">Kwa kawaida <ph name="SITE" /> hutumia usimbaji fiche ili kulinda maelezo yako. Chromium ilipojaribu kuunganisha kwenye <ph name="SITE" /> wakati huu, tovuti ilituma kitambulisho kisicho cha kawaida na kisicho sahihi. Hili linaweza kutokea mvamizi anapojaribu kujifanya kuwa <ph name="SITE" />, au uchanganuzi wa kuingia katika Wi-Fi umeingilia muunganisho. Maelezo yako yangali salama kwa sababu Chromium ilisimamisha muunganisho kabla data yoyote itumwe.</translation>
+<translation id="9106062320799175032">Ongeza Anwani ya Kutuma Bili</translation>
+<translation id="910908805481542201">Nisaidie kutatua tatizo hili</translation>
+<translation id="9128870381267983090">Unganisha kwenye mtandao</translation>
<translation id="9137013805542155359">Onyesha asili</translation>
<translation id="9137248913990643158">Tafadhali anza na uingie katika Chrome kabla ya kutumia programu hii.</translation>
<translation id="9148507642005240123">Tendua kuhariri</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> hutumia itifaki isiyokubalika.</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="9215416866750762878">Programu kwenye kompyuta yako inazuia Chrome kuunganisha salama kwenye tovuti hii</translation>
<translation id="9219103736887031265">Picha</translation>
<translation id="933612690413056017">Hakuna muunganisho wa Intaneti</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Hamna}=1{Kipengee 1}other{Vipengee #}}</translation>
<translation id="981121421437150478">Nje ya mtandao</translation>
<translation id="988159990683914416">Muundo wa Wasanidi Programu</translation>
+<translation id="989988560359834682">Badilisha Anwani</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" haikusakinishwa kwa njia sahihi kwenye mtandao au kompyuta yako:
+ &lt;ul&gt;
+ &lt;li&gt;Jaribu kuondoa au kuzima "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Jaribu kuunganisha kwenye mtandao mwingine&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index ccd378e24ba..f63b5428557 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">டெஸ்க்டாப் புக்மார்க்குகள்</translation>
<translation id="1074497978438210769">பாதுகாப்பற்றது</translation>
<translation id="1080116354587839789">அகலத்திற்குப் பொருத்து</translation>
+<translation id="1088860948719068836">கார்டிலுள்ள பெயரைச் சேர்க்கவும்</translation>
<translation id="1103523840287552314">எப்போதும் இந்த மொழியை மொழிபெயர் <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">சேமித்த எல்லாக் கடவுச்சொற்களையும் காட்டு...</translation>
<translation id="1107591249535594099">இது தேர்ந்தெடுக்கப்பட்டால், விரைவாக படிவங்களை நிரப்புவதற்காக, Chrome இந்த கார்டின் பிரதியை சாதனத்தில் சேமிக்கும்.</translation>
<translation id="1111153019813902504">சமீபத்திய புத்தகக்குறிகள்</translation>
<translation id="1113869188872983271">&amp;மறுவரிசைப்படுத்தலைச் செயல்தவிர்</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (ஒத்திசைக்கப்பட்டன)</translation>
<translation id="1263231323834454256">வாசிப்புப் பட்டியல்</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> அன்று சிதைவு அறிக்கை பெறப்பட்டது (இன்னும் பதிவேற்றப்படவில்லை அல்லது புறக்கணிக்கப்படவில்லை)</translation>
+<translation id="1270502636509132238">பிக்அப் முறை</translation>
<translation id="1281526147609854549">வழங்கியது: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">இந்த தளத்தை எப்போதும் மொழிபெயர்க்க வேண்டாம்</translation>
<translation id="129553762522093515">சமீபத்தில் மூடியவை</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">இணைப்பிற்காகக் காத்திருக்கிறது…</translation>
<translation id="153384715582417236">அவ்வளவு தான்!</translation>
<translation id="1549470594296187301">இந்த அம்சத்தைப் பயன்படுத்த JavaScript இயக்கப்பட வேண்டும்.</translation>
-<translation id="1555130319947370107">நீலம்</translation>
<translation id="1559528461873125649">இதுபோன்ற கோப்பு அல்லது கோப்பகம் எதுவுமில்லை</translation>
<translation id="1583429793053364125">இந்த இணையப்பக்கத்தைக் காட்டும்போது ஏதோ தவறு ஏற்பட்டது.</translation>
<translation id="1592005682883173041">அகத் தரவு அணுகல்</translation>
<translation id="1594030484168838125">தேர்வுசெய்</translation>
-<translation id="161042844686301425">சியான்</translation>
<translation id="1620510694547887537">கேமரா</translation>
<translation id="1629803312968146339">இந்தக் கார்டை Chrome சேமிக்க வேண்டுமா?</translation>
<translation id="1639239467298939599">ஏற்றுகிறது</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">இந்தத் தளத்திற்குச் செல்ல, <ph name="NAME" /> இன் அனுமதி வேண்டும்</translation>
<translation id="1721424275792716183">* அவசியமான புலம்</translation>
+<translation id="1727741090716970331">சரியான கார்டு எண்ணைச் சேர்க்கவும்</translation>
<translation id="1728677426644403582">இணையப் பக்கத்தின் மூலத்தைப் பார்க்கிறீர்கள்</translation>
<translation id="173080396488393970">இந்தக் கார்டு வகை ஆதரிக்கப்படவில்லை</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">தொடராக்க பிழை</translation>
<translation id="1974060860693918893">மேம்பட்டவை</translation>
<translation id="1978555033938440688">நிலைப்பொருளின் பதிப்பு</translation>
-<translation id="1995859865337580572">CVC எண்ணைச் சரிபார்க்கவும்</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{மேலும் 1}other{மேலும் #}}</translation>
<translation id="2025186561304664664">ப்ராக்ஸி, தானியங்கி உள்ளமைவுக்கு அமைக்கப்பட்டுள்ளது</translation>
<translation id="2030481566774242610"><ph name="LINK" /> ஐக் குறிப்பிடுகிறீர்களா?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">செயல்தவிர்</translation>
<translation id="20817612488360358">கணினி ப்ராக்ஸி அமைப்புகள் பயன்படுத்த அமைக்கப்பட்டுள்ளது. வெளிப்படையான ப்ராக்ஸி உள்ளமைவும் குறிப்பிடப்பட்டுள்ளது.</translation>
<translation id="2086652334978798447">Google பரிந்துரைக்கும் தனிப்பயனாக்கிய உள்ளடக்கத்தைப் பெற, Chrome இல் உள்நுழையவும்.</translation>
+<translation id="2091887806945687916">ஒலி</translation>
<translation id="2094505752054353250">டொமைன் பொருந்தவில்லை</translation>
<translation id="2096368010154057602">துறை</translation>
<translation id="2108755909498034140">கணினியை மீண்டும் தொடங்கவும்</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ஆல் கொள்கை மேலெழுதப்பட்டுள்ளதால் புறக்கணிக்கப்பட்டது.</translation>
<translation id="2138201775715568214">அருகிலுள்ள இயல்நிலை இணையப் பக்கங்களைத் தேடுகிறது</translation>
<translation id="213826338245044447">மொபைல் புக்மார்க்குகள்</translation>
+<translation id="214556005048008348">பேமண்ட்டை ரத்துசெய்</translation>
<translation id="2147827593068025794">பின்புல ஒத்திசைவு</translation>
+<translation id="2148613324460538318">கார்டைச் சேர்</translation>
<translation id="2154054054215849342">உங்கள் டொமைனுக்கு ஒத்திசைத்தல் சேவை முடக்கப்பட்டுள்ளது</translation>
<translation id="2154484045852737596">கார்டைத் திருத்தவும்</translation>
<translation id="2166049586286450108">முழு நிர்வாகி அணுகல்</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 முகவரி}other{# முகவரிகள்}}</translation>
<translation id="2187317261103489799">கண்டறி (இயல்பு)</translation>
<translation id="2202020181578195191">சரியான காலாவதி ஆண்டை உள்ளிடவும்</translation>
+<translation id="2209523182407020534">வைரஸ்தடுப்பு, ஃபயர்வால், இணைய வடிப்பான் அல்லது ப்ராக்ஸி மென்பொருள் உள்ளிட்ட பயன்பாடுகள் இந்தப் பிழையை ஏற்படுத்தக்கூடும்.</translation>
<translation id="2212735316055980242">கொள்கை காணப்படவில்லை</translation>
<translation id="2213606439339815911">உள்ளீடுகளைப் பெறுகிறது...</translation>
<translation id="2218879909401188352">தற்போது <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> எனும் தளத்தில் உள்ள தீங்கிழைப்பவர்கள் உங்கள் சாதனத்தைச் சேதப்படுத்தும் ஆபத்தான பயன்பாடுகளை நிறுவலாம், மொபைல் கட்டணத்தில் மறைமுகக் கட்டணங்களைச் சேர்க்கலாம் அல்லது உங்கள் தனிப்பட்ட தகவலைத் திருடலாம். <ph name="BEGIN_LEARN_MORE_LINK" />மேலும் அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">திரும்பிச் செல்</translation>
<translation id="2503184589641749290">ஏற்கப்படும் டெபிட் மற்றும் ப்ரீபெய்டு கார்டுகள்</translation>
<translation id="2515629240566999685">உங்கள் பகுதியில் உள்ள சிக்னலைச் சரிபார்த்தல்</translation>
+<translation id="2524461107774643265">மேலும் தகவலைச் சேர்க்கவும்</translation>
+<translation id="2536110899380797252">முகவரியைச் சேர்</translation>
<translation id="2539524384386349900">கண்டறி</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> தவறான பதிலை அனுப்பியது.</translation>
<translation id="2556876185419854533">&amp;திருத்தலைச் செயல்தவிர்</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">இப்போது உங்கள் கார்டை உறுதிசெய்ய முடியவில்லை. பிறகு முயலவும்.</translation>
<translation id="2705137772291741111">இந்தத் தளத்தின் சேமிக்கப்பட்ட (தற்காலிகச் சேமிப்பு) நகலைப் படிக்க முடியவில்லை.</translation>
<translation id="2709516037105925701">தானாகநிரப்பு</translation>
+<translation id="2710942282213947212">உங்கள் கணினியில் உள்ள மென்பொருளானது, இணையத்துடன் Chromium பாதுகாப்பாக இணைவதை நிறுத்துகிறது</translation>
<translation id="2712173769900027643">அனுமதி கேள்</translation>
-<translation id="2713444072780614174">வெள்ளை</translation>
<translation id="2720342946869265578">அருகிலுள்ளவை</translation>
<translation id="2721148159707890343">கோரிக்கை வெற்றி</translation>
<translation id="2728127805433021124">சேவையகச் சான்றிதழ் ஒரு வலுவற்ற கையொப்ப அல்காரிதமைப் பயன்படுத்தி கையொப்பமிடப்பட்டுள்ளது.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">பிணைய மாற்றம் கண்டறியப்பட்டது.</translation>
<translation id="2916038427272391327">பிற நிரல்களை மூடவும்</translation>
<translation id="2922350208395188000">சேவையகச் சான்றிதழை சோதிக்க முடியவில்லை.</translation>
+<translation id="2925673989565098301">டெலிவரி முறை</translation>
<translation id="2928905813689894207">பில்லிங் முகவரி</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழ் <ph name="DOMAIN2" /> இலிருந்து பெறப்பட்டது. இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">தவறான கொள்கை வகை</translation>
<translation id="3032412215588512954">தளத்தை மீண்டும் ஏற்றவா?</translation>
<translation id="3037605927509011580">அச்சச்சோ!</translation>
+<translation id="3039538478787849737">Google இல் கார்டைச் சேமிக்கவா?</translation>
<translation id="3041612393474885105">சான்றிதழ் தகவல்</translation>
<translation id="3063697135517575841">இப்போது உங்கள் கார்டை உறுதிசெய்ய முடியவில்லை. பிறகு முயலவும்.</translation>
<translation id="3064966200440839136">வெளிப்புறப் பயன்பாட்டின் மூலம் பணத்தை செலுத்த, மறைநிலையிலிருந்து வெளியேறுகிறீர்கள். தொடரவா?</translation>
@@ -278,12 +287,14 @@
<translation id="3150653042067488994">தற்காலிக சேவையகப் பிழை</translation>
<translation id="3154506275960390542">பாதுகாப்பற்ற முறையில் சமர்ப்பிக்கப்படக்கூடிய படிவம் இந்தப் பக்கத்தில் உள்ளது. நீங்கள் அனுப்பும் தரவு சேவையகத்தை அடையும் முன்பு பிறர் அதைப் பார்க்கலாம் அல்லது சேவையகம் பெறும் தரவை தீங்கிழைப்பவர் மாற்றியமைக்கலாம்.</translation>
<translation id="3157931365184549694">மீட்டமை</translation>
+<translation id="3162559335345991374">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் வைஃபை, அதன் உள்நுழைவுப் பக்கத்தை நீங்கள் பார்க்கக் கோரலாம்.</translation>
<translation id="3167968892399408617">உங்கள் மறைநிலை தாவல்கள் அனைத்தையும் மூடிய பின், அவற்றில் நீங்கள் பார்த்த பக்கங்கள் உலாவியின் வரலாறு, குக்கீ சேமிப்பகம் அல்லது தேடல் வரலாற்றில் இருக்காது. நீங்கள் இறக்கிய எல்லா கோப்புகள் அல்லது உருவாக்கிய புத்தகக்குறிகள் அப்படியே இருக்கும்.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">தீவு</translation>
<translation id="3176929007561373547">பிராக்சி சர்வர் இயக்கத்தில் உள்ளது என்பதை உறுதிப்படுத்த உங்கள் பிராக்சி அமைப்புகளைச் சரிபார்க்கவும் அல்லது நெட்வொர்க் நிர்வாகியைத் தொடர்புகொள்ளவும். நீங்கள் பிராக்சி சர்வரைப் பயன்படுத்துகிறீர்கள் என்பதை நம்பவில்லை என்றால், பின்வருவதைச் செய்யவும்:<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">கட்டணம் செலுத்துவதை ரத்துசெய்</translation>
<translation id="3207960819495026254">புக்மார்க் செய்யப்பட்டது</translation>
+<translation id="3211223744486044430">அடுத்த முறை விரைவாகப் பணத்தைச் செலுத்த, இந்தக் கார்டை உங்கள் Google கணக்கிலும் இந்தச் சாதனத்திலும் சேமிக்கவும்.</translation>
<translation id="3225919329040284222">உள்ளமைந்த எதிர்பார்ப்புகளுடன் பொருந்தாத சான்றிதழை சேவையகம் வழங்கியது. சில உயர்-பாதுகாப்பு வலைத்தளங்களில் உங்களைப் பாதுகாக்கவே இந்த எதிர்பார்ப்புகள் சேர்க்கப்படுகின்றன.</translation>
<translation id="3226128629678568754">பக்கத்தை ஏற்ற தேவைப்படும் தரவை மறுமுறைச் சமர்ப்பிப்பதற்கு மீண்டும் ஏற்று என்ற பொத்தானை அழுத்துக.</translation>
<translation id="3227137524299004712">மைக்ரோஃபோன்</translation>
@@ -298,7 +309,6 @@
<translation id="3303855915957856445">தேடல் முடிவுகள் எதுவுமில்லை</translation>
<translation id="3305707030755673451"><ph name="TIME" /> அன்று உங்கள் தரவு உங்கள் ஒத்திசைவு கடவுச்சொற்றொடரைக் கொண்டு முறைமையாக்கப்பட்டது. ஒத்திசைவைத் தொடங்க, அதை உள்ளிடவும்.</translation>
<translation id="3320021301628644560">பில்லிங் முகவரியைச் சேர்க்கவும்</translation>
-<translation id="3329013043687509092">நிறை செறிவு நிலை</translation>
<translation id="333371639341676808">இந்த பக்கம் கூடுதல் உரையாடல்களை உருவாக்குவதைத் தடு.</translation>
<translation id="3338095232262050444">பாதுகாப்பானது</translation>
<translation id="3340978935015468852">அமைப்புகள்</translation>
@@ -317,6 +327,7 @@
<translation id="3380864720620200369">கிளையன்ட் ஐடி:</translation>
<translation id="3391030046425686457">டெலிவரி முகவரி</translation>
<translation id="3395827396354264108">பிக்அப் முறை</translation>
+<translation id="3399952811970034796">டெலிவரி முகவரி</translation>
<translation id="3422248202833853650">பிற நிரல்களிலிருந்து வெளியேறி, நினைவகத்தைக் காலியாக்கவும்.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" />ஐத் தற்போது அணுக முடியவில்லை.</translation>
<translation id="3427092606871434483">அனுமதி (இயல்பு)</translation>
@@ -362,10 +373,12 @@
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> அன்று சிதைவு அறிக்கை பதிவுசெய்யப்பட்டு, <ph name="UPLOAD_TIME" /> அன்று பதிவேற்றப்பட்டது</translation>
<translation id="3681007416295224113">சான்றிதழ் தகவல்</translation>
<translation id="3690164694835360974">உள்நுழைவது பாதுகாப்பானது அல்ல</translation>
+<translation id="3704162925118123524">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் நெட்வொர்க், அதன் உள்நுழைவுப் பக்கத்தை நீங்கள் பார்க்க வேண்டலாம்.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ஏற்றுகிறது…</translation>
<translation id="3712624925041724820">உரிமம் முடிந்தது</translation>
<translation id="3714780639079136834">மொபைல் தரவு அல்லது வைஃபையை இயக்குதல்</translation>
+<translation id="3715597595485130451">வைஃபையுடன் இணைத்தல்</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ப்ராக்ஸி, ஃபயர்வால் மற்றும் DNS உள்ளமைவைச் சரிபார்த்தல்<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">உங்கள் பாதுகாப்பிற்கான ஆபத்தைப் புரிந்துகொண்டால், தீங்கிழைக்கும் நிரல்கள் அகற்றப்படுவதற்கு முன் <ph name="BEGIN_LINK" />இந்தப் பாதுகாப்பற்ற தளத்தைப் பார்வையிடலாம்<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">நீங்கள் நகலெடுத்த இணைப்பு</translation>
@@ -400,6 +413,7 @@
<translation id="4030383055268325496">&amp;சேர்த்தலைச் செயல்தவிர்</translation>
<translation id="404928562651467259">எச்சரிக்கை</translation>
<translation id="4058922952496707368">விசை "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">சரியான முகவரியைச் சேர்க்கவும்</translation>
<translation id="4072486802667267160">ஆர்டரைச் செயல்படுத்துவதில் பிழை ஏற்பட்டது. பிறகு முயலவும்.</translation>
<translation id="4075732493274867456">க்ளையன்ட்டும் சேவையகமும் பொதுவான SSL நெறிமுறைப் பதிப்பையோ சைஃபர் பொதியையோ ஆதரிக்கவில்லை.</translation>
<translation id="4079302484614802869">ப்ராக்ஸி உள்ளமைவானது, .pac ஸ்கிரிப்ட் URL ஐப் பயன்படுத்தும்படி அமைக்கப்பட்டிருக்கிறது, நிலையான ப்ராக்ஸி சேவையகங்களுக்கு அல்ல.</translation>
@@ -407,7 +421,6 @@
<translation id="4103249731201008433">சாதன சீரியல் எண் தவறானது</translation>
<translation id="410351446219883937">தானியங்கி</translation>
<translation id="4103763322291513355">ஏற்கத்தகாத URLகளின் பட்டியலையும் உங்கள் கணினி நிர்வாகியால் செயற்படுத்தப்படும் பிற கொள்கைகளையும் காண &lt;strong&gt;chrome://policy&lt;/strong&gt; ஐப் பார்வையிடவும்.</translation>
-<translation id="4115378294792113321">மெஜந்தா</translation>
<translation id="4116663294526079822">இந்தத் தளத்தில் எப்போதும் அனுமதி</translation>
<translation id="4117700440116928470">கொள்கையின் நோக்கம் ஆதரிக்கப்படவில்லை.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{மேலும் ஒன்று}other{மேலும் #}}</translation>
@@ -445,6 +458,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" /> ஐ அடைய முயற்சி செய்தீர்கள். ஆனால் சேவையகம் வழங்கிய சான்றிதழானது அதன் வழங்குநரால் நிராகரிக்கப்பட்டது. அதாவது, சேவையகம் வழங்கிய பாதுகாப்பு நம்பிக்கைச்சான்றுகளை நிச்சயமாக எக்காரணத்தைக்கொண்டும் நம்பக்கூடாது. போலியான ஒன்றுடன் நீங்கள் தகவல் பரிமாற்றம் செய்துகொண்டிருக்கக்கூடும்.</translation>
<translation id="4394049700291259645">முடக்கு</translation>
<translation id="4406896451731180161">தேடல் முடிவுகள்</translation>
+<translation id="4415426530740016218">பிக்அப் முகவரி</translation>
<translation id="4424024547088906515">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழை Chrome நம்பவில்லை. இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> உங்கள் உள்நுழைவுச் சான்றிதழை ஏற்கவில்லை அல்லது சான்றிதழ் வழங்கப்படாமல் இருக்கக்கூடும்.</translation>
<translation id="443673843213245140">ப்ராக்ஸி பயன்பாடு முடக்கப்பட்டுள்ளது. ஆனால் வெளிப்படையான ப்ராக்ஸி உள்ளமைவு குறிப்பிடப்பட்டுள்ளது.</translation>
@@ -457,6 +471,7 @@
<translation id="4552089082226364758">ஃப்ளாஷ்</translation>
<translation id="4558551763791394412">நீட்டிப்புகளை முடக்கவும்.</translation>
<translation id="457875822857220463">டெலிவரி</translation>
+<translation id="4582800630050655161">Google கணக்கிற்கான அணுகலை நீங்கள் இழக்கக்கூடும் அல்லது அடையாளத் திருட்டை எதிர்கொள்ளக்கூடும். இப்போதே உங்கள் கடவுச்சொல்லை மாற்றும்படி Chromium பரிந்துரைக்கிறது.</translation>
<translation id="4587425331216688090">Chrome இலிருந்து முகவரியை அகற்றவா?</translation>
<translation id="4592951414987517459">நவீன சைபர் சூட்டைப் பயன்படுத்தி <ph name="DOMAIN" /> உடனான உங்கள் இணைப்பு என்க்ரிப்ட் செய்யப்பட்டது.</translation>
<translation id="4594403342090139922">&amp;நீக்குதலைச் செயல்தவிர்</translation>
@@ -465,10 +480,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழில் பிழைகள் உள்ளன. இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
<translation id="4690462567478992370">தவறான சான்றிதழைப் பயன்படுத்துவதை நிறுத்து</translation>
+<translation id="4690954380545377795">Google கணக்கிற்கான அணுகலை நீங்கள் இழக்கக்கூடும் அல்லது அடையாளத் திருட்டை எதிர்கொள்ளக்கூடும். இப்போதே உங்கள் கடவுச்சொல்லை மாற்றும்படி Chrome பரிந்துரைக்கிறது.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">உங்கள் இணைப்பில் தடங்கல் ஏற்பட்டது</translation>
<translation id="471880041731876836">இந்தத் தளத்தைப் பார்ப்பதற்கான அனுமதி உங்களிடம் இல்லை</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows நெட்வொர்க் டயக்னஸ்டிக்ஸ் கருவியை இயக்கவும்<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">உங்கள் கட்டணம்</translation>
<translation id="4726672564094551039">கொள்கைகளை மீண்டும் ஏற்று</translation>
<translation id="4728558894243024398">ப்ளாட்ஃபார்ம்</translation>
<translation id="4736825316280949806">Chromiumஐ மீண்டும் தொடங்கவும்</translation>
@@ -507,6 +524,7 @@
<translation id="5019198164206649151">தவறான நிலையில் மீட்பு சேமிப்பு உள்ளது</translation>
<translation id="5023310440958281426">உங்கள் நிர்வாகியின் கொள்கைகளைச் சரிபார்க்கவும்</translation>
<translation id="5029568752722684782">நகலை அழி</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" மென்பொருளுக்கு மூலச் சான்றிதழ் தேவை, ஆனால் நிறுவப்படவில்லை. இந்தச் சிக்கலைச் சரிசெய்ய, "<ph name="SOFTWARE_NAME" />" மென்பொருளின் உள்ளமைவு வழிமுறைகளை ஐடி நிர்வாகி பின்பற்ற வேண்டும். <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google மொழியாக்கம் ஓர் அறிமுகம்</translation>
<translation id="5039804452771397117">அனுமதி</translation>
<translation id="5040262127954254034">தனியுரிமை</translation>
@@ -530,6 +548,8 @@
<translation id="5199729219167945352">சோதனைகள்</translation>
<translation id="5205222826937269299">பெயர் தேவை</translation>
<translation id="5222812217790122047">மின்னஞ்சல் தேவை</translation>
+<translation id="522700295135997067">உங்கள் கடவுச்சொல்லை இந்தத் தளம் திருடியிருக்கலாம்</translation>
+<translation id="5230733896359313003">ஷிப்பிங் முகவரி</translation>
<translation id="5251803541071282808">கிளவுடு</translation>
<translation id="5277279256032773186">பணியில் Chromeஐப் பயன்படுத்துகிறீர்களா? வணிக நிறுவனங்கள் தங்களின் பணியாளர்களுக்கான Chrome அமைப்புகளை நிர்வகிக்கலாம். மேலும் அறிக</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />மென்பொருளைத் தற்காலிகமாக முடக்கி, இணையத்துடன் இணைவதற்கு, பின்வரும் படிகளைப் பின்பற்றவும். உங்களுக்கு நிர்வாகி முன்னுரிமைகள் தேவைப்படும்.<ph name="END_PARAGRAPH" />
@@ -544,9 +564,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">இந்தத் தளத்திற்கான உங்கள் இணைப்பு தனிப்பட்டதல்ல. VR பயன்முறையிலிருந்து எப்போது வேண்டுமானாலும் வெளியேற, ஹெட்செட்டை அகற்றி, "முந்தையது" என்பதைக் கிளிக் செய்யவும்.</translation>
<translation id="5299298092464848405">கொள்கையை அலசுவதில் பிழை</translation>
+<translation id="5308380583665731573">இணை</translation>
<translation id="5308689395849655368">செயலிழப்பு புகாரளித்தல் முடக்கப்பட்டுள்ளது.</translation>
<translation id="5317780077021120954">சேமி</translation>
<translation id="5327248766486351172">பெயர்</translation>
+<translation id="5332219387342487447">ஷிப்பிங் முறை</translation>
<translation id="5355557959165512791"><ph name="SITE" /> தளத்தின் சான்றிதழ் ரத்துசெய்யப்பட்டதால், தற்போது அதைப் பார்க்க முடியாது. பொதுவாக நெட்வொர்க் பிழைகளும் பாதிப்புகளும் தற்காலிகமானவை என்பதால், இந்தப் பக்கம் பின்னர் சரியாகச் செயல்படக்கூடும்.</translation>
<translation id="536296301121032821">கொள்கை அமைப்புகளைச் சேமிப்பதில் தோல்வி</translation>
<translation id="5386426401304769735">இந்தச் சான்றிதழ் சங்கிலியில், SHA-1ஐப் பயன்படுத்தி கையொப்பமிடப்பட்ட சான்றிதழ் உள்ளது.</translation>
@@ -566,12 +588,15 @@
<translation id="5492298309214877701">நிறுவனம், அமைப்பு அல்லது பள்ளி அக இணையத்தில் உள்ள இந்தத் தளம் வெளிப்புற இணையதளம் ஒன்றின் அதே URLஐக் கொண்டிருக்கிறது.
<ph name="LINE_BREAK" />
உங்கள் முறைமை நிர்வாகியைத் தொடர்புகொள்ள முயலவும்.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> கிரெடிட் கார்டிற்கான பாதுகாப்புக் குறியீட்டை உள்ளிடவும். இந்தக் குறியீடு சேமிக்கப்படாது.</translation>
<translation id="5509780412636533143">நிர்வகிக்கப்படும் புக்மார்க்குகள்</translation>
<translation id="5510766032865166053">அது நகர்த்தப்பட்டிருக்கலாம் அல்லது நீக்கப்பட்டிருக்கலாம்.</translation>
<translation id="5523118979700054094">கொள்கைப் பெயர்</translation>
<translation id="552553974213252141">உரையானது சரியான முறையில் பிரித்தெடுக்கப்பட்டதா?</translation>
<translation id="5540224163453853">கோரப்பட்ட கட்டுரையைக் கண்டுபிடிக்க முடியவில்லை.</translation>
+<translation id="5541546772353173584">மின்னஞ்சலைச் சேர்க்கவும்</translation>
<translation id="5544037170328430102"><ph name="SITE" /> இல் உள்ள உட்பொதிக்கப்பட்ட பக்கம் தெரிவிப்பது:</translation>
+<translation id="5545756402275714221">உங்களுக்கான செய்திக் கட்டுரைகள்</translation>
<translation id="5556459405103347317">மீண்டும் ஏற்று</translation>
<translation id="5560088892362098740">காலாவதியாகும் தேதி</translation>
<translation id="5565735124758917034">செயலில் உள்ளது</translation>
@@ -593,6 +618,7 @@
<translation id="5659593005791499971">மின்னஞ்சல்</translation>
<translation id="5669703222995421982">தனிப்பயனாக்கிய உள்ளடக்கத்தைப் பெறுங்கள்</translation>
<translation id="5675650730144413517">இந்தப் பக்கம் செயல்படவில்லை</translation>
+<translation id="5689199277474810259">JSONக்கு ஏற்று</translation>
<translation id="5710435578057952990">இந்த தளத்தின் அடையாளம் சரிபார்க்கப்படவில்லை.</translation>
<translation id="5719499550583120431">ப்ரீபெய்டு கார்டுகள் ஏற்கப்படுகின்றன.</translation>
<translation id="5720705177508910913">நடப்புப் பயனர்</translation>
@@ -607,27 +633,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" />க்கான உங்கள் இணைப்பு, நடைமுறையில் இல்லாத சைபர் சூட்டைப் பயன்படுத்தி என்க்ரிப்ட் செய்யப்பட்டது.</translation>
<translation id="5813119285467412249">&amp;சேர்த்தலை மீண்டும் செய்</translation>
<translation id="5838278095973806738">தீங்கிழைப்பவர்கள் திருடிவிடலாம் என்பதால், இந்தத் தளத்தில் முக்கியத் தகவலை (எடுத்துக்காட்டு: கடவுச்சொற்கள் அல்லது கிரெடிட் கார்டுகள்) உள்ளிட வேண்டாம்.</translation>
+<translation id="5866257070973731571">மொபைல் எண்ணைச் சேர்க்கவும்</translation>
<translation id="5869405914158311789">இந்தத் தளத்தை அணுக முடியவில்லை</translation>
<translation id="5869522115854928033">சேமிக்கப்பட்ட கடவுச்சொற்கள்</translation>
<translation id="5872918882028971132">மூலப் பரிந்துரைகள்</translation>
<translation id="5893752035575986141">கிரெடிட் கார்டுகள் ஏற்கப்படுகின்றன.</translation>
-<translation id="5901630391730855834">மஞ்சள்</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ஒத்திசைக்கப்பட்டது)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{ஒரு குக்கீ பயன்படுத்தப்படுகிறது}other{# குக்கீகள் பயன்படுத்தப்படுகின்றன}}</translation>
<translation id="5959728338436674663">ஆபத்தான பயன்பாடுகளையும் தளங்களையும் கண்டறிவதற்கு உதவியாக, சில <ph name="BEGIN_WHITEPAPER_LINK" />சாதனத் தகவலையும் பக்க உள்ளடக்கத்தையும்<ph name="END_WHITEPAPER_LINK" /> Googleக்குத் தானாக அனுப்பு. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">தொடர்புத் தகவலைத் திருத்தவும்</translation>
<translation id="5967867314010545767">வரலாற்றிலிருந்து அகற்று</translation>
<translation id="5975083100439434680">சிறிதாக்கு</translation>
+<translation id="597552863672748783">பாதுகாப்புக் குறியீட்டை உறுதிப்படுத்தவும்</translation>
<translation id="598637245381783098">பேமெண்ட் பயன்பாட்டைத் திறக்க முடியவில்லை</translation>
<translation id="5989320800837274978">ப்ராக்ஸி சேவையகம் சரிசெய்யப்படவும் இல்லை .pac ஸ்கிரிப்ட் URL குறிப்பிடப்படவுமில்லை.</translation>
<translation id="5990559369517809815">சேவையகத்திற்கான கோரிக்கைகள் நீட்டிப்பினால் தடுக்கப்பட்டது.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{பக்கம் 1}other{பக்கம் #}}</translation>
-<translation id="6017514345406065928">பச்சை</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (ஒத்திசைக்கப்பட்டன)</translation>
<translation id="6027201098523975773">பெயரை உள்ளிடவும்</translation>
<translation id="6040143037577758943">மூடு</translation>
-<translation id="6042308850641462728">மேலும்</translation>
<translation id="6047233362582046994">உங்கள் பாதுகாப்பிற்கான ஆபத்துகளைப் புரிந்துகொண்டால், தீங்கிழைக்கும் பயன்பாடுகள் அகற்றப்படுவதற்கு முன் நீங்கள் <ph name="BEGIN_LINK" />இந்தத் தளத்தைப் பார்வையிடலாம்<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">இந்த உள்ளடக்கம், உங்களை ஏமாற்றி மென்பொருளை நிறுவ வைக்கலாம் அல்லது தனிப்பட்ட தகவலை வெளிப்படுத்தச் செய்யலாம். <ph name="BEGIN_LINK" />பரவாயில்லை, காட்டு<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> தளமானது சர்டிஃபிகேட் பின்னிங்கைப் பயன்படுத்துவதால், தற்போது அதைப் பார்க்க முடியாது. பொதுவாக நெட்வொர்க் பிழைகளும் பாதிப்புகளும் தற்காலிகமானவை என்பதால், இந்தப் பக்கம் பின்னர் சரியாகச் செயல்படக்கூடும்.</translation>
@@ -693,6 +719,7 @@
<translation id="6569060085658103619">நீட்டிப்புப் பக்கத்தைப் பார்க்கிறீர்கள்</translation>
<translation id="6596325263575161958">குறியாக்க விருப்பங்கள்</translation>
<translation id="662080504995468778">வேண்டாம்</translation>
+<translation id="6624427990725312378">தொடர்புத் தகவல்</translation>
<translation id="6626291197371920147">சரியான கார்டு எண்ணைச் சேர்க்கவும்</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> தேடல்</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> தளத்தில் தற்போதுள்ள ஹேக்கர்கள் உங்கள் தனிப்பட்ட தகவலை (எடுத்துக்காட்டாக, படங்கள், கடவுச்சொற்கள், செய்திகள் மற்றும் கிரெடிட் கார்டுகள்) திருடக்கூடிய அல்லது நீக்கக்கூடிய ஆபத்தான நிரல்களை உங்கள் Mac இல் நிறுவ முயற்சிக்கக்கூடும். <ph name="BEGIN_LEARN_MORE_LINK" />மேலும் அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -703,7 +730,6 @@
<translation id="6710213216561001401">முந்தையது</translation>
<translation id="6710594484020273272">&lt;தேடல் வார்த்தையை உள்ளிடுக&gt;</translation>
<translation id="6711464428925977395">ப்ராக்ஸி சர்வரில் ஏதோ தவறு உள்ளது அல்லது முகவரி தவறாக உள்ளது.</translation>
-<translation id="6727102863431372879">அமை</translation>
<translation id="674375294223700098">தெரியாத சேவையகச் சான்றிதழ் பிழை.</translation>
<translation id="6753269504797312559">கொள்கை மதிப்பு</translation>
<translation id="6757797048963528358">உங்கள் சாதனம் உறக்கநிலைக்குச் சென்றது.</translation>
@@ -772,6 +798,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">சுயவிவரப் பாதை</translation>
<translation id="7424977062513257142">இந்த இணையப்பக்கத்திலுள்ள உட்பொதிக்கப்பட்ட பக்கம் தெரிவிப்பது:</translation>
+<translation id="7437289804838430631">தொடர்புத் தகவலைச் சேர்</translation>
<translation id="7441627299479586546">தவறான கொள்கைத் தலைப்பு</translation>
<translation id="7444046173054089907">இந்தத் தளம் தடுக்கப்பட்டது</translation>
<translation id="7445762425076701745">நீங்கள் இணைந்துள்ள சேவையகத்தின் அடையாளத்தை முழுமையாக சரிபார்க்க முடியவில்லை. பெயர் மட்டுமே செல்லுபடியாகும் என்ற முறையைப் பயன்படுத்தி உங்கள் பிணையத்திற்குள் சேவையகத்துடன் இணைந்துள்ளீர்கள், இதன் உரிமையை ஒரு வெளிப்புற சான்றிதழ் மையம் எப்போதும் உறுதிப்படுத்த முடியாது. சில சான்றிதழ் மையங்கள், இந்தப் பெயர்களுக்கும் சான்றிதழ்களை வழங்குவார்கள் என்பதால், நீங்கள் நினைத்த வலைப்பக்கத்துடனே இணைந்துள்ளீர்கள், ஏதேனும் மோசடி தளத்துடன் இணையவில்லை என்பதை உறுதிப்படுத்த எந்த வழியும் இல்லை.</translation>
@@ -782,11 +809,11 @@
<translation id="7481312909269577407">அடுத்த பக்கம்</translation>
<translation id="7485870689360869515">தரவு எதுவும் இல்லை.</translation>
<translation id="7508255263130623398">கிடைத்த பாலிசி சாதன ஐடி காலியாக உள்ளது அல்லது தற்போதைய சாதன ஐடியுடன் பொருந்தவில்லை</translation>
+<translation id="7511955381719512146">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் வைஃபை, அதன் <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ஐ நீங்கள் பார்க்கக் கோரலாம்.</translation>
<translation id="7514365320538308">பதிவிறக்கு</translation>
<translation id="7518003948725431193">வலை முகவரிக்கான வலைப்பக்கங்கள் ஏதும் காணப்படவில்லை: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">இந்தத் தளத்திற்கான உங்கள் இணைப்பு தனிப்பட்டதல்ல</translation>
-<translation id="7535087603100972091">மதிப்பு</translation>
<translation id="7537536606612762813">கட்டாயம்</translation>
<translation id="7542403920425041731">நீங்கள் உறுதிசெய்ததும், உங்கள் கார்டு விவரங்கள் இந்தத் தளத்துடன் பகிரப்படும்.</translation>
<translation id="7542995811387359312">இந்தப் படிவம் பாதுகாப்பான இணைப்பைப் பயன்படுத்தாத காரணத்தால், தானியங்கு கடன் அட்டை நிரப்புதல் முடக்கப்பட்டிருக்கிறது.</translation>
@@ -797,7 +824,6 @@
<translation id="7567204685887185387">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழில் மோசடி செய்யப்பட்டிருக்கலாம். இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
<translation id="7568593326407688803">இந்தப் பக்கமானது<ph name="ORIGINAL_LANGUAGE" />இல் உள்ளது இதை மொழிபெயர்க்க விரும்புகிறீர்களா?</translation>
<translation id="7569952961197462199">Chrome இலிருந்து கிரெடிட் கார்டை அகற்றவா?</translation>
-<translation id="7569983096843329377">கருப்பு</translation>
<translation id="7578104083680115302">Google இல் நீங்கள் சேமித்துள்ள கார்டுகளைப் பயன்படுத்தி பல தளங்களிலும் பயன்பாடுகளிலும் உங்களுடைய சாதனங்களில் அனைத்திலும் விரைவாகப் பணம் செலுத்தலாம்.</translation>
<translation id="7588950540487816470">இயல்நிலை இணையம்</translation>
<translation id="7592362899630581445">பெயர் கட்டுப்பாடுகளைச் சேவையகத்தின் சான்றிதழ் மீறுகிறது.</translation>
@@ -816,11 +842,13 @@
<translation id="7669271284792375604">இந்தத் தளத்தில் உள்ள ஹேக்கர்கள், உங்களை ஏமாற்றி (எடுத்துக்காட்டாக, உங்கள் முகப்புப் பக்கத்தை மாற்றுவது அல்லது நீங்கள் பார்வையிடும் தளங்களில் கூடுதல் விளம்பரங்களைக் காட்டுவது), உங்கள் உலாவல் அனுபவத்தைப் பாதிக்கக்கூடிய நிரல்களை நிறுவ வைக்கலாம்.</translation>
<translation id="7674629440242451245">புதிய Chrome அம்சங்களில் ஆர்வமாக உள்ளீர்களா? chrome.com/dev இல் எங்களுடைய dev சேனலை முயற்சிக்கவும்.</translation>
<translation id="7682287625158474539">ஷிப்பிங்</translation>
+<translation id="7699293099605015246">தற்போது கட்டுரைகள் இல்லை</translation>
<translation id="7701040980221191251">எதுவுமில்லை</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> (பாதுகாப்பற்ற தளம்) க்குச் செல்லவும்<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">சான்றிதழ்</translation>
<translation id="7716147886133743102">உங்கள் நிர்வாகி தடுத்துள்ளார்</translation>
<translation id="7716424297397655342">தற்காலிகச் சேமிப்பிலிருந்து இந்தத் தளத்தை ஏற்ற முடியவில்லை</translation>
+<translation id="7723047071702270851">கார்டைத் திருத்தவும்</translation>
<translation id="774634243536837715">ஆபத்தான உள்ளடக்கம் தடுக்கப்பட்டது.</translation>
<translation id="7752995774971033316">நிர்வகிக்கப்படாதது</translation>
<translation id="7755287808199759310">உங்களுக்காக, தளத்தின் தடுப்பை உங்கள் பெற்றோர் நீக்க முடியும்</translation>
@@ -831,21 +859,24 @@
<translation id="7764225426217299476">முகவரியைச் சேர்</translation>
<translation id="777702478322588152">ப்ரீஃபெக்சர்</translation>
<translation id="7791543448312431591">சேர்</translation>
+<translation id="7793553086574152071">அடுத்த முறை விரைவாகப் பணத்தைச் செலுத்த, இந்தக் கார்டை உங்கள் Google கணக்கில் சேமிக்கவும்.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> இல் உள்ள வலைப்பக்கமானது தற்காலிகமாக இயங்காமல் இருக்கலாம் அல்லது அது ஒரு புதிய வலை முகவரிக்கு நிரந்தரமாக நகர்த்தப்பட்டிருக்கலாம்.</translation>
<translation id="7800304661137206267">செய்தி அங்கீகரிப்பிற்காக, <ph name="KX" /> ஐ விசைப் பரிமாற்ற செயல்முறையாகக் கொண்டு, <ph name="MAC" /> உடன் <ph name="CIPHER" /> ஐப் பயன்படுத்தி இணைப்பானது குறியாக்கப்பட்டது.</translation>
+<translation id="7802523362929240268">தளமானது சட்டப்பூர்வமானது</translation>
<translation id="780301667611848630">தேவையில்லை</translation>
<translation id="7805768142964895445">நிலை</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome இலிருந்து படிவப் பரிந்துரையை அகற்றவா?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'க்கு <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> உள்ளன</translation>
+<translation id="782886543891417279">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் (<ph name="WIFI_NAME" />) வைஃபை, அதன் உள்நுழைவுப் பக்கத்தை நீங்கள் பார்க்கக் கோரலாம்.</translation>
<translation id="785549533363645510">இருப்பினும், நீங்கள் மறைந்திருக்கமாட்டீர்கள். மறைநிலைக்குச் செல்வது பணிக்கமர்த்தும் நிறுவனம், இணையச் சேவை வழங்குநர் அல்லது நீங்கள் செல்லும் இணையதளங்களிடம் உங்கள் உலாவலை மறைக்காது.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">டெபிட் மற்றும் ப்ரீபெய்டு கார்டுகள் ஏற்கப்படுகின்றன.</translation>
+<translation id="7878562273885520351">உங்கள் கடவுச்சொல் திருடப்பட்டிருக்கலாம்</translation>
<translation id="7887683347370398519">CVCஐச் சோதித்து, மீண்டும் முயற்சிக்கவும்</translation>
<translation id="79338296614623784">சரியான ஃபோன் எண்ணை உள்ளிடவும்</translation>
<translation id="7935318582918952113">DOM டிஸ்டில்லர்</translation>
<translation id="7938958445268990899">சேவையகச் சான்றிதழ் இன்னும் செல்லுபடியாகவில்லை.</translation>
-<translation id="7942349550061667556">சிவப்பு</translation>
<translation id="7947285636476623132">காலாவதி ஆண்டைச் சரிபார்த்து, மீண்டும் முயலவும்</translation>
<translation id="7951415247503192394">(32-பிட்)</translation>
<translation id="7956713633345437162">மொபைல் புக்மார்க்குகள்</translation>
@@ -859,9 +890,13 @@
<translation id="8037357227543935929">கேள் (இயல்பு)</translation>
<translation id="8041089156583427627">கருத்துத் தெரிவிக்கவும்</translation>
<translation id="8041940743680923270">முழுமையான இயல்புநிலையைப் பயன்படுத்து (கேள்)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" மென்பொருள் சரியாக உள்ளமைக்கப்படவில்லை. வழக்கமாக, "<ph name="SOFTWARE_NAME" />"ஐ நிறுவல் நீக்கினால் சிக்கல் சரியாகிவிடும். <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">கட்டுரையைக் காட்டுவதில் தோல்வி.</translation>
<translation id="8091372947890762290">சேவையகத்தில் செயலாக்கம் நிலுவையிலுள்ளது</translation>
+<translation id="8094917007353911263">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் நெட்வொர்க், அதன் <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ஐ நீங்கள் பார்க்கக் கோரலாம்.</translation>
+<translation id="8103161714697287722">கட்டண முறை</translation>
<translation id="8118489163946903409">கட்டண முறை</translation>
+<translation id="8127301229239896662">உங்கள் கணினி அல்லது நெட்வொர்க்கில் "<ph name="SOFTWARE_NAME" />" மென்பொருள் சரியாக உள்ளமைக்கப்படவில்லை. இந்தச் சிக்கலைச் சரிசெய்யும்படி உங்கள் ஐடி நிர்வாகியிடம் கேட்கவும்.</translation>
<translation id="8131740175452115882">உறுதிப்படுத்து</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> இன் சேவையக <ph name="BEGIN_ABBR" />DNS முகவரியைக்<ph name="END_ABBR" /> கண்டுபிடிக்க முடியவில்லை.</translation>
<translation id="8149426793427495338">உங்கள் கணினி உறக்கநிலைக்குச் சென்றது.</translation>
@@ -884,6 +919,7 @@
<translation id="8289355894181816810">இதன் பொருள் உங்களுக்குத் தெரியவில்லையெனில் உங்கள் பிணைய நிர்வாகியைத் தொடர்புகொள்ளவும்.</translation>
<translation id="8293206222192510085">புக்மார்க்கைச் சேர்</translation>
<translation id="8294431847097064396">மூலம்</translation>
+<translation id="8298115750975731693">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் (<ph name="WIFI_NAME" />) வைஃபை, அதன் <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ஐ நீங்கள் பார்க்கக் கோரலாம்.</translation>
<translation id="8306404619377842860">உங்கள் சாதனத்தின் தேதியும் நேரமும் (<ph name="DATE_AND_TIME" />) தவறாக இருப்பதால், <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />க்கான தனிப்பட்ட இணைப்பைச் செயலாக்க முடியவில்லை. <ph name="BEGIN_LEARN_MORE_LINK" />மேலும் அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">பிணைய இணைப்பில் ஒரு சிக்கல் இருப்பதால் மொழிப்பெயர்ப்பு தோல்வியடைந்தது.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> க்கான அணுகல் மறுக்கப்பட்டது</translation>
@@ -936,20 +972,21 @@
<translation id="8870413625673593573">சமீபத்தில் மூடியவை</translation>
<translation id="8874824191258364635">சரியான கார்டு எண்ணை உள்ளிடவும்</translation>
<translation id="8876793034577346603">அலசுவதில் பிணைய உள்ளமைவு தோல்வி.</translation>
-<translation id="8889402386540077796">நிறச்சாயல்</translation>
<translation id="8891727572606052622">தவறான ப்ராக்ஸி முறை.</translation>
<translation id="889901481107108152">மன்னிக்கவும், இந்த சோதனை உங்கள் தளத்தில் கிடைக்கவில்லை.</translation>
<translation id="8903921497873541725">பெரிதாக்கு</translation>
<translation id="8931333241327730545">இந்தக் கார்டை உங்கள் Google கணக்கில் சேமிக்க வேண்டுமா?</translation>
<translation id="8932102934695377596">உங்கள் கடிகாரம் மிகவும் பின்தங்கி இருக்கிறது</translation>
+<translation id="893332455753468063">பெயரைச் சேர்க்கவும்</translation>
<translation id="8938939909778640821">ஏற்கப்படும் கிரெடிட் மற்றும் ப்ரீபெய்டு கார்டுகள்</translation>
+<translation id="8957210676456822347">கேப்டிவ் போர்டல் அங்கீகாரம்</translation>
<translation id="8971063699422889582">சேவையகச் சான்றிதழ் காலாவதியானது.</translation>
-<translation id="8986494364107987395">பயன்பாட்டுப் புள்ளிவிவரங்களையும் சிதைவு அறிக்கைகளையும் தானாகவே Google க்கு அனுப்பு</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">தளத்தில் தீங்கிழைக்கும் நிரல்கள் அதிகளவில் உள்ளன</translation>
<translation id="8997023839087525404">சான்றிதழ் வெளிப்படைத்தன்மை கொள்கையின்படி பொதுவில் வெளியிடப்படாத சான்றிதழைச் சேவையகம் வழங்கியுள்ளது. நம்பகத்தன்மை மற்றும் தாக்குதல்களுக்கு எதிரான பாதுகாப்பை உறுதிசெய்ய, சில சான்றிதழ்களுக்கு இது தேவையான ஒன்றாகும்.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> என்கிற ப்ராக்ஸிக்கு பயனர்பெயரும் கடவுச்சொல்லும் தேவை.</translation>
<translation id="9005998258318286617">PDF ஆவணத்தை ஏற்ற முடியவில்லை.</translation>
+<translation id="9008201768610948239">புறக்கணி</translation>
<translation id="901974403500617787">கணினி அளவில் பயன்படுத்தப்படும் கொடிகள் பின்வரும் உரிமையாளரால் மட்டுமே அமைக்கப்படும்: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">கார்டு பில்லிங் முகவரி தேவை</translation>
<translation id="9020542370529661692">இந்தப் பக்கம் <ph name="TARGET_LANGUAGE" /> க்கு மொழிபெயர்க்கப்பட்டது</translation>
@@ -959,12 +996,15 @@
<translation id="9049981332609050619">நீங்கள் <ph name="DOMAIN" /> ஐ அடைய முயற்சி செய்தீர்கள், ஆனால் சேவையகம் ஒரு செல்லாத சான்றிதழை வழங்கியது.</translation>
<translation id="9050666287014529139">கடவுச்சொற்றொடர்</translation>
<translation id="9065203028668620118">திருத்து</translation>
-<translation id="9068849894565669697">வண்ணத்தைத் தேர்ந்தெடு</translation>
<translation id="9069693763241529744">நீட்டிப்பு தடுத்துள்ளது</translation>
<translation id="9076283476770535406">இதில் பெரியவர்களுக்கான உள்ளடக்கம் இருக்கக்கூடும்</translation>
<translation id="9078964945751709336">கூடுதல் தகவல் தேவை</translation>
+<translation id="9080712759204168376">ஆர்டர் பற்றிய சுருக்கவிவரம்</translation>
<translation id="9103872766612412690">வழக்கமாக, <ph name="SITE" /> உங்கள் தகவலைப் பாதுகாப்பதற்காக முறைமையாக்கத்தைப் பயன்படுத்துகிறது.
இந்த முறை <ph name="SITE" /> உடன் இணைவதற்கு Chromium முயற்சித்தபோது வழக்கத்திற்கு மாறான, தவறான நற்சான்றிதழ்களை இணையதளம் வழங்கியது. தாக்குபவர் தன்னை <ph name="SITE" /> ஆகக் காட்ட முயற்சிக்கும் போது அல்லது இணைப்பை வைஃபை உள்நுழைவுத் திரை குறுக்கிடும் போது இது ஏற்படலாம். இருப்பினும், தரவு எதுவும் பரிமாற்றப்படுவதற்கு முன் Chromium இணைப்பை நிறுத்தியதால் உங்கள் தகவல் பாதுகாப்பாகவே இருக்கிறது.</translation>
+<translation id="9106062320799175032">பில்லிங் முகவரியைச் சேர்க்கவும்</translation>
+<translation id="910908805481542201">இதைச் சரிசெய்ய உதவு</translation>
+<translation id="9128870381267983090">பிணையத்துடன் இணை</translation>
<translation id="9137013805542155359">அசலைக் காண்பி</translation>
<translation id="9137248913990643158">இந்தப் பயன்பாட்டைப் பயன்படுத்தும் முன், Chromeஐத் தொடங்கி உள்நுழையவும்.</translation>
<translation id="9148507642005240123">&amp;திருத்தலைச் செயல்தவிர்</translation>
@@ -976,6 +1016,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ஆதரிக்கப்படாத நெறிமுறையைப் பயன்படுத்துகிறது.</translation>
<translation id="9205078245616868884">உங்கள் தரவு உங்கள் ஒத்திசைவு கடவுச்சொற்றொடரைக் கொண்டு முறைமையாக்கப்பட்டுள்ளது. ஒத்திசைவைத் தொடங்க, அதை உள்ளிடவும்.</translation>
<translation id="9207861905230894330">கட்டுரையைச் சேர்ப்பதில் தோல்வி.</translation>
+<translation id="9215416866750762878">இந்தத் தளத்துடன் Chrome பாதுகாப்பாக இணைவதை, பயன்பாடு தடுக்கிறது</translation>
<translation id="9219103736887031265">படங்கள்</translation>
<translation id="933612690413056017">இணைய இணைப்பு இல்லை</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -985,5 +1026,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{ஏதுமில்லை}=1{1 உருப்படி}other{# உருப்படிகள்}}</translation>
<translation id="981121421437150478">ஆஃப்லைன்</translation>
<translation id="988159990683914416">டெவலப்பர் கட்டமைப்பு</translation>
+<translation id="989988560359834682">முகவரியைத் திருத்து</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">உங்கள் கணினி அல்லது நெட்வொர்க்கில் "<ph name="SOFTWARE_NAME" />" மென்பொருள் சரியாக உள்ளமைக்கப்படவில்லை. பின்வருவனவற்றை முயற்சித்துப் பார்க்கவும்:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" மென்பொருளை நிறுவல் நீக்கவும் அல்லது முடக்கவும்&lt;/li&gt;
+ &lt;li&gt;வேறொரு நெட்வொர்க்குடன் இணைக்கவும்&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index 5074ba26a03..f7dfd32034e 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">డెస్క్‌టాప్‌ బుక్‌మార్క్‌లు</translation>
<translation id="1074497978438210769">సురక్షితం కాదు</translation>
<translation id="1080116354587839789">వెడల్పు సరిపోయేలా అమర్చు</translation>
+<translation id="1088860948719068836">కార్డ్‌లో పేరుని జోడించండి</translation>
<translation id="1103523840287552314">ఎల్లప్పుడూ <ph name="LANGUAGE" />ను అనువదించు</translation>
+<translation id="1103778128462718200">సేవ్ చేసిన అన్ని పాస్‌వర్డ్‌లను చూపు...</translation>
<translation id="1107591249535594099">ఎంచుకున్నట్లయితే, Chrome వేగవంతమైన ఫారమ్ పూరింపు కోసం ఈ పరికరంలో మీ కార్డ్ కాపీని నిల్వ చేస్తుంది.</translation>
<translation id="1111153019813902504">ఇటీవలి బుక్‌మార్క్‌లు</translation>
<translation id="1113869188872983271">&amp;మళ్లీ క్రమం చేయడాన్ని రద్దు చేయి</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (సమకాలీకరించబడ్డాయి)</translation>
<translation id="1263231323834454256">పఠన జాబితా</translation>
<translation id="1264126396475825575">క్రాష్ నివేదిక <ph name="CRASH_TIME" />కి సంగ్రహించబడింది (ఇంకా అప్‌లోడ్ చేయలేదు లేదా విస్మరించబడింది)</translation>
+<translation id="1270502636509132238">పికప్ పద్ధతి</translation>
<translation id="1281526147609854549"><ph name="ISSUER" /> ద్వారా జారీ చేయబడింది</translation>
<translation id="1285320974508926690">ఈ సైట్‌ను అనువదించవద్దు</translation>
<translation id="129553762522093515">ఇటీవల మూసివెయ్యబడినవి</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">కనెక్షన్ కోసం వేచి ఉన్నాము...</translation>
<translation id="153384715582417236">ఇప్పటికి ఇంతే</translation>
<translation id="1549470594296187301">ఈ లక్షణాన్ని ఉపయోగించడానికి జావాస్క్రిప్ట్ తప్పనిసరిగా ప్రారంభించాలి.</translation>
-<translation id="1555130319947370107">నీలం</translation>
<translation id="1559528461873125649">అటువంటి ఫైల్ లేదా డైరెక్టరీ లేదు</translation>
<translation id="1583429793053364125">ఈ వెబ్ పేజీని ప్రదర్శిస్తున్నప్పుడు ఏదో తప్పు జరిగింది.</translation>
<translation id="1592005682883173041">స్థానిక డేటా ప్రాప్యత</translation>
<translation id="1594030484168838125">ఎంచుకోండి</translation>
-<translation id="161042844686301425">నీలి ఆకుపచ్చ</translation>
<translation id="1620510694547887537">కెమెరా</translation>
<translation id="1629803312968146339">Chrome ఈ కార్డ్‌ను సేవ్ చేయాలని మీరు కోరుకుంటున్నారా?</translation>
<translation id="1639239467298939599">లోడ్ అవుతోంది</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">ఈ సైట్‌ని సందర్శించడానికి మీకు <ph name="NAME" /> నుండి అనుమతి అవసరం</translation>
<translation id="1721424275792716183">* అవసరమైన ఫీల్డ్</translation>
+<translation id="1727741090716970331">చెల్లుబాటయ్యే కార్డ్ నంబర్‌ను జోడించండి</translation>
<translation id="1728677426644403582">మీరు వెబ్ పేజీ యొక్క మూలాధారాన్ని వీక్షిస్తున్నారు</translation>
<translation id="173080396488393970">ఈ రకమైన కార్డ్‌కి మద్దతు లేదు</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">శ్రేణిగా రూపొందించడంలో లోపం</translation>
<translation id="1974060860693918893">ఆధునిక</translation>
<translation id="1978555033938440688">ఫర్మ్‌వేర్ సంస్కరణ</translation>
-<translation id="1995859865337580572">దయచేసి మీ CVCని ధృవీకరించండి</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{మరియు మరొకటి}other{మరియు మరో #}}</translation>
<translation id="2025186561304664664">ప్రాక్సీ స్వయంచాలకంగా కాన్ఫిగర్ చేయబడేలా సెట్ చేయబడింది.</translation>
<translation id="2030481566774242610">మీ ఉద్దేశ్యం <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">చర్య రద్దు</translation>
<translation id="20817612488360358">సిస్టమ్ ప్రాక్సీ సెట్టింగ్‌లు ఉపయోగించడానికి సెట్ చేయబడ్డాయి కానీ స్పష్టమైన ప్రాక్సీ కాన్ఫిగరేషన్ కూడా పేర్కొనబడింది.</translation>
<translation id="2086652334978798447">Google సూచించే వ్యక్తిగతీకృత కంటెంట్‌ను పొందడానికి, Chromeకి సైన్ ఇన్ చేయండి.</translation>
+<translation id="2091887806945687916">ధ్వని</translation>
<translation id="2094505752054353250">డొమైన్ సరిపోలలేదు</translation>
<translation id="2096368010154057602">శాఖ</translation>
<translation id="2108755909498034140">మీ కంప్యూటర్‌ను పునఃప్రారంభించండి</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">ఇది <ph name="POLICY_NAME" /> ద్వారా భర్తీ చేయబడినందున విస్మరించబడింది.</translation>
<translation id="2138201775715568214">సమీప భౌతిక వెబ్ పేజీల కోసం శోధిస్తోంది</translation>
<translation id="213826338245044447">మొబైల్ బుక్‌మార్క్‌లు</translation>
+<translation id="214556005048008348">చెల్లింపును రద్దు చేయి</translation>
<translation id="2147827593068025794">నేపథ్య సమకాలీకరణ</translation>
+<translation id="2148613324460538318">కార్డ్‌ని జోడించు</translation>
<translation id="2154054054215849342">సమకాలీకరణ మీ డొమైన్‌కు అందుబాటులో లేదు</translation>
<translation id="2154484045852737596">కార్డ్‌ను సవరించండి</translation>
<translation id="2166049586286450108">పూర్తి నిర్వాహక ప్రాప్యత</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 చిరునామా}other{# చిరునామాలు}}</translation>
<translation id="2187317261103489799">గుర్తించు (డిఫాల్ట్)</translation>
<translation id="2202020181578195191">చెల్లుబాటు అయ్యే గడువు ముగింపు సంవత్సరాన్ని నమోదు చేయండి</translation>
+<translation id="2209523182407020534">ఈ ఎర్రర్‌కు దారితీసే అప్లికేషన్‌లలో యాంటీవైరస్, ఫైర్‌వాల్ మరియు వెబ్ ఫిల్టరింగ్ లేదా ప్రాక్సీ సాఫ్ట్‌వేర్ ఉండవచ్చు.</translation>
<translation id="2212735316055980242">విధానం కనుగొనబడలేదు</translation>
<translation id="2213606439339815911">నమోదులను పొందుతోంది...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />లోని హ్యాకర్‌లు మీ పరికరంలో హానికరమైన యాప్‌లను ఇన్‌స్టాల్ చేయవచ్చు మరియు మీ మొబైల్ బిల్‌లో అదృశ్య ఛార్జీలకు కారణం కావచ్చు లేదా మీ వ్యక్తిగత సమాచారాన్ని దొంగిలించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">వెనుకకు వెళ్ళు</translation>
<translation id="2503184589641749290">ఆమోదించబడిన డెబిట్ మరియు ప్రీపెయిడ్ కార్డ్‌లు</translation>
<translation id="2515629240566999685">మీ ప్రాంతంలో సిగ్నల్‌ను తనిఖీ చేయడం</translation>
+<translation id="2524461107774643265">మరింత సమాచారాన్ని జోడించండి</translation>
+<translation id="2536110899380797252">చిరునామాను జోడించు</translation>
<translation id="2539524384386349900">గుర్తించు</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> చెల్లని ప్రతిస్పందనను పంపింది.</translation>
<translation id="2556876185419854533">&amp;సవరించడాన్ని రద్దు చేయి</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium ప్రస్తుతం మీ కార్డ్‌ను నిర్ధారించలేకపోయింది. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
<translation id="2705137772291741111">ఈ సైట్ యొక్క సేవ్ చేయబడిన (కాష్ చేసిన) కాపీ చదవదగినట్లుగా లేదు.</translation>
<translation id="2709516037105925701">స్వయంపూర్తి</translation>
+<translation id="2710942282213947212">మీ కంప్యూటర్‌లోని సాఫ్ట్‌వేర్ Chromium సురక్షితంగా వెబ్‌కు కనెక్ట్ కాకుండా ఆపుతోంది</translation>
<translation id="2712173769900027643">అనుమతి అడుగు</translation>
-<translation id="2713444072780614174">తెలుపు</translation>
<translation id="2720342946869265578">సమీపం</translation>
<translation id="2721148159707890343">అభ్యర్థన విజయవంతం అయింది</translation>
<translation id="2728127805433021124">సర్వర్ యొక్క ప్రమాణపత్రం ఒక బలహీనమైన సంతకం అల్గారిథమ్ ఉపయోగించి సంతకం చేయబడింది.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">నెట్‌వర్క్ మార్పు గుర్తించబడింది.</translation>
<translation id="2916038427272391327">ఇతర ప్రోగ్రామ్‌లను మూసివేయండి</translation>
<translation id="2922350208395188000">సర్వర్ యొక్క ప్రమాణపత్రం తనిఖీ చెయ్యబడదు.</translation>
+<translation id="2925673989565098301">బట్వాడా పద్ధతి</translation>
<translation id="2928905813689894207">బిల్లింగ్ చిరునామా</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రం <ph name="DOMAIN2" /> నుండి జారీ చేయబడింది. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">చెల్లని విధాన రకం</translation>
<translation id="3032412215588512954">మీరు ఈ సైట్‌ను మళ్లీ లోడ్ చేయాలనుకుంటున్నారా?</translation>
<translation id="3037605927509011580">ఆవ్, స్నాప్!</translation>
+<translation id="3039538478787849737">కార్డ్‌ని Googleకు సేవ్ చేయాలా?</translation>
<translation id="3041612393474885105">సర్టిఫికెట్ సమాచారం</translation>
<translation id="3063697135517575841">Chrome ప్రస్తుతం మీ కార్డ్‌ను నిర్ధారించలేకపోయింది. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
<translation id="3064966200440839136">బాహ్య అనువర్తనం ద్వారా చెల్లించడానికి అజ్ఞాత మోడ్ నుండి నిష్క్రమిస్తోంది. కొనసాగించాలా?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">తాత్కాలిక సర్వర్ లోపం</translation>
<translation id="3154506275960390542">ఈ పేజీలో ఉన్న ఫారమ్‌ని సురక్షితంగా సమర్పించలేకపోవచ్చు. బదిలీ చేయబడే సమయంలో మీరు పంపే డేటాని ఇతరులు వీక్షించవచ్చు లేదా సర్వర్ స్వీకరించే డేటాని మార్చడం కోసం హ్యాకర్‌లు దీనిని సవరించవచ్చు.</translation>
<translation id="3157931365184549694">పునరుద్ధరించు</translation>
+<translation id="3162559335345991374">మీరు ఉపయోగిస్తున్న Wi-Fiకి మీరు దాని లాగిన్ పేజీని సందర్శించడం అవసరం.</translation>
<translation id="3167968892399408617">మీరు అజ్ఞాత ట్యాబ్‌ల్లో వీక్షించిన పేజీలు మీ అన్ని అజ్ఞాత ట్యాబ్‌లను మూసివేసిన అనంతరం మీ బ్రౌజర్ చరిత్ర, కుక్కీ స్టోర్ లేదా శోధన చరిత్రలో ఉంచబడవు. మీరు డౌన్‌లోడ్ చేసే ఏవైనా ఫైల్‌లు లేదా మీరు సృష్టించే ఏవైనా బుక్‌మార్క్‌లు అలాగే ఉంచబడతాయి.</translation>
<translation id="3169472444629675720">కనుగొను</translation>
<translation id="3174168572213147020">దీవి</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">చెల్లింపును రద్దు చేయండి</translation>
<translation id="3207960819495026254">బుక్‌మార్క్ చేయబడింది</translation>
+<translation id="3211223744486044430">తదుపరిసారి వేగంగా చెల్లించాలంటే, ఈ కార్డ్‌ని మీ Google ఖాతాలో మరియు ఈ పరికరంలో సేవ్ చేయండి.</translation>
<translation id="3225919329040284222">అంతర్నిర్మిత అంచనాలకు సరిపోలని ఒక ధృవీకరణ పత్రాన్ని సర్వర్ సమర్పించింది. మిమ్మల్ని సంరక్షించే దిశగా నిర్దిష్ట, ఉన్నత స్ధాయి భద్రతా వెబ్‌సైట్‌ల కోసం ఈ అంచనాలు చేర్చబడ్డాయి.</translation>
<translation id="3226128629678568754">పేజీని లోడ్ చేయడానికి అవసరమైన డేటాను మళ్లీ సమర్పించడం కోసం మళ్లీ లోడ్ చేయి బటన్ క్లిక్ చేయండి.</translation>
<translation id="3227137524299004712">మైక్రోఫోన్</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">శోధన ఫలితాలు ఏవీ కనుగొనబడలేదు</translation>
<translation id="3305707030755673451"><ph name="TIME" />న మీ సమకాలీకరణ రహస్య పదబంధంతో మీ డేటా గుప్తీకరించబడింది. సమకాలీకరణను ప్రారంభించడానికి దీన్ని నమోదు చేయండి.</translation>
<translation id="3320021301628644560">బిల్లింగ్ చిరునామాను జోడించండి</translation>
-<translation id="3329013043687509092">సంతృప్తత</translation>
<translation id="333371639341676808">అదనపు డైలాగ్‌లను సృష్టించకుండా ఈ పేజీని అడ్డుకో</translation>
<translation id="3338095232262050444">సురక్షితం</translation>
<translation id="3340978935015468852">సెట్టింగ్‌లు</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">క్లయింట్ ID:</translation>
<translation id="3391030046425686457">బట్వాడా చిరునామా</translation>
<translation id="3395827396354264108">పికప్ పద్ధతి</translation>
+<translation id="3399952811970034796">బట్వాడా చిరునామా</translation>
<translation id="3422248202833853650">మెమరీని ఖాళీ చేయడానికి ఇతర ప్రోగ్రామ్‌ల నుండి నిష్క్రమించడాన్ని ప్రయత్నించండి.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" />ని ప్రస్తుతం చేరుకోవడం సాధ్యపడదు.</translation>
<translation id="3427092606871434483">అనుమతించు (డిఫాల్ట్)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">క్రాష్ నివేదిక <ph name="CRASH_TIME" />కి సంగ్రహించబడింది, <ph name="UPLOAD_TIME" />కి అప్‌లోడ్ చేయబడింది</translation>
<translation id="3681007416295224113">సర్టిఫికెట్ సమాచారం</translation>
<translation id="3690164694835360974">లాగిన్ సురక్షితం కాదు</translation>
+<translation id="3704162925118123524">మీరు ఉపయోగించే నెట్‌వర్క్‌కి మీరు దాని లాగిన్ పేజీని సందర్శించడం అవసరం కావచ్చు.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">లోడ్ అవుతోంది...</translation>
<translation id="3712624925041724820">లైసెన్స్‌లు అయిపోయాయి</translation>
<translation id="3714780639079136834">మొబైల్ డేటా లేదా Wi-Fiని ఆన్ చేయడం</translation>
+<translation id="3715597595485130451">Wi-Fiకి కనెక్ట్ చేయండి</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ప్రాక్సీ, ఫైర్‌వాల్ మరియు DNS కాన్ఫిగరేషన్‌ను తనిఖీ చేయడం<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">మీ భద్రతకు వాటిల్లే ఆపదల గురించి మీకు అర్థం అయ్యి ఉంటే, ప్రమాదకరమైన ప్రోగ్రామ్‌లు తీసివేయబడటానికి ముందే <ph name="BEGIN_LINK" />ఈ అసురక్షితమైన సైట్‌ను సందర్శించవచ్చు<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">మీరు కాపీ చేసిన లింక్</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;జోడించడాన్ని రద్దు చేయి</translation>
<translation id="404928562651467259">హెచ్చరిక</translation>
<translation id="4058922952496707368">కీ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">చెల్లుబాటు అయ్యే చిరునామాను జోడించండి</translation>
<translation id="4072486802667267160">మీ ఆర్డర్‌ను ప్రాసెస్ చేస్తున్నప్పుడు లోపం ఏర్పడింది. దయచేసి మళ్లీ ప్రయత్నించండి.</translation>
<translation id="4075732493274867456">క్లయింట్ మరియు సర్వర్ ఒకే SSL ప్రోటోకాల్ సంస్కరణ లేదా సైఫర్ సూట్‌కు మద్దతివ్వవు.</translation>
<translation id="4079302484614802869">ప్రాక్సీ కాన్ఫిగరేషన్ స్థిరమైన ప్రాక్సీ సర్వర్‌లను కాకుండా, ఒక .pac స్క్రిప్ట్ URLను ఉపయోగించడానికి సెట్ చేయబడింది.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">పరికరం క్రమ సంఖ్య చెల్లదు</translation>
<translation id="410351446219883937">స్వీయ ప్లే</translation>
<translation id="4103763322291513355">నిరోధిత జాబితాలో ఉన్న URLల జాబితాను మరియు మీ సిస్టమ్ నిర్వాహకుని ద్వారా అమలు చేయబడిన ఇతర విధానాలను చూడటానికి &lt;strong&gt;chrome://policy&lt;/strong&gt;ని సందర్శించండి.</translation>
-<translation id="4115378294792113321">మెజెంటా</translation>
<translation id="4116663294526079822">ఈ సైట్‌లో ఎల్లప్పుడూ అనుమతించు</translation>
<translation id="4117700440116928470">విధానం పరిధికి మద్దతు లేదు.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{మరో 1}other{మరో #}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" />ను చేరుకోవడానికి మీరు ప్రయత్నించారు, కానీ సర్వర్ అందించిన ప్రమాణపత్రాన్ని దాన్ని జారీ చేసినవారు రద్దు చేసారు. సర్వర్ అందించిన భద్రత ఆధారాలు ఖచ్చితంగా విశ్వసించబడలేదని దీని అర్థం. మీరు దాడి చేసే వారితో కమ్యూనికేట్ చేస్తూ ఉండవచ్చు.</translation>
<translation id="4394049700291259645">ఆపివెయ్యి</translation>
<translation id="4406896451731180161">శోధన ఫలితాలు</translation>
+<translation id="4415426530740016218">పికప్ చిరునామా</translation>
<translation id="4424024547088906515">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రాన్ని Chrome విశ్వసించలేదు. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> మీ లాగిన్ ప్రమాణపత్రాన్ని ఆమోదించలేదు లేదా ఏదీ అందించి ఉండకపోవచ్చు.</translation>
<translation id="443673843213245140">ప్రాక్సీని ఉపయోగించడం ఆపివేయబడింది కానీ స్పష్టమైన ప్రాక్సీ కాన్ఫిగరేషన్ పేర్కొనబడింది.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">ఫ్లాష్</translation>
<translation id="4558551763791394412">మీ పొడిగింపులను నిలిపివేయడం ప్రయత్నించండి.</translation>
<translation id="457875822857220463">బట్వాడా</translation>
+<translation id="4582800630050655161">మీరు మీ Google ఖాతాకు ప్రాప్యతను కోల్పోవచ్చు లేదా గుర్తింపు సమాచారం చౌర్యం కావచ్చు. Chromium వెంటనే మీ పాస్‌వర్డ్‌ను మార్చుకోవాల్సిందిగా సిఫార్సు చేస్తోంది.</translation>
<translation id="4587425331216688090">Chrome నుండి చిరునామాను తీసివేయాలా?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" />కి గల మీ కనెక్షన్ ఆధునిక సైఫర్ సూట్ ఉపయోగించి గుప్తీకరించబడింది.</translation>
<translation id="4594403342090139922">&amp;తొలగించడాన్ని రద్దు చేయి</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రంలో లోపాలు ఉన్నాయి. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
<translation id="4690462567478992370">చెల్లని ప్రమాణపత్రాన్ని ఉపయోగించడాన్ని ఆపివేయి</translation>
+<translation id="4690954380545377795">మీరు మీ Google ఖాతాకు ప్రాప్యతను కోల్పోవచ్చు లేదా గుర్తింపు సమాచారం చౌర్యం కావచ్చు. Chrome వెంటనే మీ పాస్‌వర్డ్‌ను మార్చుకోవాల్సిందిగా సిఫార్సు చేస్తోంది.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">మీ కనెక్షన్‌కు అంతరాయం ఏర్పడింది</translation>
<translation id="471880041731876836">ఈ సైట్‌ను సందర్శించడానికి మీకు అనుమతి లేదు</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows నెట్‌వర్క్ సమస్య విశ్లేషణలను అమలు చేయడం<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">మీ చెల్లింపు</translation>
<translation id="4726672564094551039">విధానాలను మళ్లీ లోడ్ చేయి</translation>
<translation id="4728558894243024398">ప్లాట్‌ఫారమ్</translation>
<translation id="4736825316280949806">Chromiumని పునఃప్రారంభించండి</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">బ్యాకింగ్ నిల్వ చెల్లని స్థితిలో ఉంది</translation>
<translation id="5023310440958281426">మీ నిర్వాహకుని విధానాలను చూడండి</translation>
<translation id="5029568752722684782">కాపీని తీసివేయి</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" యొక్క రూట్ సర్టిఫికేట్ అవసరం, కానీ అది ఇన్‌స్టాల్ చేయబడలేదు. ఈ సమస్యను పరిష్కరించాలంటే, మీ IT నిర్వాహకులు "<ph name="SOFTWARE_NAME" />" యొక్క కాన్ఫిగరేషన్ సూచనలను పరిశీలించాలి. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google అనువాదం గురించి</translation>
<translation id="5039804452771397117">అనుమతించు</translation>
<translation id="5040262127954254034">గోప్యత</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">ప్రయోగాలు</translation>
<translation id="5205222826937269299">పేరు ఆవశ్యకం</translation>
<translation id="5222812217790122047">ఇమెయిల్ ఆవశ్యకం</translation>
+<translation id="522700295135997067">ఈ సైట్ ఇప్పుడే మీ పాస్‌వర్డ్‌ను దొంగిలించి ఉండటానికి ఆస్కారం ఉంది</translation>
+<translation id="5230733896359313003">బట్వాడా చిరునామా</translation>
<translation id="5251803541071282808">క్లౌడ్</translation>
<translation id="5277279256032773186">కార్యాలయంలో Chrome ఉపయోగిస్తున్నారా? వ్యాపార సంస్థలు తమ ఉద్యోగుల కోసం Chrome సెట్టింగ్‌లను నిర్వహించగలవు. మరింత తెలుసుకోండి</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />సాఫ్ట్‌వేర్‌ను తాత్కాలికంగా నిలిపివేయడానికి ఈ దశలను పాటించండి తద్వారా మీరు వెబ్‌ను ప్రాప్యత చేయవచ్చు. మీకు నిర్వాహక అధికారాలు అవసరం.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">ఈ సైట్‌కు మీ కనెక్షన్ ప్రైవేట్ కాదు. ఎప్పుడైనా VR మోడ్ నుండి నిష్క్రమించడానికి, హెడ్‌సెట్‌ను తీసివేసి, వెనుకకు నొక్కండి.</translation>
<translation id="5299298092464848405">విధానాన్ని అన్వయించడంలో లోపం</translation>
+<translation id="5308380583665731573">కనెక్ట్ చేయండి</translation>
<translation id="5308689395849655368">క్రాష్ నివేదిక నిలిపివెయ్యబడింది.</translation>
<translation id="5317780077021120954">సేవ్ చేయి</translation>
<translation id="5327248766486351172">పేరు</translation>
+<translation id="5332219387342487447">షిప్పింగ్ పద్ధతి</translation>
<translation id="5355557959165512791"><ph name="SITE" /> యొక్క ప్రమాణపత్రం రద్దు చేయబడినందున మీరు ప్రస్తుతం దీన్ని సందర్శించలేరు. నెట్‌వర్క్ లోపాలు మరియు దాడులు సాధారణంగా తాత్కాలికమే, కనుక ఈ పేజీ తర్వాత పని చేయవచ్చు.</translation>
<translation id="536296301121032821">విధాన సెట్టింగ్‌లను నిల్వ చేయడంలో విఫలమైంది</translation>
<translation id="5386426401304769735">ఈ సైట్ ప్రమాణపత్రం గొలుసులో SHA-1 ఉపయోగించి సంతకం చేసిన ప్రమాణపత్రం ఉంది.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">కంపెనీ, సంస్థ లేదా పాఠశాల ఇంట్రానెట్‌లోని ఈ సైట్ బాహ్య వెబ్‌సైట్ కలిగి ఉన్న అదే URLని కలిగి ఉంది.
<ph name="LINE_BREAK" />
మీ సిస్టమ్ నిర్వాహకుడిని సంప్రదించడానికి ప్రయత్నించండి.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> యొక్క భద్రతా కోడ్‌ని నమోదు చేయండి. ఈ కోడ్ సేవ్ చేయబడదు.</translation>
<translation id="5509780412636533143">నిర్వహించబడిన బుక్‌మార్క్‌లు</translation>
<translation id="5510766032865166053">ఇది తరలించబడి ఉండవచ్చు లేదా తొలగించబడి ఉండవచ్చు.</translation>
<translation id="5523118979700054094">విధానం పేరు</translation>
<translation id="552553974213252141">వచనం సరిగ్గా సంగ్రహించబడిందా?</translation>
<translation id="5540224163453853">అభ్యర్థించిన కథనాన్ని కనుగొనడం సాధ్యపడలేదు.</translation>
+<translation id="5541546772353173584">ఇమెయిల్‌ను జోడించండి</translation>
<translation id="5544037170328430102"><ph name="SITE" />లో పొందుపరిచిన పేజీ ఇలా చెబుతోంది:</translation>
+<translation id="5545756402275714221">మీ కోసం కథనాలు</translation>
<translation id="5556459405103347317">రీలోడ్</translation>
<translation id="5560088892362098740">గడువు ముగింపు తేదీ</translation>
<translation id="5565735124758917034">సక్రియం</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">ఇమెయిల్</translation>
<translation id="5669703222995421982">వ్యక్తిగతీకరించిన కంటెంట్‌ను పొందండి</translation>
<translation id="5675650730144413517">ఈ పేజీ పని చేయడం లేదు</translation>
+<translation id="5689199277474810259">JSONకు ఎగుమతి చేయి</translation>
<translation id="5710435578057952990">ఈ వెబ్‍‌సైట్ యొక్క గుర్తింపు నిర్థారించబడలేదు.</translation>
<translation id="5719499550583120431">ప్రీపెయిడ్ కార్డ్‌లు ఆమోదించబడతాయి.</translation>
<translation id="5720705177508910913">ప్రస్తుత వినియోగదారు</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" />కి గల మీ కనెక్షన్ వాడుకలో లేని సైఫర్ సూట్ ఉపయోగించి గుప్తీకరించబడింది.</translation>
<translation id="5813119285467412249">&amp;జోడించడాన్ని పునరావృతం చేయి</translation>
<translation id="5838278095973806738">మీరు ఈ సైట్‌లో ఎలాంటి గోప్యమైన సమాచారాన్ని నమోదు చేయకూడదు (ఉదాహరణకు, పాస్‌వర్డ్‌లు లేదా క్రెడిట్ కార్డ్‌లు), దాడికి పాల్పడేవారు ఆ సమాచారం దొంగిలించే అవకాశం ఉంటుంది.</translation>
+<translation id="5866257070973731571">ఫోన్ నంబర్‌ను జోడించండి</translation>
<translation id="5869405914158311789">ఈ సైట్‌ను చేరుకోలేకపోయాము</translation>
<translation id="5869522115854928033">సేవ్ చేసిన పాస్‌వర్డ్‌లు</translation>
<translation id="5872918882028971132">తల్లి/తండ్రి సూచనలు</translation>
<translation id="5893752035575986141">క్రెడిట్ కార్డ్‌లు ఆమోదించబడతాయి.</translation>
-<translation id="5901630391730855834">పసుపు</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (సమకాలీకరించబడింది)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 వినియోగంలో ఉంది}other{# వినియోగంలో ఉన్నాయి}}</translation>
<translation id="5959728338436674663">హానికరమైన అనువర్తనాలు మరియు సైట్‌లను గుర్తించడంలో సహాయపడటానికి కొంత <ph name="BEGIN_WHITEPAPER_LINK" />సిస్టమ్ సమాచారాన్ని మరియు పేజీ కంటెంట్<ph name="END_WHITEPAPER_LINK" />ను Googleకు స్వయంచాలకంగా పంపుతుంది. <ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">సంప్రదింపు సమాచారాన్ని సవరించండి</translation>
<translation id="5967867314010545767">చరిత్ర నుండి తీసివేయి</translation>
<translation id="5975083100439434680">దూరంగా జూమ్ చెయ్యి</translation>
+<translation id="597552863672748783">భద్రతా కోడ్‌ని నిర్ధారించండి</translation>
<translation id="598637245381783098">చెల్లింపు ఆప్‌ని తెరవడం సాధ్యం కాదు</translation>
<translation id="5989320800837274978">స్థిర ప్రాక్సీ సర్వర్‌లు లేదా ఒక .pac స్క్రిప్ట్ URL పేర్కొనబడలేదు.</translation>
<translation id="5990559369517809815">సర్వర్‌కు అభ్యర్థనలను ఒక పొడిగింపు బ్లాక్ చేయబడ్డాయి.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{పేజీ 1}other{పేజీ #}}</translation>
-<translation id="6017514345406065928">ఆకుపచ్చ</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (సమకాలీకరించబడ్డాయి)</translation>
<translation id="6027201098523975773">పేరుని నమోదు చేయండి</translation>
<translation id="6040143037577758943">మూసివేయి</translation>
-<translation id="6042308850641462728">మరింత</translation>
<translation id="6047233362582046994">మీ భద్రతకు వాటిల్లే ఆపదల గురించి మీకు అర్థం అయ్యి ఉంటే, హానికర యాప్‌లు తీసివేయబడటానికి ముందే మీరు <ph name="BEGIN_LINK" />ఈ సైట్‌ను సందర్శించవచ్చు<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">ఈ కంటెంట్ సాఫ్ట్‌వేర్‌ని ఇన్‌స్టాల్ చేయడానికి లేదా వ్యక్తిగత సమాచారాన్ని బహిర్గతం చేయడానికి పురిగొల్పేలా మిమ్మల్ని మాయ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LINK" />ఏదేమైనా చూపు<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ప్రమాణపత్రాన్ని పిన్ చేసే పద్ధతిని వెబ్‌సైట్ ఉపయోగిస్తుంది కనుక మీరు ప్రస్తుతానికి <ph name="SITE" />ని సందర్శించలేరు. నెట్‌వర్క్ లోపాలు మరియు దాడులు సాధారణంగా తాత్కాలికమే, కనుక ఈ పేజీ తర్వాత పని చేయవచ్చు.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">మీరు పొడిగింపు పేజీని వీక్షిస్తున్నారు</translation>
<translation id="6596325263575161958">గుప్తీకరణ ఎంపికలు</translation>
<translation id="662080504995468778">ఇందులోనే ఉంచు</translation>
+<translation id="6624427990725312378">సంప్రదింపు సమాచారం</translation>
<translation id="6626291197371920147">చెల్లుబాటయ్యే కార్డ్ నంబర్‌ను జోడించండి</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> శోధన</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ Macలో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">మునుపటి</translation>
<translation id="6710594484020273272">&lt;శోధన పదాన్ని టైప్ చేయండి&gt;</translation>
<translation id="6711464428925977395">ప్రాక్సీ సర్వర్‌లో ఏదో తప్పు ఉంది లేదా చిరునామా సరైనది కాదు.</translation>
-<translation id="6727102863431372879">సెట్ చెయ్యి</translation>
<translation id="674375294223700098">తెలియని సర్వర్ ప్రమాణపత్రం లోపం.</translation>
<translation id="6753269504797312559">విధానం విలువ</translation>
<translation id="6757797048963528358">మీ పరికరం నిద్రావస్థకి వెళ్లింది.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">ప్రొఫైల్ మార్గం</translation>
<translation id="7424977062513257142">ఈ వెబ్‌పేజీలోని పొందుపరిచిన పేజీ ఇలా చెబుతోంది:</translation>
+<translation id="7437289804838430631">సంప్రదింపు సమాచారాన్ని జోడించు</translation>
<translation id="7441627299479586546">చెల్లని విధాన విషయం</translation>
<translation id="7444046173054089907">ఈ సైట్ బ్లాక్ చేయబడింది</translation>
<translation id="7445762425076701745">మీరు కనెక్ట్ చేసిన సర్వర్ యొక్క గుర్తింపు పూర్తిగా ధృవీకరించబడలేదు. మీరు దీని యొక్క యాజమాన్యాన్ని ధృవీకరించడానికి అంతర్గత ప్రమాణపత్రం అధికారికి మరొక దాని లేని మీ నెట్‌వర్క్‌లో మాత్రమే చెల్లుబాటు అయ్యే పేరును ఉపయోగించి సర్వర్‌కి కనెక్ట్ చేసారు. కొన్ని ప్రమాణపత్రం అధికారులు సంబంధంలేని ఈ పేర్లకు ప్రమాణపత్రాన్ని జారీ చేస్తారు, మీరు సరైన వెబ్‌సైట్‌కి మరియు అటాకర్‌కి కనెక్ట్ చేసారా అని నిర్ధారించడానికి వేరే మార్గం లేదు.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">ఫార్వార్డ్</translation>
<translation id="7485870689360869515">డేటా కనుగొనబడలేదు.</translation>
<translation id="7508255263130623398">అందించబడిన విధాన పరికర id ఖాళీగా ఉంది లేదా ప్రస్తుత పరికర idకి సరిపోలలేదు</translation>
+<translation id="7511955381719512146">మీరు ఉపయోగిస్తున్న Wi-Fiకి మీరు <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ని సందర్శించడం అవసరం.</translation>
<translation id="7514365320538308">డౌన్‌లోడ్ చేయి</translation>
<translation id="7518003948725431193">వెబ్ చిరునామాకు వెబ్‌పేజీ కనుగొనబడలేదు: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">ఈ సైట్‌కి మీ కనెక్షన్ ప్రైవేట్ కాదు</translation>
-<translation id="7535087603100972091">విలువ</translation>
<translation id="7537536606612762813">తప్పనిసరి</translation>
<translation id="7542403920425041731">మీరు నిర్ధారించిన తర్వాత, మీ కార్డ్ వివరాలు ఈ సైట్‌తో షేర్ చేయబడతాయి.</translation>
<translation id="7542995811387359312">ఈ ఫారమ్ సురక్షిత కనెక్షన్‌ని ఉపయోగించనందున స్వయంచాలకంగా క్రెడిట్ కార్డ్ పూర్తి చెయ్యడం ఆపివేయబడింది.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రం మోసపూరితంగా జారీ అయ్యి ఉండవచ్చు. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
<translation id="7568593326407688803">ఈ పేజీ<ph name="ORIGINAL_LANGUAGE" />లో ఉంది మీరు దీన్ని అనువదించాలనుకుంటున్నారా?</translation>
<translation id="7569952961197462199">Chrome నుండి క్రెడిట్ కార్డ్‌ను తీసివేయాలా?</translation>
-<translation id="7569983096843329377">నలుపు</translation>
<translation id="7578104083680115302">మీరు Googleతో సేవ్ చేసిన కార్డ్‌లను ఉపయోగించి పరికరాల్లోని సైట్‌లు మరియు అనువర్తనాల్లో శీఘ్రంగా చెల్లించండి.</translation>
<translation id="7588950540487816470">భౌతిక వెబ్</translation>
<translation id="7592362899630581445">సర్వర్ యొక్క ప్రమాణపత్రం పేరు పరిమితులను ఉల్లంఘిస్తోంది.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">ఈ సైట్‌లోని దాడి చేసేవారు మీ బ్రౌజింగ్ అనుభవానికి (ఉదాహరణకు, మీ హోమ్ పేజీని మార్చడం లేదా మీరు సందర్శించే సైట్‌ల్లో అదనపు ప్రకటనలను చూపడం ద్వారా) హాని కలిగించే ప్రోగ్రామ్‌లను ఇన్‌స్టాల్ చేసే విధంగా మిమ్మల్ని మోసగించడానికి ప్రయత్నించవచ్చు.</translation>
<translation id="7674629440242451245">అద్భుతమైన క్రొత్త Chrome లక్షణాల పట్ల ఆసక్తిగా ఉన్నారా? chrome.com/devలో మా డెవలపర్ ఛానెల్‌ను ప్రయత్నించండి.</translation>
<translation id="7682287625158474539">ఓడ రవాణా</translation>
+<translation id="7699293099605015246">ప్రస్తుతం కథనాలు అందుబాటులో లేవు</translation>
<translation id="7701040980221191251">ఏదీ కాదు</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" />కి కొనసాగించండి (అసురక్షితం)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">సర్టిఫికెట్</translation>
<translation id="7716147886133743102">మీ నిర్వాహకుల ద్వారా బ్లాక్ చేయబడింది</translation>
<translation id="7716424297397655342">కాష్ నుండి ఈ సైట్‌ను లోడ్ చేయలేకపోయాము</translation>
+<translation id="7723047071702270851">కార్డ్‌ను సవరించండి</translation>
<translation id="774634243536837715">హానికరమైన కంటెంట్ బ్లాక్ చేయబడింది.</translation>
<translation id="7752995774971033316">నిర్వహించడం లేదు</translation>
<translation id="7755287808199759310">మీ తల్లి/తండ్రి దీన్ని మీ కోసం అన్‌బ్లాక్ చేయగలరు</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">చిరునామాను జోడించు</translation>
<translation id="777702478322588152">అధికారిక నివాసం</translation>
<translation id="7791543448312431591">జోడించు</translation>
+<translation id="7793553086574152071">తదుపరిసారి వేగంగా చెల్లించాలంటే, ఈ కార్డ్‌ని మీ Google ఖాతాలో సేవ్ చేయండి.</translation>
<translation id="7793809570500803535"><ph name="SITE" />లోని వెబ్‌పేజీ తాత్కాలికంగా పని చేయకపోవచ్చు లేదా ఇది క్రొత్త వెబ్ చిరునామాకు శాశ్వతంగా తరలించబడి ఉండవచ్చు.</translation>
<translation id="7800304661137206267"><ph name="KX" />ని కీ మార్పిడి విధానం వలె మరియు సందేశ ప్రామాణీకరణ కోసం <ph name="CIPHER" />ని <ph name="MAC" />తో ఉపయోగించడం ద్వారా కనెక్షన్ గుప్తీకరించబడింది.</translation>
+<translation id="7802523362929240268">సైట్ చట్టబద్ధమైనది</translation>
<translation id="780301667611848630">వద్దు , ధన్యవాదాలు</translation>
<translation id="7805768142964895445">స్థితి</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Chrome నుండి ఫారమ్ సూచనను తీసివేయాలా?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' కోసం <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> కనుగొనబడ్డాయి</translation>
+<translation id="782886543891417279">మీరు ఉపయోగిస్తున్న Wi-Fi (<ph name="WIFI_NAME" />)కి మీరు దాని లాగిన్ పేజీని సందర్శించడం అవసరం.</translation>
<translation id="785549533363645510">అయితే, మీరు అదృశ్యంగా ఉండరు. అజ్ఞాతంలోకి వెళ్లడం వలన మీ బ్రౌజింగ్ మీ యజమానికి, మీ ఇంటర్నెట్ సేవా ప్రదాతకు లేదా మీరు సందర్శించే వెబ్‌సైట్‌లకు కనిపించకుండా దాచబడదు.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">డెబిట్ మరియు ప్రీపెయిడ్ కార్డ్‌లు ఆమోదించబడతాయి.</translation>
+<translation id="7878562273885520351">మీ పాస్‌వర్డ్ ఎవరికైనా తెలిసిపోయి ఉండవచ్చు</translation>
<translation id="7887683347370398519">మీ CVCని తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి</translation>
<translation id="79338296614623784">చెల్లుబాటు అయ్యే ఫోన్ నంబర్‌ని నమోదు చేయండి</translation>
<translation id="7935318582918952113">DOM డిస్టిల్లర్</translation>
<translation id="7938958445268990899">సర్వర్ ప్రమాణపత్రం ఇంకా చెల్లుబాటు కాదు.</translation>
-<translation id="7942349550061667556">ఎరుపు</translation>
<translation id="7947285636476623132">మీ గడువు ముగింపు సంవత్సరాన్ని తనిఖీ చేసి, ఆపై మళ్లీ ప్రయత్నించండి</translation>
<translation id="7951415247503192394">(32-బిట్)</translation>
<translation id="7956713633345437162">మొబైల్ బుక్‌మార్క్‌లు</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">అడగాలి (డిఫాల్ట్)</translation>
<translation id="8041089156583427627">ప్రతిస్పందనను పంపండి</translation>
<translation id="8041940743680923270">సార్వజనీన డిఫాల్ట్‌ను ఉపయోగించు (అడుగు)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />"ని సరిగ్గా కాన్ఫిగర్ చేయలేదు. సాధారణంగా "<ph name="SOFTWARE_NAME" />"ని అన్ఇన్‌స్టాల్ చేయడం ద్వారా సమస్య పరిష్కారం కావచ్చు. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">కథనాన్ని వీక్షించడంలో విఫలమైంది.</translation>
<translation id="8091372947890762290">సక్రియం సర్వర్‌లో పెండింగ్‌లో ఉంది</translation>
+<translation id="8094917007353911263">మీరు ఉపయోగిస్తున్న నెట్‌వర్క్‌కి మీరు <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ని సందర్శించడం అవసరం.</translation>
+<translation id="8103161714697287722">చెల్లింపు పద్ధతి</translation>
<translation id="8118489163946903409">చెల్లింపు పద్ధతి</translation>
+<translation id="8127301229239896662">మీ కంప్యూటర్ లేదా నెట్‌వర్క్‌లో "<ph name="SOFTWARE_NAME" />" సరిగ్గా ఇన్‌స్టాల్ కాలేదు. ఈ సమస్యను పరిష్కరించమని మీ IT నిర్వాహకులను కోరండి.</translation>
<translation id="8131740175452115882">నిర్ధారించు</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> సర్వర్ <ph name="BEGIN_ABBR" />DNS చిరునామా<ph name="END_ABBR" />ను కనుగొనడం సాధ్యపడలేదు.</translation>
<translation id="8149426793427495338">మీ కంప్యూటర్ నిద్రావస్థకి వెళ్లింది.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">మీకు దీని గురించి ఖచ్చితంగా తెలియకుంటే మీ నెట్‌వర్క్ నిర్వాహకుని సంప్రదించండి.</translation>
<translation id="8293206222192510085">బుక్‌మార్క్‌లను జోడించు</translation>
<translation id="8294431847097064396">మూలం</translation>
+<translation id="8298115750975731693">మీరు ఉపయోగిస్తున్న Wi-Fi (<ph name="WIFI_NAME" />)కి మీరు <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ని సందర్శించడం అవసరం.</translation>
<translation id="8306404619377842860">మీ పరికరం యొక్క తేదీ మరియు సమయం (<ph name="DATE_AND_TIME" />) తప్పుగా ఉన్న కారణంగా <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />కు ప్రైవేట్ కనెక్షన్‌ని ఏర్పాటు చేయడం సాధ్యం కాదు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">నెట్‌వర్క్ కనెక్షన్‌తో సమస్య ఉన్నందున అనువాదం విఫలమైంది.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />కి ప్రాప్యత నిరాకరించబడింది</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">ఇటీవల మూసివేసినవి</translation>
<translation id="8874824191258364635">చెల్లుబాటు అయ్యే కార్డ్ నంబర్‌ను నమోదు చేయండి</translation>
<translation id="8876793034577346603">నెట్‌వర్క్ కాన్ఫిగరేషన్ అన్వయించబడటంలో విఫలమైంది.</translation>
-<translation id="8889402386540077796">వర్ణం</translation>
<translation id="8891727572606052622">చెల్లని ప్రాక్సీ మోడ్.</translation>
<translation id="889901481107108152">క్షమించండి, ఈ ప్రయోగం మీ ప్లాట్‌ఫారమ్‌లో అందుబాటులో లేదు.</translation>
<translation id="8903921497873541725">దగ్గరికి జూమ్ చెయ్యి</translation>
<translation id="8931333241327730545">మీరు ఈ కార్డ్‌ను మీ Google ఖాతాకి సేవ్ చేయాలనుకుంటున్నారా?</translation>
<translation id="8932102934695377596">మీ గడియారం సమయం గతంలో ఉంది</translation>
+<translation id="893332455753468063">పేరుని జోడించండి</translation>
<translation id="8938939909778640821">ఆమోదించబడిన క్రెడిట్ మరియు ప్రీపెయిడ్ కార్డ్‌లు</translation>
+<translation id="8957210676456822347">క్యాప్టివ్ పోర్టల్ ప్రామాణీకరణ</translation>
<translation id="8971063699422889582">సర్వర్ యొక్క ప్రమాణపత్రం గడువు ముగిసింది.</translation>
-<translation id="8986494364107987395">Googleకు స్వయంచాలకంగా ఉపయోగ గణాంకాలను మరియు క్రాష్ నివేదికలను పంపు</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">ఈ సైట్ హానికర ప్రోగ్రామ్‌లను కలిగి ఉంది</translation>
<translation id="8997023839087525404">సర్వర్ ప్రమాణపత్ర పారదర్శకత విధానాన్ని ఉపయోగించి పబ్లిక్‌గా బహిరంగపరచబడని ప్రమాణపత్రాన్ని అందించింది. కొన్ని ప్రమాణపత్రాలకు, అవి విశ్వసనీయమైనవని మరియు దాడి చేసేవారి నుండి రక్షణ కల్పించగలవని నిర్ధారించడానికి, ఇది ఆవశ్యకం.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> ప్రాక్సీకి వినియోగదారు పేరు మరియు పాస్‌వర్డ్ అవసరం.</translation>
<translation id="9005998258318286617">PDF పత్రాన్ని లోడ్ చేయడం విఫలమైంది.</translation>
+<translation id="9008201768610948239">విస్మరించు</translation>
<translation id="901974403500617787">సిస్టమ్ వ్యాప్తంగా వర్తింపజేయబడే ఫ్లాగ్‌లు యజమాని ద్వారా మాత్రమే సెట్ చేయబడతాయి: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">కార్డ్ బిల్లింగ్ చిరునామా అవసరం</translation>
<translation id="9020542370529661692">ఈ పేజీ <ph name="TARGET_LANGUAGE" />కి అనువదించబడింది</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">మీరు <ph name="DOMAIN" />ని చేరుకోవడానికి ప్రయత్నించారు, కానీ సర్వర్ ఒక చెల్లుబాటులో లేని ప్రమాణపత్రంని అందించింది.</translation>
<translation id="9050666287014529139">పాస్‌ఫ్రేజ్</translation>
<translation id="9065203028668620118">సవరించు</translation>
-<translation id="9068849894565669697">రంగుని ఎంచుకోండి</translation>
<translation id="9069693763241529744">పొడిగింపు ద్వారా బ్లాక్ చేయబడింది</translation>
<translation id="9076283476770535406">ఇందులో పెద్దలకు మాత్రమే అనుమతించిన కంటెంట్ ఉండవచ్చు</translation>
<translation id="9078964945751709336">మరింత సమాచారం ఆవశ్యకం</translation>
+<translation id="9080712759204168376">ఆర్డర్ సారాంశం</translation>
<translation id="9103872766612412690"><ph name="SITE" /> సాధారణంగా మీ సమాచారాన్ని రక్షించడానికి గుప్తీకరణను ఉపయోగిస్తుంది. Chromium ఈసారి <ph name="SITE" />కి కనెక్ట్ చేయడానికి ప్రయత్నించినప్పుడు, వెబ్‌సైట్ అసాధారణ మరియు తప్పు ఆధారాలు అని ప్రతిస్పందించింది. దాడి చేసే వ్యక్తి <ph name="SITE" />గా వ్యవహరించి మోసగించడానికి ప్రయత్నిస్తున్నప్పుడు లేదా Wi-Fi సైన్-ఇన్ స్క్రీన్ కనెక్షన్‌కు అంతరాయం కలిగించినప్పుడు ఇలా జరగవచ్చు. Chromium ఎలాంటి డేటా వినిమయం సంభవించక ముందే కనెక్షన్‌ను ఆపివేసినందున మీ సమాచారం ఇప్పటికీ సురక్షితంగానే ఉంది.</translation>
+<translation id="9106062320799175032">బిల్లింగ్ చిరునామాను జోడించండి</translation>
+<translation id="910908805481542201">దీనిని పరిష్కరించడంలో నాకు సహాయం అందించండి</translation>
+<translation id="9128870381267983090">నెట్‌వర్క్‌కి కనెక్ట్ చెయ్యి</translation>
<translation id="9137013805542155359">అసలును చూపించు</translation>
<translation id="9137248913990643158">దయచేసి ఈ అనువర్తనాన్ని ఉపయోగించే ముందు Chromeని ప్రారంభించి, దానికి సైన్ ఇన్ చేయండి.</translation>
<translation id="9148507642005240123">&amp;సవరించడాన్ని రద్దు చేయి</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> మద్దతు లేని ప్రోటోకాల్‌ను ఉపయోగిస్తోంది.</translation>
<translation id="9205078245616868884">మీ సమకాలీకరణ రహస్య పదబంధంతో మీ డేటా గుప్తీకరించబడింది. సమకాలీకరణను ప్రారంభించడానికి దీన్ని నమోదు చేయండి.</translation>
<translation id="9207861905230894330">కథనాన్ని జోడించడంలో విఫలమైంది.</translation>
+<translation id="9215416866750762878">ఒక అప్లికేషన్ కారణంగా Chrome ఈ సైట్‌కు సురక్షితంగా కనెక్ట్ కాలేకపోతోంది</translation>
<translation id="9219103736887031265">చిత్రాలు</translation>
<translation id="933612690413056017">ఇంటర్నెట్ కనెక్షన్ లేదు</translation>
<translation id="933712198907837967">డైనర్స్ క్లబ్</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{ఏమీ లేవు}=1{1 అంశం}other{# అంశాలు}}</translation>
<translation id="981121421437150478">ఆఫ్‌లైన్</translation>
<translation id="988159990683914416">డెవలపర్ బిల్డ్</translation>
+<translation id="989988560359834682">చిరునామాను సవరించు</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">మీ కంప్యూటర్ లేదా నెట్‌వర్క్‌లో "<ph name="SOFTWARE_NAME" />" సరిగ్గా ఇన్‌స్టాల్ కాలేదు:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />"ని అన్ఇన్‌స్టాల్ చేయడానికి లేదా నిలిపివేయడానికి ప్రయత్నించండి&lt;/li&gt;
+ &lt;li&gt;మరో నెట్‌వర్క్‌కు కనెక్ట్ చేయడానికి ప్రయత్నించండి&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index 8368e45d3a1..10a7a6875b0 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">บุ๊กมาร์กบนเดสก์ท็อป</translation>
<translation id="1074497978438210769">ไม่ปลอดภัย</translation>
<translation id="1080116354587839789">พอดีกับความกว้าง</translation>
+<translation id="1088860948719068836">เพิ่มชื่อบนบัตร</translation>
<translation id="1103523840287552314">แปลภาษา<ph name="LANGUAGE" />ทุกครั้ง</translation>
+<translation id="1103778128462718200">แสดงรหัสผ่านที่บันทึกไว้ทั้งหมด...</translation>
<translation id="1107591249535594099">หากเลือก Chrome จะจัดเก็บสำเนาของบัตรบนอุปกรณ์นี้เพื่อการกรอกข้อมูลแบบฟอร์มอย่างรวดเร็ว</translation>
<translation id="1111153019813902504">บุ๊กมาร์กที่เพิ่งดู</translation>
<translation id="1113869188872983271">&amp;เลิกทำการจัดลำดับใหม่</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" /> <ph name="TYPE_2" /> (ซิงค์แล้ว)</translation>
<translation id="1263231323834454256">เรื่องรออ่าน</translation>
<translation id="1264126396475825575">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> (ยังไม่ได้อัปโหลดหรือละเว้น)</translation>
+<translation id="1270502636509132238">วิธีการรับสินค้า</translation>
<translation id="1281526147609854549">ออกโดย <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">ไม่ต้องแปลไซต์นี้</translation>
<translation id="129553762522093515">เพิ่งปิด</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">กำลังรอการเชื่อมต่อ…</translation>
<translation id="153384715582417236">เสร็จเรียบร้อย</translation>
<translation id="1549470594296187301">ต้องเปิดใช้ JavaScript เพื่อใช้ฟีเจอร์นี้</translation>
-<translation id="1555130319947370107">สีน้ำเงิน</translation>
<translation id="1559528461873125649">ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว</translation>
<translation id="1583429793053364125">มีสิ่งผิดปกติเกิดขึ้นในขณะที่แสดงหน้าเว็บนี้</translation>
<translation id="1592005682883173041">การเข้าถึงข้อมูลในเครื่อง</translation>
<translation id="1594030484168838125">เลือก</translation>
-<translation id="161042844686301425">สีฟ้า</translation>
<translation id="1620510694547887537">กล้องถ่ายรูป</translation>
<translation id="1629803312968146339">คุณต้องการให้ Chrome บันทึกบัตรนี้ไหม</translation>
<translation id="1639239467298939599">กำลังโหลด</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ระบบปฏิบัติการ</translation>
<translation id="1721312023322545264">คุณต้องได้รับสิทธิ์จาก <ph name="NAME" /> เพื่อเข้าชมเว็บไซต์นี้</translation>
<translation id="1721424275792716183">* ช่องที่ต้องกรอก</translation>
+<translation id="1727741090716970331">เพิ่มหมายเลขบัตรที่ถูกต้อง</translation>
<translation id="1728677426644403582">คุณกำลังดูซอร์สโค้ดของหน้าเว็บ</translation>
<translation id="173080396488393970">ไม่รองรับบัตรประเภทนี้</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">ข้อผิดพลาดในการจัดเรียง</translation>
<translation id="1974060860693918893">ขั้นสูง</translation>
<translation id="1978555033938440688">เวอร์ชันของเฟิร์มแวร์</translation>
-<translation id="1995859865337580572">โปรดยืนยัน CVC ของคุณ</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{และอีก 1 แอป}other{และอีก # แอป}}</translation>
<translation id="2025186561304664664">พร็อกซีถูกตั้งค่าให้ทำการกำหนดค่าโดยอัตโนมัติ</translation>
<translation id="2030481566774242610">หรือคุณหมายถึง <ph name="LINK" /></translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">เลิกทำ</translation>
<translation id="20817612488360358">มีการกำหนดให้ใช้การตั้งค่าพร็อกซีระบบ แต่ก็มีการระบุการกำหนดค่าพร็อกซีอย่างชัดเจนไว้ด้วยเช่นกัน</translation>
<translation id="2086652334978798447">หากต้องการรับคำแนะนำเนื้อหาที่เหมาะสำหรับคุณจาก Google ให้ลงชื่อเข้าใช้ Chrome</translation>
+<translation id="2091887806945687916">เสียง</translation>
<translation id="2094505752054353250">โดเมนไม่ตรง</translation>
<translation id="2096368010154057602">จังหวัด</translation>
<translation id="2108755909498034140">รีสตาร์ทคอมพิวเตอร์</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">ไม่สนใจเพราะถูกแทนที่โดย <ph name="POLICY_NAME" /></translation>
<translation id="2138201775715568214">กำลังมองหาหน้า Physical Web ที่อยู่ใกล้เคียง</translation>
<translation id="213826338245044447">บุ๊กมาร์กบนมือถือ</translation>
+<translation id="214556005048008348">ยกเลิกการชำระเงิน</translation>
<translation id="2147827593068025794">การซิงค์ในแบ็กกราวด์</translation>
+<translation id="2148613324460538318">เพิ่มบัตร</translation>
<translation id="2154054054215849342">ไม่มีการซิงค์สำหรับโดเมนของคุณ</translation>
<translation id="2154484045852737596">แก้ไขบัตร</translation>
<translation id="2166049586286450108">การเข้าถึงระดับผู้ดูแลระบบโดยสมบูรณ์</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{ที่อยู่ 1 รายการ}other{ที่อยู่ # รายการ}}</translation>
<translation id="2187317261103489799">ตรวจหา (ค่าเริ่มต้น)</translation>
<translation id="2202020181578195191">ป้อนปีที่หมดอายุที่ถูกต้อง</translation>
+<translation id="2209523182407020534">แอปพลิเคชันที่อาจทำให้เกิดข้อผิดพลาดนี้ ได้แก่ ซอฟต์แวร์ป้องกันไวรัส ซอฟต์แวร์ไฟร์วอลล์ รวมถึงซอฟต์แวร์การกรองเว็บหรือซอฟต์แวร์พร็อกซี</translation>
<translation id="2212735316055980242">ไม่พบนโยบาย</translation>
<translation id="2213606439339815911">กำลังดึงรายการ...</translation>
<translation id="2218879909401188352">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งแอปอันตรายที่ทำลายอุปกรณ์ของคุณ เพิ่มค่าใช้จ่ายแฝงในใบแจ้งยอดมือถือ หรือขโมยข้อมูลส่วนบุคคล <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">ย้อนกลับ</translation>
<translation id="2503184589641749290">บัตรเดบิตและบัตรเติมเงินที่ยอมรับ</translation>
<translation id="2515629240566999685">ตรวจสอบสัญญาณในพื้นที่ของคุณ</translation>
+<translation id="2524461107774643265">เพิ่มข้อมูลอื่นๆ</translation>
+<translation id="2536110899380797252">เพิ่มที่อยู่</translation>
<translation id="2539524384386349900">ตรวจหา</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> ส่งการตอบกลับที่ไม่ถูกต้อง</translation>
<translation id="2556876185419854533">&amp;เลิกทำการแก้ไข</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium ไม่สามารถยืนยันบัตรของคุณได้ในขณะนี้ โปรดลองอีกครั้งในภายหลัง</translation>
<translation id="2705137772291741111">อ่านสำเนาที่บันทึกไว้ (แคช) ของเว็บไซต์นี้ไม่ได้</translation>
<translation id="2709516037105925701">ป้อนอัตโนมัติ</translation>
+<translation id="2710942282213947212">ซอฟต์แวร์ในคอมพิวเตอร์ของคุณทำให้ Chromium ไม่สามารถเชื่อมต่อกับเว็บอย่างปลอดภัย</translation>
<translation id="2712173769900027643">ขออนุญาต</translation>
-<translation id="2713444072780614174">สีขาว</translation>
<translation id="2720342946869265578">ใกล้เคียง</translation>
<translation id="2721148159707890343">คำขอสำเร็จ</translation>
<translation id="2728127805433021124">ใบรับรองของเซิร์ฟเวอร์ถูกเซ็นชื่อด้วยอัลกอริทึมลายเซ็นที่ไม่รัดกุม</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">ตรวจพบการเปลี่ยนแปลงเครือข่าย</translation>
<translation id="2916038427272391327">ปิดโปรแกรมอื่นๆ</translation>
<translation id="2922350208395188000">ไม่สามารถตรวจสอบใบรับรองของเซิร์ฟเวอร์</translation>
+<translation id="2925673989565098301">วิธีการนำส่งสินค้า</translation>
<translation id="2928905813689894207">ที่อยู่สำหรับการเรียกเก็บเงิน</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> รายการ}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> รายการ}}</translation>
<translation id="2941952326391522266">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยมาจาก <ph name="DOMAIN2" /> โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">ประเภทนโยบายไม่ถูกต้อง</translation>
<translation id="3032412215588512954">คุณต้องการโหลดเว็บไซต์นี้ซ้ำใช่ไหม</translation>
<translation id="3037605927509011580">แย่จัง!</translation>
+<translation id="3039538478787849737">บันทึกบัตรไว้ใน Google ไหม</translation>
<translation id="3041612393474885105">ข้อมูลในใบรับรอง</translation>
<translation id="3063697135517575841">Chrome ไม่สามารถยืนยันบัตรของคุณได้ในขณะนี้ โปรดลองอีกครั้งในภายหลัง</translation>
<translation id="3064966200440839136">ออกจากโหมดไม่ระบุตัวตนเพื่อชำระเงินผ่านแอปพลิเคชันภายนอก ดำเนินการต่อไหม</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">ข้อผิดพลาดชั่วคราวของเซิร์ฟเวอร์</translation>
<translation id="3154506275960390542">หน้านี้มีฟอร์มที่อาจส่งอย่างไม่ปลอดภัย บุคคลอื่นสามารถดูข้อมูลที่คุณส่งได้ระหว่างทางหรือข้อมูลอาจถูกแก้ไขโดยผู้โจมตีเพื่อเปลี่ยนแปลงสิ่งที่เซิร์ฟเวอร์จะได้รับ</translation>
<translation id="3157931365184549694">คืนค่า</translation>
+<translation id="3162559335345991374">Wi-Fi ที่คุณใช้อาจต้องการให้คุณไปที่หน้าการเข้าสู่ระบบ</translation>
<translation id="3167968892399408617">หน้าที่คุณดูในแท็บไม่ระบุตัวตนจะไม่เก็บอยู่ในประวัติการเข้าชมของเบราว์เซอร์ การจัดเก็บคุกกี้ หรือประวัติการค้นหาหลังจากที่คุณปิดแท็บไม่ระบุตัวตนทั้งหมด แต่จะมีการเก็บไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่คุณสร้างขึ้น</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">เกาะ</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">ยกเลิกการชำระเงิน</translation>
<translation id="3207960819495026254">บุ๊กมาร์กแล้ว</translation>
+<translation id="3211223744486044430">เพื่อให้ชำระเงินได้เร็วขึ้นในครั้งถัดไป โปรดบันทึกบัตรนี้ไว้ในบัญชี Google และในอุปกรณ์เครื่องนี้</translation>
<translation id="3225919329040284222">เซิร์ฟเวอร์แสดงใบรับรองที่ไม่ตรงกับการคาดการณ์ที่มีอยู่ การคาดการณ์เหล่านี้มีอยู่ในบางเว็บไซต์ที่มีการรักษาความปลอดภัยสูงเพื่อปกป้องคุณ</translation>
<translation id="3226128629678568754">กดปุ่มโหลดซ้ำเพื่อส่งซ้ำข้อมูลที่จำเป็นในการโหลดหน้าเว็บ</translation>
<translation id="3227137524299004712">ไมโครโฟน</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">ไม่พบผลการค้นหา</translation>
<translation id="3305707030755673451">ข้อมูลของคุณได้รับการเข้ารหัสด้วยรหัสผ่านการซิงค์เมื่อวันที่ <ph name="TIME" /> โปรดป้อนรหัสผ่านเพื่อเริ่มซิงค์</translation>
<translation id="3320021301628644560">เพิ่มที่อยู่สำหรับการเรียกเก็บเงิน</translation>
-<translation id="3329013043687509092">ความอิ่มตัวของสี</translation>
<translation id="333371639341676808">ป้องกันหน้านี้จากการสร้างการโต้ตอบเพิ่มเติม</translation>
<translation id="3338095232262050444">ปลอดภัย</translation>
<translation id="3340978935015468852">การตั้งค่า</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">รหัสลูกค้า:</translation>
<translation id="3391030046425686457">ที่อยู่สำหรับจัดส่ง</translation>
<translation id="3395827396354264108">วิธีการรับสินค้า</translation>
+<translation id="3399952811970034796">ที่อยู่สำหรับจัดส่ง</translation>
<translation id="3422248202833853650">ลองออกจากโปรแกรมอื่นๆ เพื่อเพิ่มหน่วยความจำ</translation>
<translation id="3422472998109090673">ไม่สามารถเข้าถึง <ph name="HOST_NAME" /> ได้ในขณะนี้</translation>
<translation id="3427092606871434483">อนุญาต (ค่าเริ่มต้น)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> อัปโหลดเมื่อ <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">ข้อมูลในใบรับรอง</translation>
<translation id="3690164694835360974">การเข้าสู่ระบบไม่ปลอดภัย</translation>
+<translation id="3704162925118123524">เครือข่ายที่คุณใช้อาจต้องการให้คุณไปที่หน้าการเข้าสู่ระบบ</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">กำลังโหลด ...</translation>
<translation id="3712624925041724820">ใบอนุญาตหมด</translation>
<translation id="3714780639079136834">เปิดข้อมูลเครือข่ายมือถือหรือ Wi-Fi</translation>
+<translation id="3715597595485130451">เชื่อมต่อ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ตรวจสอบพร็อกซี ไฟร์วอลล์ และการกำหนดค่า DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">หากคุณเข้าใจความเสี่ยงต่อความปลอดภัย คุณสามารถ<ph name="BEGIN_LINK" />ไปยังไซต์ที่ไม่ปลอดภัยนี้<ph name="END_LINK" /> ก่อนจะมีการนำโปรแกรมอันตรายออก</translation>
<translation id="3739623965217189342">ลิงก์ที่คุณคัดลอกมา</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;เลิกทำการเพิ่ม</translation>
<translation id="404928562651467259">คำเตือน</translation>
<translation id="4058922952496707368">คีย์ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">เพิ่มที่อยู่ที่ถูกต้อง</translation>
<translation id="4072486802667267160">เกิดข้อผิดพลาดในการประมวลผลคำสั่งซื้อของคุณ โปรดลองอีกครั้ง</translation>
<translation id="4075732493274867456">ไคลเอ็นต์และเซิร์ฟเวอร์ไม่รองรับโปรโตคอล SSL เวอร์ชันทั่วไปหรือชุดการเข้ารหัส</translation>
<translation id="4079302484614802869">การกำหนดค่าพร็อกซีมีการตั้งค่าให้ใช้ URL สคริปต์ .pac ไม่ใช่พร็อกซีเซิร์ฟเวอร์แบบคงที่</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">หมายเลขซีเรียลของอุปกรณ์ไม่ถูกต้อง</translation>
<translation id="410351446219883937">เล่นอัตโนมัติ</translation>
<translation id="4103763322291513355">ไปที่ &lt;strong&gt;chrome://policy&lt;/strong&gt; เพื่อดูรายการของ URL ที่ไม่ได้รับอนุญาต และนโยบายอื่นๆ ที่ผู้ดูแลระบบของคุณบังคับใช้</translation>
-<translation id="4115378294792113321">สีม่วงแดง</translation>
<translation id="4116663294526079822">อนุญาตบนไซต์นี้เสมอ</translation>
<translation id="4117700440116928470">ขอบข่ายนโยบายไม่ได้รับการสนับสนุน</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{อีก 1 รายการ}other{อีก # รายการ}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">คุณพยายามเข้าถึง <ph name="DOMAIN" /> แต่ใบรับรองที่เซิร์ฟเวอร์แจ้งมาถูกเพิกถอนโดยผู้ออกใบรับรอง ซึ่งหมายความว่าข้อมูลรับรองด้านความปลอดภัยที่เซิร์ฟเวอร์แจ้งมานั้นไม่สามารถเชื่อถือได้ คุณอาจกำลังติดต่อกับคนที่คิดจะโจมตีคุณ</translation>
<translation id="4394049700291259645">ปิดการใช้งาน</translation>
<translation id="4406896451731180161">ผลการค้นหา</translation>
+<translation id="4415426530740016218">ที่อยู่ในการรับ</translation>
<translation id="4424024547088906515">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะ Chrome ไม่เชื่อถือใบรับรองความปลอดภัย โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ไม่ยอมรับใบรับรองการเข้าสู่ระบบหรือไม่ได้ให้ใบรับรองไว้</translation>
<translation id="443673843213245140">การใช้พร็อกซีถูกปิดใช้งาน แต่มีการระบุการกำหนดค่าพร็อกซีอย่างชัดเจน</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">ลองปิดใช้ส่วนขยาย</translation>
<translation id="457875822857220463">การจัดส่ง</translation>
+<translation id="4582800630050655161">คุณอาจไม่สามารถเข้าถึงบัญชี Google หรือถูกโจรกรรมข้อมูลประจำตัว Chromium ขอแนะนำให้เปลี่ยนรหัสผ่านตอนนี้เลย</translation>
<translation id="4587425331216688090">นำที่อยู่ออกจาก Chrome ไหม</translation>
<translation id="4592951414987517459">มีการเข้ารหัสการเชื่อมต่อของคุณกับ <ph name="DOMAIN" /> ด้วยชุดการเข้ารหัสที่ทันสมัย</translation>
<translation id="4594403342090139922">&amp;เลิกทำการนำออก</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยมีข้อผิดพลาด โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
<translation id="4690462567478992370">หยุดใช้ใบรับรองที่ไม่ถูกต้อง</translation>
+<translation id="4690954380545377795">คุณอาจไม่สามารถเข้าถึงบัญชี Google หรือถูกโจรกรรมข้อมูลประจำตัว Chrome ขอแนะนำให้เปลี่ยนรหัสผ่านตอนนี้เลย</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">การเชื่อมต่อของคุณขัดข้อง</translation>
<translation id="471880041731876836">คุณไม่มีสิทธิ์เข้าชมไซต์นี้</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />เรียกใช้การวินิจฉัยเครือข่ายของ Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">การชำระเงินของคุณ</translation>
<translation id="4726672564094551039">โหลดนโยบายซ้ำ</translation>
<translation id="4728558894243024398">แพลตฟอร์ม</translation>
<translation id="4736825316280949806">รีสตาร์ท Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">ไม่สามารถจัดเก็บเนื่องจากระบบแบ็คเอนด์อยู่ในสถานะไม่ดี</translation>
<translation id="5023310440958281426">ตรวจสอบนโยบายของผู้ดูแลระบบของคุณ</translation>
<translation id="5029568752722684782">ล้างสำเนา</translation>
+<translation id="503069730517007720">ไม่ได้ติดตั้งใบรับรองรากที่จำเป็นของ "<ph name="SOFTWARE_NAME" />" ผู้ดูแลระบบ IT ควรดูวิธีการกำหนดค่าของ "<ph name="SOFTWARE_NAME" />" เพื่อแก้ไขปัญหานี้ <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">เกี่ยวกับ Google แปลภาษา</translation>
<translation id="5039804452771397117">อนุญาต</translation>
<translation id="5040262127954254034">ความเป็นส่วนตัว</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">การทดลอง</translation>
<translation id="5205222826937269299">ต้องระบุชื่อ</translation>
<translation id="5222812217790122047">ต้องระบุอีเมล</translation>
+<translation id="522700295135997067">ไซต์นี้อาจเพิ่งขโมยรหัสผ่านของคุณไป</translation>
+<translation id="5230733896359313003">ที่อยู่ในการจัดส่ง</translation>
<translation id="5251803541071282808">ระบบคลาวด์</translation>
<translation id="5277279256032773186">หากใช้ Chrome ที่ทำงาน ธุรกิจสามารถจัดการการตั้งค่า Chrome ให้พนักงานของตนได้ เรียนรู้เพิ่มเติม</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />ทำตามขั้นตอนการปิดใช้ซอฟต์แวร์ชั่วคราวต่อไปนี้เพื่อให้เข้าสู่เว็บได้ คุณจะต้องมีสิทธิ์ของผู้ดูแลระบบ<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">การเชื่อมต่อกับเว็บไซต์นี้ไม่เป็นส่วนตัว หากต้องการออกจากโหมด VR ในเวลาใดก็ตาม ให้นำอุปกรณ์สวมศีรษะออก แล้วกด "กลับ"</translation>
<translation id="5299298092464848405">ข้อผิดพลาดในการแยกวิเคราะห์นโยบาย</translation>
+<translation id="5308380583665731573">เชื่อมต่อ</translation>
<translation id="5308689395849655368">การรายงานข้อขัดข้องถูกปิดใช้งาน</translation>
<translation id="5317780077021120954">บันทึก</translation>
<translation id="5327248766486351172">ชื่อ</translation>
+<translation id="5332219387342487447">วิธีการจัดส่ง</translation>
<translation id="5355557959165512791">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจากใบรับรองถูกเพิกถอนแล้ว โดยปกติข้อผิดพลาดของเครือข่ายและการโจมตีจะเกิดขึ้นเพียงชั่วคราว หน้านี้จึงอาจจะใช้งานได้ในภายหลัง</translation>
<translation id="536296301121032821">ไม่สามารถจัดเก็บการตั้งค่านโยบาย</translation>
<translation id="5386426401304769735">กลุ่มใบรับรองสำหรับเว็บไซต์นี้มีใบรับรองที่ลงนามโดยใช้ SHA-1</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">เว็บไซต์นี้บนอินทราเน็ตของบริษัท องค์กร หรือโรงเรียนมี URL เหมือนกับเว็บไซต์ภายนอก
<ph name="LINE_BREAK" />
โปรดลองติดต่อผู้ดูแลระบบของคุณ</translation>
+<translation id="5499929369096410817">ป้อนรหัสความปลอดภัยสำหรับ <ph name="CREDIT_CARD" /> ระบบจะไม่บันทึกรหัสนี้ไว้</translation>
<translation id="5509780412636533143">บุ๊กมาร์กที่มีการจัดการ</translation>
<translation id="5510766032865166053">ไฟล์อาจถูกย้ายหรือลบไปแล้ว</translation>
<translation id="5523118979700054094">ชื่อนโยบาย</translation>
<translation id="552553974213252141">ดึงข้อความออกมาถูกต้องไหม</translation>
<translation id="5540224163453853">ไม่พบบทความที่ขอ</translation>
+<translation id="5541546772353173584">เพิ่มอีเมล</translation>
<translation id="5544037170328430102">หน้าที่ฝังไว้ใน <ph name="SITE" /> บอกว่า:</translation>
+<translation id="5545756402275714221">บทความสำหรับคุณ</translation>
<translation id="5556459405103347317">โหลดใหม่</translation>
<translation id="5560088892362098740">วันที่หมดอายุ</translation>
<translation id="5565735124758917034">ใช้งานอยู่</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">อีเมล</translation>
<translation id="5669703222995421982">รับเนื้อหาที่ปรับเปลี่ยนในแบบของคุณ</translation>
<translation id="5675650730144413517">หน้านี้ใช้ไม่ได้</translation>
+<translation id="5689199277474810259">ส่งออกไปยัง JSON</translation>
<translation id="5710435578057952990">ข้อมูลประจำตัวของเว็บไซต์นี้ยังไม่ได้รับการยืนยัน</translation>
<translation id="5719499550583120431">รับบัตรเติมเงิน</translation>
<translation id="5720705177508910913">ผู้ใช้ปัจจุบัน</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">มีการเข้ารหัสการเชื่อมต่อของคุณกับ <ph name="DOMAIN" /> ด้วยชุดการเข้ารหัสที่ล้าสมัยแล้ว</translation>
<translation id="5813119285467412249">&amp;ทำซ้ำการเพิ่ม</translation>
<translation id="5838278095973806738">คุณไม่ควรป้อนข้อมูลที่ละเอียดอ่อนบนเว็บไซต์นี้ (ตัวอย่างเช่น รหัสผ่านหรือบัตรเครดิต) เนื่องจากผู้โจมตีอาจขโมยข้อมูลดังกล่าวไปได้</translation>
+<translation id="5866257070973731571">เพิ่มหมายเลขโทรศัพท์</translation>
<translation id="5869405914158311789">ไม่สามารถเข้าถึงเว็บไซต์นี้</translation>
<translation id="5869522115854928033">รหัสผ่านที่บันทึกไว้</translation>
<translation id="5872918882028971132">คำแนะนำระดับบนสุด</translation>
<translation id="5893752035575986141">รับบัตรเครดิต</translation>
-<translation id="5901630391730855834">สีเหลือง</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ซิงค์แล้ว)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{ใช้งานอยู่ 1 รายการ}other{ใช้งานอยู่ # รายการ}}</translation>
<translation id="5959728338436674663">ส่ง<ph name="BEGIN_WHITEPAPER_LINK" />ข้อมูลบางอย่างของระบบและเนื้อหาของหน้าเว็บ<ph name="END_WHITEPAPER_LINK" />ไปยัง Google เพื่อช่วยตรวจหาแอปและเว็บไซต์ที่เป็นอันตรายโดยอัตโนมัติ<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">แก้ไขข้อมูลติดต่อ</translation>
<translation id="5967867314010545767">ลบจากประวัติการเข้าชม</translation>
<translation id="5975083100439434680">ย่อ</translation>
+<translation id="597552863672748783">ยืนยันรหัสความปลอดภัย</translation>
<translation id="598637245381783098">ไม่สามารถเปิดแอปการชำระเงิน</translation>
<translation id="5989320800837274978">ไม่มีการระบุทั้งพร็อกซีเซิร์ฟเวอร์แบบคงที่หรือ URL สคริปต์ .pac</translation>
<translation id="5990559369517809815">คำขอไปยังเซิร์ฟเวอร์ถูกบล็อกโดยส่วนขยาย</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{หน้า 1}other{หน้า #}}</translation>
-<translation id="6017514345406065928">สีเขียว</translation>
<translation id="6017850046339264347">ผู้โจมตี <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="6025416945513303461"><ph name="TYPE_1" /> <ph name="TYPE_2" /> <ph name="TYPE_3" /> (ซิงค์แล้ว)</translation>
<translation id="6027201098523975773">ป้อนชื่อ</translation>
<translation id="6040143037577758943">ปิด</translation>
-<translation id="6042308850641462728">เพิ่มเติม</translation>
<translation id="6047233362582046994">หากคุณเข้าใจความเสี่ยงต่อความปลอดภัย คุณสามารถ<ph name="BEGIN_LINK" />ไปยังไซต์นี้<ph name="END_LINK" />ก่อนที่จะมีการนำแอปอันตรายออก</translation>
<translation id="6047927260846328439">เนื้อหานี้อาจพยายามหลอกล่อให้คุณติดตั้งซอฟต์แวร์หรือเปิดเผยข้อมูลส่วนบุคคล <ph name="BEGIN_LINK" />แสดงเนื้อหา<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจากเว็บไซต์ใช้การตรึงใบรับรอง โดยปกติข้อผิดพลาดของเครือข่ายและการโจมตีจะเกิดขึ้นเพียงชั่วคราว หน้านี้จึงอาจใช้งานได้ในภายหลัง</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">คุณกำลังดูหน้าส่วนขยาย</translation>
<translation id="6596325263575161958">ตัวเลือกการเข้ารหัส</translation>
<translation id="662080504995468778">อยู่ต่อ</translation>
+<translation id="6624427990725312378">ข้อมูลติดต่อ</translation>
<translation id="6626291197371920147">เพิ่มหมายเลขบัตรที่ถูกต้อง</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ค้นหา</translation>
<translation id="6630809736994426279">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรแกรมอันตรายลงในเครื่อง Mac ของคุณ เพื่อขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">ก่อนหน้า</translation>
<translation id="6710594484020273272">&lt;พิมพ์ข้อความค้นหา&gt;</translation>
<translation id="6711464428925977395">พร็อกซีเซิร์ฟเวอร์ผิดปกติหรือที่อยู่ไม่ถูกต้อง</translation>
-<translation id="6727102863431372879">ตั้งค่า</translation>
<translation id="674375294223700098">ข้อผิดพลาดใบรับรองของเซิร์ฟเวอร์ที่ไม่รู้จัก</translation>
<translation id="6753269504797312559">ค่านโยบาย</translation>
<translation id="6757797048963528358">อุปกรณ์ของคุณเข้าสู่โหมดสลีปแล้ว</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">เส้นทางโปรไฟล์</translation>
<translation id="7424977062513257142">หน้าที่ฝังไว้ในหน้าเว็บนี้บอกว่า:</translation>
+<translation id="7437289804838430631">เพิ่มข้อมูลติดต่อ</translation>
<translation id="7441627299479586546">หัวเรื่องนโยบายไม่ถูกต้อง</translation>
<translation id="7444046173054089907">เว็บไซต์นี้ถูกบล็อก</translation>
<translation id="7445762425076701745">ไม่สามารถตรวจสอบความถูกต้องของข้อมูลประจำตัวของเซิร์ฟเวอร์ที่คุณเชื่อมต่ออยู่ได้ทั้งหมด คุณกำลังเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้ชื่อที่ใช้ได้เฉพาะในเครือข่ายของคุณ ซึ่งผู้ออกใบรับรองภายนอกไม่สามารถตรวจสอบการเป็นเจ้าของได้ เนื่องจากผู้ออกใบรับรองบางรายจะยังคงออกใบรับรองให้กับชื่อเหล่านี้อยู่ คุณจึงไม่มีทางมั่นใจได้ว่ากำลังเชื่อมต่อกับเว็บไซต์ที่คุณต้องการดูโดยไม่ใช่ผู้โจมตี</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">ส่งต่อ</translation>
<translation id="7485870689360869515">ไม่พบข้อมูล</translation>
<translation id="7508255263130623398">รหัสอุปกรณ์นโยบายที่ส่งกลับว่างเปล่าหรือไม่ตรงกับรหัสอุปกรณ์ปัจจุบัน</translation>
+<translation id="7511955381719512146">Wi-Fi ที่คุณใช้อาจต้องการให้คุณไปที่ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
<translation id="7514365320538308">ดาวน์โหลด</translation>
<translation id="7518003948725431193">ไม่พบหน้าเว็บสำหรับที่อยู่เว็บ: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">การเชื่อมต่อกับไซต์นี้ไม่เป็นส่วนตัว</translation>
-<translation id="7535087603100972091">ราคา</translation>
<translation id="7537536606612762813">จำเป็น</translation>
<translation id="7542403920425041731">เมื่อคุณยืนยันแล้ว จะมีการแชร์รายละเอียดบัตรของคุณกับไซต์นี้</translation>
<translation id="7542995811387359312">การป้อนหมายเลขบัตรเครดิตอัตโนมัติถูกปิดใช้งานเนื่องจากฟอร์มนี้ไม่ได้ใช้การเชื่อมต่อที่ปลอดภัย</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะอาจมีการออกใบรับรองความปลอดภัยปลอม โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
<translation id="7568593326407688803">หน้าเว็บนี้เป็น<ph name="ORIGINAL_LANGUAGE" />คุณต้องการแปลหรือไม่</translation>
<translation id="7569952961197462199">นำบัตรเครดิตออกจาก Chrome ไหม</translation>
-<translation id="7569983096843329377">สีดำ</translation>
<translation id="7578104083680115302">ชำระเงินบนเว็บไซต์และแอปในอุปกรณ์ต่างๆ ได้อย่างรวดเร็วด้วยบัตรที่คุณได้บันทึกไว้กับ Google</translation>
<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">ใบรับรองของเซิร์ฟเวอร์ละเมิดข้อกำหนดชื่อ</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">ผู้โจมตีเว็บไซต์นี้อาจพยายามหลอกล่อให้คุณติดตั้งโปรแกรมที่เป็นอันตรายต่อประสบการณ์การท่องเว็บของคุณ (ตัวอย่างเช่น โดยการเปลี่ยนแปลงหน้าแรกหรือแสดงโฆษณาเพิ่มเติมในเว็บไซต์ที่คุณเข้าชม)</translation>
<translation id="7674629440242451245">หากสนใจในฟีเจอร์ใหม่ๆ สุดเจ๋งของ Chrome ลองใช้เวอร์ชันที่กำลังพัฒนาของเราที่ chrome.com/dev</translation>
<translation id="7682287625158474539">จัดส่ง</translation>
+<translation id="7699293099605015246">บทความไม่พร้อมใช้งานในขณะนี้</translation>
<translation id="7701040980221191251">ไม่มี</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ไปยัง <ph name="SITE" /> (ไม่ปลอดภัย)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">ใบรับรอง</translation>
<translation id="7716147886133743102">ถูกบล็อกโดยผู้ดูแลระบบ</translation>
<translation id="7716424297397655342">ไม่สามารถโหลดเว็บไซต์นี้จากแคช</translation>
+<translation id="7723047071702270851">แก้ไขบัตร</translation>
<translation id="774634243536837715">บล็อกเนื้อหาอันตรายแล้ว</translation>
<translation id="7752995774971033316">ไม่ได้จัดการ</translation>
<translation id="7755287808199759310">ผู้ปกครองสามารถเลิกบล็อกเว็บไซต์ให้คุณ</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">เพิ่มที่อยู่</translation>
<translation id="777702478322588152">เขตปกครอง</translation>
<translation id="7791543448312431591">เพิ่ม</translation>
+<translation id="7793553086574152071">เพื่อให้ชำระเงินได้เร็วขึ้นในครั้งถัดไป โปรดบันทึกบัตรนี้ไว้ในบัญชี Google</translation>
<translation id="7793809570500803535">หน้าเว็บที่ <ph name="SITE" /> อาจหยุดให้บริการชั่วคราวหรืออาจถูกย้ายไปยังที่อยู่เว็บใหม่อย่างถาวร</translation>
<translation id="7800304661137206267">การเชื่อมต่อถูกเข้ารหัสโดยใช้ <ph name="CIPHER" /> โดยใช้ <ph name="MAC" /> สำหรับตรวจสอบสิทธิ์ข้อความและ <ph name="KX" /> เป็นกลไลการแลกเปลี่ยนกุญแจ</translation>
+<translation id="7802523362929240268">ไซต์ถูกต้อง</translation>
<translation id="780301667611848630">ไม่ ขอบคุณ</translation>
<translation id="7805768142964895445">สถานะ</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">นำคำแนะนำสำหรับแบบฟอร์มออกจาก Chrome ไหม</translation>
<translation id="7815407501681723534">พบ<ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" /> รายการสำหรับ "<ph name="SEARCH_STRING" />"</translation>
+<translation id="782886543891417279">Wi-Fi ที่คุณใช้ (<ph name="WIFI_NAME" />) อาจต้องการให้คุณไปที่หน้าการเข้าสู่ระบบ</translation>
<translation id="785549533363645510">อย่างไรก็ตาม ระบบยังมองเห็นคุณ การเข้าสู่โหมดไม่ระบุตัวตนไม่ได้เป็นการซ่อนการท่องเว็บจากนายจ้างของคุณ ผู้ให้บริการอินเทอร์เน็ต หรือเว็บไซต์ที่คุณเข้าชม</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">รับบัตรเดบิตและบัตรเติมเงิน</translation>
+<translation id="7878562273885520351">รหัสผ่านของคุณอาจถูกขโมยได้</translation>
<translation id="7887683347370398519">ตรวจสอบ CVC และลองอีกครั้ง</translation>
<translation id="79338296614623784">ป้อนหมายเลขโทรศัพท์ที่ถูกต้อง</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">ใบรับรองของเซิร์ฟเวอร์ยังไม่ถูกต้อง</translation>
-<translation id="7942349550061667556">สีแดง</translation>
<translation id="7947285636476623132">ตรวจสอบปีหมดอายุแล้วลองอีกครั้ง</translation>
<translation id="7951415247503192394">(32 บิต)</translation>
<translation id="7956713633345437162">บุ๊กมาร์กบนมือถือ</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">ขอ (ค่าเริ่มต้น)</translation>
<translation id="8041089156583427627">ส่งความคิดเห็น</translation>
<translation id="8041940743680923270">ใช้ค่าเริ่มต้นสากล (ถาม)</translation>
+<translation id="8057711352706143257">กำหนดค่า "<ph name="SOFTWARE_NAME" />" ไม่ถูกต้อง การถอนการติดตั้ง "<ph name="SOFTWARE_NAME" />" มักแก้ไขปัญหานี้ได้ <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">การดูบทความล้มเหลว</translation>
<translation id="8091372947890762290">กำลังรอการเปิดใช้งานบนเซิร์ฟเวอร์</translation>
+<translation id="8094917007353911263">เครือข่ายที่คุณใช้อาจต้องการให้คุณไปที่ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
+<translation id="8103161714697287722">วิธีการชำระเงิน</translation>
<translation id="8118489163946903409">วิธีการชำระเงิน</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" ไม่ได้ติดตั้งในคอมพิวเตอร์หรือเครือข่ายอย่างถูกต้อง โปรดขอให้ผู้ดูแลระบบ IT แก้ไขปัญหานี้</translation>
<translation id="8131740175452115882">ยืนยัน</translation>
<translation id="8134994873729925007">ไม่พบ<ph name="BEGIN_ABBR" />ที่อยู่ DNS<ph name="END_ABBR" /> ของเซิร์ฟเวอร์ของ <ph name="HOST_NAME" /></translation>
<translation id="8149426793427495338">คอมพิวเตอร์ของคุณเข้าสู่โหมดสลีปแล้ว</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">ติดต่อผู้ดูแลระบบเครือข่ายของคุณหากไม่แน่ใจว่าข้อความนี้หมายถึงอะไร</translation>
<translation id="8293206222192510085">เพิ่มบุ๊กมาร์ก</translation>
<translation id="8294431847097064396">แหล่งที่มา</translation>
+<translation id="8298115750975731693">Wi-Fi ที่คุณใช้ (<ph name="WIFI_NAME" />) อาจต้องการให้คุณไปที่ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
<translation id="8306404619377842860">ไม่สามารถสร้างการเชื่อมต่อส่วนตัวกับ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> เนื่องจากวันที่และเวลาของอุปกรณ์ (<ph name="DATE_AND_TIME" />) ไม่ถูกต้อง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">การแปลล้มเหลวเนื่องจากเกิดปัญหาการเชื่อมต่อกับเครือข่าย </translation>
<translation id="8332188693563227489">การเข้าถึง <ph name="HOST_NAME" /> ถูกปฏิเสธ</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">เพิ่งปิด</translation>
<translation id="8874824191258364635">ป้อนหมายเลขบัตรที่ถูกต้อง</translation>
<translation id="8876793034577346603">ไม่สามารถแยกวิเคราะห์การกำหนดค่าเครือข่าย</translation>
-<translation id="8889402386540077796">โทนสี</translation>
<translation id="8891727572606052622">โหมดพร็อกซีไม่ถูกต้อง</translation>
<translation id="889901481107108152">ขออภัย การทดลองนี้ไม่สามารถใช้ได้กับแพลตฟอร์มของคุณ</translation>
<translation id="8903921497873541725">ขยาย</translation>
<translation id="8931333241327730545">คุณต้องการบันทึกบัตรนี้ในบัญชี Google ไหม</translation>
<translation id="8932102934695377596">นาฬิกาช้าเกินไป</translation>
+<translation id="893332455753468063">เพิ่มชื่อ</translation>
<translation id="8938939909778640821">บัตรเครดิตและบัตรเติมเงินที่ยอมรับ</translation>
+<translation id="8957210676456822347">การให้สิทธิ์แคปทีฟพอร์ทัล</translation>
<translation id="8971063699422889582">ใบรับรองของเซิร์ฟเวอร์หมดอายุแล้ว</translation>
-<translation id="8986494364107987395">ส่งสถิติการใช้งานและรายงานข้อขัดข้องไปยัง Google โดยอัตโนมัติ</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">ไซต์ที่จะเปิดมีโปรแกรมที่เป็นอันตราย</translation>
<translation id="8997023839087525404">เซิร์ฟเวอร์แสดงใบรับรองที่ไม่มีการเปิดเผยต่อสาธารณะโดยใช้นโยบายความโปร่งใสของใบรับรอง ซึ่งเป็นข้อกำหนดสำหรับใบรับรองบางรายการ เพื่อยืนยันว่าเชื่อถือได้และป้องกันการจู่โจม</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> ของพร็อกซีต้องใช้ชื่อผู้ใช้และรหัสผ่าน</translation>
<translation id="9005998258318286617">ไม่สามารถโหลดเอกสาร PDF</translation>
+<translation id="9008201768610948239">ไม่สนใจ</translation>
<translation id="901974403500617787">การตั้งค่าสถานะที่ใช้ทั้งระบบสามารถตั้งค่าได้โดยเจ้าของเท่านั้น: <ph name="OWNER_EMAIL" /></translation>
<translation id="9020200922353704812">ต้องใส่ที่อยู่สำหรับการเรียกเก็บเงินของบัตร</translation>
<translation id="9020542370529661692">หน้านี้ได้รับการแปลเป็น <ph name="TARGET_LANGUAGE" /> แล้ว</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">คุณพยายามเข้าถึง <ph name="DOMAIN" /> แต่เซิร์ฟเวอร์แสดงใบรับรองที่ไม่ถูกต้อง</translation>
<translation id="9050666287014529139">ข้อความรหัสผ่าน</translation>
<translation id="9065203028668620118">แก้ไข</translation>
-<translation id="9068849894565669697">เลือกสี</translation>
<translation id="9069693763241529744">ถูกบล็อกโดยส่วนขยาย</translation>
<translation id="9076283476770535406">เว็บไซต์นี้อาจมีเนื้อหาสำหรับผู้ใหญ่</translation>
<translation id="9078964945751709336">ต้องระบุข้อมูลเพิ่มเติม</translation>
+<translation id="9080712759204168376">สรุปการสั่งซื้อ</translation>
<translation id="9103872766612412690">โดยทั่วไป <ph name="SITE" /> จะใช้การเข้ารหัสเพื่อปกป้องข้อมูลของคุณ เมื่อ Chromium พยายามเชื่อมต่อกับ <ph name="SITE" /> ในครั้งนี้ เว็บไซต์ดังกล่าวส่งข้อมูลรับรองที่ผิดปกติและไม่ถูกต้องกลับมา เหตุการณ์นี้อาจเกิดขึ้นเมื่อผู้บุกรุกพยายามปลอมเป็น <ph name="SITE" /> หรือหน้าจอการลงชื่อเข้าใช้ Wi-Fi รบกวนการเชื่อมต่อ ข้อมูลของคุณยังปลอดภัยอยู่เนื่องจาก Chromium หยุดการเชื่อมต่อก่อนมีการแลกเปลี่ยนข้อมูล</translation>
+<translation id="9106062320799175032">เพิ่มที่อยู่สำหรับการเรียกเก็บเงิน</translation>
+<translation id="910908805481542201">ช่วยฉันแก้ไขปัญหานี้</translation>
+<translation id="9128870381267983090">เชื่อมต่อกับเครือข่าย</translation>
<translation id="9137013805542155359">แสดงหน้าเว็บเดิม</translation>
<translation id="9137248913990643158">โปรดเปิดและลงชื่อเข้าใช้ Chrome ก่อนใช้แอปนี้</translation>
<translation id="9148507642005240123">&amp;เลิกทำการแก้ไข</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ใช้โปรโตคอลที่ไม่รองรับ</translation>
<translation id="9205078245616868884">ข้อมูลของคุณมีการเข้ารหัสด้วยรหัสผ่านการซิงค์ โปรดป้อนรหัสผ่านเพื่อเริ่มซิงค์</translation>
<translation id="9207861905230894330">การเพิ่มบทความล้มเหลว</translation>
+<translation id="9215416866750762878">มีแอปพลิเคชันที่ห้ามไม่ให้ Chrome เชื่อมต่อกับไซต์นี้อย่างปลอดภัย</translation>
<translation id="9219103736887031265">ภาพ</translation>
<translation id="933612690413056017">ไม่มีการเชื่อมต่ออินเทอร์เน็ต</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{ไม่มี}=1{1 รายการ}other{# รายการ}}</translation>
<translation id="981121421437150478">ออฟไลน์</translation>
<translation id="988159990683914416">รุ่นนักพัฒนา</translation>
+<translation id="989988560359834682">แก้ไขที่อยู่</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" ไม่ได้ติดตั้งในคอมพิวเตอร์หรือเครือข่ายอย่างถูกต้อง
+ &lt;ul&gt;
+ &lt;li&gt;ลองถอนการติดตั้งหรือปิดใช้ "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;ลองเชื่อมต่อกับเครือข่ายอื่น&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index 17d464c961d..c13cf175a09 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Masaüstü Yer İşaretleri</translation>
<translation id="1074497978438210769">Güvenli değil</translation>
<translation id="1080116354587839789">Genişliğe sığdır</translation>
+<translation id="1088860948719068836">Kart Üzerindeki Adı Ekleyin</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> dilini daima çevir</translation>
+<translation id="1103778128462718200">Tüm kayıtlı şifreleri göster...</translation>
<translation id="1107591249535594099">İşaretlenirse Chrome, formları daha hızlı doldurma amacıyla kartınızın bir kopyasını bu cihazda depolar.</translation>
<translation id="1111153019813902504">Son yer işaretleri</translation>
<translation id="1113869188872983271">Sıralama değişikliğini &amp;geri al</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (senkronize edildi)</translation>
<translation id="1263231323834454256">Okuma listesi</translation>
<translation id="1264126396475825575">Kilitlenme raporu yakalanma zamanı: <ph name="CRASH_TIME" /> (henüz yüklenmedi veya yoksayıldı)</translation>
+<translation id="1270502636509132238">Alma Yöntemi</translation>
<translation id="1281526147609854549">Yayınlayan: <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Bu siteyi hiçbir zaman çevirme</translation>
<translation id="129553762522093515">Son kapatılan</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Bağlantı bekleniyor…</translation>
<translation id="153384715582417236">Şimdilik hepsi bu</translation>
<translation id="1549470594296187301">Bu özelliğin kullanılabilmesi için JavaScript etkinleştirilmelidir.</translation>
-<translation id="1555130319947370107">Mavi</translation>
<translation id="1559528461873125649">Belirtilen dosya veya dizin yok</translation>
<translation id="1583429793053364125">Bu web sayfasını görüntülerken bir hata oluştu.</translation>
<translation id="1592005682883173041">Yerel Veri Erişimi</translation>
<translation id="1594030484168838125">Seç</translation>
-<translation id="161042844686301425">Camgöbeği</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1629803312968146339">Chrome'un bu kartı kaydetmesini istiyor musunuz?</translation>
<translation id="1639239467298939599">Yükleniyor</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Bu siteyi ziyaret etmek için <ph name="NAME" /> size izin vermelidir</translation>
<translation id="1721424275792716183">* Zorunlu alan</translation>
+<translation id="1727741090716970331">Geçerli Kart Numarası Ekleyin</translation>
<translation id="1728677426644403582">Bir web sayfasının kaynak kodunu görüntülüyorsunuz</translation>
<translation id="173080396488393970">Bu kart türü desteklenmiyor</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Serileştirme hatası</translation>
<translation id="1974060860693918893">Gelişmiş</translation>
<translation id="1978555033938440688">Donanım Yazılımı Sürümü</translation>
-<translation id="1995859865337580572">Lütfen CVC'nizi doğrulayın</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{ve 1 uygulama daha}other{ve # uygulama daha}}</translation>
<translation id="2025186561304664664">Proxy, otomatik yapılandırıldı değerine ayarlandı.</translation>
<translation id="2030481566774242610">Şunu mu demek istediniz?: <ph name="LINK" /></translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Google tarafından önerilen kişiselleştirilmiş içeriği almak için Chrome'da oturum açın.</translation>
+<translation id="2091887806945687916">Ses</translation>
<translation id="2094505752054353250">Alan adı uyuşmazlığı</translation>
<translation id="2096368010154057602">Bölüm</translation>
<translation id="2108755909498034140">Bilgisayarınızı yeniden başlatın</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> tarafından geçersiz kılındığı için yoksayıldı.</translation>
<translation id="2138201775715568214">Yakınlardaki Fiziksel Web sayfaları aranıyor</translation>
<translation id="213826338245044447">Mobil Yer İşaretleri</translation>
+<translation id="214556005048008348">Ödemeyi iptal et</translation>
<translation id="2147827593068025794">Arka Plan Senkronizasyonu</translation>
+<translation id="2148613324460538318">Kart Ekle</translation>
<translation id="2154054054215849342">Senkronizasyon alan adınızda kullanılamıyor</translation>
<translation id="2154484045852737596">Kartı düzenle</translation>
<translation id="2166049586286450108">Tam Yönetici Erişimi</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adres}}</translation>
<translation id="2187317261103489799">Algıla (varsayılan)</translation>
<translation id="2202020181578195191">Geçerli bir son kullanma yılı girin</translation>
+<translation id="2209523182407020534">Bu hataya neden olabilecek uygulamalar arasında virüsten korunma programları, güvenlik duvarları ve web filtreleme veya proxy yazılımları sayılabilir.</translation>
<translation id="2212735316055980242">Politika bulunamadı</translation>
<translation id="2213606439339815911">Girişler getiriliyor...</translation>
<translation id="2218879909401188352">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> öğesini kullanan saldırganlar cihazınıza zarar verebilecek uygulamalar yükleyebilir, sizden habersiz mobil faturanıza ücretler ekleyebilir veya kişisel bilgilerinizi çalabilirler. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Geri dön</translation>
<translation id="2503184589641749290">Kabul edilen banka ve ön ödemeli kartlar</translation>
<translation id="2515629240566999685">Bulunduğunuz bölgedeki sinyali kontrol etme</translation>
+<translation id="2524461107774643265">Daha Fazla Bilgi Ekleyin</translation>
+<translation id="2536110899380797252">Adres Ekle</translation>
<translation id="2539524384386349900">Algıla</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> geçersiz bir yanıt gönderdi.</translation>
<translation id="2556876185419854533">Düzenlemeyi &amp;Geri Al</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium, şu anda kartınızı onaylayamıyor. Lütfen daha sonra tekrar deneyin.</translation>
<translation id="2705137772291741111">Bu sitenin kaydedilen (önbelleğe alınan) kopyası okunamadı.</translation>
<translation id="2709516037105925701">Otomatik doldurma</translation>
+<translation id="2710942282213947212">Bilgisayarınızdaki yazılım, Chromium'un web'e güvenli bir şekilde bağlanmasını engelliyor</translation>
<translation id="2712173769900027643">İzin iste</translation>
-<translation id="2713444072780614174">Beyaz</translation>
<translation id="2720342946869265578">Etrafımda</translation>
<translation id="2721148159707890343">İstek başarılı oldu</translation>
<translation id="2728127805433021124">Sunucunun sertifikası, zayıf bir imza algoritması kullanılarak imzalanmış.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Bir ağ değişikliği algılandı.</translation>
<translation id="2916038427272391327">Diğer programları kapatın</translation>
<translation id="2922350208395188000">Sunucunun sertifikası kontrol edilemiyor.</translation>
+<translation id="2925673989565098301">Teslimat Yöntemi</translation>
<translation id="2928905813689894207">Fatura Adresi</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> adres daha}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> adres daha}}</translation>
<translation id="2941952326391522266">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası <ph name="DOMAIN2" /> alan adından geliyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Yanlış politika türü</translation>
<translation id="3032412215588512954">Bu siteyi yeniden yüklemek istiyor musunuz?</translation>
<translation id="3037605927509011580">Hay aksi!</translation>
+<translation id="3039538478787849737">Kart Google'a kaydedilsin mi?</translation>
<translation id="3041612393474885105">Sertifika Bilgileri</translation>
<translation id="3063697135517575841">Chrome şu anda kartınızı onaylayamıyor. Lütfen daha sonra tekrar deneyin.</translation>
<translation id="3064966200440839136">Harici bir uygulama üzerinden ödeme gerçekleştirmek için gizli moddan çıkılacak. Devam edilsin mi?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Geçici sunucu hatası</translation>
<translation id="3154506275960390542">Bu sayfada güvenli şekilde gönderilemeyecek bir form bulunmaktadır. Gönderdiğiniz veriler, aktarım sırasında başkaları tarafından görüntülenebilir veya bir saldırgan tarafından sunucunun alacağı verileri değiştirmek amacıyla kullanılabilir.</translation>
<translation id="3157931365184549694">Geri yükle</translation>
+<translation id="3162559335345991374">Kullandığınız Kablosuz ağ, giriş sayfasını ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="3167968892399408617">Gizli sekmelerde görüntülediğiniz sayfalar, açık olan tüm gizli sekmeler kapatıldıktan sonra tarayıcınızın geçmişinden, çerez deposundan veya arama geçmişinden silinecektir. İndirdiğiniz dosyalar veya oluşturduğunuz yer işaretleri kalacaktır.</translation>
<translation id="3169472444629675720">Bul</translation>
<translation id="3174168572213147020">Ada</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Ödemeyi iptal et</translation>
<translation id="3207960819495026254">Yer işareti koyuldu</translation>
+<translation id="3211223744486044430">Bir dahaki sefere daha hızlı ödeme yapmak için bu kartı Google Hesabınıza ve bu cihaza kaydedin.</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>
<translation id="3226128629678568754">Sayfayı yüklemek üzere gereken verileri tekrar göndermek için yeniden yükle düğmesine basın.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Arama sonucu bulunamadı</translation>
<translation id="3305707030755673451">Verileriniz <ph name="TIME" /> tarihinde senkronizasyon parolanızla şifrelendi. Senkronizasyonu başlatmak için senkronizasyon parolanızı girin.</translation>
<translation id="3320021301628644560">Fatura adresi ekle</translation>
-<translation id="3329013043687509092">Doygunluk</translation>
<translation id="333371639341676808">Bu sayfanın ek iletişim kutusu oluşturmasına izin verme.</translation>
<translation id="3338095232262050444">Güvenli</translation>
<translation id="3340978935015468852">ayarlar</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">İstemci Kimliği:</translation>
<translation id="3391030046425686457">Teslimat adresi</translation>
<translation id="3395827396354264108">Alım yöntemi</translation>
+<translation id="3399952811970034796">Teslimat Adresi</translation>
<translation id="3422248202833853650">Bellekte yer açmak için diğer programlardan çıkmayı deneyin.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ana makinesine şu anda ulaşılamıyor.</translation>
<translation id="3427092606871434483">İzin ver (varsayılan)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Kilitlenme raporunun oluşturulma zamanı: <ph name="CRASH_TIME" />, raporun yüklenme zamanı: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifika bilgileri</translation>
<translation id="3690164694835360974">Giriş yapma işlemi güvenli değil</translation>
+<translation id="3704162925118123524">Kullandığınız ağ bir giriş sayfasını ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Yükleniyor...</translation>
<translation id="3712624925041724820">Lisanslar bitti</translation>
<translation id="3714780639079136834">Mobil veriyi veya kablosuz bağlantıyı açma</translation>
+<translation id="3715597595485130451">Kablosuz Ağa Bağlanma</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, güvenlik duvarı ve DNS yapılandırmasını kontrol etme<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Güvenliğinizle ilgili riskleri anlıyorsanız tehlikeli programlar kaldırılmadan önce <ph name="BEGIN_LINK" />güvenli olmayan bu siteyi ziyaret edebilirsiniz<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">Kopyaladığınız bağlantı</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">Eklemeyi &amp;geri al</translation>
<translation id="404928562651467259">UYARI</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" anahtarı: <ph name="ERROR" /></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>
<translation id="4079302484614802869">Proxy yapılandırması sabit proxy sunucuları değil, bir .pac komut dosyası URL'sini kullanmak üzere ayarlandı.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Cihazın seri numarası geçersiz</translation>
<translation id="410351446219883937">Otomatik oynatma</translation>
<translation id="4103763322291513355">Kara listeye alınmış 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="4115378294792113321">Macenta</translation>
<translation id="4116663294526079822">Bu sitede her zaman izin ver</translation>
<translation id="4117700440116928470">Politika kapsamı desteklenmiyor.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 öğe daha}other{# öğe daha}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719"><ph name="DOMAIN" /> adresine ulaşmayı denediniz, ancak sunucunun sağladığı sertifika, sertifikayı veren tarafından iptal edildi. Bu, sunucunun sağladığı güvenlik kimlik bilgilerine kesinlikle güvenilmemesi gerektiği anlamına gelir. Bir saldırganla irtibat kuruyor olabilirsiniz.</translation>
<translation id="4394049700291259645">Devre dışı bırak</translation>
<translation id="4406896451731180161">arama sonuçları</translation>
+<translation id="4415426530740016218">Alınacağı Adres</translation>
<translation id="4424024547088906515">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Chrome, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> giriş sertifikanızı kabul etmedi veya giriş sertifikası sağlanmamış olabilir.</translation>
<translation id="443673843213245140">Proxy kullanımı devre dışı, ancak açık bir proxy yapılandırması belirtildi.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Uzantılarınızı devre dışı bırakmayı deneyin</translation>
<translation id="457875822857220463">Teslimat</translation>
+<translation id="4582800630050655161">Google Hesabınıza erişimi kaybedebilir veya kimlik hırsızlığına maruz kalabilirsiniz. Chromium, şifrenizi hemen değiştirmenizi önerir.</translation>
<translation id="4587425331216688090">Adres Chrome'dan kaldırılsın mı?</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> ile olan bağlantınız modern bir şifre seti kullanılarak şifrelendi.</translation>
<translation id="4594403342090139922">Silmeyi &amp;Geri Al</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Geçersiz sertifika kullanımını durdur</translation>
+<translation id="4690954380545377795">Google Hesabınıza erişimi kaybedebilir veya kimlik hırsızlığına maruz kalabilirsiniz. Chrome, şifrenizi hemen değiştirmenizi önerir.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Bağlantınız kesildi</translation>
<translation id="471880041731876836">Bu siteyi ziyaret etmek için izniniz yok</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Ağ Teşhislerini Çalıştırma<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Ödemeniz</translation>
<translation id="4726672564094551039">Politikaları yeniden yükle</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4736825316280949806">Chromium'u yeniden başlatın</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Yedekleme deposu kötü durumda</translation>
<translation id="5023310440958281426">Yöneticinizin politikalarını inceleyin.</translation>
<translation id="5029568752722684782">Kopyayı temizle</translation>
+<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" için bir kök sertifika gerekli, ancak yüklenmemiş. BT yöneticiniz bu sorunu çözmek için "<ph name="SOFTWARE_NAME" />" ile ilgili yapılandırma talimatlarına bakmalıdır. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Google Çeviri Hakkında</translation>
<translation id="5039804452771397117">İzin ver</translation>
<translation id="5040262127954254034">Gizlilik</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Deneyler</translation>
<translation id="5205222826937269299">Ad gerekli</translation>
<translation id="5222812217790122047">E-posta gerekli</translation>
+<translation id="522700295135997067">Bu site az önce şifrenizi çalmış olabilir</translation>
+<translation id="5230733896359313003">Gönderim Adresi</translation>
<translation id="5251803541071282808">Bulut</translation>
<translation id="5277279256032773186">Chrome'u işte mi kullanıyorsunuz? İşletmeler, çalışanları için Chrome ayarlarını yönetebilir. Daha fazla bilgi edinin</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Web'e ulaşabilmeniz amacıyla yazılımı geçici olarak devre dışı bırakmak için bu adımları uygulayın. Bu adımları gerçekleştirmek için yönetici ayrıcalıklarınızın olması gerekir.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Bu siteyle bağlantınız gizli değil. VR modundan istediğiniz zaman çıkmak için başlığı çıkarıp Geri düğmesine basın.</translation>
<translation id="5299298092464848405">Politika ayrıştırma hatası</translation>
+<translation id="5308380583665731573">Bağlan</translation>
<translation id="5308689395849655368">Kilitlenme bildirme devre dışı.</translation>
<translation id="5317780077021120954">Kaydet</translation>
<translation id="5327248766486351172">Ad</translation>
+<translation id="5332219387342487447">Gönderim Yöntemi</translation>
<translation id="5355557959165512791">Sertifikası iptal edildiği için <ph name="SITE" /> sitesini şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan, bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="536296301121032821">Politika ayarları saklanamadı</translation>
<translation id="5386426401304769735">Bu sitenin sertifika zinciri, SHA-1 kullanılarak imzalanmış bir sertifika içeriyor.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Şirket, kuruluş veya okul intranet'indeki bu site harici bir web sitesiyle aynı URL'ye sahip.
<ph name="LINE_BREAK" />
Sistem yöneticinize başvurmayı deneyin.</translation>
+<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> kartının güvenlik kodunu girin. Bu kod kaydedilmez.</translation>
<translation id="5509780412636533143">Yönetilen yer işaretleri</translation>
<translation id="5510766032865166053">Taşınmış veya silinmiş olabilir.</translation>
<translation id="5523118979700054094">Politika adı</translation>
<translation id="552553974213252141">Metin doğru bir şekilde çıkarıldı mı?</translation>
<translation id="5540224163453853">İstenen makale bulunamadı.</translation>
+<translation id="5541546772353173584">E-posta Adresi Ekleyin</translation>
<translation id="5544037170328430102"><ph name="SITE" /> web sitesindeki yerleşik bir sayfanın mesajı:</translation>
+<translation id="5545756402275714221">Sizin için Seçilmiş Makaleler</translation>
<translation id="5556459405103347317">Yeniden Yükle</translation>
<translation id="5560088892362098740">Son Kullanma Tarihi</translation>
<translation id="5565735124758917034">Etkin</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">E-posta</translation>
<translation id="5669703222995421982">Kişiselleştirilmiş içerikler alma</translation>
<translation id="5675650730144413517">Bu sayfa çalışmıyor</translation>
+<translation id="5689199277474810259">JSON'a aktar</translation>
<translation id="5710435578057952990">Bu web sitesinin kimliği doğrulanmadı.</translation>
<translation id="5719499550583120431">Ön ödemeli kartlar kabul edilir.</translation>
<translation id="5720705177508910913">Geçerli kullanıcı</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065"><ph name="DOMAIN" /> ile olan bağlantınız eski bir şifre seti kullanılarak şifrelendi.</translation>
<translation id="5813119285467412249">Eklemeyi &amp;Yeniden Yap</translation>
<translation id="5838278095973806738">Bu sitede hiçbir hassas bilginizi (örneğin şifrelerinizi veya kredi kartı bilgilerinizi) girmemelisiniz. Aksi takdirde bu bilgiler saldırganlar tarafından çalınabilir.</translation>
+<translation id="5866257070973731571">Telefon Numarası Ekleyin</translation>
<translation id="5869405914158311789">Bu siteye ulaşılamıyor</translation>
<translation id="5869522115854928033">Kayıtlı şifreler</translation>
<translation id="5872918882028971132">Ebeveyn Önerileri</translation>
<translation id="5893752035575986141">Kredi kartları kabul edilir.</translation>
-<translation id="5901630391730855834">Sarı</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (senkronize edildi)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 çerez kullanımda}other{# çerez kullanımda}}</translation>
<translation id="5959728338436674663">Tehlikeli uygulamaların ve sitelerin tespit edilmesine yardımcı olmak için Google'a bazı <ph name="BEGIN_WHITEPAPER_LINK" />sistem bilgilerini ve sayfa içeriklerini<ph name="END_WHITEPAPER_LINK" /> otomatik olarak gönder.<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">İletişim Bilgilerini Düzenleyin</translation>
<translation id="5967867314010545767">Geçmişten kaldır.</translation>
<translation id="5975083100439434680">Uzaklaştır</translation>
+<translation id="597552863672748783">Güvenlik kodunu onaylayın</translation>
<translation id="598637245381783098">Ödeme uygulaması açılamıyor</translation>
<translation id="5989320800837274978">Sabit proxy sunucular veya bir .pac komut dosyası URL'si belirtilmedi.</translation>
<translation id="5990559369517809815">Sunucuya gönderilen istekler bir uzantı tarafından engellendi.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{1. sayfa}other{#. sayfa}}</translation>
-<translation id="6017514345406065928">Yeşil</translation>
<translation id="6017850046339264347"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> öğesini kullanan saldırganlar başka bir şeyi taklit eden aldatıcı uygulamalar yükleyebilir veya sizi izlemek için kullanılabilecek veriler toplayabilirler. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (senkronize edildi)</translation>
<translation id="6027201098523975773">Bir ad girin</translation>
<translation id="6040143037577758943">Kapat</translation>
-<translation id="6042308850641462728">Daha fazla</translation>
<translation id="6047233362582046994">Güvenliğinize ilişkin riskleri anladıysanız zararlı programlar kaldırılmadan önce <ph name="BEGIN_LINK" />bu siteyi ziyaret edebilirsiniz<ph name="END_LINK" />.</translation>
<translation id="6047927260846328439">Bu içerik sizi kandırarak yazılım yüklemenizi veya kişisel bilgilerinizi ifşa etmenizi sağlamaya çalışabilir. <ph name="BEGIN_LINK" />Yine de göster<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> sitesi sertifika sabitleme yöntemi kullandığından siteyi şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Bir uzantı sayfası görüntülüyorsunuz</translation>
<translation id="6596325263575161958">Şifreleme seçenekleri</translation>
<translation id="662080504995468778">Kal</translation>
+<translation id="6624427990725312378">İletişim Bilgileri</translation>
<translation id="6626291197371920147">Geçerli kart numarası ekle</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Arama</translation>
<translation id="6630809736994426279">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sitesindeki saldırganlar bilgilerinizi (örneğin, fotoğraflar, şifreler, mesajlar ve kredi kartları) çalabilecek veya silebilecek tehlikeli programları Mac'inize yüklemeye çalışabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Önceki</translation>
<translation id="6710594484020273272">&lt;Arama terimini yazın&gt;</translation>
<translation id="6711464428925977395">Proxy sunucusunda bir sorun var veya adres yanlış.</translation>
-<translation id="6727102863431372879">Ayarla</translation>
<translation id="674375294223700098">Bilinmeyen sunucu sertifikası hatası.</translation>
<translation id="6753269504797312559">Politika değeri</translation>
<translation id="6757797048963528358">Cihazınız uyku moduna geçti.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Profil Yolu</translation>
<translation id="7424977062513257142">Bu web sayfasındaki yerleşik bir sayfanın mesajı:</translation>
+<translation id="7437289804838430631">İletişim Bilgisi Ekle</translation>
<translation id="7441627299479586546">Politika konusu yanlış</translation>
<translation id="7444046173054089907">Bu site engellenmiş</translation>
<translation id="7445762425076701745">Bağlı olduğunuz sunucunun kimliği tam olarak doğrulanamıyor. Sunucuya yalnızca ağınızın içinde geçerli olan ve dış sertifika yetkilisi tarafından hiçbir şekilde sahipliği doğrulanamayacak bir ad kullanarak bağlandınız. Bazı sertifika yetkilileri bu adlar için sertifikalar yayınlasa da, bir saldırgana değil, hedeflenen web sitesine bağlandığınızdan emin olmanın herhangi bir yolu yoktur.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">İleri</translation>
<translation id="7485870689360869515">Hiçbir veri bulunamadı.</translation>
<translation id="7508255263130623398">Döndürülen politika cihaz kimliği boş veya mevcut cihaz kimliğiyle eşleşmiyor</translation>
+<translation id="7511955381719512146">Kullandığınız kablosuz bağlantı ağı, <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> adresini ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="7514365320538308">İndir</translation>
<translation id="7518003948725431193">Şu web adresi için web sayfası bulunamadı:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Bu siteye bağlantınız gizli değil</translation>
-<translation id="7535087603100972091">Değer</translation>
<translation id="7537536606612762813">Zorunlu</translation>
<translation id="7542403920425041731">Onayladığınızda kart ayrıntılarınız bu siteyle paylaşılacaktır.</translation>
<translation id="7542995811387359312">Bu form güvenli bağlantı kullanmadığından kredi kartı bilgilerini otomatik doldurma özelliği devre dışı bırakıldı.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası hileli bir şekilde yayınlanmış olabilir. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="7568593326407688803">Bu sayfanın dili<ph name="ORIGINAL_LANGUAGE" />Çevrilmesini istiyor musunuz?</translation>
<translation id="7569952961197462199">Kredi kartı Chrome'dan kaldırılsın mı?</translation>
-<translation id="7569983096843329377">Siyah</translation>
<translation id="7578104083680115302">Google'a kaydettiğiniz kartları kullanarak farklı cihazlardan sitelerde ve uygulamalarda ödemelerinizi hızla yapabilirsiniz.</translation>
<translation id="7588950540487816470">Fiziksel Web</translation>
<translation id="7592362899630581445">Sunucunun sertifikası ad sınırlamasını ihlal ediyor.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Bu sitedeki saldırganlar web'e göz atma deneyiminize zarar veren programlar yüklemeniz için sizi kandırmayı (örneğin ana sayfanızı değiştirerek ya da ziyaret ettiğiniz sitelerde ek reklamlar görüntüleyerek) deneyebilir.</translation>
<translation id="7674629440242451245">Chrome'daki etkileyici, yeni özellikler ilginizi çekiyor mu? chrome.com/dev adresinden geliştirici kanalımızı deneyin.</translation>
<translation id="7682287625158474539">Sevkiyat</translation>
+<translation id="7699293099605015246">Makaleler şu anda kullanılamıyor</translation>
<translation id="7701040980221191251">Yok</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> sitesine ilerle (güvenli değil)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Sertifika</translation>
<translation id="7716147886133743102">Yöneticiniz tarafından engellendi</translation>
<translation id="7716424297397655342">Bu site önbellekten yüklenemiyor</translation>
+<translation id="7723047071702270851">Kartı Düzenleyin</translation>
<translation id="774634243536837715">Tehlikeli içerik engellendi.</translation>
<translation id="7752995774971033316">Yönetimden kaldırıldı</translation>
<translation id="7755287808199759310">Ebeveyniniz engellemeyi sizin için kaldırabilir</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Adres ekle</translation>
<translation id="777702478322588152">İdari bölge</translation>
<translation id="7791543448312431591">Ekle</translation>
+<translation id="7793553086574152071">Bir dahaki sefere daha hızlı ödeme yapmak için bu kartı Google Hesabınıza kaydedin.</translation>
<translation id="7793809570500803535"><ph name="SITE" /> adresindeki Web sayfası geçici olarak kullanılamıyor veya kalıcı olarak yeni bir Web adresine taşınmış olabilir.</translation>
<translation id="7800304661137206267">Bağlantı, ileti kimlik doğrulaması için <ph name="MAC" /> ve anahtar değişim mekanizması olarak <ph name="KX" /> kullanılan <ph name="CIPHER" /> ile şifrelenmiştir.</translation>
+<translation id="7802523362929240268">Site meşrudur</translation>
<translation id="780301667611848630">Hayır, teşekkürler</translation>
<translation id="7805768142964895445">Durum</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Form önerisi Chrome'dan kaldırılsın mı?</translation>
<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" için <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> bulundu.</translation>
+<translation id="782886543891417279">Kullandığınız kablosuz bağlantı ağı (<ph name="WIFI_NAME" />) giriş sayfasını ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="785549533363645510">Ancak görünmez olmazsınız. Gizli moda geçmek göz atma etkinliğinizi işvereninizden, İnternet servis sağlayıcınızdan veya ziyaret ettiğiniz web sitelerinden gizlemez.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Banka kartları ve ön ödemeli kartlar kabul edilir.</translation>
+<translation id="7878562273885520351">Şifrenizin güvenliği ihlal edilmiş olabilir</translation>
<translation id="7887683347370398519">CVC'nizi kontrol edin ve tekrar deneyin</translation>
<translation id="79338296614623784">Geçerli bir telefon numarası girin</translation>
<translation id="7935318582918952113">DOM Ayrıştırıcı</translation>
<translation id="7938958445268990899">Sunucunun sertifikası henüz geçerli değil.</translation>
-<translation id="7942349550061667556">Kırmızı</translation>
<translation id="7947285636476623132">Son kullanma tarihinin yılını kontrol edip tekrar deneyin</translation>
<translation id="7951415247503192394">(32 bit)</translation>
<translation id="7956713633345437162">Mobil yer işaretleri</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Sor (varsayılan)</translation>
<translation id="8041089156583427627">Görüş bildirin</translation>
<translation id="8041940743680923270">Genel varsayılanı kullan (Sor)</translation>
+<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" doğru şekilde yapılandırılmamış. Genellikle "<ph name="SOFTWARE_NAME" />" kaldırıldığında sorun çözülür. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Makale görüntülenemedi.</translation>
<translation id="8091372947890762290">Etkinleştirme sunucuda bekliyor</translation>
+<translation id="8094917007353911263">Kullandığınız ağ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> adresini ziyaret etmenizi gerektiriyor olabilir.</translation>
+<translation id="8103161714697287722">Ödeme Yöntemi</translation>
<translation id="8118489163946903409">Ödeme yöntemi</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" yazılımı bilgisayarınıza veya ağa düzgün şekilde yüklenmemiş. BT yöneticinizden sorunu çözmesini isteyin.</translation>
<translation id="8131740175452115882">Onayla</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ana makinesinin sunucu <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" /> bulunamadı.</translation>
<translation id="8149426793427495338">Bilgisayarınız uyku moduna geçti.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Bunun ne anlama geldiğini bilmiyorsanız ağ yöneticinizle bağlantı kurun.</translation>
<translation id="8293206222192510085">Yer İşareti Ekle</translation>
<translation id="8294431847097064396">Kaynak</translation>
+<translation id="8298115750975731693">Kullandığınız kablosuz bağlantı ağı (<ph name="WIFI_NAME" />) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> adresini ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="8306404619377842860">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" /> ile gizli bağlantı kurulamıyor. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Ağ bağlantısıyla ilgili bir sorun nedeniyle çeviri başarısız oldu.</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ana makinesine erişim reddedildi</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Son Kapatılan</translation>
<translation id="8874824191258364635">Geçerli bir kart numarası girin</translation>
<translation id="8876793034577346603">Ağ yapılandırması ayrıştırılamadı.</translation>
-<translation id="8889402386540077796">Ton</translation>
<translation id="8891727572606052622">Geçersiz proxy modu.</translation>
<translation id="889901481107108152">Maalesef bu deney platformunuzda kullanılamıyor.</translation>
<translation id="8903921497873541725">Yakınlaştır</translation>
<translation id="8931333241327730545">Bu kartı Google Hesabınıza kaydetmek istiyor musunuz?</translation>
<translation id="8932102934695377596">Saatiniz geri</translation>
+<translation id="893332455753468063">Ad Ekleyin</translation>
<translation id="8938939909778640821">Kabul edilen kredi kartları ve ön ödemeli kartlar</translation>
+<translation id="8957210676456822347">Giriş Portalı Yetkilendirmesi</translation>
<translation id="8971063699422889582">Sunucu sertifikasının süresi doldu.</translation>
-<translation id="8986494364107987395">Kullanım istatistiklerini ve çökme raporlarını otomatik olarak Google'a gönder</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Girmekte olduğunuz site zararlı programlar içermektedir</translation>
<translation id="8997023839087525404">Sunucu, Sertifika Şeffaflığı politikası kullanılarak herkese açık bir şekilde açıklanmayan bir sertifika sundu. Güvenilir olduklarından emin olmak ve saldırganlara karşı koruma sağlamak için bazı sertifikalarda bu zorunludur.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> proxy'si için kullanıcı adı ve şifre gerekiyor.</translation>
<translation id="9005998258318286617">PDF dokümanı yüklenemedi.</translation>
+<translation id="9008201768610948239">Yoksay</translation>
<translation id="901974403500617787">Tüm sistem için geçerli olan işaretler sadece sahibi <ph name="OWNER_EMAIL" /> tarafından ayarlanabilir.</translation>
<translation id="9020200922353704812">Kartın fatura adresi gerekli</translation>
<translation id="9020542370529661692">Bu sayfa <ph name="TARGET_LANGUAGE" /> diline çevrildi</translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619"><ph name="DOMAIN" /> alan adına erişmeye çalıştınız, ancak sunucu geçersiz bir sertifika sağladı.</translation>
<translation id="9050666287014529139">Parola</translation>
<translation id="9065203028668620118">Düzenle</translation>
-<translation id="9068849894565669697">Renk seçin</translation>
<translation id="9069693763241529744">Bir uzantı tarafından engellendi</translation>
<translation id="9076283476770535406">Yetişkin içeriği bulunabilir</translation>
<translation id="9078964945751709336">Daha fazla bilgi gerekli</translation>
+<translation id="9080712759204168376">Sipariş Özeti</translation>
<translation id="9103872766612412690"><ph name="SITE" /> normalde bilgilerinizi korumak için şifreleme kullanmaktadır. Chromium bu sefer <ph name="SITE" /> sitesine bağlanmayı denediğinde, web sitesi sıra dışı ve yanlış kimlik bilgileri döndürdü. Bir saldırgan <ph name="SITE" /> gibi davranmaya çalışıyor olabilir ya da bir Kablosuz oturum açma ekranı bağlantıyı kesmiştir. Chromium herhangi bir veri alışverişinden önce bağlantıyı durdurduğu için bilgileriniz hâlâ güvendedir.</translation>
+<translation id="9106062320799175032">Fatura Adresi Ekleyin</translation>
+<translation id="910908805481542201">Bunu düzeltmeme yardım edin</translation>
+<translation id="9128870381267983090">Ağa bağlan</translation>
<translation id="9137013805542155359">Orijinali göster</translation>
<translation id="9137248913990643158">Lütfen bu uygulamayı kullanmadan önce Chrome'u başlatıp oturum açın.</translation>
<translation id="9148507642005240123">Düzenlemeyi &amp;geri al</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> desteklenmeyen bir protokol kullanıyor.</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="9215416866750762878">Bir uygulama, Chrome'un bu siteye güvenli bir şekilde bağlanmasını engelliyor</translation>
<translation id="9219103736887031265">Resimler</translation>
<translation id="933612690413056017">İnternet bağlantısı yok</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Yok}=1{1 öğe}other{# öğe}}</translation>
<translation id="981121421437150478">Çevrimdışı</translation>
<translation id="988159990683914416">Geliştirici Derlemesi</translation>
+<translation id="989988560359834682">Adresi Düzenle</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" yazılımı bilgisayarınıza veya ağa düzgün şekilde yüklenmemiş:
+ &lt;ul&gt;
+ &lt;li&gt;"<ph name="SOFTWARE_NAME" />" yazılımının yüklemesini kaldırmayı veya devre dışı bırakmayı deneyin&lt;/li&gt;
+ &lt;li&gt;Başka bir kablosuz ağa bağlanmayı deneyin&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index a030a989596..d0c9390871a 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Закладки для настільного комп’ютера</translation>
<translation id="1074497978438210769">Не конфіденційний</translation>
<translation id="1080116354587839789">За шириною сторінки</translation>
+<translation id="1088860948719068836">Додайте ім’я на картці</translation>
<translation id="1103523840287552314">Завжди перекладати з такої мови: <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Показати всі збережені паролі…</translation>
<translation id="1107591249535594099">Якщо вибрати цю опцію, Chrome зберігатиме копію даних вашої картки на цьому пристрої для швидшого заповнення форм.</translation>
<translation id="1111153019813902504">Останні закладки</translation>
<translation id="1113869188872983271">&amp;Відмінити перевпорядкування</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (синхронізовано)</translation>
<translation id="1263231323834454256">Список читання</translation>
<translation id="1264126396475825575">Звіт про аварійне завершення роботи о <ph name="CRASH_TIME" /> (ще не завантажено або пропущено)</translation>
+<translation id="1270502636509132238">Спосіб отримання</translation>
<translation id="1281526147609854549">Видано <ph name="ISSUER" /></translation>
<translation id="1285320974508926690">Ніколи не перекладати цей сайт</translation>
<translation id="129553762522093515">Нещодавно закриті</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Очікується з’єднання…</translation>
<translation id="153384715582417236">Більше нічого немає</translation>
<translation id="1549470594296187301">Щоб користуватися цією функцією, потрібно ввімкнути JavaScript.</translation>
-<translation id="1555130319947370107">Синій</translation>
<translation id="1559528461873125649">Такого файла або каталогу немає</translation>
<translation id="1583429793053364125">Під час показу цієї сторінки сталася помилка.</translation>
<translation id="1592005682883173041">Доступ до локальних даних</translation>
<translation id="1594030484168838125">Вибрати</translation>
-<translation id="161042844686301425">Бірюзовий</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1629803312968146339">Зберегти цю картку в Chrome?</translation>
<translation id="1639239467298939599">Завантаження</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">ОС</translation>
<translation id="1721312023322545264">Вам потрібен дозвіл адміністратора <ph name="NAME" />, щоб перейти на цей сайт</translation>
<translation id="1721424275792716183">* Обов’язкове поле</translation>
+<translation id="1727741090716970331">Додайте дійсний номер картки</translation>
<translation id="1728677426644403582">Ви переглядаєте джерело веб-сторінки</translation>
<translation id="173080396488393970">Цей тип картки не підтримується</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Помилка серіалізації</translation>
<translation id="1974060860693918893">Розширені</translation>
<translation id="1978555033938440688">Версія мікропрограми</translation>
-<translation id="1995859865337580572">Підтвердьте CVC</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{і ще 1}one{і ще #}few{і ще #}many{і ще #}other{і ще #}}</translation>
<translation id="2025186561304664664">Проксі-сервер установлено на автоматичне налаштування.</translation>
<translation id="2030481566774242610">Можливо, ви мали на увазі <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">Відмінити</translation>
<translation id="20817612488360358">Системні параметри проксі-сервера налаштовано для використання, але чітко вказано налаштування проксі-сервера.</translation>
<translation id="2086652334978798447">Щоб отримувати персоналізовані пропозиції від Google, увійдіть в обліковий запис Chrome.</translation>
+<translation id="2091887806945687916">Сигнал</translation>
<translation id="2094505752054353250">Невідповідність домену</translation>
<translation id="2096368010154057602">Департамент</translation>
<translation id="2108755909498034140">Перезавантажте комп’ютер</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Правило ігнорується, оскільки його замінено правилом <ph name="POLICY_NAME" />.</translation>
<translation id="2138201775715568214">Пошук веб-сторінок у сервісі "Інтернет навколо нас"</translation>
<translation id="213826338245044447">Закладки для мобільних пристроїв</translation>
+<translation id="214556005048008348">Скасувати оплату</translation>
<translation id="2147827593068025794">Фонова синхронізація</translation>
+<translation id="2148613324460538318">Додати картку</translation>
<translation id="2154054054215849342">Синхронізація недоступна для вашого домену</translation>
<translation id="2154484045852737596">Редагувати картку</translation>
<translation id="2166049586286450108">Повний адміністративний доступ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреса}one{# адреса}few{# адреси}many{# адрес}other{# адреси}}</translation>
<translation id="2187317261103489799">Визначати (за умовчанням)</translation>
<translation id="2202020181578195191">Введіть дійсний рік закінчення терміну дії</translation>
+<translation id="2209523182407020534">До додатків, що можуть спричиняти цю помилку, належать антивіруси, брандмауери й програмне забезпечення для фільтрування веб-вмісту чи доступу через проксі-сервери.</translation>
<translation id="2212735316055980242">Правило не знайдено</translation>
<translation id="2213606439339815911">Отримання записів…</translation>
<translation id="2218879909401188352">Зловмисники на сайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> можуть установити небезпечні додатки, які шкодять вашому пристрою, додають приховані платежі за мобільний зв’язок або викрадають особисту інформацію. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Назад</translation>
<translation id="2503184589641749290">Прийнятні дебетові та передплачені картки</translation>
<translation id="2515629240566999685">перевірити сигнал у своїй місцевості</translation>
+<translation id="2524461107774643265">Додайте більше інформації</translation>
+<translation id="2536110899380797252">Додати адресу</translation>
<translation id="2539524384386349900">Визначити</translation>
<translation id="255002559098805027">Хост <ph name="HOST_NAME" /> надіслав недійсну відповідь.</translation>
<translation id="2556876185419854533">&amp;Відмінити редагування</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium не вдалося підтвердити дані вашої картки. Спробуйте пізніше.</translation>
<translation id="2705137772291741111">Не вдається прочитати збережену (кешовану) копію цього сайту.</translation>
<translation id="2709516037105925701">Автозаповнення</translation>
+<translation id="2710942282213947212">Програмне забезпечення на вашому комп’ютері перешкоджає Chromium безпечно під’єднуватися до Інтернету</translation>
<translation id="2712173769900027643">Запитувати дозвіл</translation>
-<translation id="2713444072780614174">Білий</translation>
<translation id="2720342946869265578">Поблизу</translation>
<translation id="2721148159707890343">Запит надіслано</translation>
<translation id="2728127805433021124">Сертифікат сервера підписано з використанням слабкого алгоритму підпису.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Виявлено зміну в мережі.</translation>
<translation id="2916038427272391327">Закрийте інші програми</translation>
<translation id="2922350208395188000">Сертифікат сервера неможливо перевірити.</translation>
+<translation id="2925673989565098301">Спосіб доставки</translation>
<translation id="2928905813689894207">Платіжна адреса</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}few{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}many{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Його сертифікат безпеки походить із домену <ph name="DOMAIN2" />. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Неправильний тип правила</translation>
<translation id="3032412215588512954">Оновити цей сайт?</translation>
<translation id="3037605927509011580">От халепа!</translation>
+<translation id="3039538478787849737">Зберегти картку в Google?</translation>
<translation id="3041612393474885105">Інформація про сертифікат</translation>
<translation id="3063697135517575841">Chrome не вдалося підтвердити дані вашої картки. Спробуйте пізніше.</translation>
<translation id="3064966200440839136">Щоб оплатити в зовнішньому додатку, ви вийдете з режиму анонімного перегляду. Продовжити?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Тимчасова помилка сервера</translation>
<translation id="3154506275960390542">Ця сторінка містить незахищену форму. Інші люди можуть бачити дані під час передавання, а зловмисники можуть змінювати їх.</translation>
<translation id="3157931365184549694">Відновити</translation>
+<translation id="3162559335345991374">Можливо, щоб під’єднатися до цієї мережі Wi-Fi, потрібно відвідати її сторінку входу.</translation>
<translation id="3167968892399408617">Сторінки, які ви переглядаєте на анонімних вкладках, не реєструються в історії веб-переглядача чи історії пошуку та не залишають файлів cookie, коли ви закриваєте всі анонімні вкладки. Усі завантажені файли чи створені закладки зберігаються.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Острів</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Скасувати оплату</translation>
<translation id="3207960819495026254">Створено закладку</translation>
+<translation id="3211223744486044430">Щоб наступного разу платити швидше, збережіть цю картку у своєму обліковому записі Google і на цьому пристрої.</translation>
<translation id="3225919329040284222">Сервер надав сертифікат, який не відповідає очікуваним вбудованим параметрам. Ці очікувані параметри встановлено для певних веб-сайтів із високим рівнем безпеки, щоб захистити вас.</translation>
<translation id="3226128629678568754">Натисніть кнопку перезавантаження, щоб повторно надіслати дані, потрібні для завантаження сторінки.</translation>
<translation id="3227137524299004712">Мікрофон</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Немає результатів</translation>
<translation id="3305707030755673451">Ваші дані було зашифровано <ph name="TIME" /> за допомогою парольної фрази для синхронізації. Введіть її, щоб почати синхронізацію.</translation>
<translation id="3320021301628644560">Додати платіжну адресу</translation>
-<translation id="3329013043687509092">Насиченість</translation>
<translation id="333371639341676808">Заборонити створення додаткових діалогових вікон цією сторінкою.</translation>
<translation id="3338095232262050444">Надійне</translation>
<translation id="3340978935015468852">налаштування</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">Ідентифікатор клієнта:</translation>
<translation id="3391030046425686457">Адреса доставки</translation>
<translation id="3395827396354264108">Спосіб отримання</translation>
+<translation id="3399952811970034796">Адреса доставки</translation>
<translation id="3422248202833853650">Щоб звільнити пам’ять, закрийте інші програми.</translation>
<translation id="3422472998109090673">Хост <ph name="HOST_NAME" /> зараз недоступний.</translation>
<translation id="3427092606871434483">Дозволяти (за умовчанням)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Звіт про аварійне завершення роботи створено: <ph name="CRASH_TIME" />, завантажено: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Інформація про сертифікат</translation>
<translation id="3690164694835360974">Вхід не захищено</translation>
+<translation id="3704162925118123524">Можливо, щоб з’єднатися з цією мережею, потрібно відвідати її сторінку входу.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Завантаження...</translation>
<translation id="3712624925041724820">Ліцензії вичерпано</translation>
<translation id="3714780639079136834">увімкнути мобільний Інтернет або Wi-Fi</translation>
+<translation id="3715597595485130451">Під’єднання до мережі Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />перевірити конфігурацію проксі-сервера, брандмауера та DNS-сервера<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Якщо ви розумієте ризики, пов’язані з безпекою, <ph name="BEGIN_LINK" />перейдіть на цей ненадійний сайт<ph name="END_LINK" /> до того, як небезпечні програми буде видалено.</translation>
<translation id="3739623965217189342">Скопійоване посилання</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Відмінити додавання</translation>
<translation id="404928562651467259">ЗАСТЕРЕЖЕННЯ</translation>
<translation id="4058922952496707368">Ключ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
+<translation id="4067947977115446013">Додайте дійсну адресу</translation>
<translation id="4072486802667267160">Не вдалось обробити ваше замовлення. Повторіть спробу.</translation>
<translation id="4075732493274867456">Клієнт і сервер підтримують різні версії протоколу SSL або набору шифрів.</translation>
<translation id="4079302484614802869">Конфігурацію проксі-сервера налаштовано на використання URL-адреси сценарію .pac, а не фіксованих проксі-серверів.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Недійсний серійний номер пристрою</translation>
<translation id="410351446219883937">Автовідтворення</translation>
<translation id="4103763322291513355">Перейдіть на сторінку &lt;strong&gt;chrome://policy&lt;/strong&gt;, щоб переглянути список URL-адрес із "чорного" списку й інші правила, що примусово застосовується системним адміністратором.</translation>
-<translation id="4115378294792113321">Пурпурний</translation>
<translation id="4116663294526079822">Завжди дозволяти на цьому сайті</translation>
<translation id="4117700440116928470">Правило не підтримується.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{і ще 1 елемент даних}one{і ще # елемент даних}few{і ще # елементи даних}many{і ще # елементів даних}other{і ще # елемента даних}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Ви пробували зв’язатися з доменом <ph name="DOMAIN" />, проте сервер надав сертифікат, відкликаний його видавцем. Це означає, що не варто довіряти обліковим даним системи захисту, наданим сервером. Можливо, ви обмінюєтеся даними зі зловмисником.</translation>
<translation id="4394049700291259645">Вимкнути</translation>
<translation id="4406896451731180161">результати пошуку</translation>
+<translation id="4415426530740016218">Адреса отримання</translation>
<translation id="4424024547088906515">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Chrome не вважає його сертифікат безпеки надійним. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
<translation id="4432688616882109544">Хост <ph name="HOST_NAME" /> не прийняв ваш сертифікат входу або ви не надали цей сертифікат.</translation>
<translation id="443673843213245140">Використання проксі-сервера вимкнено, але чітко вказано налаштування проксі-сервера.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Спробуйте вимкнути розширення.</translation>
<translation id="457875822857220463">Доставка</translation>
+<translation id="4582800630050655161">Ви можете втратити доступ до облікового запису Google або хтось може викрасти вашу особисту інформацію. Chromium радить змінити пароль.</translation>
<translation id="4587425331216688090">Видалити адресу з Chrome?</translation>
<translation id="4592951414987517459">З’єднання з доменом <ph name="DOMAIN" /> шифрується за допомогою сучасного набору шифрів.</translation>
<translation id="4594403342090139922">&amp;Відмінити видалення</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Його сертифікат безпеки містить помилки. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
<translation id="4690462567478992370">Припинити використання недійсного сертифіката</translation>
+<translation id="4690954380545377795">Ви можете втратити доступ до облікового запису Google або хтось може викрасти вашу особисту інформацію. Chrome радить змінити пароль.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">З’єднання розірвано</translation>
<translation id="471880041731876836">У вас немає дозволу відвідувати цей сайт</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />провести діагностику мережі Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Ваш платіж</translation>
<translation id="4726672564094551039">Перезавантажити правила</translation>
<translation id="4728558894243024398">Платформа</translation>
<translation id="4736825316280949806">Перезапустіть Chromium</translation>
@@ -510,7 +527,8 @@
<translation id="5019198164206649151">Резервний носій пошкоджено</translation>
<translation id="5023310440958281426">Перегляньте правила свого адміністратора</translation>
<translation id="5029568752722684782">Видалити копію</translation>
-<translation id="5031870354684148875">Про Перекладач Google</translation>
+<translation id="503069730517007720">Для програмного забезпечення <ph name="SOFTWARE_NAME" /> потрібен кореневий сертифікат, однак його не встановлено. Вашому IT-адміністратору потрібно переглянути вказівки з налаштування <ph name="SOFTWARE_NAME" />, щоб вирішити цю проблему. <ph name="FURTHER_EXPLANATION" /></translation>
+<translation id="5031870354684148875">Про Google Перекладач</translation>
<translation id="5039804452771397117">Дозволити</translation>
<translation id="5040262127954254034">Конфіденційність</translation>
<translation id="5045550434625856497">Неправильний пароль</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Експерименти</translation>
<translation id="5205222826937269299">Укажіть ім’я</translation>
<translation id="5222812217790122047">Укажіть електронну адресу</translation>
+<translation id="522700295135997067">Можливо, хтось на цьому сайті щойно викрав ваш пароль</translation>
+<translation id="5230733896359313003">Адреса доставки</translation>
<translation id="5251803541071282808">Хмара</translation>
<translation id="5277279256032773186">Користуєтеся Chrome на роботі? Компанії можуть налаштовувати Chrome для своїх працівників. Докладніше</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Виконайте ці дії, щоб тимчасово вимкнути програмне забезпечення й отримати доступ до Інтернету. Для цього потрібні права адміністратора.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Ваше з’єднання з цим сайтом не конфіденційне. Щоб будь-коли вийти з режиму віртуальної реальності, від’єднайте гарнітуру та натисніть кнопку "Назад".</translation>
<translation id="5299298092464848405">Помилка аналізу правила</translation>
+<translation id="5308380583665731573">Під’єднатися</translation>
<translation id="5308689395849655368">Повідомлення про аварійне завершення роботи вимкнено.</translation>
<translation id="5317780077021120954">Зберегти</translation>
<translation id="5327248766486351172">Назва</translation>
+<translation id="5332219387342487447">Спосіб доставки</translation>
<translation id="5355557959165512791">Зараз не можна перейти на сторінку <ph name="SITE" />, оскільки цей сертифікат відкликано. Помилки мережі й атаки зазвичай тимчасові, тому ця сторінка, скоріш за все, запрацює пізніше.</translation>
<translation id="536296301121032821">Помилка збереження налаштувань правила</translation>
<translation id="5386426401304769735">Ланцюжок сертифіката цього сайту містить сертифікат, підписаний за допомогою SHA-1.</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">URL-адреса цього сайту в інтранеті компанії, організації чи навчального закладу збігається з адресою зовнішнього веб-сайту.
<ph name="LINE_BREAK" />
Зв’яжіться зі своїм системним адміністратором.</translation>
+<translation id="5499929369096410817">Введіть код безпеки для картки <ph name="CREDIT_CARD" />. Цей код не буде збережено.</translation>
<translation id="5509780412636533143">Закладки, якими керує адміністратор</translation>
<translation id="5510766032865166053">Можливо, його переміщено або видалено.</translation>
<translation id="5523118979700054094">Назва правила</translation>
<translation id="552553974213252141">Текст отримано правильно?</translation>
<translation id="5540224163453853">Не вдалося знайти потрібну статтю.</translation>
+<translation id="5541546772353173584">Додайте електронну адресу</translation>
<translation id="5544037170328430102">Повідомлення з вбудованої сторінки сайту <ph name="SITE" />:</translation>
+<translation id="5545756402275714221">Статті для вас</translation>
<translation id="5556459405103347317">Перезавантажити</translation>
<translation id="5560088892362098740">Термін дії</translation>
<translation id="5565735124758917034">Активний клієнт</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Електронна пошта</translation>
<translation id="5669703222995421982">Отримувати персоналізовані пропозиції</translation>
<translation id="5675650730144413517">Сторінка не працює</translation>
+<translation id="5689199277474810259">Експортувати у формат JSON</translation>
<translation id="5710435578057952990">Ідентифікаційну інформацію цього веб-сайта не було перевірено.</translation>
<translation id="5719499550583120431">Передплачені картки, які приймаються.</translation>
<translation id="5720705177508910913">Поточний користувач</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">З’єднання з доменом <ph name="DOMAIN" /> шифрується за допомогою застарілого набору шифрів.</translation>
<translation id="5813119285467412249">&amp;Повторити додавання</translation>
<translation id="5838278095973806738">Не вводьте конфіденційну інформацію на цьому сайті (як-от паролі й дані кредитних карток). Зловмисники можуть викрасти її.</translation>
+<translation id="5866257070973731571">Додайте номер телефону</translation>
<translation id="5869405914158311789">Немає зв’язку із сайтом</translation>
<translation id="5869522115854928033">Збережені паролі</translation>
<translation id="5872918882028971132">Поради для батьків</translation>
<translation id="5893752035575986141">Кредитні картки, які приймаються.</translation>
-<translation id="5901630391730855834">Жовтий</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (синхронізовано)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Використовується 1 файл}one{Використовується # файл}few{Використовуються # файли}many{Використовуються # файлів}other{Використовуються # файлу}}</translation>
<translation id="5959728338436674663">Автоматично надсилати в Google деяку <ph name="BEGIN_WHITEPAPER_LINK" />інформацію про систему та вміст сторінок<ph name="END_WHITEPAPER_LINK" />, щоб допомогти виявляти небезпечні додатки й сайти<ph name="PRIVACY_PAGE_LINK" />.</translation>
+<translation id="5967592137238574583">Змініть контактну інформацію</translation>
<translation id="5967867314010545767">Видалити з історії</translation>
<translation id="5975083100439434680">Зменшити масштаб</translation>
+<translation id="597552863672748783">Підтвердьте код безпеки</translation>
<translation id="598637245381783098">Неможливо відкрити додаток для платежів</translation>
<translation id="5989320800837274978">Не вказано ні фіксованих проксі-серверів, ні URL-адрес сценарію .pac.</translation>
<translation id="5990559369517809815">Надсилання запитів на сервер заблоковано розширенням.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Сторінка 1}one{Сторінка #}few{Сторінка #}many{Сторінка #}other{Сторінка #}}</translation>
-<translation id="6017514345406065928">Зелений</translation>
<translation id="6017850046339264347">Зловмисники на сайті <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="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (синхронізовано)</translation>
<translation id="6027201098523975773">Введіть ім’я</translation>
<translation id="6040143037577758943">Закрити</translation>
-<translation id="6042308850641462728">Більше</translation>
<translation id="6047233362582046994">Якщо ви розумієте ризики, пов’язані з безпекою, можете <ph name="BEGIN_LINK" />перейти на цей сайт<ph name="END_LINK" />, перш ніж небезпечні додатки буде видалено.</translation>
<translation id="6047927260846328439">Цей вміст може оманливим шляхом змусити вас установити програмну або надати особисту інформацію. <ph name="BEGIN_LINK" />Усе одно показати<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Зараз не можна перейти на сторінку <ph name="SITE" />, оскільки цей веб-сайт використовує закріплення сертифікатів. Помилки мережі й атаки зазвичай тимчасові, тому ця сторінка, скоріш за все, запрацює пізніше.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Ви переглядаєте сторінку розширень</translation>
<translation id="6596325263575161958">Параметри шифрування</translation>
<translation id="662080504995468778">Залишитися</translation>
+<translation id="6624427990725312378">Контактна інформація</translation>
<translation id="6626291197371920147">Додати дійсний номер картки</translation>
<translation id="6628463337424475685">Пошук <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Зловмисники на сайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> можуть установити на ваш комп’ютер Mac небезпечні програми, що викрадають або видаляють інформацію (як-от фотографії, паролі, повідомлення та дані кредитних карток). <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Попереднє</translation>
<translation id="6710594484020273272">&lt;Введіть пошуковий термін&gt;</translation>
<translation id="6711464428925977395">Помилка проксі-сервера або неправильна адреса.</translation>
-<translation id="6727102863431372879">Встановити</translation>
<translation id="674375294223700098">Помилка "Невідомий сертифікат сервера".</translation>
<translation id="6753269504797312559">Значення правила</translation>
<translation id="6757797048963528358">Ваш пристрій перейшов у режим сну.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL-адреса</translation>
<translation id="7419106976560586862">Шлях до профілю</translation>
<translation id="7424977062513257142">Повідомлення з вбудованої сторінки на цій веб-сторінці:</translation>
+<translation id="7437289804838430631">Додати контактну інформацію</translation>
<translation id="7441627299479586546">Неправильна тема правила</translation>
<translation id="7444046173054089907">Цей сайт заблоковано</translation>
<translation id="7445762425076701745">Ідентифікацію сервера, з яким ви з'єднані, не можна повністю підтвердити. Ви з'єднані із сервером за допомогою імені, дійсного лише у вашій мережі, і зовнішній центр сертифікації не має способів підтвердити право власності на це ім'я. Хоча деякі центри сертифікації, попри все, видають сертифікати на такі імена, неможливо цілком упевнитися, що ви з'єднані з безпечним сайтом, а не зі зловмисником.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Переслати</translation>
<translation id="7485870689360869515">Даних не знайдено.</translation>
<translation id="7508255263130623398">Отриманий ідентифікатор правил пристрою порожній або не збігається з поточним ідентифікатором пристрою</translation>
+<translation id="7511955381719512146">Можливо, щоб під’єднатися до цієї мережі Wi-Fi, потрібно відвідати сторінку <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Завантажити</translation>
<translation id="7518003948725431193">Не знайдено веб-сторінок для веб-адреси <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Ваше з’єднання з цим сайтом не конфіденційне</translation>
-<translation id="7535087603100972091">Яскравість</translation>
<translation id="7537536606612762813">Обов’язкове</translation>
<translation id="7542403920425041731">Щойно ви підтвердите, цей сайт отримає доступ до даних вашої картки.</translation>
<translation id="7542995811387359312">Автоматичне заповнення кредитної картки вимкнено, оскільки ця форма не використовує безпечне з'єднання.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Можливо, його сертифікат безпеки видали шахраї. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
<translation id="7568593326407688803">Мова цієї сторінки:<ph name="ORIGINAL_LANGUAGE" />Перекласти її?</translation>
<translation id="7569952961197462199">Видалити дані кредитної картки з Chrome?</translation>
-<translation id="7569983096843329377">Чорний</translation>
<translation id="7578104083680115302">Зберігайте картки в Google, щоб швидко платити на сайтах і в додатках на всіх своїх пристроях.</translation>
<translation id="7588950540487816470">Інтернет навколо нас</translation>
<translation id="7592362899630581445">Сертифікат сервера порушує обмежувальні умови щодо імен.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Зловмисники на цьому сайті можуть обманом змусити вас установити програми, які погіршують роботу в Інтернеті (наприклад, змінюють вашу домашню сторінку або показують додаткову рекламу на сайтах, які ви відвідуєте).</translation>
<translation id="7674629440242451245">Хочете спробувати нові цікаві функції Chrome? Завантажте версію для розробників зі сторінки chrome.com/dev.</translation>
<translation id="7682287625158474539">Адреса для надсилання</translation>
+<translation id="7699293099605015246">Зараз статті недоступні</translation>
<translation id="7701040980221191251">Немає</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Перейти на сайт <ph name="SITE" /> (небезпечно)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Сертифікат</translation>
<translation id="7716147886133743102">Заблоковано адміністратором</translation>
<translation id="7716424297397655342">Не вдається завантажити цей сайт із кешу</translation>
+<translation id="7723047071702270851">Відредагуйте картку</translation>
<translation id="774634243536837715">Заблоковано небезпечний вміст.</translation>
<translation id="7752995774971033316">Некерований клієнт</translation>
<translation id="7755287808199759310">Хтось із батьків може розблокувати його</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Додати адресу</translation>
<translation id="777702478322588152">Префектура</translation>
<translation id="7791543448312431591">Додати</translation>
+<translation id="7793553086574152071">Щоб наступного разу платити швидше, збережіть цю картку у своєму обліковому записі Google.</translation>
<translation id="7793809570500803535">Веб-сторінка на сайті <ph name="SITE" /> може бути тимчасово недоступна або її назавжди переміщено за новою веб-адресою.</translation>
<translation id="7800304661137206267">З'єднання зашифровано з використанням <ph name="CIPHER" /> з алгоритмом <ph name="MAC" /> для автентифікації повідомлення та кодування <ph name="KX" /> як механізму обміну ключами.</translation>
+<translation id="7802523362929240268">Сайт законно зареєстрований</translation>
<translation id="780301667611848630">Ні, дякую</translation>
<translation id="7805768142964895445">Статус</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Видалити дані для автозаповнення форм із Chrome?</translation>
<translation id="7815407501681723534">Знайдено результатів за запитом "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
+<translation id="782886543891417279">Можливо, щоб під’єднатися до цієї мережі Wi-Fi (<ph name="WIFI_NAME" />), потрібно відвідати її сторінку входу.</translation>
<translation id="785549533363645510">Навіть у режимі анонімного перегляду ваш роботодавець, постачальник послуг Інтернету чи веб-сайти, які ви відвідуєте, можуть бачити, що ви переглядаєте.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" />: <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7878176543348854470">Дебетові та передплачені картки, які приймаються.</translation>
+<translation id="7878562273885520351">Ваш пароль можуть зламати</translation>
<translation id="7887683347370398519">Перевірте код CVC й повторіть спробу</translation>
<translation id="79338296614623784">Введіть дійсний номер телефону</translation>
<translation id="7935318582918952113">Дистилятор DOM</translation>
<translation id="7938958445268990899">Сертифікат сервера ще не дійсний.</translation>
-<translation id="7942349550061667556">Червоний</translation>
<translation id="7947285636476623132">Перевірте рік закінчення терміну дії та повторіть спробу</translation>
<translation id="7951415247503192394">(32-розрядна версія)</translation>
<translation id="7956713633345437162">Закладки для мобільних пристроїв</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Запитувати (за умовчанням)</translation>
<translation id="8041089156583427627">Надіслати відгук</translation>
<translation id="8041940743680923270">Використовувати глобальне налаштування за умовчанням (Запитувати)</translation>
+<translation id="8057711352706143257"><ph name="SOFTWARE_NAME" /> налаштовано неправильно. Якщо видалити програмне забезпечення <ph name="SOFTWARE_NAME" />, проблема зазвичай зникає. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Не вдалося переглянути статтю.</translation>
<translation id="8091372947890762290">Активація очікує на сервері</translation>
+<translation id="8094917007353911263">Можливо, щоб під’єднатися до цієї мережі, потрібно відвідати сторінку <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Спосіб оплати</translation>
<translation id="8118489163946903409">Спосіб оплати</translation>
+<translation id="8127301229239896662"><ph name="SOFTWARE_NAME" /> неправильно встановлено на вашому комп’ютері або в мережі. Попросіть IT-адміністратора вирішити цю проблему.</translation>
<translation id="8131740175452115882">Підтвердити</translation>
<translation id="8134994873729925007">Не вдалося знайти <ph name="BEGIN_ABBR" />адресу DNS-сервера<ph name="END_ABBR" /> хосту <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ваш комп’ютер перейшов у режим сну.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Зверніться до адміністратора своєї мережі, якщо ви не знаєте, що це означає.</translation>
<translation id="8293206222192510085">Додати закладку</translation>
<translation id="8294431847097064396">Джерело</translation>
+<translation id="8298115750975731693">Можливо, щоб під’єднатися до цієї мережі Wi-Fi (<ph name="WIFI_NAME" />), потрібно відвідати сторінку <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">Не вдається встановити конфіденційне з’єднання з доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, оскільки на пристрої налаштовано неправильні дату й час (<ph name="DATE_AND_TIME" />). <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Переклад не виконано через проблему підключення до мережі.</translation>
<translation id="8332188693563227489">Відмовлено в доступі до хосту <ph name="HOST_NAME" /></translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Нещодавно закриті</translation>
<translation id="8874824191258364635">Введіть дійсний номер картки</translation>
<translation id="8876793034577346603">Помилка аналізу конфігурації мережі.</translation>
-<translation id="8889402386540077796">Тон</translation>
<translation id="8891727572606052622">Недійсний режим проксі-сервера.</translation>
<translation id="889901481107108152">На жаль, цей експеримент не доступний на вашій платформі.</translation>
<translation id="8903921497873541725">Збільшити масштаб</translation>
<translation id="8931333241327730545">Зберегти цю картку у вашому обліковому записі Google?</translation>
<translation id="8932102934695377596">Ваш годинник запізнюється</translation>
+<translation id="893332455753468063">Додайте ім’я</translation>
<translation id="8938939909778640821">Прийнятні кредитні та передплачені картки</translation>
+<translation id="8957210676456822347">Авторизація приєднаного порталу</translation>
<translation id="8971063699422889582">Термін дії сертифіката сервера завершився.</translation>
-<translation id="8986494364107987395">Автоматично надсилати статистику використання та звіти про аварійне завершення роботи в Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Сайт містить шкідливі програми</translation>
<translation id="8997023839087525404">Сервер надав сертифікат без інформації про перевірку. Це обов’язкові дані для деяких сертифікатів. Вони підтверджують надійність сертифіката й захищають від атак зловмисників.</translation>
<translation id="9001074447101275817">Для проксі <ph name="DOMAIN" /> потрібно ввести ім’я користувача та пароль.</translation>
<translation id="9005998258318286617">Не вдалося завантажити документ PDF.</translation>
+<translation id="9008201768610948239">Ігнорувати</translation>
<translation id="901974403500617787">Позначки, які застосовуються до всієї системи, може встановлювати лише власник: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Потрібно вказати платіжну адресу картки</translation>
<translation id="9020542370529661692">Цю сторінку перекладено такою мовою: <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Ви пробували зв’язатися з доменом <ph name="DOMAIN" />, але сервер надав недійсний сертифікат.</translation>
<translation id="9050666287014529139">Парольна фраза</translation>
<translation id="9065203028668620118">Редагувати</translation>
-<translation id="9068849894565669697">Вибрати колір</translation>
<translation id="9069693763241529744">Заблоковано розширенням</translation>
<translation id="9076283476770535406">На ньому може бути вміст для дорослих</translation>
<translation id="9078964945751709336">Потрібно більше інформації</translation>
+<translation id="9080712759204168376">Підсумок замовлення</translation>
<translation id="9103872766612412690">Веб-сайт <ph name="SITE" /> зазвичай використовує шифрування для захисту вашої інформації. Під час цієї спроби Chromium під’єднатися до сторінки <ph name="SITE" /> з неї отримано незвичні й неправильні облікові дані. Це може статися, коли зловмисник намагається видавати себе за веб-сайт <ph name="SITE" /> або з’єднання перервано екраном входу Wi-Fi. Ваша інформація залишається захищеною, оскільки Chromium припинив з’єднання до того, як почався обмін будь-якими даними.</translation>
+<translation id="9106062320799175032">Додайте платіжну адресу</translation>
+<translation id="910908805481542201">Допоможіть вирішити цю проблему</translation>
+<translation id="9128870381267983090">З'єднатися з мережею</translation>
<translation id="9137013805542155359">Показати оригінал</translation>
<translation id="9137248913990643158">Перш ніж користуватися додатком, увійдіть в обліковий запис Chrome.</translation>
<translation id="9148507642005240123">&amp;Відмінити редагування</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419">Протокол, який використовує хост <ph name="HOST_NAME" />, не підтримується.</translation>
<translation id="9205078245616868884">Ваші дані зашифровано за допомогою парольної фрази. Введіть її, щоб почати синхронізацію.</translation>
<translation id="9207861905230894330">Не вдалося додати статтю.</translation>
+<translation id="9215416866750762878">Додаток перешкоджає Chrome безпечно під’єднуватися до цього сайту</translation>
<translation id="9219103736887031265">Зображення</translation>
<translation id="933612690413056017">Немає з’єднання з Інтернетом</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Немає}=1{1 запис}one{# запис}few{# записи}many{# записів}other{# запису}}</translation>
<translation id="981121421437150478">Офлайн</translation>
<translation id="988159990683914416">Конструкція розробника</translation>
+<translation id="989988560359834682">Редагувати адресу</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401"><ph name="SOFTWARE_NAME" /> неправильно встановлено на вашому комп’ютері або в мережі.
+ &lt;ul&gt;
+ &lt;li&gt;Видаліть або вимкніть <ph name="SOFTWARE_NAME" />&lt;/li&gt;
+ &lt;li&gt;Під’єднайтеся до іншої мережі&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index aafefc8b9a1..e2a38fcec75 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">Dấu trang máy tính</translation>
<translation id="1074497978438210769">Không bảo mật</translation>
<translation id="1080116354587839789">Vừa với chiều rộng</translation>
+<translation id="1088860948719068836">Thêm tên trên thẻ</translation>
<translation id="1103523840287552314">Luôn dịch <ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">Hiển thị tất cả mật khẩu đã lưu...</translation>
<translation id="1107591249535594099">Nếu được chọn, Chrome sẽ lưu trữ bản sao thẻ của bạn trên thiết bị này để điền biểu mẫu nhanh hơn.</translation>
<translation id="1111153019813902504">Dấu trang gần đây</translation>
<translation id="1113869188872983271">&amp;Hoàn tác sắp xếp lại</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (được đồng bộ hóa)</translation>
<translation id="1263231323834454256">Danh sách đọc</translation>
<translation id="1264126396475825575">Báo cáo sự cố được ghi lại vào <ph name="CRASH_TIME" /> (nhưng chưa tải lên hoặc đã bị bỏ qua)</translation>
+<translation id="1270502636509132238">Phương thức nhận hàng</translation>
<translation id="1281526147609854549">Do <ph name="ISSUER" /> phát hành</translation>
<translation id="1285320974508926690">Không bao giờ dịch trang web này</translation>
<translation id="129553762522093515">Các tab đã đóng gần đây</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">Đang chờ kết nối…</translation>
<translation id="153384715582417236">Hiện đã hoàn tất</translation>
<translation id="1549470594296187301">Bạn phải bật JavaScript để sử dụng tính năng này.</translation>
-<translation id="1555130319947370107">Xanh lam</translation>
<translation id="1559528461873125649">Không có tệp hoặc thư mục nào như vậy</translation>
<translation id="1583429793053364125">Đã xảy ra lỗi khi hiển thị trang web này.</translation>
<translation id="1592005682883173041">Quyền truy cập dữ liệu cục bộ</translation>
<translation id="1594030484168838125">Chọn</translation>
-<translation id="161042844686301425">Lục lam</translation>
<translation id="1620510694547887537">Máy ảnh</translation>
<translation id="1629803312968146339">Bạn có muốn Chrome lưu thẻ này không?</translation>
<translation id="1639239467298939599">Đang tải</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">OS</translation>
<translation id="1721312023322545264">Bạn cần được <ph name="NAME" /> cấp quyền để truy cập vào trang web này</translation>
<translation id="1721424275792716183">Trường * là bắt buộc</translation>
+<translation id="1727741090716970331">Thêm số thẻ hợp lệ</translation>
<translation id="1728677426644403582">Bạn đang xem nguồn của trang web</translation>
<translation id="173080396488393970">Loại thẻ này không được hỗ trợ</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">Lỗi nối tiếp hóa</translation>
<translation id="1974060860693918893">Nâng cao</translation>
<translation id="1978555033938440688">Phiên bản chương trình cơ sở</translation>
-<translation id="1995859865337580572">Vui lòng xác minh CVC của bạn</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{và 1 ứng dụng khác}other{và # ứng dụng khác}}</translation>
<translation id="2025186561304664664">Proxy được đặt thành định cấu hình tự động.</translation>
<translation id="2030481566774242610">Ý của bạn là <ph name="LINK" />?</translation>
@@ -141,6 +142,7 @@
<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>
<translation id="2086652334978798447">Để nhận nội dung được cá nhân hóa do Google đề xuất, hãy đăng nhập vào Chrome.</translation>
+<translation id="2091887806945687916">Âm thanh</translation>
<translation id="2094505752054353250">Miền không khớp</translation>
<translation id="2096368010154057602">Khu hành chính</translation>
<translation id="2108755909498034140">Khởi động lại máy tính của bạn</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">Bỏ qua vì đã bị <ph name="POLICY_NAME" /> ghi đè.</translation>
<translation id="2138201775715568214">Đang tìm kiếm các trang Web trong cuộc sống lân cận</translation>
<translation id="213826338245044447">Dấu trang di động</translation>
+<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="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="2166049586286450108">Quyền truy cập quản trị đầy đủ</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 địa chỉ}other{# địa chỉ}}</translation>
<translation id="2187317261103489799">Phát hiện (mặc định)</translation>
<translation id="2202020181578195191">Nhập năm hết hạn hợp lệ</translation>
+<translation id="2209523182407020534">Các ứng dụng có thể gây ra lỗi này gồm có phần mềm diệt vi-rút, tường lửa, lọc web hoặc proxy.</translation>
<translation id="2212735316055980242">Không tìm thấy chính sách</translation>
<translation id="2213606439339815911">Đang tìm nạp các mục nhập...</translation>
<translation id="2218879909401188352">Những kẻ tấn công hiện ở trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cài đặt ứng dụng nguy hiểm làm hỏng thiết bị của bạn, thêm các khoản phí ẩn vào hóa đơn di động hoặc lấy cắp thông tin cá nhân của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">Quay lại</translation>
<translation id="2503184589641749290">Thẻ ghi nợ và thẻ trả trước được chấp nhận</translation>
<translation id="2515629240566999685">Kiểm tra tín hiệu trong khu vực của bạn</translation>
+<translation id="2524461107774643265">Thêm thông tin khác</translation>
+<translation id="2536110899380797252">Thêm địa chỉ</translation>
<translation id="2539524384386349900">Phát hiện</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> đã gửi phản hồi không hợp lệ.</translation>
<translation id="2556876185419854533">&amp;Hoàn tác chỉnh sửa</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium không thể xác nhận thẻ của bạn tại thời điểm này. Vui lòng thử lại sau.</translation>
<translation id="2705137772291741111">Không thể đọc được bản sao đã lưu (đã lưu vào bộ nhớ cache) của trang web này.</translation>
<translation id="2709516037105925701">Tự động điền</translation>
+<translation id="2710942282213947212">Phần mềm trên máy tính của bạn hiện không cho Chromium kết nối an toàn với web</translation>
<translation id="2712173769900027643">Xin phép</translation>
-<translation id="2713444072780614174">Trắng</translation>
<translation id="2720342946869265578">Lân cận</translation>
<translation id="2721148159707890343">Yêu cầu đã thành công</translation>
<translation id="2728127805433021124">Chứng chỉ của máy chủ đã được ký bằng thuật toán chữ ký yếu.</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">Đã phát hiện thấy thay đổi mạng.</translation>
<translation id="2916038427272391327">Đóng các chương trình khác</translation>
<translation id="2922350208395188000">Không thể kiểm tra chứng chỉ của máy chủ.</translation>
+<translation id="2925673989565098301">Phương thức giao hàng</translation>
<translation id="2928905813689894207">Ðịa chỉ thanh toán</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> địa chỉ giao hàng khác}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> địa chỉ giao hàng khác}}</translation>
<translation id="2941952326391522266">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 là từ <ph name="DOMAIN2" />. Đ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>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">Loại chính sách sai</translation>
<translation id="3032412215588512954">Bạn có muốn tải lại trang web này không?</translation>
<translation id="3037605927509011580">Ôi, hỏng! </translation>
+<translation id="3039538478787849737">Lưu thẻ vào Google?</translation>
<translation id="3041612393474885105">Thông tin Chứng chỉ</translation>
<translation id="3063697135517575841">Chrome không thể xác nhận thẻ của bạn tại thời điểm này. Vui lòng thử lại sau.</translation>
<translation id="3064966200440839136">Rời khỏi chế độ ẩn danh để thanh toán qua một ứng dụng bên ngoài. Tiếp tục?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">Lỗi máy chủ tạm thời</translation>
<translation id="3154506275960390542">Trang này bao gồm biểu mẫu có thể được gửi không an toàn. Dữ liệu bạn gửi có thể bị người khác xem trong khi chuyển tuyến hoặc có thể bị kẻ tấn công sửa đổi nhằm thay đổi thông tin mà máy chủ nhận được.</translation>
<translation id="3157931365184549694">Khôi phục</translation>
+<translation id="3162559335345991374">Wi-Fi mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập trang đăng nhập của mạng đó.</translation>
<translation id="3167968892399408617">Các trang bạn xem trong tab ẩn danh sẽ không bị lưu lại trong lịch sử của trình duyệt, kho cookie hoặc lịch sử tìm kiếm sau khi bạn đóng tất cả các tab ẩn danh của mình. Mọi tệp bạn tải xuống hoặc dấu trang mà bạn tạo sẽ được giữ nguyên.</translation>
<translation id="3169472444629675720">Khám phá</translation>
<translation id="3174168572213147020">Đảo</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">Hủy thanh toán</translation>
<translation id="3207960819495026254">Đã được đánh dấu trang</translation>
+<translation id="3211223744486044430">Để thanh toán nhanh hơn vào lần tiếp theo, hãy lưu thẻ này vào Tài khoản Google của bạn và thiết bị này.</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>
<translation id="3226128629678568754">Nhấn nút tải lại để gửi lại các dữ liệu cần thiết để tải trang.</translation>
<translation id="3227137524299004712">Micrô</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">Không tìm thấy kết quả tìm kiếm nào</translation>
<translation id="3305707030755673451">Dữ liệu của bạn đã được mã hóa bằng cụm mật khẩu đồng bộ hóa của bạn vào <ph name="TIME" />. Nhập cụm mật khẩu đó để bắt đầu đồng bộ hóa.</translation>
<translation id="3320021301628644560">Thêm địa chỉ thanh toán</translation>
-<translation id="3329013043687509092">Độ bão hòa</translation>
<translation id="333371639341676808">Ngăn không cho trang này tạo hộp thoại bổ sung.</translation>
<translation id="3338095232262050444">Bảo mật</translation>
<translation id="3340978935015468852">cài đặt</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">ID ứng dụng khách:</translation>
<translation id="3391030046425686457">Địa chỉ giao hàng</translation>
<translation id="3395827396354264108">Phương thức nhận hàng</translation>
+<translation id="3399952811970034796">Địa chỉ giao hàng</translation>
<translation id="3422248202833853650">Thử thoát các chương trình khác để giải phóng bộ nhớ.</translation>
<translation id="3422472998109090673">Hiện không thể truy cập <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Cho phép (mặc định)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">Báo cáo sự cố được ghi lại vào <ph name="CRASH_TIME" />, được tải lên vào <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Thông tin chứng chỉ</translation>
<translation id="3690164694835360974">Đăng nhập không an toàn</translation>
+<translation id="3704162925118123524">Mạng mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập trang đăng nhập của mạng đó.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đang tải...</translation>
<translation id="3712624925041724820">Giấy phép không đủ</translation>
<translation id="3714780639079136834">Bật dữ liệu di dộng hoặc Wi-Fi</translation>
+<translation id="3715597595485130451">Kết nối Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kiểm tra proxy, tường lửa và cấu hình DNS<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">Nếu bạn hiểu các rủi ro bảo mật, bạn có thể <ph name="BEGIN_LINK" />truy cập trang web không an toàn này<ph name="END_LINK" /> trước khi các chương trình nguy hiểm bị xóa.</translation>
<translation id="3739623965217189342">Liên kết đã sao chép</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">&amp;Hoàn tác thêm</translation>
<translation id="404928562651467259">CẢNH BÁO</translation>
<translation id="4058922952496707368">Khóa "<ph name="SUBKEY" />": <ph name="ERROR" /></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>
<translation id="4079302484614802869">Cấu hình proxy được đặt để sử dụng URL tập lệnh .pac chứ không phải máy chủ proxy cố định.</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">Số sê-ri thiết bị không hợp lệ</translation>
<translation id="410351446219883937">Tự động phát</translation>
<translation id="4103763322291513355">Truy cập &lt;strong&gt;chrome://policy&lt;/strong&gt; để xem danh sách các URL bị chặn quyền truy cập và các chính sách khác bị quản trị viên hệ thống buộc phải thực thi.</translation>
-<translation id="4115378294792113321">Đỏ thẫm</translation>
<translation id="4116663294526079822">Luôn cho phép trên trang web này</translation>
<translation id="4117700440116928470">Phạm vi chính sách không được hỗ trợ.</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 mục khác}other{# mục khác}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">Bạn đã cố truy cập vào <ph name="DOMAIN" /> nhưng chứng chỉ mà máy chủ xuất trình đã bị nhà phát hành thu hồi. Điều này có nghĩa là giấy ủy nhiệm bảo mật mà máy chủ xuất trình hoàn toàn không đáng tin cậy. Bạn có thể đang giao tiếp với kẻ tấn công.</translation>
<translation id="4394049700291259645">Vô hiệu hóa</translation>
<translation id="4406896451731180161">kết quả tìm kiếm</translation>
+<translation id="4415426530740016218">Địa chỉ nhận hàng</translation>
<translation id="4424024547088906515">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 được Chrome tin cậ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="4432688616882109544"><ph name="HOST_NAME" /> không chấp nhận chứng chỉ đăng nhập của bạn hoặc có thể bạn chưa cung cấp chứng chỉ đăng nhập.</translation>
<translation id="443673843213245140">Đã tắt sử dụng proxy nhưng cấu hình proxy rõ ràng được chỉ định.</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">Thử tắt tiện ích.</translation>
<translation id="457875822857220463">Giao hàng</translation>
+<translation id="4582800630050655161">Bạn có thể mất quyền truy cập vào Tài khoản Google của mình hoặc bị đánh cắp danh tính. Chromium khuyên bạn nên thay đổi mật khẩu của mình ngay bây giờ.</translation>
<translation id="4587425331216688090">Xóa địa chỉ khỏi Chrome?</translation>
<translation id="4592951414987517459">Kết nối của bạn tới <ph name="DOMAIN" /> được mã hóa bằng bộ số 0 hiện đại.</translation>
<translation id="4594403342090139922">&amp;Hoàn tác xóa</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</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="4690462567478992370">Dừng sử dụng chứng chỉ không hợp lệ</translation>
+<translation id="4690954380545377795">Bạn có thể mất quyền truy cập vào Tài khoản Google của mình hoặc bị đánh cắp danh tính. Chrome khuyên bạn nên thay đổi mật khẩu của mình ngay bây giờ.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Kết nối của bạn bị gián đoạn</translation>
<translation id="471880041731876836">Bạn không có quyền để truy cập trang web này</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Chạy Chẩn đoán mạng của Windows<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">Thanh toán của bạn</translation>
<translation id="4726672564094551039">Tải lại chính sách</translation>
<translation id="4728558894243024398">Nền tảng</translation>
<translation id="4736825316280949806">Khởi động lại Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">Không thể lưu trữ do chương trình phụ trợ ở trạng thái xấu</translation>
<translation id="5023310440958281426">Kiểm tra chính sách của quản trị viên của bạn</translation>
<translation id="5029568752722684782">Xóa bản sao</translation>
+<translation id="503069730517007720">Cần có chứng chỉ gốc cho "<ph name="SOFTWARE_NAME" />" nhưng chứng chỉ này chưa được cài đặt. Hãy yêu cầu quản trị viên CNTT của bạn xem hướng dẫn cấu hình cho "<ph name="SOFTWARE_NAME" />" để khắc phục sự cố này. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Giới thiệu về Google Dịch</translation>
<translation id="5039804452771397117">Cho phép</translation>
<translation id="5040262127954254034">Bảo mật</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">Thử nghiệm</translation>
<translation id="5205222826937269299">Cần có tên</translation>
<translation id="5222812217790122047">Cần có email</translation>
+<translation id="522700295135997067">Trang web này có thể vừa đánh cắp mật khẩu của bạn</translation>
+<translation id="5230733896359313003">Địa chỉ giao hàng</translation>
<translation id="5251803541071282808">Đám mây</translation>
<translation id="5277279256032773186">Sử dụng Chrome ở cơ quan? Các doanh nghiệp có thể quản lý cài đặt Chrome cho nhân viên của họ. Tìm hiểu thêm</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Hãy làm theo các bước sau để tạm thời vô hiệu hóa phần mềm nhằm giúp bạn có thể truy cập vào web. Bạn cần phải có đặc quyền của quản trị viên.<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">Kết nối của bạn tới trang web này không ở chế độ riêng tư. Để thoát chế độ VR bất cứ lúc nào, hãy tháo tai nghe và nhấn quay lại.</translation>
<translation id="5299298092464848405">Lỗi phân tích cú pháp chính sách</translation>
+<translation id="5308380583665731573">Kết nối</translation>
<translation id="5308689395849655368">Báo cáo sự cố bị tắt.</translation>
<translation id="5317780077021120954">Lưu</translation>
<translation id="5327248766486351172">Tên</translation>
+<translation id="5332219387342487447">Phương thức giao hàng</translation>
<translation id="5355557959165512791">Bạn không thể truy cập vào <ph name="SITE" /> ngay bây giờ vì chứng chỉ của trang này đã bị thu hồi. Lỗi mạng và các cuộc tấn công mạng thường chỉ là tạm thời nên trang này có thể sẽ hoạt động lại sau.</translation>
<translation id="536296301121032821">Không thể lưu trữ cài đặt chính sách</translation>
<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>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">Trang web trên mạng nội bộ của công ty, tổ chức hoặc trường học này có URL tương tự như trang web bên ngoài.
<ph name="LINE_BREAK" />
Hãy thử liên hệ với quản trị viên hệ thống của bạn.</translation>
+<translation id="5499929369096410817">Nhập mã bảo mật dành cho <ph name="CREDIT_CARD" />. Mã này sẽ không được lưu.</translation>
<translation id="5509780412636533143">Dấu trang được quản lý</translation>
<translation id="5510766032865166053">Tệp này có thể đã bị di chuyển hoặc xóa.</translation>
<translation id="5523118979700054094">Tên chính sách</translation>
<translation id="552553974213252141">Văn bản đã được trích xuất chính xác chưa?</translation>
<translation id="5540224163453853">Không thể tìm thấy bài viết đã yêu cầu.</translation>
+<translation id="5541546772353173584">Thêm email</translation>
<translation id="5544037170328430102">Trang được nhúng tại <ph name="SITE" /> cho biết:</translation>
+<translation id="5545756402275714221">Tin bài dành cho bạn</translation>
<translation id="5556459405103347317">Tải lại</translation>
<translation id="5560088892362098740">Ngày hết hạn</translation>
<translation id="5565735124758917034">Đang hoạt động</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">Email</translation>
<translation id="5669703222995421982">Nhận nội dung được cá nhân hóa</translation>
<translation id="5675650730144413517">Trang này hiện không hoạt động</translation>
+<translation id="5689199277474810259">Xuất sang định dạng JSON</translation>
<translation id="5710435578057952990">Nhận dạng trang web này chưa được xác minh.</translation>
<translation id="5719499550583120431">Thẻ trả trước được chấp nhận.</translation>
<translation id="5720705177508910913">Người dùng hiện tại</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">Kết nối của bạn tới <ph name="DOMAIN" /> được mã hóa bằng bộ số 0 đã lỗi thời.</translation>
<translation id="5813119285467412249">&amp;Làm lại thêm</translation>
<translation id="5838278095973806738">Bạn không nên nhập bất kỳ thông tin nhạy cảm nào trên trang web này (ví dụ: mật khẩu hoặc thẻ tín dụng), vì những kẻ tấn công có thể đánh cắp thông tin đó.</translation>
+<translation id="5866257070973731571">Thêm số điện thoại</translation>
<translation id="5869405914158311789">Không thể truy cập trang web này</translation>
<translation id="5869522115854928033">Mật khẩu đã lưu</translation>
<translation id="5872918882028971132">Đề xuất chính</translation>
<translation id="5893752035575986141">Thẻ tín dụng được chấp nhận.</translation>
-<translation id="5901630391730855834">Vàng</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (được đồng bộ hóa)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{Đang sử dụng 1 cookie}other{Đang sử dụng # cookie}}</translation>
<translation id="5959728338436674663">Tự động gửi một số <ph name="BEGIN_WHITEPAPER_LINK" />thông tin hệ thống và nội dung trang<ph name="END_WHITEPAPER_LINK" /> tới Google để giúp phát hiện các ứng dụng và trang web nguy hiểm. <ph name="PRIVACY_PAGE_LINK" /></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="5975083100439434680">Thu nhỏ</translation>
+<translation id="597552863672748783">Xác nhận mã bảo mật</translation>
<translation id="598637245381783098">Không thể mở ứng dụng thanh toán</translation>
<translation id="5989320800837274978">Cả máy chủ proxy cố định và URL tập lệnh .pac đều chưa được chỉ định.</translation>
<translation id="5990559369517809815">Tiện ích đã chặn yêu cầu tới máy chủ.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{Trang 1}other{Trang #}}</translation>
-<translation id="6017514345406065928">Xanh lục</translation>
<translation id="6017850046339264347">Những kẻ tấn công trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cài đặt ứng dụng lừa đảo giả vờ là nội dung khác hoặc thu thập dữ liệu có thể dùng để theo dõi bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (được đồng bộ hóa)</translation>
<translation id="6027201098523975773">Nhập tên</translation>
<translation id="6040143037577758943">Đóng</translation>
-<translation id="6042308850641462728">Thêm</translation>
<translation id="6047233362582046994">Nếu bạn hiểu các rủi ro về bảo mật, bạn có thể <ph name="BEGIN_LINK" />truy cập trang này<ph name="END_LINK" /> trước khi các ứng dụng có hại bị xóa.</translation>
<translation id="6047927260846328439">Nội dung này có thể tìm cách đánh lừa bạn cài đặt phần mềm hoặc tiết lộ thông tin cá nhân. <ph name="BEGIN_LINK" />Vẫn hiển thị<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Bạn không thể truy cập vào <ph name="SITE" /> ngay bây giờ do trang web sử dụng tính năng ghim chứng chỉ. Lỗi mạng và các cuộc tấn công mạng thường chỉ là tạm thời nên trang này có thể sẽ hoạt động lại sau.</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">Bạn đang xem trang tiện ích</translation>
<translation id="6596325263575161958">Tùy chọn mã hóa</translation>
<translation id="662080504995468778">Ở lại</translation>
+<translation id="6624427990725312378">Thông tin liên hệ</translation>
<translation id="6626291197371920147">Thêm số thẻ hợp lệ</translation>
<translation id="6628463337424475685">Tìm kiếm trên <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Những kẻ tấn công hiện ở trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cố gắng cài đặt các chương trình nguy hiểm vào máy Mac của bạn. Các chương trình này sẽ đánh cắp hoặc xóa thông tin của bạn (ví dụ: ảnh, mật khẩu, thư và thẻ tín dụng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">Trước đó</translation>
<translation id="6710594484020273272">&lt;Nhập cụm từ tìm kiếm&gt;</translation>
<translation id="6711464428925977395">Đã xảy ra sự cố với máy chủ proxy hoặc địa chỉ không chính xác.</translation>
-<translation id="6727102863431372879">Đặt</translation>
<translation id="674375294223700098">Lỗi chứng chỉ máy chủ không xác định.</translation>
<translation id="6753269504797312559">Giá trị chính sách</translation>
<translation id="6757797048963528358">Thiết bị của bạn đã chuyển sang chế độ ngủ.</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">Đường dẫn cấu hình</translation>
<translation id="7424977062513257142">Trang được nhúng trên trang web này cho biết:</translation>
+<translation id="7437289804838430631">Thêm thông tin liên hệ</translation>
<translation id="7441627299479586546">Chủ đề chính sách sai</translation>
<translation id="7444046173054089907">Trang web này bị chặn</translation>
<translation id="7445762425076701745">Không thể xác thực đầy đủ nhận dạng của máy chủ bạn đã kết nối. Bạn đã kết nối vào máy chủ bằng một tên chỉ hợp lệ trong mạng của bạn và đó là tên mà các tổ chức phát hành chứng chỉ bên ngoài không thể xác thực được. Vì một số tổ chức phát hành chứng chỉ sẽ cấp chứng chỉ cho các tên này thay thế, nên không có cách nào đảm bảo bạn được kết nối tới trang web đã chỉ định và không phải là kẻ tấn công.</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">Chuyển tiếp</translation>
<translation id="7485870689360869515">Không tìm thấy dữ liệu.</translation>
<translation id="7508255263130623398">ID thiết bị thuộc chính sách trả lại trống hoặc không khớp với ID của thiết bị hiện tại</translation>
+<translation id="7511955381719512146">Wi-Fi mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="7514365320538308">Tải xuống</translation>
<translation id="7518003948725431193">Không tìm thấy trang web nào ứng với địa chỉ web:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">Kết nối của bạn tới trang web này không ở chế độ riêng tư</translation>
-<translation id="7535087603100972091">Giá trị</translation>
<translation id="7537536606612762813">Bắt buộc</translation>
<translation id="7542403920425041731">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="7542995811387359312">Tính năng tự động điền thẻ tín dụng đã bị vô hiệu hóa vì biểu mẫu này không sử dụng kết nối an toàn.</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">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ó thể đã bị gian lận khi phát hành. Đ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="7568593326407688803">Trang này bằng<ph name="ORIGINAL_LANGUAGE" />Bạn có muốn dịch trang này không?</translation>
<translation id="7569952961197462199">Xóa thẻ tín dụng khỏi Chrome?</translation>
-<translation id="7569983096843329377">Đen</translation>
<translation id="7578104083680115302">Thanh toán nhanh trên các trang web và ứng dụng trong mọi thiết bị nhờ sử dụng thẻ bạn đã lưu với Google.</translation>
<translation id="7588950540487816470">Web trong cuộc sống</translation>
<translation id="7592362899630581445">Chứng chỉ của máy chủ vi phạm hạn chế tên.</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">Những kẻ tấn công trên trang web này có thể đánh lừa bạn cài đặt các chương trình ảnh hưởng đến trải nghiệm duyệt web của bạn (ví dụ: bằng cách thay đổi trang chủ của bạn hoặc hiển thị thêm quảng cáo trên các trang web bạn truy cập).</translation>
<translation id="7674629440242451245">Bạn quan tâm đến các tính năng mới thú vị của Chrome? Hãy dùng thử kênh nhà phát triển của chúng tôi tại chrome.com/dev.</translation>
<translation id="7682287625158474539">Địa chỉ gửi hàng</translation>
+<translation id="7699293099605015246">Không có bài viết nào ngay lúc này</translation>
<translation id="7701040980221191251">Không</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Tiếp tục truy cập <ph name="SITE" /> (không an toàn)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Chứng chỉ</translation>
<translation id="7716147886133743102">Bị quản trị viên của bạn chặn</translation>
<translation id="7716424297397655342">Không thể tải trang web này từ bộ nhớ cache</translation>
+<translation id="7723047071702270851">Chỉnh sửa thẻ</translation>
<translation id="774634243536837715">Đã chặn nội dung nguy hiểm.</translation>
<translation id="7752995774971033316">Không được quản lý</translation>
<translation id="7755287808199759310">Cha mẹ của bạn có thể bỏ chặn trang web cho bạn</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">Thêm địa chỉ</translation>
<translation id="777702478322588152">Quận</translation>
<translation id="7791543448312431591">Thêm</translation>
+<translation id="7793553086574152071">Để thanh toán nhanh hơn vào lần tiếp theo, hãy lưu thẻ này vào Tài khoản Google của bạn.</translation>
<translation id="7793809570500803535">Trang web tại <ph name="SITE" /> 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="7800304661137206267">Kết nối được mã hóa bằng <ph name="CIPHER" />, với <ph name="MAC" /> để xác thực thư và <ph name="KX" /> là cơ chế trao đổi chính.</translation>
+<translation id="7802523362929240268">Trang web hợp pháp</translation>
<translation id="780301667611848630">Không, cảm ơn</translation>
<translation id="7805768142964895445">Trạng thái</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Xóa đề xuất biểu mẫu khỏi Chrome?</translation>
<translation id="7815407501681723534">Đã tìm thấy <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> cho '<ph name="SEARCH_STRING" />'</translation>
+<translation id="782886543891417279">Wi-Fi mà bạn đang sử dụng (<ph name="WIFI_NAME" />) có thể yêu cầu bạn phải truy cập trang đăng nhập của mạng đó.</translation>
<translation id="785549533363645510">Tuy nhiên, bạn không ẩn. Việc chuyển sang chế độ ẩn danh sẽ không ẩn thao tác duyệt của bạn với chủ lao động, nhà cung cấp dịch vụ internet hoặc các trang web bạn truy cập.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">Thẻ ghi nợ và thẻ trả trước được chấp nhận.</translation>
+<translation id="7878562273885520351">Mật khẩu của bạn có thể bị xâm phạm</translation>
<translation id="7887683347370398519">Kiểm tra CVC của bạn và thử lại</translation>
<translation id="79338296614623784">Nhập số điện thoại hợp lệ</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">Chứng chỉ của máy chủ chưa hợp lệ.</translation>
-<translation id="7942349550061667556">Đỏ</translation>
<translation id="7947285636476623132">Kiểm tra năm hết hạn của bạn và thử lại</translation>
<translation id="7951415247503192394">(32 bit)</translation>
<translation id="7956713633345437162">Dấu trang di động</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">Yêu cầu (mặc định)</translation>
<translation id="8041089156583427627">Gửi phản hồi</translation>
<translation id="8041940743680923270">Sử dụng cài đặt mặc định chung (Hỏi)</translation>
+<translation id="8057711352706143257">Cấu hình của "<ph name="SOFTWARE_NAME" />" không chính xác. Việc gỡ cài đặt "<ph name="SOFTWARE_NAME" />" thường sẽ khắc phục được sự cố này. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">Không xem được bài viết.</translation>
<translation id="8091372947890762290">Kích hoạt đang chờ xử lý trên máy chủ</translation>
+<translation id="8094917007353911263">Mạng mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
+<translation id="8103161714697287722">Phương thức thanh toán</translation>
<translation id="8118489163946903409">Phương thức thanh toán</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" đã được cài đặt không đúng trên máy tính hoặc mạng của bạn. Hãy yêu cầu quản trị viên CNTT của bạn giải quyết vấn đề này.</translation>
<translation id="8131740175452115882">Xác nhận</translation>
<translation id="8134994873729925007">Không thể tìm thấy <ph name="BEGIN_ABBR" />địa chỉ DNS<ph name="END_ABBR" /> của máy chủ của <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Máy tính của bạn đã chuyển sang chế độ ngủ.</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">Hãy liên hệ với quản trị viên mạng của bạn nếu bạn không chắc chắn về điều này có ý nghĩa gì.</translation>
<translation id="8293206222192510085">Thêm Dấu trang</translation>
<translation id="8294431847097064396">Nguồn</translation>
+<translation id="8298115750975731693">Wi-Fi mà bạn đang sử dụng (<ph name="WIFI_NAME" />) có thể yêu cầu bạn phải truy cập <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
<translation id="8306404619377842860">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. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">Không thể dịch do kết nối mạng có sự cố.</translation>
<translation id="8332188693563227489">Quyền truy cập <ph name="HOST_NAME" /> bị từ chối</translation>
@@ -941,20 +977,21 @@
<translation id="8870413625673593573">Các tab đã Đóng gần đây</translation>
<translation id="8874824191258364635">Nhập số thẻ hợp lệ</translation>
<translation id="8876793034577346603">Không thể phân tích cú pháp cấu hình mạng.</translation>
-<translation id="8889402386540077796">Màu sắc</translation>
<translation id="8891727572606052622">Chế độ proxy không hợp lệ.</translation>
<translation id="889901481107108152">Rất tiếc, thử nghiệm này không sẵn có trên nền tảng của bạn.</translation>
<translation id="8903921497873541725">Phóng to</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>
+<translation id="893332455753468063">Thêm tên</translation>
<translation id="8938939909778640821">Thẻ tín dụng và thẻ trả trước được chấp nhận</translation>
+<translation id="8957210676456822347">Ủy quyền cổng bị khóa</translation>
<translation id="8971063699422889582">Chứng chỉ của máy chủ đã hết hạn.</translation>
-<translation id="8986494364107987395">Tự động gửi số liệu thống kê về việc sử dụng và báo cáo sự cố cho Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">Trang web sắp truy cập chứa chương trình độc hại</translation>
<translation id="8997023839087525404">Máy chủ đã đưa ra chứng chỉ không được tiết lộ công khai theo chính sách Tính minh bạch của chứng chỉ. Đây là yêu cầu đối với một số chứng chỉ, để đảm bảo chúng đáng tin cậy và giúp chống lại những kẻ tấn công.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> yêu cầu tên người dùng và mật khẩu.</translation>
<translation id="9005998258318286617">Không tải được tài liệu PDF.</translation>
+<translation id="9008201768610948239">Bỏ qua</translation>
<translation id="901974403500617787">Chỉ chủ sở hữu mới có thể đặt cờ áp dụng cho toàn hệ thống: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020200922353704812">Yêu cầu địa chỉ thanh toán của thẻ</translation>
<translation id="9020542370529661692">Trang này đã được dịch sang <ph name="TARGET_LANGUAGE" /></translation>
@@ -964,11 +1001,14 @@
<translation id="9049981332609050619">Bạn đã cố truy cập vào <ph name="DOMAIN" />, nhưng máy chủ cho biết chứng chỉ không hợp lệ.</translation>
<translation id="9050666287014529139">Cụm mật khẩu</translation>
<translation id="9065203028668620118">Chỉnh sửa</translation>
-<translation id="9068849894565669697">Chọn màu</translation>
<translation id="9069693763241529744">Bị một tiện ích chặn</translation>
<translation id="9076283476770535406">Trang web có thể có nội dung người lớn</translation>
<translation id="9078964945751709336">Yêu cầu thêm thông tin</translation>
+<translation id="9080712759204168376">Tóm tắt đơn hàng</translation>
<translation id="9103872766612412690"><ph name="SITE" /> thường sử dụng mã hóa để bảo vệ thông tin của bạn. Khi Chromium cố gắng kết nối với <ph name="SITE" /> tại thời điểm này, trang web đã gửi lại thông tin đăng nhập không chính xác và bất thường. Điều này có thể xảy ra khi kẻ tấn công đang cố gắng giả mạo là <ph name="SITE" /> hoặc màn hình đăng nhập Wi-Fi đã làm gián đoạn kết nối. Thông tin của bạn vẫn an toàn do Chromium đã ngừng kết nối trước khi bất kỳ dữ liệu nào được trao đổi.</translation>
+<translation id="9106062320799175032">Thêm địa chỉ thanh toán</translation>
+<translation id="910908805481542201">Giúp tôi khắc phục vấn đề này</translation>
+<translation id="9128870381267983090">Kết nối đến mạng</translation>
<translation id="9137013805542155359">Hiển thị văn bản gốc</translation>
<translation id="9137248913990643158">Vui lòng khởi động và đăng nhập vào Chrome trước khi sử dụng ứng dụng này.</translation>
<translation id="9148507642005240123">&amp;Hoàn tác chỉnh sửa</translation>
@@ -980,6 +1020,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> sử dụng giao thức không được hỗ trợ.</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="9215416866750762878">Một ứng dụng hiện không cho Chrome kết nối an toàn với trang web này</translation>
<translation id="9219103736887031265">Hình ảnh</translation>
<translation id="933612690413056017">Không có kết nối Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -989,5 +1030,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{Không có}=1{1 mục}other{# mục}}</translation>
<translation id="981121421437150478">Ngoại tuyến</translation>
<translation id="988159990683914416">Phiên bản dành cho Nhà phát triển</translation>
+<translation id="989988560359834682">Chỉnh sửa địa chỉ</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" đã được cài đặt không đúng trên máy tính hoặc mạng của bạn:
+ &lt;ul&gt;
+ &lt;li&gt;Hãy thử gỡ cài đặt hoặc vô hiệu hóa "<ph name="SOFTWARE_NAME" />"&lt;/li&gt;
+ &lt;li&gt;Hãy thử kết nối với một mạng khác&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index 5d67971f339..0c734e7a855 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">桌面书签</translation>
<translation id="1074497978438210769">不安全</translation>
<translation id="1080116354587839789">适合窗口宽度</translation>
+<translation id="1088860948719068836">添加持卡人姓名</translation>
<translation id="1103523840287552314">总是翻译<ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">显示所有已保存的密码…</translation>
<translation id="1107591249535594099">选中后,Chrome 会将您的信用卡副本存储在此设备上,以加快表单填写速度。</translation>
<translation id="1111153019813902504">最近用过的书签</translation>
<translation id="1113869188872983271">撤消顺序调整(&amp;U)</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />、<ph name="TYPE_2" />(已同步)</translation>
<translation id="1263231323834454256">阅读清单</translation>
<translation id="1264126396475825575">崩溃报告获取时间:<ph name="CRASH_TIME" />(该报告尚未上传或已被忽略)</translation>
+<translation id="1270502636509132238">取货方式</translation>
<translation id="1281526147609854549">颁发者:<ph name="ISSUER" /></translation>
<translation id="1285320974508926690">一律不翻译此网站</translation>
<translation id="129553762522093515">最近关闭的标签页</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">正在等待建立连接…</translation>
<translation id="153384715582417236">暂无新内容</translation>
<translation id="1549470594296187301">必须启用 JavaScript 才能使用此功能。</translation>
-<translation id="1555130319947370107">蓝色</translation>
<translation id="1559528461873125649">不存在此类文件或目录</translation>
<translation id="1583429793053364125">显示此网页时出了点问题。</translation>
<translation id="1592005682883173041">本地数据访问权限</translation>
<translation id="1594030484168838125">选择</translation>
-<translation id="161042844686301425">青色</translation>
<translation id="1620510694547887537">摄像头</translation>
<translation id="1629803312968146339">您希望 Chrome 保存此信用卡吗?</translation>
<translation id="1639239467298939599">正在加载</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">操作系统</translation>
<translation id="1721312023322545264">您需要获得<ph name="NAME" />的许可,然后才能访问此网站</translation>
<translation id="1721424275792716183">标有“*”的字段均是必填字段</translation>
+<translation id="1727741090716970331">添加有效卡号</translation>
<translation id="1728677426644403582">您正在查看网页的源代码</translation>
<translation id="173080396488393970">此信用卡类型不受支持</translation>
<translation id="1734864079702812349">美国运通卡</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">序列化错误</translation>
<translation id="1974060860693918893">高级</translation>
<translation id="1978555033938440688">固件版本</translation>
-<translation id="1995859865337580572">请验证您的银行卡验证码 (CVC)</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{以及另外 1 个应用}other{以及另外 # 个应用}}</translation>
<translation id="2025186561304664664">代理已设为自动配置。</translation>
<translation id="2030481566774242610">您是想访问<ph name="LINK" />吗?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">撤消</translation>
<translation id="20817612488360358">已设置为使用系统代理设置,但同时指定了一个明确的代理配置。</translation>
<translation id="2086652334978798447">要获取 Google 推荐的个性化内容,请登录 Chrome。</translation>
+<translation id="2091887806945687916">声音</translation>
<translation id="2094505752054353250">网域不匹配</translation>
<translation id="2096368010154057602">省</translation>
<translation id="2108755909498034140">重新启动计算机</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">由于已被 <ph name="POLICY_NAME" /> 替换,该政策已忽略。</translation>
<translation id="2138201775715568214">正在查找附近的“实物网”网页</translation>
<translation id="213826338245044447">移动设备书签</translation>
+<translation id="214556005048008348">取消付款</translation>
<translation id="2147827593068025794">后台同步</translation>
+<translation id="2148613324460538318">添加支付卡</translation>
<translation id="2154054054215849342">您的网域不支持同步</translation>
<translation id="2154484045852737596">修改支付卡</translation>
<translation id="2166049586286450108">完全的管理员访问权限</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 个地址}other{# 个地址}}</translation>
<translation id="2187317261103489799">检测(默认)</translation>
<translation id="2202020181578195191">请输入有效的失效年份</translation>
+<translation id="2209523182407020534">可能导致此错误的应用包括防病毒软件、防火墙软件和网络过滤/代理软件。</translation>
<translation id="2212735316055980242">找不到策略</translation>
<translation id="2213606439339815911">正在获取条目…</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的现有攻击者可能会安装危险应用来损害您的设备、给您的手机帐单增添隐含费用或窃取您的个人信息。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">返回</translation>
<translation id="2503184589641749290">接受的借记卡和预付卡</translation>
<translation id="2515629240566999685">检查您所在区域的网络信号</translation>
+<translation id="2524461107774643265">添加更多信息</translation>
+<translation id="2536110899380797252">添加地址</translation>
<translation id="2539524384386349900">检测</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> 发送的响应无效。</translation>
<translation id="2556876185419854533">撤消修改(&amp;U)</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium 目前无法确认您的信用卡,请稍后重试。</translation>
<translation id="2705137772291741111">无法读取此网站的已保存(缓存)副本。</translation>
<translation id="2709516037105925701">自动填充</translation>
+<translation id="2710942282213947212">您计算机上的软件导致 Chromium 无法安全地连接到网络</translation>
<translation id="2712173769900027643">请求批准</translation>
-<translation id="2713444072780614174">白色</translation>
<translation id="2720342946869265578">附近</translation>
<translation id="2721148159707890343">请求成功</translation>
<translation id="2728127805433021124">服务器的证书是使用弱签名算法进行签名的。</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">检测到了网络变化。</translation>
<translation id="2916038427272391327">关闭其他程序</translation>
<translation id="2922350208395188000">无法核实服务器证书。</translation>
+<translation id="2925673989565098301">递送方式</translation>
<translation id="2928905813689894207">帐单邮寄地址</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 个地址}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 个地址}}</translation>
<translation id="2941952326391522266">此服务器无法证明它是<ph name="DOMAIN" />;其安全证书来自<ph name="DOMAIN2" />。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">策略类型有误</translation>
<translation id="3032412215588512954">要重新加载该网站吗?</translation>
<translation id="3037605927509011580">喔唷,崩溃啦!</translation>
+<translation id="3039538478787849737">将卡片信息保存到 Google?</translation>
<translation id="3041612393474885105">证书信息</translation>
<translation id="3063697135517575841">Chrome 目前无法确认您的信用卡,请稍后重试。</translation>
<translation id="3064966200440839136">将要退出隐身模式,以便通过外部应用付款。是否继续?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">服务器临时错误</translation>
<translation id="3154506275960390542">此页包含一个可能无法安全提交的表单。他人可能会在传输过程中查看您所发送的数据;攻击者也可能会修改这些数据,从而改变服务器收到的内容。</translation>
<translation id="3157931365184549694">恢复</translation>
+<translation id="3162559335345991374">您要使用的 Wi-Fi 网络可能需要您访问其登录页面。</translation>
<translation id="3167968892399408617">在您关闭所有隐身标签页后,您在这些标签页中查看的网页不会在浏览器历史记录、Cookie 存储区或搜索记录中留下任何痕迹。不过,您下载的所有文件或创建的书签均会保留下来。</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">岛</translation>
@@ -285,6 +295,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">取消付款</translation>
<translation id="3207960819495026254">已加书签</translation>
+<translation id="3211223744486044430">若想在下次购物时更快捷地付款,请将此卡片的信息保存到您的 Google 帐号和此设备中。</translation>
<translation id="3225919329040284222">服务器提供的证书与内置预期证书不匹配。这些预期证书是针对某些高安全性网站提供的,以便为您提供保护。</translation>
<translation id="3226128629678568754">按“重新加载”按钮,重新提交加载该网页所需的数据。</translation>
<translation id="3227137524299004712">麦克风</translation>
@@ -299,7 +310,6 @@
<translation id="3303855915957856445">未找到任何搜索结果</translation>
<translation id="3305707030755673451">您的数据已于 <ph name="TIME" />使用您的同步密码加密。输入该密码即可开始同步。</translation>
<translation id="3320021301628644560">添加账单邮寄地址</translation>
-<translation id="3329013043687509092">饱和度</translation>
<translation id="333371639341676808">禁止此页再显示对话框。</translation>
<translation id="3338095232262050444">安全</translation>
<translation id="3340978935015468852">设置</translation>
@@ -318,6 +328,7 @@
<translation id="3380864720620200369">客户端 ID:</translation>
<translation id="3391030046425686457">递送地址</translation>
<translation id="3395827396354264108">取货方式</translation>
+<translation id="3399952811970034796">递送地址</translation>
<translation id="3422248202833853650">请尝试退出其他程序以释放内存。</translation>
<translation id="3422472998109090673">目前无法访问 <ph name="HOST_NAME" />。</translation>
<translation id="3427092606871434483">允许(默认)</translation>
@@ -362,10 +373,12 @@
<translation id="3679803492151881375">崩溃报告的获取时间:<ph name="CRASH_TIME" />;上传时间:<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">证书信息</translation>
<translation id="3690164694835360974">登录方式不安全</translation>
+<translation id="3704162925118123524">您正在使用的网络可能会要求您访问其登录页面。</translation>
<translation id="3704609568417268905"><ph name="TIME" /> - <ph name="BOOKMARKED" /> - <ph name="TITLE" /> - <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">正在加载...</translation>
<translation id="3712624925041724820">许可已用尽</translation>
<translation id="3714780639079136834">开启移动数据网络或 Wi-Fi</translation>
+<translation id="3715597595485130451">连接到 Wi-Fi 网络</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />检查代理服务器、防火墙和 DNS 配置<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">如果您了解自己将面临的安全风险,则可以在危险程序被清除前<ph name="BEGIN_LINK" />访问这个不安全的网站<ph name="END_LINK" />。</translation>
<translation id="3739623965217189342">您复制的链接</translation>
@@ -400,6 +413,7 @@
<translation id="4030383055268325496">撤消添加(&amp;U)</translation>
<translation id="404928562651467259">警告</translation>
<translation id="4058922952496707368">“<ph name="SUBKEY" />”键:<ph name="ERROR" /></translation>
+<translation id="4067947977115446013">添加有效地址</translation>
<translation id="4072486802667267160">处理您的订单时出错。请重试。</translation>
<translation id="4075732493274867456">客户端和服务器不支持一般 SSL 协议版本或加密套件。</translation>
<translation id="4079302484614802869">代理配置已设置为使用 .pac 脚本网址,而不是固定的代理服务器。</translation>
@@ -407,7 +421,6 @@
<translation id="4103249731201008433">设备序列号无效</translation>
<translation id="410351446219883937">自动播放</translation>
<translation id="4103763322291513355">请访问 &lt;strong&gt;chrome:// 政策&lt;/strong&gt;,查看列入黑名单的网址列表以及您的系统管理员强制要求执行的其他政策。</translation>
-<translation id="4115378294792113321">洋红色</translation>
<translation id="4116663294526079822">在此网站上始终允许</translation>
<translation id="4117700440116928470">政策范围不受支持。</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 项其他内容}other{# 项其他内容}}</translation>
@@ -445,6 +458,7 @@
<translation id="4377125064752653719">您尝试访问的是 <ph name="DOMAIN" />,但服务器出示的证书已被其颁发者吊销。这表明绝对不应该信任此服务器出示的安全凭据。您可能正在与攻击者进行通信。</translation>
<translation id="4394049700291259645">停用</translation>
<translation id="4406896451731180161">搜索结果</translation>
+<translation id="4415426530740016218">取货地址</translation>
<translation id="4424024547088906515">此服务器无法证明它是<ph name="DOMAIN" />;Chrome不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> 不接受您的登录证书,或者您可能没有提供登录证书。</translation>
<translation id="443673843213245140">已停用代理,但是指定了明确的代理配置。</translation>
@@ -457,6 +471,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">尝试停用扩展程序。</translation>
<translation id="457875822857220463">递送</translation>
+<translation id="4582800630050655161">您可能会无法再访问自己的 Google 帐号,或者遭遇身份信息被盗用。Chromium 建议您立即更改密码。</translation>
<translation id="4587425331216688090">从 Chrome 中移除地址?</translation>
<translation id="4592951414987517459">您与 <ph name="DOMAIN" /> 之间的连接采用新型加密套件进行了加密。</translation>
<translation id="4594403342090139922">撤消删除(&amp;U)</translation>
@@ -465,10 +480,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">此服务器无法证明它是<ph name="DOMAIN" />;其安全证书有误。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
<translation id="4690462567478992370">停止使用无效的证书</translation>
+<translation id="4690954380545377795">您可能会无法再访问自己的 Google 帐号,或者遭遇身份信息被盗用。Chrome 建议您立即更改密码。</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /><ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">您的连接已中断</translation>
<translation id="471880041731876836">您无权访问此网站</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />运行 Windows 网络诊断<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">您的付款</translation>
<translation id="4726672564094551039">重新加载政策</translation>
<translation id="4728558894243024398">平台</translation>
<translation id="4736825316280949806">重新启动 Chromium</translation>
@@ -507,6 +524,7 @@
<translation id="5019198164206649151">后备存储状态不佳</translation>
<translation id="5023310440958281426">请查看管理员制定的政策</translation>
<translation id="5029568752722684782">清除副本</translation>
+<translation id="503069730517007720">必须为“<ph name="SOFTWARE_NAME" />”安装根证书,但您尚未安装该证书。您的 IT 管理员应仔细查看“<ph name="SOFTWARE_NAME" />”的配置说明,以解决此问题。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">关于 Google 翻译</translation>
<translation id="5039804452771397117">允许</translation>
<translation id="5040262127954254034">隐私设置</translation>
@@ -530,6 +548,8 @@
<translation id="5199729219167945352">实验</translation>
<translation id="5205222826937269299">需要提供名称</translation>
<translation id="5222812217790122047">需要提供电子邮件地址</translation>
+<translation id="522700295135997067">此网站可能刚刚盗取了您的密码</translation>
+<translation id="5230733896359313003">送货地址</translation>
<translation id="5251803541071282808">云端</translation>
<translation id="5277279256032773186">使用 Chrome 办公?企业可以为其员工管理 Chrome 设置。了解详情</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />按照下述步骤操作可临时停用此类软件,以便您能够连接到网络。您需要具有管理员权限。<ph name="END_PARAGRAPH" />
@@ -544,9 +564,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">您与此网站建立的不是私密连接。您可以随时取下头戴式设备,然后按“返回”,以退出 VR 模式。</translation>
<translation id="5299298092464848405">解析策略时出错</translation>
+<translation id="5308380583665731573">连接</translation>
<translation id="5308689395849655368">已停用崩溃报告。</translation>
<translation id="5317780077021120954">保存</translation>
<translation id="5327248766486351172">名称</translation>
+<translation id="5332219387342487447">送货方式</translation>
<translation id="5355557959165512791">您目前无法访问 <ph name="SITE" />,因为此证书已被撤消。网络错误和攻击行为通常是暂时的,因此,此网页稍后可能会恢复正常。</translation>
<translation id="536296301121032821">无法存储策略设置</translation>
<translation id="5386426401304769735">此网站的证书链包含使用 SHA-1 签署的证书。</translation>
@@ -566,12 +588,15 @@
<translation id="5492298309214877701">这个位于公司、组织或学校内网中的网站使用的网址与某个外部网站的网址相同。
<ph name="LINE_BREAK" />
请尝试与您的系统管理员联系。</translation>
+<translation id="5499929369096410817">请输入“<ph name="CREDIT_CARD" />”的安全码。系统不会保存该代码。</translation>
<translation id="5509780412636533143">受管理的书签</translation>
<translation id="5510766032865166053">该文件可能已被移至别处或遭到删除。</translation>
<translation id="5523118979700054094">政策名</translation>
<translation id="552553974213252141">提取的内容是否正确?</translation>
<translation id="5540224163453853">找不到请求的文章。</translation>
+<translation id="5541546772353173584">添加电子邮件地址</translation>
<translation id="5544037170328430102"><ph name="SITE" /> 上的嵌入式页面显示:</translation>
+<translation id="5545756402275714221">为您推荐的文章</translation>
<translation id="5556459405103347317">重新加载</translation>
<translation id="5560088892362098740">到期日期</translation>
<translation id="5565735124758917034">主动</translation>
@@ -593,6 +618,7 @@
<translation id="5659593005791499971">电子邮件</translation>
<translation id="5669703222995421982">获取个性化内容</translation>
<translation id="5675650730144413517">该网页无法正常运作</translation>
+<translation id="5689199277474810259">导出为 JSON 格式</translation>
<translation id="5710435578057952990">此网站尚未经过身份验证。</translation>
<translation id="5719499550583120431">接受预付卡。</translation>
<translation id="5720705177508910913">当前用户</translation>
@@ -607,27 +633,27 @@
<translation id="5810442152076338065">您与 <ph name="DOMAIN" /> 之间的连接采用过时的加密套件进行了加密。</translation>
<translation id="5813119285467412249">恢复添加(&amp;R)</translation>
<translation id="5838278095973806738">请勿在此网站上输入任何敏感信息(例如密码或信用卡信息),因为攻击者可能会盗取这些信息。</translation>
+<translation id="5866257070973731571">添加电话号码</translation>
<translation id="5869405914158311789">无法访问此网站</translation>
<translation id="5869522115854928033">已保存的密码</translation>
<translation id="5872918882028971132">家长建议</translation>
<translation id="5893752035575986141">接受信用卡。</translation>
-<translation id="5901630391730855834">黄色</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(已同步)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{正在使用 1 个}other{正在使用 # 个}}</translation>
<translation id="5959728338436674663">自动向 Google 发送一些<ph name="BEGIN_WHITEPAPER_LINK" />系统信息和网页内容<ph name="END_WHITEPAPER_LINK" />,以帮助检测危险应用和网站。<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">修改联系信息</translation>
<translation id="5967867314010545767">从历史记录中移除</translation>
<translation id="5975083100439434680">缩小</translation>
+<translation id="597552863672748783">请确认安全码</translation>
<translation id="598637245381783098">无法打开付款应用</translation>
<translation id="5989320800837274978">固定代理服务器和 .pac 脚本网址均未指定。</translation>
<translation id="5990559369517809815">对服务器的请求已遭到某个扩展程序的阻止。</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{第 1 页}other{第 # 页}}</translation>
-<translation id="6017514345406065928">绿色</translation>
<translation id="6017850046339264347"><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="6025416945513303461"><ph name="TYPE_1" />、<ph name="TYPE_2" />、<ph name="TYPE_3" />(已同步)</translation>
<translation id="6027201098523975773">请输入名称</translation>
<translation id="6040143037577758943">关闭</translation>
-<translation id="6042308850641462728">更多</translation>
<translation id="6047233362582046994">如果您了解自己将面临的安全风险,则可在有害应用被移除之前<ph name="BEGIN_LINK" />访问此网站<ph name="END_LINK" />。</translation>
<translation id="6047927260846328439">此内容可能会试图诱骗您安装软件或透露个人信息。<ph name="BEGIN_LINK" />仍然显示<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">您目前无法访问 <ph name="SITE" />,因为此网站使用了证书锁定。网络错误和攻击通常是暂时的,因此,此网页稍后可能会恢复正常。</translation>
@@ -693,6 +719,7 @@
<translation id="6569060085658103619">您正在查看扩展程序页面</translation>
<translation id="6596325263575161958">加密选项</translation>
<translation id="662080504995468778">留下</translation>
+<translation id="6624427990725312378">联系信息</translation>
<translation id="6626291197371920147">添加有效的卡号</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> 搜索</translation>
<translation id="6630809736994426279">攻击者可能会试图通过 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在您的 Mac 上安装危险程序,以窃取或删除您的信息(如照片、密码、通讯内容和信用卡信息)。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -703,7 +730,6 @@
<translation id="6710213216561001401">上一个</translation>
<translation id="6710594484020273272">&lt;输入搜索字词&gt;</translation>
<translation id="6711464428925977395">代理服务器出现问题,或者地址有误。</translation>
-<translation id="6727102863431372879">设置</translation>
<translation id="674375294223700098">未知的服务器证书错误。</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您的设备已进入休眠模式。</translation>
@@ -772,6 +798,7 @@
<translation id="7400418766976504921">网址</translation>
<translation id="7419106976560586862">个人资料路径</translation>
<translation id="7424977062513257142">此网页上的嵌入式页面显示:</translation>
+<translation id="7437289804838430631">添加联系信息</translation>
<translation id="7441627299479586546">策略主题有误</translation>
<translation id="7444046173054089907">此网站已被屏蔽</translation>
<translation id="7445762425076701745">无法完全验证您所连接到的服务器的身份。您在连接服务器时使用的服务器名称仅在您的网络中有效,而外部证书授权中心无法验证该名称的所有权。由于一些证书授权中心仍然会为这些名称颁发证书,因此无法确保您连接到想要访问的网站而不是攻击网站。</translation>
@@ -782,11 +809,11 @@
<translation id="7481312909269577407">前进</translation>
<translation id="7485870689360869515">找不到数据。</translation>
<translation id="7508255263130623398">返回的政策设备 ID 为空,或与当前的设备 ID 不一致</translation>
+<translation id="7511955381719512146">您要使用的 Wi-Fi 网络可能需要您访问 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
<translation id="7514365320538308">下载</translation>
<translation id="7518003948725431193">找不到与以下网址对应的网页:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">您与此网站的连接不是私密连接</translation>
-<translation id="7535087603100972091">值</translation>
<translation id="7537536606612762813">强制</translation>
<translation id="7542403920425041731">一旦您予以确认,系统便会将您的信用卡详情共享给此网站。</translation>
<translation id="7542995811387359312">由于该表单不使用安全连接,因此自动填写信用卡信息的功能已停用。</translation>
@@ -797,7 +824,6 @@
<translation id="7567204685887185387">此服务器无法证明它是<ph name="DOMAIN" />;其安全证书可能是由骗子发出的。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
<translation id="7568593326407688803">此网页为<ph name="ORIGINAL_LANGUAGE" />网页,是否需要翻译?</translation>
<translation id="7569952961197462199">从 Chrome 中移除信用卡信息?</translation>
-<translation id="7569983096843329377">黑色</translation>
<translation id="7578104083680115302">通过各种设备在网站和应用中购物时,您都可以使用 Google 为您保存的银行卡信息快速付款。</translation>
<translation id="7588950540487816470">实物网</translation>
<translation id="7592362899630581445">服务器的证书违反了域名限制。</translation>
@@ -816,11 +842,13 @@
<translation id="7669271284792375604">此网站上的攻击者可能会试图诱骗您安装有损浏览体验的程序(例如:通过更改您的主页或在您访问的网站上显示额外的广告)。</translation>
<translation id="7674629440242451245">想试试超酷的 Chrome 新功能?欢迎访问 chrome.com/dev,试用我们的测试版!</translation>
<translation id="7682287625158474539">送货地址</translation>
+<translation id="7699293099605015246">目前没有文章可显示</translation>
<translation id="7701040980221191251">无</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />继续前往<ph name="SITE" />(不安全)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">证书</translation>
<translation id="7716147886133743102">已被您的管理员阻止</translation>
<translation id="7716424297397655342">无法从缓存中加载此网站</translation>
+<translation id="7723047071702270851">修改支付卡</translation>
<translation id="774634243536837715">危险内容已被拦截。</translation>
<translation id="7752995774971033316">非托管</translation>
<translation id="7755287808199759310">您的父亲/母亲可为您取消屏蔽此网站</translation>
@@ -831,21 +859,24 @@
<translation id="7764225426217299476">添加地址</translation>
<translation id="777702478322588152">县</translation>
<translation id="7791543448312431591">添加</translation>
+<translation id="7793553086574152071">若想在下次购物时更快捷地付款,请将此卡片的信息保存到您的 Google 帐号中。</translation>
<translation id="7793809570500803535">网址为 <ph name="SITE" /> 的网页可能暂时无法连接或已永久性地移动到了新网址。</translation>
<translation id="7800304661137206267">该连接是使用 <ph name="CIPHER" /> 进行加密的,同时使用 <ph name="MAC" /> 进行讯息身份验证并使用 <ph name="KX" /> 作为密钥交换机制。</translation>
+<translation id="7802523362929240268">网站是合规的</translation>
<translation id="780301667611848630">不用了,谢谢</translation>
<translation id="7805768142964895445">状态</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">从 Chrome 中移除表单建议?</translation>
<translation id="7815407501681723534">找到了 <ph name="NUMBER_OF_RESULTS" /> 个与“<ph name="SEARCH_STRING" />”相符的<ph name="SEARCH_RESULTS" /></translation>
+<translation id="782886543891417279">您要使用的 Wi-Fi 网络(<ph name="WIFI_NAME" />)可能需要您访问其登录页面。</translation>
<translation id="785549533363645510">但是,这并不意味着您能完全隐身。即使您进入隐身模式,您的雇主、互联网服务提供商和您访问的网站仍然能看到您的浏览活动。</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">接受借记卡和预付卡。</translation>
+<translation id="7878562273885520351">您的密码可能会被盗用</translation>
<translation id="7887683347370398519">请检查您的银行卡验证码 (CVC),然后重试</translation>
<translation id="79338296614623784">请输入有效的电话号码</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">服务器的证书尚未生效。</translation>
-<translation id="7942349550061667556">红色</translation>
<translation id="7947285636476623132">请检查您的信用卡到期年份,然后重试</translation>
<translation id="7951415247503192394">(32 位)</translation>
<translation id="7956713633345437162">移动设备书签</translation>
@@ -859,9 +890,13 @@
<translation id="8037357227543935929">询问(默认)</translation>
<translation id="8041089156583427627">发送反馈</translation>
<translation id="8041940743680923270">使用全局默认设置(询问)</translation>
+<translation id="8057711352706143257">“<ph name="SOFTWARE_NAME" />”的配置有误。卸载“<ph name="SOFTWARE_NAME" />”通常可解决此问题。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">无法查看文章。</translation>
<translation id="8091372947890762290">正等待在服务器上激活</translation>
+<translation id="8094917007353911263">您要使用的网络可能需要您访问 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
+<translation id="8103161714697287722">付款方式</translation>
<translation id="8118489163946903409">付款方式</translation>
+<translation id="8127301229239896662">“<ph name="SOFTWARE_NAME" />”没有正确地安装到您的计算机或网络上。请让您的 IT 管理员解决此问题。</translation>
<translation id="8131740175452115882">确认</translation>
<translation id="8134994873729925007">找不到 <ph name="HOST_NAME" /> 的服务器 <ph name="BEGIN_ABBR" />DNS 地址<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您的计算机已进入休眠模式。</translation>
@@ -884,6 +919,7 @@
<translation id="8289355894181816810">如果您不确定这是什么意思,请与您的网络管理员联系。</translation>
<translation id="8293206222192510085">添加书签</translation>
<translation id="8294431847097064396">来源</translation>
+<translation id="8298115750975731693">您要使用的 Wi-Fi 网络(<ph name="WIFI_NAME" />)可能需要您访问 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
<translation id="8306404619377842860">您设备的日期和时间(<ph name="DATE_AND_TIME" />)不正确,因此无法与 <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立私密连接。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">由于网络连接问题,翻译失败。</translation>
<translation id="8332188693563227489">访问 <ph name="HOST_NAME" /> 的请求遭到拒绝</translation>
@@ -937,20 +973,21 @@
<translation id="8870413625673593573">最近关闭的标签页</translation>
<translation id="8874824191258364635">请输入有效的信用卡号</translation>
<translation id="8876793034577346603">无法解析网络配置。</translation>
-<translation id="8889402386540077796">色调</translation>
<translation id="8891727572606052622">代理模式无效。</translation>
<translation id="889901481107108152">抱歉,此项实验性功能不能用于您的平台。</translation>
<translation id="8903921497873541725">放大</translation>
<translation id="8931333241327730545">要将此卡的信息保存到您的 Google 帐号吗?</translation>
<translation id="8932102934695377596">您的时钟慢了</translation>
+<translation id="893332455753468063">添加名称</translation>
<translation id="8938939909778640821">接受的信用卡和预付卡</translation>
+<translation id="8957210676456822347">强制门户授权</translation>
<translation id="8971063699422889582">服务器的证书已过期。</translation>
-<translation id="8986494364107987395">将使用情况统计信息和崩溃报告自动发送给 Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">您要访问的网站包含有害程序</translation>
<translation id="8997023839087525404">该服务器提供了一个未通过证书透明度政策公开披露的证书。某些证书必须通过证书透明度政策进行公开披露,以确保它们值得信任且能保护用户免遭攻击。</translation>
<translation id="9001074447101275817">代理 (<ph name="DOMAIN" />) 要求提供用户名和密码。</translation>
<translation id="9005998258318286617">未能加载 PDF 文档。</translation>
+<translation id="9008201768610948239">忽略</translation>
<translation id="901974403500617787">应用于整个系统的设置只能由以下所有者设定:<ph name="OWNER_EMAIL" />。</translation>
<translation id="9020200922353704812">必须输入信用卡帐单邮寄地址</translation>
<translation id="9020542370529661692">已将此网页内容翻译成<ph name="TARGET_LANGUAGE" /></translation>
@@ -960,11 +997,14 @@
<translation id="9049981332609050619">您试图访问 <ph name="DOMAIN" />,但服务器提供的证书无效。</translation>
<translation id="9050666287014529139">密码</translation>
<translation id="9065203028668620118">修改</translation>
-<translation id="9068849894565669697">选择颜色</translation>
<translation id="9069693763241529744">已被某款扩展程序阻止</translation>
<translation id="9076283476770535406">此网站可能包含成人内容</translation>
<translation id="9078964945751709336">必须提供更多信息</translation>
+<translation id="9080712759204168376">订单摘要</translation>
<translation id="9103872766612412690"><ph name="SITE" /> 通常会使用加密技术来保护您的信息。Chromium 此次尝试连接到 <ph name="SITE" /> 时,此网站发回了异常的错误凭据。这可能是因为有攻击者在试图冒充 <ph name="SITE" />,或 Wi-Fi 登录屏幕中断了此次连接。请放心,您的信息仍然是安全的,因为 Chromium 尚未进行任何数据交换便停止了连接。</translation>
+<translation id="9106062320799175032">添加帐单邮寄地址</translation>
+<translation id="910908805481542201">帮我解决此问题</translation>
+<translation id="9128870381267983090">连接到网络</translation>
<translation id="9137013805542155359">显示原始网页</translation>
<translation id="9137248913990643158">在使用此应用前,请先启动并登录 Chrome。</translation>
<translation id="9148507642005240123">撤消修改(&amp;U)</translation>
@@ -976,6 +1016,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> 使用了不受支持的协议。</translation>
<translation id="9205078245616868884">您的数据已使用您的同步密码加密。输入该密码即可开始同步。</translation>
<translation id="9207861905230894330">无法添加文章。</translation>
+<translation id="9215416866750762878">有一款应用正在阻止 Chrome 安全地连接到此网站</translation>
<translation id="9219103736887031265">图片</translation>
<translation id="933612690413056017">未连接到互联网</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -985,5 +1026,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{无}=1{1 项内容}other{# 项内容}}</translation>
<translation id="981121421437150478">离线</translation>
<translation id="988159990683914416">开发者内部版本</translation>
+<translation id="989988560359834682">修改地址</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">“<ph name="SOFTWARE_NAME" />”没有正确地安装到您的计算机或网络上:
+ &lt;ul&gt;
+ &lt;li&gt;请尝试卸载或停用“<ph name="SOFTWARE_NAME" />”&lt;/li&gt;
+ &lt;li&gt;请尝试连接到其他网络&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index 8084658a3b1..4cfca095230 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -13,7 +13,9 @@
<translation id="106701514854093668">電腦版書籤</translation>
<translation id="1074497978438210769">不安全</translation>
<translation id="1080116354587839789">符合視窗寬度</translation>
+<translation id="1088860948719068836">新增持卡人姓名</translation>
<translation id="1103523840287552314">一律翻譯<ph name="LANGUAGE" /></translation>
+<translation id="1103778128462718200">顯示所有已儲存的密碼...</translation>
<translation id="1107591249535594099">勾選後,Chrome 會在這個裝置上儲存您的信用卡複本,以便更快填寫資訊。</translation>
<translation id="1111153019813902504">最近使用過的書籤</translation>
<translation id="1113869188872983271">復原重新排序(&amp;U)</translation>
@@ -43,6 +45,7 @@
<translation id="1253921432148366685"><ph name="TYPE_1" />、<ph name="TYPE_2" /> (已同步)</translation>
<translation id="1263231323834454256">閱讀清單</translation>
<translation id="1264126396475825575">當機報告擷取時間:<ph name="CRASH_TIME" /> (尚未上傳或略過)</translation>
+<translation id="1270502636509132238">取件方式</translation>
<translation id="1281526147609854549">核發者:<ph name="ISSUER" /></translation>
<translation id="1285320974508926690">一律不翻譯此網站</translation>
<translation id="129553762522093515">最近關閉的分頁</translation>
@@ -73,12 +76,10 @@
<translation id="1527263332363067270">正在等待連線…</translation>
<translation id="153384715582417236">暫無內容</translation>
<translation id="1549470594296187301">您必須啟用 JavaScript 才能使用這項功能。</translation>
-<translation id="1555130319947370107">藍色</translation>
<translation id="1559528461873125649">找不到你所指定的檔案或目錄</translation>
<translation id="1583429793053364125">顯示這個網頁時發生錯誤。</translation>
<translation id="1592005682883173041">本機資料存取權</translation>
<translation id="1594030484168838125">選擇</translation>
-<translation id="161042844686301425">青色</translation>
<translation id="1620510694547887537">攝影機</translation>
<translation id="1629803312968146339">您希望 Chrome 儲存這張信用卡嗎?</translation>
<translation id="1639239467298939599">載入中</translation>
@@ -96,6 +97,7 @@
<translation id="1710259589646384581">作業系統</translation>
<translation id="1721312023322545264">你必須獲得<ph name="NAME" />授權,才能造訪這個網站</translation>
<translation id="1721424275792716183">* 這是必填欄位</translation>
+<translation id="1727741090716970331">新增有效的信用卡號碼</translation>
<translation id="1728677426644403582">目前顯示的是網頁原始碼</translation>
<translation id="173080396488393970">不支援這種信用卡類型</translation>
<translation id="1734864079702812349">Amex</translation>
@@ -130,7 +132,6 @@
<translation id="1973335181906896915">序列化錯誤</translation>
<translation id="1974060860693918893">進階</translation>
<translation id="1978555033938440688">韌體版本</translation>
-<translation id="1995859865337580572">請確認你的信用卡安全碼</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{以及另外 1 個應用程式}other{以及另外 # 個應用程式}}</translation>
<translation id="2025186561304664664">Proxy 已設為自動設定。</translation>
<translation id="2030481566774242610">你要找的是 <ph name="LINK" /> 嗎?</translation>
@@ -141,6 +142,7 @@
<translation id="2079545284768500474">復原</translation>
<translation id="20817612488360358">雖然系統 Proxy 設定已設為使用,不過也指定了明確 Proxy 設定。</translation>
<translation id="2086652334978798447">如要取得個人化的 Google 推薦內容,請登入 Chrome。</translation>
+<translation id="2091887806945687916">音訊</translation>
<translation id="2094505752054353250">網域不符</translation>
<translation id="2096368010154057602">省</translation>
<translation id="2108755909498034140">重新啟動電腦</translation>
@@ -148,7 +150,9 @@
<translation id="2114841414352855701">由於政策被「<ph name="POLICY_NAME" />」覆寫了,因此遭到略過。</translation>
<translation id="2138201775715568214">正在尋找附近的實體化網路網頁</translation>
<translation id="213826338245044447">行動版書籤</translation>
+<translation id="214556005048008348">取消付款</translation>
<translation id="2147827593068025794">背景同步處理</translation>
+<translation id="2148613324460538318">新增卡片</translation>
<translation id="2154054054215849342">你的網域無法使用同步功能</translation>
<translation id="2154484045852737596">編輯卡片資訊</translation>
<translation id="2166049586286450108">完整管理員存取權</translation>
@@ -157,6 +161,7 @@
<translation id="2184405333245229118">{COUNT,plural, =1{1 個地址}other{# 個地址}}</translation>
<translation id="2187317261103489799">偵測 (預設)</translation>
<translation id="2202020181578195191">請輸入有效的到期年份</translation>
+<translation id="2209523182407020534">可能造成這個錯誤的應用程式包括防毒軟體、防火牆、網路篩選或 Proxy 軟體。</translation>
<translation id="2212735316055980242">找不到政策</translation>
<translation id="2213606439339815911">正在擷取項目...</translation>
<translation id="2218879909401188352">目前在 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的攻擊者可能會讓你安裝不安全的應用程式,導致裝置受損、手機帳單中多出隱藏費用,或是個人資訊遭竊。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -197,6 +202,8 @@
<translation id="2501278716633472235">返回</translation>
<translation id="2503184589641749290">接受的簽帳金融卡和預付卡</translation>
<translation id="2515629240566999685">檢查所在位置的網路訊號</translation>
+<translation id="2524461107774643265">新增詳細資訊</translation>
+<translation id="2536110899380797252">新增地址</translation>
<translation id="2539524384386349900">偵測</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> 傳送的回應無效。</translation>
<translation id="2556876185419854533">復原編輯(&amp;U)</translation>
@@ -219,8 +226,8 @@
<translation id="2704951214193499422">Chromium 目前無法驗證您的信用卡,請稍後再試。</translation>
<translation id="2705137772291741111">已儲存 (快取) 這個網站的複本,但無法讀取。</translation>
<translation id="2709516037105925701">自動填入</translation>
+<translation id="2710942282213947212">你的電腦上有軟體在阻止 Chromium 建立安全的網路連線</translation>
<translation id="2712173769900027643">要求權限</translation>
-<translation id="2713444072780614174">白色</translation>
<translation id="2720342946869265578">鄰近網頁</translation>
<translation id="2721148159707890343">要求成功</translation>
<translation id="2728127805433021124">伺服器憑證是以防護力較弱的簽章演算法進行簽署。</translation>
@@ -243,6 +250,7 @@
<translation id="2909946352844186028">系統偵測到網路變更。</translation>
<translation id="2916038427272391327">關閉其他程式</translation>
<translation id="2922350208395188000">無法檢查伺服器憑證。</translation>
+<translation id="2925673989565098301">快遞方式</translation>
<translation id="2928905813689894207">帳單地址</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}other{「<ph name="SHIPPING_ADDRESS_PREVIEW" />」和另外 <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> 個地址}}</translation>
<translation id="2941952326391522266">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證來自 <ph name="DOMAIN2" /> 網域。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
@@ -265,6 +273,7 @@
<translation id="3024663005179499861">政策類型有誤</translation>
<translation id="3032412215588512954">您要重新載入這個網站嗎?</translation>
<translation id="3037605927509011580">糟糕!</translation>
+<translation id="3039538478787849737">要將卡片資訊儲存到 Google 嗎?</translation>
<translation id="3041612393474885105">憑證資訊</translation>
<translation id="3063697135517575841">Chrome 目前無法驗證您的信用卡,請稍後再試。</translation>
<translation id="3064966200440839136">即將離開無痕模式,改為使用外部應用程式付款,要繼續嗎?</translation>
@@ -278,6 +287,7 @@
<translation id="3150653042067488994">伺服器暫時發生錯誤</translation>
<translation id="3154506275960390542">這個網頁中的表單可能不會經由安全途徑提交。其他人可能會在傳輸期間檢視你的資料,攻擊者也可能會修改這些資料,導致伺服器接收不同內容。</translation>
<translation id="3157931365184549694">還原</translation>
+<translation id="3162559335345991374">目前使用的 Wi-Fi 網路可能會要求您造訪登入網頁。</translation>
<translation id="3167968892399408617">當您關閉所有無痕式分頁後,您在其中瀏覽的網頁都不會保留在瀏覽器紀錄、Cookie 儲存庫或搜尋紀錄中。不過,您下載的檔案或建立的書籤全部都會保留下來。</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">島</translation>
@@ -287,6 +297,7 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="320323717674993345">取消付款</translation>
<translation id="3207960819495026254">已加入書籤</translation>
+<translation id="3211223744486044430">只要將這張卡片的資訊儲存到你的 Google 帳戶中和這部裝置上,下次即可更快完成付款程序。</translation>
<translation id="3225919329040284222">伺服器呈現的憑證與內建的預期條件不符。我們在系統中針對特定高安全性的網站內建了這些預期條件,目的在於保護你的資料安全無虞。</translation>
<translation id="3226128629678568754">按下重新載入按鈕,重新提交載入網頁所需的資料。</translation>
<translation id="3227137524299004712">麥克風</translation>
@@ -301,7 +312,6 @@
<translation id="3303855915957856445">找不到相符的搜尋結果</translation>
<translation id="3305707030755673451">您已在 <ph name="TIME" />使用同步通關密語對資料進行加密,請輸入通關密語開始進行同步。</translation>
<translation id="3320021301628644560">新增帳單地址</translation>
-<translation id="3329013043687509092">飽和度</translation>
<translation id="333371639341676808">防止此網頁產生其他對話方塊。</translation>
<translation id="3338095232262050444">安全</translation>
<translation id="3340978935015468852">設定</translation>
@@ -320,6 +330,7 @@
<translation id="3380864720620200369">用戶端 ID:</translation>
<translation id="3391030046425686457">快遞地址</translation>
<translation id="3395827396354264108">取件方式</translation>
+<translation id="3399952811970034796">快遞地址</translation>
<translation id="3422248202833853650">嘗試關閉其他程式以釋出記憶體。</translation>
<translation id="3422472998109090673">目前無法連上 <ph name="HOST_NAME" />。</translation>
<translation id="3427092606871434483">允許 (預設)</translation>
@@ -365,10 +376,12 @@
<translation id="3679803492151881375">當機報告擷取時間:<ph name="CRASH_TIME" />,報告上傳時間:<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">憑證資訊</translation>
<translation id="3690164694835360974">登入行為不安全</translation>
+<translation id="3704162925118123524">您可能需要造訪目前所使用網路的登入網頁。</translation>
<translation id="3704609568417268905"><ph name="TIME" />,<ph name="BOOKMARKED" />,<ph name="TITLE" />,<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">載入中…</translation>
<translation id="3712624925041724820">授權已用盡</translation>
<translation id="3714780639079136834">開啟行動數據或 Wi-Fi</translation>
+<translation id="3715597595485130451">連線至 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />檢查 Proxy、防火牆和 DNS 設定<ph name="END_LINK" /></translation>
<translation id="3736520371357197498">如果你瞭解安全性風險,也可以選擇在危險程式尚未遭到移除的狀態下<ph name="BEGIN_LINK" />造訪這個不安全的網站<ph name="END_LINK" />。</translation>
<translation id="3739623965217189342">您複製的連結</translation>
@@ -403,6 +416,7 @@
<translation id="4030383055268325496">復原新增(&amp;U)</translation>
<translation id="404928562651467259">警告</translation>
<translation id="4058922952496707368">鍵「<ph name="SUBKEY" />」:<ph name="ERROR" /></translation>
+<translation id="4067947977115446013">新增有效的地址</translation>
<translation id="4072486802667267160">處理你的訂單時發生錯誤,請再試一次。</translation>
<translation id="4075732493274867456">用戶端和伺服器不支援一般 SSL 通訊協定版本或加密套件。</translation>
<translation id="4079302484614802869">Proxy 設定已設為使用 .pac 指令碼網址,而非固定的 Proxy 伺服器。</translation>
@@ -410,7 +424,6 @@
<translation id="4103249731201008433">裝置序號無效</translation>
<translation id="410351446219883937">自動播放</translation>
<translation id="4103763322291513355">請前往 &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看列入黑名單的網址清單,以及其他系統管理員強制執行的政策。</translation>
-<translation id="4115378294792113321">洋紅色</translation>
<translation id="4116663294526079822">永遠允許在這個網站執行</translation>
<translation id="4117700440116928470">系統不支援這項政策的範圍。</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{以及另外 1 項表單資料}other{以及另外 # 項表單資料}}</translation>
@@ -448,6 +461,7 @@
<translation id="4377125064752653719">你嘗試前往 <ph name="DOMAIN" />,但是發行者已撤銷伺服器提供的憑證。在這種情況下,請勿信任伺服器提供的安全性憑證,因為你的連線對象可能是攻擊者的電腦。</translation>
<translation id="4394049700291259645">停用</translation>
<translation id="4406896451731180161">搜尋結果</translation>
+<translation id="4415426530740016218">取件地址</translation>
<translation id="4424024547088906515">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證未取得 Chrome 的信任。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> 不接受你的登入憑證,或是你可能未提供登入憑證。</translation>
<translation id="443673843213245140">雖然已停用 Proxy,不過已指定明確 Proxy 設定。</translation>
@@ -460,6 +474,7 @@
<translation id="4552089082226364758">Flash</translation>
<translation id="4558551763791394412">試試看停用擴充功能。</translation>
<translation id="457875822857220463">快遞</translation>
+<translation id="4582800630050655161">你可能失去了 Google 帳戶存取權,或身分遭到冒用。Chromium 建議你立即變更密碼。</translation>
<translation id="4587425331216688090">要從 Chrome 中移除地址嗎?</translation>
<translation id="4592951414987517459">您的 <ph name="DOMAIN" /> 連線使用新型加密套件進行加密。</translation>
<translation id="4594403342090139922">復原刪除(&amp;U)</translation>
@@ -468,10 +483,12 @@
<translation id="4668929960204016307">,</translation>
<translation id="467662567472608290">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證含有錯誤。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
<translation id="4690462567478992370">停止使用無效的憑證</translation>
+<translation id="4690954380545377795">你可能失去了 Google 帳戶存取權,或身分遭到冒用。Chrome 建議你立即變更密碼。</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">您的連線已中斷</translation>
<translation id="471880041731876836">你沒有這個網站的瀏覽權限</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />執行 Windows 網路診斷<ph name="END_LINK" /></translation>
+<translation id="472349245089439925">你的付款</translation>
<translation id="4726672564094551039">重新載入政策</translation>
<translation id="4728558894243024398">平台</translation>
<translation id="4736825316280949806">重新啟動 Chromium</translation>
@@ -510,6 +527,7 @@
<translation id="5019198164206649151">備份儲存狀態不佳</translation>
<translation id="5023310440958281426">請查看你的管理員政策</translation>
<translation id="5029568752722684782">清除複本</translation>
+<translation id="503069730517007720">未安裝必要的「<ph name="SOFTWARE_NAME" />」根憑證。IT 管理員必須按照「<ph name="SOFTWARE_NAME" />」的設定說明修正這個問題。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">關於「Google 翻譯」</translation>
<translation id="5039804452771397117">允許</translation>
<translation id="5040262127954254034">隱私權</translation>
@@ -533,6 +551,8 @@
<translation id="5199729219167945352">實驗性功能</translation>
<translation id="5205222826937269299">請輸入名稱</translation>
<translation id="5222812217790122047">請輸入電子郵件地址</translation>
+<translation id="522700295135997067">這個網站剛剛可能竊取了你的密碼</translation>
+<translation id="5230733896359313003">運送地址</translation>
<translation id="5251803541071282808">雲端</translation>
<translation id="5277279256032773186">在工作環境使用 Chrome 嗎?企業可以管理員工的 Chrome 設定。瞭解詳情</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />請按照以下步驟暫時停用該軟體,以便順利連上網路。你需要管理員權限。<ph name="END_PARAGRAPH" />
@@ -547,9 +567,11 @@
<ph name="END_LIST" /></translation>
<translation id="5297526204711817721">你與這個網站之間的連線不是私人連線。你隨時可以摘下頭戴式裝置,然後按下返回鍵退出 VR 模式。</translation>
<translation id="5299298092464848405">解析政策時發生錯誤</translation>
+<translation id="5308380583665731573">連線</translation>
<translation id="5308689395849655368">當機報告功能已停用。</translation>
<translation id="5317780077021120954">儲存</translation>
<translation id="5327248766486351172">名稱</translation>
+<translation id="5332219387342487447">運送方式</translation>
<translation id="5355557959165512791">目前無法造訪 <ph name="SITE" />,因為這個網站的憑證已遭撤銷。網路錯誤和攻擊行為通常是暫時性的,因此這個網頁可能稍後就會恢復正常狀態。</translation>
<translation id="536296301121032821">無法儲存政策設定</translation>
<translation id="5386426401304769735">這個網站的憑證鏈結包含使用 SHA-1 進行簽署的憑證。</translation>
@@ -569,12 +591,15 @@
<translation id="5492298309214877701">這個位於公司、機構或學校內部網路的網站使用的網址與某個外部網站相同。
<ph name="LINE_BREAK" />
請與您的系統管理員聯絡。</translation>
+<translation id="5499929369096410817">輸入 <ph name="CREDIT_CARD" /> 的安全碼 (系統不會加以儲存)。</translation>
<translation id="5509780412636533143">受管理書籤</translation>
<translation id="5510766032865166053">檔案可能已移至其他位置或遭到刪除。</translation>
<translation id="5523118979700054094">政策名稱</translation>
<translation id="552553974213252141">擷取的文字是否正確?</translation>
<translation id="5540224163453853">找不到要求的文章。</translation>
+<translation id="5541546772353173584">新增電子郵件地址</translation>
<translation id="5544037170328430102"><ph name="SITE" /> 的嵌入式網頁顯示:</translation>
+<translation id="5545756402275714221">為你推薦的報導</translation>
<translation id="5556459405103347317">重新載入</translation>
<translation id="5560088892362098740">到期日</translation>
<translation id="5565735124758917034">管理中</translation>
@@ -596,6 +621,7 @@
<translation id="5659593005791499971">電子郵件</translation>
<translation id="5669703222995421982">取得個人化內容</translation>
<translation id="5675650730144413517">這個網頁無法正常運作</translation>
+<translation id="5689199277474810259">以 JSON 格式匯出</translation>
<translation id="5710435578057952990">此網頁的身分未經驗證。</translation>
<translation id="5719499550583120431">接受預付卡。</translation>
<translation id="5720705177508910913">目前使用者</translation>
@@ -610,27 +636,27 @@
<translation id="5810442152076338065">您的 <ph name="DOMAIN" /> 連線使用過舊的加密套件進行加密。</translation>
<translation id="5813119285467412249">重做新增(&amp;R)</translation>
<translation id="5838278095973806738">請勿在這個網站上輸入任何機密資訊 (例如密碼或信用卡號碼),以免遭到攻擊者竊取。</translation>
+<translation id="5866257070973731571">新增電話號碼</translation>
<translation id="5869405914158311789">無法連上這個網站</translation>
<translation id="5869522115854928033">已儲存的密碼</translation>
<translation id="5872918882028971132">家長建議</translation>
<translation id="5893752035575986141">接受簽帳金融卡。</translation>
-<translation id="5901630391730855834">黃色</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (已同步)</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{目前使用 1 個 Cookie}other{目前使用 # 個 Cookie}}</translation>
<translation id="5959728338436674663">自動傳送部分<ph name="BEGIN_WHITEPAPER_LINK" />系統資訊和網頁內容<ph name="END_WHITEPAPER_LINK" />給 Google,協助偵測危險的應用程式和網站。<ph name="PRIVACY_PAGE_LINK" /></translation>
+<translation id="5967592137238574583">編輯聯絡資訊</translation>
<translation id="5967867314010545767">從紀錄中移除</translation>
<translation id="5975083100439434680">縮小</translation>
+<translation id="597552863672748783">確認安全碼</translation>
<translation id="598637245381783098">無法開啟付款應用程式</translation>
<translation id="5989320800837274978">沒有指定固定的 Proxy 伺服器和 .pac 指令碼網址。</translation>
<translation id="5990559369517809815">擴充功能已封鎖要傳送至伺服器的要求。</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{第 1 頁}other{第 # 頁}}</translation>
-<translation id="6017514345406065928">綠色</translation>
<translation id="6017850046339264347">目前在 <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="6025416945513303461"><ph name="TYPE_1" />、<ph name="TYPE_2" />、<ph name="TYPE_3" /> (已同步)</translation>
<translation id="6027201098523975773">輸入名稱</translation>
<translation id="6040143037577758943">關閉</translation>
-<translation id="6042308850641462728">更多</translation>
<translation id="6047233362582046994">如果你瞭解安全性風險,也可以選擇在有害應用程式尚未遭到移除的狀態下<ph name="BEGIN_LINK" />造訪這個網站<ph name="END_LINK" />。</translation>
<translation id="6047927260846328439">這項內容可能會試圖誘使你安裝軟體或提供個人資訊。<ph name="BEGIN_LINK" />仍要顯示<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">目前無法造訪 <ph name="SITE" />,因為這個網站使用憑證鎖定功能。網路錯誤和攻擊行為通常是暫時性的,因此這個網頁可能稍後就會恢復正常狀態。</translation>
@@ -697,6 +723,7 @@
<translation id="6569060085658103619">目前顯示的是擴充功能頁面</translation>
<translation id="6596325263575161958">加密選項</translation>
<translation id="662080504995468778">不離開</translation>
+<translation id="6624427990725312378">聯絡資訊</translation>
<translation id="6626291197371920147">新增有效的信用卡號碼</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> 搜尋</translation>
<translation id="6630809736994426279">攻擊者目前可能會試圖透過 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在你的 Mac 上安裝危險程式,藉此竊取或刪除你的資訊 (例如相片、密碼、郵件和信用卡資料)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
@@ -707,7 +734,6 @@
<translation id="6710213216561001401">返回</translation>
<translation id="6710594484020273272">&lt;輸入搜尋字詞&gt;</translation>
<translation id="6711464428925977395">Proxy 伺服器發生錯誤,或是位址不正確。</translation>
-<translation id="6727102863431372879">設定</translation>
<translation id="674375294223700098">不明的伺服器憑證錯誤。</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您的裝置已進入睡眠模式。</translation>
@@ -776,6 +802,7 @@
<translation id="7400418766976504921">網址</translation>
<translation id="7419106976560586862">設定檔路徑</translation>
<translation id="7424977062513257142">這個網頁上的嵌入式網頁顯示:</translation>
+<translation id="7437289804838430631">新增聯絡資訊</translation>
<translation id="7441627299479586546">政策主體有誤</translation>
<translation id="7444046173054089907">這個網站遭到封鎖</translation>
<translation id="7445762425076701745">你所連線的伺服器身分無法完全驗證,該伺服器所使用的名稱僅在你的網路中有效,無法驗證外部憑證授權單位的擁有權。即使某些憑證授權單位會核發這些憑證,不過無法就此確保你所連上的網站是正確的,而不會遭到網路攻擊。</translation>
@@ -786,11 +813,11 @@
<translation id="7481312909269577407">往前</translation>
<translation id="7485870689360869515">找不到任何資料。</translation>
<translation id="7508255263130623398">傳回的政策裝置 ID 沒有任何內容,或是與目前的裝置 ID 不符</translation>
+<translation id="7511955381719512146">目前使用的 Wi-Fi 網路可能會要求您造訪 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
<translation id="7514365320538308">下載</translation>
<translation id="7518003948725431193">找不到此網址的網頁:<ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">你與這個網站之間的連線不是私人連線</translation>
-<translation id="7535087603100972091">值</translation>
<translation id="7537536606612762813">強制</translation>
<translation id="7542403920425041731">經過你確認後,這個網站就會取得你的信用卡詳細資料。</translation>
<translation id="7542995811387359312">由於這個表單並未採用加密連線方式,所以信用卡自動填入功能已停用。</translation>
@@ -801,7 +828,6 @@
<translation id="7567204685887185387">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證是以欺詐方式發行。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
<translation id="7568593326407688803">此網頁為<ph name="ORIGINAL_LANGUAGE" />你要翻譯網頁內容嗎?</translation>
<translation id="7569952961197462199">要從 Chrome 中移除信用卡嗎?</translation>
-<translation id="7569983096843329377">黑色</translation>
<translation id="7578104083680115302">在不同的裝置上透過各個網站和應用程式消費時,使用您讓 Google 儲存的信用卡資料即可快速付款。</translation>
<translation id="7588950540487816470">實體化網路</translation>
<translation id="7592362899630581445">伺服器憑證的名稱不符合限制。</translation>
@@ -820,11 +846,13 @@
<translation id="7669271284792375604">攻擊者可能會試圖透過這個網站誘使你安裝對瀏覽體驗有害 (例如變更你的首頁,或是在你造訪的網站上顯示多餘的廣告) 的程式。</translation>
<translation id="7674629440242451245">想搶先試用酷炫的 Chrome 新功能嗎?請前往 chrome.com/dev 安裝開發人員版。</translation>
<translation id="7682287625158474539">寄送地址</translation>
+<translation id="7699293099605015246">目前無法顯示文章</translation>
<translation id="7701040980221191251">無</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />繼續前往 <ph name="SITE" /> 網站 (不安全)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">憑證</translation>
<translation id="7716147886133743102">依據管理員的設定封鎖</translation>
<translation id="7716424297397655342">無法從快取載入這個網站</translation>
+<translation id="7723047071702270851">編輯卡片資訊</translation>
<translation id="774634243536837715">已封鎖危險內容。</translation>
<translation id="7752995774971033316">未管理</translation>
<translation id="7755287808199759310">你的家長可以為你解除封鎖這個網站</translation>
@@ -835,21 +863,24 @@
<translation id="7764225426217299476">新增地址</translation>
<translation id="777702478322588152">縣</translation>
<translation id="7791543448312431591">新增</translation>
+<translation id="7793553086574152071">只要將這張卡片的資訊儲存到你的 Google 帳戶中,下次即可更快完成付款程序。</translation>
<translation id="7793809570500803535"><ph name="SITE" /> 的網頁可能暫時無法使用或已永久移至新網址。</translation>
<translation id="7800304661137206267">連線採用 <ph name="CIPHER" /> 加密,並設有 <ph name="MAC" /> 訊息驗證及 <ph name="KX" /> 金鑰交換機制。</translation>
+<translation id="7802523362929240268">網站合法</translation>
<translation id="780301667611848630">不用了,謝謝</translation>
<translation id="7805768142964895445">狀態</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">要從 Chrome 中移除建議嗎?</translation>
<translation id="7815407501681723534">找到 <ph name="NUMBER_OF_RESULTS" /> 個與「<ph name="SEARCH_STRING" />」相符的<ph name="SEARCH_RESULTS" /></translation>
+<translation id="782886543891417279">目前使用的 Wi-Fi 網路 (<ph name="WIFI_NAME" />) 可能會要求您造訪登入網頁。</translation>
<translation id="785549533363645510">不過,這並不意味著您可以完全隱形。使用無痕模式時,您的雇主和網際網路服務供應商仍然可以追蹤您的瀏覽紀錄,您所造訪的網站也可能會記錄您的瀏覽行為。</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7878176543348854470">接受簽帳金融卡和預付卡。</translation>
+<translation id="7878562273885520351">你的密碼可能已經外洩</translation>
<translation id="7887683347370398519">請檢查您的 CVC,然後再試一次</translation>
<translation id="79338296614623784">請輸入有效的電話號碼</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">伺服器憑證尚未生效。</translation>
-<translation id="7942349550061667556">紅色</translation>
<translation id="7947285636476623132">請檢查信用卡到期年份,然後再試一次</translation>
<translation id="7951415247503192394">(32 位元)</translation>
<translation id="7956713633345437162">行動版書籤</translation>
@@ -863,9 +894,13 @@
<translation id="8037357227543935929">詢問 (預設)</translation>
<translation id="8041089156583427627">提供意見</translation>
<translation id="8041940743680923270">使用全域預設值 (要求確認)</translation>
+<translation id="8057711352706143257">「<ph name="SOFTWARE_NAME" />」的設定不正確。通常解除安裝「<ph name="SOFTWARE_NAME" />」即可修正這個問題。<ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8088680233425245692">無法查看文章。</translation>
<translation id="8091372947890762290">尚未在伺服器上啟動</translation>
+<translation id="8094917007353911263">目前使用的網路可能會要求您造訪 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
+<translation id="8103161714697287722">付款方式</translation>
<translation id="8118489163946903409">付款方式</translation>
+<translation id="8127301229239896662">「<ph name="SOFTWARE_NAME" />」未正確安裝在電腦或網路上。請通知 IT 管理員解決這個問題。</translation>
<translation id="8131740175452115882">確認</translation>
<translation id="8134994873729925007">找不到 <ph name="HOST_NAME" /> 的伺服器 <ph name="BEGIN_ABBR" />DNS 位址<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您的電腦已進入睡眠模式。</translation>
@@ -888,6 +923,7 @@
<translation id="8289355894181816810">如果你不確定這代表什麼意思,請與網路管理員聯絡。</translation>
<translation id="8293206222192510085">新增書籤</translation>
<translation id="8294431847097064396">來源</translation>
+<translation id="8298115750975731693">目前使用的 Wi-Fi 網路 (<ph name="WIFI_NAME" />) 可能會要求您造訪 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
<translation id="8306404619377842860">裝置的日期和時間 (<ph name="DATE_AND_TIME" />) 不正確,因此無法與 <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立私人連線。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8308427013383895095">網路連線發生問題,翻譯作業失敗。</translation>
<translation id="8332188693563227489">存取 <ph name="HOST_NAME" /> 的要求遭到拒絕</translation>
@@ -940,20 +976,21 @@
<translation id="8870413625673593573">最近關閉的分頁</translation>
<translation id="8874824191258364635">請輸入有效的信用卡號碼</translation>
<translation id="8876793034577346603">無法解析網路設定。</translation>
-<translation id="8889402386540077796">色調</translation>
<translation id="8891727572606052622">Proxy 模式無效。</translation>
<translation id="889901481107108152">很抱歉,這項實驗功能無法支援你的平台。</translation>
<translation id="8903921497873541725">放大</translation>
<translation id="8931333241327730545">您要將這張卡片的資訊儲存到您的 Google 帳戶嗎?</translation>
<translation id="8932102934695377596">你的時鐘時間過慢</translation>
+<translation id="893332455753468063">新增名稱</translation>
<translation id="8938939909778640821">接受的信用卡和預付卡</translation>
+<translation id="8957210676456822347">監控式入口網站授權</translation>
<translation id="8971063699422889582">伺服器憑證已過期。</translation>
-<translation id="8986494364107987395">自動傳送使用統計資料及當機報告給 Google</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
<translation id="8996941253935762404">你要瀏覽的網站含有有害程式</translation>
<translation id="8997023839087525404">該伺服器的憑證並未根據憑證透明化政策對外公開。部分憑證必須符合這項規定,以確保憑證值得信任,不會讓使用者遭到攻擊。</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> Proxy 要求提供使用者名稱和密碼。</translation>
<translation id="9005998258318286617">無法載入 PDF 文件。</translation>
+<translation id="9008201768610948239">略過</translation>
<translation id="901974403500617787">這些設定會套用至整個系統,只有以下使用者可設定:<ph name="OWNER_EMAIL" />。</translation>
<translation id="9020200922353704812">請輸入信用卡帳單地址</translation>
<translation id="9020542370529661692">此網頁內容已翻譯成<ph name="TARGET_LANGUAGE" /></translation>
@@ -963,11 +1000,14 @@
<translation id="9049981332609050619">你嘗試連線至 <ph name="DOMAIN" />,但伺服器提供的憑證無效。</translation>
<translation id="9050666287014529139">通關密語</translation>
<translation id="9065203028668620118">編輯</translation>
-<translation id="9068849894565669697">選取顏色</translation>
<translation id="9069693763241529744">依據擴充功能設定封鎖</translation>
<translation id="9076283476770535406">這個網站可能含有成人內容</translation>
<translation id="9078964945751709336">請提供詳細資訊</translation>
+<translation id="9080712759204168376">訂單摘要</translation>
<translation id="9103872766612412690"><ph name="SITE" /> 通常使用加密方式保護您的資訊。但 Chromium 這次嘗試連線到 <ph name="SITE" /> 時,該網站傳回了異常且錯誤的憑證。這可能是因為有攻擊者企圖偽裝成 <ph name="SITE" />,或是受到 Wi-Fi 登入畫面影響而造成連線中斷。不過請放心,Chromium 已及時停止連線,並未傳輸任何資料,因此您的資訊仍然安全無虞。</translation>
+<translation id="9106062320799175032">新增帳單地址</translation>
+<translation id="910908805481542201">請協助我解決這個問題</translation>
+<translation id="9128870381267983090">連線至網路</translation>
<translation id="9137013805542155359">顯示原文</translation>
<translation id="9137248913990643158">使用這個應用程式前,請先啟動 Chrome 並登入帳戶。</translation>
<translation id="9148507642005240123">復原編輯(&amp;U)</translation>
@@ -979,6 +1019,7 @@
<translation id="9183425211371246419"><ph name="HOST_NAME" /> 使用了不支援的通訊協定。</translation>
<translation id="9205078245616868884">您已使用同步通關密語對資料進行加密,請輸入通關密語開始進行同步。</translation>
<translation id="9207861905230894330">無法新增文章。</translation>
+<translation id="9215416866750762878">有應用程式阻止 Chrome 建立這個網站的安全連線</translation>
<translation id="9219103736887031265">圖片</translation>
<translation id="933612690413056017">無法連上網際網路</translation>
<translation id="933712198907837967">Diners Club</translation>
@@ -988,5 +1029,11 @@
<translation id="975560348586398090">{COUNT,plural, =0{無}=1{1 個項目}other{# 個項目}}</translation>
<translation id="981121421437150478">離線</translation>
<translation id="988159990683914416">開發人員版本</translation>
+<translation id="989988560359834682">編輯地址</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
+<translation id="992432478773561401">「<ph name="SOFTWARE_NAME" />」未正確安裝在電腦或網路上:
+ &lt;ul&gt;
+ &lt;li&gt;嘗試解除安裝或停用「<ph name="SOFTWARE_NAME" />」&lt;/li&gt;
+ &lt;li&gt;嘗試連線至其他網路&lt;/li&gt;
+ &lt;/ul&gt;</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
index e8a80a7dd8b..2db31a5e697 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
@@ -138,14 +138,13 @@ ActivationStateComputingNavigationThrottle::filter() const {
// when activation IPCs are not sent to the render process.
std::unique_ptr<AsyncDocumentSubresourceFilter>
ActivationStateComputingNavigationThrottle::ReleaseFilter() {
- return could_send_activation_to_renderer_ ? std::move(async_filter_)
- : nullptr;
+ return will_send_activation_to_renderer_ ? std::move(async_filter_) : nullptr;
}
void ActivationStateComputingNavigationThrottle::
- CouldSendActivationToRenderer() {
+ WillSendActivationToRenderer() {
DCHECK(async_filter_);
- could_send_activation_to_renderer_ = true;
+ will_send_activation_to_renderer_ = true;
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
index 16d67ea012e..fc67179a91a 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
@@ -71,7 +71,7 @@ class ActivationStateComputingNavigationThrottle
AsyncDocumentSubresourceFilter* filter() const;
- void CouldSendActivationToRenderer();
+ void WillSendActivationToRenderer();
private:
void OnActivationStateComputed(ActivationState state);
@@ -95,12 +95,11 @@ class ActivationStateComputingNavigationThrottle
// Callback to be run in the destructor.
base::OnceClosure destruction_closure_;
- // Can become true when the throttle manager reaches ReadyToCommitNavigation.
+ // Will become true when the throttle manager reaches ReadyToCommitNavigation.
// Makes sure a caller cannot take ownership of the subresource filter unless
// the throttle has reached this point. After this point the throttle manager
- // can send an activation IPC to the render process. Note that an IPC is not
- // always sent in case this activation is ignoring ruleset rules.
- bool could_send_activation_to_renderer_ = false;
+ // will send an activation IPC to the render process.
+ bool will_send_activation_to_renderer_ = false;
base::WeakPtrFactory<ActivationStateComputingNavigationThrottle>
weak_ptr_factory_;
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 b49ad49dd98..bd31786c028 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
@@ -176,7 +176,7 @@ class ActivationStateComputingNavigationThrottleTest
return;
ASSERT_EQ(navigation_handle, test_throttle_->navigation_handle());
if (test_throttle_->filter())
- test_throttle_->CouldSendActivationToRenderer();
+ test_throttle_->WillSendActivationToRenderer();
if (auto filter = test_throttle_->ReleaseFilter()) {
EXPECT_NE(ActivationLevel::DISABLED,
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 c91f0b90154..0d2dbab829e 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
@@ -13,6 +13,7 @@
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
+#include "components/subresource_filter/core/common/scoped_timers.h"
#include "components/subresource_filter/core/common/time_measurements.h"
#include "components/url_pattern_index/proto/rules.pb.h"
@@ -24,16 +25,22 @@ ActivationState ComputeActivationState(
const ActivationState& parent_activation_state,
const MemoryMappedRuleset* ruleset) {
DCHECK(ruleset);
+
SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
"SubresourceFilter.DocumentLoad.Activation.WallDuration");
SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
"SubresourceFilter.DocumentLoad.Activation.CPUDuration");
- if (parent_document_origin.unique()) {
- SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
- "SubresourceFilter.PageLoad.Activation.WallDuration");
- SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
- "SubresourceFilter.PageLoad.Activation.CPUDuration");
- }
+
+ auto page_wall_duration_timer = ScopedTimers::StartIf(
+ parent_document_origin.unique(), [](base::TimeDelta delta) {
+ UMA_HISTOGRAM_MICRO_TIMES(
+ "SubresourceFilter.PageLoad.Activation.WallDuration", delta);
+ });
+ auto page_cpu_duration_timer = ScopedThreadTimers::StartIf(
+ parent_document_origin.unique(), [](base::TimeDelta delta) {
+ UMA_HISTOGRAM_MICRO_TIMES(
+ "SubresourceFilter.PageLoad.Activation.CPUDuration", delta);
+ });
IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length());
ActivationState activation_state = parent_activation_state;
diff --git a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc
index bff2cef641d..e98538347f5 100644
--- a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc
+++ b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.cc
@@ -8,11 +8,11 @@ namespace subresource_filter {
ActivationList GetListForThreatTypeAndMetadata(
safe_browsing::SBThreatType threat_type,
- safe_browsing::ThreatPatternType threat_type_metadata) {
+ const safe_browsing::ThreatMetadata& threat_type_metadata) {
bool is_phishing_interstitial =
(threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
bool is_soc_engineering_ads_interstitial =
- threat_type_metadata ==
+ threat_type_metadata.threat_pattern_type ==
safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS;
bool subresource_filter =
(threat_type == safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
@@ -22,7 +22,18 @@ ActivationList GetListForThreatTypeAndMetadata(
}
return ActivationList::PHISHING_INTERSTITIAL;
} else if (subresource_filter) {
- return ActivationList::SUBRESOURCE_FILTER;
+ switch (threat_type_metadata.threat_pattern_type) {
+ case safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_BETTER_ADS:
+ return ActivationList::BETTER_ADS;
+ case safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_ABUSIVE_ADS:
+ return ActivationList::ABUSIVE_ADS;
+ case safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS:
+ return ActivationList::ALL_ADS;
+ case safe_browsing::ThreatPatternType::NONE:
+ return ActivationList::SUBRESOURCE_FILTER;
+ default:
+ break;
+ }
}
return ActivationList::NONE;
diff --git a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h
index dc23a48b4d9..645648cdf98 100644
--- a/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h
+++ b/chromium/components/subresource_filter/content/browser/content_activation_list_utils.h
@@ -12,7 +12,7 @@ namespace subresource_filter {
ActivationList GetListForThreatTypeAndMetadata(
safe_browsing::SBThreatType threat_type,
- safe_browsing::ThreatPatternType threat_type_metadata);
+ const safe_browsing::ThreatMetadata& threat_type_metadata);
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index 01d474160f0..3a8bf2a3efe 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -7,12 +7,17 @@
#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "base/time/time.h"
+#include "components/subresource_filter/content/browser/page_load_statistics.h"
#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
#include "components/subresource_filter/core/common/activation_list.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/console_message_level.h"
#include "net/base/net_errors.h"
#include "url/gurl.h"
@@ -64,28 +69,37 @@ ContentSubresourceFilterDriverFactory::
void ContentSubresourceFilterDriverFactory::NotifyPageActivationComputed(
content::NavigationHandle* navigation_handle,
ActivationDecision activation_decision,
- Configuration::ActivationOptions matched_options) {
+ const Configuration& matched_configuration) {
DCHECK(navigation_handle->IsInMainFrame());
DCHECK(!navigation_handle->IsSameDocument());
if (navigation_handle->GetNetErrorCode() != net::OK)
return;
activation_decision_ = activation_decision;
- activation_options_ = matched_options;
+ matched_configuration_ = matched_configuration;
DCHECK_NE(activation_decision_, ActivationDecision::UNKNOWN);
// ACTIVATION_DISABLED implies DISABLED activation level.
DCHECK(activation_decision_ != ActivationDecision::ACTIVATION_DISABLED ||
- activation_options_.activation_level == ActivationLevel::DISABLED);
- ActivationState state = ActivationState(activation_options_.activation_level);
+ activation_options().activation_level == ActivationLevel::DISABLED);
+
+ // Ensure the matched config is in our config list. If it wasn't then this
+ // must be a forced activation via devtools.
+ DCHECK(activation_decision_ != ActivationDecision::ACTIVATED ||
+ HasEnabledConfiguration(matched_configuration) ||
+ matched_configuration == Configuration::MakeForForcedActivation())
+ << matched_configuration;
+
+ ActivationState state =
+ ActivationState(activation_options().activation_level);
state.measure_performance = ShouldMeasurePerformanceForPageLoad(
- activation_options_.performance_measurement_rate);
+ activation_options().performance_measurement_rate);
// TODO(csharrison): Also use metadata returned from the safe browsing filter,
// when it is available to set enable_logging. Add tests for this behavior.
state.enable_logging =
- activation_options_.activation_level == ActivationLevel::ENABLED &&
- !activation_options_.should_suppress_notifications &&
+ activation_options().activation_level == ActivationLevel::ENABLED &&
+ !activation_options().should_suppress_notifications &&
base::FeatureList::IsEnabled(
kSafeBrowsingSubresourceFilterExperimentalUI);
@@ -94,19 +108,48 @@ void ContentSubresourceFilterDriverFactory::NotifyPageActivationComputed(
state);
}
-void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
- if (activation_options_.should_suppress_notifications)
- return;
- client_->ToggleNotificationVisibility(activation_options_.activation_level ==
- ActivationLevel::ENABLED);
+// Blocking popups here should trigger the standard popup blocking UI, so don't
+// force the subresource filter specific UI.
+bool ContentSubresourceFilterDriverFactory::ShouldDisallowNewWindow(
+ const content::OpenURLParams* open_url_params) {
+ if (activation_options().activation_level != ActivationLevel::ENABLED ||
+ !activation_options().should_strengthen_popup_blocker)
+ return false;
+
+ // Block new windows from navigations whose triggering JS Event has an
+ // isTrusted bit set to false. This bit is set to true if the event is
+ // generated via a user action. See docs:
+ // https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
+ bool should_block = true;
+ if (open_url_params) {
+ should_block = open_url_params->triggering_event_info ==
+ blink::WebTriggeringEventInfo::kFromUntrustedEvent;
+ }
+ if (should_block) {
+ web_contents()->GetMainFrame()->AddMessageToConsole(
+ content::CONSOLE_MESSAGE_LEVEL_ERROR, kDisallowNewWindowMessage);
+ if (PageLoadStatistics* statistics =
+ throttle_manager_->page_load_statistics()) {
+ statistics->OnBlockedPopup();
+ }
+ }
+ return should_block;
}
-bool ContentSubresourceFilterDriverFactory::AllowStrongPopupBlocking() {
- return activation_options_.should_strengthen_popup_blocker;
+void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
+ if (activation_options().should_suppress_notifications)
+ return;
+ // This shouldn't happen normally, but in the rare case that an IPC from a
+ // previous page arrives late we should guard against it.
+ if (activation_options().should_disable_ruleset_rules ||
+ activation_options().activation_level != ActivationLevel::ENABLED) {
+ return;
+ }
+ client_->ShowNotification();
}
bool ContentSubresourceFilterDriverFactory::AllowRulesetRules() {
- return !activation_options_.should_disable_ruleset_rules;
+ return !activation_options().should_disable_ruleset_rules;
}
void ContentSubresourceFilterDriverFactory::DidStartNavigation(
@@ -114,7 +157,7 @@ void ContentSubresourceFilterDriverFactory::DidStartNavigation(
if (navigation_handle->IsInMainFrame() &&
!navigation_handle->IsSameDocument()) {
activation_decision_ = ActivationDecision::UNKNOWN;
- client_->ToggleNotificationVisibility(false);
+ client_->OnNewNavigationStarted();
}
}
@@ -125,7 +168,7 @@ void ContentSubresourceFilterDriverFactory::DidFinishNavigation(
activation_decision_ == ActivationDecision::UNKNOWN &&
navigation_handle->HasCommitted()) {
activation_decision_ = ActivationDecision::ACTIVATION_DISABLED;
- activation_options_ = Configuration::ActivationOptions();
+ matched_configuration_ = Configuration();
}
}
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index b63e80afac1..e4956fa5742 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -45,31 +45,24 @@ class ContentSubresourceFilterDriverFactory
SubresourceFilterClient* client);
~ContentSubresourceFilterDriverFactory() override;
+ // This class will be notified of page level activation, before the associated
+ // navigation commits.
void NotifyPageActivationComputed(
content::NavigationHandle* navigation_handle,
ActivationDecision activation_decision,
- Configuration::ActivationOptions matched_options);
-
- // Returns the |ActivationDecision| for the current main frame document. Do
- // not rely on this API, it is only temporary.
- // TODO(csharrison): Remove this and |activation_decision_| once consumers
- // move to become SubresourceFilterObservers.
- ActivationDecision GetActivationDecisionForLastCommittedPageLoad() const {
- return activation_decision_;
- }
+ const Configuration& matched_configuration);
+
+ // Returns whether or not the current WebContents is allowed to create a new
+ // window.
+ bool ShouldDisallowNewWindow(const content::OpenURLParams* open_url_params);
- // Returns the |ActivationOptions| for the current main frame
- // document. Do not rely on this API, it is only temporary.
- // TODO(csharrison): Remove this and |activation_options_| in place of adding
- // |should_suppress_notifications| on ActivationState.
- const Configuration::ActivationOptions&
- GetActivationOptionsForLastCommittedPageLoad() const {
- return activation_options_;
+ // Returns the Configuration for the current main frame document.
+ const Configuration& GetMatchedConfigurationForLastCommittedPageLoad() const {
+ return matched_configuration_;
}
// ContentSubresourceFilterThrottleManager::Delegate:
void OnFirstSubresourceLoadDisallowed() override;
- bool AllowStrongPopupBlocking() override;
bool AllowRulesetRules() override;
ContentSubresourceFilterThrottleManager* throttle_manager() {
@@ -82,6 +75,10 @@ class ContentSubresourceFilterDriverFactory
friend class ContentSubresourceFilterDriverFactoryTest;
friend class safe_browsing::SafeBrowsingServiceTest;
+ const Configuration::ActivationOptions& activation_options() const {
+ return matched_configuration_.activation_options;
+ }
+
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
@@ -104,14 +101,18 @@ class ContentSubresourceFilterDriverFactory
ActivationDecision activation_decision_ =
ActivationDecision::ACTIVATION_DISABLED;
- // The activation options corresponding to the most recently _committed_
+ // The Configuration corresponding to the most recently _committed_
// non-same-document navigation in the main frame.
//
// The value corresponding to the previous such navigation will be retained,
// and the new value not assigned until a subsequent navigation successfully
// reaches the WillProcessResponse stage (or successfully finishes if
// throttles are not invoked).
- Configuration::ActivationOptions activation_options_;
+ //
+ // Careful note: the Configuration may not entirely match up with
+ // a config in GetEnabledConfigurations() due to activation computation
+ // changing the config (e.g. for forcing devtools activation).
+ Configuration matched_configuration_;
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactory);
};
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 8311ba76a6c..19b3a3cfd22 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
@@ -19,10 +19,10 @@
#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
#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/common/subresource_filter_utils.h"
#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
-#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/console_message_level.h"
@@ -30,11 +30,6 @@
namespace subresource_filter {
-bool ContentSubresourceFilterThrottleManager::Delegate::
- AllowStrongPopupBlocking() {
- return false;
-}
-
bool ContentSubresourceFilterThrottleManager::Delegate::AllowRulesetRules() {
return true;
}
@@ -97,22 +92,28 @@ void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
if (level == ActivationLevel::DISABLED)
return;
+ // If the ruleset rules are disabled then we should never reach this point.
+ // Main frames: should never get notified about page activation.
+ // Sub frames: should never be constructed if its associated page has ruleset
+ // rules disabled.
+ //
+ // However, navigation code is known to be quite fragile to these assumptions
+ // so it is not clear that a subframe's WillStartRequest (e.g. throttle
+ // insertion) will always occur before it's associated main frame's
+ // WillProcessResponse. Be defensive for that case.
+ if (!delegate_->AllowRulesetRules())
+ return;
+
TRACE_EVENT1(
TRACE_DISABLED_BY_DEFAULT("loading"),
"ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation",
"activation_state", filter->activation_state().ToTracedValue());
- // Only send the IPC to the renderer if not actively ignoring rules from our
- // ruleset. Note, if we ever want to do anything more complex in the renderer
- // (other than just consume the rules), we will likely have to find a
- // different solution here.
- throttle->CouldSendActivationToRenderer();
- if (delegate_->AllowRulesetRules()) {
- content::RenderFrameHost* frame_host =
- navigation_handle->GetRenderFrameHost();
- frame_host->Send(new SubresourceFilterMsg_ActivateForNextCommittedLoad(
- frame_host->GetRoutingID(), filter->activation_state()));
- }
+ throttle->WillSendActivationToRenderer();
+ content::RenderFrameHost* frame_host =
+ navigation_handle->GetRenderFrameHost();
+ frame_host->Send(new SubresourceFilterMsg_ActivateForNextCommittedLoad(
+ frame_host->GetRoutingID(), filter->activation_state()));
}
void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
@@ -164,7 +165,13 @@ void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
activated_frame_hosts_[frame_host] = std::move(filter);
} else {
activated_frame_hosts_.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 activated_frame_hosts_.
+ MaybeActivateSubframeSpecialUrls(navigation_handle);
}
+
DestroyRulesetHandleIfNoLongerUsed();
}
@@ -203,6 +210,11 @@ void ContentSubresourceFilterThrottleManager::OnPageActivationComputed(
// Do not notify the throttle if activation is disabled.
if (activation_state.activation_level == ActivationLevel::DISABLED)
return;
+
+ // Do not notify page activation if ruleset rules are disabled. This ensures
+ // we don't initialize/verify the ruleset.
+ if (!delegate_->AllowRulesetRules())
+ return;
auto it = ongoing_activation_throttles_.find(navigation_handle);
if (it != ongoing_activation_throttles_.end()) {
it->second->NotifyPageActivationWithRuleset(EnsureRulesetHandle(),
@@ -233,35 +245,6 @@ void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles(
}
}
-// Blocking popups here should trigger the standard popup blocking UI, so don't
-// force the subresource filter specific UI.
-bool ContentSubresourceFilterThrottleManager::ShouldDisallowNewWindow(
- const content::OpenURLParams* open_url_params) {
- auto it = activated_frame_hosts_.find(web_contents()->GetMainFrame());
- if (it == activated_frame_hosts_.end())
- return false;
- const ActivationState state = it->second->activation_state();
- if (state.activation_level != ActivationLevel::ENABLED ||
- state.filtering_disabled_for_document ||
- state.generic_blocking_rules_disabled ||
- !delegate_->AllowStrongPopupBlocking()) {
- return false;
- }
-
- // Block new windows from navigations whose triggering JS Event has an
- // isTrusted bit set to false. This bit is set to true if the event is
- // generated via a user action. See docs:
- // https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
- bool should_block = true;
- if (open_url_params) {
- should_block = open_url_params->triggering_event_info ==
- blink::WebTriggeringEventInfo::kFromUntrustedEvent;
- }
- if (should_block)
- delegate_->OnFirstSubresourceLoadDisallowed();
- return should_block;
-}
-
std::unique_ptr<SubframeNavigationFilteringThrottle>
ContentSubresourceFilterThrottleManager::
MaybeCreateSubframeNavigationFilteringThrottle(
@@ -287,7 +270,10 @@ ContentSubresourceFilterThrottleManager::
navigation_handle);
}
- // Subframes: create only for frames with activated parents.
+ // Subframes: create only for frames with activated parents, and if we're
+ // abiding by ruleset rules for this page load.
+ if (!delegate_->AllowRulesetRules())
+ return nullptr;
AsyncDocumentSubresourceFilter* parent_filter =
GetParentFrameFilter(navigation_handle);
if (!parent_filter)
@@ -304,8 +290,25 @@ ContentSubresourceFilterThrottleManager::GetParentFrameFilter(
DCHECK(!child_frame_navigation->IsInMainFrame());
content::RenderFrameHost* parent = child_frame_navigation->GetParentFrame();
DCHECK(parent);
- auto it = activated_frame_hosts_.find(parent);
- return it == activated_frame_hosts_.end() ? nullptr : it->second.get();
+
+ // Filter will be null for those special url navigations that were added in
+ // MaybeActivateSubframeSpecialUrls. Return the filter of the first parent
+ // with a non-null filter.
+ while (parent) {
+ auto it = activated_frame_hosts_.find(parent);
+ if (it == activated_frame_hosts_.end())
+ return nullptr;
+
+ if (it->second.get())
+ return it->second.get();
+ parent = it->first->GetParent();
+ }
+
+ // Since null filter is only possible for special navigations of iframes, the
+ // above loop should have found a filter for at least the top level frame,
+ // thus making this unreachable.
+ NOTREACHED();
+ return nullptr;
}
void ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad() {
@@ -317,6 +320,7 @@ void ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad() {
VerifiedRuleset::Handle*
ContentSubresourceFilterThrottleManager::EnsureRulesetHandle() {
+ DCHECK(delegate_->AllowRulesetRules());
if (!ruleset_handle_)
ruleset_handle_ = base::MakeUnique<VerifiedRuleset::Handle>(dealer_handle_);
return ruleset_handle_.get();
@@ -342,4 +346,23 @@ void ContentSubresourceFilterThrottleManager::OnActivationThrottleDestroyed(
CHECK_EQ(0u, num_erased);
}
+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::ContainsKey(activated_frame_hosts_, parent))
+ activated_frame_hosts_[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 dc6652f364a..ce4cc04b228 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
@@ -19,7 +19,6 @@
#include "content/public/browser/web_contents_observer.h"
namespace content {
-struct OpenURLParams;
class NavigationHandle;
class NavigationThrottle;
class RenderFrameHost;
@@ -59,10 +58,6 @@ class ContentSubresourceFilterThrottleManager
// first load is disallowed for a given page load.
virtual void OnFirstSubresourceLoadDisallowed() {}
- // Whether the stronger version of the popup blocker is enabled for this
- // page load.
- virtual bool AllowStrongPopupBlocking();
-
// Whether we should be using ruleset rules for this page load.
virtual bool AllowRulesetRules();
};
@@ -86,9 +81,7 @@ class ContentSubresourceFilterThrottleManager
content::NavigationHandle* navigation_handle,
std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles);
- // Returns whether or not the current WebContents is allowed to create a new
- // window.
- bool ShouldDisallowNewWindow(const content::OpenURLParams* open_url_params);
+ PageLoadStatistics* page_load_statistics() const { return statistics_.get(); }
VerifiedRuleset::Handle* ruleset_handle_for_testing() {
return ruleset_handle_.get();
@@ -140,8 +133,16 @@ class ContentSubresourceFilterThrottleManager
void OnActivationThrottleDestroyed(
content::NavigationHandle* navigation_handle);
+ // 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);
+
// For each RenderFrameHost where the last committed load has subresource
// filtering activated, owns the corresponding AsyncDocumentSubresourceFilter.
+ // It is possible for a frame to have a null filter.
std::unordered_map<content::RenderFrameHost*,
std::unique_ptr<AsyncDocumentSubresourceFilter>>
activated_frame_hosts_;
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 f714da0babb..e904794e185 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
@@ -16,6 +16,7 @@
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
+#include "base/time/time.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
@@ -278,6 +279,15 @@ class ContentSubresourceFilterThrottleManagerTest
void OnFirstSubresourceLoadDisallowed() override {
++disallowed_notification_count_;
}
+ bool AllowRulesetRules() override { return allow_ruleset_rules_; }
+
+ ContentSubresourceFilterThrottleManager* throttle_manager() {
+ return throttle_manager_.get();
+ }
+
+ void set_allow_ruleset_rules(bool allow_ruleset_rules) {
+ allow_ruleset_rules_ = allow_ruleset_rules;
+ }
private:
testing::TestRulesetCreator test_ruleset_creator_;
@@ -292,6 +302,8 @@ class ContentSubresourceFilterThrottleManagerTest
// Incremented on every OnFirstSubresourceLoadDisallowed call.
int disallowed_notification_count_ = 0;
+ bool allow_ruleset_rules_ = true;
+
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterThrottleManagerTest);
};
@@ -705,8 +717,41 @@ TEST_F(ContentSubresourceFilterThrottleManagerTest, LogActivation) {
// 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",
- 2);
+ base::ThreadTicks::IsSupported() ? 2 : 0);
+}
+
+// If ruleset rules are disabled, should never map the ruleset into memory.
+TEST_F(ContentSubresourceFilterThrottleManagerTest,
+ DisableRulesetRules_NoRuleset) {
+ set_allow_ruleset_rules(false);
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+ EXPECT_FALSE(ManagerHasRulesetHandle());
+}
+
+TEST_F(ContentSubresourceFilterThrottleManagerTest,
+ DisableRulesAfterActivation_NoRuleset) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+
+ // Navigate a subframe that is not filtered, but should still activate.
+ CreateSubframeWithTestNavigation(GURL("https://whitelist.com"), main_rfh());
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ content::RenderFrameHost* subframe1 =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe1, true /* expect_activation */);
+
+ // Simulate a commit of a page which should disallow ruleset rules. This
+ // should cause the subframe to detach.
+ set_allow_ruleset_rules(false);
+ content::RenderFrameHostTester::For(subframe1)->Detach();
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation2));
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+ EXPECT_FALSE(ManagerHasRulesetHandle());
}
// TODO(csharrison): Make sure the following conditions are exercised in tests:
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 14c9cab3df9..49e98b7502e 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
@@ -15,8 +15,17 @@ FakeSafeBrowsingDatabaseManager::FakeSafeBrowsingDatabaseManager() {}
void FakeSafeBrowsingDatabaseManager::AddBlacklistedUrl(
const GURL& url,
safe_browsing::SBThreatType threat_type,
+ const safe_browsing::ThreatMetadata& metadata) {
+ url_to_threat_type_[url] = std::make_pair(threat_type, metadata);
+}
+
+void FakeSafeBrowsingDatabaseManager::AddBlacklistedUrl(
+ const GURL& url,
+ safe_browsing::SBThreatType threat_type,
safe_browsing::ThreatPatternType pattern_type) {
- url_to_threat_type_[url] = std::make_pair(threat_type, pattern_type);
+ safe_browsing::ThreatMetadata metadata;
+ metadata.threat_pattern_type = pattern_type;
+ AddBlacklistedUrl(url, threat_type, metadata);
}
void FakeSafeBrowsingDatabaseManager::RemoveBlacklistedUrl(const GURL& url) {
@@ -68,7 +77,7 @@ void FakeSafeBrowsingDatabaseManager::OnCheckUrlForSubresourceFilterComplete(
auto it = url_to_threat_type_.find(url);
if (it != url_to_threat_type_.end()) {
threat_type = it->second.first;
- metadata.threat_pattern_type = it->second.second;
+ metadata = it->second.second;
}
client->OnCheckBrowseUrlResult(url, threat_type, metadata);
diff --git a/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h b/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
index d28c0284421..440946845e9 100644
--- a/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
+++ b/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
@@ -23,6 +23,9 @@ class FakeSafeBrowsingDatabaseManager
void AddBlacklistedUrl(const GURL& url,
safe_browsing::SBThreatType threat_type,
+ const safe_browsing::ThreatMetadata& metadata);
+ void AddBlacklistedUrl(const GURL& url,
+ safe_browsing::SBThreatType threat_type,
safe_browsing::ThreatPatternType pattern_type =
safe_browsing::ThreatPatternType::NONE);
void RemoveBlacklistedUrl(const GURL& url);
@@ -56,7 +59,7 @@ class FakeSafeBrowsingDatabaseManager
std::set<Client*> checks_;
std::map<
GURL,
- std::pair<safe_browsing::SBThreatType, safe_browsing::ThreatPatternType>>
+ std::pair<safe_browsing::SBThreatType, safe_browsing::ThreatMetadata>>
url_to_threat_type_;
bool simulate_timeout_ = false;
bool synchronous_failure_ = false;
diff --git a/chromium/components/subresource_filter/content/browser/page_load_statistics.cc b/chromium/components/subresource_filter/content/browser/page_load_statistics.cc
index 6d9f749585d..43fe28d7f77 100644
--- a/chromium/components/subresource_filter/content/browser/page_load_statistics.cc
+++ b/chromium/components/subresource_filter/content/browser/page_load_statistics.cc
@@ -13,7 +13,17 @@ namespace subresource_filter {
PageLoadStatistics::PageLoadStatistics(const ActivationState& state)
: activation_state_(state) {}
-PageLoadStatistics::~PageLoadStatistics() = default;
+PageLoadStatistics::~PageLoadStatistics() {
+ // This object is only created for pages which are activated. So, it makes
+ // sense to log blocked popups unconditionally here.
+ //
+ // We *could* restrict this for page loads with configurations allowing the
+ // strong popup blocker, but it doesn't make a big difference. Logging it
+ // always could always show us if the feature is breaking (and triggering when
+ // it shouldn't be).
+ UMA_HISTOGRAM_COUNTS_100("SubresourceFilter.PageLoad.BlockedPopups",
+ num_popups_blocked_);
+}
void PageLoadStatistics::OnDocumentLoadStatistics(
const DocumentLoadStatistics& statistics) {
@@ -32,6 +42,8 @@ void PageLoadStatistics::OnDocumentLoadStatistics(
statistics.evaluation_total_cpu_duration;
}
+// Do not log popup metrics here, since popups are usually not blocked during
+// the load of the page, but during interaction.
void PageLoadStatistics::OnDidFinishLoad() {
if (activation_state_.activation_level != ActivationLevel::DISABLED) {
UMA_HISTOGRAM_COUNTS_1000(
@@ -68,4 +80,8 @@ void PageLoadStatistics::OnDidFinishLoad() {
}
}
+void PageLoadStatistics::OnBlockedPopup() {
+ num_popups_blocked_++;
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/page_load_statistics.h b/chromium/components/subresource_filter/content/browser/page_load_statistics.h
index 9666e240916..02a8593ff0d 100644
--- a/chromium/components/subresource_filter/content/browser/page_load_statistics.h
+++ b/chromium/components/subresource_filter/content/browser/page_load_statistics.h
@@ -11,9 +11,12 @@
namespace subresource_filter {
-// This class is notified of performance metrics recorded for individual
-// (sub-)documents of a page, aggregates them, and logs the aggregated metrics
-// to UMA histograms when the page load is complete (at the load event).
+// This class is notified of metrics recorded for individual (sub-)documents of
+// a page, aggregates them, and logs the aggregated metrics to UMA histograms
+// when the page load is complete (at the load event).
+//
+// Additionally, it manages aggregation of page load metrics like the number of
+// popups blocked.
class PageLoadStatistics {
public:
PageLoadStatistics(const ActivationState& state);
@@ -22,6 +25,8 @@ class PageLoadStatistics {
void OnDocumentLoadStatistics(const DocumentLoadStatistics& statistics);
void OnDidFinishLoad();
+ void OnBlockedPopup();
+
private:
ActivationState activation_state_;
@@ -29,6 +34,8 @@ class PageLoadStatistics {
// current page.
DocumentLoadStatistics aggregated_document_statistics_;
+ int num_popups_blocked_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(PageLoadStatistics);
};
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 9971215160c..553c5d32c50 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
@@ -199,11 +199,11 @@ TEST_F(SubframeNavigationFilteringThrottleTest, FilterSubsubframe) {
content::RenderFrameHostTester::For(main_rfh())
->AppendChild("parent-sub");
GURL test_url = GURL("https://example.test");
- content::RenderFrameHostTester::For(parent_subframe)
- ->SimulateNavigationStart(test_url);
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ test_url, parent_subframe);
+ navigation->Start();
InitializeDocumentSubresourceFilter(GURL("https://example.test"));
- content::RenderFrameHostTester::For(parent_subframe)
- ->SimulateNavigationCommit(test_url);
+ navigation->Commit();
CreateTestSubframeAndInitNavigation(
GURL("https://example.test/disallowed.html"), parent_subframe);
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 c46a0a24576..77dd18ed37b 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_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_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "content/public/browser/web_contents.h"
@@ -20,13 +20,12 @@ class SubresourceFilterClient {
public:
virtual ~SubresourceFilterClient() = default;
- // Changes the visibility of the prompt that informs the user that potentially
- // deceptive content has been blocked on the page according to the passed
- // |visibility| parameter. When |visibility| is set to true, an icon on the
- // right side of the omnibox is displayed. If the user clicks on the icon then
- // a bubble is shown that explains the feature and alalows the user to turn it
- // off.
- virtual void ToggleNotificationVisibility(bool visibility) = 0;
+ // Informs the embedder to show some UI indicating that resources are being
+ // blocked.
+ virtual void ShowNotification() = 0;
+
+ // Called when the component is starting to observe a new navigation.
+ virtual void OnNewNavigationStarted() = 0;
// Called when the activation decision is otherwise completely computed by the
// subresource filter. At this point, the embedder still has a chance to
@@ -36,14 +35,19 @@ class SubresourceFilterClient {
// Precondition: The navigation must be a main frame navigation.
virtual bool OnPageActivationComputed(
content::NavigationHandle* navigation_handle,
- bool activated) = 0;
+ bool activated,
+ bool suppressing_notifications) = 0;
// Adds |url| to a per-WebContents whitelist.
virtual void WhitelistInCurrentWebContents(const GURL& url) = 0;
virtual VerifiedRulesetDealer::Handle* GetRulesetDealer() = 0;
+
+ // Returns whether this navigation should be forced to be activated. This is
+ // currently only used for devtools.
+ virtual bool ForceActivationInCurrentWebContents() = 0;
};
} // namespace subresource_filter
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
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 24cf94808a5..fee8b0d09d5 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
@@ -11,8 +11,11 @@ namespace subresource_filter {
TestSubresourceFilterObserver::TestSubresourceFilterObserver(
content::WebContents* web_contents)
: scoped_observer_(this) {
- scoped_observer_.Add(
- SubresourceFilterObserverManager::FromWebContents(web_contents));
+ auto* manager =
+ SubresourceFilterObserverManager::FromWebContents(web_contents);
+ DCHECK(manager);
+ scoped_observer_.Add(manager);
+ Observe(web_contents);
}
TestSubresourceFilterObserver::~TestSubresourceFilterObserver() {}
@@ -25,7 +28,9 @@ void TestSubresourceFilterObserver::OnPageActivationComputed(
content::NavigationHandle* navigation_handle,
ActivationDecision activation_decision,
const ActivationState& activation_state) {
+ DCHECK(navigation_handle->IsInMainFrame());
page_activations_[navigation_handle->GetURL()] = activation_decision;
+ pending_activations_[navigation_handle] = activation_decision;
}
void TestSubresourceFilterObserver::OnSubframeNavigationEvaluated(
@@ -34,8 +39,27 @@ void TestSubresourceFilterObserver::OnSubframeNavigationEvaluated(
subframe_load_evaluations_[navigation_handle->GetURL()] = load_policy;
}
+void TestSubresourceFilterObserver::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ auto it = pending_activations_.find(navigation_handle);
+ bool did_compute = it != pending_activations_.end();
+ if (!navigation_handle->IsInMainFrame() ||
+ !navigation_handle->HasCommitted() || navigation_handle->IsErrorPage()) {
+ if (did_compute)
+ pending_activations_.erase(it);
+ return;
+ }
+
+ if (did_compute) {
+ last_committed_activation_ = it->second;
+ pending_activations_.erase(it);
+ } else {
+ last_committed_activation_ = base::Optional<ActivationDecision>();
+ }
+}
+
base::Optional<ActivationDecision>
-TestSubresourceFilterObserver::GetPageActivation(const GURL& url) {
+TestSubresourceFilterObserver::GetPageActivation(const GURL& url) const {
auto it = page_activations_.find(url);
if (it != page_activations_.end())
return it->second;
@@ -43,11 +67,16 @@ TestSubresourceFilterObserver::GetPageActivation(const GURL& url) {
}
base::Optional<LoadPolicy> TestSubresourceFilterObserver::GetSubframeLoadPolicy(
- const GURL& url) {
+ const GURL& url) const {
auto it = subframe_load_evaluations_.find(url);
if (it != subframe_load_evaluations_.end())
return it->second;
return base::Optional<LoadPolicy>();
}
+base::Optional<ActivationDecision>
+TestSubresourceFilterObserver::GetPageActivationForLastCommittedLoad() const {
+ return last_committed_activation_;
+}
+
} // namespace subresource_filter
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 b76f203bdf6..8c82bdf1fee 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
@@ -14,9 +14,11 @@
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/core/common/activation_decision.h"
#include "components/subresource_filter/core/common/load_policy.h"
+#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
namespace content {
+class NavigationHandle;
class WebContents;
} // namespace content
@@ -25,7 +27,8 @@ namespace subresource_filter {
// This class can be used to observe subresource filtering events associated
// with a particular web contents. Particular events can be expected by using
// the Get* methods.
-class TestSubresourceFilterObserver : public SubresourceFilterObserver {
+class TestSubresourceFilterObserver : public SubresourceFilterObserver,
+ public content::WebContentsObserver {
public:
TestSubresourceFilterObserver(content::WebContents* web_contents);
~TestSubresourceFilterObserver() override;
@@ -40,13 +43,22 @@ class TestSubresourceFilterObserver : public SubresourceFilterObserver {
content::NavigationHandle* navigation_handle,
LoadPolicy load_policy) override;
- base::Optional<ActivationDecision> GetPageActivation(const GURL& url);
- base::Optional<LoadPolicy> GetSubframeLoadPolicy(const GURL& url);
+ // content::WebContentsObserver
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+
+ base::Optional<ActivationDecision> GetPageActivation(const GURL& url) const;
+ base::Optional<LoadPolicy> GetSubframeLoadPolicy(const GURL& url) const;
+ base::Optional<ActivationDecision> GetPageActivationForLastCommittedLoad()
+ const;
private:
std::map<GURL, LoadPolicy> subframe_load_evaluations_;
std::map<GURL, ActivationDecision> page_activations_;
+ std::map<content::NavigationHandle*, ActivationDecision> pending_activations_;
+ base::Optional<ActivationDecision> last_committed_activation_;
+
ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver>
scoped_observer_;
DISALLOW_COPY_AND_ASSIGN(TestSubresourceFilterObserver);
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 5c578c41098..263b7fa10ae 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
@@ -24,23 +24,6 @@
namespace subresource_filter {
-namespace {
-
-// Records histograms about the pattern of redirect chains, and about the
-// pattern of whether the last URL in the chain matched the activation list.
-#define REPORT_REDIRECT_PATTERN_FOR_SUFFIX(suffix, is_matched, chain_size) \
- do { \
- UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.PageLoad.FinalURLMatch." suffix, \
- is_matched); \
- if (is_matched) { \
- UMA_HISTOGRAM_COUNTS( \
- "SubresourceFilter.PageLoad.RedirectChainLength." suffix, \
- chain_size); \
- }; \
- } while (0)
-
-} // namespace
-
SubresourceFilterSafeBrowsingActivationThrottle::
SubresourceFilterSafeBrowsingActivationThrottle(
content::NavigationHandle* handle,
@@ -73,11 +56,55 @@ SubresourceFilterSafeBrowsingActivationThrottle::
// The last check could be ongoing when the navigation is cancelled.
if (check_results_.empty() || !check_results_.back().finished)
return;
+ ActivationList matched_list = GetListForThreatTypeAndMetadata(
+ check_results_.back().threat_type, check_results_.back().threat_metadata);
+
// TODO(csharrison): Log more metrics based on check_results_.
- RecordRedirectChainMatchPatternForList(
- ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
- RecordRedirectChainMatchPatternForList(ActivationList::PHISHING_INTERSTITIAL);
- RecordRedirectChainMatchPatternForList(ActivationList::SUBRESOURCE_FILTER);
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationList",
+ matched_list,
+ static_cast<int>(ActivationList::LAST) + 1);
+
+ size_t chain_size = check_results_.size();
+ switch (matched_list) {
+ case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "SocialEngineeringAdsInterstitial",
+ chain_size);
+ break;
+ case ActivationList::PHISHING_INTERSTITIAL:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "PhishingInterstitial",
+ chain_size);
+ break;
+ case ActivationList::SUBRESOURCE_FILTER:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "SubresourceFilterOnly",
+ chain_size);
+ break;
+ case ActivationList::BETTER_ADS:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "BetterAds",
+ chain_size);
+ break;
+ case ActivationList::ABUSIVE_ADS:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "AbusiveAds",
+ chain_size);
+ break;
+ case ActivationList::ALL_ADS:
+ UMA_HISTOGRAM_COUNTS(
+ "SubresourceFilter.PageLoad.RedirectChainLength."
+ "AllAds",
+ chain_size);
+ break;
+ default:
+ break;
+ }
}
bool SubresourceFilterSafeBrowsingActivationThrottle::NavigationIsPageReload(
@@ -113,6 +140,8 @@ SubresourceFilterSafeBrowsingActivationThrottle::WillProcessResponse() {
NotifyResult();
return content::NavigationThrottle::ThrottleCheckResult::PROCEED;
}
+ CHECK(!deferring_);
+ deferring_ = true;
defer_time_ = base::TimeTicks::Now();
return content::NavigationThrottle::ThrottleCheckResult::DEFER;
}
@@ -129,10 +158,12 @@ void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI(
DCHECK_LT(request_id, check_results_.size());
auto& stored_result = check_results_.at(request_id);
- DCHECK(!stored_result.finished);
+ CHECK(!stored_result.finished);
stored_result = result;
- if (!defer_time_.is_null() && request_id == check_results_.size() - 1) {
+ if (deferring_ && request_id == check_results_.size() - 1) {
NotifyResult();
+
+ deferring_ = false;
Resume();
}
}
@@ -149,34 +180,48 @@ void SubresourceFilterSafeBrowsingActivationThrottle::CheckCurrentUrl() {
}
void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult");
auto* driver_factory = ContentSubresourceFilterDriverFactory::FromWebContents(
navigation_handle()->GetWebContents());
DCHECK(driver_factory);
- if (driver_factory->GetActivationOptionsForLastCommittedPageLoad()
- .should_whitelist_site_on_reload &&
+ if (driver_factory->GetMatchedConfigurationForLastCommittedPageLoad()
+ .activation_options.should_whitelist_site_on_reload &&
NavigationIsPageReload(navigation_handle())) {
// Whitelist this host for the current as well as subsequent navigations.
client_->WhitelistInCurrentWebContents(navigation_handle()->GetURL());
}
- Configuration::ActivationOptions matched_options;
- ActivationDecision activation_decision = ComputeActivation(&matched_options);
+ Configuration matched_configuration;
+ ActivationDecision activation_decision = ActivationDecision::UNKNOWN;
+ if (client_->ForceActivationInCurrentWebContents()) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationForced");
+ activation_decision = ActivationDecision::ACTIVATED;
+ matched_configuration = Configuration::MakeForForcedActivation();
+ } else {
+ activation_decision = ComputeActivation(&matched_configuration);
+ }
+ DCHECK_NE(activation_decision, ActivationDecision::UNKNOWN);
// Check for whitelisted status last, so that the client gets an accurate
// indication of whether there would be activation otherwise.
+ // Note that the client is responsible for noticing if we're forcing
+ // activation.
bool whitelisted = client_->OnPageActivationComputed(
navigation_handle(),
- matched_options.activation_level == ActivationLevel::ENABLED);
+ matched_configuration.activation_options.activation_level ==
+ ActivationLevel::ENABLED,
+ matched_configuration.activation_options.should_suppress_notifications);
// Only reset the activation decision reason if we would have activated.
if (whitelisted && activation_decision == ActivationDecision::ACTIVATED) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationWhitelisted");
activation_decision = ActivationDecision::URL_WHITELISTED;
- matched_options = Configuration::ActivationOptions();
+ matched_configuration = Configuration();
}
driver_factory->NotifyPageActivationComputed(
- navigation_handle(), activation_decision, matched_options);
+ navigation_handle(), activation_decision, matched_configuration);
base::TimeDelta delay = defer_time_.is_null()
? base::TimeDelta::FromMilliseconds(0)
@@ -195,27 +240,30 @@ void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
ActivationDecision
SubresourceFilterSafeBrowsingActivationThrottle::ComputeActivation(
- Configuration::ActivationOptions* options) {
+ Configuration* configuration) {
const GURL& url(navigation_handle()->GetURL());
ActivationList matched_list = ActivationList::NONE;
DCHECK(!database_client_ || !check_results_.empty());
+ bool experimental_list = false;
if (!check_results_.empty()) {
- DCHECK(check_results_.back().finished);
+ const auto& check_result = check_results_.back();
+ DCHECK(check_result.finished);
matched_list = GetListForThreatTypeAndMetadata(
- check_results_.back().threat_type, check_results_.back().pattern_type);
+ check_result.threat_type, check_result.threat_metadata);
+ experimental_list = check_result.threat_metadata.experimental;
}
const auto config_list = GetEnabledConfigurations();
bool scheme_is_http_or_https = url.SchemeIsHTTPOrHTTPS();
- const auto highest_priority_activated_config =
- std::find_if(config_list->configs_by_decreasing_priority().begin(),
- config_list->configs_by_decreasing_priority().end(),
- [&url, scheme_is_http_or_https, matched_list,
- this](const Configuration& config) {
- return DoesMainFrameURLSatisfyActivationConditions(
- url, scheme_is_http_or_https,
- config.activation_conditions, matched_list);
- });
+ const auto highest_priority_activated_config = std::find_if(
+ config_list->configs_by_decreasing_priority().begin(),
+ config_list->configs_by_decreasing_priority().end(),
+ [&url, scheme_is_http_or_https, matched_list, experimental_list,
+ this](const Configuration& config) {
+ return DoesMainFrameURLSatisfyActivationConditions(
+ url, scheme_is_http_or_https, config.activation_conditions,
+ matched_list, experimental_list);
+ });
bool has_activated_config =
highest_priority_activated_config !=
@@ -231,14 +279,14 @@ SubresourceFilterSafeBrowsingActivationThrottle::ComputeActivation(
if (!has_activated_config)
return ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET;
- const Configuration::ActivationOptions activation_options =
+ const Configuration::ActivationOptions& activation_options =
highest_priority_activated_config->activation_options;
if (!scheme_is_http_or_https &&
activation_options.activation_level != ActivationLevel::DISABLED) {
return ActivationDecision::UNSUPPORTED_SCHEME;
}
- *options = activation_options;
+ *configuration = *highest_priority_activated_config;
return activation_options.activation_level == ActivationLevel::DISABLED
? ActivationDecision::ACTIVATION_DISABLED
: ActivationDecision::ACTIVATED;
@@ -249,7 +297,8 @@ bool SubresourceFilterSafeBrowsingActivationThrottle::
const GURL& url,
bool scheme_is_http_or_https,
const Configuration::ActivationConditions& conditions,
- ActivationList matched_list) const {
+ ActivationList matched_list,
+ bool experimental_list) const {
// Avoid copies when tracing disabled.
auto list_to_string = [](ActivationList activation_list) {
std::ostringstream matched_list_stream;
@@ -268,8 +317,17 @@ bool SubresourceFilterSafeBrowsingActivationThrottle::
// ACTIVATION_LIST does not support non http/s URLs.
if (!scheme_is_http_or_https)
return false;
- if (conditions.activation_list == matched_list)
- return true;
+ if (matched_list == ActivationList::NONE)
+ return false;
+
+ // Normal match. Make sure that if the list is experimental, we only match
+ // if our activation conditions also specify that we support experimental
+ // lists.
+ if (conditions.activation_list == matched_list) {
+ return !experimental_list || conditions.experimental;
+ }
+
+ // Phishing / SocEng lists don't have experimental metadata.
if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL &&
matched_list == ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) {
// Handling special case, where activation on the phishing sites also
@@ -284,30 +342,4 @@ bool SubresourceFilterSafeBrowsingActivationThrottle::
return false;
}
-void SubresourceFilterSafeBrowsingActivationThrottle::
- RecordRedirectChainMatchPatternForList(ActivationList activation_list) {
- DCHECK(check_results_.back().finished);
- ActivationList matched_list = GetListForThreatTypeAndMetadata(
- check_results_.back().threat_type, check_results_.back().pattern_type);
- bool is_matched = matched_list == activation_list;
- size_t chain_size = check_results_.size();
- switch (activation_list) {
- case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
- REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SocialEngineeringAdsInterstitial",
- is_matched, chain_size);
- break;
- case ActivationList::PHISHING_INTERSTITIAL:
- REPORT_REDIRECT_PATTERN_FOR_SUFFIX("PhishingInterstitial", is_matched,
- chain_size);
- break;
- case ActivationList::SUBRESOURCE_FILTER:
- REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SubresourceFilterOnly", is_matched,
- chain_size);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
index 774ec62be88..bd5f519cfc5 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -65,8 +65,7 @@ class SubresourceFilterSafeBrowsingActivationThrottle
void CheckCurrentUrl();
void NotifyResult();
- ActivationDecision ComputeActivation(
- Configuration::ActivationOptions* options);
+ ActivationDecision ComputeActivation(Configuration* configuration);
// Returns whether a main-frame navigation to the given |url| satisfies the
// activation |conditions| of a given configuration, except for |priority|.
@@ -74,13 +73,11 @@ class SubresourceFilterSafeBrowsingActivationThrottle
const GURL& url,
bool scheme_is_http_or_https,
const Configuration::ActivationConditions& conditions,
- ActivationList matched_list) const;
-
- void RecordRedirectChainMatchPatternForList(ActivationList activation_list);
+ ActivationList matched_list,
+ bool experimental_list) const;
std::vector<SubresourceFilterSafeBrowsingClient::CheckResult> check_results_;
- scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
std::unique_ptr<SubresourceFilterSafeBrowsingClient,
@@ -94,6 +91,10 @@ class SubresourceFilterSafeBrowsingActivationThrottle
// WillProcessResponse. If deferral was not necessary, will remain null.
base::TimeTicks defer_time_;
+ // Whether this throttle is deferring the navigation. Only set to true in
+ // WillProcessResponse if there are ongoing safe browsing checks.
+ bool deferring_ = false;
+
// Added to investigate crbug.com/733099.
bool will_start_request_called_ = false;
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 0e307f99d4f..16bb30183b8 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,14 +12,17 @@
#include <vector>
#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/test/test_mock_time_task_runner.h"
+#include "build/build_config.h"
#include "components/safe_browsing_db/test_database_manager.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_client.h"
+#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.h"
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
@@ -67,7 +70,7 @@ const char kSafeBrowsingNavigationDelayNoSpeculation[] =
const char kSafeBrowsingCheckTime[] =
"SubresourceFilter.SafeBrowsing.CheckTime";
const char kMatchesPatternHistogramName[] =
- "SubresourceFilter.PageLoad.FinalURLMatch.";
+ "SubresourceFilter.PageLoad.ActivationList";
const char kNavigationChainSize[] =
"SubresourceFilter.PageLoad.RedirectChainLength.";
@@ -83,7 +86,8 @@ class MockSubresourceFilterClient : public SubresourceFilterClient {
}
bool OnPageActivationComputed(content::NavigationHandle* handle,
- bool activated) override {
+ bool activated,
+ bool suppress_notifications) override {
DCHECK(handle->IsInMainFrame());
return whitelisted_hosts_.count(handle->GetURL().host());
}
@@ -97,7 +101,9 @@ class MockSubresourceFilterClient : public SubresourceFilterClient {
return ruleset_dealer_.get();
}
- MOCK_METHOD1(ToggleNotificationVisibility, void(bool));
+ MOCK_METHOD0(ShowNotification, void());
+ MOCK_METHOD0(OnNewNavigationStarted, void());
+ MOCK_METHOD0(ForceActivationInCurrentWebContents, bool());
void ClearWhitelist() { whitelisted_hosts_.clear(); }
@@ -117,6 +123,12 @@ std::string GetSuffixForList(const ActivationList& type) {
return "PhishingInterstitial";
case ActivationList::SUBRESOURCE_FILTER:
return "SubresourceFilterOnly";
+ case ActivationList::BETTER_ADS:
+ return "BetterAds";
+ case ActivationList::ABUSIVE_ADS:
+ return "AbusiveAds";
+ case ActivationList::ALL_ADS:
+ return "AllAds";
case ActivationList::NONE:
return std::string();
}
@@ -131,27 +143,27 @@ struct ActivationListTestData {
};
const ActivationListTestData kActivationListTestData[] = {
- {subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+ {kActivationListSocialEngineeringAdsInterstitial,
ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL,
safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
- {subresource_filter::kActivationListPhishingInterstitial,
- ActivationList::PHISHING_INTERSTITIAL,
+ {kActivationListPhishingInterstitial, ActivationList::PHISHING_INTERSTITIAL,
safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
safe_browsing::ThreatPatternType::NONE},
- {subresource_filter::kActivationListSubresourceFilter,
- ActivationList::SUBRESOURCE_FILTER,
+ {kActivationListSubresourceFilter, ActivationList::SUBRESOURCE_FILTER,
safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER,
safe_browsing::ThreatPatternType::NONE},
+ {kActivationListBetterAds, ActivationList::BETTER_ADS,
+ safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER,
+ safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_BETTER_ADS},
+ {kActivationListAbusiveAds, ActivationList::ABUSIVE_ADS,
+ safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER,
+ safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_ABUSIVE_ADS},
+ {kActivationListAllAds, ActivationList::ALL_ADS,
+ safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER,
+ safe_browsing::ThreatPatternType::SUBRESOURCE_FILTER_ALL_ADS},
};
-void ExpectSampleForSuffix(const std::string& suffix,
- const std::string& match_suffix,
- const base::HistogramTester& tester) {
- tester.ExpectUniqueSample(kMatchesPatternHistogramName + suffix,
- (suffix == match_suffix), 1);
-}
-
} // namespace
class SubresourceFilterSafeBrowsingActivationThrottleTest
@@ -183,6 +195,9 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
NavigateAndCommit(GURL("https://test.com"));
Observe(RenderViewHostTestHarness::web_contents());
+
+ observer_ = base::MakeUnique<TestSubresourceFilterObserver>(
+ RenderViewHostTestHarness::web_contents());
}
virtual void Configure() {
@@ -212,6 +227,8 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
RenderViewHostTestHarness::web_contents());
}
+ TestSubresourceFilterObserver* observer() { return observer_.get(); }
+
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override {
@@ -356,6 +373,7 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
std::unique_ptr<MockSubresourceFilterClient> client_;
+ std::unique_ptr<TestSubresourceFilterObserver> observer_;
scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
base::HistogramTester tester_;
@@ -459,26 +477,26 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
UsePassThroughThrottle();
SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
scoped_configuration()->ResetConfiguration(
Configuration(ActivationLevel::ENABLED, ActivationScope::ALL_SITES));
SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
scoped_configuration()->ResetConfiguration(
Configuration(ActivationLevel::ENABLED, ActivationScope::NO_SITES));
SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, NoConfigs) {
scoped_configuration()->ResetConfiguration(std::vector<Configuration>());
SimulateNavigateAndCommit({GURL(kURL)}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
@@ -504,12 +522,12 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
SimulateNavigateAndCommit({match_url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Should match |config3|.
SimulateNavigateAndCommit({non_match_url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Should match |config3|, but a reload, so this should get whitelisted.
auto reload_simulator = content::NavigationSimulator::CreateRendererInitiated(
@@ -518,7 +536,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
reload_simulator->Start();
SimulateCommit(reload_simulator.get());
EXPECT_EQ(ActivationDecision::URL_WHITELISTED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
@@ -530,18 +548,18 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
ConfigureForMatch(url);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Whitelisting occurs last, so the decision should still be DISABLED.
factory()->client()->WhitelistInCurrentWebContents(url);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
@@ -551,12 +569,12 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
GURL url(kURL);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
ConfigureForMatch(url);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Adding performance measurement should keep activation.
Configuration config_with_perf(
@@ -565,27 +583,27 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
scoped_configuration()->ResetConfiguration(std::move(config_with_perf));
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
NavigationFails_NoActivation) {
- EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ EXPECT_EQ(base::Optional<ActivationDecision>(),
+ observer()->GetPageActivationForLastCommittedLoad());
content::NavigationSimulator::NavigateAndFailFromDocument(
GURL(kURL), net::ERR_TIMED_OUT, main_rfh());
- EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ EXPECT_EQ(base::Optional<ActivationDecision>(),
+ observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
NotificationVisibility) {
GURL url(kURL);
ConfigureForMatch(url);
- EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1);
+ EXPECT_CALL(*client(), OnNewNavigationStarted()).Times(1);
content::RenderFrameHost* rfh = SimulateNavigateAndCommit({url}, main_rfh());
- EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1);
+ EXPECT_CALL(*client(), ShowNotification()).Times(1);
EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(rfh));
}
@@ -597,7 +615,8 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
GURL url(kURL);
content::RenderFrameHost* rfh = SimulateNavigateAndCommit({url}, main_rfh());
- EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
+ EXPECT_CALL(*client(), ShowNotification()).Times(0);
+ EXPECT_CALL(*client(), OnNewNavigationStarted()).Times(0);
EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(rfh));
}
@@ -632,14 +651,14 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
simulator->SetReferrer(test_case.referrer);
SimulateCommit(simulator.get());
EXPECT_EQ(test_case.expected_activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Verify that if the first URL failed to activate, subsequent same-origin
// navigations also fail to activate.
simulator = content::NavigationSimulator::CreateRendererInitiated(
GURL(kURLWithParams), main_rfh());
SimulateCommit(simulator.get());
EXPECT_EQ(test_case.expected_activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
}
@@ -667,7 +686,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(test_data.activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
// Whitelisting is only applied when the page will otherwise activate.
client()->WhitelistInCurrentWebContents(url);
@@ -676,8 +695,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
? test_data.activation_decision
: ActivationDecision::URL_WHITELISTED;
SimulateNavigateAndCommit({url}, main_rfh());
- EXPECT_EQ(decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ EXPECT_EQ(decision, *observer()->GetPageActivationForLastCommittedLoad());
}
}
@@ -764,7 +782,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, ActivationList) {
SimulateNavigateAndCommit({GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), test_url},
main_rfh());
EXPECT_EQ(test_case.expected_activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
}
@@ -780,6 +798,34 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
0);
}
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ ExperimentalMetadata) {
+ const GURL url("https://example.test/");
+
+ // Set the list metadata for |url| to be experimental.
+ safe_browsing::ThreatMetadata metadata;
+ metadata.experimental = true;
+ fake_safe_browsing_database()->AddBlacklistedUrl(
+ url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER, metadata);
+
+ // Navigate without an experimental config.
+ SimulateStartAndExpectProceed(url);
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
+ *observer()->GetPageActivationForLastCommittedLoad());
+
+ // Navigate with an experimental config.
+ Configuration config(ActivationLevel::ENABLED,
+ ActivationScope::ACTIVATION_LIST,
+ ActivationList::SUBRESOURCE_FILTER);
+ config.activation_conditions.experimental = true;
+ scoped_configuration()->ResetConfiguration(std::move(config));
+ SimulateStartAndExpectProceed(url);
+ SimulateCommitAndExpectProceed();
+ EXPECT_EQ(ActivationDecision::ACTIVATED,
+ *observer()->GetPageActivationForLastCommittedLoad());
+}
+
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
ActivateForScopeType) {
const ActivationScopeTestData& test_data = GetParam();
@@ -792,7 +838,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
ConfigureForMatch(test_url);
SimulateNavigateAndCommit({test_url}, main_rfh());
EXPECT_EQ(test_data.expected_activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
if (test_data.url_matches_activation_list) {
factory()->client()->WhitelistInCurrentWebContents(test_url);
ActivationDecision expected_decision =
@@ -801,7 +847,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
expected_decision = ActivationDecision::URL_WHITELISTED;
SimulateNavigateAndCommit({test_url}, main_rfh());
EXPECT_EQ(expected_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
};
@@ -835,7 +881,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
expected_decision = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET;
}
EXPECT_EQ(expected_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
for (auto* url : supported_urls) {
@@ -844,7 +890,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
ConfigureForMatch(GURL(url));
SimulateNavigateAndCommit({GURL(url)}, main_rfh());
EXPECT_EQ(test_data.expected_activation_decision,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
}
};
@@ -852,19 +898,18 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
ListNotMatched_NoActivation) {
const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
SimulateStartAndExpectProceed(url);
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", std::string(),
- tester());
- ExpectSampleForSuffix("PhishingInterstitial", std::string(), tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", std::string(), tester());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(ActivationList::NONE), 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelay, 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
tester().ExpectTotalCount(kSafeBrowsingCheckTime, 1);
+
+ const std::string suffix(GetSuffixForList(test_data.activation_list_type));
tester().ExpectTotalCount(kNavigationChainSize + suffix, 0);
}
@@ -876,11 +921,11 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateStartAndExpectProceed(url);
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(test_data.activation_list_type),
+ 1);
const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", suffix, tester());
- ExpectSampleForSuffix("PhishingInterstitial", suffix, tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", suffix, tester());
tester().ExpectUniqueSample(kNavigationChainSize + suffix, 1, 1);
}
@@ -888,16 +933,15 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
ListNotMatchedAfterRedirect_NoActivation) {
const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
SimulateStartAndExpectProceed(url);
SimulateRedirectAndExpectProceed(GURL(kRedirectURL));
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", std::string(),
- tester());
- ExpectSampleForSuffix("PhishingInterstitial", std::string(), tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", std::string(), tester());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(ActivationList::NONE), 1);
+
+ const std::string suffix(GetSuffixForList(test_data.activation_list_type));
tester().ExpectTotalCount(kNavigationChainSize + suffix, 0);
}
@@ -905,17 +949,18 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
ListMatchedAfterRedirect_Activation) {
const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
ConfigureForMatchParam(GURL(kRedirectURL));
SimulateStartAndExpectProceed(url);
SimulateRedirectAndExpectProceed(GURL(kRedirectURL));
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(test_data.activation_list_type),
+ 1);
+
+ const std::string suffix(GetSuffixForList(test_data.activation_list_type));
tester().ExpectUniqueSample(kNavigationChainSize + suffix, 2, 1);
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", suffix, tester());
- ExpectSampleForSuffix("PhishingInterstitial", suffix, tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", suffix, tester());
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
@@ -937,7 +982,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
test_io_task_runner()->FastForwardBy(expected_delay);
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
0);
tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
@@ -946,8 +991,9 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
tester().ExpectTotalCount(kSafeBrowsingCheckTime, 1);
}
+// Flaky on Win, Chromium and Linux. http://crbug.com/748524
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
- ListMatchedOnStart_NoDelay) {
+ DISABLED_ListMatchedOnStart_NoDelay) {
const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
ConfigureForMatchParam(url);
@@ -958,11 +1004,12 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(test_data.activation_list_type),
+ 1);
+
const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", suffix, tester());
- ExpectSampleForSuffix("PhishingInterstitial", suffix, tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", suffix, tester());
tester().ExpectUniqueSample(kNavigationChainSize + suffix, 1, 1);
tester().ExpectTimeBucketCount(kSafeBrowsingNavigationDelay,
@@ -970,8 +1017,9 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
}
+// Flaky on Win, Chromium and Linux. http://crbug.com/748524
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
- ListMatchedOnRedirect_NoDelay) {
+ DISABLED_ListMatchedOnRedirect_NoDelay) {
const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
const GURL redirect_url(kRedirectURL);
@@ -985,11 +1033,12 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
+ tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ static_cast<int>(test_data.activation_list_type),
+ 1);
+
const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- ExpectSampleForSuffix("SocialEngineeringAdsInterstitial", suffix, tester());
- ExpectSampleForSuffix("PhishingInterstitial", suffix, tester());
- ExpectSampleForSuffix("SubresourceFilterOnly", suffix, tester());
tester().ExpectUniqueSample(kNavigationChainSize + suffix, 2, 1);
tester().ExpectTimeBucketCount(kSafeBrowsingNavigationDelay,
@@ -998,8 +1047,9 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
tester().ExpectTotalCount(kSafeBrowsingCheckTime, 2);
}
+// Disabled due to flaky failures: https://crbug.com/753669.
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
- ListMatchedOnStartWithRedirect_NoActivation) {
+ DISABLED_ListMatchedOnStartWithRedirect_NoActivation) {
const GURL url(kURL);
const GURL redirect_url(kRedirectURL);
ConfigureForMatchParam(url);
@@ -1014,7 +1064,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- factory()->GetActivationDecisionForLastCommittedPageLoad());
+ *observer()->GetPageActivationForLastCommittedLoad());
tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
0);
tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
@@ -1066,10 +1116,10 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
auto check_histogram = [&](std::string suffix) {
bool matches =
suffix == suffix_param && test_data.blacklisted_urls.back();
- histogram_tester.ExpectBucketCount(kMatchesPatternHistogramName + suffix,
- matches, 1);
-
if (matches) {
+ histogram_tester.ExpectUniqueSample(
+ kMatchesPatternHistogramName,
+ static_cast<int>(GetParam().activation_list_type), 1);
histogram_tester.ExpectBucketCount(kNavigationChainSize + suffix,
test_data.navigation_chain.size(),
1);
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
index fd97742f362..e4075eb03ad 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
@@ -24,7 +24,9 @@ SubresourceFilterSafeBrowsingClient::CheckResult::ToTracedValue() const {
auto value = base::MakeUnique<base::trace_event::TracedValue>();
value->SetInteger("request_id", request_id);
value->SetInteger("threat_type", threat_type);
- value->SetInteger("pattern_type", static_cast<int>(pattern_type));
+ value->SetInteger("pattern_type",
+ static_cast<int>(threat_metadata.threat_pattern_type));
+ // TODO(crbug.com/756009): Add "experimental" and "warning" when it lands.
value->SetInteger("check_time (us)", check_time.InMicroseconds());
value->SetBoolean("finished", finished);
return value;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h
index 5b06b854aac..36961c4c8d1 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h
@@ -45,8 +45,11 @@ class SubresourceFilterSafeBrowsingClient {
size_t request_id = 0;
safe_browsing::SBThreatType threat_type =
safe_browsing::SBThreatType::SB_THREAT_TYPE_SAFE;
- safe_browsing::ThreatPatternType pattern_type =
- safe_browsing::ThreatPatternType::NONE;
+
+ // The metadata should generally be lightweight enough to copy around
+ // without performance implications. Refactor this class if that ever
+ // changes.
+ safe_browsing::ThreatMetadata threat_metadata;
base::TimeDelta check_time;
bool finished = false;
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 3e98d1141fd..d8203556d9b 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
@@ -85,7 +85,7 @@ void SubresourceFilterSafeBrowsingClientRequest::SendCheckResultToClient(
SubresourceFilterSafeBrowsingClient::CheckResult result;
result.request_id = request_id_;
result.threat_type = threat_type;
- result.pattern_type = metadata.threat_pattern_type;
+ result.threat_metadata = metadata;
result.check_time = base::TimeTicks::Now() - start_time_;
// This memeber is separate from |request_completed_|, in that it just
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 e9467455402..2ec1c37a5bb 100644
--- a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
+++ b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
@@ -9,6 +9,7 @@
#include "base/files/file.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "components/subresource_filter/core/common/indexed_ruleset.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
@@ -26,6 +27,8 @@ void VerifiedRulesetDealer::SetRulesetFile(base::File ruleset_file) {
scoped_refptr<const MemoryMappedRuleset> VerifiedRulesetDealer::GetRuleset() {
DCHECK(CalledOnValidSequence());
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "VerifiedRulesetDealer::GetRuleset");
// TODO(pkalinnikov): Record verification status to a histogram.
switch (status_) {
diff --git a/chromium/components/subresource_filter/content/common/BUILD.gn b/chromium/components/subresource_filter/content/common/BUILD.gn
index 05f9b61a9b4..aab4b33ba33 100644
--- a/chromium/components/subresource_filter/content/common/BUILD.gn
+++ b/chromium/components/subresource_filter/content/common/BUILD.gn
@@ -9,6 +9,8 @@ static_library("common") {
"subresource_filter_message_generator.cc",
"subresource_filter_message_generator.h",
"subresource_filter_messages.h",
+ "subresource_filter_utils.cc",
+ "subresource_filter_utils.h",
]
public_deps = [
"//base",
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
index c8333c09a8e..2f3b244e54c 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
@@ -17,7 +17,7 @@
#define IPC_MESSAGE_START SubresourceFilterMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(subresource_filter::ActivationLevel,
- subresource_filter::ActivationLevel::LAST);
+ subresource_filter::ActivationLevel::LAST)
IPC_STRUCT_TRAITS_BEGIN(subresource_filter::ActivationState)
IPC_STRUCT_TRAITS_MEMBER(activation_level)
@@ -44,7 +44,7 @@ IPC_STRUCT_TRAITS_END()
// process, containing the subresource filtering rules to be consulted for all
// subsequent document loads that have subresource filtering activated.
IPC_MESSAGE_CONTROL1(SubresourceFilterMsg_SetRulesetForProcess,
- IPC::PlatformFileForTransit /* ruleset_file */);
+ IPC::PlatformFileForTransit /* ruleset_file */)
// Instructs the renderer to activate subresource filtering at the specified
// |activation_state| for the document load committed next in a frame.
@@ -59,7 +59,7 @@ IPC_MESSAGE_CONTROL1(SubresourceFilterMsg_SetRulesetForProcess,
//
// If no message arrives, the default behavior is ActivationLevel::DISABLED.
IPC_MESSAGE_ROUTED1(SubresourceFilterMsg_ActivateForNextCommittedLoad,
- subresource_filter::ActivationState /* activation_state */);
+ subresource_filter::ActivationState /* activation_state */)
// ----------------------------------------------------------------------------
// Messages sent from the renderer to the browser.
@@ -68,7 +68,7 @@ IPC_MESSAGE_ROUTED1(SubresourceFilterMsg_ActivateForNextCommittedLoad,
// Sent to the browser the first time a subresource load is disallowed for the
// most recently commited document load in a frame. It is used to trigger a
// UI prompt to inform the user and allow them to turn off filtering.
-IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_DidDisallowFirstSubresource);
+IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_DidDisallowFirstSubresource)
// This is sent to a RenderFrameHost in the browser when a document load is
// finished, just before the DidFinishLoad message, and contains statistics
@@ -76,6 +76,5 @@ IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_DidDisallowFirstSubresource);
// subresources evaluated/disallowed/etc, and total time spent on evaluating
// subresource loads in its allowLoad method. The time metrics are equal to zero
// if performance measurements were disabled for the load.
-IPC_MESSAGE_ROUTED1(
- SubresourceFilterHostMsg_DocumentLoadStatistics,
- subresource_filter::DocumentLoadStatistics /* statistics */);
+IPC_MESSAGE_ROUTED1(SubresourceFilterHostMsg_DocumentLoadStatistics,
+ subresource_filter::DocumentLoadStatistics /* statistics */)
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc b/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc
new file mode 100644
index 00000000000..a84ae2a2d6e
--- /dev/null
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc
@@ -0,0 +1,26 @@
+// 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/common/subresource_filter_utils.h"
+
+#include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+bool ShouldUseParentActivation(const GURL& url) {
+ if (content::IsBrowserSideNavigationEnabled())
+ return !content::IsURLHandledByNetworkStack(url);
+
+ // TODO(csharrison): It is not always true that a data URL can use its
+ // parent's activation in OOPIF mode, where the resulting data frame will
+ // be same-process to its initiator. See crbug.com/739777 for more
+ // information.
+ return (url.SchemeIs(url::kDataScheme) || url == url::kAboutBlankURL ||
+ url == content::kAboutSrcDocURL);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_utils.h b/chromium/components/subresource_filter/content/common/subresource_filter_utils.h
new file mode 100644
index 00000000000..460e16a4383
--- /dev/null
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_utils.h
@@ -0,0 +1,19 @@
+// 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_COMMON_SUBRESOURCE_FILTER_UTILS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_COMMON_SUBRESOURCE_FILTER_UTILS_H_
+
+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);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_COMMON_SUBRESOURCE_FILTER_UTILS_H_
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 8c66b5bfa03..375d737ed6b 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -13,6 +13,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/content/common/subresource_filter_utils.h"
#include "components/subresource_filter/content/renderer/unverified_ruleset_dealer.h"
#include "components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h"
#include "components/subresource_filter/core/common/document_load_statistics.h"
@@ -25,8 +26,8 @@
#include "content/public/renderer/render_frame.h"
#include "ipc/ipc_message.h"
#include "third_party/WebKit/public/platform/WebWorkerFetchContext.h"
-#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebDocumentLoader.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "url/url_constants.h"
@@ -47,10 +48,14 @@ GURL SubresourceFilterAgent::GetDocumentURL() {
return render_frame()->GetWebFrame()->GetDocument().Url();
}
+bool SubresourceFilterAgent::IsMainFrame() {
+ return render_frame()->IsMainFrame();
+}
+
void SubresourceFilterAgent::SetSubresourceFilterForCommittedLoad(
std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) {
blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
- web_frame->DataSource()->SetSubresourceFilter(filter.release());
+ web_frame->GetDocumentLoader()->SetSubresourceFilter(filter.release());
}
void SubresourceFilterAgent::
@@ -80,15 +85,15 @@ ActivationState SubresourceFilterAgent::GetParentActivationState(
}
void SubresourceFilterAgent::OnActivateForNextCommittedLoad(
- ActivationState activation_state) {
+ const ActivationState& activation_state) {
activation_state_for_next_commit_ = activation_state;
}
-void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted() {
+void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted(
+ const ActivationState& activation_state) {
// Note: ActivationLevel used to be called ActivationState, the legacy name is
// kept for the histogram.
- ActivationLevel activation_level =
- activation_state_for_next_commit_.activation_level;
+ ActivationLevel activation_level = activation_state.activation_level;
UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.DocumentLoad.ActivationState",
static_cast<int>(activation_level),
static_cast<int>(ActivationLevel::LAST) + 1);
@@ -163,38 +168,40 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
// which require changes to the unit tests.
const GURL& url = GetDocumentURL();
- bool use_parent_activation = ShouldUseParentActivation(url);
- if (use_parent_activation) {
- activation_state_for_next_commit_ =
- GetParentActivationState(render_frame());
- }
+ bool use_parent_activation = !IsMainFrame() && ShouldUseParentActivation(url);
- if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile() ||
- use_parent_activation) {
- RecordHistogramsOnLoadCommitted();
- if (activation_state_for_next_commit_.activation_level !=
- ActivationLevel::DISABLED &&
- ruleset_dealer_->IsRulesetFileAvailable()) {
- base::OnceClosure first_disallowed_load_callback(
- base::BindOnce(&SubresourceFilterAgent::
- SignalFirstSubresourceDisallowedForCommittedLoad,
- AsWeakPtr()));
-
- auto ruleset = ruleset_dealer_->GetRuleset();
- // TODO(csharrison): Replace with DCHECK when crbug.com/734102 is
- // resolved.
- CHECK(ruleset);
- CHECK(ruleset->data());
- auto filter = base::MakeUnique<WebDocumentSubresourceFilterImpl>(
- url::Origin(url), activation_state_for_next_commit_,
- std::move(ruleset), std::move(first_disallowed_load_callback));
-
- filter_for_last_committed_load_ = filter->AsWeakPtr();
- SetSubresourceFilterForCommittedLoad(std::move(filter));
- }
- }
+ const ActivationState activation_state =
+ use_parent_activation ? GetParentActivationState(render_frame())
+ : activation_state_for_next_commit_;
ResetActivatonStateForNextCommit();
+
+ // Do not pollute the histograms for empty main frame documents.
+ if (IsMainFrame() && !url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile())
+ return;
+
+ RecordHistogramsOnLoadCommitted(activation_state);
+ if (activation_state.activation_level == ActivationLevel::DISABLED ||
+ !ruleset_dealer_->IsRulesetFileAvailable())
+ return;
+
+ scoped_refptr<const MemoryMappedRuleset> ruleset =
+ ruleset_dealer_->GetRuleset();
+ DCHECK(ruleset);
+ // Data can be null even if the original file is valid, if there is a
+ // memory mapping issue.
+ if (!ruleset->data())
+ return;
+
+ base::OnceClosure first_disallowed_load_callback(base::BindOnce(
+ &SubresourceFilterAgent::SignalFirstSubresourceDisallowedForCommittedLoad,
+ AsWeakPtr()));
+ auto filter = base::MakeUnique<WebDocumentSubresourceFilterImpl>(
+ url::Origin(url), activation_state, std::move(ruleset),
+ std::move(first_disallowed_load_callback));
+
+ filter_for_last_committed_load_ = filter->AsWeakPtr();
+ SetSubresourceFilterForCommittedLoad(std::move(filter));
}
void SubresourceFilterAgent::DidFailProvisionalLoad(
@@ -239,14 +246,4 @@ void SubresourceFilterAgent::WillCreateWorkerFetchContext(
AsWeakPtr())));
}
-bool SubresourceFilterAgent::ShouldUseParentActivation(const GURL& url) const {
- // TODO(csharrison): It is not always true that a data URL can use its
- // parent's activation in OOPIF mode, where the resulting data frame will
- // be same-process to its initiator. See crbug.com/739777 for more
- // information.
- return render_frame() && !render_frame()->IsMainFrame() &&
- (url.SchemeIs(url::kDataScheme) || url == url::kAboutBlankURL ||
- url == content::kAboutSrcDocURL);
-}
-
} // namespace subresource_filter
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 3b886c33076..73d7c1aa2bb 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -24,10 +24,10 @@ struct DocumentLoadStatistics;
class UnverifiedRulesetDealer;
class WebDocumentSubresourceFilterImpl;
-// The renderer-side agent of ContentSubresourceFilterDriverFactory. There is
+// The renderer-side agent of ContentSubresourceFilterThrottleManager. There is
// one instance per RenderFrame, responsible for setting up the subresource
// filter for the ongoing provisional document load in the frame when instructed
-// to do so by the driver.
+// to do so by the manager.
class SubresourceFilterAgent
: public content::RenderFrameObserver,
public content::RenderFrameObserverTracker<SubresourceFilterAgent>,
@@ -45,6 +45,8 @@ class SubresourceFilterAgent
// Returns the URL of the currently committed document.
virtual GURL GetDocumentURL();
+ virtual bool IsMainFrame();
+
// Injects the provided subresource |filter| into the DocumentLoader
// orchestrating the most recently committed load.
virtual void SetSubresourceFilterForCommittedLoad(
@@ -64,8 +66,8 @@ class SubresourceFilterAgent
static ActivationState GetParentActivationState(
content::RenderFrame* render_frame);
- void OnActivateForNextCommittedLoad(ActivationState activation_state);
- void RecordHistogramsOnLoadCommitted();
+ void OnActivateForNextCommittedLoad(const ActivationState& activation_state);
+ void RecordHistogramsOnLoadCommitted(const ActivationState& activation_state);
void RecordHistogramsOnLoadFinished();
void ResetActivatonStateForNextCommit();
@@ -78,11 +80,6 @@ class SubresourceFilterAgent
bool OnMessageReceived(const IPC::Message& message) override;
void WillCreateWorkerFetchContext(blink::WebWorkerFetchContext*) override;
- // Subframe navigations matching these URLs/schemes will not trigger
- // ReadyToCommitNavigation in the browser process, so they must be treated
- // specially to maintain activation.
- bool ShouldUseParentActivation(const GURL& url) const;
-
// Owned by the ChromeContentRendererClient and outlives us.
UnverifiedRulesetDealer* ruleset_dealer_;
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 ab996288586..4e3c2adb692 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
@@ -51,6 +51,8 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
MOCK_METHOD0(SignalFirstSubresourceDisallowedForCommittedLoad, void());
MOCK_METHOD1(SendDocumentLoadStatistics, void(const DocumentLoadStatistics&));
+ bool IsMainFrame() override { return true; }
+
void SetSubresourceFilterForCommittedLoad(
std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) override {
last_injected_filter_ = std::move(filter);
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
index a8ccdf9a30c..9c2bc6a24d2 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
@@ -66,6 +66,10 @@ constexpr char kDisallowSubframeConsoleMessageSuffix[] =
constexpr char kLearnMoreLink[] =
"https://support.google.com/chrome/?p=blocked_ads";
+constexpr char kDisallowNewWindowMessage[] =
+ "Chrome prevented this site from opening a new tab or window. Learn more "
+ "at https://www.chromestatus.com/feature/5243055179300864";
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
index 450e3283380..8f9ab9153ef 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -80,19 +80,26 @@ ActivationScope ParseActivationScope(const base::StringPiece activation_scope) {
}
ActivationList ParseActivationList(std::string activation_lists_string) {
- ActivationList activation_list_type = ActivationList::NONE;
CommaSeparatedStrings activation_lists(std::move(activation_lists_string));
if (activation_lists.CaseInsensitiveContains(
kActivationListPhishingInterstitial)) {
return ActivationList::PHISHING_INTERSTITIAL;
} else if (activation_lists.CaseInsensitiveContains(
kActivationListSocialEngineeringAdsInterstitial)) {
- activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
+ return ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
} else if (activation_lists.CaseInsensitiveContains(
kActivationListSubresourceFilter)) {
- activation_list_type = ActivationList::SUBRESOURCE_FILTER;
+ return ActivationList::SUBRESOURCE_FILTER;
+ } else if (activation_lists.CaseInsensitiveContains(
+ kActivationListBetterAds)) {
+ return ActivationList::BETTER_ADS;
+ } else if (activation_lists.CaseInsensitiveContains(
+ kActivationListAbusiveAds)) {
+ return ActivationList::ABUSIVE_ADS;
+ } else if (activation_lists.CaseInsensitiveContains(kActivationListAllAds)) {
+ return ActivationList::ALL_ADS;
}
- return activation_list_type;
+ return ActivationList::NONE;
}
double ParsePerformanceMeasurementRate(const std::string& rate) {
@@ -156,6 +163,10 @@ Configuration ParseExperimentalConfiguration(
ParseInt(TakeVariationParamOrReturnEmpty(
params, kActivationPriorityParameterName));
+ configuration.activation_conditions.experimental =
+ ParseBool(TakeVariationParamOrReturnEmpty(
+ params, kActivationExperimentalParameterName));
+
// ActivationOptions:
configuration.activation_options.activation_level = ParseActivationLevel(
TakeVariationParamOrReturnEmpty(params, kActivationLevelParameterName));
@@ -259,8 +270,12 @@ const char kActivationListSocialEngineeringAdsInterstitial[] =
"social_engineering_ads_interstitial";
const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
const char kActivationListSubresourceFilter[] = "subresource_filter";
+const char kActivationListBetterAds[] = "better_ads";
+const char kActivationListAbusiveAds[] = "abusive_ads";
+const char kActivationListAllAds[] = "all_ads";
const char kActivationPriorityParameterName[] = "activation_priority";
+const char kActivationExperimentalParameterName[] = "experimental";
const char kPerformanceMeasurementRateParameterName[] =
"performance_measurement_rate";
@@ -296,6 +311,16 @@ Configuration Configuration::MakePresetForPerformanceTestingDryRunOnAllSites() {
return config;
}
+// static
+Configuration Configuration::MakeForForcedActivation() {
+ // This is a strange configuration, but it is generated on-the-fly rather than
+ // via finch configs, and is separate from the standard activation computation
+ // (which is why scope is no_sites).
+ Configuration config(ActivationLevel::ENABLED, ActivationScope::NO_SITES);
+ config.activation_conditions.forced_activation = true;
+ return config;
+}
+
Configuration::Configuration() = default;
Configuration::Configuration(ActivationLevel activation_level,
ActivationScope activation_scope,
@@ -315,6 +340,8 @@ bool Configuration::operator==(const Configuration& rhs) const {
return std::tie(config.activation_conditions.activation_scope,
config.activation_conditions.activation_list,
config.activation_conditions.priority,
+ config.activation_conditions.experimental,
+ config.activation_conditions.forced_activation,
config.activation_options.activation_level,
config.activation_options.performance_measurement_rate,
config.activation_options.should_whitelist_site_on_reload,
@@ -336,6 +363,8 @@ Configuration::ActivationConditions::ToTracedValue() const {
value->SetString("activation_scope", StreamToString(activation_scope));
value->SetString("activation_list", StreamToString(activation_list));
value->SetInteger("priority", priority);
+ value->SetBoolean("experimental", experimental);
+ value->SetBoolean("forced_activation", forced_activation);
return value;
}
@@ -361,6 +390,11 @@ std::unique_ptr<base::trace_event::TracedValue> Configuration::ToTracedValue()
return value;
}
+std::ostream& operator<<(std::ostream& os, const Configuration& config) {
+ os << config.ToTracedValue()->ToString();
+ return os;
+}
+
// ConfigurationList ----------------------------------------------------------
ConfigurationList::ConfigurationList(std::vector<Configuration> configs)
@@ -380,6 +414,11 @@ scoped_refptr<ConfigurationList> GetEnabledConfigurations() {
return g_active_configurations.Get();
}
+bool HasEnabledConfiguration(const Configuration& config) {
+ return base::ContainsValue(
+ GetEnabledConfigurations()->configs_by_decreasing_priority(), config);
+}
+
namespace testing {
scoped_refptr<ConfigurationList> GetAndSetActivateConfigurations(
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
index 2d011a473d3..4c6b638f6ea 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -62,6 +62,14 @@ struct Configuration {
// otherwise satisfied. A greater value indicates higher priority.
int priority = 0;
+ // Whether to activate on SafeBrowsing lists with experimental metadata.
+ bool experimental = false;
+
+ // This boolean is set to true for a navigation which has forced activation,
+ // despite other conditions not matching. It should never be possible to set
+ // this via variation params.
+ bool forced_activation = false;
+
std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const;
};
@@ -129,11 +137,17 @@ struct Configuration {
static Configuration MakePresetForLiveRunOnPhishingSites();
static Configuration MakePresetForPerformanceTestingDryRunOnAllSites();
+ // Not really a preset, but used as the configuration for forcing activation
+ // (e.g. via devtools).
+ static Configuration MakeForForcedActivation();
+
ActivationConditions activation_conditions;
ActivationOptions activation_options;
GeneralSettings general_settings;
};
+std::ostream& operator<<(std::ostream& os, const Configuration& config);
+
// Thread-safe, ref-counted wrapper around an immutable list of configurations.
class ConfigurationList : public base::RefCountedThreadSafe<ConfigurationList> {
public:
@@ -169,6 +183,8 @@ class ConfigurationList : public base::RefCountedThreadSafe<ConfigurationList> {
// callers should not hold on to the result for long.
scoped_refptr<ConfigurationList> GetEnabledConfigurations();
+bool HasEnabledConfiguration(const Configuration& config);
+
namespace testing {
// Returns the currently cached enabled ConfigurationList, if any, and replaces
@@ -201,8 +217,12 @@ extern const char kActivationListsParameterName[];
extern const char kActivationListSocialEngineeringAdsInterstitial[];
extern const char kActivationListPhishingInterstitial[];
extern const char kActivationListSubresourceFilter[];
+extern const char kActivationListBetterAds[];
+extern const char kActivationListAbusiveAds[];
+extern const char kActivationListAllAds[];
extern const char kActivationPriorityParameterName[];
+extern const char kActivationExperimentalParameterName[];
extern const char kPerformanceMeasurementRateParameterName[];
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
index 5ab04be3d16..e52d6d5f22c 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -252,6 +252,9 @@ TEST(SubresourceFilterFeaturesTest, ActivationList) {
{true, "%$ garbage !%", ActivationList::NONE},
{true, kActivationListSocialEngineeringAdsInterstitial,
ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL},
+ {true, kActivationListBetterAds, ActivationList::BETTER_ADS},
+ {true, kActivationListAbusiveAds, ActivationList::ABUSIVE_ADS},
+ {true, kActivationListAllAds, ActivationList::ALL_ADS},
{true, kActivationListPhishingInterstitial,
ActivationList::PHISHING_INTERSTITIAL},
{true, socEngPhising.c_str(), ActivationList::NONE},
@@ -680,4 +683,21 @@ TEST(SubresourceFilterFeaturesTest,
config_list->lexicographically_greatest_ruleset_flavor());
}
+TEST(SubresourceFilterFeaturesTest, ForcedActivation_NotConfigurable) {
+ ScopedExperimentalStateToggle scoped_experimental_state(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ {{kActivationLevelParameterName, kActivationLevelEnabled},
+ {kActivationScopeParameterName, kActivationScopeNoSites},
+ {"forced_activation", "true"}});
+
+ Configuration actual_configuration;
+ ExpectAndRetrieveExactlyOneEnabledConfig(&actual_configuration);
+ EXPECT_EQ(ActivationLevel::ENABLED,
+ actual_configuration.activation_options.activation_level);
+ EXPECT_EQ(ActivationScope::NO_SITES,
+ actual_configuration.activation_conditions.activation_scope);
+
+ EXPECT_FALSE(actual_configuration.activation_conditions.forced_activation);
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/activation_list.cc b/chromium/components/subresource_filter/core/common/activation_list.cc
index a5f50e1df33..e3ad196be24 100644
--- a/chromium/components/subresource_filter/core/common/activation_list.cc
+++ b/chromium/components/subresource_filter/core/common/activation_list.cc
@@ -24,6 +24,15 @@ std::ostream& operator<<(std::ostream& os, const ActivationList& type) {
case ActivationList::SUBRESOURCE_FILTER:
os << "SUBRESOURCE_FILTER";
break;
+ case ActivationList::BETTER_ADS:
+ os << "BETTER_ADS";
+ break;
+ case ActivationList::ABUSIVE_ADS:
+ os << "ABUSIVE_ADS";
+ break;
+ case ActivationList::ALL_ADS:
+ os << "ALL_ADS";
+ break;
default:
NOTREACHED();
break;
diff --git a/chromium/components/subresource_filter/core/common/activation_list.h b/chromium/components/subresource_filter/core/common/activation_list.h
index e17cce074ec..eff38cabccc 100644
--- a/chromium/components/subresource_filter/core/common/activation_list.h
+++ b/chromium/components/subresource_filter/core/common/activation_list.h
@@ -9,12 +9,25 @@
namespace subresource_filter {
-enum class ActivationList {
+// This enum backs a histogram. Make sure all updates are reflected in
+// enums.xml.
+enum class ActivationList : int {
NONE,
SOCIAL_ENG_ADS_INTERSTITIAL,
PHISHING_INTERSTITIAL,
SUBRESOURCE_FILTER,
- LAST = SUBRESOURCE_FILTER,
+
+ // Site violates the better ads standard.
+ BETTER_ADS,
+
+ // Site shows abusive ads.
+ ABUSIVE_ADS,
+
+ // Site violates the better ads standard and shows abusive ads.
+ ALL_ADS,
+
+ // Make sure new elements added update the LAST value.
+ LAST = ALL_ADS
};
// For logging use only.
diff --git a/chromium/components/subresource_filter/core/common/document_subresource_filter.cc b/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
index 2dcbaaa5292..243000f3aad 100644
--- a/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
+++ b/chromium/components/subresource_filter/core/common/document_subresource_filter.cc
@@ -45,9 +45,7 @@ LoadPolicy DocumentSubresourceFilter::GetLoadPolicy(
return LoadPolicy::ALLOW;
auto wall_duration_timer = ScopedTimers::StartIf(
- activation_state_.measure_performance &&
- ScopedThreadTimers::IsSupported(),
- [this](base::TimeDelta delta) {
+ activation_state_.measure_performance, [this](base::TimeDelta delta) {
statistics_.evaluation_total_wall_duration += delta;
UMA_HISTOGRAM_MICRO_TIMES(
"SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta);
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
index 009258e7081..18c9faae76e 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -5,7 +5,9 @@
#include "components/subresource_filter/core/common/indexed_ruleset.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "components/subresource_filter/core/common/first_party_origin.h"
+#include "components/subresource_filter/core/common/time_measurements.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -58,6 +60,10 @@ void RulesetIndexer::Finish() {
// static
bool IndexedRulesetMatcher::Verify(const uint8_t* buffer, size_t size) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "IndexedRulesetMatcher::Verify");
+ SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
+ "SubresourceFilter.IndexRuleset.Verify.WallDuration");
flatbuffers::Verifier verifier(buffer, size);
return flat::VerifyIndexedRulesetBuffer(verifier);
}
diff --git a/chromium/components/suggestions/image_manager.cc b/chromium/components/suggestions/image_manager.cc
index 321aef28ac1..6d843bd3c26 100644
--- a/chromium/components/suggestions/image_manager.cc
+++ b/chromium/components/suggestions/image_manager.cc
@@ -55,7 +55,7 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can disable this feature by signing out of Chrome, or "
"disabling Sync or History Sync in Chrome settings under 'Advanced "
diff --git a/chromium/components/suggestions/suggestions_service_impl.cc b/chromium/components/suggestions/suggestions_service_impl.cc
index e1af0660e44..420eab51b16 100644
--- a/chromium/components/suggestions/suggestions_service_impl.cc
+++ b/chromium/components/suggestions/suggestions_service_impl.cc
@@ -442,7 +442,7 @@ SuggestionsServiceImpl::CreateSuggestionsRequest(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can disable this feature by signing out of Chromium, or "
"disabling Sync or History Sync in Chromium settings under "
diff --git a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
index d6b93275843..164bbac83a6 100644
--- a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
+++ b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
@@ -40,7 +40,6 @@ function sendCommand(cmd) {
// TODO(bauerb): domAutomationController is not defined when this page is
// shown in chrome://interstitials. Use a MessageHandler or something to
// support interactions.
- window.domAutomationController.setAutomationId(1);
window.domAutomationController.send(cmd);
}
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
index d3402fa132c..08589b08546 100644
--- a/chromium/components/sync/BUILD.gn
+++ b/chromium/components/sync/BUILD.gn
@@ -62,8 +62,6 @@ static_library("sync") {
"base/report_unrecoverable_error.cc",
"base/report_unrecoverable_error.h",
"base/stop_source.h",
- "base/sync_features.cc",
- "base/sync_features.h",
"base/sync_prefs.cc",
"base/sync_prefs.h",
"base/syncer_error.cc",
@@ -610,6 +608,7 @@ static_library("sync") {
"//google_apis",
"//sql",
"//third_party/cacheinvalidation",
+ "//third_party/crc32c",
"//third_party/leveldatabase",
"//third_party/zlib",
"//third_party/zlib/google:compression_utils",
@@ -617,12 +616,7 @@ static_library("sync") {
if (is_android) {
deps += [ "//components/sync/android:jni_headers" ]
- sources += [
- "android/model_type_helper.cc",
- "android/model_type_helper.h",
- "android/sync_jni_registrar.cc",
- "android/sync_jni_registrar.h",
- ]
+ sources += [ "android/model_type_helper.cc" ]
}
if (is_chromeos) {
@@ -991,6 +985,7 @@ source_set("unit_tests") {
"//sql:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//third_party/crc32c",
"//third_party/leveldatabase",
"//third_party/protobuf:protobuf_lite",
"//third_party/zlib/google:compression_utils",
diff --git a/chromium/components/sync/android/BUILD.gn b/chromium/components/sync/android/BUILD.gn
index 5896fb4228f..0bf004a9ec7 100644
--- a/chromium/components/sync/android/BUILD.gn
+++ b/chromium/components/sync/android/BUILD.gn
@@ -15,7 +15,6 @@ android_library("sync_java") {
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
"//third_party/jsr-305:jsr_305_javalib",
- google_play_services_library,
]
srcjar_deps = [ ":java_enums" ]
java_files = [
@@ -46,6 +45,7 @@ android_library("sync_javatests") {
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
"//third_party/jsr-305:jsr_305_javalib",
+ "//third_party/junit",
]
java_files = [
"javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java",
diff --git a/chromium/components/sync_bookmarks/BUILD.gn b/chromium/components/sync_bookmarks/BUILD.gn
index e283f6876cc..09110f92ce3 100644
--- a/chromium/components/sync_bookmarks/BUILD.gn
+++ b/chromium/components/sync_bookmarks/BUILD.gn
@@ -12,6 +12,10 @@ static_library("sync_bookmarks") {
"bookmark_data_type_controller.h",
"bookmark_model_associator.cc",
"bookmark_model_associator.h",
+ "bookmark_model_type_controller.cc",
+ "bookmark_model_type_controller.h",
+ "bookmark_model_type_processor.cc",
+ "bookmark_model_type_processor.h",
]
deps = [
@@ -30,6 +34,8 @@ source_set("unit_tests") {
sources = [
"bookmark_data_type_controller_unittest.cc",
+ "bookmark_model_type_controller_unittest.cc",
+ "bookmark_model_type_processor_unittest.cc",
]
deps = [
@@ -41,6 +47,7 @@ source_set("unit_tests") {
"//components/prefs:test_support",
"//components/sync",
"//components/sync:test_support_driver",
+ "//components/sync:test_support_engine",
"//components/sync:test_support_model",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/sync_bookmarks/bookmark_data_type_controller.h b/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
index 62c2741586d..781333d3ce7 100644
--- a/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
+++ b/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "components/bookmarks/browser/base_bookmark_model_observer.h"
diff --git a/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc b/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
index 340785c50e8..8fe1338846f 100644
--- a/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -71,11 +70,11 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
void SetUp() override {
model_associator_ = new ModelAssociatorMock();
change_processor_ = new ChangeProcessorMock();
- history_service_ = base::MakeUnique<HistoryMock>();
+ history_service_ = std::make_unique<HistoryMock>();
profile_sync_factory_ =
- base::MakeUnique<syncer::SyncApiComponentFactoryMock>(
+ std::make_unique<syncer::SyncApiComponentFactoryMock>(
model_associator_, change_processor_);
- bookmark_dtc_ = base::MakeUnique<BookmarkDataTypeController>(
+ bookmark_dtc_ = std::make_unique<BookmarkDataTypeController>(
base::Bind(&base::DoNothing), this);
}
@@ -86,8 +85,8 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
};
void CreateBookmarkModel(BookmarkLoadPolicy bookmark_load_policy) {
- bookmark_model_ = base::MakeUnique<BookmarkModel>(
- base::MakeUnique<bookmarks::TestBookmarkClient>());
+ bookmark_model_ = std::make_unique<BookmarkModel>(
+ std::make_unique<bookmarks::TestBookmarkClient>());
if (bookmark_load_policy == LOAD_MODEL) {
TestingPrefServiceSimple prefs;
bookmark_model_->Load(&prefs, base::FilePath(),
diff --git a/chromium/components/sync_bookmarks/bookmark_model_associator.cc b/chromium/components/sync_bookmarks/bookmark_model_associator.cc
index c710dbc1b78..a490d4deced 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_associator.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_associator.cc
@@ -963,9 +963,10 @@ syncer::SyncError BookmarkModelAssociator::CheckModelSyncState(
if (native_version == sync_version) {
context->set_native_model_sync_state(IN_SYNC);
} else {
+ // TODO(wychen): enum uma should be strongly typed. crbug.com/661401
UMA_HISTOGRAM_ENUMERATION("Sync.LocalModelOutOfSync",
ModelTypeToHistogramInt(syncer::BOOKMARKS),
- syncer::MODEL_TYPE_COUNT);
+ static_cast<int>(syncer::MODEL_TYPE_COUNT));
// Clear version on bookmark model so that we only report error once.
bookmark_model_->SetNodeSyncTransactionVersion(
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc b/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc
new file mode 100644
index 00000000000..ccc49f88cf2
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc
@@ -0,0 +1,169 @@
+// 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/sync_bookmarks/bookmark_model_type_controller.h"
+
+#include <utility>
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/engine/model_type_configurer.h"
+#include "components/sync/engine/model_type_processor_proxy.h"
+#include "components/sync/model/sync_error.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/syncable/directory.h"
+#include "components/sync/syncable/user_share.h"
+#include "components/sync_bookmarks/bookmark_model_type_processor.h"
+
+using syncer::SyncError;
+
+namespace sync_bookmarks {
+
+BookmarkModelTypeController::BookmarkModelTypeController(
+ syncer::SyncClient* sync_client)
+ : DataTypeController(syncer::BOOKMARKS),
+ sync_client_(sync_client),
+ state_(NOT_RUNNING) {}
+
+BookmarkModelTypeController::~BookmarkModelTypeController() = default;
+
+bool BookmarkModelTypeController::ShouldLoadModelBeforeConfigure() const {
+ DCHECK(CalledOnValidThread());
+ return true;
+}
+
+void BookmarkModelTypeController::BeforeLoadModels(
+ syncer::ModelTypeConfigurer* configurer) {
+ DCHECK(CalledOnValidThread());
+}
+
+void BookmarkModelTypeController::LoadModels(
+ const ModelLoadCallback& model_load_callback) {
+ DCHECK(CalledOnValidThread());
+ if (state() != NOT_RUNNING) {
+ model_load_callback.Run(type(),
+ SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
+ "Model already running", type()));
+ return;
+ }
+
+ state_ = MODEL_STARTING;
+
+ if (DependenciesLoaded()) {
+ state_ = MODEL_LOADED;
+ model_load_callback.Run(type(), SyncError());
+ } else {
+ // TODO(pavely): Subscribe for BookmarkModel and HistoryService
+ // notifications.
+ NOTIMPLEMENTED();
+ }
+}
+
+void BookmarkModelTypeController::RegisterWithBackend(
+ base::Callback<void(bool)> set_downloaded,
+ syncer::ModelTypeConfigurer* configurer) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(configurer);
+ std::unique_ptr<syncer::ActivationContext> activation_context =
+ PrepareActivationContext();
+ set_downloaded.Run(activation_context->model_type_state.initial_sync_done());
+ configurer->ActivateNonBlockingDataType(type(),
+ std::move(activation_context));
+}
+
+void BookmarkModelTypeController::StartAssociating(
+ const StartCallback& start_callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!start_callback.is_null());
+ DCHECK_EQ(MODEL_LOADED, state_);
+
+ state_ = RUNNING;
+
+ // There is no association, just call back promptly.
+ syncer::SyncMergeResult merge_result(type());
+ start_callback.Run(OK, merge_result, merge_result);
+}
+
+void BookmarkModelTypeController::ActivateDataType(
+ syncer::ModelTypeConfigurer* configurer) {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeController::DeactivateDataType(
+ syncer::ModelTypeConfigurer* configurer) {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeController::Stop() {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+syncer::DataTypeController::State BookmarkModelTypeController::state() const {
+ DCHECK(CalledOnValidThread());
+ return state_;
+}
+
+void BookmarkModelTypeController::GetAllNodes(
+ const AllNodesCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeController::GetStatusCounters(
+ const StatusCountersCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeController::RecordMemoryUsageHistogram() {
+ DCHECK(CalledOnValidThread());
+ NOTIMPLEMENTED();
+}
+
+bool BookmarkModelTypeController::DependenciesLoaded() {
+ DCHECK(CalledOnValidThread());
+ bookmarks::BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
+ if (!bookmark_model || !bookmark_model->loaded())
+ return false;
+
+ history::HistoryService* history_service = sync_client_->GetHistoryService();
+ if (!history_service || !history_service->BackendLoaded())
+ return false;
+
+ return true;
+}
+
+std::unique_ptr<syncer::ActivationContext>
+BookmarkModelTypeController::PrepareActivationContext() {
+ DCHECK(!model_type_processor_);
+
+ syncer::UserShare* user_share =
+ sync_client_->GetSyncService()->GetUserShare();
+ syncer::syncable::Directory* directory = user_share->directory.get();
+
+ std::unique_ptr<syncer::ActivationContext> activation_context =
+ std::make_unique<syncer::ActivationContext>();
+
+ directory->GetDownloadProgress(
+ type(), activation_context->model_type_state.mutable_progress_marker());
+ activation_context->model_type_state.set_initial_sync_done(
+ directory->InitialSyncEndedForType(type()));
+ // TODO(pavely): Populate model_type_state.type_context.
+
+ model_type_processor_ = std::make_unique<BookmarkModelTypeProcessor>();
+ activation_context->type_processor =
+ std::make_unique<syncer::ModelTypeProcessorProxy>(
+ model_type_processor_->GetWeakPtr(),
+ base::ThreadTaskRunnerHandle::Get());
+ return activation_context;
+}
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_controller.h b/chromium/components/sync_bookmarks/bookmark_model_type_controller.h
new file mode 100644
index 00000000000..daf3b1a130c
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_controller.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_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_CONTROLLER_H_
+#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_CONTROLLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "components/sync/engine/activation_context.h"
+
+namespace syncer {
+class SyncClient;
+} // namespace syncer
+
+namespace sync_bookmarks {
+
+class BookmarkModelTypeProcessor;
+
+// A class that manages the startup and shutdown of bookmark sync implemented
+// through USS APIs.
+class BookmarkModelTypeController : public syncer::DataTypeController {
+ public:
+ explicit BookmarkModelTypeController(syncer::SyncClient* sync_client);
+ ~BookmarkModelTypeController() override;
+
+ // syncer::DataTypeController implementation.
+ bool ShouldLoadModelBeforeConfigure() const override;
+ void BeforeLoadModels(syncer::ModelTypeConfigurer* configurer) override;
+ void LoadModels(const ModelLoadCallback& model_load_callback) override;
+ void RegisterWithBackend(base::Callback<void(bool)> set_downloaded,
+ syncer::ModelTypeConfigurer* configurer) override;
+ void StartAssociating(const StartCallback& start_callback) override;
+ void ActivateDataType(syncer::ModelTypeConfigurer* configurer) override;
+ void DeactivateDataType(syncer::ModelTypeConfigurer* configurer) override;
+ void Stop() override;
+ State state() const override;
+ void GetAllNodes(const AllNodesCallback& callback) override;
+ void GetStatusCounters(const StatusCountersCallback& callback) override;
+ void RecordMemoryUsageHistogram() override;
+
+ private:
+ friend class BookmarkModelTypeControllerTest;
+
+ // Returns true if both BookmarkModel and HistoryService are loaded.
+ bool DependenciesLoaded();
+
+ // Reads ModelTypeState from storage and creates BookmarkModelTypeProcessor.
+ std::unique_ptr<syncer::ActivationContext> PrepareActivationContext();
+
+ // SyncClient provides access to BookmarkModel, HistoryService and
+ // SyncService.
+ syncer::SyncClient* sync_client_;
+
+ // State of this datatype controller.
+ State state_;
+
+ // BookmarkModelTypeProcessor handles communications between sync engine and
+ // BookmarkModel/HistoryService.
+ std::unique_ptr<BookmarkModelTypeProcessor> model_type_processor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeController);
+};
+
+} // namespace sync_bookmarks
+
+#endif // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_CONTROLLER_H_
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_controller_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_type_controller_unittest.cc
new file mode 100644
index 00000000000..8d63337a0a2
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_controller_unittest.cc
@@ -0,0 +1,244 @@
+// 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/sync_bookmarks/bookmark_model_type_controller.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.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/sync/base/model_type.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "components/sync/driver/data_type_controller_mock.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/engine/model_type_configurer.h"
+#include "components/sync/model/sync_error.h"
+#include "components/sync/model/sync_merge_result.h"
+#include "components/sync/syncable/directory.h"
+#include "components/sync/syncable/test_user_share.h"
+#include "components/sync/test/engine/test_syncable_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::DataTypeController;
+using syncer::ModelType;
+using syncer::SyncService;
+using syncer::UserShare;
+using testing::_;
+
+namespace sync_bookmarks {
+
+namespace {
+
+// Fake specializations for BookmarModelTypeController's external dependencies.
+
+class TestHistoryService : public history::HistoryService {
+ public:
+ bool BackendLoaded() override { return true; }
+};
+
+class TestSyncClient : public syncer::FakeSyncClient {
+ public:
+ TestSyncClient(bookmarks::BookmarkModel* bookmark_model,
+ history::HistoryService* history_service,
+ SyncService* sync_service)
+ : bookmark_model_(bookmark_model),
+ history_service_(history_service),
+ sync_service_(sync_service) {}
+
+ bookmarks::BookmarkModel* GetBookmarkModel() override {
+ return bookmark_model_;
+ }
+
+ history::HistoryService* GetHistoryService() override {
+ return history_service_;
+ }
+
+ SyncService* GetSyncService() override { return sync_service_; }
+
+ private:
+ bookmarks::BookmarkModel* bookmark_model_;
+ history::HistoryService* history_service_;
+ SyncService* sync_service_;
+};
+
+class TestSyncService : public syncer::FakeSyncService {
+ public:
+ explicit TestSyncService(UserShare* user_share) : user_share_(user_share) {}
+
+ UserShare* GetUserShare() const override { return user_share_; }
+
+ private:
+ UserShare* user_share_;
+};
+
+class TestModelTypeConfigurer : public syncer::ModelTypeConfigurer {
+ public:
+ TestModelTypeConfigurer() {}
+ ~TestModelTypeConfigurer() override {}
+
+ void ConfigureDataTypes(ConfigureParams params) override {}
+
+ void RegisterDirectoryDataType(ModelType type,
+ syncer::ModelSafeGroup group) override {}
+
+ void UnregisterDirectoryDataType(ModelType type) override {}
+
+ void ActivateDirectoryDataType(
+ ModelType type,
+ syncer::ModelSafeGroup group,
+ syncer::ChangeProcessor* change_processor) override {}
+
+ void DeactivateDirectoryDataType(ModelType type) override {}
+
+ void ActivateNonBlockingDataType(
+ ModelType type,
+ std::unique_ptr<syncer::ActivationContext> activation_context) override {
+ activation_context_ = std::move(activation_context);
+ }
+
+ void DeactivateNonBlockingDataType(ModelType type) override {}
+
+ syncer::ActivationContext* activation_context() {
+ return activation_context_.get();
+ }
+
+ private:
+ // ActivationContext captured in ActivateNonBlockingDataType call.
+ std::unique_ptr<syncer::ActivationContext> activation_context_;
+};
+
+} // namespace
+
+class BookmarkModelTypeControllerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
+ history_service_ = std::make_unique<TestHistoryService>();
+ test_user_share_.SetUp();
+ sync_service_ =
+ std::make_unique<TestSyncService>(test_user_share_.user_share());
+ sync_client_ = std::make_unique<TestSyncClient>(
+ bookmark_model_.get(), history_service_.get(), sync_service_.get());
+ controller_ =
+ std::make_unique<BookmarkModelTypeController>(sync_client_.get());
+ }
+
+ void TearDown() override { test_user_share_.TearDown(); }
+
+ protected:
+ BookmarkModelTypeController* controller() { return controller_.get(); }
+
+ syncer::UserShare* user_share() { return test_user_share_.user_share(); }
+
+ syncer::ModelLoadCallbackMock& model_load_callback() {
+ return model_load_callback_;
+ }
+
+ syncer::StartCallbackMock& start_callback() { return start_callback_; }
+
+ syncer::ActivationContext* activation_context() {
+ return model_type_configurer_.activation_context();
+ }
+
+ void LoadModels() {
+ controller()->LoadModels(
+ base::Bind(&syncer::ModelLoadCallbackMock::Run,
+ base::Unretained(&model_load_callback_)));
+ }
+
+ static void CaptureBoolean(bool* value_dest, bool value) {
+ *value_dest = value;
+ }
+
+ void CallRegisterWithBackend(bool* initial_sync_done) {
+ controller()->RegisterWithBackend(
+ base::Bind(&BookmarkModelTypeControllerTest::CaptureBoolean,
+ initial_sync_done),
+ &model_type_configurer_);
+ }
+
+ void StartAssociating() {
+ controller()->StartAssociating(base::Bind(
+ &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+
+ std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
+ std::unique_ptr<history::HistoryService> history_service_;
+ syncer::TestUserShare test_user_share_;
+ std::unique_ptr<SyncService> sync_service_;
+ std::unique_ptr<TestSyncClient> sync_client_;
+ TestModelTypeConfigurer model_type_configurer_;
+
+ syncer::ModelLoadCallbackMock model_load_callback_;
+ syncer::StartCallbackMock start_callback_;
+
+ std::unique_ptr<BookmarkModelTypeController> controller_;
+};
+
+// Tests model type and initial state of bookmarks controller.
+TEST_F(BookmarkModelTypeControllerTest, InitialState) {
+ EXPECT_EQ(syncer::BOOKMARKS, controller()->type());
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
+ EXPECT_TRUE(controller()->ShouldLoadModelBeforeConfigure());
+}
+
+// Tests that call to LoadModels triggers ModelLoadCallback and advances DTC
+// state.
+TEST_F(BookmarkModelTypeControllerTest, LoadModels) {
+ EXPECT_CALL(model_load_callback(), Run(_, _));
+ LoadModels();
+ EXPECT_EQ(DataTypeController::MODEL_LOADED, controller()->state());
+}
+
+// Tests that registering with backend from clean state reports that initial
+// sync is not done and progress marker is empty.
+TEST_F(BookmarkModelTypeControllerTest, RegisterWithBackend_CleanState) {
+ LoadModels();
+ bool initial_sync_done = false;
+ CallRegisterWithBackend(&initial_sync_done);
+ EXPECT_FALSE(initial_sync_done);
+ EXPECT_FALSE(activation_context()->model_type_state.initial_sync_done());
+ EXPECT_TRUE(
+ activation_context()->model_type_state.progress_marker().token().empty());
+ EXPECT_NE(nullptr, activation_context()->type_processor);
+}
+
+// Tests that registering with backend from valid state returns non-empty
+// progress marker.
+TEST_F(BookmarkModelTypeControllerTest, RegisterWithBackend) {
+ syncer::TestUserShare::CreateRoot(syncer::BOOKMARKS, user_share());
+ sync_pb::DataTypeProgressMarker progress_marker =
+ syncer::syncable::BuildProgress(syncer::BOOKMARKS);
+ user_share()->directory->SetDownloadProgress(syncer::BOOKMARKS,
+ progress_marker);
+ LoadModels();
+ bool initial_sync_done = false;
+ CallRegisterWithBackend(&initial_sync_done);
+ EXPECT_TRUE(initial_sync_done);
+ EXPECT_TRUE(activation_context()->model_type_state.initial_sync_done());
+ EXPECT_EQ(progress_marker.SerializeAsString(),
+ activation_context()
+ ->model_type_state.progress_marker()
+ .SerializeAsString());
+ EXPECT_NE(nullptr, activation_context()->type_processor);
+}
+
+// Tests that call to StartAssociating triggers StartCallback and adjusts DTC
+// state.
+TEST_F(BookmarkModelTypeControllerTest, StartAssociating) {
+ LoadModels();
+ EXPECT_CALL(start_callback(), Run(_, _, _));
+ StartAssociating();
+ EXPECT_EQ(DataTypeController::RUNNING, controller()->state());
+}
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
new file mode 100644
index 00000000000..ccac311794b
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -0,0 +1,61 @@
+// 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/sync_bookmarks/bookmark_model_type_processor.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/engine/commit_queue.h"
+
+namespace sync_bookmarks {
+
+BookmarkModelTypeProcessor::BookmarkModelTypeProcessor()
+ : weak_ptr_factory_(this) {}
+
+BookmarkModelTypeProcessor::~BookmarkModelTypeProcessor() = default;
+
+void BookmarkModelTypeProcessor::ConnectSync(
+ std::unique_ptr<syncer::CommitQueue> worker) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!worker_);
+ worker_ = std::move(worker);
+}
+
+void BookmarkModelTypeProcessor::DisconnectSync() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeProcessor::GetLocalChanges(
+ size_t max_entries,
+ const GetLocalChangesCallback& callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ syncer::CommitRequestDataList local_changes;
+ callback.Run(std::move(local_changes));
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeProcessor::OnCommitCompleted(
+ const sync_pb::ModelTypeState& type_state,
+ const syncer::CommitResponseDataList& response_list) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ NOTIMPLEMENTED();
+}
+
+void BookmarkModelTypeProcessor::OnUpdateReceived(
+ const sync_pb::ModelTypeState& model_type_state,
+ const syncer::UpdateResponseDataList& updates) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ NOTIMPLEMENTED();
+}
+
+base::WeakPtr<syncer::ModelTypeProcessor>
+BookmarkModelTypeProcessor::GetWeakPtr() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.h b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
new file mode 100644
index 00000000000..3a32a958a29
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -0,0 +1,47 @@
+// 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_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_PROCESSOR_H_
+#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_PROCESSOR_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "components/sync/engine/model_type_processor.h"
+
+namespace sync_bookmarks {
+
+class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor {
+ public:
+ BookmarkModelTypeProcessor();
+ ~BookmarkModelTypeProcessor() override;
+
+ // ModelTypeProcessor implementation.
+ void ConnectSync(std::unique_ptr<syncer::CommitQueue> worker) override;
+ void DisconnectSync() override;
+ void GetLocalChanges(size_t max_entries,
+ const GetLocalChangesCallback& callback) override;
+ void OnCommitCompleted(
+ const sync_pb::ModelTypeState& type_state,
+ const syncer::CommitResponseDataList& response_list) override;
+ void OnUpdateReceived(const sync_pb::ModelTypeState& type_state,
+ const syncer::UpdateResponseDataList& updates) override;
+
+ base::WeakPtr<syncer::ModelTypeProcessor> GetWeakPtr();
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ std::unique_ptr<syncer::CommitQueue> worker_;
+
+ base::WeakPtrFactory<BookmarkModelTypeProcessor> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeProcessor);
+};
+
+} // namespace sync_bookmarks
+
+#endif // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_PROCESSOR_H_
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
new file mode 100644
index 00000000000..b3d40e3581d
--- /dev/null
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -0,0 +1,21 @@
+// 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/sync_bookmarks/bookmark_model_type_processor.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_bookmarks {
+
+namespace {
+
+class BookmarkModelTypeProcessorTest : public testing::Test {};
+
+TEST_F(BookmarkModelTypeProcessorTest, CreateInstance) {
+ BookmarkModelTypeProcessor processor;
+}
+
+} // namespace
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_preferences/pref_model_associator.cc b/chromium/components/sync_preferences/pref_model_associator.cc
index 3175208aa1b..2f0a8e50b84 100644
--- a/chromium/components/sync_preferences/pref_model_associator.cc
+++ b/chromium/components/sync_preferences/pref_model_associator.cc
@@ -241,8 +241,10 @@ std::unique_ptr<base::Value> PrefModelAssociator::MergePreference(
std::string new_pref_name;
if (client_->IsMergeableListPreference(name))
return MergeListValues(local_value, server_value);
- if (client_->IsMergeableDictionaryPreference(name))
- return MergeDictionaryValues(local_value, server_value);
+ if (client_->IsMergeableDictionaryPreference(name)) {
+ return base::MakeUnique<base::Value>(
+ MergeDictionaryValues(local_value, server_value));
+ }
}
// If this is not a specially handled preference, server wins.
@@ -281,62 +283,49 @@ std::unique_ptr<base::Value> PrefModelAssociator::MergeListValues(
const base::Value& from_value,
const base::Value& to_value) {
if (from_value.GetType() == base::Value::Type::NONE)
- return base::MakeUnique<base::Value>(to_value);
+ return base::MakeUnique<base::Value>(to_value.Clone());
if (to_value.GetType() == base::Value::Type::NONE)
- return base::MakeUnique<base::Value>(from_value);
+ return base::MakeUnique<base::Value>(from_value.Clone());
DCHECK(from_value.GetType() == base::Value::Type::LIST);
DCHECK(to_value.GetType() == base::Value::Type::LIST);
- const base::ListValue& from_list_value =
- static_cast<const base::ListValue&>(from_value);
- const base::ListValue& to_list_value =
- static_cast<const base::ListValue&>(to_value);
-
- auto result = base::MakeUnique<base::ListValue>(to_list_value);
- base::Value::ListStorage& list = result->GetList();
- std::copy_if(
- from_list_value.GetList().begin(), from_list_value.GetList().end(),
- std::back_inserter(list), [&list](const base::Value& value) {
- return std::find(list.begin(), list.end(), value) == list.end();
- });
- return std::move(result);
+
+ base::Value result = to_value.Clone();
+ base::Value::ListStorage& list = result.GetList();
+ for (const auto& value : from_value.GetList()) {
+ if (std::find(list.begin(), list.end(), value) == list.end())
+ list.emplace_back(value.Clone());
+ }
+
+ return base::MakeUnique<base::Value>(std::move(result));
}
-std::unique_ptr<base::Value> PrefModelAssociator::MergeDictionaryValues(
+base::Value PrefModelAssociator::MergeDictionaryValues(
const base::Value& from_value,
const base::Value& to_value) {
- if (from_value.GetType() == base::Value::Type::NONE)
- return base::MakeUnique<base::Value>(to_value);
- if (to_value.GetType() == base::Value::Type::NONE)
- return base::MakeUnique<base::Value>(from_value);
-
- DCHECK_EQ(from_value.GetType(), base::Value::Type::DICTIONARY);
- DCHECK_EQ(to_value.GetType(), base::Value::Type::DICTIONARY);
- const base::DictionaryValue& from_dict_value =
- static_cast<const base::DictionaryValue&>(from_value);
- const base::DictionaryValue& to_dict_value =
- static_cast<const base::DictionaryValue&>(to_value);
- auto result = base::MakeUnique<base::DictionaryValue>(to_dict_value);
-
- for (base::DictionaryValue::Iterator it(from_dict_value); !it.IsAtEnd();
- it.Advance()) {
- const base::Value* from_key_value = &it.value();
- base::Value* to_key_value;
- if (result->GetWithoutPathExpansion(it.key(), &to_key_value)) {
- if (from_key_value->GetType() == base::Value::Type::DICTIONARY &&
- to_key_value->GetType() == base::Value::Type::DICTIONARY) {
- std::unique_ptr<base::Value> merged_value =
- MergeDictionaryValues(*from_key_value, *to_key_value);
- result->SetWithoutPathExpansion(it.key(), std::move(merged_value));
+ if (from_value.is_none())
+ return to_value.Clone();
+ if (to_value.is_none())
+ return from_value.Clone();
+
+ DCHECK(from_value.is_dict());
+ DCHECK(to_value.is_dict());
+ base::Value result = to_value.Clone();
+
+ for (const auto& it : from_value.DictItems()) {
+ const base::Value* from_key_value = &it.second;
+ base::Value* to_key_value = result.FindKey(it.first);
+ if (to_key_value) {
+ if (from_key_value->is_dict() && to_key_value->is_dict()) {
+ *to_key_value = MergeDictionaryValues(*from_key_value, *to_key_value);
}
// Note that for all other types we want to preserve the "to"
// values so we do nothing here.
} else {
- result->SetWithoutPathExpansion(
- it.key(), base::MakeUnique<base::Value>(*from_key_value));
+ result.SetKey(it.first, from_key_value->Clone());
}
}
- return std::move(result);
+ return result;
}
// Note: This will build a model of all preferences registered as syncable
diff --git a/chromium/components/sync_preferences/pref_model_associator.h b/chromium/components/sync_preferences/pref_model_associator.h
index 257f0f53758..20ceba75f56 100644
--- a/chromium/components/sync_preferences/pref_model_associator.h
+++ b/chromium/components/sync_preferences/pref_model_associator.h
@@ -143,9 +143,8 @@ class PrefModelAssociator : public syncer::SyncableService {
static std::unique_ptr<base::Value> MergeListValues(
const base::Value& from_value,
const base::Value& to_value);
- static std::unique_ptr<base::Value> MergeDictionaryValues(
- const base::Value& from_value,
- const base::Value& to_value);
+ static base::Value MergeDictionaryValues(const base::Value& from_value,
+ const base::Value& to_value);
// Do we have an active association between the preferences and sync models?
// Set when start syncing, reset in StopSyncing. While this is not set, we
diff --git a/chromium/components/sync_preferences/pref_model_associator_unittest.cc b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
index 25da5672dd2..03170029226 100644
--- a/chromium/components/sync_preferences/pref_model_associator_unittest.cc
+++ b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
@@ -71,7 +71,7 @@ class AbstractPreferenceMergeTest : public testing::Test {
expression_dict = patterns_dict->SetDictionaryWithoutPathExpansion(
expression, base::MakeUnique<base::DictionaryValue>());
}
- expression_dict->SetIntegerWithoutPathExpansion("setting", setting);
+ expression_dict->SetKey("setting", base::Value(setting));
}
void SetPrefToEmpty(const std::string& pref_name) {
diff --git a/chromium/components/sync_sessions/favicon_cache_unittest.cc b/chromium/components/sync_sessions/favicon_cache_unittest.cc
index b39a8b37a76..bf917831845 100644
--- a/chromium/components/sync_sessions/favicon_cache_unittest.cc
+++ b/chromium/components/sync_sessions/favicon_cache_unittest.cc
@@ -200,7 +200,7 @@ testing::AssertionResult CompareFaviconDataToSpecifics(
if (tracking_specifics.last_visit_time_ms() != test_data.last_visit_time)
return testing::AssertionFailure() << "Visit time doesn't match.";
if (tracking_specifics.is_bookmarked() != test_data.is_bookmarked)
- return testing::AssertionFailure() << "Bookmark status doens't match.";
+ return testing::AssertionFailure() << "Bookmark status doesn't match.";
}
return testing::AssertionSuccess();
}
@@ -401,7 +401,7 @@ testing::AssertionResult SyncFaviconCacheTest::VerifyLocalCustomIcons(
std::unique_ptr<syncer::SyncChangeProcessor>
SyncFaviconCacheTest::CreateAndPassProcessor() {
- return base::MakeUnique<syncer::SyncChangeProcessorWrapperForTest>(
+ return std::make_unique<syncer::SyncChangeProcessorWrapperForTest>(
sync_processor_.get());
}
diff --git a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
index 9ead16bc0a1..e9dd2cea622 100644
--- a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
@@ -4,7 +4,6 @@
#include "components/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,7 +34,7 @@ class TestBookmarksByUrlProvider : public BookmarksByUrlProvider {
void RunObserver(const std::vector<const bookmarks::BookmarkNode*>& nodes) {
BookmarksPageRevisitObserver observer(
- base::MakeUnique<TestBookmarksByUrlProvider>(nodes));
+ std::make_unique<TestBookmarksByUrlProvider>(nodes));
observer.OnPageVisit(kExampleGurl, PageVisitObserver::kTransitionPage);
}
diff --git a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
index f887f26f123..77e4cdf63ea 100644
--- a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
+++ b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
@@ -6,7 +6,6 @@
#include <string>
-#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/history/core/browser/history_service.h"
@@ -49,20 +48,20 @@ PageRevisitBroadcaster::PageRevisitBroadcaster(
base::FieldTrialList::FindFullName("PageRevisitInstrumentation");
bool shouldInstrument = group_name == "Enabled";
if (shouldInstrument) {
- revisit_observers_.push_back(base::MakeUnique<SessionsPageRevisitObserver>(
- base::MakeUnique<SessionsSyncManagerWrapper>(manager)));
+ revisit_observers_.push_back(std::make_unique<SessionsPageRevisitObserver>(
+ std::make_unique<SessionsSyncManagerWrapper>(manager)));
history::HistoryService* history = sessions_client_->GetHistoryService();
if (history) {
revisit_observers_.push_back(
- base::MakeUnique<TypedUrlPageRevisitObserver>(history));
+ std::make_unique<TypedUrlPageRevisitObserver>(history));
}
bookmarks::BookmarkModel* bookmarks = sessions_client_->GetBookmarkModel();
if (bookmarks) {
revisit_observers_.push_back(
- base::MakeUnique<BookmarksPageRevisitObserver>(
- base::MakeUnique<BookmarksByUrlProviderImpl>(bookmarks)));
+ std::make_unique<BookmarksPageRevisitObserver>(
+ std::make_unique<BookmarksByUrlProviderImpl>(bookmarks)));
}
}
}
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
index f69c731c664..97878c08f8c 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
@@ -7,7 +7,6 @@
#include <string>
#include <utility>
-#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
@@ -74,7 +73,7 @@ class SessionsPageRevisitObserverTest : public ::testing::Test {
std::vector<const SyncedSession*> sessions;
sessions.push_back(session);
SessionsPageRevisitObserver observer(
- base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
+ std::make_unique<TestForeignSessionsProvider>(sessions, true));
CheckAndExpect(&observer, url, current_match, offset_match);
}
};
@@ -82,44 +81,44 @@ class SessionsPageRevisitObserverTest : public ::testing::Test {
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoSessions) {
std::vector<const SyncedSession*> sessions;
SessionsPageRevisitObserver observer(
- base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
+ std::make_unique<TestForeignSessionsProvider>(sessions, true));
CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoWindows) {
- auto session = base::MakeUnique<SyncedSession>();
+ auto session = std::make_unique<SyncedSession>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoTabs) {
- auto session = base::MakeUnique<SyncedSession>();
- session->windows[0] = base::MakeUnique<SyncedSessionWindow>();
+ auto session = std::make_unique<SyncedSession>();
+ session->windows[0] = std::make_unique<SyncedSessionWindow>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoEntries) {
- auto window = base::MakeUnique<SyncedSessionWindow>();
- window->wrapped_window.tabs.push_back(base::MakeUnique<SessionTab>());
- auto session = base::MakeUnique<SyncedSession>();
+ auto window = std::make_unique<SyncedSessionWindow>();
+ window->wrapped_window.tabs.push_back(std::make_unique<SessionTab>());
+ auto session = std::make_unique<SyncedSession>();
session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersSingle) {
- auto tab = base::MakeUnique<SessionTab>();
+ auto tab = std::make_unique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 0;
- auto window = base::MakeUnique<SyncedSessionWindow>();
+ auto window = std::make_unique<SyncedSessionWindow>();
window->wrapped_window.tabs.push_back(std::move(tab));
- auto session = base::MakeUnique<SyncedSession>();
+ auto session = std::make_unique<SyncedSession>();
session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), true, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
- auto tab = base::MakeUnique<SessionTab>();
+ auto tab = std::make_unique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -127,9 +126,9 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 1;
- auto window = base::MakeUnique<SyncedSessionWindow>();
+ auto window = std::make_unique<SyncedSessionWindow>();
window->wrapped_window.tabs.push_back(std::move(tab));
- auto session = base::MakeUnique<SyncedSession>();
+ auto session = std::make_unique<SyncedSession>();
session->windows[0] = std::move(window);
// The provider returns false when asked for foreign sessions, even though
@@ -137,30 +136,30 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
std::vector<const SyncedSession*> sessions;
sessions.push_back(session.get());
SessionsPageRevisitObserver observer(
- base::MakeUnique<TestForeignSessionsProvider>(sessions, false));
+ std::make_unique<TestForeignSessionsProvider>(sessions, false));
CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
- auto tab1 = base::MakeUnique<SessionTab>();
+ auto tab1 = std::make_unique<SessionTab>();
tab1->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab1->current_navigation_index = 0;
- auto tab2 = base::MakeUnique<SessionTab>();
+ auto tab2 = std::make_unique<SessionTab>();
tab2->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab2->current_navigation_index = 0;
- auto tab3 = base::MakeUnique<SessionTab>();
+ auto tab3 = std::make_unique<SessionTab>();
tab3->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab3->current_navigation_index = 0;
- auto tab4 = base::MakeUnique<SessionTab>();
+ auto tab4 = std::make_unique<SessionTab>();
tab4->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -169,17 +168,17 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
kDifferentUrl, ""));
tab4->current_navigation_index = 1;
- auto window1 = base::MakeUnique<SyncedSessionWindow>();
+ auto window1 = std::make_unique<SyncedSessionWindow>();
window1->wrapped_window.tabs.push_back(std::move(tab1));
- auto window2 = base::MakeUnique<SyncedSessionWindow>();
+ auto window2 = std::make_unique<SyncedSessionWindow>();
window2->wrapped_window.tabs.push_back(std::move(tab2));
- auto window3 = base::MakeUnique<SyncedSessionWindow>();
+ auto window3 = std::make_unique<SyncedSessionWindow>();
window3->wrapped_window.tabs.push_back(std::move(tab3));
window3->wrapped_window.tabs.push_back(std::move(tab4));
- auto session1 = base::MakeUnique<SyncedSession>();
+ auto session1 = std::make_unique<SyncedSession>();
session1->windows[1] = std::move(window1);
- auto session2 = base::MakeUnique<SyncedSession>();
+ auto session2 = std::make_unique<SyncedSession>();
session2->windows[2] = std::move(window2);
session2->windows[3] = std::move(window3);
@@ -187,7 +186,7 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
sessions.push_back(session1.get());
sessions.push_back(session2.get());
SessionsPageRevisitObserver observer(
- base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
+ std::make_unique<TestForeignSessionsProvider>(sessions, true));
base::HistogramTester histogram_tester;
CheckAndExpect(&observer, GURL(kExampleUrl), true, true);
diff --git a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
index f102220b428..58816acc4da 100644
--- a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
+++ b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
@@ -4,7 +4,8 @@
#include "components/sync_sessions/revisit/typed_url_page_revisit_observer.h"
-#include "base/memory/ptr_util.h"
+#include <memory>
+
#include "components/history/core/browser/history_service.h"
#include "components/sync_sessions/revisit/typed_url_page_revisit_task.h"
#include "url/gurl.h"
@@ -22,7 +23,7 @@ void TypedUrlPageRevisitObserver::OnPageVisit(
const PageVisitObserver::TransitionType transition) {
if (history_) {
history_->ScheduleDBTask(
- base::MakeUnique<TypedUrlPageRevisitTask>(url, transition),
+ std::make_unique<TypedUrlPageRevisitTask>(url, transition),
&task_tracker_);
}
}
diff --git a/chromium/components/sync_sessions/session_data_type_controller_unittest.cc b/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
index e09bf7ee664..570964cebf2 100644
--- a/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
+++ b/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -117,18 +116,18 @@ class SessionDataTypeControllerTest : public testing::Test,
prefs_.registry()->RegisterBooleanPref(kSavingBrowserHistoryDisabled,
false);
- synced_window_delegate_ = base::MakeUnique<MockSyncedWindowDelegate>();
- synced_window_getter_ = base::MakeUnique<MockSyncedWindowDelegatesGetter>();
- sync_sessions_client_ = base::MakeUnique<TestSyncSessionsClient>();
+ synced_window_delegate_ = std::make_unique<MockSyncedWindowDelegate>();
+ synced_window_getter_ = std::make_unique<MockSyncedWindowDelegatesGetter>();
+ sync_sessions_client_ = std::make_unique<TestSyncSessionsClient>();
synced_window_getter_->Add(synced_window_delegate_.get());
sync_sessions_client_->SetSyncedWindowDelegatesGetter(
synced_window_getter_.get());
- local_device_ = base::MakeUnique<LocalDeviceInfoProviderMock>(
+ local_device_ = std::make_unique<LocalDeviceInfoProviderMock>(
"cache_guid", "Wayne Gretzky's Hacking Box", "Chromium 10k",
"Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id");
- controller_ = base::MakeUnique<SessionDataTypeController>(
+ controller_ = std::make_unique<SessionDataTypeController>(
base::Bind(&base::DoNothing), this, local_device_.get(),
kSavingBrowserHistoryDisabled);
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.cc b/chromium/components/sync_sessions/sessions_sync_manager.cc
index 5810f8fc937..6720b520232 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager.cc
@@ -9,7 +9,6 @@
#include "base/format_macros.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
@@ -51,6 +50,20 @@ const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs";
// stale and becomes a candidate for garbage collection.
const int kDefaultStaleSessionThresholdDays = 14; // 2 weeks.
+// Clean up navigation tracking when we have over this many global_ids.
+const size_t kNavigationTrackingCleanupThreshold = 100;
+
+// When we clean up navigation tracking, delete this many global_ids.
+const int kNavigationTrackingCleanupAmount = 10;
+
+// Used to record conflict information into histogram Sync.GlobalIdConflict.
+enum SyncGlobalIdConflict {
+ CONFLICT = 0,
+ NO_CONFLICT_NEW_ID,
+ NO_CONFLICT_SAME_IDS,
+ CONFLICT_MAX,
+};
+
// Comparator function for use with std::sort that will sort tabs by
// descending timestamp (i.e., most recent first).
bool TabsRecencyComparator(const sessions::SessionTab* t1,
@@ -157,7 +170,7 @@ SessionsSyncManager::SessionsSyncManager(
page_revisit_broadcaster_(this, sessions_client),
sessions_updated_callback_(sessions_updated_callback),
datatype_refresh_callback_(datatype_refresh_callback),
- task_tracker_(base::MakeUnique<TaskTracker>()) {}
+ task_tracker_(std::make_unique<TaskTracker>()) {}
SessionsSyncManager::~SessionsSyncManager() {}
@@ -198,7 +211,7 @@ syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
// already associated with |sync_processor|, so leave it alone.
if (!lost_navigations_recorder_.get()) {
lost_navigations_recorder_ =
- base::MakeUnique<sync_sessions::LostNavigationsRecorder>();
+ std::make_unique<sync_sessions::LostNavigationsRecorder>();
sync_processor_->AddLocalChangeObserver(lost_navigations_recorder_.get());
}
@@ -578,6 +591,11 @@ void SessionsSyncManager::OnLocalTabModified(SyncedTabDelegate* modified_tab) {
}
}
+ sessions::SerializedNavigationEntry current;
+ modified_tab->GetSerializedNavigationAtIndex(
+ modified_tab->GetCurrentEntryIndex(), &current);
+ TrackNavigationIds(current);
+
if (local_tab_pool_out_of_sync_) {
// If our tab pool is corrupt, pay the price of a full re-association to
// fix things up. This takes care of the new tab modification as well.
@@ -1285,6 +1303,22 @@ void SessionsSyncManager::DoGarbageCollection() {
sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
}
+void SessionsSyncManager::AddGlobalIdChangeObserver(
+ syncer::GlobalIdChange callback) {
+ global_id_change_observers_.push_back(std::move(callback));
+}
+
+int64_t SessionsSyncManager::GetLatestGlobalId(int64_t global_id) {
+ auto g2u_iter = global_to_unique_.find(global_id);
+ if (g2u_iter != global_to_unique_.end()) {
+ auto u2g_iter = unique_to_current_global_.find(g2u_iter->second);
+ if (u2g_iter != unique_to_current_global_.end()) {
+ return u2g_iter->second;
+ }
+ }
+ return global_id;
+}
+
// static
std::string SessionsSyncManager::TagHashFromSpecifics(
const sync_pb::SessionSpecifics& specifics) {
@@ -1292,4 +1326,76 @@ std::string SessionsSyncManager::TagHashFromSpecifics(
TagFromSpecifics(specifics));
}
+void SessionsSyncManager::TrackNavigationIds(
+ const sessions::SerializedNavigationEntry& current) {
+ // The expectation is that global_id will update for a given unique_id, which
+ // should accurately and uniquely represent a single navigation. It is
+ // theoretically possible for two unique_ids to map to the same global_id, but
+ // hopefully rare enough that it doesn't cause much harm. Lets record metrics
+ // verify this theory.
+ int64_t global_id = current.timestamp().ToInternalValue();
+ // It is possible that the global_id has not been set yet for this navigation.
+ // In this case there's nothing here for us to track yet.
+ if (global_id == 0) {
+ return;
+ }
+
+ int unique_id = current.unique_id();
+ DCHECK_NE(0, unique_id);
+
+ auto g2u_iter = global_to_unique_.find(global_id);
+ if (g2u_iter == global_to_unique_.end()) {
+ global_to_unique_.insert(g2u_iter, std::make_pair(global_id, unique_id));
+ UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", NO_CONFLICT_NEW_ID,
+ CONFLICT_MAX);
+ } else if (g2u_iter->second != unique_id) {
+ UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", CONFLICT, CONFLICT_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Sync.GlobalIdConflict", NO_CONFLICT_SAME_IDS,
+ CONFLICT_MAX);
+ }
+
+ auto u2g_iter = unique_to_current_global_.find(unique_id);
+ if (u2g_iter == unique_to_current_global_.end()) {
+ unique_to_current_global_.insert(u2g_iter,
+ std::make_pair(unique_id, global_id));
+ } else if (u2g_iter->second != global_id) {
+ // Remember the old_global_id before we insert and invalidate out iter.
+ int64_t old_global_id = u2g_iter->second;
+
+ // TODO(skym): Use insert_or_assign with hint once on C++17.
+ unique_to_current_global_[unique_id] = global_id;
+
+ // This should be done after updating unique_to_current_global_ in case one
+ // of our observers calls into GetLatestGlobalId().
+ for (auto& observer : global_id_change_observers_) {
+ observer.Run(old_global_id, global_id);
+ }
+ }
+
+ CleanupNavigationTracking();
+}
+
+void SessionsSyncManager::CleanupNavigationTracking() {
+ DCHECK(kNavigationTrackingCleanupThreshold >
+ kNavigationTrackingCleanupAmount);
+
+ // |global_to_unique_| is implicitly ordered by least recently created, which
+ // means we can drop from the beginning.
+ if (global_to_unique_.size() > kNavigationTrackingCleanupThreshold) {
+ auto iter = global_to_unique_.begin();
+ std::advance(iter, kNavigationTrackingCleanupAmount);
+ global_to_unique_.erase(global_to_unique_.begin(), iter);
+
+ // While |unique_id|s do get bigger for the most part, this isn't a great
+ // thing to make assumptions about, and an old tab may get refreshed often
+ // and still be very important. So instead just delete anything that's
+ // orphaned from |global_to_unique_|.
+ base::EraseIf(unique_to_current_global_,
+ [this](const std::pair<int, int64_t> kv) {
+ return !base::ContainsKey(global_to_unique_, kv.second);
+ });
+ }
+}
+
}; // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.h b/chromium/components/sync_sessions/sessions_sync_manager.h
index 975b673cdc6..8776a8964ae 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.h
+++ b/chromium/components/sync_sessions/sessions_sync_manager.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SYNC_SESSIONS_SESSIONS_SYNC_MANAGER_H_
#include <stddef.h>
+#include <stdint.h>
#include <map>
#include <memory>
@@ -23,6 +24,7 @@
#include "components/sync/base/sync_prefs.h"
#include "components/sync/device_info/device_info.h"
#include "components/sync/model/syncable_service.h"
+#include "components/sync/user_events/global_id_mapper.h"
#include "components/sync_sessions/favicon_cache.h"
#include "components/sync_sessions/local_session_event_router.h"
#include "components/sync_sessions/lost_navigations_recorder.h"
@@ -58,7 +60,8 @@ class SyncedWindowDelegatesGetter;
// the sync sessions model.
class SessionsSyncManager : public syncer::SyncableService,
public OpenTabsUIDelegate,
- public LocalSessionEventHandler {
+ public LocalSessionEventHandler,
+ public syncer::GlobalIdMapper {
public:
SessionsSyncManager(SyncSessionsClient* sessions_client,
syncer::SyncPrefs* sync_prefs,
@@ -117,6 +120,10 @@ class SessionsSyncManager : public syncer::SyncableService,
// sessions data downloaded (sync cycles complete).
void DoGarbageCollection();
+ // GlobalIdMapper implementation.
+ void AddGlobalIdChangeObserver(syncer::GlobalIdChange callback) override;
+ int64_t GetLatestGlobalId(int64_t global_id) override;
+
private:
friend class extensions::ExtensionSessionsTest;
friend class SessionsSyncManagerTest;
@@ -281,6 +288,10 @@ class SessionsSyncManager : public syncer::SyncableService,
SyncedWindowDelegatesGetter* synced_window_delegates_getter() const;
+ void TrackNavigationIds(const sessions::SerializedNavigationEntry& current);
+
+ void CleanupNavigationTracking();
+
// The client of this sync sessions datatype.
SyncSessionsClient* const sessions_client_;
@@ -337,6 +348,12 @@ class SessionsSyncManager : public syncer::SyncableService,
// changes of current session.
std::unique_ptr<TaskTracker> task_tracker_;
+ // Used to track global_ids that should be used when referencing various
+ // pieces of sessions data, and notify observer when things have changed.
+ std::map<int64_t, int> global_to_unique_;
+ std::map<int, int64_t> unique_to_current_global_;
+ std::vector<syncer::GlobalIdChange> global_id_change_observers_;
+
DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager);
};
diff --git a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
index d61838d3102..eddad61d6cf 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -8,7 +8,6 @@
#include <utility>
-#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
@@ -230,7 +229,7 @@ class TestSyncedTabDelegate : public SyncedTabDelegate {
navs) {
for (auto& entry : navs) {
blocked_navigations_.push_back(
- base::MakeUnique<sessions::SerializedNavigationEntry>(*entry));
+ std::make_unique<sessions::SerializedNavigationEntry>(*entry));
}
}
@@ -516,16 +515,16 @@ class SessionsSyncManagerTest : public testing::Test {
SessionsSyncManagerTest() {}
void SetUp() override {
- local_device_ = base::MakeUnique<LocalDeviceInfoProviderMock>(
+ local_device_ = std::make_unique<LocalDeviceInfoProviderMock>(
"cache_guid", "Wayne Gretzky's Hacking Box", "Chromium 10k",
"Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id");
- sync_client_ = base::MakeUnique<syncer::FakeSyncClient>();
+ sync_client_ = std::make_unique<syncer::FakeSyncClient>();
sessions_client_shim_ =
- base::MakeUnique<SyncSessionsClientShim>(&window_getter_);
+ std::make_unique<SyncSessionsClientShim>(&window_getter_);
sync_prefs_ =
- base::MakeUnique<syncer::SyncPrefs>(sync_client_->GetPrefService());
- router_ = base::MakeUnique<DummyRouter>();
- manager_ = base::MakeUnique<SessionsSyncManager>(
+ std::make_unique<syncer::SyncPrefs>(sync_client_->GetPrefService());
+ router_ = std::make_unique<DummyRouter>();
+ manager_ = std::make_unique<SessionsSyncManager>(
sessions_client_shim(), sync_prefs_.get(), local_device_.get(),
router_.get(),
base::Bind(&SessionNotificationObserver::NotifyOfUpdate,
@@ -689,7 +688,7 @@ class SessionsSyncManagerTest : public testing::Test {
TestSyncedTabDelegate* AddTab(SessionID::id_type window_id,
const std::string& url,
base::Time time) {
- tabs_.push_back(base::MakeUnique<TestSyncedTabDelegate>());
+ tabs_.push_back(std::make_unique<TestSyncedTabDelegate>());
for (auto& window : windows_) {
if (window->GetSessionId() == window_id) {
int tab_index = window->GetTabCount();
@@ -721,7 +720,7 @@ class SessionsSyncManagerTest : public testing::Test {
tab_navigation.set_unique_id(time.ToInternalValue());
tab_navigation.set_http_status_code(200);
- auto entry = base::MakeUnique<sessions::SerializedNavigationEntry>(
+ auto entry = std::make_unique<sessions::SerializedNavigationEntry>(
sessions::SerializedNavigationEntry::FromSyncData(0, tab_navigation));
SerializedNavigationEntryTestHelper::SetTimestamp(time, entry.get());
SerializedNavigationEntryTestHelper::SetTransitionType(transition,
@@ -745,13 +744,27 @@ class SessionsSyncManagerTest : public testing::Test {
NavigateTab(delegate, url, base::Time::Now(), transition);
}
+ void ReloadTab(TestSyncedTabDelegate* delegate, base::Time time) {
+ sessions::SerializedNavigationEntry old_entry;
+ delegate->GetSerializedNavigationAtIndex(delegate->GetCurrentEntryIndex(),
+ &old_entry);
+
+ auto new_entry =
+ std::make_unique<sessions::SerializedNavigationEntry>(old_entry);
+ SerializedNavigationEntryTestHelper::SetTimestamp(time, new_entry.get());
+
+ delegate->reset();
+ delegate->AppendEntry(std::move(new_entry));
+ router_->NotifyNav(delegate);
+ }
+
void ResetWindows() {
window_getter_.ClearSyncedWindowDelegates();
windows_.clear();
}
TestSyncedWindowDelegate* AddWindow() {
- windows_.push_back(base::MakeUnique<TestSyncedWindowDelegate>());
+ windows_.push_back(std::make_unique<TestSyncedWindowDelegate>());
window_getter_.AddSyncedWindowDelegate(windows_.back().get());
return windows_.back().get();
}
@@ -893,12 +906,12 @@ TEST_F(SessionsSyncManagerTest, BlockedNavigations) {
TestSyncedTabDelegate* tab =
AddTab(AddWindow()->GetSessionId(), kFoo1, kTime1);
- auto entry2 = base::MakeUnique<sessions::SerializedNavigationEntry>();
+ auto entry2 = std::make_unique<sessions::SerializedNavigationEntry>();
GURL url2("http://blocked.com/foo");
SerializedNavigationEntryTestHelper::SetVirtualURL(GURL(url2), entry2.get());
SerializedNavigationEntryTestHelper::SetTimestamp(kTime2, entry2.get());
- auto entry3 = base::MakeUnique<sessions::SerializedNavigationEntry>();
+ auto entry3 = std::make_unique<sessions::SerializedNavigationEntry>();
GURL url3("http://evil.com");
SerializedNavigationEntryTestHelper::SetVirtualURL(GURL(url3), entry3.get());
SerializedNavigationEntryTestHelper::SetTimestamp(kTime3, entry3.get());
@@ -1040,7 +1053,7 @@ TEST_F(SessionsSyncManagerTest, PreserveTabbedDataCustomTab) {
SessionID new_window_id;
window->OverrideWindowId(new_window_id.id());
std::unique_ptr<TestSyncedTabDelegate> custom_tab =
- base::MakeUnique<TestSyncedTabDelegate>();
+ std::make_unique<TestSyncedTabDelegate>();
NavigateTab(custom_tab.get(), kBar1);
window->OverrideTabAt(0, custom_tab.get());
InitWithSyncDataTakeOutput(ConvertToRemote(in), &out);
@@ -2621,4 +2634,80 @@ TEST_F(SessionsSyncManagerTest, TrackTasksOnLocalTabModified) {
EXPECT_EQ(tab.navigation(1).ancestor_task_id(0), tab.navigation(0).task_id());
}
+void CaptureGlobalIdChange(int64_t* old_ptr,
+ int64_t* new_ptr,
+ int64_t old_id,
+ int64_t new_id) {
+ *old_ptr = old_id;
+ *new_ptr = new_id;
+}
+
+// Tests that subscribers to AddGlobalIdChangeObserver are notified when a
+// global_id is noticed to have been changed.
+TEST_F(SessionsSyncManagerTest, AddGlobalIdChangeObserver) {
+ TestSyncedWindowDelegate* window = AddWindow();
+ SessionID::id_type window_id = window->GetSessionId();
+ SyncChangeList out;
+ InitWithSyncDataTakeOutput(SyncDataList(), &out);
+
+ int64_t old_id = -1;
+ int64_t new_id = -1;
+ manager()->AddGlobalIdChangeObserver(
+ base::Bind(&CaptureGlobalIdChange, &old_id, &new_id));
+
+ TestSyncedTabDelegate* tab = AddTab(window_id, kFoo1, kTime1);
+ EXPECT_EQ(-1, old_id);
+ EXPECT_EQ(-1, new_id);
+
+ ReloadTab(tab, kTime2);
+ EXPECT_EQ(kTime1.ToInternalValue(), old_id);
+ EXPECT_EQ(kTime2.ToInternalValue(), new_id);
+}
+
+// Tests that GetLatestGlobalId returns correct mappings for updated global_ids.
+TEST_F(SessionsSyncManagerTest, GetLatestGlobalId) {
+ TestSyncedWindowDelegate* window = AddWindow();
+ SessionID::id_type window_id = window->GetSessionId();
+ SyncChangeList out;
+ InitWithSyncDataTakeOutput(SyncDataList(), &out);
+
+ TestSyncedTabDelegate* tab = AddTab(window_id, kFoo1, kTime1);
+ ReloadTab(tab, kTime2);
+ ReloadTab(tab, kTime3);
+
+ EXPECT_EQ(kTime3.ToInternalValue(),
+ manager()->GetLatestGlobalId(kTime1.ToInternalValue()));
+ EXPECT_EQ(kTime3.ToInternalValue(),
+ manager()->GetLatestGlobalId(kTime2.ToInternalValue()));
+ EXPECT_EQ(kTime3.ToInternalValue(),
+ manager()->GetLatestGlobalId(kTime3.ToInternalValue()));
+ // kTime4 is not mapped, so itself should be returned.
+ EXPECT_EQ(kTime4.ToInternalValue(),
+ manager()->GetLatestGlobalId(kTime4.ToInternalValue()));
+}
+
+// Tests that the global_id mapping is eventually dropped after we reach out
+// threshold for the amount to remember.
+TEST_F(SessionsSyncManagerTest, GlobalIdMapperCleanup) {
+ TestSyncedWindowDelegate* window = AddWindow();
+ SessionID::id_type window_id = window->GetSessionId();
+ SyncChangeList out;
+ InitWithSyncDataTakeOutput(SyncDataList(), &out);
+
+ base::Time current_time = kTime1;
+ TestSyncedTabDelegate* tab = AddTab(window_id, kFoo1, current_time);
+
+ for (int i = 0; i < 105; i++) {
+ current_time =
+ base::Time::FromInternalValue(current_time.ToInternalValue() + 1);
+ ReloadTab(tab, current_time);
+ }
+
+ // Threshold is 100, kTime1 should be dropped, kTime1+10 should not.
+ EXPECT_EQ(kTime1.ToInternalValue(),
+ manager()->GetLatestGlobalId(kTime1.ToInternalValue()));
+ EXPECT_EQ(current_time.ToInternalValue(),
+ manager()->GetLatestGlobalId(10 + kTime1.ToInternalValue()));
+}
+
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
index 987e0a52c79..4e06278a4b0 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
+++ b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include <memory>
-#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
#include "components/sessions/core/session_types.h"
@@ -65,12 +64,12 @@ class SyncSessionsMetricsTest : public ::testing::Test {
void PushTab(size_t tabIndex, int windowIndex, Time timestamp) {
// First add sessions/windows as necessary.
while (tabIndex >= sessions_.size()) {
- sessions_.push_back(base::MakeUnique<SyncedSession>());
+ sessions_.push_back(std::make_unique<SyncedSession>());
}
if (sessions_[tabIndex]->windows.find(windowIndex) ==
sessions_[tabIndex]->windows.end()) {
sessions_[tabIndex]->windows[windowIndex] =
- base::MakeUnique<SyncedSessionWindow>();
+ std::make_unique<SyncedSessionWindow>();
}
sessions_[tabIndex]->modified_time =
@@ -80,7 +79,7 @@ class SyncSessionsMetricsTest : public ::testing::Test {
sessions_[tabIndex]->windows[windowIndex]->wrapped_window.timestamp,
timestamp);
sessions_[tabIndex]->windows[windowIndex]->wrapped_window.tabs.push_back(
- base::MakeUnique<SessionTab>());
+ std::make_unique<SessionTab>());
sessions_[tabIndex]
->windows[windowIndex]
->wrapped_window.tabs.back()
diff --git a/chromium/components/sync_sessions/synced_session_tracker.cc b/chromium/components/sync_sessions/synced_session_tracker.cc
index 08c0933070f..4b2975ab234 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/sync_sessions/synced_tab_delegate.h"
@@ -142,7 +141,7 @@ SyncedSession* SyncedSessionTracker::GetSession(
return synced_session_map_[session_tag].get();
std::unique_ptr<SyncedSession> synced_session =
- base::MakeUnique<SyncedSession>();
+ std::make_unique<SyncedSession>();
DVLOG(1) << "Creating new session with tag " << session_tag << " at "
<< synced_session.get();
synced_session->session_tag = session_tag;
@@ -239,7 +238,7 @@ void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag,
: session_tag);
} else {
// Create the window.
- window = base::MakeUnique<SyncedSessionWindow>();
+ window = std::make_unique<SyncedSessionWindow>();
window->wrapped_window.window_id.set_id(window_id);
synced_window_map_[session_tag][window_id] = window.get();
DVLOG(1) << "Putting new window " << window_id << " at " << window.get()
@@ -336,7 +335,7 @@ sessions::SessionTab* SyncedSessionTracker::GetTab(
}
} else {
std::unique_ptr<sessions::SessionTab> tab =
- base::MakeUnique<sessions::SessionTab>();
+ std::make_unique<sessions::SessionTab>();
tab_ptr = tab.get();
tab->tab_id.set_id(tab_id);
synced_tab_map_[session_tag][tab_id] = tab_ptr;
diff --git a/chromium/components/sync_sessions/task_tracker.cc b/chromium/components/sync_sessions/task_tracker.cc
index d8351cbb7b0..c04bd0a1dfb 100644
--- a/chromium/components/sync_sessions/task_tracker.cc
+++ b/chromium/components/sync_sessions/task_tracker.cc
@@ -131,10 +131,10 @@ TabTasks* TaskTracker::GetTabTasks(SessionID::id_type tab_id,
// larger task encompassing the parent tab. Perform a deep copy of the
// parent's TabTasks object in order to simplify tracking this relationship.
local_tab_tasks_map_[tab_id] =
- base::MakeUnique<TabTasks>(*local_tab_tasks_map_[parent_tab_id]);
+ std::make_unique<TabTasks>(*local_tab_tasks_map_[parent_tab_id]);
local_tab_tasks_map_[tab_id]->set_parent_tab_id(parent_tab_id);
} else {
- local_tab_tasks_map_[tab_id] = base::MakeUnique<TabTasks>();
+ local_tab_tasks_map_[tab_id] = std::make_unique<TabTasks>();
}
return local_tab_tasks_map_[tab_id].get();
}
diff --git a/chromium/components/task_scheduler_util/common/variations_util.cc b/chromium/components/task_scheduler_util/common/variations_util.cc
index 04ef1dfa1bf..d83362b514d 100644
--- a/chromium/components/task_scheduler_util/common/variations_util.cc
+++ b/chromium/components/task_scheduler_util/common/variations_util.cc
@@ -41,7 +41,6 @@ bool ContainsSeparator(const std::string& str) {
// 2. Thread Count Multiplier (double)
// 3. Thread Count Offset (int)
// 4. Detach Time in Milliseconds (int)
-// 5. Standby Thread Policy (string)
// Additional values may appear as necessary and will be ignored.
std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
base::StringPiece variation_param_prefix,
@@ -49,8 +48,6 @@ std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
const std::map<std::string, std::string>& variation_params,
base::SchedulerBackwardCompatibility backward_compatibility =
base::SchedulerBackwardCompatibility::DISABLED) {
- using StandbyThreadPolicy =
- base::SchedulerWorkerPoolParams::StandbyThreadPolicy;
auto pool_descriptor_it = variation_params.find(
base::JoinString({variation_param_prefix, pool_name}, ""));
@@ -80,8 +77,6 @@ std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
}
auto params = base::MakeUnique<base::SchedulerWorkerPoolParams>(
- (tokens.size() >= 6 && tokens[5] == "lazy") ? StandbyThreadPolicy::LAZY
- : StandbyThreadPolicy::ONE,
base::RecommendedMaxNumberOfThreadsInPool(min, max, cores_multiplier,
offset),
base::TimeDelta::FromMilliseconds(detach_milliseconds),
diff --git a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc b/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
index d5612f7a011..453c62e0d61 100644
--- a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
+++ b/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
@@ -21,8 +21,6 @@ namespace task_scheduler_util {
namespace {
-using StandbyThreadPolicy =
- base::SchedulerWorkerPoolParams::StandbyThreadPolicy;
using SchedulerBackwardCompatibility = base::SchedulerBackwardCompatibility;
#if !defined(OS_IOS)
@@ -62,8 +60,6 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) {
base::SchedulerBackwardCompatibility::INIT_COM_STA);
ASSERT_TRUE(init_params);
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->background_worker_pool_params.standby_thread_policy());
EXPECT_EQ(1, init_params->background_worker_pool_params.max_threads());
EXPECT_EQ(
base::TimeDelta::FromMilliseconds(42),
@@ -72,9 +68,6 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) {
base::SchedulerBackwardCompatibility::DISABLED,
init_params->background_worker_pool_params.backward_compatibility());
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->background_blocking_worker_pool_params
- .standby_thread_policy());
EXPECT_EQ(2,
init_params->background_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(52),
@@ -84,8 +77,6 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) {
init_params->background_blocking_worker_pool_params
.backward_compatibility());
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->foreground_worker_pool_params.standby_thread_policy());
EXPECT_EQ(4, init_params->foreground_worker_pool_params.max_threads());
EXPECT_EQ(
base::TimeDelta::FromMilliseconds(62),
@@ -94,66 +85,6 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) {
base::SchedulerBackwardCompatibility::DISABLED,
init_params->foreground_worker_pool_params.backward_compatibility());
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->foreground_blocking_worker_pool_params
- .standby_thread_policy());
- EXPECT_EQ(8,
- init_params->foreground_blocking_worker_pool_params.max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(72),
- init_params->foreground_blocking_worker_pool_params
- .suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::INIT_COM_STA,
- init_params->foreground_blocking_worker_pool_params
- .backward_compatibility());
-}
-
-TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams6) {
- std::map<std::string, std::string> variation_params;
- variation_params["RendererBackground"] = "1;1;1;0;42;lazy";
- variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
- variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
- variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
-
- auto init_params = GetTaskSchedulerInitParams(
- "Renderer", variation_params,
- base::SchedulerBackwardCompatibility::INIT_COM_STA);
- ASSERT_TRUE(init_params);
-
- EXPECT_EQ(StandbyThreadPolicy::LAZY,
- init_params->background_worker_pool_params.standby_thread_policy());
- EXPECT_EQ(1, init_params->background_worker_pool_params.max_threads());
- EXPECT_EQ(
- base::TimeDelta::FromMilliseconds(42),
- init_params->background_worker_pool_params.suggested_reclaim_time());
- EXPECT_EQ(
- base::SchedulerBackwardCompatibility::DISABLED,
- init_params->background_worker_pool_params.backward_compatibility());
-
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->background_blocking_worker_pool_params
- .standby_thread_policy());
- EXPECT_EQ(2,
- init_params->background_blocking_worker_pool_params.max_threads());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(52),
- init_params->background_blocking_worker_pool_params
- .suggested_reclaim_time());
- EXPECT_EQ(base::SchedulerBackwardCompatibility::DISABLED,
- init_params->background_blocking_worker_pool_params
- .backward_compatibility());
-
- EXPECT_EQ(StandbyThreadPolicy::LAZY,
- init_params->foreground_worker_pool_params.standby_thread_policy());
- EXPECT_EQ(4, init_params->foreground_worker_pool_params.max_threads());
- EXPECT_EQ(
- base::TimeDelta::FromMilliseconds(62),
- init_params->foreground_worker_pool_params.suggested_reclaim_time());
- EXPECT_EQ(
- base::SchedulerBackwardCompatibility::DISABLED,
- init_params->foreground_worker_pool_params.backward_compatibility());
-
- EXPECT_EQ(StandbyThreadPolicy::ONE,
- init_params->foreground_blocking_worker_pool_params
- .standby_thread_policy());
EXPECT_EQ(8,
init_params->foreground_blocking_worker_pool_params.max_threads());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(72),
@@ -191,10 +122,10 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, ZeroMaxThreads) {
// The Background pool has a maximum number of threads equal to zero, which is
// invalid.
std::map<std::string, std::string> variation_params;
- variation_params["RendererBackground"] = "0;0;0;0;0;lazy";
- variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
- variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
- variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ variation_params["RendererBackground"] = "0;0;0;0;0";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52";
+ variation_params["RendererForeground"] = "4;4;1;0;62";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72";
EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
}
@@ -202,10 +133,10 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeMaxThreads) {
// The Background pool has a negative maximum number of threads, which is
// invalid.
std::map<std::string, std::string> variation_params;
- variation_params["RendererBackground"] = "-5;-5;0;0;0;lazy";
- variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
- variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
- variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ variation_params["RendererBackground"] = "-5;-5;0;0;0";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52";
+ variation_params["RendererForeground"] = "4;4;1;0;62";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72";
EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
}
@@ -213,10 +144,10 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeSuggestedReclaimTime) {
// The Background pool has a negative suggested reclaim time, which is
// invalid.
std::map<std::string, std::string> variation_params;
- variation_params["RendererBackground"] = "1;1;1;0;-5;lazy";
- variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52;one";
- variation_params["RendererForeground"] = "4;4;1;0;62;lazy";
- variation_params["RendererForegroundBlocking"] = "8;8;1;0;72;one";
+ variation_params["RendererBackground"] = "1;1;1;0;-5";
+ variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52";
+ variation_params["RendererForeground"] = "4;4;1;0;62";
+ variation_params["RendererForegroundBlocking"] = "8;8;1;0;72";
EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer", variation_params));
}
diff --git a/chromium/components/toolbar/toolbar_model_impl.cc b/chromium/components/toolbar/toolbar_model_impl.cc
index 6e275ef989d..8122ef33f52 100644
--- a/chromium/components/toolbar/toolbar_model_impl.cc
+++ b/chromium/components/toolbar/toolbar_model_impl.cc
@@ -45,7 +45,7 @@ base::string16 ToolbarModelImpl::GetFormattedURL(size_t* prefix_end) const {
const base::string16 formatted_text =
delegate_->FormattedStringWithEquivalentMeaning(
url, url_formatter::FormatUrl(
- url, url_formatter::kFormatUrlOmitAll,
+ url, url_formatter::kFormatUrlOmitDefaults,
net::UnescapeRule::NORMAL, nullptr, prefix_end, nullptr));
if (formatted_text.length() <= max_url_display_chars_)
return formatted_text;
@@ -89,9 +89,6 @@ const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
case security_state::EV_SECURE:
case security_state::SECURE:
return toolbar::kHttpsValidIcon;
- case security_state::SECURITY_WARNING:
- // Surface Dubious as Neutral.
- return toolbar::kHttpIcon;
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
return vector_icons::kBusinessIcon;
case security_state::DANGEROUS:
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index 7ec5f96f96c..13c96a068bc 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -11,8 +11,6 @@ component("tracing") {
"child/child_trace_message_filter.h",
"common/graphics_memory_dump_provider_android.cc",
"common/graphics_memory_dump_provider_android.h",
- "common/process_metrics_memory_dump_provider.cc",
- "common/process_metrics_memory_dump_provider.h",
"common/tracing_messages.cc",
"common/tracing_messages.h",
"core/proto_utils.cc",
@@ -35,17 +33,11 @@ component("tracing") {
deps = [
"//base",
"//ipc",
- "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
]
public_deps = [
"//components/tracing/proto:protos",
]
-
- if (is_nacl) {
- sources -= [ "common/process_metrics_memory_dump_provider.cc" ]
- deps -= [ "//services/resource_coordinator/public/cpp:resource_coordinator_cpp" ]
- }
}
component("startup_tracing") {
diff --git a/chromium/components/tracing/child/child_trace_message_filter.cc b/chromium/components/tracing/child/child_trace_message_filter.cc
index ce9c86f75f6..9afddad1fb5 100644
--- a/chromium/components/tracing/child/child_trace_message_filter.cc
+++ b/chromium/components/tracing/child/child_trace_message_filter.cc
@@ -10,7 +10,6 @@
#include "base/metrics/statistics_recorder.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
-#include "components/tracing/common/process_metrics_memory_dump_provider.h"
#include "components/tracing/common/tracing_messages.h"
#include "ipc/ipc_channel.h"
@@ -34,13 +33,6 @@ ChildTraceMessageFilter::ChildTraceMessageFilter(
void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
sender_ = channel;
sender_->Send(new TracingHostMsg_ChildSupportsTracing());
-
-#if !defined(OS_LINUX) && !defined(OS_NACL)
- // On linux the browser process takes care of dumping process metrics.
- // The child process is not allowed to do so due to BPF sandbox.
- tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
- base::kNullProcessId);
-#endif
}
void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) {
diff --git a/chromium/components/tracing/common/DEPS b/chromium/components/tracing/common/DEPS
deleted file mode 100644
index 75450912357..00000000000
--- a/chromium/components/tracing/common/DEPS
+++ /dev/null
@@ -1,7 +0,0 @@
-specific_include_rules = {
- # TODO(hjd): crbug.com/728199 Remove once service knows which
- # processes to collect OS dumps.
- 'process_metrics_memory_dump_provider\.cc': [
- "+services/resource_coordinator/public/cpp/memory_instrumentation",
- ],
-}
diff --git a/chromium/components/tracing/common/graphics_memory_dump_provider_android.cc b/chromium/components/tracing/common/graphics_memory_dump_provider_android.cc
index 3c47bc2d57d..520f72b634d 100644
--- a/chromium/components/tracing/common/graphics_memory_dump_provider_android.cc
+++ b/chromium/components/tracing/common/graphics_memory_dump_provider_android.cc
@@ -19,7 +19,6 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/process_memory_totals.h"
using base::trace_event::MemoryAllocatorDump;
diff --git a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc b/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
deleted file mode 100644
index 023fb5dc8ac..00000000000
--- a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
+++ /dev/null
@@ -1,29 +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/tracing/common/process_metrics_memory_dump_provider.h"
-
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider.h"
-
-namespace tracing {
-
-// TODO(hjd): crbug.com/728199 Remove once service knows which
-// processes to collect OS dumps from.
-// static
-void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
- base::ProcessId process) {
- memory_instrumentation::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
- process);
-}
-
-// TODO(hjd): crbug.com/728199 Remove once service knows which
-// processes to collect OS dumps from.
-// static
-void ProcessMetricsMemoryDumpProvider::UnregisterForProcess(
- base::ProcessId process) {
- memory_instrumentation::ProcessMetricsMemoryDumpProvider::
- UnregisterForProcess(process);
-}
-
-} // namespace tracing
diff --git a/chromium/components/tracing/common/process_metrics_memory_dump_provider.h b/chromium/components/tracing/common/process_metrics_memory_dump_provider.h
deleted file mode 100644
index eb89e6297b3..00000000000
--- a/chromium/components/tracing/common/process_metrics_memory_dump_provider.h
+++ /dev/null
@@ -1,33 +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.
-
-#ifndef COMPONENTS_TRACING_COMMON_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_
-#define COMPONENTS_TRACING_COMMON_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_
-
-#include "base/process/process_handle.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "components/tracing/tracing_export.h"
-
-// TODO(hjd): The actual impl lives in service/resource_coordinator. Update the
-// callsites and remove this file.
-namespace tracing {
-
-// Dump provider which collects process-wide memory stats.
-class TRACING_EXPORT ProcessMetricsMemoryDumpProvider
- : public base::trace_event::MemoryDumpProvider {
- public:
- // Pass base::kNullProcessId to register for current process.
- static void RegisterForProcess(base::ProcessId process);
- static void UnregisterForProcess(base::ProcessId process);
-
-
- private:
- ProcessMetricsMemoryDumpProvider();
- ~ProcessMetricsMemoryDumpProvider() override;
- DISALLOW_COPY_AND_ASSIGN(ProcessMetricsMemoryDumpProvider);
-};
-
-} // namespace tracing
-
-#endif // COMPONENTS_TRACING_COMMON_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_
diff --git a/chromium/components/translate/ios/browser/BUILD.gn b/chromium/components/translate/ios/browser/BUILD.gn
index ea58e5374cb..36e00c33a2b 100644
--- a/chromium/components/translate/ios/browser/BUILD.gn
+++ b/chromium/components/translate/ios/browser/BUILD.gn
@@ -61,6 +61,7 @@ source_set("unit_tests") {
"//components/translate/core/browser",
"//ios/web/public/test",
"//ios/web/public/test/fakes",
+ "//net:net",
"//testing/gtest",
"//third_party/ocmock",
"//ui/base",
diff --git a/chromium/components/ui_devtools/BUILD.gn b/chromium/components/ui_devtools/BUILD.gn
index bb1d83b3bf2..d7d038ea084 100644
--- a/chromium/components/ui_devtools/BUILD.gn
+++ b/chromium/components/ui_devtools/BUILD.gn
@@ -11,6 +11,8 @@ _protocol_generated = [
"DOM.cpp",
"DOM.h",
"Forward.h",
+ "Overlay.cpp",
+ "Overlay.h",
"Protocol.cpp",
"Protocol.h",
]
diff --git a/chromium/components/ui_devtools/devtools_server.h b/chromium/components/ui_devtools/devtools_server.h
index f5bce624581..ae8d608b0ef 100644
--- a/chromium/components/ui_devtools/devtools_server.h
+++ b/chromium/components/ui_devtools/devtools_server.h
@@ -20,8 +20,7 @@
namespace ui_devtools {
-class UI_DEVTOOLS_EXPORT UiDevToolsServer
- : public NON_EXPORTED_BASE(net::HttpServer::Delegate) {
+class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
public:
~UiDevToolsServer() override;
diff --git a/chromium/components/ui_devtools/protocol.json b/chromium/components/ui_devtools/protocol.json
index e69dd13c3cc..db337d1bd42 100644
--- a/chromium/components/ui_devtools/protocol.json
+++ b/chromium/components/ui_devtools/protocol.json
@@ -23,29 +23,52 @@
},
{
"name": "highlightNode",
- "parameters": [
- {
- "name": "highlightConfig",
- "$ref": "HighlightConfig",
- "description": "A descriptor for the highlight appearance."
- },
- {
- "description": "Identifier of the node to highlight.",
- "optional": true,
- "name": "nodeId",
- "$ref": "NodeId"
- }
- ],
- "description": "Highlights DOM node with given id or with the given JavaScript object wrapper. Either nodeId or objectId must be specified."
+ "description": "Highlights DOM node.",
+ "redirect": "Overlay"
},
{
"name": "hideHighlight",
"description": "Hides DOM node highlight."
+ },
+ {
+ "name": "pushNodesByBackendIdsToFrontend",
+ "parameters": [
+ {
+ "name": "backendNodeIds",
+ "type": "array",
+ "items": {
+ "$ref": "BackendNodeId"
+ },
+ "description": "The array of backend node ids."
+ }
+ ],
+ "returns": [
+ {
+ "name": "nodeIds",
+ "type": "array",
+ "items": {
+ "$ref": "NodeId"
+ },
+ "description": "The array of ids of pushed nodes that correspond to the backend ids specified in backendNodeIds."
+ }
+ ],
+ "description": "Requests that a batch of nodes is sent to the caller given their backend node ids.",
+ "experimental": true
}
-
],
"events": [
{
+ "name": "nodeHighlightRequested",
+ "parameters": [
+ {
+ "name": "nodeId",
+ "$ref": "NodeId",
+ "description": "Identifier of the node to highlight in DOM tree."
+ }
+ ],
+ "description": "In DOM tree, highlights DOM node with given id."
+ },
+ {
"name": "childNodeInserted",
"parameters": [
{
@@ -54,7 +77,6 @@
"$ref": "NodeId"
},
{
-
"description": "Id of the previous sibling (0 if this is at the beginning of the list).",
"name": "previousNodeId",
"$ref": "NodeId"
@@ -92,6 +114,11 @@
"type": "integer"
},
{
+ "id": "BackendNodeId",
+ "type": "integer",
+ "description": "Unique DOM node identifier used to reference a node that may not have been pushed to the front-end."
+ },
+ {
"description": "DOM interaction is implemented in terms of mirror objects that represent the actual DOM nodes. DOMNode is a base node mirror type.",
"id": "Node",
"properties": [
@@ -101,6 +128,11 @@
"name": "nodeId"
},
{
+ "name": "backendNodeId",
+ "$ref": "BackendNodeId",
+ "description": "The BackendNodeId for this node."
+ },
+ {
"description": "<code>Node</code>'s nodeType.",
"name": "nodeType",
"type": "integer"
@@ -153,49 +185,113 @@
"id": "RGBA",
"type": "object",
"properties": [
- {
+ {
"name": "r",
"type": "integer",
"description": "The red component, in the [0-255] range."
},
- {
- "name": "g",
- "type": "integer",
- "description": "The green component, in the [0-255] range."
+ {
+ "name": "g",
+ "type": "integer",
+ "description": "The green component, in the [0-255] range."
},
{
- "name": "b",
- "type": "integer",
- "description": "The blue component, in the [0-255] range."
+ "name": "b",
+ "type": "integer",
+ "description": "The blue component, in the [0-255] range."
},
- {
- "name": "a",
- "type": "number",
- "optional": true,
- "description": "The alpha component, in the [0-1] range (default: 1)."
+ {
+ "name": "a",
+ "type": "number",
+ "optional": true,
+ "description": "The alpha component, in the [0-1] range (default: 1)."
}
],
"description": "A structure holding an RGBA color."
},
{
+ "id": "Mode",
+ "type": "string",
+ "description": "Enable or Disable the highlighting inspector."
+ },
+ {
"id": "HighlightConfig",
"type": "object",
"properties": [
- {
- "name": "contentColor",
- "$ref": "RGBA",
- "optional": true,
- "description": "The content box highlight fill color (default: transparent)."
- },
- {
- "name": "borderColor",
- "$ref": "RGBA",
- "optional": true,
- "description": "The border highlight fill color (default: transparent)."
+ {
+ "name": "showInfo",
+ "type": "boolean",
+ "optional": true,
+ "description": "Whether the node info tooltip should be shown (default: false)."
+ },
+ {
+ "name": "showRulers",
+ "type": "boolean",
+ "optional": true,
+ "description": "Whether the rulers should be shown (default: false)."
+ },
+ {
+ "name": "showExtensionLines",
+ "type": "boolean",
+ "optional": true,
+ "description": "Whether the extension lines from node to the rulers should be shown (default: false)."
+ },
+ {
+ "name": "displayAsMaterial",
+ "type": "boolean",
+ "optional": true
+ },
+ {
+ "name": "contentColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The content box highlight fill color (default: transparent)."
+ },
+ {
+ "name": "paddingColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The padding highlight fill color (default: transparent)."
+ },
+ {
+ "name": "borderColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The border highlight fill color (default: transparent)."
+ },
+ {
+ "name": "marginColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The margin highlight fill color (default: transparent)."
+ },
+ {
+ "name": "eventTargetColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The event target element highlight fill color (default: transparent)."
+ },
+ {
+ "name": "shapeColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The shape outside fill color (default: transparent)."
+ },
+ {
+ "name": "shapeMarginColor",
+ "$ref": "DOM.RGBA",
+ "optional": true,
+ "description": "The shape margin fill color (default: transparent)."
+ },
+ {
+ "name": "selectorList",
+ "type": "string",
+ "optional": true,
+ "description": "Selectors to highlight relevant nodes."
}
],
"description": "Configuration data for the highlighting of page elements."
- }
+ }
]
},
{
@@ -224,7 +320,6 @@
"name": "inlineStyle",
"optional": true
}
-
]
},
{
@@ -326,11 +421,11 @@
"name": "value",
"type": "string"
},
- {
- "name": "range",
- "$ref": "SourceRange",
- "optional": true,
- "description": "The entire property range in the enclosing style declaration (if available)."
+ {
+ "name": "range",
+ "$ref": "SourceRange",
+ "optional": true,
+ "description": "The entire property range in the enclosing style declaration (if available)."
}
],
"type": "object"
@@ -371,6 +466,174 @@
"type": "object"
}
]
+ },
+ {
+ "commands": [
+ {
+ "description": "Enables Overlay agent for the given page.",
+ "name": "enable"
+ },
+ {
+ "description": "Disables Overlay agent for the given page.",
+ "name": "disable"
+ },
+ {
+ "name": "highlightNode",
+ "description": "Highlights DOM node with given id.",
+ "parameters": [
+ {
+ "name": "highlightConfig",
+ "$ref": "HighlightConfig",
+ "description": "A descriptor for the highlight appearance."
+ },
+ {
+ "name": "nodeId",
+ "$ref": "DOM.NodeId",
+ "optional":true,
+ "description": "Identifier of the node to highlight."
+ }
+ ]
+ },
+ {
+ "name": "hideHighlight",
+ "description": "Hides DOM node highlight."
+ },
+ {
+ "name": "setInspectMode",
+ "parameters": [
+ {
+ "description": "Set an inspection mode.",
+ "name": "mode",
+ "$ref": "InspectMode"
+ },
+ {
+ "description": "A descriptor for the highlight appearance of hovered-over nodes. May be omitted if <code>enabled == false</code>.",
+ "optional":true,
+ "name": "highlightConfig",
+ "$ref": "HighlightConfig"
+ }
+ ],
+ "description": "Enters the 'inspect' mode. In this mode, elements that user is hovering over are highlighted. Backend then generates 'inspectNodeRequested' event upon element selection."
+ }
+ ],
+ "description": "This domain provides various functionality related to drawing atop the inspected page.",
+ "domain": "Overlay",
+ "dependencies": [
+ "DOM"
+ ],
+ "experimental":true,
+ "events": [
+ {
+ "name": "nodeHighlightRequested",
+ "description": "Fired when the node should be highlighted. This happens after call to <code>setInspectMode</code>.",
+ "parameters": [
+ {
+ "name": "nodeId",
+ "$ref": "DOM.NodeId"
+ }
+ ]
+ },
+ {
+ "name": "inspectNodeRequested",
+ "description": "Fired when the node should be inspected. This happens after call to <code>setInspectMode</code> or when user manually inspects an element.",
+ "parameters": [
+ {
+ "name": "backendNodeId",
+ "$ref": "DOM.BackendNodeId",
+ "description": "Id of the node to inspect."
+ }
+ ]
+ }
+ ],
+ "types": [
+ {
+ "id": "HighlightConfig",
+ "type": "object",
+ "properties": [
+ {
+ "name": "showInfo",
+ "type": "boolean",
+ "optional":true,
+ "description": "Whether the node info tooltip should be shown (default: false)."
+ },
+ {
+ "name": "showRulers",
+ "type": "boolean",
+ "optional":true,
+ "description": "Whether the rulers should be shown (default: false)."
+ },
+ {
+ "name": "showExtensionLines",
+ "type": "boolean",
+ "optional":true,
+ "description": "Whether the extension lines from node to the rulers should be shown (default: false)."
+ },
+ {
+ "name": "displayAsMaterial",
+ "type": "boolean",
+ "optional":true
+ },
+ {
+ "name": "contentColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The content box highlight fill color (default: transparent)."
+ },
+ {
+ "name": "paddingColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The padding highlight fill color (default: transparent)."
+ },
+ {
+ "name": "borderColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The border highlight fill color (default: transparent)."
+ },
+ {
+ "name": "marginColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The margin highlight fill color (default: transparent)."
+ },
+ {
+ "name": "eventTargetColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The event target element highlight fill color (default: transparent)."
+ },
+ {
+ "name": "shapeColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The shape outside fill color (default: transparent)."
+ },
+ {
+ "name": "shapeMarginColor",
+ "$ref": "DOM.RGBA",
+ "optional":true,
+ "description": "The shape margin fill color (default: transparent)."
+ },
+ {
+ "name": "selectorList",
+ "type": "string",
+ "optional":true,
+ "description": "Selectors to highlight relevant nodes."
+ }
+ ],
+ "description": "Configuration data for the highlighting of page elements."
+ },
+ {
+ "id": "InspectMode",
+ "type": "string",
+ "enum": [
+ "searchForNode",
+ "searchForUAShadowDOM",
+ "none"
+ ]
+ }
+ ]
}
],
"version": {
diff --git a/chromium/components/ui_devtools/string_util.cc b/chromium/components/ui_devtools/string_util.cc
index ade4b6f3152..fde02a7b521 100644
--- a/chromium/components/ui_devtools/string_util.cc
+++ b/chromium/components/ui_devtools/string_util.cc
@@ -5,6 +5,7 @@
#include "components/ui_devtools/string_util.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/Protocol.h"
namespace ui_devtools {
@@ -18,5 +19,15 @@ std::unique_ptr<Value> StringUtil::parseJSON(const String& string) {
string.length());
};
+// static
+void StringUtil::builderAppendQuotedString(StringBuilder& builder,
+ const String& str) {
+ builder.append('"');
+ base::string16 str16 = base::UTF8ToUTF16(str);
+ escapeWideStringForJSON(reinterpret_cast<const uint16_t*>(&str16[0]),
+ str16.length(), &builder);
+ builder.append('"');
+}
+
} // namespace protocol
} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/string_util.h b/chromium/components/ui_devtools/string_util.h
index 8f12102f406..6efd379689d 100644
--- a/chromium/components/ui_devtools/string_util.h
+++ b/chromium/components/ui_devtools/string_util.h
@@ -56,6 +56,8 @@ class StringUtil {
static void builderAppend(StringBuilder& builder, const char* s, size_t len) {
builder.append(s, len);
}
+ static void builderAppendQuotedString(StringBuilder& builder,
+ const String& str);
static void builderReserve(StringBuilder& builder, unsigned capacity) {
builder.reserveCapacity(capacity);
}
diff --git a/chromium/components/ui_devtools/views/BUILD.gn b/chromium/components/ui_devtools/views/BUILD.gn
index 514fadfb170..6329d23f6fa 100644
--- a/chromium/components/ui_devtools/views/BUILD.gn
+++ b/chromium/components/ui_devtools/views/BUILD.gn
@@ -15,6 +15,8 @@ source_set("views") {
"ui_devtools_css_agent.h",
"ui_devtools_dom_agent.cc",
"ui_devtools_dom_agent.h",
+ "ui_devtools_overlay_agent.cc",
+ "ui_devtools_overlay_agent.h",
"ui_element.cc",
"ui_element.h",
"ui_element_delegate.h",
@@ -53,6 +55,7 @@ source_set("unit_tests") {
"//skia",
"//testing/gtest",
"//ui/aura",
+ "//ui/events:test_support",
"//ui/views",
"//ui/views:test_support",
"//ui/wm:wm",
diff --git a/chromium/components/ui_devtools/views/DEPS b/chromium/components/ui_devtools/views/DEPS
index 35272fdbaa4..f97255e94b1 100644
--- a/chromium/components/ui_devtools/views/DEPS
+++ b/chromium/components/ui_devtools/views/DEPS
@@ -1,4 +1,4 @@
include_rules = [
- "+third_party/skia/include/core",
+ "+third_party/skia/include",
"+ui"
]
diff --git a/chromium/components/ui_devtools/views/ui_devtools_css_agent.cc b/chromium/components/ui_devtools/views/ui_devtools_css_agent.cc
index 62a4be272e8..bfb9d88aa0f 100644
--- a/chromium/components/ui_devtools/views/ui_devtools_css_agent.cc
+++ b/chromium/components/ui_devtools/views/ui_devtools_css_agent.cc
@@ -7,7 +7,6 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/ui_devtools/views/ui_element.h"
-#include "ui/aura/window.h"
namespace ui_devtools {
namespace {
@@ -42,6 +41,15 @@ std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name,
.build();
}
+std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name,
+ const std::string& value) {
+ return CSS::CSSProperty::create()
+ .setRange(BuildDefaultSourceRange())
+ .setName(name)
+ .setValue(value)
+ .build();
+}
+
std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSPropertyArray(
const gfx::Rect& bounds,
const bool visible) {
@@ -54,13 +62,24 @@ std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSPropertyArray(
return cssProperties;
}
-std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(int node_id,
- const gfx::Rect& bounds,
- bool visible) {
+std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(UIElement* ui_element) {
+ gfx::Rect bounds;
+ bool visible;
+ ui_element->GetBounds(&bounds);
+ ui_element->GetVisible(&visible);
+
+ std::unique_ptr<Array<CSS::CSSProperty>> css_properties(
+ BuildCSSPropertyArray(bounds, visible));
+ const std::vector<std::pair<std::string, std::string>> attributes(
+ ui_element->GetCustomAttributes());
+
+ for (const auto& it : attributes)
+ css_properties->addItem(BuildCSSProperty(it.first, it.second));
+
return CSS::CSSStyle::create()
.setRange(BuildDefaultSourceRange())
- .setStyleSheetId(base::IntToString(node_id))
- .setCssProperties(BuildCSSPropertyArray(bounds, visible))
+ .setStyleSheetId(base::IntToString(ui_element->node_id()))
+ .setCssProperties(std::move(css_properties))
.setShorthandEntries(Array<std::string>::create())
.build();
}
@@ -122,7 +141,8 @@ ui_devtools::protocol::Response UIDevToolsCSSAgent::getMatchedStylesForNode(
int node_id,
ui_devtools::protocol::Maybe<ui_devtools::protocol::CSS::CSSStyle>*
inline_style) {
- *inline_style = GetStylesForNode(node_id);
+ UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id);
+ *inline_style = GetStylesForUIElement(ui_element);
if (!inline_style)
return NodeNotFoundError(node_id);
return ui_devtools::protocol::Response::OK();
@@ -144,9 +164,10 @@ ui_devtools::protocol::Response UIDevToolsCSSAgent::setStyleTexts(
if (!base::StringToInt(edit->getStyleSheetId(), &node_id))
return ui_devtools::protocol::Response::Error("Invalid node id");
+ UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id);
gfx::Rect updated_bounds;
bool visible = false;
- if (!GetPropertiesForNodeId(node_id, &updated_bounds, &visible))
+ if (!GetPropertiesForUIElement(ui_element, &updated_bounds, &visible))
return NodeNotFoundError(node_id);
ui_devtools::protocol::Response response(
@@ -154,37 +175,36 @@ ui_devtools::protocol::Response UIDevToolsCSSAgent::setStyleTexts(
if (!response.isSuccess())
return response;
- updated_styles->addItem(BuildCSSStyle(node_id, updated_bounds, visible));
+ updated_styles->addItem(BuildCSSStyle(ui_element));
- if (!SetPropertiesForNodeId(node_id, updated_bounds, visible))
+ if (!SetPropertiesForUIElement(ui_element, updated_bounds, visible))
return NodeNotFoundError(node_id);
}
*result = std::move(updated_styles);
return ui_devtools::protocol::Response::OK();
}
-void UIDevToolsCSSAgent::OnNodeBoundsChanged(int node_id) {
- InvalidateStyleSheet(node_id);
+void UIDevToolsCSSAgent::OnElementBoundsChanged(UIElement* ui_element) {
+ InvalidateStyleSheet(ui_element);
}
std::unique_ptr<ui_devtools::protocol::CSS::CSSStyle>
-UIDevToolsCSSAgent::GetStylesForNode(int node_id) {
+UIDevToolsCSSAgent::GetStylesForUIElement(UIElement* ui_element) {
gfx::Rect bounds;
bool visible = false;
- return GetPropertiesForNodeId(node_id, &bounds, &visible)
- ? BuildCSSStyle(node_id, bounds, visible)
+ return GetPropertiesForUIElement(ui_element, &bounds, &visible)
+ ? BuildCSSStyle(ui_element)
: nullptr;
}
-void UIDevToolsCSSAgent::InvalidateStyleSheet(int node_id) {
+void UIDevToolsCSSAgent::InvalidateStyleSheet(UIElement* ui_element) {
// The stylesheetId for each node is equivalent to its node_id (as a string).
- frontend()->styleSheetChanged(base::IntToString(node_id));
+ frontend()->styleSheetChanged(base::IntToString(ui_element->node_id()));
}
-bool UIDevToolsCSSAgent::GetPropertiesForNodeId(int node_id,
- gfx::Rect* bounds,
- bool* visible) {
- UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id);
+bool UIDevToolsCSSAgent::GetPropertiesForUIElement(UIElement* ui_element,
+ gfx::Rect* bounds,
+ bool* visible) {
if (ui_element) {
ui_element->GetBounds(bounds);
ui_element->GetVisible(visible);
@@ -193,10 +213,9 @@ bool UIDevToolsCSSAgent::GetPropertiesForNodeId(int node_id,
return false;
}
-bool UIDevToolsCSSAgent::SetPropertiesForNodeId(int node_id,
- const gfx::Rect& bounds,
- bool visible) {
- UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id);
+bool UIDevToolsCSSAgent::SetPropertiesForUIElement(UIElement* ui_element,
+ const gfx::Rect& bounds,
+ bool visible) {
if (ui_element) {
ui_element->SetBounds(bounds);
ui_element->SetVisible(visible);
diff --git a/chromium/components/ui_devtools/views/ui_devtools_css_agent.h b/chromium/components/ui_devtools/views/ui_devtools_css_agent.h
index ef88dccce1d..3084b7ea137 100644
--- a/chromium/components/ui_devtools/views/ui_devtools_css_agent.h
+++ b/chromium/components/ui_devtools/views/ui_devtools_css_agent.h
@@ -11,6 +11,8 @@
namespace ui_devtools {
+class UIElement;
+
class UIDevToolsCSSAgent : public ui_devtools::UiDevToolsBaseAgent<
ui_devtools::protocol::CSS::Metainfo>,
public UIDevToolsDOMAgentObserver {
@@ -33,17 +35,19 @@ class UIDevToolsCSSAgent : public ui_devtools::UiDevToolsBaseAgent<
result) override;
// UIDevToolsDOMAgentObserver:
- void OnNodeBoundsChanged(int node_id) override;
+ void OnElementBoundsChanged(UIElement* ui_element) override;
private:
- std::unique_ptr<ui_devtools::protocol::CSS::CSSStyle> GetStylesForNode(
- int node_id);
- void InvalidateStyleSheet(int node_id);
- bool GetPropertiesForNodeId(int node_id, gfx::Rect* bounds, bool* visible);
- bool SetPropertiesForNodeId(int node_id,
- const gfx::Rect& bounds,
- bool visible);
- UIDevToolsDOMAgent* dom_agent_;
+ std::unique_ptr<ui_devtools::protocol::CSS::CSSStyle> GetStylesForUIElement(
+ UIElement* ui_element);
+ void InvalidateStyleSheet(UIElement* ui_element);
+ bool GetPropertiesForUIElement(UIElement* ui_element,
+ gfx::Rect* bounds,
+ bool* visible);
+ bool SetPropertiesForUIElement(UIElement* ui_element,
+ const gfx::Rect& bounds,
+ bool visible);
+ UIDevToolsDOMAgent* const dom_agent_;
DISALLOW_COPY_AND_ASSIGN(UIDevToolsCSSAgent);
};
diff --git a/chromium/components/ui_devtools/views/ui_devtools_dom_agent.cc b/chromium/components/ui_devtools/views/ui_devtools_dom_agent.cc
index 1e7638b1b0c..57a87ee972f 100644
--- a/chromium/components/ui_devtools/views/ui_devtools_dom_agent.cc
+++ b/chromium/components/ui_devtools/views/ui_devtools_dom_agent.cc
@@ -5,18 +5,24 @@
#include "components/ui_devtools/views/ui_devtools_dom_agent.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/devtools_server.h"
+#include "components/ui_devtools/views/ui_devtools_overlay_agent.h"
#include "components/ui_devtools/views/ui_element.h"
#include "components/ui_devtools/views/view_element.h"
#include "components/ui_devtools/views/widget_element.h"
#include "components/ui_devtools/views/window_element.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/compositor/paint_recorder.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/render_text.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/view.h"
@@ -37,6 +43,7 @@ std::unique_ptr<DOM::Node> BuildNode(
constexpr int kDomElementNodeType = 1;
std::unique_ptr<DOM::Node> node = DOM::Node::create()
.setNodeId(node_ids)
+ .setBackendNodeId(node_ids)
.setNodeName(name)
.setNodeType(kDomElementNodeType)
.setAttributes(std::move(attributes))
@@ -80,20 +87,6 @@ std::unique_ptr<Array<std::string>> GetAttributes(UIElement* ui_element) {
return attributes;
}
-int MaskColor(int value) {
- return value & 0xff;
-}
-
-SkColor RGBAToSkColor(DOM::RGBA* rgba) {
- if (!rgba)
- return SkColorSetARGB(0, 0, 0, 0);
- // Default alpha value is 0 (not visible) and need to convert alpha decimal
- // percentage value to hex
- return SkColorSetARGB(MaskColor(static_cast<int>(rgba->getA(0) * 255)),
- MaskColor(rgba->getR()), MaskColor(rgba->getG()),
- MaskColor(rgba->getB()));
-}
-
views::Widget* GetWidgetFromWindow(aura::Window* window) {
return views::Widget::GetWidgetForNativeView(window);
}
@@ -103,21 +96,152 @@ std::unique_ptr<DOM::Node> BuildDomNodeFromUIElement(UIElement* root) {
for (auto* it : root->children())
children->addItem(BuildDomNodeFromUIElement(it));
- constexpr int kDomElementNodeType = 1;
- std::unique_ptr<DOM::Node> node = DOM::Node::create()
- .setNodeId(root->node_id())
- .setNodeName(root->GetTypeName())
- .setNodeType(kDomElementNodeType)
- .setAttributes(GetAttributes(root))
- .build();
- node->setChildNodeCount(static_cast<int>(children->length()));
- node->setChildren(std::move(children));
- return node;
+ return BuildNode(root->GetTypeName(), GetAttributes(root),
+ std::move(children), root->node_id());
+}
+
+// Draw width() x height() of a rectangle if not empty. Otherwise, draw either
+// width() or height() if any of them is not empty.
+void DrawSizeOfRectangle(const gfx::Rect& hovered_rect,
+ const RectSide drawing_side,
+ gfx::Canvas* canvas,
+ gfx::RenderText* render_text_) {
+ base::string16 utf16_text;
+ const std::string unit = "dp";
+
+ if (!hovered_rect.IsEmpty()) {
+ utf16_text = base::UTF8ToUTF16(hovered_rect.size().ToString() + unit);
+ } else if (hovered_rect.height()) {
+ // Draw only height() if height() is not empty.
+ utf16_text =
+ base::UTF8ToUTF16(std::to_string(hovered_rect.height()) + unit);
+ } else if (hovered_rect.width()) {
+ // Draw only width() if width() is not empty.
+ utf16_text = base::UTF8ToUTF16(std::to_string(hovered_rect.width()) + unit);
+ } else {
+ // If both width() and height() are empty, canvas won't draw size.
+ return;
+ }
+ render_text_->SetText(utf16_text);
+ render_text_->SetColor(SK_ColorRED);
+
+ const gfx::Size& text_size = render_text_->GetStringSize();
+ gfx::Rect text_rect;
+ if (drawing_side == RectSide::LEFT_SIDE) {
+ const gfx::Point text_left_side(
+ hovered_rect.x() + 1,
+ hovered_rect.height() / 2 - text_size.height() / 2 + hovered_rect.y());
+ text_rect = gfx::Rect(text_left_side,
+ gfx::Size(text_size.width(), text_size.height()));
+ } else if (drawing_side == RectSide::RIGHT_SIDE) {
+ const gfx::Point text_right_side(
+ hovered_rect.right() - 1 - text_size.width(),
+ hovered_rect.height() / 2 - text_size.height() / 2 + hovered_rect.y());
+ text_rect = gfx::Rect(text_right_side,
+ gfx::Size(text_size.width(), text_size.height()));
+ } else if (drawing_side == RectSide::TOP_SIDE) {
+ const gfx::Point text_top_side(
+ hovered_rect.x() + hovered_rect.width() / 2 - text_size.width() / 2,
+ hovered_rect.y() + 1);
+ text_rect = gfx::Rect(text_top_side,
+ gfx::Size(text_size.width(), text_size.height()));
+ } else if (drawing_side == RectSide::BOTTOM_SIDE) {
+ const gfx::Point text_top_side(
+ hovered_rect.x() + hovered_rect.width() / 2 - text_size.width() / 2,
+ hovered_rect.bottom() - 1 - text_size.height());
+ text_rect = gfx::Rect(text_top_side,
+ gfx::Size(text_size.width(), text_size.height()));
+ }
+ canvas->FillRect(text_rect, SK_ColorWHITE, SkBlendMode::kColor);
+ render_text_->SetDisplayRect(text_rect);
+ render_text_->Draw(canvas);
+}
+
+void DrawRectGuideLinesOnCanvas(const gfx::Rect& screen_bounds,
+ const gfx::RectF& rect_f,
+ cc::PaintFlags flags,
+ gfx::Canvas* canvas) {
+ // Top horizontal dotted line from left to right.
+ canvas->DrawLine(gfx::PointF(0.0f, rect_f.y()),
+ gfx::PointF(screen_bounds.right(), rect_f.y()), flags);
+
+ // Bottom horizontal dotted line from left to right.
+ canvas->DrawLine(gfx::PointF(0.0f, rect_f.bottom()),
+ gfx::PointF(screen_bounds.right(), rect_f.bottom()), flags);
+
+ // Left vertical dotted line from top to bottom.
+ canvas->DrawLine(gfx::PointF(rect_f.x(), 0.0f),
+ gfx::PointF(rect_f.x(), screen_bounds.bottom()), flags);
+
+ // Right vertical dotted line from top to bottom.
+ canvas->DrawLine(gfx::PointF(rect_f.right(), 0.0f),
+ gfx::PointF(rect_f.right(), screen_bounds.bottom()), flags);
+}
+
+void DrawTextWithAnyBounds(float x1,
+ float y1,
+ float x2,
+ float y2,
+ RectSide side,
+ gfx::Canvas* canvas,
+ gfx::RenderText* render_text) {
+ if (x2 > x1 || y2 > y1) {
+ DrawSizeOfRectangle(gfx::Rect(x1, y1, x2 - x1, y2 - y1), side, canvas,
+ render_text);
+ } else {
+ DrawSizeOfRectangle(gfx::Rect(x2, y2, x1 - x2, y1 - y2), side, canvas,
+ render_text);
+ }
+}
+
+void DrawR1ContainsR2(const gfx::RectF& pinned_rect_f,
+ const gfx::RectF& hovered_rect_f,
+ const cc::PaintFlags& flags,
+ gfx::Canvas* canvas,
+ gfx::RenderText* render_text) {
+ // Horizontal left distance line.
+ float x1 = pinned_rect_f.x();
+ float y1 = pinned_rect_f.y() + pinned_rect_f.height() / 2;
+ float x2 = hovered_rect_f.x();
+ float y2 = y1;
+ canvas->DrawLine(gfx::PointF(x1, y1), gfx::PointF(x2, y2), flags);
+ DrawTextWithAnyBounds(x1, y1, x2, y2, RectSide::BOTTOM_SIDE, canvas,
+ render_text);
+
+ // Horizontal right distance line.
+ x1 = hovered_rect_f.right();
+ y1 = pinned_rect_f.y() + pinned_rect_f.height() / 2;
+ x2 = pinned_rect_f.right();
+ y2 = y1;
+ canvas->DrawLine(gfx::PointF(x1, y1), gfx::PointF(x2, y2), flags);
+ DrawTextWithAnyBounds(x1, y1, x2, y2, RectSide::BOTTOM_SIDE, canvas,
+ render_text);
+
+ // Vertical top distance line.
+ x1 = pinned_rect_f.x() + pinned_rect_f.width() / 2;
+ y1 = pinned_rect_f.y();
+ x2 = x1;
+ y2 = hovered_rect_f.y();
+ canvas->DrawLine(gfx::PointF(x1, y1), gfx::PointF(x2, y2), flags);
+ DrawTextWithAnyBounds(x1, y1, x2, y2, RectSide::LEFT_SIDE, canvas,
+ render_text);
+
+ // Vertical bottom distance line.
+ x1 = pinned_rect_f.x() + pinned_rect_f.width() / 2;
+ y1 = hovered_rect_f.bottom();
+ x2 = x1;
+ y2 = pinned_rect_f.bottom();
+ canvas->DrawLine(gfx::PointF(x1, y1), gfx::PointF(x2, y2), flags);
+ DrawTextWithAnyBounds(x1, y1, x2, y2, RectSide::LEFT_SIDE, canvas,
+ render_text);
}
} // namespace
-UIDevToolsDOMAgent::UIDevToolsDOMAgent() : is_building_tree_(false) {
+UIDevToolsDOMAgent::UIDevToolsDOMAgent()
+ : is_building_tree_(false),
+ show_size_on_canvas_(false),
+ highlight_rect_config_(HighlightRectsConfiguration::NO_DRAW) {
aura::Env::GetInstance()->AddObserver(this);
}
@@ -137,19 +261,22 @@ ui_devtools::protocol::Response UIDevToolsDOMAgent::getDocument(
return ui_devtools::protocol::Response::OK();
}
-ui_devtools::protocol::Response UIDevToolsDOMAgent::highlightNode(
- std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
- highlight_config,
- ui_devtools::protocol::Maybe<int> node_id) {
- return HighlightNode(std::move(highlight_config), node_id.fromJust());
-}
-
ui_devtools::protocol::Response UIDevToolsDOMAgent::hideHighlight() {
if (layer_for_highlighting_ && layer_for_highlighting_->visible())
layer_for_highlighting_->SetVisible(false);
return ui_devtools::protocol::Response::OK();
}
+ui_devtools::protocol::Response
+UIDevToolsDOMAgent::pushNodesByBackendIdsToFrontend(
+ std::unique_ptr<protocol::Array<int>> backend_node_ids,
+ std::unique_ptr<protocol::Array<int>>* result) {
+ *result = protocol::Array<int>::create();
+ for (size_t index = 0; index < backend_node_ids->length(); ++index)
+ (*result)->addItem(backend_node_ids->get(index));
+ return ui_devtools::protocol::Response::OK();
+}
+
void UIDevToolsDOMAgent::OnUIElementAdded(UIElement* parent, UIElement* child) {
// When parent is null, only need to update |node_id_to_ui_element_|.
if (!parent) {
@@ -191,7 +318,7 @@ void UIDevToolsDOMAgent::OnUIElementRemoved(UIElement* ui_element) {
void UIDevToolsDOMAgent::OnUIElementBoundsChanged(UIElement* ui_element) {
for (auto& observer : observers_)
- observer.OnNodeBoundsChanged(ui_element->node_id());
+ observer.OnElementBoundsChanged(ui_element);
}
void UIDevToolsDOMAgent::AddObserver(UIDevToolsDOMAgentObserver* observer) {
@@ -206,13 +333,195 @@ UIElement* UIDevToolsDOMAgent::GetElementFromNodeId(int node_id) {
return node_id_to_ui_element_[node_id];
}
+ui_devtools::protocol::Response UIDevToolsDOMAgent::HighlightNode(
+ int node_id,
+ bool show_size) {
+ if (!layer_for_highlighting_) {
+ layer_for_highlighting_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED));
+ layer_for_highlighting_->set_name("HighlightingLayer");
+ layer_for_highlighting_->set_delegate(this);
+ layer_for_highlighting_->SetFillsBoundsOpaquely(false);
+ }
+ std::pair<aura::Window*, gfx::Rect> window_and_bounds =
+ node_id_to_ui_element_.count(node_id)
+ ? node_id_to_ui_element_[node_id]->GetNodeWindowAndBounds()
+ : std::make_pair<aura::Window*, gfx::Rect>(nullptr, gfx::Rect());
+
+ if (!window_and_bounds.first)
+ return ui_devtools::protocol::Response::Error("No node found with that id");
+
+ highlight_rect_config_ = HighlightRectsConfiguration::NO_DRAW;
+ show_size_on_canvas_ = show_size;
+ UpdateHighlight(window_and_bounds);
+
+ if (!layer_for_highlighting_->visible())
+ layer_for_highlighting_->SetVisible(true);
+
+ return ui_devtools::protocol::Response::OK();
+}
+
+int UIDevToolsDOMAgent::FindElementIdTargetedByPoint(
+ const gfx::Point& p,
+ aura::Window* root_window) const {
+ aura::Window* targeted_window = root_window->GetEventHandlerForPoint(p);
+ if (!targeted_window)
+ return 0;
+
+ views::Widget* targeted_widget =
+ views::Widget::GetWidgetForNativeWindow(targeted_window);
+ if (!targeted_widget) {
+ return window_element_root_->FindUIElementIdForBackendElement<aura::Window>(
+ targeted_window);
+ }
+
+ views::View* root_view = targeted_widget->GetRootView();
+ DCHECK(root_view);
+
+ gfx::Point point_in_targeted_window(p);
+ aura::Window::ConvertPointToTarget(root_window, targeted_window,
+ &point_in_targeted_window);
+ views::View* targeted_view =
+ root_view->GetEventHandlerForPoint(point_in_targeted_window);
+ DCHECK(targeted_view);
+ return window_element_root_->FindUIElementIdForBackendElement<views::View>(
+ targeted_view);
+}
+
+void UIDevToolsDOMAgent::ShowDistancesInHighlightOverlay(int pinned_id,
+ int element_id) {
+ const std::pair<aura::Window*, gfx::Rect> pair_r2(
+ node_id_to_ui_element_[element_id]->GetNodeWindowAndBounds());
+ const std::pair<aura::Window*, gfx::Rect> pair_r1(
+ node_id_to_ui_element_[pinned_id]->GetNodeWindowAndBounds());
+ gfx::Rect r2(pair_r2.second);
+ gfx::Rect r1(pair_r1.second);
+ pinned_rect_ = r1;
+
+ is_swap_ = false;
+ if (r1.x() > r2.x()) {
+ is_swap_ = true;
+ std::swap(r1, r2);
+ }
+ if (r1.Contains(r2)) {
+ highlight_rect_config_ = HighlightRectsConfiguration::R1_CONTAINS_R2;
+ } else if (r1.right() <= r2.x()) {
+ if ((r1.y() <= r2.y() && r2.y() <= r1.bottom()) ||
+ (r1.y() <= r2.bottom() && r2.bottom() <= r1.bottom()) ||
+ (r2.y() <= r1.y() && r1.y() <= r2.bottom()) ||
+ (r2.y() <= r1.bottom() && r1.bottom() <= r2.bottom())) {
+ highlight_rect_config_ =
+ HighlightRectsConfiguration::R1_HORIZONTAL_FULL_LEFT_R2;
+ } else if (r1.bottom() <= r2.y()) {
+ highlight_rect_config_ = HighlightRectsConfiguration::R1_TOP_FULL_LEFT_R2;
+ } else if (r1.y() >= r2.bottom()) {
+ highlight_rect_config_ =
+ HighlightRectsConfiguration::R1_BOTTOM_FULL_LEFT_R2;
+ }
+ } else if (r1.x() <= r2.x() && r2.x() <= r1.right()) {
+ if (r1.bottom() <= r2.y()) {
+ highlight_rect_config_ =
+ HighlightRectsConfiguration::R1_TOP_PARTIAL_LEFT_R2;
+ } else if (r1.y() >= r2.bottom()) {
+ highlight_rect_config_ =
+ HighlightRectsConfiguration::R1_BOTTOM_PARTIAL_LEFT_R2;
+ } else if (r1.Intersects(r2)) {
+ highlight_rect_config_ = HighlightRectsConfiguration::R1_INTERSECTS_R2;
+ } else {
+ NOTREACHED();
+ }
+ } else {
+ highlight_rect_config_ = HighlightRectsConfiguration::NO_DRAW;
+ }
+}
+
+void UIDevToolsDOMAgent::OnPaintLayer(const ui::PaintContext& context) {
+ const gfx::Rect& screen_bounds(layer_for_highlighting_->bounds());
+ ui::PaintRecorder recorder(context, screen_bounds.size());
+ gfx::Canvas* canvas = recorder.canvas();
+ gfx::RectF hovered_rect_f(hovered_rect_);
+
+ cc::PaintFlags flags;
+ flags.setColor(SK_ColorBLUE);
+ flags.setStrokeWidth(1.0f);
+ flags.setStyle(cc::PaintFlags::kStroke_Style);
+
+ constexpr SkScalar intervals[] = {1.f, 4.f};
+ flags.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
+
+ if (!render_text_) {
+ render_text_ =
+ base::WrapUnique<gfx::RenderText>(gfx::RenderText::CreateInstance());
+ }
+ // Display guide lines if |highlight_rect_config_| is NO_DRAW.
+ if (highlight_rect_config_ == HighlightRectsConfiguration::NO_DRAW) {
+ hovered_rect_f.Inset(gfx::InsetsF(-1));
+ DrawRectGuideLinesOnCanvas(screen_bounds, hovered_rect_f, flags, canvas);
+ // Draw |hovered_rect_f| bounds.
+ flags.setPathEffect(0);
+ canvas->DrawRect(hovered_rect_f, flags);
+
+ // Display size of the rectangle after mouse click.
+ if (show_size_on_canvas_) {
+ DrawSizeOfRectangle(hovered_rect_, RectSide::BOTTOM_SIDE, canvas,
+ render_text_.get());
+ }
+ return;
+ }
+ flags.setPathEffect(0);
+ flags.setColor(SK_ColorBLUE);
+
+ gfx::RectF pinned_rect_f(pinned_rect_);
+
+ // Draw |pinned_rect_f| bounds in blue.
+ canvas->DrawRect(pinned_rect_f, flags);
+
+ // Draw |hovered_rect_f| bounds in green.
+ flags.setColor(SK_ColorGREEN);
+ canvas->DrawRect(hovered_rect_f, flags);
+
+ // Draw distances in red colour.
+ flags.setPathEffect(0);
+ flags.setColor(SK_ColorRED);
+
+ if (pinned_rect_f.Contains(hovered_rect_f))
+ std::swap(pinned_rect_f, hovered_rect_f);
+
+ switch (highlight_rect_config_) {
+ case HighlightRectsConfiguration::R1_CONTAINS_R2:
+ DrawR1ContainsR2(pinned_rect_f, hovered_rect_f, flags, canvas,
+ render_text_.get());
+ return;
+ case HighlightRectsConfiguration::R1_HORIZONTAL_FULL_LEFT_R2:
+ NOTIMPLEMENTED();
+ return;
+ case HighlightRectsConfiguration::R1_TOP_FULL_LEFT_R2:
+ NOTIMPLEMENTED();
+ return;
+ case HighlightRectsConfiguration::R1_BOTTOM_FULL_LEFT_R2:
+ NOTIMPLEMENTED();
+ return;
+ case HighlightRectsConfiguration::R1_TOP_PARTIAL_LEFT_R2:
+ NOTIMPLEMENTED();
+ return;
+ case HighlightRectsConfiguration::R1_BOTTOM_PARTIAL_LEFT_R2:
+ NOTIMPLEMENTED();
+ return;
+ case HighlightRectsConfiguration::R1_INTERSECTS_R2:
+ NOTIMPLEMENTED();
+ return;
+ default:
+ NOTREACHED();
+ return;
+ }
+}
+
void UIDevToolsDOMAgent::OnHostInitialized(aura::WindowTreeHost* host) {
root_windows_.push_back(host->window());
}
-void UIDevToolsDOMAgent::OnNodeBoundsChanged(int node_id) {
+void UIDevToolsDOMAgent::OnElementBoundsChanged(UIElement* ui_element) {
for (auto& observer : observers_)
- observer.OnNodeBoundsChanged(node_id);
+ observer.OnElementBoundsChanged(ui_element);
}
std::unique_ptr<ui_devtools::protocol::DOM::Node>
@@ -324,6 +633,7 @@ void UIDevToolsDOMAgent::RemoveDomNode(UIElement* ui_element) {
void UIDevToolsDOMAgent::Reset() {
is_building_tree_ = false;
+ render_text_.reset();
layer_for_highlighting_.reset();
window_element_root_.reset();
node_id_to_ui_element_.clear();
@@ -331,14 +641,14 @@ void UIDevToolsDOMAgent::Reset() {
}
void UIDevToolsDOMAgent::UpdateHighlight(
- const std::pair<aura::Window*, gfx::Rect>& window_and_bounds,
- SkColor background) {
- layer_for_highlighting_->SetColor(background);
-
+ const std::pair<aura::Window*, gfx::Rect>& window_and_bounds) {
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(
window_and_bounds.first);
aura::Window* root = window_and_bounds.first->GetRootWindow();
+ layer_for_highlighting_->SetBounds(root->bounds());
+ layer_for_highlighting_->SchedulePaint(root->bounds());
+
if (root->layer() != layer_for_highlighting_->parent())
root->layer()->Add(layer_for_highlighting_.get());
else
@@ -346,40 +656,10 @@ void UIDevToolsDOMAgent::UpdateHighlight(
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root);
-
- gfx::Rect bounds(window_and_bounds.second);
- gfx::Point origin = bounds.origin();
+ hovered_rect_ = window_and_bounds.second;
+ gfx::Point origin = hovered_rect_.origin();
screen_position_client->ConvertPointFromScreen(root, &origin);
- bounds.set_origin(origin);
- layer_for_highlighting_->SetBounds(bounds);
-}
-
-ui_devtools::protocol::Response UIDevToolsDOMAgent::HighlightNode(
- std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
- highlight_config,
- int node_id) {
- if (!layer_for_highlighting_) {
- layer_for_highlighting_.reset(
- new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR));
- layer_for_highlighting_->set_name("HighlightingLayer");
- }
-
- std::pair<aura::Window*, gfx::Rect> window_and_bounds =
- node_id_to_ui_element_.count(node_id)
- ? node_id_to_ui_element_[node_id]->GetNodeWindowAndBounds()
- : std::make_pair<aura::Window*, gfx::Rect>(nullptr, gfx::Rect());
-
- if (!window_and_bounds.first) {
- return ui_devtools::protocol::Response::Error("No node found with that id");
- }
- SkColor content_color =
- RGBAToSkColor(highlight_config->getContentColor(nullptr));
- UpdateHighlight(window_and_bounds, content_color);
-
- if (!layer_for_highlighting_->visible())
- layer_for_highlighting_->SetVisible(true);
-
- return ui_devtools::protocol::Response::OK();
+ hovered_rect_.set_origin(origin);
}
} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/views/ui_devtools_dom_agent.h b/chromium/components/ui_devtools/views/ui_devtools_dom_agent.h
index cdd2382fd7c..4cb75ad9ff6 100644
--- a/chromium/components/ui_devtools/views/ui_devtools_dom_agent.h
+++ b/chromium/components/ui_devtools/views/ui_devtools_dom_agent.h
@@ -9,6 +9,7 @@
#include "components/ui_devtools/devtools_base_agent.h"
#include "components/ui_devtools/views/ui_element_delegate.h"
#include "ui/aura/env_observer.h"
+#include "ui/compositor/layer_delegate.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -16,20 +17,37 @@ namespace aura {
class Window;
}
+namespace gfx {
+class RenderText;
+}
+
namespace ui_devtools {
+enum HighlightRectsConfiguration {
+ NO_DRAW,
+ R1_CONTAINS_R2,
+ R1_HORIZONTAL_FULL_LEFT_R2,
+ R1_TOP_FULL_LEFT_R2,
+ R1_BOTTOM_FULL_LEFT_R2,
+ R1_TOP_PARTIAL_LEFT_R2,
+ R1_BOTTOM_PARTIAL_LEFT_R2,
+ R1_INTERSECTS_R2
+};
+
+enum RectSide { TOP_SIDE, LEFT_SIDE, RIGHT_SIDE, BOTTOM_SIDE };
+
class UIElement;
class UIDevToolsDOMAgentObserver {
public:
- // TODO(thanhph): Use UIElement* as input argument instead.
- virtual void OnNodeBoundsChanged(int node_id) = 0;
+ virtual void OnElementBoundsChanged(UIElement* ui_element) = 0;
};
class UIDevToolsDOMAgent : public ui_devtools::UiDevToolsBaseAgent<
ui_devtools::protocol::DOM::Metainfo>,
public UIElementDelegate,
- public aura::EnvObserver {
+ public aura::EnvObserver,
+ public ui::LayerDelegate {
public:
UIDevToolsDOMAgent();
~UIDevToolsDOMAgent() override;
@@ -38,11 +56,10 @@ class UIDevToolsDOMAgent : public ui_devtools::UiDevToolsBaseAgent<
ui_devtools::protocol::Response disable() override;
ui_devtools::protocol::Response getDocument(
std::unique_ptr<ui_devtools::protocol::DOM::Node>* out_root) override;
- ui_devtools::protocol::Response highlightNode(
- std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
- highlight_config,
- ui_devtools::protocol::Maybe<int> node_id) override;
ui_devtools::protocol::Response hideHighlight() override;
+ ui_devtools::protocol::Response pushNodesByBackendIdsToFrontend(
+ std::unique_ptr<protocol::Array<int>> backend_node_ids,
+ std::unique_ptr<protocol::Array<int>>* result) override;
// UIElementDelegate:
void OnUIElementAdded(UIElement* parent, UIElement* child) override;
@@ -57,13 +74,35 @@ class UIDevToolsDOMAgent : public ui_devtools::UiDevToolsBaseAgent<
const std::vector<aura::Window*>& root_windows() const {
return root_windows_;
};
+ HighlightRectsConfiguration highlight_rect_config() const {
+ return highlight_rect_config_;
+ };
+ ui_devtools::protocol::Response HighlightNode(int node_id,
+ bool show_size = false);
+
+ // Return the id of the UI element targeted by an event located at |p|, where
+ // |p| is in the local coodinate space of |root_window|. The function
+ // first searches for the targeted window, then the targeted widget (if one
+ // exists), then the targeted view (if one exists). Return 0 if no valid
+ // target is found.
+ int FindElementIdTargetedByPoint(const gfx::Point& p,
+ aura::Window* root_window) const;
+
+ // Shows the distances between the nodes identified by |pinned_id| and
+ // |element_id| in the highlight overlay.
+ void ShowDistancesInHighlightOverlay(int pinned_id, int element_id);
private:
+ // ui::LayerDelegate:
+ void OnPaintLayer(const ui::PaintContext& context) override;
+ void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
+
// aura::EnvObserver:
void OnWindowInitialized(aura::Window* window) override {}
void OnHostInitialized(aura::WindowTreeHost* host) override;
- void OnNodeBoundsChanged(int node_id);
+ void OnElementBoundsChanged(UIElement* ui_element);
std::unique_ptr<ui_devtools::protocol::DOM::Node> BuildInitialTree();
std::unique_ptr<ui_devtools::protocol::DOM::Node> BuildTreeForUIElement(
UIElement* ui_element);
@@ -78,20 +117,23 @@ class UIDevToolsDOMAgent : public ui_devtools::UiDevToolsBaseAgent<
views::View* view);
void RemoveDomNode(UIElement* ui_element);
void Reset();
- void InitializeHighlightingWidget();
void UpdateHighlight(
- const std::pair<aura::Window*, gfx::Rect>& window_and_bounds,
- SkColor background);
- ui_devtools::protocol::Response HighlightNode(
- std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
- highlight_config,
- int node_id);
+ const std::pair<aura::Window*, gfx::Rect>& window_and_bounds);
+ std::unique_ptr<gfx::RenderText> render_text_;
bool is_building_tree_;
+ bool show_size_on_canvas_ = false;
+ HighlightRectsConfiguration highlight_rect_config_;
+ bool is_swap_ = false;
std::unique_ptr<UIElement> window_element_root_;
std::unordered_map<int, UIElement*> node_id_to_ui_element_;
+
+ // TODO(thanhph): |layer_for_highlighting_| should be owned by the overlay
+ // agent.
std::unique_ptr<ui::Layer> layer_for_highlighting_;
std::vector<aura::Window*> root_windows_;
+ gfx::Rect hovered_rect_;
+ gfx::Rect pinned_rect_;
base::ObserverList<UIDevToolsDOMAgentObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(UIDevToolsDOMAgent);
diff --git a/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.cc b/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.cc
new file mode 100644
index 00000000000..972a1bf0776
--- /dev/null
+++ b/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.cc
@@ -0,0 +1,92 @@
+// 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/ui_devtools/views/ui_devtools_overlay_agent.h"
+
+#include "ui/aura/env.h"
+
+namespace ui_devtools {
+
+UIDevToolsOverlayAgent::UIDevToolsOverlayAgent(UIDevToolsDOMAgent* dom_agent)
+ : dom_agent_(dom_agent) {
+ DCHECK(dom_agent_);
+}
+
+UIDevToolsOverlayAgent::~UIDevToolsOverlayAgent() {}
+
+ui_devtools::protocol::Response UIDevToolsOverlayAgent::setInspectMode(
+ const String& in_mode,
+ protocol::Maybe<protocol::Overlay::HighlightConfig> in_highlightConfig) {
+ pinned_id_ = 0;
+ if (in_mode.compare("searchForNode") == 0)
+ aura::Env::GetInstance()->PrependPreTargetHandler(this);
+ else if (in_mode.compare("none") == 0)
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ return ui_devtools::protocol::Response::OK();
+}
+
+ui_devtools::protocol::Response UIDevToolsOverlayAgent::highlightNode(
+ std::unique_ptr<ui_devtools::protocol::Overlay::HighlightConfig>
+ highlight_config,
+ ui_devtools::protocol::Maybe<int> node_id) {
+ return dom_agent_->HighlightNode(node_id.fromJust());
+}
+
+ui_devtools::protocol::Response UIDevToolsOverlayAgent::hideHighlight() {
+ return dom_agent_->hideHighlight();
+}
+
+void UIDevToolsOverlayAgent::OnMouseEvent(ui::MouseEvent* event) {
+ // Make sure the element tree has been populated before processing
+ // mouse events.
+ if (!dom_agent_->window_element_root())
+ return;
+
+ // Find node id of element whose bounds contain the mouse pointer location.
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ int element_id = dom_agent_->FindElementIdTargetedByPoint(
+ event->root_location(), target->GetRootWindow());
+
+ if (pinned_id_ == element_id) {
+ event->SetHandled();
+ return;
+ }
+
+ // Pin the hover element on click.
+ if (event->type() == ui::ET_MOUSE_PRESSED) {
+ event->SetHandled();
+ if (element_id) {
+ pinned_id_ = element_id;
+ frontend()->nodeHighlightRequested(element_id);
+ dom_agent_->HighlightNode(element_id, true /* show_size */);
+ }
+ } else if (element_id && !pinned_id_) {
+ // Display only guidelines if hovering without a pinned element.
+ frontend()->nodeHighlightRequested(element_id);
+ dom_agent_->HighlightNode(element_id, false /* show_size */);
+ } else if (element_id && pinned_id_) {
+ // If hovering with a pinned element, then show distances between the pinned
+ // element and the hover element.
+ dom_agent_->HighlightNode(element_id, false /* show_size */);
+ dom_agent_->ShowDistancesInHighlightOverlay(pinned_id_, element_id);
+ }
+}
+
+void UIDevToolsOverlayAgent::OnKeyEvent(ui::KeyEvent* event) {
+ if (!dom_agent_->window_element_root())
+ return;
+
+ // Exit inspect mode by pressing ESC key.
+ if (event->key_code() == ui::KeyboardCode::VKEY_ESCAPE) {
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ if (pinned_id_) {
+ frontend()->inspectNodeRequested(pinned_id_);
+ dom_agent_->HighlightNode(pinned_id_, true /* show_size */);
+ }
+ // Unpin element.
+ pinned_id_ = 0;
+ }
+}
+
+} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.h b/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.h
new file mode 100644
index 00000000000..15eafbfc14c
--- /dev/null
+++ b/chromium/components/ui_devtools/views/ui_devtools_overlay_agent.h
@@ -0,0 +1,45 @@
+// 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_UI_DEVTOOLS_VIEWS_UI_DEVTOOLS_OVERLAY_AGENT_H_
+#define COMPONENTS_UI_DEVTOOLS_VIEWS_UI_DEVTOOLS_OVERLAY_AGENT_H_
+
+#include "components/ui_devtools/Overlay.h"
+#include "components/ui_devtools/views/ui_devtools_dom_agent.h"
+#include "ui/events/event_handler.h"
+
+namespace ui_devtools {
+
+class UIDevToolsOverlayAgent : public ui_devtools::UiDevToolsBaseAgent<
+ ui_devtools::protocol::Overlay::Metainfo>,
+ public ui::EventHandler {
+ public:
+ explicit UIDevToolsOverlayAgent(UIDevToolsDOMAgent* dom_agent);
+ ~UIDevToolsOverlayAgent() override;
+
+ // Overlay::Backend:
+ ui_devtools::protocol::Response setInspectMode(
+ const String& in_mode,
+ protocol::Maybe<protocol::Overlay::HighlightConfig> in_highlightConfig)
+ override;
+ ui_devtools::protocol::Response highlightNode(
+ std::unique_ptr<ui_devtools::protocol::Overlay::HighlightConfig>
+ highlight_config,
+ ui_devtools::protocol::Maybe<int> node_id) override;
+ ui_devtools::protocol::Response hideHighlight() override;
+
+ private:
+ // ui:EventHandler:
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnKeyEvent(ui::KeyEvent* event) override;
+
+ UIDevToolsDOMAgent* const dom_agent_;
+ int pinned_id_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(UIDevToolsOverlayAgent);
+};
+
+} // namespace ui_devtools
+
+#endif // COMPONENTS_UI_DEVTOOLS_VIEWS_UI_DEVTOOLS_OVERLAY_AGENT_H_
diff --git a/chromium/components/ui_devtools/views/ui_devtools_unittest.cc b/chromium/components/ui_devtools/views/ui_devtools_unittest.cc
index 9ebf91f541c..6dfd26455cf 100644
--- a/chromium/components/ui_devtools/views/ui_devtools_unittest.cc
+++ b/chromium/components/ui_devtools/views/ui_devtools_unittest.cc
@@ -4,8 +4,10 @@
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/views/ui_devtools_css_agent.h"
#include "components/ui_devtools/views/ui_devtools_dom_agent.h"
+#include "components/ui_devtools/views/ui_devtools_overlay_agent.h"
#include "components/ui_devtools/views/ui_element.h"
#include "components/ui_devtools/views/view_element.h"
#include "components/ui_devtools/views/widget_element.h"
@@ -13,6 +15,8 @@
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/window_tree_host.h"
#include "ui/display/display.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/test/event_generator.h"
#include "ui/views/background.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/native_widget_private.h"
@@ -25,7 +29,7 @@ namespace {
using namespace ui_devtools::protocol;
const int kDefaultChildNodeCount = -1;
-const SkColor kBackgroundColor = SK_ColorRED;
+const SkColor kBackgroundColor = 0;
const SkColor kBorderColor = SK_ColorBLUE;
class TestView : public views::View {
@@ -59,7 +63,7 @@ class FakeFrontendChannel : public FrontendChannel {
protocol_notification_messages_.end(), message);
}
- // FrontendChannel
+ // FrontendChannel:
void sendProtocolResponse(int callId,
std::unique_ptr<Serializable> message) override {}
void flushProtocolNotifications() override {}
@@ -125,8 +129,8 @@ DOM::Node* FindInRoot(aura::Window* window, DOM::Node* root) {
return window_node;
}
-int GetPropertyByName(const std::string& name,
- Array<CSS::CSSProperty>* properties) {
+int GetIntPropertyByName(const std::string& name,
+ Array<CSS::CSSProperty>* properties) {
for (size_t i = 0; i < properties->length(); i++) {
CSS::CSSProperty* property = properties->get(i);
if (property->getName() == name) {
@@ -139,12 +143,22 @@ int GetPropertyByName(const std::string& name,
return -1;
}
+std::string GetStringPropertyByName(const std::string& name,
+ Array<CSS::CSSProperty>* properties) {
+ for (size_t i = 0; i < properties->length(); i++) {
+ CSS::CSSProperty* property = properties->get(i);
+ if (property->getName() == name)
+ return property->getValue();
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
ui::Layer* GetHighlightingLayer(aura::Window* root_window) {
for (auto* layer : root_window->layer()->children()) {
if (layer->name() == "HighlightingLayer")
return layer;
}
- NOTREACHED();
return nullptr;
}
@@ -157,22 +171,15 @@ std::unique_ptr<DOM::RGBA> SkColorToRGBA(const SkColor& color) {
.build();
}
-std::unique_ptr<DOM::HighlightConfig> CreateHighlightConfig(
+std::unique_ptr<Overlay::HighlightConfig> CreateHighlightConfig(
const SkColor& background_color,
const SkColor& border_color) {
- return DOM::HighlightConfig::create()
+ return Overlay::HighlightConfig::create()
.setContentColor(SkColorToRGBA(background_color))
.setBorderColor(SkColorToRGBA(border_color))
.build();
}
-void ExpectHighlighted(const gfx::Rect& bounds, aura::Window* root_window) {
- ui::Layer* highlighting_layer = GetHighlightingLayer(root_window);
- EXPECT_TRUE(highlighting_layer->visible());
- EXPECT_EQ(bounds, highlighting_layer->bounds());
- EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
-}
-
} // namespace
class UIDevToolsTest : public views::ViewsTestBase {
@@ -223,6 +230,10 @@ class UIDevToolsTest : public views::ViewsTestBase {
base::MakeUnique<ui_devtools::UIDevToolsCSSAgent>(dom_agent_.get());
css_agent_->Init(uber_dispatcher_.get());
css_agent_->enable();
+ overlay_agent_ =
+ base::MakeUnique<ui_devtools::UIDevToolsOverlayAgent>(dom_agent_.get());
+ overlay_agent_->Init(uber_dispatcher_.get());
+ overlay_agent_->enable();
// We need to create |dom_agent| first to observe creation of
// WindowTreeHosts in ViewTestBase::SetUp().
@@ -239,6 +250,7 @@ class UIDevToolsTest : public views::ViewsTestBase {
top_default_container_window.reset();
top_window.reset();
css_agent_.reset();
+ overlay_agent_.reset();
dom_agent_.reset();
uber_dispatcher_.reset();
fake_frontend_channel_.reset();
@@ -268,15 +280,44 @@ class UIDevToolsTest : public views::ViewsTestBase {
node_id));
}
+ int GetOverlayNodeHighlightRequestedCount(int node_id) {
+ return frontend_channel()->CountProtocolNotificationMessage(
+ base::StringPrintf(
+ "{\"method\":\"Overlay.nodeHighlightRequested\",\"params\":{"
+ "\"nodeId\":%d}}",
+ node_id));
+ }
+
+ int GetOverlayInspectNodeRequestedCount(int node_id) {
+ return frontend_channel()->CountProtocolNotificationMessage(
+ base::StringPrintf(
+ "{\"method\":\"Overlay.inspectNodeRequested\",\"params\":{"
+ "\"backendNodeId\":%d}}",
+ node_id));
+ }
+
void CompareNodeBounds(DOM::Node* node, const gfx::Rect& bounds) {
Maybe<CSS::CSSStyle> styles;
css_agent_->getMatchedStylesForNode(node->getNodeId(), &styles);
ASSERT_TRUE(styles.isJust());
Array<CSS::CSSProperty>* properties = styles.fromJust()->getCssProperties();
- EXPECT_EQ(bounds.height(), GetPropertyByName("height", properties));
- EXPECT_EQ(bounds.width(), GetPropertyByName("width", properties));
- EXPECT_EQ(bounds.x(), GetPropertyByName("x", properties));
- EXPECT_EQ(bounds.y(), GetPropertyByName("y", properties));
+ EXPECT_EQ(bounds.height(), GetIntPropertyByName("height", properties));
+ EXPECT_EQ(bounds.width(), GetIntPropertyByName("width", properties));
+ EXPECT_EQ(bounds.x(), GetIntPropertyByName("x", properties));
+ EXPECT_EQ(bounds.y(), GetIntPropertyByName("y", properties));
+ }
+
+ void CompareViewAtrributes(DOM::Node* node, views::View* view) {
+ Maybe<CSS::CSSStyle> styles;
+ css_agent_->getMatchedStylesForNode(node->getNodeId(), &styles);
+ ASSERT_TRUE(styles.isJust());
+ Array<CSS::CSSProperty>* properties = styles.fromJust()->getCssProperties();
+
+ base::string16 description;
+ if (view->GetTooltipText(gfx::Point(), &description)) {
+ EXPECT_EQ(base::UTF16ToUTF8(description),
+ GetStringPropertyByName("tooltip", properties));
+ }
}
void SetStyleTexts(DOM::Node* node,
@@ -299,7 +340,7 @@ class UIDevToolsTest : public views::ViewsTestBase {
}
void HighlightNode(int node_id) {
- dom_agent_->highlightNode(
+ overlay_agent_->highlightNode(
CreateHighlightConfig(kBackgroundColor, kBorderColor), node_id);
}
@@ -324,6 +365,9 @@ class UIDevToolsTest : public views::ViewsTestBase {
ui_devtools::UIDevToolsCSSAgent* css_agent() { return css_agent_.get(); }
ui_devtools::UIDevToolsDOMAgent* dom_agent() { return dom_agent_.get(); }
+ ui_devtools::UIDevToolsOverlayAgent* overlay_agent() {
+ return overlay_agent_.get();
+ }
std::unique_ptr<aura::Window> top_overlay_window;
std::unique_ptr<aura::Window> top_window;
@@ -334,10 +378,119 @@ class UIDevToolsTest : public views::ViewsTestBase {
std::unique_ptr<FakeFrontendChannel> fake_frontend_channel_;
std::unique_ptr<ui_devtools::UIDevToolsDOMAgent> dom_agent_;
std::unique_ptr<ui_devtools::UIDevToolsCSSAgent> css_agent_;
+ std::unique_ptr<ui_devtools::UIDevToolsOverlayAgent> overlay_agent_;
DISALLOW_COPY_AND_ASSIGN(UIDevToolsTest);
};
+// Tests that FindElementIdTargetedByPoint() returns a non-zero id when a UI
+// element target exists.
+TEST_F(UIDevToolsTest, FindElementIdTargetedByPoint) {
+ std::unique_ptr<views::Widget> widget(
+ CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+ std::unique_ptr<ui_devtools::protocol::DOM::Node> root;
+ dom_agent()->getDocument(&root);
+ EXPECT_NE(0, dom_agent()->FindElementIdTargetedByPoint(
+ gfx::Point(1, 1), GetPrimaryRootWindow()));
+}
+
+// Test case R1_CONTAINS_R2.
+TEST_F(UIDevToolsTest, OneUIElementContainsAnother) {
+ const gfx::Rect outside_rect(1, 1, 100, 100);
+ std::unique_ptr<views::Widget> widget_outside(CreateTestWidget(outside_rect));
+
+ const gfx::Rect inside_rect(2, 2, 50, 50);
+ std::unique_ptr<views::Widget> widget_inside(CreateTestWidget(inside_rect));
+
+ std::unique_ptr<ui_devtools::protocol::DOM::Node> root;
+ dom_agent()->getDocument(&root);
+
+ int outside_rect_id = dom_agent()->FindElementIdTargetedByPoint(
+ outside_rect.origin(), GetPrimaryRootWindow());
+ int inside_rect_id = dom_agent()->FindElementIdTargetedByPoint(
+ inside_rect.origin(), GetPrimaryRootWindow());
+ dom_agent()->ShowDistancesInHighlightOverlay(outside_rect_id, inside_rect_id);
+
+ HighlightRectsConfiguration highlight_rect_config =
+ dom_agent()->highlight_rect_config();
+
+ // Swapping R1 and R2 shouldn't change |highlight_rect_config|.
+ dom_agent()->ShowDistancesInHighlightOverlay(inside_rect_id, outside_rect_id);
+ DCHECK_EQ(highlight_rect_config, dom_agent()->highlight_rect_config());
+
+ const std::pair<aura::Window*, gfx::Rect> element_outside(
+ dom_agent()
+ ->GetElementFromNodeId(outside_rect_id)
+ ->GetNodeWindowAndBounds());
+
+ const std::pair<aura::Window*, gfx::Rect> element_inside(
+ dom_agent()
+ ->GetElementFromNodeId(inside_rect_id)
+ ->GetNodeWindowAndBounds());
+
+ EXPECT_TRUE(element_outside.second == outside_rect);
+ EXPECT_TRUE(element_inside.second == inside_rect);
+ DCHECK_EQ(dom_agent()->highlight_rect_config(),
+ HighlightRectsConfiguration::R1_CONTAINS_R2);
+}
+
+// Tests that the correct Overlay events are dispatched to the frontend when
+// hovering and clicking over a UI element in inspect mode.
+TEST_F(UIDevToolsTest, MouseEventsGenerateFEEventsInInspectMode) {
+ std::unique_ptr<views::Widget> widget(
+ CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+
+ std::unique_ptr<ui_devtools::protocol::DOM::Node> root;
+ dom_agent()->getDocument(&root);
+
+ gfx::Point p(1, 1);
+ int node_id =
+ dom_agent()->FindElementIdTargetedByPoint(p, GetPrimaryRootWindow());
+
+ EXPECT_EQ(0, GetOverlayInspectNodeRequestedCount(node_id));
+ EXPECT_EQ(0, GetOverlayNodeHighlightRequestedCount(node_id));
+ overlay_agent()->setInspectMode(
+ "searchForNode", protocol::Maybe<protocol::Overlay::HighlightConfig>());
+
+ // Moving the mouse cursor over the widget bounds should request a node
+ // highlight.
+ ui::test::EventGenerator generator(widget->GetNativeWindow());
+ generator.MoveMouseBy(p.x(), p.y());
+
+ // 2 mouse events ET_MOUSE_ENTERED and ET_MOUSE_MOVED are generated.
+ EXPECT_EQ(2, GetOverlayNodeHighlightRequestedCount(node_id));
+ EXPECT_EQ(0, GetOverlayInspectNodeRequestedCount(node_id));
+
+ // Clicking on the widget should pin that element.
+ generator.PressLeftButton();
+
+ int inspect_node_notification_count =
+ GetOverlayInspectNodeRequestedCount(node_id);
+
+ // Press escape to exit inspect mode.
+ generator.PressKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EventFlags::EF_NONE);
+
+ // Upon exiting inspect mode, the element is inspected and highlighted.
+ EXPECT_EQ(inspect_node_notification_count + 1,
+ GetOverlayInspectNodeRequestedCount(node_id));
+ ui::Layer* highlighting_layer = GetHighlightingLayer(GetPrimaryRootWindow());
+ EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
+ EXPECT_TRUE(highlighting_layer->visible());
+
+ int highlight_notification_count =
+ GetOverlayNodeHighlightRequestedCount(node_id);
+ inspect_node_notification_count =
+ GetOverlayInspectNodeRequestedCount(node_id);
+
+ // Since inspect mode is exited, a subsequent mouse move should generate no
+ // nodeHighlightRequested or inspectNodeRequested events.
+ generator.MoveMouseBy(p.x(), p.y());
+ EXPECT_EQ(highlight_notification_count,
+ GetOverlayNodeHighlightRequestedCount(node_id));
+ EXPECT_EQ(inspect_node_notification_count,
+ GetOverlayInspectNodeRequestedCount(node_id));
+}
+
TEST_F(UIDevToolsTest, GetDocumentWithWindowWidgetView) {
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
@@ -686,7 +839,11 @@ TEST_F(UIDevToolsTest, WindowWidgetViewHighlight) {
DOM::Node* root_view_node = widget_node->getChildren(nullptr)->get(0);
HighlightNode(window_node->getNodeId());
- ExpectHighlighted(window->GetBoundsInScreen(), GetPrimaryRootWindow());
+
+ ui::Layer* highlighting_layer = GetHighlightingLayer(GetPrimaryRootWindow());
+ EXPECT_TRUE(highlighting_layer->visible());
+ EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
+
ui_devtools::UIElement* element =
dom_agent()->GetElementFromNodeId(window_node->getNodeId());
ASSERT_EQ(ui_devtools::UIElementType::WINDOW, element->type());
@@ -695,9 +852,11 @@ TEST_F(UIDevToolsTest, WindowWidgetViewHighlight) {
window->GetBoundsInScreen());
HideHighlight(0);
-
HighlightNode(widget_node->getNodeId());
- ExpectHighlighted(widget->GetWindowBoundsInScreen(), GetPrimaryRootWindow());
+
+ highlighting_layer = GetHighlightingLayer(GetPrimaryRootWindow());
+ EXPECT_TRUE(highlighting_layer->visible());
+ EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
element = dom_agent()->GetElementFromNodeId(widget_node->getNodeId());
ASSERT_EQ(ui_devtools::UIElementType::WIDGET, element->type());
@@ -706,9 +865,11 @@ TEST_F(UIDevToolsTest, WindowWidgetViewHighlight) {
widget->GetWindowBoundsInScreen());
HideHighlight(0);
-
HighlightNode(root_view_node->getNodeId());
- ExpectHighlighted(root_view->GetBoundsInScreen(), GetPrimaryRootWindow());
+
+ highlighting_layer = GetHighlightingLayer(GetPrimaryRootWindow());
+ EXPECT_TRUE(highlighting_layer->visible());
+ EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
element = dom_agent()->GetElementFromNodeId(root_view_node->getNodeId());
ASSERT_EQ(ui_devtools::UIElementType::VIEW, element->type());
@@ -769,6 +930,8 @@ TEST_F(UIDevToolsTest, WindowWidgetViewGetMatchedStylesForNode) {
CompareNodeBounds(parent_children->get(1), window_bounds);
CompareNodeBounds(parent_children->get(0)->getChildren(nullptr)->get(0),
view_bounds);
+ CompareViewAtrributes(parent_children->get(0)->getChildren(nullptr)->get(0),
+ widget->GetRootView());
}
TEST_F(UIDevToolsTest, WindowWidgetViewStyleSheetChanged) {
diff --git a/chromium/components/ui_devtools/views/ui_element.cc b/chromium/components/ui_devtools/views/ui_element.cc
index a44ff1658c5..0d4a3e0b616 100644
--- a/chromium/components/ui_devtools/views/ui_element.cc
+++ b/chromium/components/ui_devtools/views/ui_element.cc
@@ -68,6 +68,43 @@ void UIElement::ReorderChild(UIElement* child, int new_index) {
delegate()->OnUIElementReordered(child->parent(), child);
}
+template <class T>
+int UIElement::FindUIElementIdForBackendElement(T* element) const {
+ NOTREACHED();
+ return 0;
+}
+
+template <>
+int UIElement::FindUIElementIdForBackendElement<aura::Window>(
+ aura::Window* element) const {
+ if (type_ == UIElementType::WINDOW &&
+ UIElement::GetBackingElement<aura::Window, WindowElement>(this) ==
+ element) {
+ return node_id_;
+ }
+ for (auto* child : children_) {
+ int ui_element_id = child->FindUIElementIdForBackendElement(element);
+ if (ui_element_id)
+ return ui_element_id;
+ }
+ return 0;
+}
+
+template <>
+int UIElement::FindUIElementIdForBackendElement<views::View>(
+ views::View* element) const {
+ if (type_ == UIElementType::VIEW &&
+ UIElement::GetBackingElement<views::View, ViewElement>(this) == element) {
+ return node_id_;
+ }
+ for (auto* child : children_) {
+ int ui_element_id = child->FindUIElementIdForBackendElement(element);
+ if (ui_element_id)
+ return ui_element_id;
+ }
+ return 0;
+}
+
UIElement::UIElement(const UIElementType type,
UIElementDelegate* delegate,
UIElement* parent)
diff --git a/chromium/components/ui_devtools/views/ui_element.h b/chromium/components/ui_devtools/views/ui_element.h
index dcd614a02fb..1df61821190 100644
--- a/chromium/components/ui_devtools/views/ui_element.h
+++ b/chromium/components/ui_devtools/views/ui_element.h
@@ -40,6 +40,12 @@ class UIElement {
// Move |child| to position new_index in |children_|.
void ReorderChild(UIElement* child, int new_index);
+ template <class T>
+ int FindUIElementIdForBackendElement(T* element) const;
+
+ // Return a vector of pairs of attributes' names and values.
+ virtual std::vector<std::pair<std::string, std::string>> GetCustomAttributes()
+ const = 0;
virtual void GetBounds(gfx::Rect* bounds) const = 0;
virtual void SetBounds(const gfx::Rect& bounds) = 0;
virtual void GetVisible(bool* visible) const = 0;
@@ -51,7 +57,7 @@ class UIElement {
const = 0;
template <typename BackingT, typename T>
- static BackingT* GetBackingElement(UIElement* element) {
+ static BackingT* GetBackingElement(const UIElement* element) {
return T::From(element);
};
diff --git a/chromium/components/ui_devtools/views/view_element.cc b/chromium/components/ui_devtools/views/view_element.cc
index e7080110587..3c7e50c709e 100644
--- a/chromium/components/ui_devtools/views/view_element.cc
+++ b/chromium/components/ui_devtools/views/view_element.cc
@@ -4,6 +4,7 @@
#include "components/ui_devtools/views/view_element.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/views/ui_element_delegate.h"
#include "ui/views/widget/widget.h"
@@ -56,6 +57,16 @@ void ViewElement::OnViewBoundsChanged(views::View* view) {
delegate()->OnUIElementBoundsChanged(this);
}
+std::vector<std::pair<std::string, std::string>>
+ViewElement::GetCustomAttributes() const {
+ base::string16 description;
+ if (view_->GetTooltipText(gfx::Point(), &description)) {
+ return {std::make_pair<std::string, std::string>(
+ "tooltip", base::UTF16ToUTF8(description))};
+ }
+ return {};
+}
+
void ViewElement::GetBounds(gfx::Rect* bounds) const {
*bounds = view_->bounds();
}
@@ -79,9 +90,9 @@ std::pair<aura::Window*, gfx::Rect> ViewElement::GetNodeWindowAndBounds()
}
// static
-views::View* ViewElement::From(UIElement* element) {
+views::View* ViewElement::From(const UIElement* element) {
DCHECK_EQ(UIElementType::VIEW, element->type());
- return static_cast<ViewElement*>(element)->view_;
+ return static_cast<const ViewElement*>(element)->view_;
}
} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/views/view_element.h b/chromium/components/ui_devtools/views/view_element.h
index 37e46cc81c4..6576069daa6 100644
--- a/chromium/components/ui_devtools/views/view_element.h
+++ b/chromium/components/ui_devtools/views/view_element.h
@@ -31,12 +31,14 @@ class ViewElement : public views::ViewObserver, public UIElement {
void OnViewBoundsChanged(views::View* view) override;
// UIElement:
+ std::vector<std::pair<std::string, std::string>> GetCustomAttributes()
+ const override;
void GetBounds(gfx::Rect* bounds) const override;
void SetBounds(const gfx::Rect& bounds) override;
void GetVisible(bool* visible) const override;
void SetVisible(bool visible) override;
std::pair<aura::Window*, gfx::Rect> GetNodeWindowAndBounds() const override;
- static views::View* From(UIElement* element);
+ static views::View* From(const UIElement* element);
private:
views::View* view_;
diff --git a/chromium/components/ui_devtools/views/widget_element.cc b/chromium/components/ui_devtools/views/widget_element.cc
index 7f87219bdad..fd5fa7efcd1 100644
--- a/chromium/components/ui_devtools/views/widget_element.cc
+++ b/chromium/components/ui_devtools/views/widget_element.cc
@@ -35,6 +35,11 @@ void WidgetElement::OnWidgetBoundsChanged(views::Widget* widget,
delegate()->OnUIElementBoundsChanged(this);
}
+std::vector<std::pair<std::string, std::string>>
+WidgetElement::GetCustomAttributes() const {
+ return {};
+}
+
void WidgetElement::GetBounds(gfx::Rect* bounds) const {
*bounds = widget_->GetRestoredBounds();
}
@@ -63,9 +68,9 @@ std::pair<aura::Window*, gfx::Rect> WidgetElement::GetNodeWindowAndBounds()
}
// static
-views::Widget* WidgetElement::From(UIElement* element) {
+views::Widget* WidgetElement::From(const UIElement* element) {
DCHECK_EQ(UIElementType::WIDGET, element->type());
- return static_cast<WidgetElement*>(element)->widget_;
+ return static_cast<const WidgetElement*>(element)->widget_;
}
} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/views/widget_element.h b/chromium/components/ui_devtools/views/widget_element.h
index 9acc5ebfcce..56aa0cf4406 100644
--- a/chromium/components/ui_devtools/views/widget_element.h
+++ b/chromium/components/ui_devtools/views/widget_element.h
@@ -35,13 +35,15 @@ class WidgetElement : public views::WidgetRemovalsObserver,
const gfx::Rect& new_bounds) override;
// UIElement:
+ std::vector<std::pair<std::string, std::string>> GetCustomAttributes()
+ const override;
void GetBounds(gfx::Rect* bounds) const override;
void SetBounds(const gfx::Rect& bounds) override;
void GetVisible(bool* visible) const override;
void SetVisible(bool visible) override;
std::pair<aura::Window*, gfx::Rect> GetNodeWindowAndBounds() const override;
- static views::Widget* From(UIElement* element);
+ static views::Widget* From(const UIElement* element);
private:
views::Widget* widget_;
diff --git a/chromium/components/ui_devtools/views/window_element.cc b/chromium/components/ui_devtools/views/window_element.cc
index 951d13792e8..537d022d920 100644
--- a/chromium/components/ui_devtools/views/window_element.cc
+++ b/chromium/components/ui_devtools/views/window_element.cc
@@ -63,6 +63,11 @@ void WindowElement::OnWindowBoundsChanged(aura::Window* window,
delegate()->OnUIElementBoundsChanged(this);
}
+std::vector<std::pair<std::string, std::string>>
+WindowElement::GetCustomAttributes() const {
+ return {};
+}
+
void WindowElement::GetBounds(gfx::Rect* bounds) const {
*bounds = window_->bounds();
}
@@ -88,9 +93,9 @@ std::pair<aura::Window*, gfx::Rect> WindowElement::GetNodeWindowAndBounds()
}
// static
-aura::Window* WindowElement::From(UIElement* element) {
+aura::Window* WindowElement::From(const UIElement* element) {
DCHECK_EQ(UIElementType::WINDOW, element->type());
- return static_cast<WindowElement*>(element)->window_;
+ return static_cast<const WindowElement*>(element)->window_;
}
} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/views/window_element.h b/chromium/components/ui_devtools/views/window_element.h
index 2574eff9156..e2ad70d1846 100644
--- a/chromium/components/ui_devtools/views/window_element.h
+++ b/chromium/components/ui_devtools/views/window_element.h
@@ -32,13 +32,15 @@ class WindowElement : public aura::WindowObserver, public UIElement {
const gfx::Rect& new_bounds) override;
// UIElement:
+ std::vector<std::pair<std::string, std::string>> GetCustomAttributes()
+ const override;
void GetBounds(gfx::Rect* bounds) const override;
void SetBounds(const gfx::Rect& bounds) override;
void GetVisible(bool* visible) const override;
void SetVisible(bool visible) override;
std::pair<aura::Window*, gfx::Rect> GetNodeWindowAndBounds() const override;
- static aura::Window* From(UIElement* element);
+ static aura::Window* From(const UIElement* element);
private:
aura::Window* window_;
diff --git a/chromium/components/ukm/BUILD.gn b/chromium/components/ukm/BUILD.gn
index 6dbee54fc86..eb7723f2462 100644
--- a/chromium/components/ukm/BUILD.gn
+++ b/chromium/components/ukm/BUILD.gn
@@ -49,12 +49,14 @@ static_library("ukm_interface") {
public_deps = [
"//base",
+ "//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/interfaces",
]
deps = [
":ukm",
"//mojo/public/cpp/bindings",
+ "//services/metrics/public/cpp:metrics_cpp",
]
}
diff --git a/chromium/components/ukm/debug_page/BUILD.gn b/chromium/components/ukm/debug_page/BUILD.gn
index 9fa09128304..ffbaa4fa776 100644
--- a/chromium/components/ukm/debug_page/BUILD.gn
+++ b/chromium/components/ukm/debug_page/BUILD.gn
@@ -12,6 +12,7 @@ static_library("debug_page") {
"//base",
"//components/ukm",
"//content/public/browser",
+ "//services/metrics/public/cpp:ukm_builders",
"//url",
]
}
diff --git a/chromium/components/ukm/debug_page/debug_page.cc b/chromium/components/ukm/debug_page/debug_page.cc
index 23a774772ee..fb6e60dffcf 100644
--- a/chromium/components/ukm/debug_page/debug_page.cc
+++ b/chromium/components/ukm/debug_page/debug_page.cc
@@ -10,11 +10,27 @@
#include "base/strings/stringprintf.h"
#include "components/ukm/ukm_service.h"
#include "components/ukm/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "url/gurl.h"
namespace ukm {
namespace debug {
+namespace {
+
+struct SourceData {
+ UkmSource* source;
+ std::vector<mojom::UkmEntry*> entries;
+};
+
+std::string GetName(ukm::builders::DecodeMap& decode_map, uint64_t hash) {
+ if (decode_map.count(hash))
+ return decode_map[hash];
+ return base::StringPrintf("Unknown %" PRIu64, hash);
+}
+
+} // namespace
+
DebugPage::DebugPage(ServiceGetter service_getter)
: service_getter_(service_getter) {}
@@ -54,18 +70,35 @@ void DebugPage::StartDataRequest(
data.append(
base::StringPrintf("<p>SessionId:%d</p>", ukm_service->session_id_));
- data.append("<h2>Sources</h2>");
+ auto decode_map = ::ukm::builders::CreateDecodeMap();
+ std::map<SourceId, SourceData> source_data;
for (const auto& kv : ukm_service->sources_) {
- const auto* src = kv.second.get();
- data.append(base::StringPrintf("<p>Id:%" PRId64 " Url:%s</p>", src->id(),
- src->url().spec().c_str()));
+ source_data[kv.first].source = kv.second.get();
}
- data.append("<h2>Entries</h2>");
for (const auto& v : ukm_service->entries_) {
- const auto* entry = v.get();
- data.append(base::StringPrintf("<h3>Id:%" PRId64 " Hash:%" PRIu64 "</h3>",
- entry->source_id, entry->event_hash));
+ source_data[v.get()->source_id].entries.push_back(v.get());
+ }
+
+ data.append("<h2>Sources</h2>");
+ for (const auto& kv : source_data) {
+ const auto* src = kv.second.source;
+ if (src) {
+ data.append(base::StringPrintf("<h3>Id:%" PRId64 " Url:%s</h3>",
+ src->id(), src->url().spec().c_str()));
+ } else {
+ data.append(base::StringPrintf("<h3>Id:%" PRId64 "</h3>", kv.first));
+ }
+ for (auto* entry : kv.second.entries) {
+ data.append(
+ base::StringPrintf("<h4>Entry:%s</h4>",
+ GetName(decode_map, entry->event_hash).c_str()));
+ for (const auto& metric : entry->metrics) {
+ data.append(base::StringPrintf(
+ "<h5>Metric:%s Value:%" PRId64 "</h5>",
+ GetName(decode_map, metric->metric_hash).c_str(), metric->value));
+ }
+ }
}
}
diff --git a/chromium/components/ukm/ukm_interface.cc b/chromium/components/ukm/ukm_interface.cc
index c0eb4de7f4a..3cc99a25d7a 100644
--- a/chromium/components/ukm/ukm_interface.cc
+++ b/chromium/components/ukm/ukm_interface.cc
@@ -8,24 +8,11 @@
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace ukm {
-namespace {
-
-// Map source ids from different instances into unique namespaces, so that
-// clients can create thier own IDs without having them collide.
-// This won't be necessary once we switch to using CoordinationUnitIDs.
-int64_t ConvertSourceId(int64_t source_id, int64_t instance_id) {
- const int64_t low_bits = (INT64_C(1) << 32) - 1;
- // Neither ID should get large enough to cause an issue, but explicitly
- // discard down to 32 bits anyway.
- return ((instance_id & low_bits) << 32) | (source_id & low_bits);
-}
-
-} // namespace
-
UkmInterface::UkmInterface(UkmRecorder* ukm_recorder, int64_t instance_id)
: ukm_recorder_(ukm_recorder), instance_id_(instance_id) {}
@@ -42,13 +29,14 @@ void UkmInterface::Create(UkmRecorder* ukm_recorder,
}
void UkmInterface::AddEntry(mojom::UkmEntryPtr ukm_entry) {
- ukm_entry->source_id = ConvertSourceId(instance_id_, ukm_entry->source_id);
+ ukm_entry->source_id =
+ ConvertSourceIdFromInstance(instance_id_, ukm_entry->source_id);
ukm_recorder_->AddEntry(std::move(ukm_entry));
}
void UkmInterface::UpdateSourceURL(int64_t source_id, const std::string& url) {
- ukm_recorder_->UpdateSourceURL(ConvertSourceId(instance_id_, source_id),
- GURL(url));
+ ukm_recorder_->UpdateSourceURL(
+ ConvertSourceIdFromInstance(instance_id_, source_id), GURL(url));
}
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_service.cc b/chromium/components/ukm/ukm_service.cc
index c38c2fc634c..8a2a2e48987 100644
--- a/chromium/components/ukm/ukm_service.cc
+++ b/chromium/components/ukm/ukm_service.cc
@@ -34,12 +34,6 @@ namespace {
// initialization work.
constexpr int kInitializationDelaySeconds = 5;
-// True if we should record session ids in the UKM Report proto.
-bool ShouldRecordSessionId() {
- return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId",
- false);
-}
-
// Generates a new client id and stores it in prefs.
uint64_t GenerateClientId(PrefService* pref_service) {
uint64_t client_id = 0;
@@ -73,6 +67,7 @@ UkmService::UkmService(PrefService* pref_service,
: pref_service_(pref_service),
client_id_(0),
session_id_(0),
+ report_count_(0),
client_(client),
reporting_service_(client, pref_service),
initialize_started_(false),
@@ -94,8 +89,7 @@ UkmService::UkmService(PrefService* pref_service,
scheduler_.reset(new ukm::UkmRotationScheduler(rotate_callback,
get_upload_interval_callback));
- for (auto& provider : metrics_providers_)
- provider->Init();
+ metrics_providers_.Init();
StoreWhitelistedEntries();
@@ -125,8 +119,7 @@ void UkmService::EnableReporting() {
if (reporting_service_.reporting_active())
return;
- for (auto& provider : metrics_providers_)
- provider->OnRecordingEnabled();
+ metrics_providers_.OnRecordingEnabled();
if (!initialize_started_)
Initialize();
@@ -140,8 +133,7 @@ void UkmService::DisableReporting() {
reporting_service_.DisableReporting();
- for (auto& provider : metrics_providers_)
- provider->OnRecordingDisabled();
+ metrics_providers_.OnRecordingDisabled();
scheduler_->Stop();
Flush();
@@ -170,8 +162,7 @@ void UkmService::OnAppEnterBackground() {
scheduler_->Stop();
// Give providers a chance to persist ukm data as part of being backgrounded.
- for (auto& provider : metrics_providers_)
- provider->OnAppEnterBackground();
+ metrics_providers_.OnAppEnterBackground();
Flush();
}
@@ -196,11 +187,12 @@ void UkmService::Purge() {
void UkmService::ResetClientId() {
client_id_ = GenerateClientId(pref_service_);
session_id_ = LoadSessionId(pref_service_);
+ report_count_ = 0;
}
void UkmService::RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider> provider) {
- metrics_providers_.push_back(std::move(provider));
+ metrics_providers_.RegisterMetricsProvider(std::move(provider));
}
// static
@@ -215,8 +207,10 @@ void UkmService::StartInitTask() {
DVLOG(1) << "UkmService::StartInitTask";
client_id_ = LoadOrGenerateClientId(pref_service_);
session_id_ = LoadSessionId(pref_service_);
- client_->InitializeSystemProfileMetrics(base::Bind(
- &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr()));
+ report_count_ = 0;
+
+ metrics_providers_.AsyncInit(base::Bind(&UkmService::FinishedInitTask,
+ self_ptr_factory_.GetWeakPtr()));
}
void UkmService::FinishedInitTask() {
@@ -245,17 +239,16 @@ void UkmService::BuildAndStoreLog() {
Report report;
report.set_client_id(client_id_);
- if (ShouldRecordSessionId())
- report.set_session_id(session_id_);
+ report.set_session_id(session_id_);
+ report.set_report_id(++report_count_);
StoreRecordingsInReport(&report);
metrics::MetricsLog::RecordCoreSystemProfile(client_,
report.mutable_system_profile());
- for (auto& provider : metrics_providers_) {
- provider->ProvideSystemProfileMetrics(report.mutable_system_profile());
- }
+ metrics_providers_.ProvideSystemProfileMetrics(
+ report.mutable_system_profile());
std::string serialized_log;
report.SerializeToString(&serialized_log);
diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h
index b6931198f3f..22b7ef5ee27 100644
--- a/chromium/components/ukm/ukm_service.h
+++ b/chromium/components/ukm/ukm_service.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
+#include "components/metrics/delegating_provider.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/metrics_rotation_scheduler.h"
#include "components/ukm/ukm_recorder_impl.h"
@@ -115,12 +116,15 @@ class UkmService : public UkmRecorderImpl {
// The UKM session id stored in prefs.
int32_t session_id_;
+ // The number of reports generated this session.
+ int32_t report_count_;
+
// Used to interact with the embedder. Weak pointer; must outlive |this|
// instance.
metrics::MetricsServiceClient* const client_;
// Registered metrics providers.
- std::vector<std::unique_ptr<metrics::MetricsProvider>> metrics_providers_;
+ metrics::DelegatingProvider metrics_providers_;
// Log reporting service.
ukm::UkmReportingService reporting_service_;
diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc
index 4059680ef70..75b383ab3a9 100644
--- a/chromium/components/ukm/ukm_service_unittest.cc
+++ b/chromium/components/ukm/ukm_service_unittest.cc
@@ -209,7 +209,7 @@ TEST_F(UkmServiceTest, SourceSerialization) {
Report proto_report = GetPersistedReport();
EXPECT_EQ(1, proto_report.sources_size());
- EXPECT_FALSE(proto_report.has_session_id());
+ EXPECT_TRUE(proto_report.has_session_id());
const Source& proto_source = proto_report.sources(0);
EXPECT_EQ(id, proto_source.id());
@@ -428,30 +428,24 @@ TEST_F(UkmServiceTest, RecordInitialUrl) {
}
TEST_F(UkmServiceTest, RecordSessionId) {
- for (bool should_record_session_id : {true, false}) {
- base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
- ScopedUkmFeatureParams params(
- base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"RecordSessionId", should_record_session_id ? "true" : "false"}});
-
- ClearPrefs();
- UkmService service(&prefs_, &client_);
- TestRecordingHelper recorder(&service);
- EXPECT_EQ(0, GetPersistedLogCount());
- service.Initialize();
- task_runner_->RunUntilIdle();
- service.EnableRecording();
- service.EnableReporting();
+ ClearPrefs();
+ UkmService service(&prefs_, &client_);
+ TestRecordingHelper recorder(&service);
+ EXPECT_EQ(0, GetPersistedLogCount());
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording();
+ service.EnableReporting();
- auto id = UkmRecorder::GetNewSourceID();
- recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
+ auto id = UkmRecorder::GetNewSourceID();
+ recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
- service.Flush();
- EXPECT_EQ(1, GetPersistedLogCount());
+ service.Flush();
+ EXPECT_EQ(1, GetPersistedLogCount());
- auto proto_report = GetPersistedReport();
- EXPECT_EQ(should_record_session_id, proto_report.has_session_id());
- }
+ auto proto_report = GetPersistedReport();
+ EXPECT_TRUE(proto_report.has_session_id());
+ EXPECT_EQ(1, proto_report.report_id());
}
TEST_F(UkmServiceTest, SourceSize) {
diff --git a/chromium/components/ukm/ukm_source.cc b/chromium/components/ukm/ukm_source.cc
index c9eda128a8f..5324048fc28 100644
--- a/chromium/components/ukm/ukm_source.cc
+++ b/chromium/components/ukm/ukm_source.cc
@@ -4,6 +4,7 @@
#include "components/ukm/ukm_source.h"
+#include "base/atomicops.h"
#include "base/hash.h"
#include "components/metrics/proto/ukm/source.pb.h"
@@ -17,6 +18,12 @@ constexpr int kMaxURLLength = 2 * 1024;
// The string sent in place of a URL if the real URL was too long.
constexpr char kMaxUrlLengthMessage[] = "URLTooLong";
+// Using a simple global assumes that all access to it will be done on the same
+// thread, namely the UI thread. If this becomes not the case then it can be
+// changed to an Atomic32 (make CustomTabState derive from int32_t) and accessed
+// with no-barrier loads and stores.
+UkmSource::CustomTabState g_custom_tab_state = UkmSource::kCustomTabUnset;
+
// Returns a URL that is under the length limit, by returning a constant
// string when the URl is too long.
std::string GetShortenedURL(const GURL& url) {
@@ -27,7 +34,12 @@ std::string GetShortenedURL(const GURL& url) {
} // namespace
-UkmSource::UkmSource() = default;
+// static
+void UkmSource::SetCustomTabVisible(bool visible) {
+ g_custom_tab_state = visible ? kCustomTabTrue : kCustomTabFalse;
+}
+
+UkmSource::UkmSource() : custom_tab_state_(g_custom_tab_state) {}
UkmSource::~UkmSource() = default;
@@ -49,6 +61,9 @@ void UkmSource::PopulateProto(Source* proto_source) const {
proto_source->set_url(GetShortenedURL(url_));
if (!initial_url_.is_empty())
proto_source->set_initial_url(GetShortenedURL(initial_url_));
+
+ if (custom_tab_state_ != kCustomTabUnset)
+ proto_source->set_is_custom_tab(custom_tab_state_ == kCustomTabTrue);
}
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_source.h b/chromium/components/ukm/ukm_source.h
index 928144be056..6492cd1cf5b 100644
--- a/chromium/components/ukm/ukm_source.h
+++ b/chromium/components/ukm/ukm_source.h
@@ -5,22 +5,27 @@
#ifndef COMPONENTS_UKM_UKM_SOURCE_H_
#define COMPONENTS_UKM_UKM_SOURCE_H_
-#include <stddef.h>
#include <map>
#include "base/macros.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace ukm {
class Source;
-typedef int64_t SourceId;
-
// Contains UKM data for a single navigation entry.
class UkmSource {
public:
+ enum CustomTabState {
+ kCustomTabUnset,
+ kCustomTabTrue,
+ kCustomTabFalse,
+ };
+
UkmSource();
~UkmSource();
@@ -43,6 +48,9 @@ class UkmSource {
// Serializes the members of the class into the supplied proto.
void PopulateProto(Source* proto_source) const;
+ // Sets the current "custom tab" state. This can be called from any thread.
+ static void SetCustomTabVisible(bool visible);
+
private:
ukm::SourceId id_;
@@ -53,6 +61,11 @@ class UkmSource {
// the URL changed over the lifetime of this source).
GURL initial_url_;
+ // A flag indicating if metric was collected in a custom tab. This is set
+ // automatically when the object is created and so represents the state when
+ // the metric was created.
+ const CustomTabState custom_tab_state_;
+
DISALLOW_COPY_AND_ASSIGN(UkmSource);
};
diff --git a/chromium/components/update_client/BUILD.gn b/chromium/components/update_client/BUILD.gn
index 545210a9a5a..23ac41f0ab8 100644
--- a/chromium/components/update_client/BUILD.gn
+++ b/chromium/components/update_client/BUILD.gn
@@ -37,6 +37,7 @@ static_library("update_client") {
"task.h",
"task_send_uninstall_ping.cc",
"task_send_uninstall_ping.h",
+ "task_traits.h",
"task_update.cc",
"task_update.h",
"update_checker.cc",
diff --git a/chromium/components/update_client/action_runner.cc b/chromium/components/update_client/action_runner.cc
index 0cc68d02861..125b6db7523 100644
--- a/chromium/components/update_client/action_runner.cc
+++ b/chromium/components/update_client/action_runner.cc
@@ -13,19 +13,18 @@
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/update_client/component.h"
+#include "components/update_client/task_traits.h"
#include "components/update_client/update_client.h"
namespace update_client {
-ActionRunner::ActionRunner(
- const Component& component,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner,
- const std::vector<uint8_t>& key_hash)
+ActionRunner::ActionRunner(const Component& component,
+ const std::vector<uint8_t>& key_hash)
: component_(component),
- task_runner_(task_runner),
key_hash_(key_hash),
main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
@@ -38,39 +37,34 @@ void ActionRunner::Run(const Callback& run_complete) {
run_complete_ = run_complete;
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&ActionRunner::Unpack, base::Unretained(this)));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ActionRunner::Unpack, base::Unretained(this)));
}
void ActionRunner::Unpack() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
const auto& installer = component_.crx_component().installer;
base::FilePath file_path;
installer->GetInstalledFile(component_.action_run(), &file_path);
- auto unpacker = base::MakeRefCounted<ComponentUnpacker>(
- key_hash_, file_path, installer, nullptr, task_runner_);
-
+ auto unpacker = base::MakeRefCounted<ComponentUnpacker>(key_hash_, file_path,
+ installer, nullptr);
unpacker->Unpack(
base::Bind(&ActionRunner::UnpackComplete, base::Unretained(this)));
}
void ActionRunner::UnpackComplete(const ComponentUnpacker::Result& result) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
if (result.error != UnpackerError::kNone) {
DCHECK(!base::DirectoryExists(result.unpack_path));
main_task_runner_->PostTask(
FROM_HERE,
- base::Bind(run_complete_, false, static_cast<int>(result.error),
- result.extended_error));
+ base::BindOnce(run_complete_, false, static_cast<int>(result.error),
+ result.extended_error));
return;
}
- task_runner_->PostTask(
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&ActionRunner::RunCommand, base::Unretained(this),
MakeCommandLine(result.unpack_path)));
@@ -79,10 +73,8 @@ void ActionRunner::UnpackComplete(const ComponentUnpacker::Result& result) {
#if !defined(OS_WIN)
void ActionRunner::RunCommand(const base::CommandLine& cmdline) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
main_task_runner_->PostTask(FROM_HERE,
- base::Bind(run_complete_, false, -1, 0));
+ base::BindOnce(run_complete_, false, -1, 0));
}
base::CommandLine ActionRunner::MakeCommandLine(
diff --git a/chromium/components/update_client/action_runner.h b/chromium/components/update_client/action_runner.h
index b253ae0ccff..84c14ed56f8 100644
--- a/chromium/components/update_client/action_runner.h
+++ b/chromium/components/update_client/action_runner.h
@@ -20,7 +20,7 @@
namespace base {
class CommandLine;
class Process;
-class SequencedTaskRunner;
+class SingleThreadTaskRunner;
}
namespace update_client {
@@ -33,7 +33,6 @@ class ActionRunner {
base::Callback<void(bool succeeded, int error_code, int extra_code1)>;
ActionRunner(const Component& component,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const std::vector<uint8_t>& key_hash);
~ActionRunner();
@@ -50,14 +49,13 @@ class ActionRunner {
void WaitForCommand(base::Process process);
const Component& component_;
- const scoped_refptr<base::SequencedTaskRunner>& task_runner_;
// Contains the key hash of the CRX this object is allowed to run. This value
// is using during the unpacking of the CRX to verify its integrity.
const std::vector<uint8_t> key_hash_;
// Used to post callbacks to the main thread.
- scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
Callback run_complete_;
diff --git a/chromium/components/update_client/action_runner_win.cc b/chromium/components/update_client/action_runner_win.cc
index f6ce555a90e..3e082b96a70 100644
--- a/chromium/components/update_client/action_runner_win.cc
+++ b/chromium/components/update_client/action_runner_win.cc
@@ -11,8 +11,9 @@
#include "base/location.h"
#include "base/process/launch.h"
#include "base/process/process.h"
-#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_scheduler/post_task.h"
+#include "components/update_client/task_traits.h"
namespace {
@@ -24,17 +25,12 @@ const base::FilePath::CharType kRecoveryFileName[] =
namespace update_client {
void ActionRunner::RunCommand(const base::CommandLine& cmdline) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
base::LaunchOptions options;
options.start_hidden = true;
base::Process process = base::LaunchProcess(cmdline, options);
- // This task joins a process, hence .WithBaseSyncPrimitives().
base::PostTaskWithTraits(
- FROM_HERE,
- {base::WithBaseSyncPrimitives(), base::TaskPriority::BACKGROUND,
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+ FROM_HERE, kTaskTraitsRunCommand,
base::BindOnce(&ActionRunner::WaitForCommand, base::Unretained(this),
std::move(process)));
}
@@ -44,9 +40,8 @@ void ActionRunner::WaitForCommand(base::Process process) {
const base::TimeDelta kMaxWaitTime = base::TimeDelta::FromSeconds(600);
const bool succeeded =
process.WaitForExitWithTimeout(kMaxWaitTime, &exit_code);
-
main_task_runner_->PostTask(
- FROM_HERE, base::Bind(run_complete_, succeeded, exit_code, 0));
+ FROM_HERE, base::BindOnce(run_complete_, succeeded, exit_code, 0));
}
base::CommandLine ActionRunner::MakeCommandLine(
diff --git a/chromium/components/update_client/background_downloader_win.cc b/chromium/components/update_client/background_downloader_win.cc
index feaef33a682..f4f82d19b13 100644
--- a/chromium/components/update_client/background_downloader_win.cc
+++ b/chromium/components/update_client/background_downloader_win.cc
@@ -30,6 +30,7 @@
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "base/win/scoped_co_mem.h"
+#include "components/update_client/task_traits.h"
#include "components/update_client/update_client_errors.h"
#include "components/update_client/utils.h"
#include "url/gurl.h"
@@ -398,13 +399,10 @@ void CleanupJob(const ComPtr<IBackgroundCopyJob>& job) {
} // namespace
BackgroundDownloader::BackgroundDownloader(
- std::unique_ptr<CrxDownloader> successor,
- net::URLRequestContextGetter* context_getter)
+ std::unique_ptr<CrxDownloader> successor)
: CrxDownloader(std::move(successor)),
com_task_runner_(base::CreateCOMSTATaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
- context_getter_(context_getter),
+ kTaskTraitsBackgroundDownloader)),
git_cookie_bits_manager_(0),
git_cookie_job_(0) {}
@@ -422,15 +420,15 @@ void BackgroundDownloader::StartTimer() {
void BackgroundDownloader::OnTimer() {
DCHECK(thread_checker_.CalledOnValidThread());
com_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundDownloader::OnDownloading, base::Unretained(this)));
+ FROM_HERE, base::BindOnce(&BackgroundDownloader::OnDownloading,
+ base::Unretained(this)));
}
void BackgroundDownloader::DoStartDownload(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
- com_task_runner_->PostTask(FROM_HERE,
- base::Bind(&BackgroundDownloader::BeginDownload,
- base::Unretained(this), url));
+ com_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&BackgroundDownloader::BeginDownload,
+ base::Unretained(this), url));
}
// Called one time when this class is asked to do a download.
@@ -447,9 +445,9 @@ void BackgroundDownloader::BeginDownload(const GURL& url) {
}
ResetInterfacePointers();
- main_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundDownloader::StartTimer, base::Unretained(this)));
+ main_task_runner()->PostTask(FROM_HERE,
+ base::BindOnce(&BackgroundDownloader::StartTimer,
+ base::Unretained(this)));
}
// Creates or opens an existing BITS job to download the |url|, and handles
@@ -538,9 +536,9 @@ void BackgroundDownloader::OnDownloading() {
return;
ResetInterfacePointers();
- main_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundDownloader::StartTimer, base::Unretained(this)));
+ main_task_runner()->PostTask(FROM_HERE,
+ base::BindOnce(&BackgroundDownloader::StartTimer,
+ base::Unretained(this)));
}
// Completes the BITS download, picks up the file path of the response, and
@@ -584,9 +582,9 @@ void BackgroundDownloader::EndDownload(HRESULT error) {
result.downloaded_bytes = downloaded_bytes;
result.total_bytes = total_bytes;
main_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundDownloader::OnDownloadComplete,
- base::Unretained(this), is_handled, result, download_metrics));
+ FROM_HERE, base::BindOnce(&BackgroundDownloader::OnDownloadComplete,
+ base::Unretained(this), is_handled, result,
+ download_metrics));
// Once the task is posted to the the main thread, this object may be deleted
// by its owner. It is not safe to access members of this object on this task
@@ -674,8 +672,8 @@ bool BackgroundDownloader::OnStateTransferring() {
result.total_bytes = total_bytes;
main_task_runner()->PostTask(
- FROM_HERE, base::Bind(&BackgroundDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&BackgroundDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
return false;
}
diff --git a/chromium/components/update_client/background_downloader_win.h b/chromium/components/update_client/background_downloader_win.h
index 7549b709455..28b96938642 100644
--- a/chromium/components/update_client/background_downloader_win.h
+++ b/chromium/components/update_client/background_downloader_win.h
@@ -38,10 +38,8 @@ namespace update_client {
// a sequenced task runner, which handles all client COM interaction with
// the BITS service.
class BackgroundDownloader : public CrxDownloader {
- protected:
- friend class CrxDownloader;
- BackgroundDownloader(std::unique_ptr<CrxDownloader> successor,
- net::URLRequestContextGetter* context_getter);
+ public:
+ explicit BackgroundDownloader(std::unique_ptr<CrxDownloader> successor);
~BackgroundDownloader() override;
private:
@@ -129,8 +127,6 @@ class BackgroundDownloader : public CrxDownloader {
// Executes blocking COM calls to BITS.
scoped_refptr<base::SequencedTaskRunner> com_task_runner_;
- net::URLRequestContextGetter* context_getter_;
-
// The timer has thread affinity. This member is initialized and destroyed
// on the main task runner.
std::unique_ptr<base::OneShotTimer> timer_;
diff --git a/chromium/components/update_client/component.cc b/chromium/components/update_client/component.cc
index 750ee8ae18d..cd2b0d88d3b 100644
--- a/chromium/components/update_client/component.cc
+++ b/chromium/components/update_client/component.cc
@@ -14,11 +14,13 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/update_client/action_runner.h"
#include "components/update_client/component_unpacker.h"
#include "components/update_client/configurator.h"
#include "components/update_client/protocol_builder.h"
+#include "components/update_client/task_traits.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"
#include "components/update_client/update_engine.h"
@@ -64,14 +66,10 @@ using InstallOnBlockingTaskRunnerCompleteCallback =
base::Callback<void(int error_category, int error_code, int extra_code1)>;
CrxInstaller::Result DoInstallOnBlockingTaskRunner(
- const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
const base::FilePath& unpack_path,
const std::string& fingerprint,
const scoped_refptr<CrxInstaller>& installer,
InstallOnBlockingTaskRunnerCompleteCallback callback) {
- DCHECK(blocking_task_runner->RunsTasksInCurrentSequence());
-
if (static_cast<int>(fingerprint.size()) !=
base::WriteFile(
unpack_path.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
@@ -88,70 +86,60 @@ CrxInstaller::Result DoInstallOnBlockingTaskRunner(
void InstallOnBlockingTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
const base::FilePath& unpack_path,
const std::string& fingerprint,
const scoped_refptr<CrxInstaller>& installer,
InstallOnBlockingTaskRunnerCompleteCallback callback) {
- DCHECK(blocking_task_runner->RunsTasksInCurrentSequence());
-
DCHECK(base::DirectoryExists(unpack_path));
- const auto result = DoInstallOnBlockingTaskRunner(
- main_task_runner, blocking_task_runner, unpack_path, fingerprint,
- installer, callback);
+ const auto result = DoInstallOnBlockingTaskRunner(unpack_path, fingerprint,
+ installer, callback);
base::DeleteFile(unpack_path, true);
const ErrorCategory error_category =
result.error ? ErrorCategory::kInstallError : ErrorCategory::kErrorNone;
main_task_runner->PostTask(
FROM_HERE,
- base::Bind(callback, static_cast<int>(error_category),
- static_cast<int>(result.error), result.extended_error));
+ base::BindOnce(callback, static_cast<int>(error_category),
+ static_cast<int>(result.error), result.extended_error));
}
void UnpackCompleteOnBlockingTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
const base::FilePath& crx_path,
const std::string& fingerprint,
const scoped_refptr<CrxInstaller>& installer,
InstallOnBlockingTaskRunnerCompleteCallback callback,
const ComponentUnpacker::Result& result) {
- DCHECK(blocking_task_runner->RunsTasksInCurrentSequence());
-
update_client::DeleteFileAndEmptyParentDirectory(crx_path);
if (result.error != UnpackerError::kNone) {
main_task_runner->PostTask(
FROM_HERE,
- base::Bind(callback, static_cast<int>(ErrorCategory::kUnpackError),
- static_cast<int>(result.error), result.extended_error));
+ base::BindOnce(callback, static_cast<int>(ErrorCategory::kUnpackError),
+ static_cast<int>(result.error), result.extended_error));
return;
}
- blocking_task_runner->PostTask(
- FROM_HERE, base::Bind(&InstallOnBlockingTaskRunner, main_task_runner,
- blocking_task_runner, result.unpack_path,
- fingerprint, installer, callback));
+ base::PostTaskWithTraits(
+ FROM_HERE, kTaskTraits,
+ base::BindOnce(&InstallOnBlockingTaskRunner, main_task_runner,
+ result.unpack_path, fingerprint, installer, callback));
}
void StartInstallOnBlockingTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
const std::vector<uint8_t>& pk_hash,
const base::FilePath& crx_path,
const std::string& fingerprint,
const scoped_refptr<CrxInstaller>& installer,
const scoped_refptr<OutOfProcessPatcher>& oop_patcher,
InstallOnBlockingTaskRunnerCompleteCallback callback) {
- DCHECK(blocking_task_runner->RunsTasksInCurrentSequence());
-
auto unpacker = base::MakeRefCounted<ComponentUnpacker>(
- pk_hash, crx_path, installer, oop_patcher, blocking_task_runner);
+ pk_hash, crx_path, installer, oop_patcher);
unpacker->Unpack(base::Bind(&UnpackCompleteOnBlockingTaskRunner,
- main_task_runner, blocking_task_runner, crx_path,
- fingerprint, installer, callback));
+ main_task_runner, crx_path, fingerprint,
+ installer, callback));
}
} // namespace
@@ -296,7 +284,7 @@ void Component::State::TransitionState(std::unique_ptr<State> next_state) {
is_final_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback(), base::Passed(&next_state)));
+ FROM_HERE, base::BindOnce(callback(), base::Passed(&next_state)));
}
Component::StateNew::StateNew(Component* component)
@@ -583,16 +571,16 @@ void Component::StateUpdatingDiff::DoHandle() {
component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
- update_context.blocking_task_runner->PostTask(
- FROM_HERE,
- base::Bind(&update_client::StartInstallOnBlockingTaskRunner,
- base::ThreadTaskRunnerHandle::Get(),
- update_context.blocking_task_runner,
- component.crx_component_.pk_hash, component.crx_path_,
- component.next_fp_, component.crx_component_.installer,
- update_context.config->CreateOutOfProcessPatcher(),
- base::Bind(&Component::StateUpdatingDiff::InstallComplete,
- base::Unretained(this))));
+ base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(
+ &update_client::StartInstallOnBlockingTaskRunner,
+ base::ThreadTaskRunnerHandle::Get(),
+ component.crx_component_.pk_hash, component.crx_path_,
+ component.next_fp_, component.crx_component_.installer,
+ update_context.config->CreateOutOfProcessPatcher(),
+ base::Bind(&Component::StateUpdatingDiff::InstallComplete,
+ base::Unretained(this))));
}
void Component::StateUpdatingDiff::InstallComplete(int error_category,
@@ -642,16 +630,16 @@ void Component::StateUpdating::DoHandle() {
component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
- update_context.blocking_task_runner->PostTask(
- FROM_HERE,
- base::Bind(&update_client::StartInstallOnBlockingTaskRunner,
- base::ThreadTaskRunnerHandle::Get(),
- update_context.blocking_task_runner,
- component.crx_component_.pk_hash, component.crx_path_,
- component.next_fp_, component.crx_component_.installer,
- update_context.config->CreateOutOfProcessPatcher(),
- base::Bind(&Component::StateUpdating::InstallComplete,
- base::Unretained(this))));
+ base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
+ ->PostTask(
+ FROM_HERE,
+ base::BindOnce(&update_client::StartInstallOnBlockingTaskRunner,
+ base::ThreadTaskRunnerHandle::Get(),
+ component.crx_component_.pk_hash, component.crx_path_,
+ component.next_fp_, component.crx_component_.installer,
+ update_context.config->CreateOutOfProcessPatcher(),
+ base::Bind(&Component::StateUpdating::InstallComplete,
+ base::Unretained(this))));
}
void Component::StateUpdating::InstallComplete(int error_category,
@@ -733,8 +721,7 @@ void Component::StateRun::DoHandle() {
const auto& component = State::component();
action_runner_ = base::MakeUnique<ActionRunner>(
- component, component.update_context_.blocking_task_runner,
- component.update_context_.config->GetRunActionKeyHash());
+ component, component.update_context_.config->GetRunActionKeyHash());
action_runner_->Run(
base::Bind(&StateRun::ActionRunComplete, base::Unretained(this)));
diff --git a/chromium/components/update_client/component_patcher.cc b/chromium/components/update_client/component_patcher.cc
index 0bd27dd2776..a69860c5b85 100644
--- a/chromium/components/update_client/component_patcher.cc
+++ b/chromium/components/update_client/component_patcher.cc
@@ -14,6 +14,7 @@
#include "base/json/json_file_value_serializer.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/values.h"
#include "components/update_client/component_patcher_operation.h"
#include "components/update_client/update_client.h"
@@ -45,23 +46,20 @@ ComponentPatcher::ComponentPatcher(
const base::FilePath& input_dir,
const base::FilePath& unpack_dir,
scoped_refptr<CrxInstaller> installer,
- scoped_refptr<OutOfProcessPatcher> out_of_process_patcher,
- scoped_refptr<base::SequencedTaskRunner> task_runner)
+ scoped_refptr<OutOfProcessPatcher> out_of_process_patcher)
: input_dir_(input_dir),
unpack_dir_(unpack_dir),
installer_(installer),
- out_of_process_patcher_(out_of_process_patcher),
- task_runner_(task_runner) {
-}
+ out_of_process_patcher_(out_of_process_patcher) {}
ComponentPatcher::~ComponentPatcher() {
}
void ComponentPatcher::Start(const Callback& callback) {
callback_ = callback;
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&ComponentPatcher::StartPatching,
- scoped_refptr<ComponentPatcher>(this)));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ComponentPatcher::StartPatching,
+ scoped_refptr<ComponentPatcher>(this)));
}
void ComponentPatcher::StartPatching() {
@@ -97,8 +95,7 @@ void ComponentPatcher::PatchNextFile() {
}
current_operation_->Run(command_args, input_dir_, unpack_dir_, installer_,
base::Bind(&ComponentPatcher::DonePatchingFile,
- scoped_refptr<ComponentPatcher>(this)),
- task_runner_);
+ scoped_refptr<ComponentPatcher>(this)));
}
void ComponentPatcher::DonePatchingFile(UnpackerError error,
@@ -113,8 +110,8 @@ void ComponentPatcher::DonePatchingFile(UnpackerError error,
void ComponentPatcher::DonePatching(UnpackerError error, int extended_error) {
current_operation_ = NULL;
- task_runner_->PostTask(FROM_HERE,
- base::Bind(callback_, error, extended_error));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback_, error, extended_error));
callback_.Reset();
}
diff --git a/chromium/components/update_client/component_patcher.h b/chromium/components/update_client/component_patcher.h
index 3302d177305..2179778ad94 100644
--- a/chromium/components/update_client/component_patcher.h
+++ b/chromium/components/update_client/component_patcher.h
@@ -32,7 +32,6 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
#include "base/values.h"
#include "components/update_client/component_unpacker.h"
@@ -67,8 +66,7 @@ class ComponentPatcher : public base::RefCountedThreadSafe<ComponentPatcher> {
ComponentPatcher(const base::FilePath& input_dir,
const base::FilePath& unpack_dir,
scoped_refptr<CrxInstaller> installer,
- scoped_refptr<OutOfProcessPatcher> out_of_process_patcher,
- scoped_refptr<base::SequencedTaskRunner> task_runner);
+ scoped_refptr<OutOfProcessPatcher> out_of_process_patcher);
// Starts patching files. This member function returns immediately, after
// posting a task to do the patching. When patching has been completed,
@@ -97,7 +95,6 @@ class ComponentPatcher : public base::RefCountedThreadSafe<ComponentPatcher> {
std::unique_ptr<base::ListValue> commands_;
base::ListValue::const_iterator next_command_;
scoped_refptr<DeltaUpdateOp> current_operation_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(ComponentPatcher);
};
diff --git a/chromium/components/update_client/component_patcher_operation.cc b/chromium/components/update_client/component_patcher_operation.cc
index be7be1f3208..6fbde6b7aef 100644
--- a/chromium/components/update_client/component_patcher_operation.cc
+++ b/chromium/components/update_client/component_patcher_operation.cc
@@ -12,6 +12,8 @@
#include "base/files/memory_mapped_file.h"
#include "base/location.h"
#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/update_client/out_of_process_patcher.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"
@@ -57,15 +59,12 @@ DeltaUpdateOp::DeltaUpdateOp() {
DeltaUpdateOp::~DeltaUpdateOp() {
}
-void DeltaUpdateOp::Run(
- const base::DictionaryValue* command_args,
- const base::FilePath& input_dir,
- const base::FilePath& unpack_dir,
- const scoped_refptr<CrxInstaller>& installer,
- const ComponentPatcher::Callback& callback,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+void DeltaUpdateOp::Run(const base::DictionaryValue* command_args,
+ const base::FilePath& input_dir,
+ const base::FilePath& unpack_dir,
+ const scoped_refptr<CrxInstaller>& installer,
+ const ComponentPatcher::Callback& callback) {
callback_ = callback;
- task_runner_ = task_runner;
std::string output_rel_path;
if (!command_args->GetString(kOutput, &output_rel_path) ||
!command_args->GetString(kSha256, &output_sha256_)) {
@@ -97,8 +96,8 @@ void DeltaUpdateOp::Run(
void DeltaUpdateOp::DoneRunning(UnpackerError error, int extended_error) {
if (error == UnpackerError::kNone)
error = CheckHash();
- task_runner_->PostTask(FROM_HERE,
- base::Bind(callback_, error, extended_error));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback_, error, extended_error));
callback_.Reset();
}
@@ -110,10 +109,6 @@ UnpackerError DeltaUpdateOp::CheckHash() {
: UnpackerError::kDeltaVerificationFailure;
}
-scoped_refptr<base::SequencedTaskRunner> DeltaUpdateOp::GetTaskRunner() {
- return task_runner_;
-}
-
DeltaUpdateOpCopy::DeltaUpdateOpCopy() {
}
@@ -200,8 +195,7 @@ UnpackerError DeltaUpdateOpPatch::DoParseArguments(
void DeltaUpdateOpPatch::DoRun(const ComponentPatcher::Callback& callback) {
if (out_of_process_patcher_.get()) {
out_of_process_patcher_->Patch(
- operation_, GetTaskRunner(), input_abs_path_, patch_abs_path_,
- output_abs_path_,
+ operation_, input_abs_path_, patch_abs_path_, output_abs_path_,
base::Bind(&DeltaUpdateOpPatch::DonePatching, this, callback));
return;
}
diff --git a/chromium/components/update_client/component_patcher_operation.h b/chromium/components/update_client/component_patcher_operation.h
index 4520b986ffb..553f76f8d49 100644
--- a/chromium/components/update_client/component_patcher_operation.h
+++ b/chromium/components/update_client/component_patcher_operation.h
@@ -11,7 +11,6 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
#include "components/update_client/component_patcher.h"
#include "components/update_client/component_unpacker.h"
@@ -41,14 +40,11 @@ class DeltaUpdateOp : public base::RefCountedThreadSafe<DeltaUpdateOp> {
const base::FilePath& input_dir,
const base::FilePath& unpack_dir,
const scoped_refptr<CrxInstaller>& installer,
- const ComponentPatcher::Callback& callback,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+ const ComponentPatcher::Callback& callback);
protected:
virtual ~DeltaUpdateOp();
- scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
-
std::string output_sha256_;
base::FilePath output_abs_path_;
@@ -76,7 +72,6 @@ class DeltaUpdateOp : public base::RefCountedThreadSafe<DeltaUpdateOp> {
void DoneRunning(UnpackerError error, int extended_error);
ComponentPatcher::Callback callback_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOp);
};
diff --git a/chromium/components/update_client/component_patcher_unittest.cc b/chromium/components/update_client/component_patcher_unittest.cc
index 19876268423..b6dfe2cbfed 100644
--- a/chromium/components/update_client/component_patcher_unittest.cc
+++ b/chromium/components/update_client/component_patcher_unittest.cc
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/update_client/component_patcher.h"
#include "components/update_client/component_patcher_operation.h"
@@ -63,12 +62,14 @@ base::FilePath test_file(const char* file) {
namespace update_client {
-ComponentPatcherOperationTest::ComponentPatcherOperationTest() {
+ComponentPatcherOperationTest::ComponentPatcherOperationTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {
EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir());
EXPECT_TRUE(input_dir_.CreateUniqueTempDir());
EXPECT_TRUE(installed_dir_.CreateUniqueTempDir());
- installer_ = new ReadOnlyTestInstaller(installed_dir_.GetPath());
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ installer_ =
+ base::MakeRefCounted<ReadOnlyTestInstaller>(installed_dir_.GetPath());
}
ComponentPatcherOperationTest::~ComponentPatcherOperationTest() {
@@ -90,9 +91,8 @@ TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
TestCallback callback;
scoped_refptr<DeltaUpdateOp> op = new DeltaUpdateOpCreate();
op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(), NULL,
- base::Bind(&TestCallback::Set, base::Unretained(&callback)),
- task_runner_);
- base::RunLoop().RunUntilIdle();
+ base::Bind(&TestCallback::Set, base::Unretained(&callback)));
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(true, callback.called_);
EXPECT_EQ(UnpackerError::kNone, callback.error_);
@@ -119,9 +119,8 @@ TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
scoped_refptr<DeltaUpdateOp> op = new DeltaUpdateOpCopy();
op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
- base::Bind(&TestCallback::Set, base::Unretained(&callback)),
- task_runner_);
- base::RunLoop().RunUntilIdle();
+ base::Bind(&TestCallback::Set, base::Unretained(&callback)));
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(true, callback.called_);
EXPECT_EQ(UnpackerError::kNone, callback.error_);
@@ -153,9 +152,8 @@ TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
CreateDeltaUpdateOp("courgette", NULL /* out_of_process_patcher */);
op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
- base::Bind(&TestCallback::Set, base::Unretained(&callback)),
- task_runner_);
- base::RunLoop().RunUntilIdle();
+ base::Bind(&TestCallback::Set, base::Unretained(&callback)));
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(true, callback.called_);
EXPECT_EQ(UnpackerError::kNone, callback.error_);
@@ -187,9 +185,8 @@ TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) {
CreateDeltaUpdateOp("bsdiff", NULL /* out_of_process_patcher */);
op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
- base::Bind(&TestCallback::Set, base::Unretained(&callback)),
- task_runner_);
- base::RunLoop().RunUntilIdle();
+ base::Bind(&TestCallback::Set, base::Unretained(&callback)));
+ scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(true, callback.called_);
EXPECT_EQ(UnpackerError::kNone, callback.error_);
diff --git a/chromium/components/update_client/component_patcher_unittest.h b/chromium/components/update_client/component_patcher_unittest.h
index b642a7c71e6..bf5168c308a 100644
--- a/chromium/components/update_client/component_patcher_unittest.h
+++ b/chromium/components/update_client/component_patcher_unittest.h
@@ -9,8 +9,9 @@
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "base/test/scoped_task_environment.h"
#include "courgette/courgette.h"
#include "courgette/third_party/bsdiff/bsdiff.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -28,14 +29,11 @@ class ComponentPatcherOperationTest : public testing::Test {
~ComponentPatcherOperationTest() override;
protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
base::ScopedTempDir input_dir_;
base::ScopedTempDir installed_dir_;
base::ScopedTempDir unpack_dir_;
scoped_refptr<ReadOnlyTestInstaller> installer_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
- private:
- base::MessageLoopForIO loop_;
};
} // namespace update_client
diff --git a/chromium/components/update_client/component_unpacker.cc b/chromium/components/update_client/component_unpacker.cc
index 50444e80d9e..f9ef280666d 100644
--- a/chromium/components/update_client/component_unpacker.cc
+++ b/chromium/components/update_client/component_unpacker.cc
@@ -19,6 +19,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/values.h"
#include "components/crx_file/crx_verifier.h"
#include "components/update_client/component_patcher.h"
@@ -54,16 +55,14 @@ ComponentUnpacker::ComponentUnpacker(
const std::vector<uint8_t>& pk_hash,
const base::FilePath& path,
const scoped_refptr<CrxInstaller>& installer,
- const scoped_refptr<OutOfProcessPatcher>& oop_patcher,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+ const scoped_refptr<OutOfProcessPatcher>& oop_patcher)
: pk_hash_(pk_hash),
path_(path),
is_delta_(false),
installer_(installer),
oop_patcher_(oop_patcher),
error_(UnpackerError::kNone),
- extended_error_(0),
- task_runner_(task_runner) {}
+ extended_error_(0) {}
ComponentUnpacker::~ComponentUnpacker() {}
@@ -125,18 +124,18 @@ bool ComponentUnpacker::BeginPatching() {
error_ = UnpackerError::kUnzipPathError;
return false;
}
- patcher_ = new ComponentPatcher(unpack_diff_path_, unpack_path_, installer_,
- oop_patcher_, task_runner_);
- task_runner_->PostTask(
+ patcher_ = base::MakeRefCounted<ComponentPatcher>(
+ unpack_diff_path_, unpack_path_, installer_, oop_patcher_);
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&ComponentPatcher::Start, patcher_,
- base::Bind(&ComponentUnpacker::EndPatching,
- scoped_refptr<ComponentUnpacker>(this))));
+ base::BindOnce(&ComponentPatcher::Start, patcher_,
+ base::Bind(&ComponentUnpacker::EndPatching,
+ scoped_refptr<ComponentUnpacker>(this))));
} else {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&ComponentUnpacker::EndPatching,
- scoped_refptr<ComponentUnpacker>(this),
- UnpackerError::kNone, 0));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ComponentUnpacker::EndPatching,
+ scoped_refptr<ComponentUnpacker>(this),
+ UnpackerError::kNone, 0));
}
return true;
}
@@ -161,7 +160,8 @@ void ComponentUnpacker::EndUnpacking() {
if (error_ == UnpackerError::kNone)
result.unpack_path = unpack_path_;
- task_runner_->PostTask(FROM_HERE, base::Bind(callback_, result));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback_, result));
}
} // namespace update_client
diff --git a/chromium/components/update_client/component_unpacker.h b/chromium/components/update_client/component_unpacker.h
index 54fc6a9094c..d0b5259fb5c 100644
--- a/chromium/components/update_client/component_unpacker.h
+++ b/chromium/components/update_client/component_unpacker.h
@@ -16,7 +16,6 @@
#include "base/json/json_file_value_serializer.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
#include "components/update_client/out_of_process_patcher.h"
#include "components/update_client/update_client_errors.h"
@@ -84,12 +83,10 @@ class ComponentUnpacker : public base::RefCountedThreadSafe<ComponentUnpacker> {
// Constructs an unpacker for a specific component unpacking operation.
// |pk_hash| is the expected/ public key SHA256 hash. |path| is the current
// location of the CRX.
- ComponentUnpacker(
- const std::vector<uint8_t>& pk_hash,
- const base::FilePath& path,
- const scoped_refptr<CrxInstaller>& installer,
- const scoped_refptr<OutOfProcessPatcher>& oop_patcher,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+ ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
+ const base::FilePath& path,
+ const scoped_refptr<CrxInstaller>& installer,
+ const scoped_refptr<OutOfProcessPatcher>& oop_patcher);
// Begins the actual unpacking of the files. May invoke a patcher and the
// component installer if the package is a differential update.
@@ -135,7 +132,6 @@ class ComponentUnpacker : public base::RefCountedThreadSafe<ComponentUnpacker> {
scoped_refptr<OutOfProcessPatcher> oop_patcher_;
UnpackerError error_;
int extended_error_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(ComponentUnpacker);
};
diff --git a/chromium/components/update_client/component_unpacker_unittest.cc b/chromium/components/update_client/component_unpacker_unittest.cc
index 1488c3273a8..65eca6d7049 100644
--- a/chromium/components/update_client/component_unpacker_unittest.cc
+++ b/chromium/components/update_client/component_unpacker_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task_scheduler/post_task.h"
@@ -78,24 +79,14 @@ class ComponentUnpackerTest : public testing::Test {
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_ =
base::ThreadTaskRunnerHandle::Get();
base::RunLoop runloop_;
- base::Closure quit_closure_;
-
- scoped_refptr<update_client::TestConfigurator> config_;
+ const base::Closure quit_closure_ = runloop_.QuitClosure();
ComponentUnpacker::Result result_;
};
-ComponentUnpackerTest::ComponentUnpackerTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI) {
- quit_closure_ = runloop_.QuitClosure();
-
- config_ = new TestConfigurator(
- base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
- base::ThreadTaskRunnerHandle::Get());
-}
+ComponentUnpackerTest::ComponentUnpackerTest() = default;
-ComponentUnpackerTest::~ComponentUnpackerTest() {}
+ComponentUnpackerTest::~ComponentUnpackerTest() = default;
void ComponentUnpackerTest::RunThreads() {
runloop_.Run();
@@ -108,10 +99,10 @@ void ComponentUnpackerTest::UnpackComplete(
}
TEST_F(ComponentUnpackerTest, UnpackFullCrx) {
- scoped_refptr<ComponentUnpacker> component_unpacker = new ComponentUnpacker(
- std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"), nullptr, nullptr,
- config_->GetSequencedTaskRunner());
+ scoped_refptr<ComponentUnpacker> component_unpacker =
+ base::MakeRefCounted<ComponentUnpacker>(
+ std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)),
+ test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"), nullptr, nullptr);
component_unpacker->Unpack(base::Bind(&ComponentUnpackerTest::UnpackComplete,
base::Unretained(this)));
RunThreads();
@@ -138,10 +129,10 @@ TEST_F(ComponentUnpackerTest, UnpackFullCrx) {
}
TEST_F(ComponentUnpackerTest, UnpackFileNotFound) {
- scoped_refptr<ComponentUnpacker> component_unpacker = new ComponentUnpacker(
- std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)),
- test_file("file-not-found.crx"), nullptr, nullptr,
- config_->GetSequencedTaskRunner());
+ scoped_refptr<ComponentUnpacker> component_unpacker =
+ base::MakeRefCounted<ComponentUnpacker>(
+ std::vector<uint8_t>(std::begin(jebg_hash), std::end(jebg_hash)),
+ test_file("file-not-found.crx"), nullptr, nullptr);
component_unpacker->Unpack(base::Bind(&ComponentUnpackerTest::UnpackComplete,
base::Unretained(this)));
RunThreads();
@@ -155,10 +146,10 @@ TEST_F(ComponentUnpackerTest, UnpackFileNotFound) {
// Tests a mismatch between the public key hash and the id of the component.
TEST_F(ComponentUnpackerTest, UnpackFileHashMismatch) {
- scoped_refptr<ComponentUnpacker> component_unpacker = new ComponentUnpacker(
- std::vector<uint8_t>(std::begin(abag_hash), std::end(abag_hash)),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"), nullptr, nullptr,
- config_->GetSequencedTaskRunner());
+ scoped_refptr<ComponentUnpacker> component_unpacker =
+ base::MakeRefCounted<ComponentUnpacker>(
+ std::vector<uint8_t>(std::begin(abag_hash), std::end(abag_hash)),
+ test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"), nullptr, nullptr);
component_unpacker->Unpack(base::Bind(&ComponentUnpackerTest::UnpackComplete,
base::Unretained(this)));
RunThreads();
diff --git a/chromium/components/update_client/configurator.h b/chromium/components/update_client/configurator.h
index ddb5b5d29f6..44a2d04e018 100644
--- a/chromium/components/update_client/configurator.h
+++ b/chromium/components/update_client/configurator.h
@@ -15,7 +15,6 @@ class GURL;
class PrefService;
namespace base {
-class SequencedTaskRunner;
class Version;
}
@@ -116,10 +115,6 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
// True if signing of update checks is enabled.
virtual bool EnabledCupSigning() const = 0;
- // Gets a task runner to a blocking pool of threads suitable for worker jobs.
- virtual scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
- const = 0;
-
// Returns a PrefService that the update_client can use to store persistent
// update information. The PrefService must outlive the entire update_client,
// and be safe to access from the thread the update_client is constructed
diff --git a/chromium/components/update_client/crx_downloader.cc b/chromium/components/update_client/crx_downloader.cc
index afdfdbf6d8f..b75be30172c 100644
--- a/chromium/components/update_client/crx_downloader.cc
+++ b/chromium/components/update_client/crx_downloader.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -18,6 +19,7 @@
#if defined(OS_WIN)
#include "components/update_client/background_downloader_win.h"
#endif
+#include "components/update_client/task_traits.h"
#include "components/update_client/update_client_errors.h"
#include "components/update_client/url_fetcher_downloader.h"
#include "components/update_client/utils.h"
@@ -41,13 +43,13 @@ CrxDownloader::DownloadMetrics::DownloadMetrics()
std::unique_ptr<CrxDownloader> CrxDownloader::Create(
bool is_background_download,
net::URLRequestContextGetter* context_getter) {
- std::unique_ptr<CrxDownloader> url_fetcher_downloader(
- std::unique_ptr<CrxDownloader>(new UrlFetcherDownloader(
- std::unique_ptr<CrxDownloader>(), context_getter)));
+ std::unique_ptr<CrxDownloader> url_fetcher_downloader =
+ base::MakeUnique<UrlFetcherDownloader>(nullptr, context_getter);
+
#if defined(OS_WIN)
if (is_background_download) {
- return std::unique_ptr<CrxDownloader>(new BackgroundDownloader(
- std::move(url_fetcher_downloader), context_getter));
+ return base::MakeUnique<BackgroundDownloader>(
+ std::move(url_fetcher_downloader));
}
#endif
@@ -105,7 +107,7 @@ void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
Result result;
result.error = static_cast<int>(error);
main_task_runner()->PostTask(FROM_HERE,
- base::Bind(download_callback, result));
+ base::BindOnce(download_callback, result));
return;
}
@@ -125,16 +127,14 @@ void CrxDownloader::OnDownloadComplete(
if (!result.error)
base::PostTaskWithTraits(
- FROM_HERE,
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
- base::Bind(&CrxDownloader::VerifyResponse, base::Unretained(this),
- is_handled, result, download_metrics));
+ FROM_HERE, kTaskTraits,
+ base::BindOnce(&CrxDownloader::VerifyResponse, base::Unretained(this),
+ is_handled, result, download_metrics));
else
main_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
- is_handled, result, download_metrics));
+ FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
+ base::Unretained(this), is_handled, result,
+ download_metrics));
}
void CrxDownloader::OnDownloadProgress(const Result& result) {
@@ -158,7 +158,7 @@ void CrxDownloader::VerifyResponse(bool is_handled,
if (VerifyFileHash256(result.response, expected_hash_)) {
download_metrics_.push_back(download_metrics);
main_task_runner()->PostTask(FROM_HERE,
- base::Bind(download_callback_, result));
+ base::BindOnce(download_callback_, result));
return;
}
@@ -171,9 +171,9 @@ void CrxDownloader::VerifyResponse(bool is_handled,
result.response.clear();
main_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
- is_handled, result, download_metrics));
+ FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
+ base::Unretained(this), is_handled, result,
+ download_metrics));
}
void CrxDownloader::HandleDownloadError(
@@ -212,7 +212,7 @@ void CrxDownloader::HandleDownloadError(
// The download ends here since there is no url nor downloader to handle this
// download request further.
main_task_runner()->PostTask(FROM_HERE,
- base::Bind(download_callback_, result));
+ base::BindOnce(download_callback_, result));
}
} // namespace update_client
diff --git a/chromium/components/update_client/crx_downloader.h b/chromium/components/update_client/crx_downloader.h
index 0b6cae8981a..6c27ca77ac7 100644
--- a/chromium/components/update_client/crx_downloader.h
+++ b/chromium/components/update_client/crx_downloader.h
@@ -15,7 +15,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "url/gurl.h"
@@ -136,7 +136,7 @@ class CrxDownloader {
// Returns the url which is currently being downloaded from.
GURL url() const;
- scoped_refptr<base::SequencedTaskRunner> main_task_runner() const {
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner() const {
return main_task_runner_;
}
@@ -154,7 +154,7 @@ class CrxDownloader {
base::ThreadChecker thread_checker_;
// Used to post callbacks to the main thread.
- scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
std::vector<GURL> urls_;
diff --git a/chromium/components/update_client/out_of_process_patcher.h b/chromium/components/update_client/out_of_process_patcher.h
index a41f01b223c..df0ee37ff79 100644
--- a/chromium/components/update_client/out_of_process_patcher.h
+++ b/chromium/components/update_client/out_of_process_patcher.h
@@ -12,7 +12,6 @@
namespace base {
class FilePath;
-class SequencedTaskRunner;
}
namespace update_client {
@@ -23,7 +22,6 @@ class OutOfProcessPatcher
public:
virtual void Patch(
const std::string& operation,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& input_abs_path,
const base::FilePath& patch_abs_path,
const base::FilePath& output_abs_path,
diff --git a/chromium/components/update_client/ping_manager.cc b/chromium/components/update_client/ping_manager.cc
index 66d9e2b970c..50d7b2cbe8a 100644
--- a/chromium/components/update_client/ping_manager.cc
+++ b/chromium/components/update_client/ping_manager.cc
@@ -16,7 +16,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/sequenced_task_runner.h"
#include "components/update_client/configurator.h"
#include "components/update_client/protocol_builder.h"
#include "components/update_client/request_sender.h"
diff --git a/chromium/components/update_client/ping_manager_unittest.cc b/chromium/components/update_client/ping_manager_unittest.cc
index 503a4d59528..b883d3766ab 100644
--- a/chromium/components/update_client/ping_manager_unittest.cc
+++ b/chromium/components/update_client/ping_manager_unittest.cc
@@ -50,9 +50,8 @@ class PingManagerTest : public testing::Test {
PingManagerTest::PingManagerTest() {}
void PingManagerTest::SetUp() {
- config_ = new TestConfigurator(base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- ping_manager_.reset(new PingManager(config_));
+ config_ = base::MakeRefCounted<TestConfigurator>();
+ ping_manager_ = base::MakeUnique<PingManager>(config_);
}
void PingManagerTest::TearDown() {
diff --git a/chromium/components/update_client/protocol_builder.cc b/chromium/components/update_client/protocol_builder.cc
index f8430b117a8..d662fcec75a 100644
--- a/chromium/components/update_client/protocol_builder.cc
+++ b/chromium/components/update_client/protocol_builder.cc
@@ -158,9 +158,7 @@ std::string BuildUninstalledEventElement(const Component& component) {
using base::StringAppendF;
std::string event;
- StringAppendF(&event, "<event eventtype=\"4\" extracode1=\"%d\"",
- component.extra_code1());
-
+ StringAppendF(&event, "<event eventtype=\"4\" eventresult=\"1\"");
if (component.extra_code1())
StringAppendF(&event, " extracode1=\"%d\"", component.extra_code1());
StringAppendF(&event, "/>");
diff --git a/chromium/components/update_client/request_sender.cc b/chromium/components/update_client/request_sender.cc
index 782ada6a270..af2b87b5fe7 100644
--- a/chromium/components/update_client/request_sender.cc
+++ b/chromium/components/update_client/request_sender.cc
@@ -11,7 +11,6 @@
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/client_update_protocol/ecdsa.h"
@@ -26,14 +25,14 @@ namespace update_client {
namespace {
// This is an ECDSA prime256v1 named-curve key.
-const int kKeyVersion = 7;
+constexpr int kKeyVersion = 7;
const char kKeyPubBytesBase64[] =
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj0QKufXIOBN30DtKeOYA5NV64FfY"
"HDou4sGqtcNUIlxpTzIbO45rB45QILhW6aDTwwjWLR1YCqpEAGICvFs8dQ==";
// The ETag header carries the ECSDA signature of the protocol response, if
// signing has been used.
-const char kHeaderEtag[] = "ETag";
+constexpr const char* kHeaderEtag = "ETag";
// The server uses the optional X-Retry-After header to indicate that the
// current request should not be attempted again. Any response received along
@@ -47,17 +46,11 @@ const char kHeaderEtag[] = "ETag";
// The value of the header is the number of seconds to wait before trying to do
// a subsequent update check. The upper bound for the number of seconds to wait
// before trying to do a subsequent update check is capped at 24 hours.
-const char kHeaderXRetryAfter[] = "X-Retry-After";
-const int64_t kMaxRetryAfterSec = 24 * 60 * 60;
+constexpr const char* kHeaderXRetryAfter = "X-Retry-After";
+constexpr int64_t kMaxRetryAfterSec = 24 * 60 * 60;
} // namespace
-// This value is chosen not to conflict with network errors defined by
-// net/base/net_error_list.h. The callers don't have to handle this error in
-// any meaningful way, but this value may be reported in UMA stats, therefore
-// avoiding collisions with known network errors is desirable.
-int RequestSender::kErrorResponseNotTrusted = -10000;
-
RequestSender::RequestSender(const scoped_refptr<Configurator>& config)
: config_(config), use_signing_(false) {}
@@ -111,9 +104,9 @@ void RequestSender::SendInternal() {
SendProtocolRequest(url, request_body_, this, config_->RequestContext());
if (!url_fetcher_.get())
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&RequestSender::SendInternalComplete, base::Unretained(this),
- -1, std::string(), std::string(), 0));
+ FROM_HERE, base::BindOnce(&RequestSender::SendInternalComplete,
+ base::Unretained(this), -1, std::string(),
+ std::string(), 0));
}
void RequestSender::SendInternalComplete(int error,
@@ -123,8 +116,8 @@ void RequestSender::SendInternalComplete(int error,
if (!error) {
if (!use_signing_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(request_sender_callback_, 0, response_body,
- retry_after_sec));
+ FROM_HERE, base::BindOnce(request_sender_callback_, 0, response_body,
+ retry_after_sec));
return;
}
@@ -132,8 +125,8 @@ void RequestSender::SendInternalComplete(int error,
DCHECK(signer_.get());
if (signer_->ValidateResponse(response_body, response_etag)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(request_sender_callback_, 0, response_body,
- retry_after_sec));
+ FROM_HERE, base::BindOnce(request_sender_callback_, 0, response_body,
+ retry_after_sec));
return;
}
@@ -146,8 +139,8 @@ void RequestSender::SendInternalComplete(int error,
// should not send further request until the cooldown has expired.
if (retry_after_sec <= 0 && ++cur_url_ != urls_.end() &&
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&RequestSender::SendInternal, base::Unretained(this)))) {
+ FROM_HERE, base::BindOnce(&RequestSender::SendInternal,
+ base::Unretained(this)))) {
return;
}
@@ -174,16 +167,17 @@ void RequestSender::OnURLFetchComplete(const net::URLFetcher* source) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&RequestSender::SendInternalComplete,
- base::Unretained(this), fetch_error, response_body,
- GetStringHeaderValue(source, kHeaderEtag),
- static_cast<int>(retry_after_sec)));
+ FROM_HERE,
+ base::BindOnce(&RequestSender::SendInternalComplete,
+ base::Unretained(this), fetch_error, response_body,
+ GetStringHeaderValue(source, kHeaderEtag),
+ static_cast<int>(retry_after_sec)));
}
void RequestSender::HandleSendError(int error, int retry_after_sec) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(request_sender_callback_, error, std::string(),
- retry_after_sec));
+ FROM_HERE, base::BindOnce(request_sender_callback_, error, std::string(),
+ retry_after_sec));
}
std::string RequestSender::GetKey(const char* key_bytes_base64) {
diff --git a/chromium/components/update_client/request_sender.h b/chromium/components/update_client/request_sender.h
index f1ec16e95d4..e6ecbda9035 100644
--- a/chromium/components/update_client/request_sender.h
+++ b/chromium/components/update_client/request_sender.h
@@ -45,7 +45,11 @@ class RequestSender : public net::URLFetcherDelegate {
using RequestSenderCallback = base::Callback<
void(int error, const std::string& response, int retry_after_sec)>;
- static int kErrorResponseNotTrusted;
+ // This value is chosen not to conflict with network errors defined by
+ // net/base/net_error_list.h. The callers don't have to handle this error in
+ // any meaningful way, but this value may be reported in UMA stats, therefore
+ // avoiding collisions with known network errors is desirable.
+ enum : int { kErrorResponseNotTrusted = -10000 };
explicit RequestSender(const scoped_refptr<Configurator>& config);
~RequestSender() override;
diff --git a/chromium/components/update_client/request_sender_unittest.cc b/chromium/components/update_client/request_sender_unittest.cc
index 82a07c20dd6..d96e4da7e7f 100644
--- a/chromium/components/update_client/request_sender_unittest.cc
+++ b/chromium/components/update_client/request_sender_unittest.cc
@@ -9,11 +9,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
-#include "base/test/scoped_task_scheduler.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/update_client/test_configurator.h"
#include "components/update_client/url_request_post_interceptor.h"
@@ -58,7 +57,8 @@ class RequestSenderTest : public testing::Test {
protected:
void Quit();
void RunThreads();
- void RunThreadsUntilIdle();
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<TestConfigurator> config_;
std::unique_ptr<RequestSender> request_sender_;
@@ -72,20 +72,19 @@ class RequestSenderTest : public testing::Test {
std::string response_;
private:
- base::MessageLoopForIO loop_;
- base::test::ScopedTaskScheduler scoped_task_scheduler_;
base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
};
-RequestSenderTest::RequestSenderTest() : scoped_task_scheduler_(&loop_) {}
+RequestSenderTest::RequestSenderTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
RequestSenderTest::~RequestSenderTest() {}
void RequestSenderTest::SetUp() {
- config_ = base::MakeRefCounted<TestConfigurator>(
- base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get());
+ config_ = base::MakeRefCounted<TestConfigurator>();
interceptor_factory_ =
base::MakeUnique<InterceptorFactory>(base::ThreadTaskRunnerHandle::Get());
post_interceptor_1_ =
@@ -107,8 +106,6 @@ void RequestSenderTest::TearDown() {
interceptor_factory_ = nullptr;
config_ = nullptr;
-
- RunThreadsUntilIdle();
}
void RequestSenderTest::RunThreads() {
@@ -120,11 +117,7 @@ void RequestSenderTest::RunThreads() {
// intercepts on the IO thread, run the threads until they are
// idle. The component updater service won't loop again until the loop count
// is set and the service is started.
- RunThreadsUntilIdle();
-}
-
-void RequestSenderTest::RunThreadsUntilIdle() {
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
void RequestSenderTest::Quit() {
diff --git a/chromium/components/update_client/task_send_uninstall_ping.cc b/chromium/components/update_client/task_send_uninstall_ping.cc
index bb5d96a5a76..70130ed3795 100644
--- a/chromium/components/update_client/task_send_uninstall_ping.cc
+++ b/chromium/components/update_client/task_send_uninstall_ping.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
-#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
#include "components/update_client/update_client.h"
@@ -56,7 +55,7 @@ void TaskSendUninstallPing::TaskComplete(Error error) {
DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback_, this, error));
+ FROM_HERE, base::BindOnce(callback_, this, error));
}
} // namespace update_client
diff --git a/chromium/components/update_client/task_traits.h b/chromium/components/update_client/task_traits.h
new file mode 100644
index 00000000000..1a3d393b264
--- /dev/null
+++ b/chromium/components/update_client/task_traits.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_UPDATE_CLIENT_TASK_TRAITS_H_
+#define COMPONENTS_UPDATE_CLIENT_TASK_TRAITS_H_
+
+#include "base/task_scheduler/task_traits.h"
+
+namespace update_client {
+
+constexpr base::TaskTraits kTaskTraits = {
+ base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
+
+constexpr base::TaskTraits kTaskTraitsBackgroundDownloader = {
+ base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
+
+// This task joins a process, hence .WithBaseSyncPrimitives().
+constexpr base::TaskTraits kTaskTraitsRunCommand = {
+ base::MayBlock(), base::WithBaseSyncPrimitives(),
+ base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
+
+} // namespace update_client
+
+#endif // COMPONENTS_UPDATE_CLIENT_TASK_TRAITS_H_
diff --git a/chromium/components/update_client/task_update.cc b/chromium/components/update_client/task_update.cc
index 3c85950b90f..b9fb47b1f1b 100644
--- a/chromium/components/update_client/task_update.cc
+++ b/chromium/components/update_client/task_update.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
-#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_engine.h"
@@ -56,7 +55,7 @@ void TaskUpdate::TaskComplete(Error error) {
DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback_, this, error));
+ FROM_HERE, base::BindOnce(callback_, this, error));
}
} // namespace update_client
diff --git a/chromium/components/update_client/test_configurator.cc b/chromium/components/update_client/test_configurator.cc
index ade005de167..a61c093701f 100644
--- a/chromium/components/update_client/test_configurator.cc
+++ b/chromium/components/update_client/test_configurator.cc
@@ -6,8 +6,7 @@
#include <utility>
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/out_of_process_patcher.h"
@@ -27,16 +26,14 @@ std::vector<GURL> MakeDefaultUrls() {
} // namespace
-TestConfigurator::TestConfigurator(
- const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner)
- : worker_task_runner_(worker_task_runner),
- brand_("TEST"),
+TestConfigurator::TestConfigurator()
+ : brand_("TEST"),
initial_time_(0),
ondemand_time_(0),
enabled_cup_signing_(false),
enabled_component_updates_(true),
- context_(new net::TestURLRequestContextGetter(network_task_runner)) {}
+ context_(base::MakeRefCounted<net::TestURLRequestContextGetter>(
+ base::ThreadTaskRunnerHandle::Get())) {}
TestConfigurator::~TestConfigurator() {
}
@@ -163,12 +160,6 @@ void TestConfigurator::SetPingUrl(const GURL& url) {
ping_url_ = url;
}
-scoped_refptr<base::SequencedTaskRunner>
-TestConfigurator::GetSequencedTaskRunner() const {
- DCHECK(worker_task_runner_.get());
- return worker_task_runner_;
-}
-
PrefService* TestConfigurator::GetPrefService() const {
return nullptr;
}
diff --git a/chromium/components/update_client/test_configurator.h b/chromium/components/update_client/test_configurator.h
index fd0bc2f31df..01a9674ed73 100644
--- a/chromium/components/update_client/test_configurator.h
+++ b/chromium/components/update_client/test_configurator.h
@@ -18,11 +18,6 @@
class PrefService;
-namespace base {
-class SequencedTaskRunner;
-class SingleThreadTaskRunner;
-} // namespace base
-
namespace net {
class TestURLRequestContextGetter;
class URLRequestContextGetter;
@@ -61,9 +56,7 @@ const uint8_t gjpm_hash[] = {0x69, 0xfc, 0x41, 0xf6, 0x17, 0x20, 0xc6, 0x36,
class TestConfigurator : public Configurator {
public:
- TestConfigurator(
- const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner);
+ TestConfigurator();
// Overrrides for Configurator.
int InitialDelay() const override;
@@ -86,8 +79,6 @@ class TestConfigurator : public Configurator {
bool EnabledComponentUpdates() const override;
bool EnabledBackgroundDownloader() const override;
bool EnabledCupSigning() const override;
- scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
- const override;
PrefService* GetPrefService() const override;
bool IsPerUserInstall() const override;
std::vector<uint8_t> GetRunActionKeyHash() const override;
@@ -103,11 +94,8 @@ class TestConfigurator : public Configurator {
private:
friend class base::RefCountedThreadSafe<TestConfigurator>;
-
~TestConfigurator() override;
- scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
-
std::string brand_;
int initial_time_;
int ondemand_time_;
diff --git a/chromium/components/update_client/update_checker.cc b/chromium/components/update_client/update_checker.cc
index 4995f7500bc..dd4348d131d 100644
--- a/chromium/components/update_client/update_checker.cc
+++ b/chromium/components/update_client/update_checker.cc
@@ -17,6 +17,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
+#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/update_client/component.h"
@@ -25,6 +26,7 @@
#include "components/update_client/protocol_builder.h"
#include "components/update_client/protocol_parser.h"
#include "components/update_client/request_sender.h"
+#include "components/update_client/task_traits.h"
#include "components/update_client/update_client.h"
#include "components/update_client/updater_state.h"
#include "components/update_client/utils.h"
@@ -52,7 +54,7 @@ class UpdateCheckerImpl : public UpdateChecker {
~UpdateCheckerImpl() override;
// Overrides for UpdateChecker.
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_checked,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -95,7 +97,7 @@ UpdateCheckerImpl::~UpdateCheckerImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
}
-bool UpdateCheckerImpl::CheckForUpdates(
+void UpdateCheckerImpl::CheckForUpdates(
const std::vector<std::string>& ids_checked,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -106,13 +108,13 @@ bool UpdateCheckerImpl::CheckForUpdates(
ids_checked_ = ids_checked;
update_check_callback_ = update_check_callback;
- return config_->GetSequencedTaskRunner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&UpdateCheckerImpl::ReadUpdaterStateAttributes,
- base::Unretained(this)),
- base::Bind(&UpdateCheckerImpl::CheckForUpdatesHelper,
- base::Unretained(this), base::ConstRef(components),
- additional_attributes, enabled_component_updates));
+ base::PostTaskWithTraitsAndReply(
+ FROM_HERE, kTaskTraits,
+ base::BindOnce(&UpdateCheckerImpl::ReadUpdaterStateAttributes,
+ base::Unretained(this)),
+ base::BindOnce(&UpdateCheckerImpl::CheckForUpdatesHelper,
+ base::Unretained(this), base::ConstRef(components),
+ additional_attributes, enabled_component_updates));
}
// This function runs on the blocking pool task runner.
@@ -195,7 +197,7 @@ void UpdateCheckerImpl::UpdateCheckSucceeded(
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback_, 0, retry_after_sec));
+ FROM_HERE, base::BindOnce(update_check_callback_, 0, retry_after_sec));
}
void UpdateCheckerImpl::UpdateCheckFailed(const IdToComponentPtrMap& components,
@@ -210,7 +212,8 @@ void UpdateCheckerImpl::UpdateCheckFailed(const IdToComponentPtrMap& components,
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback_, error, retry_after_sec));
+ FROM_HERE,
+ base::BindOnce(update_check_callback_, error, retry_after_sec));
}
} // namespace
diff --git a/chromium/components/update_client/update_checker.h b/chromium/components/update_client/update_checker.h
index f9729fb81fb..c38bf61e790 100644
--- a/chromium/components/update_client/update_checker.h
+++ b/chromium/components/update_client/update_checker.h
@@ -37,7 +37,7 @@ class UpdateChecker {
// XML attribute string.
// On completion, the state of |components| is mutated as required by the
// server response received.
- virtual bool CheckForUpdates(
+ virtual void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
diff --git a/chromium/components/update_client/update_checker_unittest.cc b/chromium/components/update_client/update_checker_unittest.cc
index 033118be25f..70c667fc901 100644
--- a/chromium/components/update_client/update_checker_unittest.cc
+++ b/chromium/components/update_client/update_checker_unittest.cc
@@ -13,10 +13,9 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/test/scoped_task_scheduler.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
#include "build/build_config.h"
@@ -64,7 +63,6 @@ class UpdateCheckerTest : public testing::Test {
protected:
void Quit();
void RunThreads();
- void RunThreadsUntilIdle();
std::unique_ptr<Component> MakeComponent() const;
@@ -86,21 +84,21 @@ class UpdateCheckerTest : public testing::Test {
private:
std::unique_ptr<UpdateContext> MakeFakeUpdateContext() const;
- base::MessageLoopForIO loop_;
- base::test::ScopedTaskScheduler scoped_task_scheduler_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest);
};
-UpdateCheckerTest::UpdateCheckerTest() : scoped_task_scheduler_(&loop_) {}
+UpdateCheckerTest::UpdateCheckerTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
UpdateCheckerTest::~UpdateCheckerTest() {
}
void UpdateCheckerTest::SetUp() {
- config_ = base::MakeRefCounted<TestConfigurator>(
- base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get());
+ config_ = base::MakeRefCounted<TestConfigurator>();
pref_ = base::MakeUnique<TestingPrefServiceSimple>();
PersistedData::RegisterPrefs(pref_->registry());
metadata_ = base::MakeUnique<PersistedData>(pref_.get());
@@ -126,7 +124,7 @@ void UpdateCheckerTest::TearDown() {
// The PostInterceptor requires the message loop to run to destruct correctly.
// TODO(sorin): This is fragile and should be fixed.
- RunThreadsUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
void UpdateCheckerTest::RunThreads() {
@@ -138,11 +136,7 @@ void UpdateCheckerTest::RunThreads() {
// intercepts on the IO thread, run the threads until they are
// idle. The component updater service won't loop again until the loop count
// is set and the service is started.
- RunThreadsUntilIdle();
-}
-
-void UpdateCheckerTest::RunThreadsUntilIdle() {
- base::RunLoop().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
}
void UpdateCheckerTest::Quit() {
diff --git a/chromium/components/update_client/update_client.cc b/chromium/components/update_client/update_client.cc
index 4d248b27f5e..429a7a98864 100644
--- a/chromium/components/update_client/update_client.cc
+++ b/chromium/components/update_client/update_client.cc
@@ -18,8 +18,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/observer_list.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -131,7 +129,7 @@ void UpdateClientImpl::Update(const std::vector<std::string>& ids,
void UpdateClientImpl::RunTask(std::unique_ptr<Task> task) {
DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&Task::Run, base::Unretained(task.get())));
+ FROM_HERE, base::BindOnce(&Task::Run, base::Unretained(task.get())));
tasks_.insert(task.release());
}
@@ -141,8 +139,8 @@ void UpdateClientImpl::OnTaskComplete(const Callback& callback,
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(task);
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, error));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback, error));
// Remove the task from the set of the running tasks. Only tasks handled by
// the update engine can be in this data structure.
diff --git a/chromium/components/update_client/update_client_unittest.cc b/chromium/components/update_client/update_client_unittest.cc
index 98d02bcdc32..05b872fe288 100644
--- a/chromium/components/update_client/update_client_unittest.cc
+++ b/chromium/components/update_client/update_client_unittest.cc
@@ -172,10 +172,12 @@ class UpdateClientTest : public testing::Test {
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::RunLoop runloop_;
- base::Closure quit_closure_;
+ const base::Closure quit_closure_ = runloop_.QuitClosure();
- scoped_refptr<update_client::TestConfigurator> config_;
- std::unique_ptr<TestingPrefServiceSimple> pref_;
+ scoped_refptr<update_client::TestConfigurator> config_ =
+ base::MakeRefCounted<TestConfigurator>();
+ std::unique_ptr<TestingPrefServiceSimple> pref_ =
+ base::MakeUnique<TestingPrefServiceSimple>();
std::unique_ptr<update_client::PersistedData> metadata_;
DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
@@ -183,15 +185,7 @@ class UpdateClientTest : public testing::Test {
constexpr int UpdateClientTest::kNumWorkerThreads_;
-UpdateClientTest::UpdateClientTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI),
- pref_(base::MakeUnique<TestingPrefServiceSimple>()) {
- quit_closure_ = runloop_.QuitClosure();
-
- config_ = base::MakeRefCounted<TestConfigurator>(
- base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
- base::ThreadTaskRunnerHandle::Get());
+UpdateClientTest::UpdateClientTest() {
PersistedData::RegisterPrefs(pref_->registry());
metadata_ = base::MakeUnique<PersistedData>(pref_.get());
}
@@ -245,7 +239,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -267,9 +261,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
-
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -358,7 +350,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -429,8 +421,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -465,13 +456,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
result.total_bytes = 1843;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -570,7 +561,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -663,8 +654,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -719,8 +709,8 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -840,7 +830,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -930,8 +920,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -986,13 +975,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -1111,7 +1100,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -1217,8 +1206,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -1273,13 +1261,13 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -1440,7 +1428,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -1488,8 +1476,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -1528,9 +1515,9 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -1628,7 +1615,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -1736,8 +1723,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -1807,13 +1793,13 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -1934,7 +1920,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -1956,8 +1942,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -2047,7 +2032,7 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -2101,8 +2086,7 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
EXPECT_TRUE(component->on_demand());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -2141,13 +2125,13 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -2240,7 +2224,7 @@ TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -2263,8 +2247,7 @@ TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
EXPECT_TRUE(component->on_demand());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -2346,14 +2329,12 @@ TEST_F(UpdateClientTest, EmptyIdList) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
bool enabled_component_updates,
- const UpdateCheckCallback& update_check_callback) override {
- return false;
- }
+ const UpdateCheckCallback& update_check_callback) override {}
};
class FakeCrxDownloader : public CrxDownloader {
@@ -2398,14 +2379,12 @@ TEST_F(UpdateClientTest, SendUninstallPing) {
return nullptr;
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
bool enabled_component_updates,
- const UpdateCheckCallback& update_check_callback) override {
- return false;
- }
+ const UpdateCheckCallback& update_check_callback) override {}
};
class FakeCrxDownloader : public CrxDownloader {
@@ -2499,7 +2478,7 @@ TEST_F(UpdateClientTest, RetryAfter) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -2529,8 +2508,7 @@ TEST_F(UpdateClientTest, RetryAfter) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, retry_after_sec));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, retry_after_sec));
}
};
@@ -2673,7 +2651,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -2768,8 +2746,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -2808,13 +2785,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
- base::Unretained(this), result));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -2921,7 +2898,7 @@ TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -2934,9 +2911,7 @@ TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
EXPECT_EQ(1u, components.count(id));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, -1, 0));
-
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, -1, 0));
}
};
@@ -3004,7 +2979,7 @@ TEST_F(UpdateClientTest, ActionRun_Install) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -3058,8 +3033,7 @@ TEST_F(UpdateClientTest, ActionRun_Install) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -3098,9 +3072,9 @@ TEST_F(UpdateClientTest, ActionRun_Install) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeCrxDownloader::OnDownloadComplete,
- base::Unretained(this), true, result, download_metrics));
+ FROM_HERE, base::BindOnce(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result,
+ download_metrics));
}
};
@@ -3164,7 +3138,7 @@ TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
return base::MakeUnique<FakeUpdateChecker>();
}
- bool CheckForUpdates(
+ void CheckForUpdates(
const std::vector<std::string>& ids_to_check,
const IdToComponentPtrMap& components,
const std::string& additional_attributes,
@@ -3199,9 +3173,7 @@ TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
component->SetParseResult(result);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(update_check_callback, 0, 0));
-
- return true;
+ FROM_HERE, base::BindOnce(update_check_callback, 0, 0));
}
};
@@ -3242,8 +3214,7 @@ TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
scoped_refptr<ComponentUnpacker> component_unpacker = new ComponentUnpacker(
std::vector<uint8_t>(std::begin(gjpm_hash), std::end(gjpm_hash)),
- TestFilePath("runaction_test_win.crx3"), nullptr, nullptr,
- config()->GetSequencedTaskRunner());
+ TestFilePath("runaction_test_win.crx3"), nullptr, nullptr);
component_unpacker->Unpack(base::Bind(
[](base::FilePath* unpack_path, const base::Closure& quit_closure,
diff --git a/chromium/components/update_client/update_engine.cc b/chromium/components/update_client/update_engine.cc
index ef4db8eaf93..cf22810a980 100644
--- a/chromium/components/update_client/update_engine.cc
+++ b/chromium/components/update_client/update_engine.cc
@@ -39,7 +39,6 @@ UpdateContext::UpdateContext(
crx_data_callback(crx_data_callback),
notify_observers_callback(notify_observers_callback),
callback(callback),
- blocking_task_runner(config->GetSequencedTaskRunner()),
crx_downloader_factory(crx_downloader_factory) {
for (const auto& id : ids)
components.insert(
@@ -74,7 +73,7 @@ void UpdateEngine::Update(
if (IsThrottled(is_foreground)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, Error::RETRY_LATER));
+ FROM_HERE, base::BindOnce(callback, Error::RETRY_LATER));
return;
}
@@ -143,7 +142,7 @@ void UpdateEngine::ComponentCheckingForUpdatesStart(
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&UpdateEngine::DoUpdateCheck, base::Unretained(this), it));
+ base::BindOnce(&UpdateEngine::DoUpdateCheck, base::Unretained(this), it));
}
void UpdateEngine::DoUpdateCheck(const UpdateContextIterator& it) {
@@ -209,8 +208,8 @@ void UpdateEngine::ComponentCheckingForUpdatesComplete(
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&UpdateEngine::UpdateCheckComplete,
- base::Unretained(this), it));
+ FROM_HERE, base::BindOnce(&UpdateEngine::UpdateCheckComplete,
+ base::Unretained(this), it));
}
void UpdateEngine::UpdateCheckComplete(const UpdateContextIterator& it) {
@@ -223,8 +222,8 @@ void UpdateEngine::UpdateCheckComplete(const UpdateContextIterator& it) {
update_context->component_queue.push(id);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it));
+ FROM_HERE, base::BindOnce(&UpdateEngine::HandleComponent,
+ base::Unretained(this), it));
}
void UpdateEngine::HandleComponent(const UpdateContextIterator& it) {
@@ -254,7 +253,8 @@ void UpdateEngine::HandleComponent(const UpdateContextIterator& it) {
if (!next_update_delay.is_zero() && component->IsUpdateAvailable()) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
- base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it),
+ base::BindOnce(&UpdateEngine::HandleComponent, base::Unretained(this),
+ it),
next_update_delay);
next_update_delay = base::TimeDelta();
@@ -293,8 +293,8 @@ void UpdateEngine::HandleComponentComplete(const UpdateContextIterator& it) {
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it));
+ FROM_HERE, base::BindOnce(&UpdateEngine::HandleComponent,
+ base::Unretained(this), it));
}
void UpdateEngine::UpdateComplete(const UpdateContextIterator& it,
@@ -362,8 +362,8 @@ void UpdateEngine::SendUninstallPing(const std::string& id,
update_context->component_queue.push(id);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it));
+ FROM_HERE, base::BindOnce(&UpdateEngine::HandleComponent,
+ base::Unretained(this), it));
}
} // namespace update_client
diff --git a/chromium/components/update_client/update_engine.h b/chromium/components/update_client/update_engine.h
index df643b1ea42..9f3b57f7502 100644
--- a/chromium/components/update_client/update_engine.h
+++ b/chromium/components/update_client/update_engine.h
@@ -28,7 +28,6 @@
namespace base {
class TimeTicks;
-class SequencedTaskRunner;
} // namespace base
namespace update_client {
@@ -152,9 +151,6 @@ struct UpdateContext {
// Called when the all updates associated with this context have completed.
const UpdateEngine::Callback callback;
- // Runs tasks in a blocking thread pool.
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
-
// Creates instances of CrxDownloader;
CrxDownloader::Factory crx_downloader_factory;
diff --git a/chromium/components/update_client/update_query_params.cc b/chromium/components/update_client/update_query_params.cc
index 7b576e585b2..65d53ba79ee 100644
--- a/chromium/components/update_client/update_query_params.cc
+++ b/chromium/components/update_client/update_query_params.cc
@@ -33,6 +33,8 @@ const char kOs[] =
"cros";
#elif defined(OS_LINUX)
"linux";
+#elif defined(OS_FUCHSIA)
+ "fuchsia";
#elif defined(OS_OPENBSD)
"openbsd";
#else
diff --git a/chromium/components/update_client/updater_state_unittest.cc b/chromium/components/update_client/updater_state_unittest.cc
index ca889ade7e1..86ad660a3d7 100644
--- a/chromium/components/update_client/updater_state_unittest.cc
+++ b/chromium/components/update_client/updater_state_unittest.cc
@@ -46,9 +46,9 @@ TEST_F(UpdaterStateTest, Serialize) {
#if defined(OS_WIN)
// The name of the Windows updater for Chrome.
EXPECT_STREQ("Omaha", UpdaterState::GetState(false)->at("name").c_str());
- #elif defined(OS_MACOSX)
- EXPECT_STREQ("Keystone", UpdaterState::GetState(false)->at("name").c_str());
- #endif
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ EXPECT_STREQ("Keystone", UpdaterState::GetState(false)->at("name").c_str());
+#endif
#endif // GOOGLE_CHROME_BUILD
// Tests some of the remaining values.
diff --git a/chromium/components/update_client/url_fetcher_downloader.cc b/chromium/components/update_client/url_fetcher_downloader.cc
index 03e6190bd4d..2213f483fff 100644
--- a/chromium/components/update_client/url_fetcher_downloader.cc
+++ b/chromium/components/update_client/url_fetcher_downloader.cc
@@ -79,7 +79,7 @@ void UrlFetcherDownloader::StartURLFetch(const GURL& url) {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled."
chrome_policy {
ComponentUpdatesEnabled {
diff --git a/chromium/components/update_client/url_fetcher_downloader.h b/chromium/components/update_client/url_fetcher_downloader.h
index cb81fbc8850..2007aa76c8a 100644
--- a/chromium/components/update_client/url_fetcher_downloader.h
+++ b/chromium/components/update_client/url_fetcher_downloader.h
@@ -27,8 +27,7 @@ namespace update_client {
// Implements a CRX downloader in top of the URLFetcher.
class UrlFetcherDownloader : public CrxDownloader,
public net::URLFetcherDelegate {
- protected:
- friend class CrxDownloader;
+ public:
UrlFetcherDownloader(std::unique_ptr<CrxDownloader> successor,
net::URLRequestContextGetter* context_getter);
~UrlFetcherDownloader() override;
diff --git a/chromium/components/update_client/utils.cc b/chromium/components/update_client/utils.cc
index 74ef1e7e769..8d4afcfbff7 100644
--- a/chromium/components/update_client/utils.cc
+++ b/chromium/components/update_client/utils.cc
@@ -84,7 +84,7 @@ std::unique_ptr<net::URLFetcher> SendProtocolRequest(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled."
chrome_policy {
ComponentUpdatesEnabled {
diff --git a/chromium/components/url_formatter/OWNERS b/chromium/components/url_formatter/OWNERS
index 907aaa24ab1..3336b55a8b5 100644
--- a/chromium/components/url_formatter/OWNERS
+++ b/chromium/components/url_formatter/OWNERS
@@ -1,4 +1,5 @@
pkasting@chromium.org
+tommycli@chromium.org
# Backup reviewer
brettw@chromium.org
diff --git a/chromium/components/url_formatter/android/BUILD.gn b/chromium/components/url_formatter/android/BUILD.gn
index b4d97e8c1a1..9070dc7799d 100644
--- a/chromium/components/url_formatter/android/BUILD.gn
+++ b/chromium/components/url_formatter/android/BUILD.gn
@@ -9,9 +9,8 @@ android_library("url_formatter_java") {
"//base:base_java",
]
- java_files = [
- "java/src/org/chromium/components/url_formatter/UrlFormatter.java",
- ]
+ java_files =
+ [ "java/src/org/chromium/components/url_formatter/UrlFormatter.java" ]
}
generate_jni("jni_headers") {
diff --git a/chromium/components/url_formatter/elide_url.cc b/chromium/components/url_formatter/elide_url.cc
index 984de31952c..f42c9b8b22b 100644
--- a/chromium/components/url_formatter/elide_url.cc
+++ b/chromium/components/url_formatter/elide_url.cc
@@ -37,6 +37,8 @@ base::string16 BuildPathFromComponents(
const std::vector<base::string16>& path_elements,
const base::string16& filename,
size_t num_components) {
+ DCHECK_LE(num_components, path_elements.size());
+
// Add the initial elements of the path.
base::string16 path = path_prefix;
@@ -55,6 +57,8 @@ base::string16 BuildPathFromComponents(
// Takes a prefix (Domain, or Domain+subdomain) and a collection of path
// components and elides if possible. Returns a string containing the longest
// possible elided path, or an empty string if elision is not possible.
+// Warning: This is O(url_path_elements.size() ^ 2), so it should not be called
+// on a very large path.
base::string16 ElideComponentizedPath(
const base::string16& url_path_prefix,
const std::vector<base::string16>& url_path_elements,
@@ -154,8 +158,8 @@ base::string16 ElideUrl(const GURL& url,
// Get a formatted string and corresponding parsing of the url.
url::Parsed parsed;
const base::string16 url_string = url_formatter::FormatUrl(
- url, url_formatter::kFormatUrlOmitAll,
- net::UnescapeRule::SPACES, &parsed, nullptr, nullptr);
+ url, url_formatter::kFormatUrlOmitDefaults, net::UnescapeRule::SPACES,
+ &parsed, nullptr, nullptr);
if (available_pixel_width <= 0)
return url_string;
@@ -259,12 +263,13 @@ base::string16 ElideUrl(const GURL& url,
}
const size_t kMaxNumberOfUrlPathElementsAllowed = 1024;
- // TODO(mgiuca): If there is no path, this means the end of the domain gets
- // elided, not the start (inconsistent). https://crbug.com/739636.
- if (url_path_number_of_elements <= 1 ||
- url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
- // No path to elide, or too long of a path (could overflow in loop below)
- // Just elide this as a text string.
+ if (url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
+ // Too long of a path (ElideComponentizedPath is O(N^2) so this would result
+ // in degenerate behaviour). Just elide this as a text string.
+ // TODO(mgiuca): Fix ElideComponentizedPath to deal with degenerate cases
+ // itself, so we don't need this special case. We should not fall back on
+ // ElideText if we don't know the entire domain will fit, or else we might
+ // chop off the TLD. https://crbug.com/739975.
return gfx::ElideText(url_subdomain + url_domain + url_path_query_etc,
font_list, available_pixel_width, gfx::ELIDE_TAIL);
}
@@ -276,11 +281,13 @@ base::string16 ElideUrl(const GURL& url,
gfx::GetStringWidthF(kEllipsisAndSlash, font_list);
// Check with both subdomain and domain.
- base::string16 elided_path = ElideComponentizedPath(
- url_subdomain + url_domain, url_path_elements, url_filename, url_query,
- font_list, available_pixel_width);
- if (!elided_path.empty())
- return elided_path;
+ if (url_path_number_of_elements > 0) {
+ base::string16 elided_path = ElideComponentizedPath(
+ url_subdomain + url_domain, url_path_elements, url_filename, url_query,
+ font_list, available_pixel_width);
+ if (!elided_path.empty())
+ return elided_path;
+ }
// Check with only domain.
// If a subdomain is present, add an ellipsis before domain.
@@ -294,12 +301,13 @@ base::string16 ElideUrl(const GURL& url,
else
url_elided_domain = url_domain;
- elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
- url_filename, url_query, font_list,
- available_pixel_width);
-
- if (!elided_path.empty())
- return elided_path;
+ if (url_path_number_of_elements > 0) {
+ base::string16 elided_path = ElideComponentizedPath(
+ url_elided_domain, url_path_elements, url_filename, url_query,
+ font_list, available_pixel_width);
+ if (!elided_path.empty())
+ return elided_path;
+ }
}
// Return elided domain/.../filename anyway.
@@ -308,9 +316,11 @@ base::string16 ElideUrl(const GURL& url,
gfx::GetStringWidthF(url_elided_domain, font_list);
// A hack to prevent trailing ".../...".
- if ((available_pixel_width - url_elided_domain_width) >
- pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
- gfx::GetStringWidthF(base::ASCIIToUTF16("UV"), font_list)) {
+ if (url_path_number_of_elements > 0 &&
+ url_elided_domain_width + pixel_width_ellipsis_slash +
+ kPixelWidthDotsTrailer +
+ gfx::GetStringWidthF(base::ASCIIToUTF16("UV"), font_list) <
+ available_pixel_width) {
final_elided_url_string += BuildPathFromComponents(
base::string16(), url_path_elements, url_filename, 1);
} else {
diff --git a/chromium/components/url_formatter/elide_url_unittest.cc b/chromium/components/url_formatter/elide_url_unittest.cc
index 54f70243e03..58dbfb5c7af 100644
--- a/chromium/components/url_formatter/elide_url_unittest.cc
+++ b/chromium/components/url_formatter/elide_url_unittest.cc
@@ -53,6 +53,8 @@ TEST(TextEliderTest, TestGeneralEliding) {
{"http://www.google.com/intl/en/ads/", "google.com/" + kEllipsisStr},
{"http://www.google.com/intl/en/ads/", "goog" + kEllipsisStr},
{"https://subdomain.foo.com/bar/filename.html",
+ "https://subdomain.foo.com/bar/filename.html"},
+ {"https://subdomain.foo.com/bar/filename.html",
"subdomain.foo.com/bar/filename.html"},
{"https://subdomain.foo.com/bar/filename.html",
"subdomain.foo.com/" + kEllipsisStr + "/filename.html"},
@@ -94,6 +96,16 @@ TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) {
ASSERT_GT(expected.length(), std::string("battersbox.com/d").length());
EXPECT_EQ(expected, url_formatter::ElideUrl(url, font_list, available_width));
+ // Regression test for https://crbug.com/756717. An empty path, eliding to a
+ // width in between the full domain ("www.angelfire.lycos.com") and a bit
+ // longer than the ETLD+1 ("…lycos.com…/…UV"). This previously crashed due to
+ // the path being empty.
+ url = GURL("http://www.angelfire.lycos.com/");
+ available_width = gfx::GetStringWidthF(
+ base::UTF8ToUTF16(kEllipsisStr + "angelfire.lycos.com"), font_list);
+ EXPECT_EQ(base::UTF8ToUTF16(kEllipsisStr + "lycos.com"),
+ url_formatter::ElideUrl(url, font_list, available_width));
+
// More space available - elide directories, partially elide filename.
Testcase testcases[] = {
{"http://battersbox.com/directory/foo/peter_paul_and_mary.html",
@@ -111,7 +123,7 @@ TEST(TextEliderTest, TestMoreEliding) {
const std::string kEllipsisStr(gfx::kEllipsis);
Testcase testcases[] = {
// Eliding the same URL to various lengths.
- {"http://www.google.com/foo?bar", "www.google.com/foo?bar"},
+ {"http://xyz.google.com/foo?bar", "xyz.google.com/foo?bar"},
{"http://xyz.google.com/foo?bar", "xyz.google.com/foo?" + kEllipsisStr},
{"http://xyz.google.com/foo?bar", "xyz.google.com/foo" + kEllipsisStr},
{"http://xyz.google.com/foo?bar", "xyz.google.com/fo" + kEllipsisStr},
@@ -133,11 +145,13 @@ TEST(TextEliderTest, TestMoreEliding) {
{"http://xyz.google.com/foo?bar", kEllipsisStr + "googl" + kEllipsisStr},
{"http://xyz.google.com/foo?bar", kEllipsisStr + "g" + kEllipsisStr},
+ // URL with "www" subdomain (gets removed specially).
+ {"http://www.google.com/foo?bar", "www.google.com/foo?bar"},
+ {"http://www.google.com/foo?bar", "google.com/foo?bar"},
+
// URL with no path.
- // TODO(mgiuca): These should elide the start of the URL, not the end.
- // https://crbug.com/739636.
- {"http://xyz.google.com", "xyz.google" + kEllipsisStr},
- {"https://xyz.google.com", "xyz.google" + kEllipsisStr},
+ {"http://xyz.google.com", kEllipsisStr + "google.com"},
+ {"https://xyz.google.com", kEllipsisStr + "google.com"},
{"http://a.b.com/pathname/c?d", "a.b.com/" + kEllipsisStr + "/c?d"},
{"", ""},
diff --git a/chromium/components/url_formatter/idn_spoof_checker.cc b/chromium/components/url_formatter/idn_spoof_checker.cc
index 1c4d9bdb74f..376b2c65e05 100644
--- a/chromium/components/url_formatter/idn_spoof_checker.cc
+++ b/chromium/components/url_formatter/idn_spoof_checker.cc
@@ -242,6 +242,8 @@ bool IDNSpoofChecker::SafeToDisplayAsUnicode(base::StringPiece16 label,
// character set.
// - Disallow Arabic non-spacing marks after non-Arabic characters.
// - Disallow Hebrew non-spacing marks after non-Hebrew characters.
+ // - Disallow U+0307 (dot above) after 'i', 'j', 'l' or dotless i (U+0131).
+ // Dotless j (U+0237) is not in the allowed set to begin with.
dangerous_pattern = new icu::RegexMatcher(
icu::UnicodeString(
R"([^\p{scx=kana}\p{scx=hira}\p{scx=hani}])"
@@ -260,7 +262,8 @@ bool IDNSpoofChecker::SafeToDisplayAsUnicode(base::StringPiece16 label,
R"([\p{sc=tfng}].*[a-z]|[a-z].*[\p{sc=tfng}]|)"
R"([^\p{scx=latn}\p{scx=grek}\p{scx=cyrl}][\u0300-\u0339]|)"
R"([^\p{scx=arab}][\u064b-\u0655\u0670]|)"
- R"([^\p{scx=hebr}]\u05b4)",
+ R"([^\p{scx=hebr}]\u05b4|)"
+ R"([ijl\u0131]\u0307)",
-1, US_INV),
0, status);
tls_index.Set(dangerous_pattern);
diff --git a/chromium/components/url_formatter/top_domains/alexa_domains.list b/chromium/components/url_formatter/top_domains/alexa_domains.list
index a76cc116ada..a5cf95028df 100644
--- a/chromium/components/url_formatter/top_domains/alexa_domains.list
+++ b/chromium/components/url_formatter/top_domains/alexa_domains.list
@@ -9170,6 +9170,8 @@ ntd.tv
onclkds.com
uber.com
lyft.com
+ok.ru
+stripe.com
# for testing
digklmo68.com
digklmo68.co.uk
diff --git a/chromium/components/url_formatter/top_domains/alexa_skeletons.gperf b/chromium/components/url_formatter/top_domains/alexa_skeletons.gperf
index 957c69b1e89..8f1990f2c18 100644
--- a/chromium/components/url_formatter/top_domains/alexa_skeletons.gperf
+++ b/chromium/components/url_formatter/top_domains/alexa_skeletons.gperf
@@ -9180,6 +9180,8 @@ ntd.tv, 1
onclkds.corn, 1
uber.corn, 1
lyft.corn, 1
+ok.ru, 1
+stripe.corn, 1
digklrno68.corn, 1
digklrno68.co.uk, 1
islkpxl23.corn, 1
diff --git a/chromium/components/url_formatter/top_domains/make_alexa_top_list.py b/chromium/components/url_formatter/top_domains/make_alexa_top_list.py
index 20820e84c3e..ce6ced81a29 100755
--- a/chromium/components/url_formatter/top_domains/make_alexa_top_list.py
+++ b/chromium/components/url_formatter/top_domains/make_alexa_top_list.py
@@ -46,7 +46,7 @@ with open(alexa_out, 'w') as outfile, open(alexa10k_path, 'r') as infile:
# Add some popular domains if they're missing.
# TODO(jshin): Find a way to update the list. (crbug.com/722022)
for domain in ["gmail.com", "hotmail.com", "360.cn", "ntd.tv", "onclkds.com",
- "uber.com", "lyft.com", "ok.ru"]:
+ "uber.com", "lyft.com", "ok.ru", "stripe.com"]:
if domain not in domains:
outfile.write(domain + "\n")
diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc
index 461bc7942c5..bad3a45a9ec 100644
--- a/chromium/components/url_formatter/url_formatter.cc
+++ b/chromium/components/url_formatter/url_formatter.cc
@@ -68,7 +68,7 @@ class HostComponentTransform : public AppendComponentTransform {
std::string domain_and_registry =
net::registry_controlled_domains::GetDomainAndRegistry(
component_text,
- net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+ net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
base::OffsetAdjuster::Adjustments trivial_subdomains_adjustments;
base::StringTokenizer tokenizer(
@@ -405,12 +405,13 @@ const FormatUrlType kFormatUrlOmitNothing = 0;
const FormatUrlType kFormatUrlOmitUsernamePassword = 1 << 0;
const FormatUrlType kFormatUrlOmitHTTP = 1 << 1;
const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname = 1 << 2;
-const FormatUrlType kFormatUrlOmitAll =
+const FormatUrlType kFormatUrlOmitHTTPS = 1 << 3;
+const FormatUrlType kFormatUrlExperimentalElideAfterHost = 1 << 4;
+const FormatUrlType kFormatUrlExperimentalOmitTrivialSubdomains = 1 << 5;
+
+const FormatUrlType kFormatUrlOmitDefaults =
kFormatUrlOmitUsernamePassword | kFormatUrlOmitHTTP |
kFormatUrlOmitTrailingSlashOnBareHostname;
-const FormatUrlType kFormatUrlExperimentalElideAfterHost = 1 << 3;
-const FormatUrlType kFormatUrlExperimentalOmitHTTPS = 1 << 4;
-const FormatUrlType kFormatUrlExperimentalOmitTrivialSubdomains = 1 << 5;
base::string16 FormatUrl(const GURL& url,
FormatUrlTypes format_types,
@@ -604,7 +605,7 @@ base::string16 FormatUrlWithAdjustments(
!base::StartsWith(url.host(), kFTP, base::CompareCase::SENSITIVE) &&
(((format_types & kFormatUrlOmitHTTP) &&
url.SchemeIs(url::kHttpScheme)) ||
- ((format_types & kFormatUrlExperimentalOmitHTTPS) &&
+ ((format_types & kFormatUrlOmitHTTPS) &&
url.SchemeIs(url::kHttpsScheme)));
// If we need to strip out schemes do it after the fact.
diff --git a/chromium/components/url_formatter/url_formatter.h b/chromium/components/url_formatter/url_formatter.h
index a44f60eeb5c..32e095e760e 100644
--- a/chromium/components/url_formatter/url_formatter.h
+++ b/chromium/components/url_formatter/url_formatter.h
@@ -51,21 +51,21 @@ extern const FormatUrlType kFormatUrlOmitHTTP;
// meaningful for non-file "standard" URLs.
extern const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname;
-// Convenience for omitting all unecessary types. Does not include experimental
-// flags below.
-extern const FormatUrlType kFormatUrlOmitAll;
+// If the scheme is 'https://', it's removed. Not in kFormatUrlOmitDefaults.
+extern const FormatUrlType kFormatUrlOmitHTTPS;
// Replaces the path, query, and ref with an ellipsis. Experimental and not in
-// kFormatUrlOmitAll.
+// kFormatUrlOmitDefaults.
extern const FormatUrlType kFormatUrlExperimentalElideAfterHost;
-// If the scheme is 'https://', it's removed. Experimental and not in
-// kFormatUrlOmitAll.
-extern const FormatUrlType kFormatUrlExperimentalOmitHTTPS;
-
-// Omits some trivially informative subdomains such as "www" or "m".
+// Omits some trivially informative subdomains such as "www" or "m". Not in
+// kFormatUrlOmitDefaults.
extern const FormatUrlType kFormatUrlExperimentalOmitTrivialSubdomains;
+// Convenience for omitting all unecessary types. Does not include HTTPS scheme
+// removal, or experimental flags.
+extern const FormatUrlType kFormatUrlOmitDefaults;
+
// Creates a string representation of |url|. The IDN host name is turned to
// Unicode if the Unicode representation is deemed safe. |format_type| is a
// bitmask of FormatUrlTypes, see it for details. |unescape_rules| defines how
@@ -125,11 +125,12 @@ base::string16 FormatUrlWithAdjustments(
base::OffsetAdjuster::Adjustments* adjustments);
// This is a convenience function for FormatUrl() with
-// format_types = kFormatUrlOmitAll and unescape = SPACES. This is the typical
-// set of flags for "URLs to display to the user". You should be cautious about
-// using this for URLs which will be parsed or sent to other applications.
+// format_types = kFormatUrlOmitDefaults and unescape = SPACES. This is the
+// typical set of flags for "URLs to display to the user". You should be
+// cautious about using this for URLs which will be parsed or sent to other
+// applications.
inline base::string16 FormatUrl(const GURL& url) {
- return FormatUrl(url, kFormatUrlOmitAll, net::UnescapeRule::SPACES,
+ return FormatUrl(url, kFormatUrlOmitDefaults, net::UnescapeRule::SPACES,
nullptr, nullptr, nullptr);
}
diff --git a/chromium/components/url_formatter/url_formatter_unittest.cc b/chromium/components/url_formatter/url_formatter_unittest.cc
index 49f03f163e1..66435304485 100644
--- a/chromium/components/url_formatter/url_formatter_unittest.cc
+++ b/chromium/components/url_formatter/url_formatter_unittest.cc
@@ -249,6 +249,17 @@ const IDNTestCase idn_cases[] = {
L"abc.jp",
false},
+ // The following three are detected by |dangerous_pattern| regex, but
+ // can be regarded as an extension of blocking repeated diacritic marks.
+ // i followed by U+0307 (combining dot above)
+ {"xn--pixel-8fd.com", L"pi\x0307xel.com", false},
+ // U+0131 (dotless i) followed by U+0307
+ {"xn--pxel-lza43z.com", L"p\x0131\x0307xel.com", false},
+ // j followed by U+0307 (combining dot above)
+ {"xn--jack-qwc.com", L"j\x0307" L"ack.com", false},
+ // l followed by U+0307
+ {"xn--lace-qwc.com", L"l\x0307" L"ace.com", false},
+
// Mixed script confusable
// google with Armenian Small Letter Oh(U+0585)
{"xn--gogle-lkg.com", L"g\x0585ogle.com", false},
@@ -828,11 +839,12 @@ TEST(UrlFormatterTest, FormatUrl) {
{"omit http", "http://www.google.com/", kFormatUrlOmitHTTP,
net::UnescapeRule::NORMAL, L"www.google.com/", 0},
- {"omit http on bare scheme", "http://", kFormatUrlOmitAll,
+ {"omit http on bare scheme", "http://", kFormatUrlOmitDefaults,
net::UnescapeRule::NORMAL, L"", 0},
{"omit http with user name", "http://user@example.com/foo",
- kFormatUrlOmitAll, net::UnescapeRule::NORMAL, L"example.com/foo", 0},
+ kFormatUrlOmitDefaults, net::UnescapeRule::NORMAL, L"example.com/foo",
+ 0},
{"omit http with https", "https://www.google.com/", kFormatUrlOmitHTTP,
net::UnescapeRule::NORMAL, L"https://www.google.com/", 8},
@@ -873,66 +885,66 @@ TEST(UrlFormatterTest, FormatUrl) {
// view-source should omit http and trailing slash where non-view-source
// would.
- {"view-source omit http", "view-source:http://a.b/c", kFormatUrlOmitAll,
- net::UnescapeRule::NORMAL, L"view-source:a.b/c", 12},
+ {"view-source omit http", "view-source:http://a.b/c",
+ kFormatUrlOmitDefaults, net::UnescapeRule::NORMAL, L"view-source:a.b/c",
+ 12},
{"view-source omit http starts with ftp.", "view-source:http://ftp.b/c",
- kFormatUrlOmitAll, net::UnescapeRule::NORMAL,
+ kFormatUrlOmitDefaults, net::UnescapeRule::NORMAL,
L"view-source:http://ftp.b/c", 19},
{"view-source omit slash when it's the entire path",
- "view-source:http://a.b/", kFormatUrlOmitAll, net::UnescapeRule::NORMAL,
- L"view-source:a.b", 12},
+ "view-source:http://a.b/", kFormatUrlOmitDefaults,
+ net::UnescapeRule::NORMAL, L"view-source:a.b", 12},
// -------- elide after host --------
{"elide after host but still strip trailing slashes",
"http://google.com/",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com", 0},
{"elide after host in simple filename-only case", "http://google.com/foo",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host in directory and file case", "http://google.com/ab/cd",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with query only", "http://google.com/?foo=bar",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with ref only", "http://google.com/#foobar",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with path and query only", "http://google.com/foo?a=b",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with path and ref only", "http://google.com/foo#c",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with query and ref only", "http://google.com/?a=b#c",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with path, query and ref",
"http://google.com/foo?a=b#c",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
{"elide after host with repeated delimiters (sanity check)",
"http://google.com////???####",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, L"google.com/\x2026\x0000", 0},
// -------- omit https --------
- {"omit https", "https://www.google.com/", kFormatUrlExperimentalOmitHTTPS,
+ {"omit https", "https://www.google.com/", kFormatUrlOmitHTTPS,
net::UnescapeRule::NORMAL, L"www.google.com/", 0},
{"omit https but do not omit http", "http://www.google.com/",
- kFormatUrlExperimentalOmitHTTPS, net::UnescapeRule::NORMAL,
+ kFormatUrlOmitHTTPS, net::UnescapeRule::NORMAL,
L"http://www.google.com/", 7},
{"omit https, username, and password",
"https://user:password@example.com/foo",
- kFormatUrlOmitAll | kFormatUrlExperimentalOmitHTTPS,
- net::UnescapeRule::NORMAL, L"example.com/foo", 0},
+ kFormatUrlOmitDefaults | kFormatUrlOmitHTTPS, net::UnescapeRule::NORMAL,
+ L"example.com/foo", 0},
{"omit https, but preserve user name and password",
- "https://user:password@example.com/foo", kFormatUrlExperimentalOmitHTTPS,
+ "https://user:password@example.com/foo", kFormatUrlOmitHTTPS,
net::UnescapeRule::NORMAL, L"user:password@example.com/foo", 14},
{"omit https should not affect hosts starting with ftp.",
- "https://ftp.google.com/",
- kFormatUrlOmitHTTP | kFormatUrlExperimentalOmitHTTPS,
+ "https://ftp.google.com/", kFormatUrlOmitHTTP | kFormatUrlOmitHTTPS,
net::UnescapeRule::NORMAL, L"https://ftp.google.com/", 8},
// -------- omit trivial subdomains --------
@@ -949,6 +961,9 @@ TEST(UrlFormatterTest, FormatUrl) {
"http://en.m.wikipedia.org/",
kFormatUrlExperimentalOmitTrivialSubdomains, net::UnescapeRule::NORMAL,
L"http://en.wikipedia.org/", 7},
+ {"omit trivial subdomains - exclude private registries",
+ "http://www.blogspot.com/", kFormatUrlExperimentalOmitTrivialSubdomains,
+ net::UnescapeRule::NORMAL, L"http://blogspot.com/", 7},
{"omit trivial subdomains - don't do blind substring matches for www",
"http://wwww.google.com/", kFormatUrlExperimentalOmitTrivialSubdomains,
net::UnescapeRule::NORMAL, L"http://wwww.google.com/", 7},
@@ -1324,36 +1339,41 @@ TEST(UrlFormatterTest, FormatUrlWithOffsets) {
0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, kNpos, kNpos, kNpos, kNpos,
0, 1, 2, 3, 4, 5, 6, 7
};
- CheckAdjustedOffsets("http://user@foo.com/", kFormatUrlOmitAll,
+ CheckAdjustedOffsets("http://user@foo.com/", kFormatUrlOmitDefaults,
net::UnescapeRule::NORMAL, omit_all_offsets);
const size_t elide_after_host_offsets[] = {
0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, 1, 2, 3, 4,
5, 6, 7, 8, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 9};
- CheckAdjustedOffsets("http://foo.com/abcdefg",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
- CheckAdjustedOffsets("http://foo.com/abc/def",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
- CheckAdjustedOffsets("http://foo.com/abc?a=b",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
- CheckAdjustedOffsets("http://foo.com/abc#def",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
- CheckAdjustedOffsets("http://foo.com/a?a=b#f",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
- CheckAdjustedOffsets("http://foo.com//??###",
- kFormatUrlOmitAll | kFormatUrlExperimentalElideAfterHost,
- net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com/abcdefg",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com/abc/def",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com/abc?a=b",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com/abc#def",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com/a?a=b#f",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ CheckAdjustedOffsets(
+ "http://foo.com//??###",
+ kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
+ net::UnescapeRule::NORMAL, elide_after_host_offsets);
const size_t omit_https_offsets[] = {
0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
- CheckAdjustedOffsets("https://www.google.com/",
- kFormatUrlExperimentalOmitHTTPS,
+ CheckAdjustedOffsets("https://www.google.com/", kFormatUrlOmitHTTPS,
net::UnescapeRule::NORMAL, omit_https_offsets);
const size_t omit_https_with_auth_offsets[] = {
@@ -1361,7 +1381,7 @@ TEST(UrlFormatterTest, FormatUrlWithOffsets) {
kNpos, kNpos, kNpos, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14};
CheckAdjustedOffsets("https://u:p@www.google.com/",
- kFormatUrlOmitAll | kFormatUrlExperimentalOmitHTTPS,
+ kFormatUrlOmitDefaults | kFormatUrlOmitHTTPS,
net::UnescapeRule::NORMAL, omit_https_with_auth_offsets);
const size_t strip_trivial_subdomains_offsets_1[] = {
diff --git a/chromium/components/url_matcher/url_matcher_factory_unittest.cc b/chromium/components/url_matcher/url_matcher_factory_unittest.cc
index bb598348976..347bea4f2ae 100644
--- a/chromium/components/url_matcher/url_matcher_factory_unittest.cc
+++ b/chromium/components/url_matcher/url_matcher_factory_unittest.cc
@@ -240,7 +240,7 @@ void UrlConditionCaseTest::CheckCondition(
list->AppendString(value);
condition.SetWithoutPathExpansion(condition_key_, std::move(list));
} else {
- condition.SetStringWithoutPathExpansion(condition_key_, value);
+ condition.SetKey(condition_key_, base::Value(value));
}
URLMatcher matcher;
diff --git a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
index cb5d305a55c..bf5ed8664bd 100644
--- a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
+++ b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
@@ -79,13 +79,21 @@ table UrlRule {
anchor_right : AnchorType = NONE;
// The list of domains to be included/excluded from the filter's affected set.
- // Kept sorted for fast matching. Should either be null or have at least a
- // single element.
+ // Should either be null or have at least a single element. The domains
+ // should be in lower-case and kept sorted as defined by
+ // url_pattern_index::CompareDomains.
domains_included : [string];
domains_excluded : [string];
// A URL pattern in the format defined by |url_pattern_type|.
url_pattern : string;
+
+ // An id which uniquely identifies the rule. Clients must ensure uniqueness if
+ // they use this field.
+ id : uint;
+
+ // Priority of the rule. Larger the value, greater the priority.
+ priority : uint;
}
// Contains an N-gram (acting as a key in a hash table) and a list of URL rules
diff --git a/chromium/components/url_pattern_index/url_pattern_index.cc b/chromium/components/url_pattern_index/url_pattern_index.cc
index d868afdd1a5..38d75e811ee 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.cc
+++ b/chromium/components/url_pattern_index/url_pattern_index.cc
@@ -95,14 +95,6 @@ base::StringPiece ToStringPiece(const flatbuffers::String* string) {
return base::StringPiece(string->c_str(), string->size());
}
-// Performs three-way comparison between two domains. In the total order defined
-// by this predicate, the lengths of domains will be monotonically decreasing.
-int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain) {
- if (lhs_domain.size() != rhs_domain.size())
- return lhs_domain.size() > rhs_domain.size() ? -1 : 1;
- return lhs_domain.compare(rhs_domain);
-}
-
bool HasNoUpperAscii(base::StringPiece string) {
return std::none_of(string.begin(), string.end(),
[](char c) { return base::IsAsciiUpper(c); });
@@ -342,6 +334,12 @@ UrlRuleOffset SerializeUrlRule(const proto::UrlRule& rule,
return converter.SerializeConvertedRule(builder);
}
+int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain) {
+ if (lhs_domain.size() != rhs_domain.size())
+ return lhs_domain.size() > rhs_domain.size() ? -1 : 1;
+ return lhs_domain.compare(rhs_domain);
+}
+
// UrlPatternIndexBuilder ------------------------------------------------------
UrlPatternIndexBuilder::UrlPatternIndexBuilder(
diff --git a/chromium/components/url_pattern_index/url_pattern_index.h b/chromium/components/url_pattern_index/url_pattern_index.h
index 8f7618871e7..ce991530665 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.h
+++ b/chromium/components/url_pattern_index/url_pattern_index.h
@@ -46,6 +46,14 @@ static_assert(kNGramSize <= sizeof(NGram), "NGram type is too narrow.");
UrlRuleOffset SerializeUrlRule(const proto::UrlRule& rule,
flatbuffers::FlatBufferBuilder* builder);
+// Performs three-way comparison between two domains. In the total order defined
+// by this predicate, the lengths of domains will be monotonically decreasing.
+// Domains of same length are ordered in lexicographic order.
+// Returns a negative value if |lhs_domain| should be ordered before
+// |rhs_domain|, zero if |lhs_domain| is equal to |rhs_domain| and a positive
+// value if |lhs_domain| should be ordered after |rhs_domain|.
+int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain);
+
// The class used to construct an index over the URL patterns of a set of URL
// rules. The rules themselves need to be converted to FlatBuffers format by the
// client of this class, as well as persisted into the |flat_builder| that is
diff --git a/chromium/components/user_manager/fake_user_manager.cc b/chromium/components/user_manager/fake_user_manager.cc
index c046e774c8f..37dd70dc9ab 100644
--- a/chromium/components/user_manager/fake_user_manager.cc
+++ b/chromium/components/user_manager/fake_user_manager.cc
@@ -95,7 +95,7 @@ void FakeUserManager::UserLoggedIn(const AccountId& account_id,
it != users_.end(); ++it) {
if ((*it)->username_hash() == username_hash) {
(*it)->set_is_logged_in(true);
- (*it)->set_profile_is_created();
+ (*it)->SetProfileIsCreated();
logged_in_users_.push_back(*it);
if (!primary_user_)
diff --git a/chromium/components/user_manager/user.cc b/chromium/components/user_manager/user.cc
index 11aba12cb85..a89a91d56e7 100644
--- a/chromium/components/user_manager/user.cc
+++ b/chromium/components/user_manager/user.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@@ -223,10 +224,22 @@ bool User::is_active() const {
return is_active_;
}
+void User::AddProfileCreatedObserver(base::OnceClosure on_profile_created) {
+ DCHECK(!profile_is_created_);
+ on_profile_created_observers_.push_back(std::move(on_profile_created));
+}
+
bool User::IsAffiliated() const {
return is_affiliated_;
}
+void User::SetProfileIsCreated() {
+ profile_is_created_ = true;
+ for (auto& callback : on_profile_created_observers_)
+ std::move(callback).Run();
+ on_profile_created_observers_.clear();
+}
+
void User::SetAffiliation(bool is_affiliated) {
is_affiliated_ = is_affiliated;
}
diff --git a/chromium/components/user_manager/user.h b/chromium/components/user_manager/user.h
index b8940e62b6a..645cf8849fd 100644
--- a/chromium/components/user_manager/user.h
+++ b/chromium/components/user_manager/user.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
@@ -176,6 +177,8 @@ class USER_MANAGER_EXPORT User : public UserInfo {
return CreatePublicAccountUser(account_id);
}
+ void AddProfileCreatedObserver(base::OnceClosure on_profile_created);
+
protected:
friend class UserManagerBase;
friend class chromeos::ChromeUserManagerImpl;
@@ -253,7 +256,7 @@ class USER_MANAGER_EXPORT User : public UserInfo {
void set_is_active(bool is_active) { is_active_ = is_active; }
- void set_profile_is_created() { profile_is_created_ = true; }
+ void SetProfileIsCreated();
// True if user has google account (not a guest or managed user).
bool has_gaia_account() const;
@@ -306,6 +309,8 @@ class USER_MANAGER_EXPORT User : public UserInfo {
// True if the user is affiliated to the device.
bool is_affiliated_ = false;
+ std::vector<base::OnceClosure> on_profile_created_observers_;
+
DISALLOW_COPY_AND_ASSIGN(User);
};
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index 4b52f9f98fd..6ed0497c859 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -374,8 +374,9 @@ void UserManagerBase::SaveUserOAuthStatus(
{
DictionaryPrefUpdate oauth_status_update(GetLocalState(),
kUserOAuthTokenStatus);
- oauth_status_update->SetIntegerWithoutPathExpansion(
- account_id.GetUserEmail(), static_cast<int>(oauth_token_status));
+ oauth_status_update->SetKey(
+ account_id.GetUserEmail(),
+ base::Value(static_cast<int>(oauth_token_status)));
}
GetLocalState()->CommitPendingWrite();
}
@@ -396,8 +397,8 @@ void UserManagerBase::SaveForceOnlineSignin(const AccountId& account_id,
{
DictionaryPrefUpdate force_online_update(GetLocalState(),
kUserForceOnlineSignin);
- force_online_update->SetBooleanWithoutPathExpansion(
- account_id.GetUserEmail(), force_online_signin);
+ force_online_update->SetKey(account_id.GetUserEmail(),
+ base::Value(force_online_signin));
}
GetLocalState()->CommitPendingWrite();
}
@@ -414,8 +415,8 @@ void UserManagerBase::SaveUserDisplayName(const AccountId& account_id,
if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
DictionaryPrefUpdate display_name_update(GetLocalState(),
kUserDisplayName);
- display_name_update->SetStringWithoutPathExpansion(
- account_id.GetUserEmail(), display_name);
+ display_name_update->SetKey(account_id.GetUserEmail(),
+ base::Value(display_name));
}
}
}
@@ -444,8 +445,8 @@ void UserManagerBase::SaveUserDisplayEmail(const AccountId& account_id,
return;
DictionaryPrefUpdate display_email_update(GetLocalState(), kUserDisplayEmail);
- display_email_update->SetStringWithoutPathExpansion(account_id.GetUserEmail(),
- display_email);
+ display_email_update->SetKey(account_id.GetUserEmail(),
+ base::Value(display_email));
}
std::string UserManagerBase::GetUserDisplayEmail(
@@ -470,8 +471,8 @@ void UserManagerBase::SaveUserType(const AccountId& account_id,
return;
DictionaryPrefUpdate user_type_update(GetLocalState(), kUserType);
- user_type_update->SetIntegerWithoutPathExpansion(account_id.GetUserEmail(),
- static_cast<int>(user_type));
+ user_type_update->SetKey(account_id.GetUserEmail(),
+ base::Value(static_cast<int>(user_type)));
GetLocalState()->CommitPendingWrite();
}
@@ -487,8 +488,8 @@ void UserManagerBase::UpdateUserAccountData(
user->set_given_name(given_name);
if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
DictionaryPrefUpdate given_name_update(GetLocalState(), kUserGivenName);
- given_name_update->SetStringWithoutPathExpansion(
- account_id.GetUserEmail(), given_name);
+ given_name_update->SetKey(account_id.GetUserEmail(),
+ base::Value(given_name));
}
}
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn
index 04ab95dbeff..326ef5e0132 100644
--- a/chromium/components/variations/BUILD.gn
+++ b/chromium/components/variations/BUILD.gn
@@ -10,10 +10,7 @@ static_library("variations") {
sources = [
"active_field_trials.cc",
"active_field_trials.h",
- "android/component_jni_registrar.cc",
- "android/component_jni_registrar.h",
"android/variations_associated_data_android.cc",
- "android/variations_associated_data_android.h",
"android/variations_seed_bridge.cc",
"android/variations_seed_bridge.h",
"caching_permuted_entropy_provider.cc",
diff --git a/chromium/components/variations/android/variations_associated_data_android.cc b/chromium/components/variations/android/variations_associated_data_android.cc
index ebbb0a748fd..612d1105b78 100644
--- a/chromium/components/variations/android/variations_associated_data_android.cc
+++ b/chromium/components/variations/android/variations_associated_data_android.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/variations/android/variations_associated_data_android.h"
-
#include <string>
#include "base/android/jni_string.h"
@@ -39,9 +37,5 @@ ScopedJavaLocalRef<jstring> GetFeedbackVariations(
return ConvertUTF8ToJavaString(env, values);
}
-bool RegisterVariationsAssociatedData(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace variations
diff --git a/chromium/components/variations/android/variations_associated_data_android.h b/chromium/components/variations/android/variations_associated_data_android.h
deleted file mode 100644
index 88122d339ad..00000000000
--- a/chromium/components/variations/android/variations_associated_data_android.h
+++ /dev/null
@@ -1,23 +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.
-
-#ifndef COMPONENTS_VARIATIONS_ANDROID_VARIATIONS_ASSOCIATED_DATA_ANDROID_H_
-#define COMPONENTS_VARIATIONS_ANDROID_VARIATIONS_ASSOCIATED_DATA_ANDROID_H_
-
-#include <jni.h>
-
-#include <string>
-
-namespace variations {
-
-namespace android {
-
-// Register JNI methods for VariationsAssociatedData.
-bool RegisterVariationsAssociatedData(JNIEnv* env);
-
-} // namespace android
-
-} // namespace variations
-
-#endif // COMPONENTS_VARIATIONS_ANDROID_VARIATIONS_ASSOCIATED_DATA_ANDROID_H_
diff --git a/chromium/components/variations/client_filterable_state.cc b/chromium/components/variations/client_filterable_state.cc
index 0e36db82e70..6fda4f446c8 100644
--- a/chromium/components/variations/client_filterable_state.cc
+++ b/chromium/components/variations/client_filterable_state.cc
@@ -20,6 +20,8 @@ Study::Platform ClientFilterableState::GetCurrentPlatform() {
return Study::PLATFORM_CHROMEOS;
#elif defined(OS_ANDROID)
return Study::PLATFORM_ANDROID;
+#elif defined(OS_FUCHSIA)
+ return Study::PLATFORM_FUCHSIA;
#elif defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
// Default BSD and SOLARIS to Linux to not break those builds, although these
// platforms are not officially supported by Chrome.
diff --git a/chromium/components/variations/proto/study.proto b/chromium/components/variations/proto/study.proto
index b7a0bb69b1b..2ed59b73337 100644
--- a/chromium/components/variations/proto/study.proto
+++ b/chromium/components/variations/proto/study.proto
@@ -189,6 +189,7 @@ message Study {
PLATFORM_ANDROID = 4;
PLATFORM_IOS = 5;
PLATFORM_ANDROID_WEBVIEW = 6;
+ PLATFORM_FUCHSIA = 7;
}
// Possible form factors Chrome is running on.
diff --git a/chromium/components/variations/service/BUILD.gn b/chromium/components/variations/service/BUILD.gn
index f0e3cc719cc..8cac6ef0ba2 100644
--- a/chromium/components/variations/service/BUILD.gn
+++ b/chromium/components/variations/service/BUILD.gn
@@ -21,6 +21,7 @@ static_library("service") {
"//components/pref_registry",
"//components/prefs",
"//components/variations",
+ "//components/variations/field_trial_config",
"//components/variations/proto",
"//components/version_info",
"//components/web_resource",
diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc
index d01415249b3..af4eae1f4e2 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator.cc
@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
+#include "base/base_switches.h"
#include "base/build_time.h"
#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
@@ -18,9 +19,12 @@
#include "base/version.h"
#include "build/build_config.h"
#include "components/prefs/pref_service.h"
+#include "components/variations/field_trial_config/field_trial_util.h"
+#include "components/variations/platform_field_trials.h"
#include "components/variations/pref_names.h"
#include "components/variations/proto/variations_seed.pb.h"
#include "components/variations/service/variations_service_client.h"
+#include "components/variations/variations_http_header_provider.h"
#include "components/variations/variations_seed_processor.h"
#include "components/variations/variations_switches.h"
#include "ui/base/device_form_factor.h"
@@ -122,7 +126,9 @@ VariationsFieldTrialCreator::VariationsFieldTrialCreator(
: client_(client),
ui_string_overrider_(ui_string_overrider),
seed_store_(local_state),
- create_trials_from_seed_called_(false) {}
+ create_trials_from_seed_called_(false),
+ has_platform_override_(false),
+ platform_override_(Study::PLATFORM_WINDOWS) {}
VariationsFieldTrialCreator::~VariationsFieldTrialCreator() {}
@@ -214,7 +220,9 @@ VariationsFieldTrialCreator::GetClientFilterableStateForVersion(
state->version = version;
state->channel = GetChannelForVariations(client_->GetChannel());
state->form_factor = GetCurrentFormFactor();
- state->platform = ClientFilterableState::GetCurrentPlatform();
+ state->platform = (has_platform_override_)
+ ? platform_override_
+ : ClientFilterableState::GetCurrentPlatform();
state->hardware_class = GetHardwareClass();
#if defined(OS_ANDROID)
// This is set on Android only currently, because the IsLowEndDevice() API
@@ -325,4 +333,81 @@ bool VariationsFieldTrialCreator::LoadSeed(VariationsSeed* seed) {
return seed_store_.LoadSeed(seed);
}
+void VariationsFieldTrialCreator::OverrideVariationsPlatform(
+ Study::Platform platform_override) {
+ has_platform_override_ = true;
+ platform_override_ = platform_override;
+}
+
+bool VariationsFieldTrialCreator::SetupFieldTrials(
+ const char* kEnableGpuBenchmarking,
+ const char* kEnableFeatures,
+ const char* kDisableFeatures,
+ const std::set<std::string>& unforceable_field_trials,
+ std::unique_ptr<const base::FieldTrial::EntropyProvider>
+ low_entropy_provider,
+ std::unique_ptr<base::FeatureList> feature_list,
+ std::vector<std::string>* variation_ids,
+ PlatformFieldTrials* platform_field_trials) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kEnableBenchmarking) ||
+ command_line->HasSwitch(kEnableGpuBenchmarking)) {
+ base::FieldTrial::EnableBenchmarking();
+ }
+
+ if (command_line->HasSwitch(switches::kForceFieldTrialParams)) {
+ bool result = AssociateParamsFromString(
+ command_line->GetSwitchValueASCII(switches::kForceFieldTrialParams));
+ CHECK(result) << "Invalid --" << switches::kForceFieldTrialParams
+ << " list specified.";
+ }
+
+ // Ensure any field trials specified on the command line are initialized.
+ if (command_line->HasSwitch(::switches::kForceFieldTrials)) {
+ // Create field trials without activating them, so that this behaves in a
+ // consistent manner with field trials created from the server.
+ bool result = base::FieldTrialList::CreateTrialsFromString(
+ command_line->GetSwitchValueASCII(::switches::kForceFieldTrials),
+ unforceable_field_trials);
+ CHECK(result) << "Invalid --" << ::switches::kForceFieldTrials
+ << " list specified.";
+ }
+
+ VariationsHttpHeaderProvider* http_header_provider =
+ VariationsHttpHeaderProvider::GetInstance();
+ // Force the variation ids selected in chrome://flags and/or specified using
+ // the command-line flag.
+ bool result = http_header_provider->ForceVariationIds(
+ command_line->GetSwitchValueASCII(switches::kForceVariationIds),
+ variation_ids);
+ CHECK(result) << "Invalid list of variation ids specified (either in --"
+ << switches::kForceVariationIds << " or in chrome://flags)";
+
+ feature_list->InitializeFromCommandLine(
+ command_line->GetSwitchValueASCII(kEnableFeatures),
+ command_line->GetSwitchValueASCII(kDisableFeatures));
+
+#if defined(FIELDTRIAL_TESTING_ENABLED)
+ if (!command_line->HasSwitch(switches::kDisableFieldTrialTestingConfig) &&
+ !command_line->HasSwitch(::switches::kForceFieldTrials) &&
+ !command_line->HasSwitch(switches::kVariationsServerURL)) {
+ AssociateDefaultFieldTrialConfig(feature_list.get());
+ }
+#endif // defined(FIELDTRIAL_TESTING_ENABLED)
+
+ bool has_seed =
+ CreateTrialsFromSeed(std::move(low_entropy_provider), feature_list.get());
+
+ platform_field_trials->SetupFeatureControllingFieldTrials(has_seed,
+ feature_list.get());
+
+ base::FeatureList::SetInstance(std::move(feature_list));
+
+ // This must be called after |local_state_| is initialized.
+ platform_field_trials->SetupFieldTrials();
+
+ return has_seed;
+}
+
} // namespace variations
diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h
index 8e32f8168d1..dceecfb23f9 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.h
+++ b/chromium/components/variations/service/variations_field_trial_creator.h
@@ -15,10 +15,9 @@
#include "components/variations/variations_seed_store.h"
namespace variations {
-class VariationsServiceClient;
-}
-namespace variations {
+class VariationsServiceClient;
+class PlatformFieldTrials;
// Used to setup field trials based on stored variations seed data.
class VariationsFieldTrialCreator {
@@ -28,7 +27,7 @@ class VariationsFieldTrialCreator {
VariationsFieldTrialCreator(PrefService* local_state,
VariationsServiceClient* client,
const UIStringOverrider& ui_string_overrider);
- ~VariationsFieldTrialCreator();
+ virtual ~VariationsFieldTrialCreator();
// Returns what variations will consider to be the latest country. Returns
// empty if it is not available.
@@ -55,6 +54,27 @@ class VariationsFieldTrialCreator {
// Exposed for testing.
void SetCreateTrialsFromSeedCalledForTesting(bool called);
+ // Sets up field trials based on stored variations seed data.
+ // |kEnableGpuBenchmarking|, |kEnableFeatures|, |kDisableFeatures| are
+ // feature controlling flags not directly accesible from variations.
+ // |unforcable_field_trials| contains the list of trials that can not be
+ // overridden.
+ // |low_entropy_provider| allows for field trial randomization.
+ // |feature_list| contains the list of all active features for this client.
+ // |variation_ids| allows for forcing ids selected in chrome://flags and/or
+ // specified using the command-line flag.
+ // |platform_field_trials| provides the platform specific field trial set up
+ // for Chrome.
+ bool SetupFieldTrials(const char* kEnableGpuBenchmarking,
+ const char* kEnableFeatures,
+ const char* kDisableFeatures,
+ const std::set<std::string>& unforceable_field_trials,
+ std::unique_ptr<const base::FieldTrial::EntropyProvider>
+ low_entropy_provider,
+ std::unique_ptr<base::FeatureList> feature_list,
+ std::vector<std::string>* variation_ids,
+ PlatformFieldTrials* platform_field_trials);
+
// Returns all of the client state used for filtering studies.
// As a side-effect, may update the stored permanent consistency country.
std::unique_ptr<ClientFilterableState> GetClientFilterableStateForVersion(
@@ -81,6 +101,10 @@ class VariationsFieldTrialCreator {
// so that it can be overridden by tests.
virtual bool LoadSeed(VariationsSeed* seed);
+ // Allow the platform that is used to filter the set of active trials
+ // to be overridden.
+ void OverrideVariationsPlatform(Study::Platform platform_override);
+
private:
PrefService* local_state() { return seed_store_.local_state(); }
@@ -113,6 +137,14 @@ class VariationsFieldTrialCreator {
// it gets called prior to |StartRepeatedVariationsSeedFetch|.
bool create_trials_from_seed_called_;
+ // Indiciate if OverrideVariationsPlatform has been used to set
+ // |platform_override_|.
+ bool has_platform_override_;
+
+ // Platform to be used for variations filtering, overridding the current
+ // platform.
+ Study::Platform platform_override_;
+
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(VariationsFieldTrialCreator);
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 47fefb3a0a1..c5d83da6a9d 100644
--- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -80,7 +80,7 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
SetCreateTrialsFromSeedCalledForTesting(true);
}
- ~TestVariationsFieldTrialCreator() {
+ ~TestVariationsFieldTrialCreator() override {
delete client_;
client_ = 0;
}
diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc
index 11c418e4faf..01b48fa0b1e 100644
--- a/chromium/components/variations/service/variations_service.cc
+++ b/chromium/components/variations/service/variations_service.cc
@@ -194,6 +194,22 @@ bool GetInstanceManipulations(const net::HttpResponseHeaders* headers,
return true;
}
+// Variations seed fetching is only enabled in official Chrome builds, if a URL
+// is specified on the command line, and for testing.
+bool IsFetchingEnabled() {
+#if !defined(GOOGLE_CHROME_BUILD)
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kVariationsServerURL) &&
+ !g_enabled_for_testing) {
+ DVLOG(1)
+ << "Not performing repeated fetching in unofficial build without --"
+ << switches::kVariationsServerURL << " specified.";
+ return false;
+ }
+#endif
+ return true;
+}
+
} // namespace
VariationsService::VariationsService(
@@ -256,28 +272,10 @@ VariationsService::~VariationsService() {
void VariationsService::PerformPreMainMessageLoopStartup() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- StartRepeatedVariationsSeedFetch();
-}
-
-void VariationsService::StartRepeatedVariationsSeedFetch() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- // Initialize the Variations server URL.
- variations_server_url_ =
- GetVariationsServerURL(policy_pref_service_, restrict_mode_);
-
- // Check that |CreateTrialsFromSeed| was called, which is necessary to
- // retrieve the serial number that will be sent to the server.
- DCHECK(field_trial_creator_.create_trials_from_seed_called());
+ if (!IsFetchingEnabled())
+ return;
- DCHECK(!request_scheduler_.get());
- request_scheduler_.reset(VariationsRequestScheduler::Create(
- base::Bind(&VariationsService::FetchVariationsSeed,
- weak_ptr_factory_.GetWeakPtr()),
- local_state_));
- // Note that the act of starting the scheduler will start the fetch, if the
- // scheduler deems appropriate.
- request_scheduler_->Start();
+ StartRepeatedVariationsSeedFetch();
}
std::string VariationsService::LoadPermanentConsistencyCountry(
@@ -300,6 +298,9 @@ void VariationsService::RemoveObserver(Observer* observer) {
void VariationsService::OnAppEnterForeground() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!IsFetchingEnabled())
+ return;
+
// On mobile platforms, initialize the fetch scheduler when we receive the
// first app foreground notification.
if (!request_scheduler_)
@@ -387,17 +388,6 @@ std::unique_ptr<VariationsService> VariationsService::Create(
const char* disable_network_switch,
const UIStringOverrider& ui_string_overrider) {
std::unique_ptr<VariationsService> result;
-#if !defined(GOOGLE_CHROME_BUILD)
- // Unless the URL was provided, unsupported builds should return NULL to
- // indicate that the service should not be used.
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kVariationsServerURL) &&
- !g_enabled_for_testing) {
- DVLOG(1) << "Not creating VariationsService in unofficial build without --"
- << switches::kVariationsServerURL << " specified.";
- return result;
- }
-#endif
result.reset(new VariationsService(
std::move(client),
base::MakeUnique<web_resource::ResourceRequestAllowedNotifier>(
@@ -413,6 +403,7 @@ void VariationsService::EnableForTesting() {
void VariationsService::DoActualFetch() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(IsFetchingEnabled());
// Pessimistically assume the fetch will fail. The failure streak will be
// reset upon success.
@@ -442,7 +433,7 @@ void VariationsService::DoActualFetch() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled by settings."
policy_exception_justification:
"Not implemented, considered not required."
@@ -518,6 +509,27 @@ VariationsService::CreateLowEntropyProvider() {
return state_manager_->CreateLowEntropyProvider();
}
+void VariationsService::StartRepeatedVariationsSeedFetch() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ // Initialize the Variations server URL.
+ variations_server_url_ =
+ GetVariationsServerURL(policy_pref_service_, restrict_mode_);
+
+ // Check that |CreateTrialsFromSeed| was called, which is necessary to
+ // retrieve the serial number that will be sent to the server.
+ DCHECK(field_trial_creator_.create_trials_from_seed_called());
+
+ DCHECK(!request_scheduler_.get());
+ request_scheduler_.reset(VariationsRequestScheduler::Create(
+ base::Bind(&VariationsService::FetchVariationsSeed,
+ weak_ptr_factory_.GetWeakPtr()),
+ local_state_));
+ // Note that the act of starting the scheduler will start the fetch, if the
+ // scheduler deems appropriate.
+ request_scheduler_->Start();
+}
+
void VariationsService::FetchVariationsSeed() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -708,6 +720,20 @@ std::string VariationsService::GetLatestCountry() const {
return field_trial_creator_.GetLatestCountry();
}
+bool VariationsService::SetupFieldTrials(
+ const char* kEnableGpuBenchmarking,
+ const char* kEnableFeatures,
+ const char* kDisableFeatures,
+ const std::set<std::string>& unforceable_field_trials,
+ std::unique_ptr<base::FeatureList> feature_list,
+ std::vector<std::string>* variation_ids,
+ variations::PlatformFieldTrials* platform_field_trials) {
+ return field_trial_creator_.SetupFieldTrials(
+ kEnableGpuBenchmarking, kEnableFeatures, kDisableFeatures,
+ unforceable_field_trials, CreateLowEntropyProvider(),
+ std::move(feature_list), variation_ids, platform_field_trials);
+}
+
bool VariationsService::CreateTrialsFromSeed(base::FeatureList* feature_list) {
return field_trial_creator_.CreateTrialsFromSeed(CreateLowEntropyProvider(),
feature_list);
diff --git a/chromium/components/variations/service/variations_service.h b/chromium/components/variations/service/variations_service.h
index 75b6a774198..0ea096c5e39 100644
--- a/chromium/components/variations/service/variations_service.h
+++ b/chromium/components/variations/service/variations_service.h
@@ -86,11 +86,6 @@ class VariationsService
// Should be called before startup of the main message loop.
void PerformPreMainMessageLoopStartup();
- // Calls FetchVariationsSeed once and repeats this periodically. See
- // implementation for details on the period. Must be called after
- // |CreateTrialsFromSeed|.
- void StartRepeatedVariationsSeedFetch();
-
// Adds an observer to listen for detected experiment changes.
void AddObserver(Observer* observer);
@@ -170,6 +165,15 @@ class VariationsService
// Exposed for testing.
void GetClientFilterableStateForVersionCalledForTesting();
+ // Wrapper around VariationsFieldTrialCreator::SetupFieldTrials().
+ bool SetupFieldTrials(const char* kEnableGpuBenchmarking,
+ const char* kEnableFeatures,
+ const char* kDisableFeatures,
+ const std::set<std::string>& unforceable_field_trials,
+ std::unique_ptr<base::FeatureList> feature_list,
+ std::vector<std::string>* variation_ids,
+ variations::PlatformFieldTrials* platform_field_trials);
+
protected:
// Starts the fetching process once, where |OnURLFetchComplete| is called with
// the response.
@@ -215,6 +219,8 @@ class VariationsService
LoadPermanentConsistencyCountry);
FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, CountryHeader);
FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, GetVariationsServerURL);
+ FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, RequestsInitiallyAllowed);
+ FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, RequestsInitiallyNotAllowed);
FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest,
SafeMode_SuccessfulFetchClearsFailureStreaks);
FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest,
@@ -237,6 +243,11 @@ class VariationsService
LOAD_COUNTRY_MAX,
};
+ // Calls FetchVariationsSeed once and repeats this periodically. See
+ // implementation for details on the period. Must be called after
+ // |CreateTrialsFromSeed|.
+ void StartRepeatedVariationsSeedFetch();
+
// Checks if prerequisites for fetching the Variations seed are met, and if
// so, performs the actual fetch using |DoActualFetch|.
void FetchVariationsSeed();
diff --git a/chromium/components/variations/service/variations_service_unittest.cc b/chromium/components/variations/service/variations_service_unittest.cc
index 54718df8434..8ba2957a302 100644
--- a/chromium/components/variations/service/variations_service_unittest.cc
+++ b/chromium/components/variations/service/variations_service_unittest.cc
@@ -273,6 +273,7 @@ class VariationsServiceTest : public ::testing::Test {
VariationsServiceTest()
: enabled_state_provider_(
new metrics::TestEnabledStateProvider(false, false)) {
+ VariationsService::EnableForTesting();
VariationsService::RegisterPrefs(prefs_.registry());
metrics::CleanExitBeacon::RegisterPrefs(prefs_.registry());
metrics::MetricsStateManager::RegisterPrefs(prefs_.registry());
diff --git a/chromium/components/variations/study_filtering_unittest.cc b/chromium/components/variations/study_filtering_unittest.cc
index c9728e4fddc..acf097ae239 100644
--- a/chromium/components/variations/study_filtering_unittest.cc
+++ b/chromium/components/variations/study_filtering_unittest.cc
@@ -215,8 +215,7 @@ TEST(VariationsStudyFilteringTest, CheckStudyPlatform) {
Study::PLATFORM_WINDOWS, Study::PLATFORM_MAC,
Study::PLATFORM_LINUX, Study::PLATFORM_CHROMEOS,
Study::PLATFORM_ANDROID, Study::PLATFORM_IOS,
- Study::PLATFORM_ANDROID_WEBVIEW,
- };
+ Study::PLATFORM_ANDROID_WEBVIEW, Study::PLATFORM_FUCHSIA};
ASSERT_EQ(Study::Platform_ARRAYSIZE, static_cast<int>(arraysize(platforms)));
bool platform_added[arraysize(platforms)] = { 0 };
diff --git a/chromium/components/vector_icons/BUILD.gn b/chromium/components/vector_icons/BUILD.gn
index 24c915b5f8f..b03c1898576 100644
--- a/chromium/components/vector_icons/BUILD.gn
+++ b/chromium/components/vector_icons/BUILD.gn
@@ -8,6 +8,7 @@ aggregate_vector_icons("components_vector_icons") {
icon_directory = "."
icons = [
+ "accessibility.icon",
"back_arrow.1x.icon",
"back_arrow.icon",
"bluetooth_connected.icon",
@@ -19,6 +20,7 @@ aggregate_vector_icons("components_vector_icons") {
"error_circle.icon",
"forward_arrow.1x.icon",
"forward_arrow.icon",
+ "help_outline.icon",
"info_outline.icon",
"location_on.icon",
"lock.icon",
@@ -31,8 +33,11 @@ aggregate_vector_icons("components_vector_icons") {
"notifications.icon",
"notifications_off.icon",
"protocol_handler.icon",
+ "reload.1x.icon",
+ "reload.icon",
"screen_share.icon",
"search.icon",
+ "usb.icon",
"videocam.icon",
"warning.icon",
]
diff --git a/chromium/components/vector_icons/README.md b/chromium/components/vector_icons/README.md
new file mode 100644
index 00000000000..e8922c4161a
--- /dev/null
+++ b/chromium/components/vector_icons/README.md
@@ -0,0 +1,48 @@
+# Vectorized icons in native Chrome UI
+
+## Background
+
+Chrome can draw vectorized images using Skia. Vector images have the advantages of looking better at different scale factors or sizes, can be easily colorized at runtime, and reduce the chrome binary size.
+
+Chrome uses .icon files to describe vector icons. This is a bespoke file format which is actually a C++ array definition. At build time, the .icon files are composed into a .cc file which is compiled into the binary.
+
+Vector icons can be found in various vector_icons subdirectories throughout the code base. Use `components/vector_icons/` for generic icons shared among many directories and components, or more specific directories such as `ui/views/vector_icons` or `ash/resources/vector_icons` for less widely used icons.
+
+Some of the icons have **.1x.icon** variants which are used when the device scale factor is 100%. For any other scale factor, the **.icon** variant will be used. The 1x variants are generally only necessary for very small icons which may look fuzzy if shrunk from a larger icon.
+
+## Converting an SVG to .icon format
+
+[This tool](http://evanstade.github.io/skiafy/) generates .icon file output from SVGs. (If you want to contribute improvements, [here's the project](https://github.com/evanstade/skiafy).)
+
+It handles only a small subset of SVG (paths, circles, etc.) and it's finicky about what it expects as the format, but with a minor amount of manual intervention beforehand, it mostly spits out usable .icon output. It will often work better if you run the SVG through SVGO first, which is a separate project (an SVG minifier). [Jake Archibald's SVGOMG](https://jakearchibald.github.io/svgomg/) is a web interface to SVGO. If any manual adjustments need to be made to the output, the [SVG Path spec](https://www.w3.org/TR/SVG/paths.html) is a helpful reference.
+
+Some SVGs are already pretty minimal, like the ones at [the Material Design Icon repository](https://material.io/icons/) so they don't require much if any adjustment, but some SVG editing tools like Sketch leave a lot of random cruft so SVGOMG helps a lot. Take the output and insert into a .icon file.
+
+## Using .icon files
+
+Once you have created an .icon file, place it in an appropriate vector_icon subdirectory and add the filename to the corresponding BUILD.gn. A constant is automatically generated so that the icon can be referenced at runtime. The icon file foo_bar.icon is mapped to the constant name of kFooBarIcon ('k' + camel-cased filename + 'Icon') and a sample call site to create this icon looks something like:
+
+ gfx::CreateVectorIcon(kFooBarIcon, 32, color_utils::DeriveDefaultIconColor(text_color));
+
+If the size argument is unspecified, the size will be taken from the .icon file (or the .1x.icon if more than one exists). The icon's name should match its identifier on [the MD icons site](https://material.io/icons/) if that's where it came from. For example, `ic_accessibility` would become `accessibility.icon`.
+
+## FAQ
+
+### Where can I use vector icons?
+
+Chrome's native UI on desktop platforms. Currently the vector icons are in extensive use on Views platforms, where Skia is the normal drawing tool. Mac uses them sometimes, but optimizing performance is still a [TODO](http://crbug.com/595035) so many places stick with raster assets. The files in `chrome/app/theme/default_*_percent/legacy` are ones that have been switched to vector icons for Views but not yet for OS X. If you need to add raster assets (PNG) for mobile or OS X, please make sure to limit their inclusion to those platforms.
+
+### How can I preview vector icons?
+
+Use [this extension](https://github.com/sadrulhc/vector-icons) to preview icons in [codesearch](http://cs.chromium.org/).
+
+You can also build and run the `views_examples_exe` (or `views_examples_with_content_exe`) target and select "Vector Icons" from the dropdown menu. This loads a simple interface which allows you view a provided vector icon file at a specified size and color. Contributions to improve this interface are welcome ([bug](https://bugs.chromium.org/p/chromium/issues/detail?id=630295)).
+
+### Can my vector icon have more than one color?
+
+Yes. You can hard-code colors for specific path elements by adding a `PATH_COLOR_ARGB` command to the appropriate place within the .icon file. Any path elements which are not given a hard-coded color in this manner will use the color provided to `CreateVectorIcon()` at runtime.
+
+
+### When introducing a new icon, should I use a PNG or a vector icon?
+
+Use a vector icon, unless the icon is extremely complex (e.g., a product logo). Also see above, "Where can I use vector icons?"
diff --git a/chromium/components/vector_icons/accessibility.icon b/chromium/components/vector_icons/accessibility.icon
new file mode 100644
index 00000000000..62b8b71ccf2
--- /dev/null
+++ b/chromium/components/vector_icons/accessibility.icon
@@ -0,0 +1,25 @@
+// 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.
+
+CANVAS_DIMENSIONS, 32,
+MOVE_TO, 16, 11.44f,
+R_CUBIC_TO, -3.5f, 0, -7.2f, -0.62f, -10.27f, -1.44f,
+LINE_TO, 5, 12.16f,
+R_CUBIC_TO, 2.27f, 0.77f, 5.56f, 1.05f, 8, 1.34f,
+V_LINE_TO, 28,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -7,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 7,
+R_H_LINE_TO, 2,
+V_LINE_TO, 13.5f,
+R_CUBIC_TO, 2.44f, -0.29f, 5.73f, -0.57f, 8, -1.34f,
+LINE_TO, 26.27f, 10,
+R_CUBIC_TO, -3.07f, 0.82f, -6.77f, 1.44f, -10.27f, 1.44f,
+CLOSE,
+R_MOVE_TO, 0, -1.94f,
+R_ARC_TO, 2.5f, 2.5f, 0, 1, 0, 0, -5,
+R_ARC_TO, 2.5f, 2.5f, 0, 0, 0, 0, 5,
+CLOSE,
+END
diff --git a/chromium/components/vector_icons/help_outline.icon b/chromium/components/vector_icons/help_outline.icon
new file mode 100644
index 00000000000..9f07e956717
--- /dev/null
+++ b/chromium/components/vector_icons/help_outline.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 11, 18,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, 1, -16,
+CUBIC_TO, 6.48f, 2, 2, 6.48f, 2, 12,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+CUBIC_TO_SHORTHAND, 17.52f, 2, 12, 2,
+CLOSE,
+R_MOVE_TO, 0, 18,
+R_CUBIC_TO, -4.41f, 0, -8, -3.59f, -8, -8,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 4.41f, -3.59f, 8, -8, 8,
+CLOSE,
+R_MOVE_TO, 0, -14,
+R_CUBIC_TO, -2.21f, 0, -4, 1.79f, -4, 4,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+R_CUBIC_TO, 0, 2, -3, 1.75f, -3, 5,
+R_H_LINE_TO, 2,
+R_CUBIC_TO, 0, -2.25f, 3, -2.5f, 3, -5,
+R_CUBIC_TO, 0, -2.21f, -1.79f, -4, -4, -4,
+CLOSE,
+END
diff --git a/chromium/components/vector_icons/reload.1x.icon b/chromium/components/vector_icons/reload.1x.icon
new file mode 100644
index 00000000000..77d5c53f83b
--- /dev/null
+++ b/chromium/components/vector_icons/reload.1x.icon
@@ -0,0 +1,23 @@
+// 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.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 15, 1,
+LINE_TO, 15, 7,
+LINE_TO, 9, 7,
+LINE_TO, 11.62f, 4.37f,
+CUBIC_TO, 10.67f, 3.43f, 9.44f, 3, 8, 3,
+CUBIC_TO, 5.09f, 3, 3, 5.1f, 3, 8,
+CUBIC_TO, 3, 10.9f, 5.09f, 13, 8, 13,
+CUBIC_TO, 10.3f, 13, 12.08f, 11.81f, 12.75f, 9.83f,
+LINE_TO, 12.77f, 9.79f,
+CUBIC_TO, 12.93f, 9.44f, 13.47f, 9.18f, 13.76f, 9.18f,
+CUBIC_TO, 14.15f, 9.18f, 14.79f, 9.41f, 14.79f, 10.01f,
+CUBIC_TO, 14.79f, 10.14f, 14.71f, 10.46f, 14.66f, 10.57f,
+CUBIC_TO, 13.66f, 13.13f, 10.98f, 15, 8.03f, 15,
+CUBIC_TO, 4.15f, 15, 1, 11.87f, 1, 8,
+CUBIC_TO, 1, 4.13f, 4.15f, 1, 8.03f, 1,
+CUBIC_TO, 9.96f, 1, 11.7f, 1.77f, 12.97f, 3.03f,
+CLOSE,
+END
diff --git a/chromium/components/vector_icons/reload.icon b/chromium/components/vector_icons/reload.icon
new file mode 100644
index 00000000000..3d7275846da
--- /dev/null
+++ b/chromium/components/vector_icons/reload.icon
@@ -0,0 +1,27 @@
+// 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.
+
+CANVAS_DIMENSIONS, 32,
+MOVE_TO, 25.1f, 20.15f,
+LINE_TO, 25.08f, 20.14f,
+CUBIC_TO, 23.51f, 23.59f, 20.04f, 26, 16, 26,
+CUBIC_TO, 10.48f, 26, 6, 21.52f, 6, 16,
+CUBIC_TO, 6, 10.48f, 10.48f, 6, 16, 6,
+CUBIC_TO, 19.02f, 6, 21.72f, 7.34f, 23.55f, 9.45f,
+LINE_TO, 23.55f, 9.45f,
+LINE_TO, 19, 14,
+LINE_TO, 25.8f, 14,
+LINE_TO, 28.83f, 14,
+LINE_TO, 30, 14,
+LINE_TO, 30, 3,
+LINE_TO, 25.67f, 7.33f,
+CUBIC_TO, 23.3f, 4.67f, 19.85f, 3, 16, 3,
+CUBIC_TO, 8.82f, 3, 3, 8.82f, 3, 16,
+CUBIC_TO, 3, 23.18f, 8.82f, 29, 16, 29,
+CUBIC_TO, 21.27f, 29, 25.8f, 25.86f, 27.84f, 21.34f,
+CUBIC_TO, 27.96f, 21.13f, 28.03f, 20.88f, 28.03f, 20.61f,
+CUBIC_TO, 28.03f, 19.78f, 27.36f, 19.11f, 26.53f, 19.11f,
+CUBIC_TO, 25.87f, 19.11f, 25.3f, 19.55f, 25.1f, 20.15f,
+CLOSE,
+END
diff --git a/chromium/components/vector_icons/usb.icon b/chromium/components/vector_icons/usb.icon
new file mode 100644
index 00000000000..61d9679015e
--- /dev/null
+++ b/chromium/components/vector_icons/usb.icon
@@ -0,0 +1,38 @@
+// 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.
+
+MOVE_TO, 30, 14,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 4,
+R_H_LINE_TO, -6,
+V_LINE_TO, 10,
+R_H_LINE_TO, 4,
+R_LINE_TO, -6, -8,
+R_LINE_TO, -6, 8,
+R_H_LINE_TO, 4,
+R_V_LINE_TO, 16,
+R_H_LINE_TO, -6,
+R_V_LINE_TO, -4.14f,
+R_CUBIC_TO, 1.41f, -0.73f, 2.4f, -2.16f, 2.4f, -3.86f,
+R_CUBIC_TO, 0, -2.43f, -1.97f, -4.4f, -4.4f, -4.4f,
+R_CUBIC_TO, -2.43f, 0, -4.4f, 1.97f, -4.4f, 4.4f,
+R_CUBIC_TO, 0, 1.7f, 0.99f, 3.13f, 2.4f, 3.86f,
+V_LINE_TO, 26,
+R_CUBIC_TO, 0, 2.21f, 1.79f, 4, 4, 4,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6.1f,
+R_CUBIC_TO, -1.42f, 0.73f, -2.4f, 2.19f, -2.4f, 3.9f,
+R_CUBIC_TO, 0, 2.43f, 1.97f, 4.4f, 4.4f, 4.4f,
+R_CUBIC_TO, 2.43f, 0, 4.4f, -1.97f, 4.4f, -4.4f,
+R_CUBIC_TO, 0, -1.71f, -0.98f, -3.17f, -2.4f, -3.9f,
+V_LINE_TO, 30,
+R_H_LINE_TO, 6,
+R_CUBIC_TO, 2.21f, 0, 4, -1.79f, 4, -4,
+R_V_LINE_TO, -4,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -8,
+R_H_LINE_TO, -8,
+CLOSE,
+END
diff --git a/chromium/components/viz/BUILD.gn b/chromium/components/viz/BUILD.gn
index 2795882f245..7c33150e304 100644
--- a/chromium/components/viz/BUILD.gn
+++ b/chromium/components/viz/BUILD.gn
@@ -17,6 +17,7 @@ viz_test("viz_unittests") {
"//components/viz/service:unit_tests",
"//components/viz/test:test_suite",
"//components/viz/test:test_support",
+ "//components/viz/test:unit_tests",
"//mojo/edk/system",
]
diff --git a/chromium/components/viz/DEPS b/chromium/components/viz/DEPS
index c4d836f14ed..ecdd1168819 100644
--- a/chromium/components/viz/DEPS
+++ b/chromium/components/viz/DEPS
@@ -1,4 +1,6 @@
include_rules = [
"-components/viz",
"+components/viz/common",
+ "+ui/base",
+ "+ui/gfx",
]
diff --git a/chromium/components/viz/OWNERS b/chromium/components/viz/OWNERS
index 6c960a1408b..88e5ae49f23 100644
--- a/chromium/components/viz/OWNERS
+++ b/chromium/components/viz/OWNERS
@@ -1,10 +1,54 @@
+# For patches touching specific topics, try the topic-specific OWNERS. For
+# patches that touch multiple areas or if you aren't sure, try the general
+# OWNERS at the bottom.
+#
+# Folks listed as unofficial can't do OWNERS approvals but are good people to
+# ask for informal reviews.
+
+# display / resources / quads / passes
+danakj@chromium.org
+enne@chromium.org
+piman@chromium.org
+vmpstr@chromium.org
+weiliangc@chromium.org
+
+# display_embedder / ozone
+reveman@chromium.org
+rjkroege@chromium.org
+sadrul@chromium.org
+
+# frame sinks / surfaces
+enne@chromium.org
fsamuel@chromium.org
+kylechar@chromium.org
+
+# gpu
+danakj@chromium.org
+piman@chromium.org
+sadrul@chromium.org
+
+# hit testing
rjkroege@chromium.org
sadrul@chromium.org
+vollick@chromium.org
+
+# math / geometry
+flackr@chromium.org
+vollick@chromium.org
+
+# overlays
+dcastagna@chromium.org
+reveman@chromium.org
+
+# scheduling / begin frames
+brianderson@chromium.org
+skyostil@chromium.org
+sunnyps@chromium.org
+
+# general
danakj@chromium.org
enne@chromium.org
vmpstr@chromium.org
-piman@chromium.org
-jbauman@chromium.org
-# COMPONENT: Internals>GPU>Internals
+# TEAM: graphics-dev@chromium.org
+# COMPONENT: Internals>Compositing
diff --git a/chromium/components/viz/PRESUBMIT.py b/chromium/components/viz/PRESUBMIT.py
index a3b3d1b46d1..c8bef10af0d 100644
--- a/chromium/components/viz/PRESUBMIT.py
+++ b/chromium/components/viz/PRESUBMIT.py
@@ -2,317 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Top-level presubmit script for components/viz.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-import re
-import string
-
-VIZ_SOURCE_FILES=(r'^components[\\/]viz[\\/].*\.(cc|h)$',)
-
-def CheckChangeLintsClean(input_api, output_api):
- source_filter = lambda x: input_api.FilterSourceFile(
- x, white_list=VIZ_SOURCE_FILES, black_list=None)
-
- return input_api.canned_checks.CheckChangeLintsClean(
- input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
-
-def CheckAsserts(input_api, output_api, white_list=VIZ_SOURCE_FILES, black_list=None):
- black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
- source_file_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list)
-
- assert_files = []
-
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- # WebKit ASSERT() is not allowed.
- if re.search(r"\bASSERT\(", contents):
- assert_files.append(f.LocalPath())
-
- if assert_files:
- return [output_api.PresubmitError(
- 'These files use ASSERT instead of using DCHECK:',
- items=assert_files)]
- return []
-
-def CheckStdAbs(input_api, output_api,
- white_list=VIZ_SOURCE_FILES, black_list=None):
- black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
- source_file_filter = lambda x: input_api.FilterSourceFile(x,
- white_list,
- black_list)
-
- using_std_abs_files = []
- found_fabs_files = []
- missing_std_prefix_files = []
-
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- if re.search(r"using std::f?abs;", contents):
- using_std_abs_files.append(f.LocalPath())
- if re.search(r"\bfabsf?\(", contents):
- found_fabs_files.append(f.LocalPath());
-
- no_std_prefix = r"(?<!std::)"
- # Matches occurrences of abs/absf/fabs/fabsf without a "std::" prefix.
- abs_without_prefix = r"%s(\babsf?\()" % no_std_prefix
- fabs_without_prefix = r"%s(\bfabsf?\()" % no_std_prefix
- # Skips matching any lines that have "// NOLINT".
- no_nolint = r"(?![^\n]*//\s+NOLINT)"
-
- expression = re.compile("(%s|%s)%s" %
- (abs_without_prefix, fabs_without_prefix, no_nolint))
- if expression.search(contents):
- missing_std_prefix_files.append(f.LocalPath())
-
- result = []
- if using_std_abs_files:
- result.append(output_api.PresubmitError(
- 'These files have "using std::abs" which is not permitted.',
- items=using_std_abs_files))
- if found_fabs_files:
- result.append(output_api.PresubmitError(
- 'std::abs() should be used instead of std::fabs() for consistency.',
- items=found_fabs_files))
- if missing_std_prefix_files:
- result.append(output_api.PresubmitError(
- 'These files use abs(), absf(), fabs(), or fabsf() without qualifying '
- 'the std namespace. Please use std::abs() in all places.',
- items=missing_std_prefix_files))
- return result
-
-def CheckPassByValue(input_api,
- output_api,
- white_list=VIZ_SOURCE_FILES,
- black_list=None):
- black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
- source_file_filter = lambda x: input_api.FilterSourceFile(x,
- white_list,
- black_list)
-
- local_errors = []
-
- # Well-defined simple classes the same size as a primitive type.
- pass_by_value_types = ['base::Time',
- 'base::TimeTicks',
- ]
-
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- match = re.search(
- r'\bconst +' + '(?P<type>(%s))&' %
- string.join(pass_by_value_types, '|'),
- contents)
- if match:
- local_errors.append(output_api.PresubmitError(
- '%s passes %s by const ref instead of by value.' %
- (f.LocalPath(), match.group('type'))))
- return local_errors
-
-def CheckTodos(input_api, output_api):
- errors = []
-
- source_file_filter = lambda x: x
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- if ('FIX'+'ME') in contents:
- errors.append(f.LocalPath())
-
- if errors:
- return [output_api.PresubmitError(
- 'All TODO comments should be of the form TODO(name/bug). ' +
- 'Use TODO instead of FIX' + 'ME',
- items=errors)]
- return []
-
-def CheckDoubleAngles(input_api, output_api, white_list=VIZ_SOURCE_FILES,
- black_list=None):
- errors = []
-
- source_file_filter = lambda x: input_api.FilterSourceFile(x,
- white_list,
- black_list)
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- if ('> >') in contents:
- errors.append(f.LocalPath())
-
- if errors:
- return [output_api.PresubmitError('Use >> instead of > >:', items=errors)]
- return []
-
-def CheckUniquePtr(input_api, output_api,
- white_list=VIZ_SOURCE_FILES, black_list=None):
- black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
- source_file_filter = lambda x: input_api.FilterSourceFile(x,
- white_list,
- black_list)
- errors = []
- for f in input_api.AffectedSourceFiles(source_file_filter):
- for line_number, line in f.ChangedContents():
- # Disallow:
- # return std::unique_ptr<T>(foo);
- # bar = std::unique_ptr<T>(foo);
- # But allow:
- # return std::unique_ptr<T[]>(foo);
- # bar = std::unique_ptr<T[]>(foo);
- if re.search(r'(=|\breturn)\s*std::unique_ptr<.*?(?<!])>\([^)]+\)', line):
- errors.append(output_api.PresubmitError(
- ('%s:%d uses explicit std::unique_ptr constructor. ' +
- 'Use base::MakeUnique<T>() instead.') %
- (f.LocalPath(), line_number)))
- # Disallow:
- # std::unique_ptr<T>()
- if re.search(r'\bstd::unique_ptr<.*?>\(\)', line):
- errors.append(output_api.PresubmitError(
- '%s:%d uses std::unique_ptr<T>(). Use nullptr instead.' %
- (f.LocalPath(), line_number)))
- return errors
-
-def FindUnquotedQuote(contents, pos):
- match = re.search(r"(?<!\\)(?P<quote>\")", contents[pos:])
- return -1 if not match else match.start("quote") + pos
-
-def FindUselessIfdefs(input_api, output_api):
- errors = []
- source_file_filter = lambda x: x
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- if re.search(r'#if\s*0\s', contents):
- errors.append(f.LocalPath())
- if errors:
- return [output_api.PresubmitError(
- 'Don\'t use #if '+'0; just delete the code.',
- items=errors)]
- return []
-
-def FindNamespaceInBlock(pos, namespace, contents, whitelist=[]):
- open_brace = -1
- close_brace = -1
- quote = -1
- name = -1
- brace_count = 1
- quote_count = 0
- while pos < len(contents) and brace_count > 0:
- if open_brace < pos: open_brace = contents.find("{", pos)
- if close_brace < pos: close_brace = contents.find("}", pos)
- if quote < pos: quote = FindUnquotedQuote(contents, pos)
- if name < pos: name = contents.find(("%s::" % namespace), pos)
-
- if name < 0:
- return False # The namespace is not used at all.
- if open_brace < 0:
- open_brace = len(contents)
- if close_brace < 0:
- close_brace = len(contents)
- if quote < 0:
- quote = len(contents)
-
- next = min(open_brace, min(close_brace, min(quote, name)))
-
- if next == open_brace:
- brace_count += 1
- elif next == close_brace:
- brace_count -= 1
- elif next == quote:
- quote_count = 0 if quote_count else 1
- elif next == name and not quote_count:
- in_whitelist = False
- for w in whitelist:
- if re.match(w, contents[next:]):
- in_whitelist = True
- break
- if not in_whitelist:
- return True
- pos = next + 1
- return False
-
-# Checks for the use of viz:: within the viz namespace, which is usually
-# redundant.
-def CheckNamespace(input_api, output_api):
- errors = []
-
- source_file_filter = lambda x: x
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
- match = re.search(r'namespace\s*viz\s*{', contents)
- if match:
- whitelist = []
- if FindNamespaceInBlock(match.end(), 'viz', contents, whitelist=whitelist):
- errors.append(f.LocalPath())
-
- if errors:
- return [output_api.PresubmitError(
- 'Do not use viz:: inside of the viz namespace.',
- items=errors)]
- return []
-
-def CheckForUseOfWrongClock(input_api,
- output_api,
- white_list=VIZ_SOURCE_FILES,
- black_list=None):
- """Make sure new lines of code don't use a clock susceptible to skew."""
- black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
- source_file_filter = lambda x: input_api.FilterSourceFile(x,
- white_list,
- black_list)
- # Regular expression that should detect any explicit references to the
- # base::Time type (or base::Clock/DefaultClock), whether in using decls,
- # typedefs, or to call static methods.
- base_time_type_pattern = r'(^|\W)base::(Time|Clock|DefaultClock)(\W|$)'
-
- # Regular expression that should detect references to the base::Time class
- # members, such as a call to base::Time::Now.
- base_time_member_pattern = r'(^|\W)(Time|Clock|DefaultClock)::'
-
- # Regular expression to detect "using base::Time" declarations. We want to
- # prevent these from triggerring a warning. For example, it's perfectly
- # reasonable for code to be written like this:
- #
- # using base::Time;
- # ...
- # int64 foo_us = foo_s * Time::kMicrosecondsPerSecond;
- using_base_time_decl_pattern = r'^\s*using\s+(::)?base::Time\s*;'
-
- # Regular expression to detect references to the kXXX constants in the
- # base::Time class. We want to prevent these from triggerring a warning.
- base_time_konstant_pattern = r'(^|\W)Time::k\w+'
-
- problem_re = input_api.re.compile(
- r'(' + base_time_type_pattern + r')|(' + base_time_member_pattern + r')')
- exception_re = input_api.re.compile(
- r'(' + using_base_time_decl_pattern + r')|(' +
- base_time_konstant_pattern + r')')
- problems = []
- for f in input_api.AffectedSourceFiles(source_file_filter):
- for line_number, line in f.ChangedContents():
- if problem_re.search(line):
- if not exception_re.search(line):
- problems.append(
- ' %s:%d\n %s' % (f.LocalPath(), line_number, line.strip()))
-
- if problems:
- return [output_api.PresubmitPromptOrNotify(
- 'You added one or more references to the base::Time class and/or one\n'
- 'of its member functions (or base::Clock/DefaultClock). In cc code,\n'
- 'it is most certainly incorrect! Instead use base::TimeTicks.\n\n'
- '\n'.join(problems))]
- else:
- return []
+"""Top-level presubmit script for components/viz."""
def CheckChangeOnUpload(input_api, output_api):
- results = []
- results += CheckAsserts(input_api, output_api)
- results += CheckStdAbs(input_api, output_api)
- results += CheckPassByValue(input_api, output_api)
- results += CheckChangeLintsClean(input_api, output_api)
- results += CheckTodos(input_api, output_api)
- results += CheckDoubleAngles(input_api, output_api)
- results += CheckUniquePtr(input_api, output_api)
- results += CheckNamespace(input_api, output_api)
- results += CheckForUseOfWrongClock(input_api, output_api)
- results += FindUselessIfdefs(input_api, output_api)
- return results
+ import sys
+ original_sys_path = sys.path
+ sys.path = sys.path + [input_api.os_path.join(
+ input_api.change.RepositoryRoot(),
+ 'components', 'viz')]
+
+ import presubmit_checks as ps
+ white_list=(r'^components[\\/]viz[\\/].*\.(cc|h)$',)
+ return ps.RunAllChecks(input_api, output_api, white_list)
diff --git a/chromium/components/viz/README.md b/chromium/components/viz/README.md
new file mode 100644
index 00000000000..c73a9ba2227
--- /dev/null
+++ b/chromium/components/viz/README.md
@@ -0,0 +1,224 @@
+# //components/viz
+
+Viz - short for visuals - is the client library and service implementations for
+compositing and gpu presentation.
+
+See [//services/viz](../../services/viz/README.md) for more information about
+Viz overall.
+
+**Table of Contents**
+1. [Terminology](#terminology)
+2. [Directory structure](#directory-structure)
+ 1. [common](#directory-structure-common)
+ 2. [client](#directory-structure-client)
+ 3. [host](#directory-structure-host)
+ 4. [service](#directory-structure-service)
+3. [Naming guidelines with Mojo](#naming-guidelines)
+
+## Terminology
+
+**Mojo Interface**: The interface definition, found in a .mojom file. This is
+an abstract interface and can be thought of as a process/thread-independent C++
+abstract class.
+
+**Mojo Implementation**: The default implementation of a mojom interface for
+production. Many interfaces will only have a single implementation that we
+ship.
+
+**Alternate Mojo Implementations**: Secondary implementations of a mojom
+interface for platform-specific details, for tests, etc.
+
+**Service**: Where Mojo implementations live and run.
+
+**Host**: A privileged process that provides access to viz Mojo interfaces for
+Clients. Most services in Chrome don’t have these, and Clients find the service
+directly, but they are more common in Viz. Currently the Host is in the browser
+process. In a fully-realized mus+ash, the Host moves outside of Chrome to the
+window server.
+
+**Client**: All users of a Mojo interface who are not the Host. They will
+usually need to go through the Host to gain access to the Mojo interface.
+
+**Host-side Wrapper**: A C++ wrapper around a Mojo interface for use in Hosts,
+that often also exposes or uses some privileged interfaces that Clients don’t
+have. Generally prefer to use the Mojo interfaces directly, but sometimes we
+need another C++ helper around it.
+
+**Client-side Wrapper**: A C++ wrapper around a Mojo interface for use in
+Clients. Generally prefer to use the Mojo interface directly, but sometimes we
+need another C++ helper around it.
+
+**Host/Client-side Abstraction**: A C++ wrapper around a Mojo interface that is
+also a subclass of a C++ interface. Generally prefer to use the Mojo interfaces
+directly, but sometimes we need a higher-level C++ abstraction, usually because
+other subclasses cannot use the Mojo interface.
+
+
+## Directory Structure <a name="directory-structure"></a>
+To keep dependencies clear into the Viz source tree, all source code files
+should appear in leaf directories.
+
+### common <a name="directory-structure-common"></a>
+Data types and simple helpers that are used by the client library, or by
+clients directly, and by service implementations.
+
+### client <a name="directory-structure-client"></a>
+Client library for accessing Viz services. May be used from privileged (eg
+browser) or unprivileged (eg renderer) processes.
+
+| Can depend on: |
+|:---------------|
+| viz/common/ |
+
+### host <a name="directory-structure-host"></a>
+Privileged client library for owning and controlling Viz services. May only be
+used from privileged (eg browser) processes.
+
+This should not depend on other parts of Viz, as they are core data types and
+helpers only, and can be used from anywhere else in Viz.
+
+| Can depend on: |
+|:---------------|
+| viz/common/ |
+
+### service <a name="directory-structure-service"></a>
+Service-side implementations of Viz Mojo interfaces, which are found in
+[//services/viz](https://cs.chromium.org/chromium/src/services/viz/). Each
+component of the service-side implementation is located in its own
+sub-directory.
+
+As of this writing, these service components may be instantiated and used
+directly from the browser process. But these services are intended to be
+abstracted away through Mojo interfaces so that they are able to live entirely
+outside the browser process, and gain in-process access to the Gpu.
+
+#### service/display
+**Display compositor**: The display compositor uses Gpu or software to composite
+a set of frames, from multiple clients, into a single backing store for display
+to the user. Also deals in getting screenshots of content by drawing to
+offscreen buffers.
+
+The top-level scheduler that coordinates when the compositor should draw, along
+with when clients should be submitting frames.
+
+This component is platform-agnostic, with any platform-specific details
+abstracted away from it. It accesses Gpu services through the command buffer as
+a client even though it is in the same process as the Gpu service in order to
+be scheduled as a peer among other clients.
+
+| Can depend on: |
+|:----------------------|
+| viz/common/* |
+| viz/service/surfaces/ |
+
+#### service/display_embedder
+**Platform details for display compositor**: While the display compositor is
+platform-agnostic, this component provides implementations of platform-specific
+behaviour needed for the display compositor, and injected into it.
+
+Code here supports presentation of the backing store drawn by the display
+compositor (typically thought of as SwapBuffers), as well as the use of
+overlays.
+
+| Can depend on: |
+|:---------------|
+| viz/common/* |
+
+#### service/frame_sinks
+**Frame sinks**: This component implements the Mojo interfaces to send frames,
+resources, and other data types from ``viz/common/`` for display to the
+compositing service. It receives and organizes relationships between what should
+be composited.
+
+| Can depend on: |
+|:----------------------|
+| viz/common/* |
+| viz/service/display/ |
+| viz/service/surfaces/ |
+
+#### service/gl
+**GL**: This component implements the Mojo interfaces for allocating (and
+deallocating) gpu memory buffers, setting up a channel for the command buffer,
+etc.
+
+| Can depend on: |
+|:----------------------|
+| viz/common/* |
+
+#### service/hit_test
+**Hit testing**: Service-side code to resolve input events to individual
+clients.
+
+| Can depend on: |
+|:----------------------|
+| viz/common/* |
+| viz/service/surfaces/ |
+
+#### service/main
+**Main**: TODO(fsamuel): This will hold implementation of the root interface
+from which other service interfaces are accessed.
+
+As the root of the service/ code structure, it instantiates and connects all
+other parts of Viz.
+
+| Can depend on: |
+|:---------------|
+| viz/common/* |
+| viz/service/* |
+
+#### service/surfaces
+**Surfaces**: This component acts like the data model for the compositing service.
+It holds data received from frame sinks, and provides access to them for the
+display compositor.
+
+| Can depend on: |
+|:---------------|
+| viz/common/* |
+
+
+## Naming guidelines with Mojo <a name="naming-guidelines"></a>
+
+Viz makes extensive use of Mojo, and there are conflicting patterns with
+regard to naming types around Mojo interfaces in the codebase today. This aims
+to provide a standard to adhere to for future naming to increase our
+consistency within the team.
+
+For a given mojo service called `TimeTraveller`, we would use the following.
+
+**Mojo Interface**: `mojom::TimeTraveller`
+* This is the abstract interface definition. It comes with no prefix or suffix,
+and lives in a (sometimes nested) mojom namespace.
+
+**Mojo Implementation**: `TimeTravellerImpl`
+* This is the implementation of the interface. For other C++ interfaces we
+commonly use the Impl suffix, and we will repeat this here, as it’s already
+commonly used and is well understood.
+* If there will be multiple implementations, see below.
+
+**Alternative Mojo Implementation**: `DescriptivePrefixTimeTravellerImpl`
+* This is a non-default implementation of the interface. It follows the same
+rules as a default implementation, but is used for tests, or cases where we
+don’t have a simple default production implementation.
+* The descriptive prefix should describe what makes this implementation
+different from others, as such why it exists.
+
+**Host-side Wrapper**: `HostTimeTraveller`
+* This wraps the Mojo interface, providing a higher-level abstraction and
+utilities for using the Mojo interface. It only is meant to exist and be
+accessed in the privileged Host process. We prefix with Host to explain what
+makes this interface special and when it can be used. We do not suffix to be
+consistent with Clients.
+
+**Client-side Wrapper**: `ClientTimeTraveller`
+* This wraps the Mojo interface, providing a higher-level abstraction and
+utilities for using the Mojo interface. It may exist and be used in any Client
+in place of the Mojo interface. Prefer to use the Mojo interface directly when
+possible. We prefix with Client to explain in what situations it can be used.
+We do not suffix to avoid a TimeTravellerClientClient in the case where this
+class has itself a C++ client, as ClientTimeTravellerClient appeared to be a
+better option of the two.
+
+**Host/Client-side Abstraction**: `OtherAbstractionName`
+* This is a case of an object implementing a C++ interface, which it should be
+named after. A prefix describing what makes this implementation special can
+refer to its use of the Mojo interface.
diff --git a/chromium/components/viz/client/BUILD.gn b/chromium/components/viz/client/BUILD.gn
index 1c97eed5def..96eb83e8b72 100644
--- a/chromium/components/viz/client/BUILD.gn
+++ b/chromium/components/viz/client/BUILD.gn
@@ -10,6 +10,7 @@ viz_source_set("client") {
"client_layer_tree_frame_sink.h",
"client_shared_bitmap_manager.cc",
"client_shared_bitmap_manager.h",
+ "hit_test_data_provider.h",
"local_surface_id_provider.cc",
"local_surface_id_provider.h",
]
@@ -18,8 +19,8 @@ viz_source_set("client") {
"//base",
"//cc",
"//cc/ipc:interfaces",
- "//cc/surfaces",
"//components/viz/common",
"//mojo/public/cpp/bindings",
+ "//services/viz/public/interfaces",
]
}
diff --git a/chromium/components/viz/client/DEPS b/chromium/components/viz/client/DEPS
index 78b21a84333..5ef5a56fc11 100644
--- a/chromium/components/viz/client/DEPS
+++ b/chromium/components/viz/client/DEPS
@@ -2,9 +2,9 @@ include_rules = [
"+cc",
"-cc/blink",
"-cc/test",
-
+ "-components/viz/common/switches.h",
"+components/viz/client",
"+mojo/public/cpp/bindings",
"+mojo/public/cpp/system",
- "+ui/gfx/geometry",
+ "+services/viz/public/interfaces",
]
diff --git a/chromium/components/viz/client/client_layer_tree_frame_sink.cc b/chromium/components/viz/client/client_layer_tree_frame_sink.cc
index 4425d5f5758..524b86f520c 100644
--- a/chromium/components/viz/client/client_layer_tree_frame_sink.cc
+++ b/chromium/components/viz/client/client_layer_tree_frame_sink.cc
@@ -6,10 +6,12 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
-#include "cc/output/begin_frame_args.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/layer_tree_frame_sink_client.h"
+#include "components/viz/client/hit_test_data_provider.h"
#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
namespace viz {
@@ -19,15 +21,17 @@ ClientLayerTreeFrameSink::ClientLayerTreeFrameSink(
scoped_refptr<ContextProvider> worker_context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
SharedBitmapManager* shared_bitmap_manager,
- std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source,
- cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
- cc::mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source,
+ mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
+ mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<HitTestDataProvider> hit_test_data_provider,
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider,
bool enable_surface_synchronization)
: cc::LayerTreeFrameSink(std::move(context_provider),
std::move(worker_context_provider),
gpu_memory_buffer_manager,
shared_bitmap_manager),
+ hit_test_data_provider_(std::move(hit_test_data_provider)),
local_surface_id_provider_(std::move(local_surface_id_provider)),
synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)),
compositor_frame_sink_info_(std::move(compositor_frame_sink_info)),
@@ -39,13 +43,15 @@ ClientLayerTreeFrameSink::ClientLayerTreeFrameSink(
}
ClientLayerTreeFrameSink::ClientLayerTreeFrameSink(
- scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider,
- std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source,
- cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
- cc::mojom::CompositorFrameSinkClientRequest client_request,
+ scoped_refptr<VulkanContextProvider> vulkan_context_provider,
+ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source,
+ mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
+ mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<HitTestDataProvider> hit_test_data_provider,
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider,
bool enable_surface_synchronization)
: cc::LayerTreeFrameSink(std::move(vulkan_context_provider)),
+ hit_test_data_provider_(std::move(hit_test_data_provider)),
local_surface_id_provider_(std::move(local_surface_id_provider)),
synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)),
compositor_frame_sink_info_(std::move(compositor_frame_sink_info)),
@@ -78,7 +84,7 @@ bool ClientLayerTreeFrameSink::BindToClient(
if (synthetic_begin_frame_source_) {
client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
} else {
- begin_frame_source_ = base::MakeUnique<cc::ExternalBeginFrameSource>(this);
+ begin_frame_source_ = base::MakeUnique<ExternalBeginFrameSource>(this);
begin_frame_source_->OnSetBeginFrameSourcePaused(begin_frames_paused_);
client->SetBeginFrameSource(begin_frame_source_.get());
}
@@ -108,7 +114,7 @@ void ClientLayerTreeFrameSink::SubmitCompositorFrame(
cc::CompositorFrame frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(frame.metadata.begin_frame_ack.has_damage);
- DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber,
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber,
frame.metadata.begin_frame_ack.sequence_number);
if (!enable_surface_synchronization_) {
@@ -116,26 +122,38 @@ void ClientLayerTreeFrameSink::SubmitCompositorFrame(
local_surface_id_provider_->GetLocalSurfaceIdForFrame(frame);
}
- compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_,
- std::move(frame));
+ TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
+ "SubmitCompositorFrame",
+ local_surface_id_.local_id());
+ bool tracing_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
+ &tracing_enabled);
+
+ mojom::HitTestRegionListPtr hit_test_region_list;
+ if (hit_test_data_provider_)
+ hit_test_region_list = hit_test_data_provider_->GetHitTestData();
+
+ compositor_frame_sink_->SubmitCompositorFrame(
+ local_surface_id_, std::move(frame), std::move(hit_test_region_list),
+ tracing_enabled ? base::TimeTicks::Now().since_origin().InMicroseconds()
+ : 0);
}
-void ClientLayerTreeFrameSink::DidNotProduceFrame(
- const cc::BeginFrameAck& ack) {
+void ClientLayerTreeFrameSink::DidNotProduceFrame(const BeginFrameAck& ack) {
DCHECK(!ack.has_damage);
- DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
compositor_frame_sink_->DidNotProduceFrame(ack);
}
void ClientLayerTreeFrameSink::DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
client_->ReclaimResources(resources);
client_->DidReceiveCompositorFrameAck();
}
void ClientLayerTreeFrameSink::OnBeginFrame(
- const cc::BeginFrameArgs& begin_frame_args) {
+ const BeginFrameArgs& begin_frame_args) {
if (begin_frame_source_)
begin_frame_source_->OnBeginFrame(begin_frame_args);
}
@@ -147,7 +165,7 @@ void ClientLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
}
void ClientLayerTreeFrameSink::ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
client_->ReclaimResources(resources);
}
diff --git a/chromium/components/viz/client/client_layer_tree_frame_sink.h b/chromium/components/viz/client/client_layer_tree_frame_sink.h
index b2893ccf828..22edb9e0353 100644
--- a/chromium/components/viz/client/client_layer_tree_frame_sink.h
+++ b/chromium/components/viz/client/client_layer_tree_frame_sink.h
@@ -7,65 +7,69 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "cc/ipc/compositor_frame_sink.mojom.h"
#include "cc/output/layer_tree_frame_sink.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
namespace viz {
+class HitTestDataProvider;
class LocalSurfaceIdProvider;
class SharedBitmapManager;
class ClientLayerTreeFrameSink : public cc::LayerTreeFrameSink,
- public cc::mojom::CompositorFrameSinkClient,
- public cc::ExternalBeginFrameSourceClient {
+ public mojom::CompositorFrameSinkClient,
+ public ExternalBeginFrameSourceClient {
public:
ClientLayerTreeFrameSink(
scoped_refptr<ContextProvider> context_provider,
scoped_refptr<ContextProvider> worker_context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
SharedBitmapManager* shared_bitmap_manager,
- std::unique_ptr<cc::SyntheticBeginFrameSource>
- synthetic_begin_frame_source,
- cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
- cc::mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source,
+ mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
+ mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<HitTestDataProvider> hit_test_data_provider,
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider,
bool enable_surface_synchronization);
ClientLayerTreeFrameSink(
- scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider,
- std::unique_ptr<cc::SyntheticBeginFrameSource>
- synthetic_begin_frame_source,
- cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
- cc::mojom::CompositorFrameSinkClientRequest client_request,
+ scoped_refptr<VulkanContextProvider> vulkan_context_provider,
+ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source,
+ mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
+ mojom::CompositorFrameSinkClientRequest client_request,
+ std::unique_ptr<HitTestDataProvider> hit_test_data_provider,
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider,
bool enable_surface_synchronization);
~ClientLayerTreeFrameSink() override;
base::WeakPtr<ClientLayerTreeFrameSink> GetWeakPtr();
+ const HitTestDataProvider* hit_test_data_provider() const {
+ return hit_test_data_provider_.get();
+ }
// cc::LayerTreeFrameSink implementation.
bool BindToClient(cc::LayerTreeFrameSinkClient* client) override;
void DetachFromClient() override;
void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id) override;
void SubmitCompositorFrame(cc::CompositorFrame frame) override;
- void DidNotProduceFrame(const cc::BeginFrameAck& ack) override;
+ void DidNotProduceFrame(const BeginFrameAck& ack) override;
private:
- // cc::mojom::CompositorFrameSinkClient implementation:
+ // mojom::CompositorFrameSinkClient implementation:
void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override;
- void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override;
+ const std::vector<ReturnedResource>& resources) override;
+ void OnBeginFrame(const BeginFrameArgs& begin_frame_args) override;
void OnBeginFramePausedChanged(bool paused) override;
void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override;
+ const std::vector<ReturnedResource>& resources) override;
- // cc::ExternalBeginFrameSourceClient implementation.
+ // ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;
static void OnMojoConnectionError(uint32_t custom_reason,
@@ -73,13 +77,14 @@ class ClientLayerTreeFrameSink : public cc::LayerTreeFrameSink,
bool begin_frames_paused_ = false;
LocalSurfaceId local_surface_id_;
+ std::unique_ptr<HitTestDataProvider> hit_test_data_provider_;
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider_;
- std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_;
- std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
- cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info_;
- cc::mojom::CompositorFrameSinkClientRequest client_request_;
- cc::mojom::CompositorFrameSinkPtr compositor_frame_sink_;
- mojo::Binding<cc::mojom::CompositorFrameSinkClient> client_binding_;
+ std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+ mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info_;
+ mojom::CompositorFrameSinkClientRequest client_request_;
+ mojom::CompositorFrameSinkPtr compositor_frame_sink_;
+ mojo::Binding<mojom::CompositorFrameSinkClient> client_binding_;
THREAD_CHECKER(thread_checker_);
const bool enable_surface_synchronization_;
diff --git a/chromium/components/viz/client/client_shared_bitmap_manager.cc b/chromium/components/viz/client/client_shared_bitmap_manager.cc
index 8c1d51a6819..63b30e74bbe 100644
--- a/chromium/components/viz/client/client_shared_bitmap_manager.cc
+++ b/chromium/components/viz/client/client_shared_bitmap_manager.cc
@@ -24,7 +24,7 @@ namespace {
class ClientSharedBitmap : public SharedBitmap {
public:
ClientSharedBitmap(
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier,
base::SharedMemory* shared_memory,
const SharedBitmapId& id,
@@ -36,7 +36,7 @@ class ClientSharedBitmap : public SharedBitmap {
std::move(shared_bitmap_allocation_notifier)) {}
ClientSharedBitmap(
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier,
std::unique_ptr<base::SharedMemory> shared_memory_holder,
const SharedBitmapId& id,
@@ -60,7 +60,7 @@ class ClientSharedBitmap : public SharedBitmap {
}
private:
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier_;
std::unique_ptr<base::SharedMemory> shared_memory_holder_;
};
@@ -112,7 +112,7 @@ std::unique_ptr<base::SharedMemory> AllocateSharedMemory(size_t buf_size) {
} // namespace
ClientSharedBitmapManager::ClientSharedBitmapManager(
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier)
: shared_bitmap_allocation_notifier_(
std::move(shared_bitmap_allocation_notifier)) {}
diff --git a/chromium/components/viz/client/client_shared_bitmap_manager.h b/chromium/components/viz/client/client_shared_bitmap_manager.h
index 8bb479cbed1..553bb5702ea 100644
--- a/chromium/components/viz/client/client_shared_bitmap_manager.h
+++ b/chromium/components/viz/client/client_shared_bitmap_manager.h
@@ -13,9 +13,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/synchronization/lock.h"
-#include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
+#include "services/viz/public/interfaces/compositing/shared_bitmap_allocation_notifier.mojom.h"
namespace viz {
@@ -25,7 +25,7 @@ namespace viz {
class ClientSharedBitmapManager : public SharedBitmapManager {
public:
explicit ClientSharedBitmapManager(
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier);
~ClientSharedBitmapManager() override;
@@ -43,7 +43,7 @@ class ClientSharedBitmapManager : public SharedBitmapManager {
uint32_t NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
const SharedBitmapId& id);
- scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
+ scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
shared_bitmap_allocation_notifier_;
base::Lock lock_;
diff --git a/chromium/components/viz/client/hit_test_data_provider.h b/chromium/components/viz/client/hit_test_data_provider.h
new file mode 100644
index 00000000000..73012424ebb
--- /dev/null
+++ b/chromium/components/viz/client/hit_test_data_provider.h
@@ -0,0 +1,31 @@
+// 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_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_H_
+#define COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
+
+namespace viz {
+
+class HitTestDataProvider {
+ public:
+ HitTestDataProvider() = default;
+ virtual ~HitTestDataProvider() = default;
+
+ // Returns an array of hit-test regions. May return nullptr to disable
+ // hit-testing.
+ virtual mojom::HitTestRegionListPtr GetHitTestData() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HitTestDataProvider);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_H_
diff --git a/chromium/components/viz/client/local_surface_id_provider.cc b/chromium/components/viz/client/local_surface_id_provider.cc
index 90773f302ff..e556b194f6f 100644
--- a/chromium/components/viz/client/local_surface_id_provider.cc
+++ b/chromium/components/viz/client/local_surface_id_provider.cc
@@ -15,13 +15,13 @@ DefaultLocalSurfaceIdProvider::DefaultLocalSurfaceIdProvider() = default;
const LocalSurfaceId& DefaultLocalSurfaceIdProvider::GetLocalSurfaceIdForFrame(
const cc::CompositorFrame& frame) {
- gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
- if (!local_surface_id_.is_valid() || surface_size_ != frame_size ||
- frame.metadata.device_scale_factor != device_scale_factor_) {
+ if (!local_surface_id_.is_valid() ||
+ surface_size_ != frame.size_in_pixels() ||
+ frame.device_scale_factor() != device_scale_factor_) {
local_surface_id_ = local_surface_id_allocator_.GenerateId();
}
- surface_size_ = frame_size;
- device_scale_factor_ = frame.metadata.device_scale_factor;
+ surface_size_ = frame.size_in_pixels();
+ device_scale_factor_ = frame.device_scale_factor();
return local_surface_id_;
}
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index 84f40f15662..95ac2e7fdaf 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -5,6 +5,27 @@
import("//components/viz/viz.gni")
import("//testing/test.gni")
+viz_component("resource_format") {
+ output_name = "viz_resource_format"
+
+ defines = [ "VIZ_RESOURCE_FORMAT_IMPLEMENTATION" ]
+
+ sources = [
+ "resources/resource_format.h",
+ "resources/resource_format_utils.cc",
+ "resources/resource_format_utils.h",
+ "viz_resource_format_export.h",
+ ]
+
+ configs = [ "//third_party/khronos:khronos_headers" ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/gfx:buffer_types",
+ ]
+}
+
viz_component("common") {
output_name = "viz_common"
@@ -13,6 +34,12 @@ viz_component("common") {
sources = [
"display/renderer_settings.cc",
"display/renderer_settings.h",
+ "frame_sinks/begin_frame_args.cc",
+ "frame_sinks/begin_frame_args.h",
+ "frame_sinks/begin_frame_source.cc",
+ "frame_sinks/begin_frame_source.h",
+ "frame_sinks/delay_based_time_source.cc",
+ "frame_sinks/delay_based_time_source.h",
"gl_helper.cc",
"gl_helper.h",
"gl_helper_readback_support.cc",
@@ -25,20 +52,33 @@ viz_component("common") {
"gpu/context_provider.h",
"gpu/in_process_context_provider.cc",
"gpu/in_process_context_provider.h",
+ "gpu/vulkan_context_provider.h",
+ "gpu/vulkan_in_process_context_provider.cc",
+ "gpu/vulkan_in_process_context_provider.h",
"hit_test/aggregated_hit_test_region.h",
- "quads/resource_format.h",
+ "quads/copy_output_request.cc",
+ "quads/copy_output_request.h",
+ "quads/copy_output_result.cc",
+ "quads/copy_output_result.h",
+ "quads/release_callback.h",
"quads/shared_bitmap.cc",
"quads/shared_bitmap.h",
+ "quads/shared_quad_state.cc",
+ "quads/shared_quad_state.h",
+ "quads/single_release_callback.cc",
+ "quads/single_release_callback.h",
"quads/texture_mailbox.cc",
"quads/texture_mailbox.h",
"resources/buffer_to_texture_target_map.cc",
"resources/buffer_to_texture_target_map.h",
"resources/platform_color.h",
- "resources/resource_format_utils.cc",
- "resources/resource_format_utils.h",
+ "resources/resource_id.h",
"resources/resource_settings.cc",
"resources/resource_settings.h",
+ "resources/returned_resource.h",
"resources/shared_bitmap_manager.h",
+ "resources/transferable_resource.cc",
+ "resources/transferable_resource.h",
"surfaces/frame_sink_id.cc",
"surfaces/frame_sink_id.h",
"surfaces/frame_sink_id_allocator.h",
@@ -48,6 +88,8 @@ viz_component("common") {
"surfaces/local_surface_id_allocator.h",
"surfaces/sequence_surface_reference_factory.cc",
"surfaces/sequence_surface_reference_factory.h",
+ "surfaces/stub_surface_reference_factory.cc",
+ "surfaces/stub_surface_reference_factory.h",
"surfaces/surface_id.cc",
"surfaces/surface_id.h",
"surfaces/surface_info.h",
@@ -56,10 +98,18 @@ viz_component("common") {
"surfaces/surface_sequence.h",
"surfaces/surface_sequence_generator.cc",
"surfaces/surface_sequence_generator.h",
+ "switches.cc",
+ "switches.h",
+ "traced_value.cc",
+ "traced_value.h",
"viz_common_export.h",
]
deps = [
+ # TODO(staraz): cc/base was added because SharedQuadState includes
+ # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
+ "//cc/base",
+
"//base",
"//gpu",
"//gpu/command_buffer/client:gles2_implementation",
@@ -67,6 +117,7 @@ viz_component("common") {
"//gpu/command_buffer/service",
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings:skia_bindings",
+ "//gpu/vulkan:features",
"//mojo/public/cpp/bindings",
"//skia",
"//ui/gfx:color_space",
@@ -75,6 +126,7 @@ viz_component("common") {
]
public_deps = [
+ ":resource_format",
"//gpu/command_buffer/client",
"//gpu/command_buffer/common",
"//mojo/public/cpp/bindings",
@@ -84,6 +136,8 @@ viz_component("common") {
viz_source_set("unit_tests") {
testonly = true
sources = [
+ "frame_sinks/begin_frame_args_unittest.cc",
+ "frame_sinks/delay_based_time_source_unittest.cc",
"gl_helper_unittest.cc",
"resources/buffer_to_texture_target_map_unittest.cc",
"resources/platform_color_unittest.cc",
@@ -94,6 +148,7 @@ viz_source_set("unit_tests") {
deps = [
":common",
"//base/test:test_support",
+ "//components/viz/test:test_support",
"//gpu/command_buffer/client:gles2_implementation",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/ipc:gl_in_process_context",
diff --git a/chromium/components/viz/common/DEPS b/chromium/components/viz/common/DEPS
index 4efdc7698ad..7732773b1b8 100644
--- a/chromium/components/viz/common/DEPS
+++ b/chromium/components/viz/common/DEPS
@@ -7,18 +7,16 @@ specific_include_rules = {
"+gpu/command_buffer/service",
"+gpu/ipc/common",
"+mojo/public/cpp/bindings",
- "+ui/gfx/geometry",
"+services/ui/gpu/interfaces",
"+third_party/skia",
],
".*_unittest\.cc": [
+ "+components/viz/test",
"+gpu/ipc/gl_in_process_context.h",
"+media/base",
- "+ui/gfx",
"+ui/gl",
],
".*_benchmark\.cc": [
"+gpu/ipc/gl_in_process_context.h",
- "+ui/gfx",
],
}
diff --git a/chromium/components/viz/common/README.md b/chromium/components/viz/common/README.md
deleted file mode 100644
index d2e8fd6f3d9..00000000000
--- a/chromium/components/viz/common/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory contains common code used by implementations of client/, host/,
-and/or service/. It also contains common code used by the users of these
-components (i.e. code outside of //components/viz that use code in client/,
-host/, and/or service/ can also use this code).
diff --git a/chromium/components/viz/common/display/renderer_settings.h b/chromium/components/viz/common/display/renderer_settings.h
index c7fb57c2540..28b529d304e 100644
--- a/chromium/components/viz/common/display/renderer_settings.h
+++ b/chromium/components/viz/common/display/renderer_settings.h
@@ -29,12 +29,15 @@ class VIZ_COMMON_EXPORT RendererSettings {
bool gl_composited_overlay_candidate_quad_border = false;
bool show_overdraw_feedback = false;
bool enable_color_correct_rendering = false;
+ bool use_skia_renderer = false;
int highp_threshold_min = 0;
// Determines whether we disallow non-exact matches when finding resources
// in ResourcePool. Only used for layout or pixel tests, as non-deterministic
// resource sizes can lead to floating point error and noise in these tests.
bool disallow_non_exact_resource_reuse = false;
+
+ int slow_down_compositing_scale_factor = 1;
};
} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args.cc b/chromium/components/viz/common/frame_sinks/begin_frame_args.cc
new file mode 100644
index 00000000000..a955809fdb1
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args.cc
@@ -0,0 +1,130 @@
+// 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/viz/common/frame_sinks/begin_frame_args.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace viz {
+
+const char* BeginFrameArgs::TypeToString(BeginFrameArgsType type) {
+ switch (type) {
+ case BeginFrameArgs::INVALID:
+ return "INVALID";
+ case BeginFrameArgs::NORMAL:
+ return "NORMAL";
+ case BeginFrameArgs::MISSED:
+ return "MISSED";
+ case BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX:
+ return "BEGIN_FRAME_ARGS_TYPE_MAX";
+ }
+ NOTREACHED();
+ return "???";
+}
+
+constexpr uint64_t BeginFrameArgs::kInvalidFrameNumber;
+constexpr uint64_t BeginFrameArgs::kStartingFrameNumber;
+
+BeginFrameArgs::BeginFrameArgs()
+ : frame_time(base::TimeTicks()),
+ deadline(base::TimeTicks()),
+ interval(base::TimeDelta::FromMicroseconds(-1)),
+ sequence_number(kInvalidFrameNumber),
+ source_id(0),
+ type(BeginFrameArgs::INVALID),
+ on_critical_path(true) {}
+
+BeginFrameArgs::BeginFrameArgs(uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgs::BeginFrameArgsType type)
+ : frame_time(frame_time),
+ deadline(deadline),
+ interval(interval),
+ sequence_number(sequence_number),
+ source_id(source_id),
+ type(type),
+ on_critical_path(true) {
+ DCHECK_LE(kStartingFrameNumber, sequence_number);
+}
+
+BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
+ uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgs::BeginFrameArgsType type) {
+ DCHECK_NE(type, BeginFrameArgs::INVALID);
+ DCHECK_NE(type, BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX);
+#ifdef NDEBUG
+ return BeginFrameArgs(source_id, sequence_number, frame_time, deadline,
+ interval, type);
+#else
+ BeginFrameArgs args = BeginFrameArgs(source_id, sequence_number, frame_time,
+ deadline, interval, type);
+ args.created_from = location;
+ return args;
+#endif
+}
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+BeginFrameArgs::AsValue() const {
+ std::unique_ptr<base::trace_event::TracedValue> state(
+ new base::trace_event::TracedValue());
+ AsValueInto(state.get());
+ return std::move(state);
+}
+
+void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetString("type", "BeginFrameArgs");
+ state->SetString("subtype", TypeToString(type));
+ state->SetInteger("source_id", source_id);
+ state->SetInteger("sequence_number", sequence_number);
+ state->SetDouble("frame_time_us", frame_time.since_origin().InMicroseconds());
+ state->SetDouble("deadline_us", deadline.since_origin().InMicroseconds());
+ state->SetDouble("interval_us", interval.InMicroseconds());
+#ifndef NDEBUG
+ state->SetString("created_from", created_from.ToString());
+#endif
+ state->SetBoolean("on_critical_path", on_critical_path);
+}
+
+// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
+// cases where a good estimated draw time is not known. Using 1/3 of the vsync
+// as the default adjustment gives the Browser the last 1/3 of a frame to
+// produce output, the Renderer Impl thread the middle 1/3 of a frame to produce
+// ouput, and the Renderer Main thread the first 1/3 of a frame to produce
+// output.
+base::TimeDelta BeginFrameArgs::DefaultEstimatedParentDrawTime() {
+ return base::TimeDelta::FromMicroseconds(16666 / 3);
+}
+
+base::TimeDelta BeginFrameArgs::DefaultInterval() {
+ return base::TimeDelta::FromMicroseconds(16666);
+}
+
+BeginFrameAck::BeginFrameAck()
+ : sequence_number(BeginFrameArgs::kInvalidFrameNumber),
+ source_id(0),
+ has_damage(false) {}
+
+BeginFrameAck::BeginFrameAck(uint32_t source_id,
+ uint64_t sequence_number,
+ bool has_damage)
+ : sequence_number(sequence_number),
+ source_id(source_id),
+ has_damage(has_damage) {
+ DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, sequence_number);
+}
+
+// static
+BeginFrameAck BeginFrameAck::CreateManualAckWithDamage() {
+ return BeginFrameAck(BeginFrameArgs::kManualSourceId,
+ BeginFrameArgs::kStartingFrameNumber, true);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args.h b/chromium/components/viz/common/frame_sinks/begin_frame_args.h
new file mode 100644
index 00000000000..72175015936
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args.h
@@ -0,0 +1,145 @@
+// 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_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
+
+#include <stdint.h>
+#include <memory>
+
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class ConvertableToTraceFormat;
+class TracedValue;
+} // namespace trace_event
+} // namespace base
+
+/**
+ * In debug builds we trace the creation origin of BeginFrameArgs objects. We
+ * reuse the tracked_objects::Location system to do that.
+ *
+ * However, in release builds we don't want this as it doubles the size of the
+ * BeginFrameArgs object. As well it adds a number of largish strings to the
+ * binary. Despite the argument being unused, most compilers are unable to
+ * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE
+ * macro to prevent the data even getting referenced.
+ */
+#ifdef NDEBUG
+#define BEGINFRAME_FROM_HERE nullptr
+#else
+#define BEGINFRAME_FROM_HERE FROM_HERE
+#endif
+
+namespace viz {
+
+struct VIZ_COMMON_EXPORT BeginFrameArgs {
+ enum BeginFrameArgsType {
+ INVALID,
+ NORMAL,
+ MISSED,
+ // Not a real type, but used by the IPC system. Should always remain the
+ // *last* value in this enum.
+ BEGIN_FRAME_ARGS_TYPE_MAX,
+ };
+ static const char* TypeToString(BeginFrameArgsType type);
+
+ static constexpr uint32_t kStartingSourceId = 0;
+ // |source_id| for BeginFrameArgs not created by a BeginFrameSource. Used to
+ // avoid sequence number conflicts of BeginFrameArgs manually fed to an
+ // observer with those fed to the observer by the its BeginFrameSource.
+ static constexpr uint32_t kManualSourceId = UINT32_MAX;
+
+ static constexpr uint64_t kInvalidFrameNumber = 0;
+ static constexpr uint64_t kStartingFrameNumber = 1;
+
+ // Creates an invalid set of values.
+ BeginFrameArgs();
+
+#ifdef NDEBUG
+ typedef const void* CreationLocation;
+#else
+ typedef const tracked_objects::Location& CreationLocation;
+ tracked_objects::Location created_from;
+#endif
+
+ // You should be able to find all instances where a BeginFrame has been
+ // created by searching for "BeginFrameArgs::Create".
+ // The location argument should **always** be BEGINFRAME_FROM_HERE macro.
+ static BeginFrameArgs Create(CreationLocation location,
+ uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgsType type);
+
+ // This is the default delta that will be used to adjust the deadline when
+ // proper draw-time estimations are not yet available.
+ static base::TimeDelta DefaultEstimatedParentDrawTime();
+
+ // This is the default interval to use to avoid sprinkling the code with
+ // magic numbers.
+ static base::TimeDelta DefaultInterval();
+
+ bool IsValid() const { return interval >= base::TimeDelta(); }
+
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ base::TimeTicks frame_time;
+ base::TimeTicks deadline;
+ base::TimeDelta interval;
+
+ // |source_id| and |sequence_number| identify a BeginFrame within a single
+ // process and are set by the original BeginFrameSource that created the
+ // BeginFrameArgs. When |source_id| of consecutive BeginFrameArgs changes,
+ // observers should expect the continuity of |sequence_number| to break.
+ uint64_t sequence_number;
+ uint32_t source_id; // |source_id| after |sequence_number| for packing.
+
+ BeginFrameArgsType type;
+ bool on_critical_path;
+
+ private:
+ BeginFrameArgs(uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgsType type);
+};
+
+// Sent by a BeginFrameObserver as acknowledgment of completing a BeginFrame.
+struct VIZ_COMMON_EXPORT BeginFrameAck {
+ BeginFrameAck();
+ BeginFrameAck(uint32_t source_id, uint64_t sequence_number, bool has_damage);
+
+ // Creates a BeginFrameAck for a manual BeginFrame. Used when clients produce
+ // a CompositorFrame without prior BeginFrame, e.g. for synchronous drawing.
+ static BeginFrameAck CreateManualAckWithDamage();
+
+ // Sequence number of the BeginFrame that is acknowledged.
+ uint64_t sequence_number;
+
+ // Source identifier of the BeginFrame that is acknowledged. The
+ // BeginFrameSource that receives the acknowledgment uses this to discard
+ // BeginFrameAcks for BeginFrames sent by a different source. Such a situation
+ // may occur when the BeginFrameSource of the observer changes while a
+ // BeginFrame from the old source is still in flight.
+ uint32_t source_id; // |source_id| after above fields for packing.
+
+ // |true| if the observer has produced damage (e.g. sent a CompositorFrame or
+ // damaged a surface) as part of responding to the BeginFrame.
+ bool has_damage;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc b/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc
new file mode 100644
index 00000000000..50f898bb15a
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc
@@ -0,0 +1,125 @@
+// 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 <string>
+
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+constexpr base::TimeDelta k1Usec = base::TimeDelta::FromMicroseconds(1);
+constexpr base::TimeDelta k2Usec = base::TimeDelta::FromMicroseconds(2);
+constexpr base::TimeDelta k3Usec = base::TimeDelta::FromMicroseconds(3);
+
+TEST(BeginFrameArgsTest, Helpers) {
+ // Quick create methods work
+ BeginFrameArgs args0 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ EXPECT_TRUE(args0.IsValid()) << args0;
+
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1, 0, 0, -1);
+ EXPECT_FALSE(args1.IsValid()) << args1;
+
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 10, 1, 2, 3);
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(123u, args2.source_id);
+ EXPECT_EQ(10u, args2.sequence_number);
+ EXPECT_EQ(k1Usec, args2.frame_time.since_origin());
+ EXPECT_EQ(k2Usec, args2.deadline.since_origin());
+ EXPECT_EQ(k3Usec, args2.interval);
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type);
+
+ BeginFrameArgs args4 = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 234, 20, 1, 2, 3, BeginFrameArgs::MISSED);
+ EXPECT_TRUE(args4.IsValid()) << args4;
+ EXPECT_EQ(234u, args4.source_id);
+ EXPECT_EQ(20u, args4.sequence_number);
+ EXPECT_EQ(k1Usec, args4.frame_time.since_origin());
+ EXPECT_EQ(k2Usec, args4.deadline.since_origin());
+ EXPECT_EQ(k3Usec, args4.interval);
+ EXPECT_EQ(BeginFrameArgs::MISSED, args4.type);
+
+ // operator==
+ EXPECT_EQ(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 20, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 20, 4, 5, 6));
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9, BeginFrameArgs::MISSED),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 4,
+ 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 40, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 234, 30, 7,
+ 8, 9)),
+ "");
+
+ // operator<<
+ std::stringstream out1;
+ out1 << args1;
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 0, 1, 0, 0, -1us)", out1.str());
+ std::stringstream out2;
+ out2 << args2;
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 123, 10, 1, 2, 3us)", out2.str());
+
+ // PrintTo
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 0, 1, 0, 0, -1us)"),
+ ::testing::PrintToString(args1));
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 123, 10, 1, 2, 3us)"),
+ ::testing::PrintToString(args2));
+}
+
+TEST(BeginFrameArgsTest, Create) {
+ // BeginFrames are not valid by default
+ BeginFrameArgs args1;
+ EXPECT_FALSE(args1.IsValid()) << args1;
+ EXPECT_TRUE(args1.on_critical_path);
+
+ BeginFrameArgs args2 = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, 123, 10, base::TimeTicks() + k1Usec,
+ base::TimeTicks() + k2Usec, k3Usec, BeginFrameArgs::NORMAL);
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(123u, args2.source_id) << args2;
+ EXPECT_EQ(10u, args2.sequence_number) << args2;
+ EXPECT_EQ(k1Usec, args2.frame_time.since_origin()) << args2;
+ EXPECT_EQ(k2Usec, args2.deadline.since_origin()) << args2;
+ EXPECT_EQ(k3Usec, args2.interval) << args2;
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2;
+}
+
+#ifndef NDEBUG
+TEST(BeginFrameArgsTest, Location) {
+ tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location, 0, 1);
+ EXPECT_EQ(expected_location.ToString(), args.created_from.ToString());
+}
+#endif
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.cc b/chromium/components/viz/common/frame_sinks/begin_frame_source.cc
new file mode 100644
index 00000000000..7b3729259de
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -0,0 +1,354 @@
+// 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/viz/common/frame_sinks/begin_frame_source.h"
+
+#include <stddef.h>
+
+#include "base/atomic_sequence_num.h"
+#include "base/auto_reset.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+namespace viz {
+
+namespace {
+// kDoubleTickDivisor prevents the SyntheticBFS from sending BeginFrames too
+// often to an observer.
+static const double kDoubleTickDivisor = 2.0;
+} // namespace
+
+// BeginFrameObserverBase -------------------------------------------------
+BeginFrameObserverBase::BeginFrameObserverBase() = default;
+
+BeginFrameObserverBase::~BeginFrameObserverBase() = default;
+
+const BeginFrameArgs& BeginFrameObserverBase::LastUsedBeginFrameArgs() const {
+ return last_begin_frame_args_;
+}
+
+void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
+ DCHECK(args.IsValid());
+ DCHECK(args.frame_time >= last_begin_frame_args_.frame_time);
+ DCHECK(args.sequence_number > last_begin_frame_args_.sequence_number ||
+ args.source_id != last_begin_frame_args_.source_id)
+ << "current " << args.AsValue()->ToString() << ", last "
+ << last_begin_frame_args_.AsValue()->ToString();
+ bool used = OnBeginFrameDerivedImpl(args);
+ if (used) {
+ last_begin_frame_args_ = args;
+ } else {
+ ++dropped_begin_frame_args_;
+ }
+}
+
+void BeginFrameObserverBase::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("dropped_begin_frame_args", dropped_begin_frame_args_);
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
+// BeginFrameSource -------------------------------------------------------
+namespace {
+static base::AtomicSequenceNumber g_next_source_id;
+} // namespace
+
+BeginFrameSource::BeginFrameSource() : source_id_(g_next_source_id.GetNext()) {}
+
+BeginFrameSource::~BeginFrameSource() = default;
+
+void BeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("source_id", source_id_);
+}
+
+// StubBeginFrameSource ---------------------------------------------------
+bool StubBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+// SyntheticBeginFrameSource ----------------------------------------------
+SyntheticBeginFrameSource::~SyntheticBeginFrameSource() = default;
+
+// BackToBackBeginFrameSource ---------------------------------------------
+BackToBackBeginFrameSource::BackToBackBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source)
+ : time_source_(std::move(time_source)),
+ next_sequence_number_(BeginFrameArgs::kStartingFrameNumber),
+ weak_factory_(this) {
+ time_source_->SetClient(this);
+ // The time_source_ ticks immediately, so we SetActive(true) for a single
+ // tick when we need it, and keep it as SetActive(false) otherwise.
+ time_source_->SetTimebaseAndInterval(base::TimeTicks(), base::TimeDelta());
+}
+
+BackToBackBeginFrameSource::~BackToBackBeginFrameSource() = default;
+
+void BackToBackBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+ observers_.insert(obs);
+ pending_begin_frame_observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(false);
+ time_source_->SetActive(true);
+}
+
+void BackToBackBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+ observers_.erase(obs);
+ pending_begin_frame_observers_.erase(obs);
+ if (pending_begin_frame_observers_.empty())
+ time_source_->SetActive(false);
+}
+
+void BackToBackBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs) {
+ if (observers_.find(obs) != observers_.end()) {
+ pending_begin_frame_observers_.insert(obs);
+ time_source_->SetActive(true);
+ }
+}
+
+bool BackToBackBeginFrameSource::IsThrottled() const {
+ return false;
+}
+
+void BackToBackBeginFrameSource::OnTimerTick() {
+ base::TimeTicks frame_time = time_source_->LastTickTime();
+ base::TimeDelta default_interval = BeginFrameArgs::DefaultInterval();
+ BeginFrameArgs args = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_, frame_time,
+ frame_time + default_interval, default_interval, BeginFrameArgs::NORMAL);
+ next_sequence_number_++;
+
+ // This must happen after getting the LastTickTime() from the time source.
+ time_source_->SetActive(false);
+
+ std::unordered_set<BeginFrameObserver*> pending_observers;
+ pending_observers.swap(pending_begin_frame_observers_);
+ DCHECK(!pending_observers.empty());
+ for (BeginFrameObserver* obs : pending_observers)
+ obs->OnBeginFrame(args);
+}
+
+// DelayBasedBeginFrameSource ---------------------------------------------
+DelayBasedBeginFrameSource::DelayBasedBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source)
+ : time_source_(std::move(time_source)),
+ next_sequence_number_(BeginFrameArgs::kStartingFrameNumber) {
+ time_source_->SetClient(this);
+}
+
+DelayBasedBeginFrameSource::~DelayBasedBeginFrameSource() = default;
+
+void DelayBasedBeginFrameSource::OnUpdateVSyncParameters(
+ base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (!authoritative_interval_.is_zero()) {
+ interval = authoritative_interval_;
+ } else if (interval.is_zero()) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
+ interval = BeginFrameArgs::DefaultInterval();
+ }
+
+ last_timebase_ = timebase;
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+}
+
+void DelayBasedBeginFrameSource::SetAuthoritativeVSyncInterval(
+ base::TimeDelta interval) {
+ authoritative_interval_ = interval;
+ OnUpdateVSyncParameters(last_timebase_, interval);
+}
+
+BeginFrameArgs DelayBasedBeginFrameSource::CreateBeginFrameArgs(
+ base::TimeTicks frame_time) {
+ uint64_t sequence_number = next_sequence_number_++;
+ return BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, source_id(), sequence_number, frame_time,
+ time_source_->NextTickTime(), time_source_->Interval(),
+ BeginFrameArgs::NORMAL);
+}
+
+void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+
+ observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(false);
+ time_source_->SetActive(true);
+
+ // Missed args should correspond to |last_begin_frame_args_| (particularly,
+ // have the same sequence number) if |last_begin_frame_args_| still correspond
+ // to the last time the time source should have ticked. This may not be the
+ // case if the time source was inactive before AddObserver() was called. In
+ // such a case, we create new args with a new sequence number only if
+ // sufficient time has passed since the last tick.
+ base::TimeTicks last_or_missed_tick_time =
+ time_source_->NextTickTime() - time_source_->Interval();
+ if (!last_begin_frame_args_.IsValid() ||
+ last_or_missed_tick_time >
+ last_begin_frame_args_.frame_time +
+ last_begin_frame_args_.interval / kDoubleTickDivisor) {
+ last_begin_frame_args_ = CreateBeginFrameArgs(last_or_missed_tick_time);
+ }
+ BeginFrameArgs missed_args = last_begin_frame_args_;
+ missed_args.type = BeginFrameArgs::MISSED;
+
+ BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() ||
+ (missed_args.frame_time >
+ last_args.frame_time + missed_args.interval / kDoubleTickDivisor)) {
+ DCHECK(missed_args.sequence_number > last_args.sequence_number ||
+ missed_args.source_id != last_args.source_id)
+ << "missed " << missed_args.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ obs->OnBeginFrame(missed_args);
+ }
+}
+
+void DelayBasedBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+
+ observers_.erase(obs);
+ if (observers_.empty())
+ time_source_->SetActive(false);
+}
+
+bool DelayBasedBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+void DelayBasedBeginFrameSource::OnTimerTick() {
+ last_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime());
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers) {
+ BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() ||
+ (last_begin_frame_args_.frame_time >
+ last_args.frame_time +
+ last_begin_frame_args_.interval / kDoubleTickDivisor)) {
+ obs->OnBeginFrame(last_begin_frame_args_);
+ }
+ }
+}
+
+// ExternalBeginFrameSource -----------------------------------------------
+ExternalBeginFrameSource::ExternalBeginFrameSource(
+ ExternalBeginFrameSourceClient* client)
+ : client_(client) {
+ DCHECK(client_);
+}
+
+ExternalBeginFrameSource::~ExternalBeginFrameSource() = default;
+
+void ExternalBeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ BeginFrameSource::AsValueInto(state);
+
+ state->SetBoolean("paused", paused_);
+ state->SetInteger("num_observers", observers_.size());
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
+void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+
+ bool observers_was_empty = observers_.empty();
+ observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(paused_);
+ if (observers_was_empty)
+ client_->OnNeedsBeginFrames(true);
+
+ // Send a MISSED begin frame if necessary.
+ BeginFrameArgs missed_args = GetMissedBeginFrameArgs(obs);
+ if (missed_args.IsValid()) {
+ DCHECK_EQ(BeginFrameArgs::MISSED, missed_args.type);
+ obs->OnBeginFrame(missed_args);
+ }
+}
+
+void ExternalBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+
+ observers_.erase(obs);
+ if (observers_.empty())
+ client_->OnNeedsBeginFrames(false);
+}
+
+bool ExternalBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) {
+ if (paused_ == paused)
+ return;
+ paused_ = paused;
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers)
+ obs->OnBeginFrameSourcePausedChanged(paused_);
+}
+
+void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
+ // Ignore out of order begin frames because of layer tree frame sink being
+ // recreated.
+ if (last_begin_frame_args_.IsValid() &&
+ (args.frame_time <= last_begin_frame_args_.frame_time ||
+ (args.source_id == last_begin_frame_args_.source_id &&
+ args.sequence_number <= last_begin_frame_args_.sequence_number)))
+ return;
+
+ last_begin_frame_args_ = args;
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers) {
+ // It is possible that the source in which |args| originate changes, or that
+ // our hookup to this source changes, so we have to check for continuity.
+ // See also https://crbug.com/690127 for what may happen without this check.
+ const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() || (args.frame_time > last_args.frame_time)) {
+ DCHECK((args.source_id != last_args.source_id) ||
+ (args.sequence_number > last_args.sequence_number))
+ << "current " << args.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ obs->OnBeginFrame(args);
+ }
+ }
+}
+
+BeginFrameArgs ExternalBeginFrameSource::GetMissedBeginFrameArgs(
+ BeginFrameObserver* obs) {
+ if (!last_begin_frame_args_.IsValid())
+ return BeginFrameArgs();
+
+ const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
+ if (last_args.IsValid() &&
+ last_begin_frame_args_.frame_time <= last_args.frame_time) {
+ return BeginFrameArgs();
+ }
+
+ DCHECK((last_begin_frame_args_.source_id != last_args.source_id) ||
+ (last_begin_frame_args_.sequence_number > last_args.sequence_number))
+ << "current " << last_begin_frame_args_.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ BeginFrameArgs missed_args = last_begin_frame_args_;
+ missed_args.type = BeginFrameArgs::MISSED;
+ return missed_args;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.h b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
new file mode 100644
index 00000000000..8c6c46201fe
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
@@ -0,0 +1,275 @@
+// 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.
+
+#ifndef COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+namespace viz {
+
+// (Pure) Interface for observing BeginFrame messages from BeginFrameSource
+// objects.
+class VIZ_COMMON_EXPORT BeginFrameObserver {
+ public:
+ virtual ~BeginFrameObserver() {}
+
+ // The |args| given to OnBeginFrame is guaranteed to have
+ // |args|.IsValid()==true. If |args|.source_id did not change between
+ // invocations, |args|.sequence_number is guaranteed to be be strictly greater
+ // than the previous call. Further, |args|.frame_time is guaranteed to be
+ // greater than or equal to the previous call even if the source_id changes.
+ //
+ // Side effects: This function can (and most of the time *will*) change the
+ // return value of the LastUsedBeginFrameArgs method. See the documentation
+ // on that method for more information.
+ //
+ // The observer is required call BeginFrameSource::DidFinishFrame() as soon as
+ // it has completed handling the BeginFrame.
+ virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
+
+ // Returns the last BeginFrameArgs used by the observer. This method's
+ // return value is affected by the OnBeginFrame method!
+ //
+ // - Before the first call of OnBeginFrame, this method should return a
+ // BeginFrameArgs on which IsValid() returns false.
+ //
+ // - If the |args| passed to OnBeginFrame is (or *will be*) used, then
+ // LastUsedBeginFrameArgs return value should become the |args| given to
+ // OnBeginFrame.
+ //
+ // - If the |args| passed to OnBeginFrame is dropped, then
+ // LastUsedBeginFrameArgs return value should *not* change.
+ //
+ // These requirements are designed to allow chaining and nesting of
+ // BeginFrameObservers which filter the incoming BeginFrame messages while
+ // preventing "double dropping" and other bad side effects.
+ virtual const BeginFrameArgs& LastUsedBeginFrameArgs() const = 0;
+
+ virtual void OnBeginFrameSourcePausedChanged(bool paused) = 0;
+};
+
+// Simple base class which implements a BeginFrameObserver which checks the
+// incoming values meet the BeginFrameObserver requirements and implements the
+// required LastUsedBeginFrameArgs behaviour.
+//
+// Users of this class should;
+// - Implement the OnBeginFrameDerivedImpl function.
+// - Recommended (but not required) to call
+// BeginFrameObserverBase::OnValueInto in their overridden OnValueInto
+// function.
+class VIZ_COMMON_EXPORT BeginFrameObserverBase : public BeginFrameObserver {
+ public:
+ BeginFrameObserverBase();
+ ~BeginFrameObserverBase() override;
+
+ // BeginFrameObserver
+
+ // Traces |args| and DCHECK |args| satisfies pre-conditions then calls
+ // OnBeginFrameDerivedImpl and updates the last_begin_frame_args_ value on
+ // true.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+
+ protected:
+ // Return true if the given argument is (or will be) used.
+ virtual bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) = 0;
+
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ BeginFrameArgs last_begin_frame_args_;
+ int64_t dropped_begin_frame_args_ = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameObserverBase);
+};
+
+// Interface for a class which produces BeginFrame calls to a
+// BeginFrameObserver.
+//
+// BeginFrame calls *normally* occur just after a vsync interrupt when input
+// processing has been finished and provide information about the time values
+// of the vsync times. *However*, these values can be heavily modified or even
+// plain made up (when no vsync signal is available or vsync throttling is
+// turned off). See the BeginFrameObserver for information about the guarantees
+// all BeginFrameSources *must* provide.
+class VIZ_COMMON_EXPORT BeginFrameSource {
+ public:
+ BeginFrameSource();
+ virtual ~BeginFrameSource();
+
+ // Returns an identifier for this BeginFrameSource. Guaranteed unique within a
+ // process, but not across processes. This is used to create BeginFrames that
+ // originate at this source. Note that BeginFrameSources may pass on
+ // BeginFrames created by other sources, with different IDs.
+ uint32_t source_id() const { return source_id_; }
+
+ // BeginFrameObservers use DidFinishFrame to provide back pressure to a frame
+ // source about frame processing (rather than toggling SetNeedsBeginFrames
+ // every frame). For example, the BackToBackFrameSource uses them to make sure
+ // only one frame is pending at a time.
+ virtual void DidFinishFrame(BeginFrameObserver* obs) = 0;
+
+ // Add/Remove an observer from the source. When no observers are added the BFS
+ // should shut down its timers, disable vsync, etc.
+ virtual void AddObserver(BeginFrameObserver* obs) = 0;
+ virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
+
+ // Returns false if the begin frame source will just continue to produce
+ // begin frames without waiting.
+ virtual bool IsThrottled() const = 0;
+
+ virtual void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ private:
+ uint32_t source_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameSource);
+};
+
+// A BeginFrameSource that does nothing.
+class VIZ_COMMON_EXPORT StubBeginFrameSource : public BeginFrameSource {
+ public:
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ void AddObserver(BeginFrameObserver* obs) override {}
+ void RemoveObserver(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+};
+
+// A frame source which ticks itself independently.
+class VIZ_COMMON_EXPORT SyntheticBeginFrameSource : public BeginFrameSource {
+ public:
+ ~SyntheticBeginFrameSource() override;
+
+ virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) = 0;
+ // This overrides any past or future interval from updating vsync parameters.
+ virtual void SetAuthoritativeVSyncInterval(base::TimeDelta interval) = 0;
+};
+
+// A frame source which calls BeginFrame (at the next possible time) as soon as
+// an observer acknowledges the prior BeginFrame.
+class VIZ_COMMON_EXPORT BackToBackBeginFrameSource
+ : public SyntheticBeginFrameSource,
+ public DelayBasedTimeSourceClient {
+ public:
+ explicit BackToBackBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source);
+ ~BackToBackBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override;
+ bool IsThrottled() const override;
+
+ // SyntheticBeginFrameSource implementation.
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override {}
+ void SetAuthoritativeVSyncInterval(base::TimeDelta interval) override {}
+
+ // DelayBasedTimeSourceClient implementation.
+ void OnTimerTick() override;
+
+ private:
+ std::unique_ptr<DelayBasedTimeSource> time_source_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ std::unordered_set<BeginFrameObserver*> pending_begin_frame_observers_;
+ uint64_t next_sequence_number_;
+ base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackToBackBeginFrameSource);
+};
+
+// A frame source which is locked to an external parameters provides from a
+// vsync source and generates BeginFrameArgs for it.
+class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource
+ : public SyntheticBeginFrameSource,
+ public DelayBasedTimeSourceClient {
+ public:
+ explicit DelayBasedBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source);
+ ~DelayBasedBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+
+ // SyntheticBeginFrameSource implementation.
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+ void SetAuthoritativeVSyncInterval(base::TimeDelta interval) override;
+
+ // DelayBasedTimeSourceClient implementation.
+ void OnTimerTick() override;
+
+ private:
+ BeginFrameArgs CreateBeginFrameArgs(base::TimeTicks frame_time);
+
+ std::unique_ptr<DelayBasedTimeSource> time_source_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ base::TimeTicks last_timebase_;
+ base::TimeDelta authoritative_interval_;
+ BeginFrameArgs last_begin_frame_args_;
+ uint64_t next_sequence_number_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelayBasedBeginFrameSource);
+};
+
+class VIZ_COMMON_EXPORT ExternalBeginFrameSourceClient {
+ public:
+ // Only called when changed. Assumed false by default.
+ virtual void OnNeedsBeginFrames(bool needs_begin_frames) = 0;
+};
+
+// A BeginFrameSource that is only ticked manually. Usually the endpoint
+// of messages from some other thread/process that send OnBeginFrame and
+// receive SetNeedsBeginFrame messages. This turns such messages back into
+// an observable BeginFrameSource.
+class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
+ public:
+ // Client lifetime must be preserved by owner past the lifetime of this class.
+ explicit ExternalBeginFrameSource(ExternalBeginFrameSourceClient* client);
+ ~ExternalBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+ void AsValueInto(base::trace_event::TracedValue* state) const override;
+
+ void OnSetBeginFrameSourcePaused(bool paused);
+ void OnBeginFrame(const BeginFrameArgs& args);
+
+ protected:
+ // Called on AddObserver and gets missed BeginFrameArgs for the given
+ // observer. The missed BeginFrame is sent only if the returned
+ // BeginFrameArgs is valid.
+ virtual BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs);
+
+ BeginFrameArgs last_begin_frame_args_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ ExternalBeginFrameSourceClient* client_;
+ bool paused_ = false;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExternalBeginFrameSource);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc b/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc
new file mode 100644
index 00000000000..0b646241e63
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc
@@ -0,0 +1,610 @@
+// Copyright 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/viz/common/frame_sinks/begin_frame_source.h"
+
+#include <stdint.h>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/begin_frame_source_test.h"
+#include "components/viz/test/fake_delay_based_time_source.h"
+#include "components/viz/test/ordered_simple_task_runner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::NiceMock;
+using testing::_;
+
+namespace viz {
+namespace {
+
+// Returns a fake TimeTicks based on the given microsecond offset.
+base::TimeTicks TicksFromMicroseconds(int64_t micros) {
+ return base::TimeTicks() + base::TimeDelta::FromMicroseconds(micros);
+}
+
+// BeginFrameSource testing ----------------------------------------------------
+TEST(BeginFrameSourceTest, SourceIdsAreUnique) {
+ StubBeginFrameSource source1;
+ StubBeginFrameSource source2;
+ StubBeginFrameSource source3;
+ EXPECT_NE(source1.source_id(), source2.source_id());
+ EXPECT_NE(source1.source_id(), source3.source_id());
+ EXPECT_NE(source2.source_id(), source3.source_id());
+}
+
+// BackToBackBeginFrameSource testing
+// ------------------------------------------
+class BackToBackBeginFrameSourceTest : public ::testing::Test {
+ protected:
+ static const int64_t kDeadline;
+ static const int64_t kInterval;
+
+ void SetUp() override {
+ now_src_.reset(new base::SimpleTestTickClock());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
+ task_runner_ =
+ make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
+ std::unique_ptr<FakeDelayBasedTimeSource> time_source(
+ new FakeDelayBasedTimeSource(now_src_.get(), task_runner_.get()));
+ delay_based_time_source_ = time_source.get();
+ source_.reset(new BackToBackBeginFrameSource(std::move(time_source)));
+ obs_ = base::WrapUnique(new ::testing::NiceMock<MockBeginFrameObserver>);
+ }
+
+ void TearDown() override { obs_.reset(); }
+
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ std::unique_ptr<BackToBackBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+ FakeDelayBasedTimeSource* delay_based_time_source_; // Owned by |now_src_|.
+};
+
+const int64_t BackToBackBeginFrameSourceTest::kDeadline =
+ BeginFrameArgs::DefaultInterval().InMicroseconds();
+
+const int64_t BackToBackBeginFrameSourceTest::kInterval =
+ BeginFrameArgs::DefaultInterval().InMicroseconds();
+
+TEST_F(BackToBackBeginFrameSourceTest, AddObserverSendsBeginFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ RemoveObserverThenDidFinishFrameProducesNoFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->RemoveObserver(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+
+ // Verify no BeginFrame is sent to |obs_|. There is a pending task in the
+ // task_runner_ as a BeginFrame was posted, but it gets aborted since |obs_|
+ // is removed.
+ task_runner_->RunPendingTasks();
+ EXPECT_FALSE(task_runner_->HasPendingTasks());
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ DidFinishFrameThenRemoveObserverProducesNoFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->RemoveObserver(obs_.get());
+
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ TogglingObserverThenDidFinishFrameProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->RemoveObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ source_->DidFinishFrame(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ // The begin frame is posted at the time when the observer was added,
+ // so it ignores changes to "now" afterward.
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1110,
+ 1110 + kDeadline, kInterval);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ DidFinishFrameThenTogglingObserverProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ source_->RemoveObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ // Ticks at the time at which the observer was added, ignoring the
+ // last change to "now".
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1120,
+ 1120 + kDeadline, kInterval);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameNoObserver) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ source_->RemoveObserver(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_FALSE(task_runner_->RunPendingTasks());
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameMultipleCallsIdempotent) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 1200,
+ 1200 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DelayInPostedTaskProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(50));
+ // Ticks at the time the last frame finished, so ignores the last change to
+ // "now".
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversSynchronized) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ source_->AddObserver(&obs1);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs2);
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ source_->DidFinishFrame(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ source_->DidFinishFrame(&obs2);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ source_->RemoveObserver(&obs1);
+ source_->RemoveObserver(&obs2);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversInterleaved) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ source_->AddObserver(&obs1);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 3, 1200, 1200 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs1);
+ source_->RemoveObserver(&obs1);
+ // Removing all finished observers should disable the time source.
+ EXPECT_FALSE(delay_based_time_source_->Active());
+ // Finishing the frame for |obs1| posts a begin frame task, which will be
+ // aborted since |obs1| is removed. Clear that from the task runner.
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 4, 1300, 1300 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs2);
+ source_->RemoveObserver(&obs2);
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversAtOnce) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs1);
+ source_->AddObserver(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ // |obs1| finishes first.
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+
+ // |obs2| finishes also, before getting to the newly posted begin frame.
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs2);
+
+ // Because the begin frame source already ticked when |obs1| finished,
+ // we see it as the frame time for both observers.
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs1);
+ source_->RemoveObserver(&obs1);
+ source_->DidFinishFrame(&obs2);
+ source_->RemoveObserver(&obs2);
+}
+
+// DelayBasedBeginFrameSource testing
+// ------------------------------------------
+class DelayBasedBeginFrameSourceTest : public ::testing::Test {
+ public:
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ std::unique_ptr<DelayBasedBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+
+ void SetUp() override {
+ now_src_.reset(new base::SimpleTestTickClock());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
+ task_runner_ =
+ make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
+ std::unique_ptr<DelayBasedTimeSource> time_source(
+ new FakeDelayBasedTimeSource(now_src_.get(), task_runner_.get()));
+ time_source->SetTimebaseAndInterval(
+ base::TimeTicks(), base::TimeDelta::FromMicroseconds(10000));
+ source_.reset(new DelayBasedBeginFrameSource(std::move(time_source)));
+ obs_.reset(new MockBeginFrameObserver);
+ }
+
+ void TearDown() override { obs_.reset(); }
+};
+
+TEST_F(DelayBasedBeginFrameSourceTest,
+ AddObserverCallsOnBeginFrameWithMissedTick) {
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 10000, 20000,
+ 10000);
+ source_->AddObserver(obs_.get()); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, AddObserverCallsCausesOnBeginFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+ EXPECT_EQ(TicksFromMicroseconds(10000), task_runner_->NextTaskTime());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, BasicOperation) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20000, 30000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30000, 40000, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(30001));
+
+ source_->RemoveObserver(obs_.get());
+ // No new frames....
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60000));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, VSyncChanges) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20000, 30000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30000, 40000, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(30001));
+
+ // Update the vsync information
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(27500),
+ base::TimeDelta::FromMicroseconds(10001));
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 5, 40000, 47502, 10001);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 6, 47502, 57503, 10001);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 7, 57503, 67504, 10001);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60000));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, AuthoritativeVSyncChanges) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(500),
+ base::TimeDelta::FromMicroseconds(10000));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 500, 10500,
+ 10000);
+ source_->AddObserver(obs_.get());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10500, 20500, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20500, 30500, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(20501));
+
+ // This will keep the same timebase, so 500, 9999
+ source_->SetAuthoritativeVSyncInterval(
+ base::TimeDelta::FromMicroseconds(9999));
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30500, 40496, 9999);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 5, 40496, 50495, 9999);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(40497));
+
+ // Change the vsync params, but the new interval will be ignored.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(400),
+ base::TimeDelta::FromMicroseconds(1));
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 6, 50495, 60394, 9999);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 7, 60394, 70393, 9999);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60395));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, MultipleObservers) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ // now_src_ starts off at 1000.
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(9010));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs1, source_->source_id(), 1, 10000, 20000,
+ 10000);
+ source_->AddObserver(&obs1); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 20000, 30000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ // Sequence number unchanged for missed frame with time of last normal frame.
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs2, source_->source_id(), 2, 20000, 30000,
+ 10000);
+ source_->AddObserver(&obs2); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 3, 30000, 40000, 10000);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 3, 30000, 40000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ source_->RemoveObserver(&obs1);
+
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 4, 40000, 50000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ source_->RemoveObserver(&obs2);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(50000));
+ EXPECT_FALSE(task_runner_->HasPendingTasks());
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, DoubleTick) {
+ NiceMock<MockBeginFrameObserver> obs;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
+ source_->AddObserver(&obs);
+
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(5000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(4000));
+
+ // No begin frame received.
+ task_runner_->RunPendingTasks();
+
+ // Begin frame received.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(10000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(5000));
+ EXPECT_BEGIN_FRAME_USED(obs, source_->source_id(), 2, 10000, 20000, 10000);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, DoubleTickMissedFrame) {
+ NiceMock<MockBeginFrameObserver> obs;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(5000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(4000));
+
+ // No missed frame received.
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ // This does not cause a missed BeginFrame because of double ticking
+ // prevention. It does not produce a new sequence number.
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+
+ // Missed frame received.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(10000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(5000));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ // Sequence number is incremented again, because sufficient time has passed.
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 2, 10000, 20000,
+ 10000);
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+}
+
+// ExternalBeginFrameSource testing
+// --------------------------------------------
+class MockExternalBeginFrameSourceClient
+ : public ExternalBeginFrameSourceClient {
+ public:
+ MOCK_METHOD1(OnNeedsBeginFrames, void(bool));
+};
+
+class ExternalBeginFrameSourceTest : public ::testing::Test {
+ public:
+ std::unique_ptr<MockExternalBeginFrameSourceClient> client_;
+ std::unique_ptr<ExternalBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+
+ void SetUp() override {
+ client_.reset(new MockExternalBeginFrameSourceClient);
+ source_.reset(new ExternalBeginFrameSource(client_.get()));
+ obs_.reset(new MockBeginFrameObserver);
+ }
+
+ void TearDown() override {
+ client_.reset();
+ obs_.reset();
+ }
+};
+
+// https://crbug.com/690127: Duplicate BeginFrame caused DCHECK crash.
+TEST_F(ExternalBeginFrameSourceTest, OnBeginFrameChecksBeginFrameContinuity) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ source_->AddObserver(obs_.get());
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 0, 2, TicksFromMicroseconds(10000));
+ EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args);
+ source_->OnBeginFrame(args);
+
+ // Providing same args again to OnBeginFrame() should not notify observer.
+ source_->OnBeginFrame(args);
+
+ // Providing same args through a different ExternalBeginFrameSource also
+ // does not notify observer.
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ ExternalBeginFrameSource source2(client_.get());
+ source2.AddObserver(obs_.get());
+ source2.OnBeginFrame(args);
+}
+
+// https://crbug.com/730218: Avoid DCHECK crash in
+// ExternalBeginFrameSource::GetMissedBeginFrameArgs.
+TEST_F(ExternalBeginFrameSourceTest, GetMissedBeginFrameArgs) {
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0,
+ 2, 10000, 10100, 100);
+ source_->OnBeginFrame(args);
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 2, 10000, 10100, 100);
+ source_->AddObserver(obs_.get());
+ source_->RemoveObserver(obs_.get());
+
+ // Out of order frame_time. This might not be valid but still shouldn't
+ // cause a DCHECK in ExternalBeginFrameSource code.
+ args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2, 9999, 10100,
+ 101);
+ source_->OnBeginFrame(args);
+
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL(*obs_, OnBeginFrame(_)).Times(0);
+ source_->AddObserver(obs_.get());
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
new file mode 100644
index 00000000000..1a6cd56f4a2
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
@@ -0,0 +1,180 @@
+// Copyright 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/viz/common/frame_sinks/delay_based_time_source.h"
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+
+namespace viz {
+
+// The following methods correspond to the DelayBasedTimeSource that uses
+// the base::TimeTicks::Now as the timebase.
+DelayBasedTimeSource::DelayBasedTimeSource(
+ base::SingleThreadTaskRunner* task_runner)
+ : client_(nullptr),
+ active_(false),
+ timebase_(base::TimeTicks()),
+ interval_(BeginFrameArgs::DefaultInterval()),
+ last_tick_time_(base::TimeTicks() - interval_),
+ next_tick_time_(base::TimeTicks()),
+ task_runner_(task_runner),
+ weak_factory_(this) {}
+
+DelayBasedTimeSource::~DelayBasedTimeSource() = default;
+
+void DelayBasedTimeSource::SetActive(bool active) {
+ TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active);
+
+ if (active == active_)
+ return;
+
+ active_ = active;
+
+ if (active_) {
+ PostNextTickTask(Now());
+ } else {
+ last_tick_time_ = base::TimeTicks();
+ next_tick_time_ = base::TimeTicks();
+ tick_closure_.Cancel();
+ }
+}
+
+base::TimeDelta DelayBasedTimeSource::Interval() const {
+ return interval_;
+}
+
+bool DelayBasedTimeSource::Active() const {
+ return active_;
+}
+
+base::TimeTicks DelayBasedTimeSource::LastTickTime() const {
+ return last_tick_time_;
+}
+
+base::TimeTicks DelayBasedTimeSource::NextTickTime() const {
+ return next_tick_time_;
+}
+
+void DelayBasedTimeSource::OnTimerTick() {
+ DCHECK(active_);
+
+ last_tick_time_ = next_tick_time_;
+
+ PostNextTickTask(Now());
+
+ // Fire the tick.
+ if (client_)
+ client_->OnTimerTick();
+}
+
+void DelayBasedTimeSource::SetClient(DelayBasedTimeSourceClient* client) {
+ client_ = client;
+}
+
+void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ interval_ = interval;
+ timebase_ = timebase;
+}
+
+base::TimeTicks DelayBasedTimeSource::Now() const {
+ return base::TimeTicks::Now();
+}
+
+// This code tries to achieve an average tick rate as close to interval_ as
+// possible. To do this, it has to deal with a few basic issues:
+// 1. PostDelayedTask can delay only at a millisecond granularity. So, 16.666
+// has to posted as 16 or 17.
+// 2. A delayed task may come back a bit late (a few ms), or really late
+// (frames later)
+//
+// The basic idea with this scheduler here is to keep track of where we *want*
+// to run in tick_target_. We update this with the exact interval.
+//
+// Then, when we post our task, we take the floor of (tick_target_ and Now()).
+// If we started at now=0, and 60FPs (all times in milliseconds):
+// now=0 target=16.667 PostDelayedTask(16)
+//
+// When our callback runs, we figure out how far off we were from that goal.
+// Because of the flooring operation, and assuming our timer runs exactly when
+// it should, this yields:
+// now=16 target=16.667
+//
+// Since we can't post a 0.667 ms task to get to now=16, we just treat this as a
+// tick. Then, we update target to be 33.333. We now post another task based on
+// the difference between our target and now:
+// now=16 tick_target=16.667 new_target=33.333 -->
+// PostDelayedTask(floor(33.333 - 16)) --> PostDelayedTask(17)
+//
+// Over time, with no late tasks, this leads to us posting tasks like this:
+// now=0 tick_target=0 new_target=16.667 -->
+// tick(), PostDelayedTask(16)
+// now=16 tick_target=16.667 new_target=33.333 -->
+// tick(), PostDelayedTask(17)
+// now=33 tick_target=33.333 new_target=50.000 -->
+// tick(), PostDelayedTask(17)
+// now=50 tick_target=50.000 new_target=66.667 -->
+// tick(), PostDelayedTask(16)
+//
+// We treat delays in tasks differently depending on the amount of delay we
+// encounter. Suppose we posted a task with a target=16.667:
+// Case 1: late but not unrecoverably-so
+// now=18 tick_target=16.667
+//
+// Case 2: so late we obviously missed the tick
+// now=25.0 tick_target=16.667
+//
+// We treat the first case as a tick anyway, and assume the delay was unusual.
+// Thus, we compute the new_target based on the old timebase:
+// now=18 tick_target=16.667 new_target=33.333 -->
+// tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15)
+// This brings us back to 18+15 = 33, which was where we would have been if the
+// task hadn't been late.
+//
+// For the really late delay, we we move to the next logical tick. The timebase
+// is not reset.
+// now=37 tick_target=16.667 new_target=50.000 -->
+// tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
+void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
+ if (interval_.is_zero()) {
+ next_tick_time_ = now;
+ } else {
+ next_tick_time_ = now.SnappedToNextTick(timebase_, interval_);
+ if (next_tick_time_ == now)
+ next_tick_time_ += interval_;
+ DCHECK_GT(next_tick_time_, now);
+ }
+ tick_closure_.Reset(base::Bind(&DelayBasedTimeSource::OnTimerTick,
+ weak_factory_.GetWeakPtr()));
+ task_runner_->PostDelayedTask(FROM_HERE, tick_closure_.callback(),
+ next_tick_time_ - now);
+}
+
+std::string DelayBasedTimeSource::TypeString() const {
+ return "DelayBasedTimeSource";
+}
+
+void DelayBasedTimeSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetString("type", TypeString());
+ state->SetDouble("last_tick_time_us",
+ LastTickTime().since_origin().InMicroseconds());
+ state->SetDouble("next_tick_time_us",
+ NextTickTime().since_origin().InMicroseconds());
+ state->SetDouble("interval_us", interval_.InMicroseconds());
+ state->SetDouble("timebase_us", timebase_.since_origin().InMicroseconds());
+ state->SetBoolean("active", active_);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.h b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
new file mode 100644
index 00000000000..9a9d0a3d069
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
@@ -0,0 +1,91 @@
+// Copyright 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_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace viz {
+class VIZ_COMMON_EXPORT DelayBasedTimeSourceClient {
+ public:
+ virtual void OnTimerTick() = 0;
+
+ protected:
+ virtual ~DelayBasedTimeSourceClient() {}
+};
+
+// This timer implements a time source that achieves the specified interval
+// in face of millisecond-precision delayed callbacks and random queueing
+// delays. DelayBasedTimeSource uses base::TimeTicks::Now as its timebase.
+class VIZ_COMMON_EXPORT DelayBasedTimeSource {
+ public:
+ explicit DelayBasedTimeSource(base::SingleThreadTaskRunner* task_runner);
+ virtual ~DelayBasedTimeSource();
+
+ void SetClient(DelayBasedTimeSourceClient* client);
+
+ void SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ base::TimeDelta Interval() const;
+
+ void SetActive(bool active);
+ bool Active() const;
+
+ // Get the last and next tick times. NextTickTime() returns null when
+ // inactive.
+ base::TimeTicks LastTickTime() const;
+ base::TimeTicks NextTickTime() const;
+
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ protected:
+ // Virtual for testing.
+ virtual base::TimeTicks Now() const;
+ virtual std::string TypeString() const;
+
+ private:
+ void PostNextTickTask(base::TimeTicks now);
+ void ResetTickTask(base::TimeTicks now);
+
+ void OnTimerTick();
+
+ DelayBasedTimeSourceClient* client_;
+
+ bool active_;
+
+ base::TimeTicks timebase_;
+ base::TimeDelta interval_;
+
+ base::TimeTicks last_tick_time_;
+ base::TimeTicks next_tick_time_;
+
+ base::CancelableClosure tick_closure_;
+
+ base::SingleThreadTaskRunner* task_runner_;
+
+ base::WeakPtrFactory<DelayBasedTimeSource> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
new file mode 100644
index 00000000000..be4437dcce4
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
@@ -0,0 +1,351 @@
+// Copyright 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/viz/common/frame_sinks/delay_based_time_source.h"
+
+#include <stdint.h>
+
+#include "base/test/test_simple_task_runner.h"
+#include "components/viz/test/fake_delay_based_time_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+base::TimeDelta Interval() {
+ return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
+ 60);
+}
+
+class DelayBasedTimeSourceTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ now_src_ = base::MakeUnique<base::SimpleTestTickClock>();
+ task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
+ delay_based_time_source_ = base::MakeUnique<FakeDelayBasedTimeSource>(
+ now_src_.get(), task_runner_.get());
+ delay_based_time_source_->SetClient(&client_);
+ }
+
+ void TearDown() override {
+ delay_based_time_source_.reset();
+ task_runner_ = nullptr;
+ now_src_.reset();
+ }
+
+ void SetNow(base::TimeTicks ticks) { now_src_->SetNowTicks(ticks); }
+
+ base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
+
+ FakeDelayBasedTimeSource* timer() { return delay_based_time_source_.get(); }
+
+ FakeDelayBasedTimeSourceClient* client() { return &client_; }
+
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ FakeDelayBasedTimeSourceClient client_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ std::unique_ptr<FakeDelayBasedTimeSource> delay_based_time_source_;
+};
+
+TEST_F(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(timer()->Active());
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(16));
+ task_runner()->RunPendingTasks();
+ EXPECT_TRUE(timer()->Active());
+ EXPECT_TRUE(client()->TickCalled());
+}
+
+TEST_F(DelayBasedTimeSourceTest, TickNotCalledWithTaskPosted) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ timer()->SetActive(false);
+ task_runner()->RunPendingTasks();
+ EXPECT_FALSE(client()->TickCalled());
+}
+
+TEST_F(DelayBasedTimeSourceTest, StartTwiceEnqueuesOneTask) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->ClearPendingTasks();
+ timer()->SetActive(true);
+ EXPECT_FALSE(task_runner()->HasPendingTask());
+}
+
+TEST_F(DelayBasedTimeSourceTest, StartWhenRunningDoesntTick) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->RunPendingTasks();
+ task_runner()->ClearPendingTasks();
+ timer()->SetActive(true);
+ EXPECT_FALSE(task_runner()->HasPendingTask());
+}
+
+// At 60Hz, when the tick returns at exactly the requested next time, make sure
+// a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenExactlyOnRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval());
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at slightly after the requested next time,
+// make sure a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenSlightlyAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval() + base::TimeDelta::FromMicroseconds(1));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at exactly 2*interval after the requested next
+// time, make sure we don't tick unnecessarily.
+TEST_F(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + 2 * Interval());
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at 2*interval and a bit after the requested
+// next time, make sure a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + 2 * Interval() +
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns halfway to the next frame time, make sure
+// a correct next delay value is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenHalfAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval() + base::TimeDelta::FromMilliseconds(8));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ base::TimeTicks future_timebase = timer()->Now() + Interval() * 10;
+
+ // 1ms jitter
+ base::TimeDelta jitter1 = base::TimeDelta::FromMilliseconds(1);
+
+ // Tick with +1ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -1ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // 8 ms jitter
+ base::TimeDelta jitter8 = base::TimeDelta::FromMilliseconds(8);
+
+ // Tick with +8ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -8ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // 15 ms jitter
+ base::TimeDelta jitter15 = base::TimeDelta::FromMilliseconds(15);
+
+ // Tick with +15ms jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -15ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
+ int num_iterations = 10;
+
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+
+ double total_frame_time = 0.0;
+ for (int i = 0; i < num_iterations; ++i) {
+ int64_t delay_ms = task_runner()->NextPendingTaskDelay().InMilliseconds();
+
+ // accumulate the "delay"
+ total_frame_time += delay_ms / 1000.0;
+
+ // Run the callback exactly when asked
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(delay_ms));
+ task_runner()->RunPendingTasks();
+ }
+ double average_interval =
+ total_frame_time / static_cast<double>(num_iterations);
+ EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1);
+}
+
+TEST_F(DelayBasedTimeSourceTest, TestDeactivateWhilePending) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true); // Should post a task.
+ timer()->SetActive(false);
+ // Should run the posted task without crashing.
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->RunPendingTasks();
+}
+
+TEST_F(DelayBasedTimeSourceTest,
+ TestDeactivateAndReactivateBeforeNextTickTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+
+ // Should run the activate task, and pick up a new timebase.
+ timer()->SetActive(true);
+ task_runner()->RunPendingTasks();
+
+ // Stop the timer()
+ timer()->SetActive(false);
+
+ // Task will be pending anyway, run it
+ task_runner()->RunPendingTasks();
+
+ // Start the timer() again, but before the next tick time the timer()
+ // previously planned on using. That same tick time should still be targeted.
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(4));
+ timer()->SetActive(true);
+ EXPECT_EQ(12, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+
+ // Should run the activate task, and pick up a new timebase.
+ timer()->SetActive(true);
+ task_runner()->RunPendingTasks();
+
+ // Stop the timer().
+ timer()->SetActive(false);
+
+ // Task will be pending anyway, run it.
+ task_runner()->RunPendingTasks();
+
+ // Start the timer() again, but before the next tick time the timer()
+ // previously planned on using. That same tick time should still be targeted.
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(20));
+ timer()->SetActive(true);
+ EXPECT_EQ(13, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/gl_helper_benchmark.cc b/chromium/components/viz/common/gl_helper_benchmark.cc
index 59c3a73e537..7d9a76b811c 100644
--- a/chromium/components/viz/common/gl_helper_benchmark.cc
+++ b/chromium/components/viz/common/gl_helper_benchmark.cc
@@ -120,7 +120,7 @@ class GLHelperBenchmark : public testing::Test {
gpu::gles2::GLES2Interface* gl_;
std::unique_ptr<GLHelper> helper_;
std::unique_ptr<GLHelperScaling> helper_scaling_;
- std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
};
TEST_F(GLHelperBenchmark, ScaleBenchmark) {
diff --git a/chromium/components/viz/common/gl_helper_scaling.cc b/chromium/components/viz/common/gl_helper_scaling.cc
index e394202df35..4fa88db8b92 100644
--- a/chromium/components/viz/common/gl_helper_scaling.cc
+++ b/chromium/components/viz/common/gl_helper_scaling.cc
@@ -6,11 +6,11 @@
#include <stddef.h>
-#include <deque>
#include <string>
#include <vector>
#include "base/bind.h"
+#include "base/containers/circular_deque.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -271,12 +271,12 @@ void GLHelperScaling::ConvertScalerOpsToScalerStages(
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- std::deque<GLHelperScaling::ScaleOp>* x_ops,
- std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
std::vector<ScalerStage>* scaler_stages) {
while (!x_ops->empty() || !y_ops->empty()) {
gfx::Size intermediate_size = src_subrect.size();
- std::deque<ScaleOp>* current_queue = NULL;
+ base::circular_deque<ScaleOp>* current_queue = NULL;
if (!y_ops->empty()) {
current_queue = y_ops;
@@ -397,7 +397,7 @@ void GLHelperScaling::ComputeScalerStages(
return;
}
- std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), dst_size.width(), true,
quality == GLHelper::SCALER_QUALITY_GOOD,
&x_ops);
diff --git a/chromium/components/viz/common/gl_helper_scaling.h b/chromium/components/viz/common/gl_helper_scaling.h
index a37ea919ee5..1d21916942b 100644
--- a/chromium/components/viz/common/gl_helper_scaling.h
+++ b/chromium/components/viz/common/gl_helper_scaling.h
@@ -5,10 +5,10 @@
#ifndef COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
#define COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
-#include <deque>
#include <map>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "components/viz/common/gl_helper.h"
#include "components/viz/common/viz_common_export.h"
@@ -97,7 +97,7 @@ class VIZ_COMMON_EXPORT GLHelperScaling {
int dst,
bool scale_x,
bool allow3,
- std::deque<ScaleOp>* ops) {
+ base::circular_deque<ScaleOp>* ops) {
int num_downscales = 0;
if (allow3 && dst * 3 >= src && dst * 2 < src) {
// Technically, this should be a scale up and then a
@@ -177,8 +177,8 @@ class VIZ_COMMON_EXPORT GLHelperScaling {
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- std::deque<GLHelperScaling::ScaleOp>* x_ops,
- std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
std::vector<ScalerStage>* scaler_stages);
scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
diff --git a/chromium/components/viz/common/gl_helper_unittest.cc b/chromium/components/viz/common/gl_helper_unittest.cc
index 34192b4837c..49a42f581b8 100644
--- a/chromium/components/viz/common/gl_helper_unittest.cc
+++ b/chromium/components/viz/common/gl_helper_unittest.cc
@@ -960,7 +960,7 @@ class GLHelperTest : public testing::Test {
for (int x = 0; x < bmp1.width(); ++x) {
if (!ColorsClose(bmp1.getColor(x, y), bmp2.getColor(x, y),
bmp1.colorType())) {
- LOG(ERROR) << "Bitmap color comparision failure";
+ LOG(ERROR) << "Bitmap color comparison failure";
return false;
}
}
@@ -1038,7 +1038,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
bool result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-1";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-1";
return false;
}
const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4;
@@ -1051,7 +1051,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-2";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-2";
return false;
}
// Test Pattern-3, Fill with CheckerBoard Pattern.
@@ -1062,7 +1062,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-3";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-3";
return false;
}
gl_->DeleteTextures(1, &src_texture);
@@ -1073,7 +1073,7 @@ class GLHelperTest : public testing::Test {
}
void TestAddOps(int src, int dst, bool scale_x, bool allow3) {
- std::deque<GLHelperScaling::ScaleOp> ops;
+ base::circular_deque<GLHelperScaling::ScaleOp> ops;
GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
// Scale factor 3 is a special case.
// It is currently only allowed by itself.
@@ -1249,7 +1249,7 @@ class GLHelperTest : public testing::Test {
gpu::gles2::GLES2Interface* gl_;
std::unique_ptr<GLHelper> helper_;
std::unique_ptr<GLHelperScaling> helper_scaling_;
- std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
};
class GLHelperPixelTest : public GLHelperTest {
diff --git a/chromium/components/viz/common/gpu/DEPS b/chromium/components/viz/common/gpu/DEPS
index 945aba3fc2b..d038e11da6e 100644
--- a/chromium/components/viz/common/gpu/DEPS
+++ b/chromium/components/viz/common/gpu/DEPS
@@ -5,7 +5,7 @@ include_rules = [
"+gpu/GLES2/gl2extchromium.h",
"+gpu/ipc",
"+gpu/skia_bindings",
- "+ui/gfx",
+ "+gpu/vulkan",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/khronos/GLES2/gl2ext.h",
"+third_party/skia/include/gpu",
diff --git a/chromium/components/viz/common/gpu/in_process_context_provider.h b/chromium/components/viz/common/gpu/in_process_context_provider.h
index 493191fc389..f1eea6c030f 100644
--- a/chromium/components/viz/common/gpu/in_process_context_provider.h
+++ b/chromium/components/viz/common/gpu/in_process_context_provider.h
@@ -33,8 +33,7 @@ class GrContextForGLES2Interface;
namespace viz {
-class VIZ_COMMON_EXPORT InProcessContextProvider
- : public NON_EXPORTED_BASE(ContextProvider) {
+class VIZ_COMMON_EXPORT InProcessContextProvider : public ContextProvider {
public:
InProcessContextProvider(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
diff --git a/chromium/components/viz/common/gpu/vulkan_context_provider.h b/chromium/components/viz/common/gpu/vulkan_context_provider.h
new file mode 100644
index 00000000000..0dc77b003fa
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_context_provider.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace gpu {
+class VulkanDeviceQueue;
+}
+
+namespace viz {
+
+// The VulkanContextProvider groups sharing of vulkan objects synchronously.
+class VIZ_COMMON_EXPORT VulkanContextProvider
+ : public base::RefCountedThreadSafe<VulkanContextProvider> {
+ public:
+ virtual gpu::VulkanDeviceQueue* GetDeviceQueue() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<VulkanContextProvider>;
+ virtual ~VulkanContextProvider() {}
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
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
new file mode 100644
index 00000000000..d1714290d3d
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -0,0 +1,73 @@
+// 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/viz/common/gpu/vulkan_in_process_context_provider.h"
+#include "gpu/vulkan/features.h"
+
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+#endif // BUILDFLAG(ENABLE_VULKAN)
+
+namespace viz {
+
+scoped_refptr<VulkanInProcessContextProvider>
+VulkanInProcessContextProvider::Create() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ if (!gpu::VulkanSupported())
+ return nullptr;
+
+ scoped_refptr<VulkanInProcessContextProvider> context_provider(
+ new VulkanInProcessContextProvider);
+ if (!context_provider->Initialize())
+ return nullptr;
+ return context_provider;
+#else
+ return nullptr;
+#endif
+}
+
+bool VulkanInProcessContextProvider::Initialize() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ DCHECK(!device_queue_);
+ std::unique_ptr<gpu::VulkanDeviceQueue> device_queue(
+ new gpu::VulkanDeviceQueue);
+ if (!device_queue->Initialize(
+ gpu::VulkanDeviceQueue::GRAPHICS_QUEUE_FLAG |
+ gpu::VulkanDeviceQueue::PRESENTATION_SUPPORT_QUEUE_FLAG)) {
+ device_queue->Destroy();
+ return false;
+ }
+
+ device_queue_ = std::move(device_queue);
+ return true;
+#else
+ return false;
+#endif
+}
+
+void VulkanInProcessContextProvider::Destroy() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ if (device_queue_) {
+ device_queue_->Destroy();
+ device_queue_.reset();
+ }
+#endif
+}
+
+gpu::VulkanDeviceQueue* VulkanInProcessContextProvider::GetDeviceQueue() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ return device_queue_.get();
+#else
+ return nullptr;
+#endif
+}
+
+VulkanInProcessContextProvider::VulkanInProcessContextProvider() {}
+
+VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
+ Destroy();
+}
+
+} // 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
new file mode 100644
index 00000000000..9a94fccaf99
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -0,0 +1,45 @@
+// 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_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
+
+#include <memory>
+
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/vulkan/features.h"
+
+namespace gpu {
+class VulkanDeviceQueue;
+}
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT VulkanInProcessContextProvider
+ : public VulkanContextProvider {
+ public:
+ static scoped_refptr<VulkanInProcessContextProvider> Create();
+
+ bool Initialize();
+ void Destroy();
+
+ // VulkanContextProvider implementation
+ gpu::VulkanDeviceQueue* GetDeviceQueue() override;
+
+ protected:
+ VulkanInProcessContextProvider();
+ ~VulkanInProcessContextProvider() override;
+
+ private:
+#if BUILDFLAG(ENABLE_VULKAN)
+ std::unique_ptr<gpu::VulkanDeviceQueue> device_queue_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(VulkanInProcessContextProvider);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/common/hit_test/DEPS b/chromium/components/viz/common/hit_test/DEPS
deleted file mode 100644
index b49b8636b9b..00000000000
--- a/chromium/components/viz/common/hit_test/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+ui/gfx/geometry",
- "+ui/gfx/transform.h",
-] \ No newline at end of file
diff --git a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
index b90bfb19a6e..2f93daae037 100644
--- a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
+++ b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
@@ -15,7 +15,7 @@ namespace viz {
// A AggregatedHitTestRegion element with child_count of kEndOfList indicates
// the last element and end of the list.
-constexpr int kEndOfList = -1;
+constexpr int32_t kEndOfList = -1;
// An array of AggregatedHitTestRegion elements is used to define the
// aggregated hit-test data for the Display.
@@ -24,6 +24,17 @@ constexpr int kEndOfList = -1;
// write the hit_test data, and the viz host can read without
// process hops.
struct AggregatedHitTestRegion {
+ AggregatedHitTestRegion(FrameSinkId frame_sink_id,
+ uint32_t flags,
+ gfx::Rect rect,
+ gfx::Transform transform,
+ int32_t child_count)
+ : frame_sink_id(frame_sink_id),
+ flags(flags),
+ rect(rect),
+ transform(transform),
+ child_count(child_count) {}
+
// The FrameSinkId corresponding to this region. Events that match
// are routed to this surface.
FrameSinkId frame_sink_id;
@@ -41,7 +52,7 @@ struct AggregatedHitTestRegion {
// The number of children including their children below this entry.
// If this element is not matched then child_count elements can be skipped
// to move to the next entry.
- int child_count;
+ int32_t child_count;
};
} // namespace viz
diff --git a/chromium/components/viz/common/quads/DEPS b/chromium/components/viz/common/quads/DEPS
index 766ac6bb3c0..abf379f6838 100644
--- a/chromium/components/viz/common/quads/DEPS
+++ b/chromium/components/viz/common/quads/DEPS
@@ -1,5 +1,9 @@
include_rules = [
+ # TODO(staraz): cc/base was added because SharedQuadState includes
+ # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
+ "+cc/base",
+
"+gpu/command_buffer/common",
"+mojo/public/cpp/bindings",
- "+ui/gfx",
+ "+third_party/skia",
]
diff --git a/chromium/components/viz/common/quads/copy_output_request.cc b/chromium/components/viz/common/quads/copy_output_request.cc
new file mode 100644
index 00000000000..de505d68c32
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_request.cc
@@ -0,0 +1,68 @@
+// 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/viz/common/quads/copy_output_request.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace viz {
+
+CopyOutputRequest::CopyOutputRequest() : force_bitmap_result_(false) {}
+
+CopyOutputRequest::CopyOutputRequest(bool force_bitmap_result,
+ CopyOutputRequestCallback result_callback)
+ : force_bitmap_result_(force_bitmap_result),
+ result_callback_(std::move(result_callback)) {
+ DCHECK(!result_callback_.is_null());
+ TRACE_EVENT_ASYNC_BEGIN0("viz", "CopyOutputRequest", this);
+}
+
+CopyOutputRequest::~CopyOutputRequest() {
+ if (!result_callback_.is_null())
+ SendResult(CopyOutputResult::CreateEmptyResult());
+}
+
+void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) {
+ TRACE_EVENT_ASYNC_END1("viz", "CopyOutputRequest", this, "success",
+ !result->IsEmpty());
+ if (result_task_runner_) {
+ result_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(result_callback_), std::move(result)));
+ result_task_runner_ = nullptr;
+ } else {
+ std::move(result_callback_).Run(std::move(result));
+ }
+}
+
+void CopyOutputRequest::SendEmptyResult() {
+ SendResult(CopyOutputResult::CreateEmptyResult());
+}
+
+void CopyOutputRequest::SendBitmapResult(std::unique_ptr<SkBitmap> bitmap) {
+ SendResult(CopyOutputResult::CreateBitmapResult(std::move(bitmap)));
+}
+
+void CopyOutputRequest::SendTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback) {
+ DCHECK(texture_mailbox.IsTexture());
+ SendResult(CopyOutputResult::CreateTextureResult(
+ size, texture_mailbox, std::move(release_callback)));
+}
+
+void CopyOutputRequest::SetTextureMailbox(
+ const TextureMailbox& texture_mailbox) {
+ DCHECK(!force_bitmap_result_);
+ DCHECK(texture_mailbox.IsTexture());
+ texture_mailbox_ = texture_mailbox;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/copy_output_request.h b/chromium/components/viz/common/quads/copy_output_request.h
new file mode 100644
index 00000000000..ccb42adfdb2
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_request.h
@@ -0,0 +1,114 @@
+// 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_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/task_runner.h"
+#include "base/unguessable_token.h"
+#include "components/viz/common/quads/single_release_callback.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/viz_common_export.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkBitmap;
+
+namespace viz {
+
+namespace mojom {
+class CopyOutputRequestDataView;
+}
+
+class CopyOutputResult;
+
+class VIZ_COMMON_EXPORT CopyOutputRequest {
+ public:
+ using CopyOutputRequestCallback =
+ base::OnceCallback<void(std::unique_ptr<CopyOutputResult> result)>;
+
+ static std::unique_ptr<CopyOutputRequest> CreateEmptyRequest() {
+ return base::WrapUnique(new CopyOutputRequest);
+ }
+ static std::unique_ptr<CopyOutputRequest> CreateRequest(
+ CopyOutputRequestCallback result_callback) {
+ return base::WrapUnique(
+ new CopyOutputRequest(false, std::move(result_callback)));
+ }
+ static std::unique_ptr<CopyOutputRequest> CreateBitmapRequest(
+ CopyOutputRequestCallback result_callback) {
+ return base::WrapUnique(
+ new CopyOutputRequest(true, std::move(result_callback)));
+ }
+
+ ~CopyOutputRequest();
+
+ bool IsEmpty() const { return result_callback_.is_null(); }
+
+ // Requests that the result callback be run as a task posted to the given
+ // |task_runner|. If this is not set, the result callback could be run from
+ // any context.
+ void set_result_task_runner(scoped_refptr<base::TaskRunner> task_runner) {
+ result_task_runner_ = std::move(task_runner);
+ }
+ bool has_result_task_runner() const { return !!result_task_runner_; }
+
+ // Optionally specify the source of this copy request. If set when this copy
+ // request is submitted to a layer, a prior uncommitted copy request from the
+ // same source will be aborted.
+ void set_source(const base::UnguessableToken& source) { source_ = source; }
+ bool has_source() const { return source_.has_value(); }
+ const base::UnguessableToken& source() const { return *source_; }
+
+ bool force_bitmap_result() const { return force_bitmap_result_; }
+
+ // By default copy requests copy the entire layer's subtree output. If an
+ // area is given, then the intersection of this rect (in layer space) with
+ // the layer's subtree output will be returned.
+ void set_area(const gfx::Rect& area) { area_ = area; }
+ bool has_area() const { return area_.has_value(); }
+ const gfx::Rect& area() const { return *area_; }
+
+ // By default copy requests create a new TextureMailbox to return contents
+ // in. This allows a client to provide a TextureMailbox, and the compositor
+ // will place the result inside the TextureMailbox.
+ void SetTextureMailbox(const TextureMailbox& texture_mailbox);
+ bool has_texture_mailbox() const { return texture_mailbox_.has_value(); }
+ const TextureMailbox& texture_mailbox() const { return *texture_mailbox_; }
+
+ void SendEmptyResult();
+ void SendBitmapResult(std::unique_ptr<SkBitmap> bitmap);
+ void SendTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback);
+
+ void SendResult(std::unique_ptr<CopyOutputResult> result);
+
+ private:
+ friend struct mojo::StructTraits<mojom::CopyOutputRequestDataView,
+ std::unique_ptr<CopyOutputRequest>>;
+
+ CopyOutputRequest();
+ CopyOutputRequest(bool force_bitmap_result,
+ CopyOutputRequestCallback result_callback);
+
+ scoped_refptr<base::TaskRunner> result_task_runner_;
+ base::Optional<base::UnguessableToken> source_;
+ bool force_bitmap_result_;
+ base::Optional<gfx::Rect> area_;
+ base::Optional<TextureMailbox> texture_mailbox_;
+ CopyOutputRequestCallback result_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyOutputRequest);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
diff --git a/chromium/components/viz/common/quads/copy_output_result.cc b/chromium/components/viz/common/quads/copy_output_result.cc
new file mode 100644
index 00000000000..62f723c8223
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_result.cc
@@ -0,0 +1,47 @@
+// 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/viz/common/quads/copy_output_result.h"
+
+#include "base/logging.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+
+namespace viz {
+
+CopyOutputResult::CopyOutputResult() {}
+
+CopyOutputResult::CopyOutputResult(std::unique_ptr<SkBitmap> bitmap)
+ : size_(bitmap->width(), bitmap->height()), bitmap_(std::move(bitmap)) {
+ DCHECK(bitmap_);
+}
+
+CopyOutputResult::CopyOutputResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback)
+ : size_(size),
+ texture_mailbox_(texture_mailbox),
+ release_callback_(std::move(release_callback)) {
+ DCHECK(texture_mailbox_.IsTexture());
+}
+
+CopyOutputResult::~CopyOutputResult() {
+ if (release_callback_)
+ release_callback_->Run(gpu::SyncToken(), false);
+}
+
+std::unique_ptr<SkBitmap> CopyOutputResult::TakeBitmap() {
+ return std::move(bitmap_);
+}
+
+void CopyOutputResult::TakeTexture(
+ TextureMailbox* texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback>* release_callback) {
+ *texture_mailbox = texture_mailbox_;
+ *release_callback = std::move(release_callback_);
+
+ texture_mailbox_ = TextureMailbox();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/copy_output_result.h b/chromium/components/viz/common/quads/copy_output_result.h
new file mode 100644
index 00000000000..901ea5c9628
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_result.h
@@ -0,0 +1,79 @@
+// 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_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "components/viz/common/quads/single_release_callback.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/viz_common_export.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
+
+class SkBitmap;
+
+namespace cc {
+namespace mojom {
+class CopyOutputResultDataView;
+}
+} // namespace cc
+
+namespace viz {
+
+class TextureMailbox;
+
+class VIZ_COMMON_EXPORT CopyOutputResult {
+ public:
+ static std::unique_ptr<CopyOutputResult> CreateEmptyResult() {
+ return base::WrapUnique(new CopyOutputResult);
+ }
+ static std::unique_ptr<CopyOutputResult> CreateBitmapResult(
+ std::unique_ptr<SkBitmap> bitmap) {
+ return base::WrapUnique(new CopyOutputResult(std::move(bitmap)));
+ }
+ static std::unique_ptr<CopyOutputResult> CreateTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback) {
+ return base::WrapUnique(new CopyOutputResult(size, texture_mailbox,
+ std::move(release_callback)));
+ }
+
+ ~CopyOutputResult();
+
+ bool IsEmpty() const { return !HasBitmap() && !HasTexture(); }
+ bool HasBitmap() const { return !!bitmap_ && !bitmap_->isNull(); }
+ bool HasTexture() const { return texture_mailbox_.IsValid(); }
+
+ gfx::Size size() const { return size_; }
+ std::unique_ptr<SkBitmap> TakeBitmap();
+ void TakeTexture(TextureMailbox* texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback>* release_callback);
+
+ private:
+ friend struct mojo::StructTraits<cc::mojom::CopyOutputResultDataView,
+ std::unique_ptr<CopyOutputResult>>;
+
+ CopyOutputResult();
+ explicit CopyOutputResult(std::unique_ptr<SkBitmap> bitmap);
+ explicit CopyOutputResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback);
+
+ gfx::Size size_;
+ std::unique_ptr<SkBitmap> bitmap_;
+ TextureMailbox texture_mailbox_;
+ std::unique_ptr<SingleReleaseCallback> release_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyOutputResult);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
diff --git a/chromium/components/viz/common/quads/release_callback.h b/chromium/components/viz/common/quads/release_callback.h
new file mode 100644
index 00000000000..8166416c16c
--- /dev/null
+++ b/chromium/components/viz/common/quads/release_callback.h
@@ -0,0 +1,21 @@
+// 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_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
+
+#include "base/callback.h"
+
+namespace gpu {
+struct SyncToken;
+} // namespace gpu
+
+namespace viz {
+
+typedef base::Callback<void(const gpu::SyncToken& sync_token, bool is_lost)>
+ ReleaseCallback;
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
diff --git a/chromium/components/viz/common/quads/resource_format.h b/chromium/components/viz/common/quads/resource_format.h
deleted file mode 100644
index 4ae7b0675fb..00000000000
--- a/chromium/components/viz/common/quads/resource_format.h
+++ /dev/null
@@ -1,35 +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_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
-#define COMPONENTS_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
-
-#include "base/logging.h"
-#include "ui/gfx/buffer_types.h"
-
-// TODO(prashant.n): Including third_party/khronos/GLES2/gl2.h causes
-// redefinition errors as macros/functions defined in it conflict with
-// macros/functions defined in ui/gl/gl_bindings.h. (http://crbug.com/512833).
-typedef unsigned int GLenum;
-
-namespace viz {
-
-// Keep in sync with arrays below.
-enum ResourceFormat {
- RGBA_8888,
- RGBA_4444,
- BGRA_8888,
- ALPHA_8,
- LUMINANCE_8,
- RGB_565,
- ETC1,
- RED_8,
- LUMINANCE_F16,
- RGBA_F16,
- RESOURCE_FORMAT_MAX = RGBA_F16,
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
diff --git a/chromium/components/viz/common/quads/shared_quad_state.cc b/chromium/components/viz/common/quads/shared_quad_state.cc
new file mode 100644
index 00000000000..71eed58d78a
--- /dev/null
+++ b/chromium/components/viz/common/quads/shared_quad_state.cc
@@ -0,0 +1,65 @@
+// Copyright 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/viz/common/quads/shared_quad_state.h"
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "cc/base/math_util.h"
+#include "components/viz/common/traced_value.h"
+#include "third_party/skia/include/core/SkBlendMode.h"
+
+namespace viz {
+
+SharedQuadState::SharedQuadState()
+ : is_clipped(false),
+ opacity(0.f),
+ blend_mode(SkBlendMode::kSrcOver),
+ sorting_context_id(0) {}
+
+SharedQuadState::SharedQuadState(const SharedQuadState& other) = default;
+
+SharedQuadState::~SharedQuadState() {
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), "viz::SharedQuadState",
+ this);
+}
+
+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::Rect& clip_rect,
+ bool is_clipped,
+ float opacity,
+ SkBlendMode blend_mode,
+ int sorting_context_id) {
+ 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->clip_rect = clip_rect;
+ this->is_clipped = is_clipped;
+ this->opacity = opacity;
+ this->blend_mode = blend_mode;
+ this->sorting_context_id = sorting_context_id;
+}
+
+void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
+ cc::MathUtil::AddToTracedValue("transform", quad_to_target_transform, value);
+ cc::MathUtil::AddToTracedValue("layer_content_rect", quad_layer_rect, value);
+ cc::MathUtil::AddToTracedValue("layer_visible_content_rect",
+ visible_quad_layer_rect, value);
+
+ value->SetBoolean("is_clipped", is_clipped);
+
+ cc::MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
+
+ value->SetDouble("opacity", opacity);
+ value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
+ TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), value,
+ "viz::SharedQuadState", this);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/shared_quad_state.h b/chromium/components/viz/common/quads/shared_quad_state.h
new file mode 100644
index 00000000000..d1b0a974745
--- /dev/null
+++ b/chromium/components/viz/common/quads/shared_quad_state.h
@@ -0,0 +1,61 @@
+// Copyright 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_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
+
+#include <memory>
+
+#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/transform.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+} // namespace base
+
+namespace viz {
+
+// SharedQuadState holds a set of properties that are common across multiple
+// DrawQuads. It's purely an optimization - the properties behave in exactly the
+// same way as if they were replicated on each DrawQuad. A given SharedQuadState
+// can only be shared by DrawQuads that are adjacent in their RenderPass'
+// QuadList.
+class VIZ_COMMON_EXPORT SharedQuadState {
+ public:
+ SharedQuadState();
+ SharedQuadState(const SharedQuadState& other);
+ ~SharedQuadState();
+
+ void SetAll(const gfx::Transform& quad_to_target_transform,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& visible_layer_rect,
+ const gfx::Rect& clip_rect,
+ bool is_clipped,
+ float opacity,
+ SkBlendMode blend_mode,
+ int sorting_context_id);
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ // Transforms quad rects into the target content space.
+ gfx::Transform quad_to_target_transform;
+ // The rect of the quads' originating layer in the space of the quad rects.
+ gfx::Rect quad_layer_rect;
+ // 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.
+ gfx::Rect clip_rect;
+ bool is_clipped;
+ float opacity;
+ SkBlendMode blend_mode;
+ int sorting_context_id;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
diff --git a/chromium/components/viz/common/quads/single_release_callback.cc b/chromium/components/viz/common/quads/single_release_callback.cc
new file mode 100644
index 00000000000..bd3dca9eb12
--- /dev/null
+++ b/chromium/components/viz/common/quads/single_release_callback.cc
@@ -0,0 +1,29 @@
+// 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/viz/common/quads/single_release_callback.h"
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+
+namespace viz {
+
+SingleReleaseCallback::SingleReleaseCallback(const ReleaseCallback& callback)
+ : callback_(callback) {
+ DCHECK(!callback_.is_null())
+ << "Use a NULL SingleReleaseCallback for an empty callback.";
+}
+
+SingleReleaseCallback::~SingleReleaseCallback() {
+ DCHECK(callback_.is_null()) << "SingleReleaseCallback was never run.";
+}
+
+void SingleReleaseCallback::Run(const gpu::SyncToken& sync_token,
+ bool is_lost) {
+ DCHECK(!callback_.is_null())
+ << "SingleReleaseCallback was run more than once.";
+ base::ResetAndReturn(&callback_).Run(sync_token, is_lost);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/single_release_callback.h b/chromium/components/viz/common/quads/single_release_callback.h
new file mode 100644
index 00000000000..29420f57487
--- /dev/null
+++ b/chromium/components/viz/common/quads/single_release_callback.h
@@ -0,0 +1,35 @@
+// 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_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "components/viz/common/quads/release_callback.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT SingleReleaseCallback {
+ public:
+ static std::unique_ptr<SingleReleaseCallback> Create(
+ const ReleaseCallback& cb) {
+ return base::WrapUnique(new SingleReleaseCallback(cb));
+ }
+
+ ~SingleReleaseCallback();
+
+ void Run(const gpu::SyncToken& sync_token, bool is_lost);
+
+ private:
+ explicit SingleReleaseCallback(const ReleaseCallback& callback);
+
+ ReleaseCallback callback_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
diff --git a/chromium/components/viz/common/resources/DEPS b/chromium/components/viz/common/resources/DEPS
index ce3dad47826..fe456ebd62e 100644
--- a/chromium/components/viz/common/resources/DEPS
+++ b/chromium/components/viz/common/resources/DEPS
@@ -1,6 +1,6 @@
include_rules = [
+ "+gpu/command_buffer/common",
"+gpu/GLES2",
"+third_party/khronos/GLES2",
"+third_party/skia",
- "+ui/gfx",
]
diff --git a/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc b/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
index 83877f4e1fb..4d3e66b9058 100644
--- a/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
+++ b/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
@@ -7,7 +7,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/khronos/GLES2/gl2.h"
namespace viz {
diff --git a/chromium/components/viz/common/resources/platform_color.h b/chromium/components/viz/common/resources/platform_color.h
index 505b6d43269..9c0fa1e66e3 100644
--- a/chromium/components/viz/common/resources/platform_color.h
+++ b/chromium/components/viz/common/resources/platform_color.h
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/resources/resource_format.h"
#include "third_party/skia/include/core/SkTypes.h"
namespace viz {
diff --git a/chromium/components/viz/common/resources/resource_format.h b/chromium/components/viz/common/resources/resource_format.h
new file mode 100644
index 00000000000..1e90781fb63
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_format.h
@@ -0,0 +1,28 @@
+// 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_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
+
+namespace viz {
+
+// If these values are modified, then it is likely that resource_format_utils.cc
+// has to be updated as well.
+enum ResourceFormat {
+ RGBA_8888,
+ RGBA_4444,
+ BGRA_8888,
+ ALPHA_8,
+ LUMINANCE_8,
+ RGB_565,
+ ETC1,
+ RED_8,
+ LUMINANCE_F16,
+ RGBA_F16,
+ RESOURCE_FORMAT_MAX = RGBA_F16,
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index f15ddc72682..4cee8649088 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -4,9 +4,11 @@
#include "components/viz/common/resources/resource_format_utils.h"
+#include "base/logging.h"
+#include "base/macros.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
-#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/buffer_types.h"
namespace viz {
@@ -57,7 +59,7 @@ int BitsPerPixel(ResourceFormat format) {
return 0;
}
-GLenum GLDataType(ResourceFormat format) {
+unsigned int GLDataType(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const GLenum format_gl_data_type[] = {
GL_UNSIGNED_BYTE, // RGBA_8888
@@ -77,7 +79,7 @@ GLenum GLDataType(ResourceFormat format) {
return format_gl_data_type[format];
}
-GLenum GLDataFormat(ResourceFormat format) {
+unsigned int GLDataFormat(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const GLenum format_gl_data_format[] = {
GL_RGBA, // RGBA_8888
@@ -96,13 +98,13 @@ GLenum GLDataFormat(ResourceFormat format) {
return format_gl_data_format[format];
}
-GLenum GLInternalFormat(ResourceFormat format) {
+unsigned int GLInternalFormat(ResourceFormat format) {
// In GLES2, the internal format must match the texture format. (It no longer
// is true in GLES3, however it still holds for the BGRA extension.)
return GLDataFormat(format);
}
-GLenum GLCopyTextureInternalFormat(ResourceFormat format) {
+unsigned int GLCopyTextureInternalFormat(ResourceFormat format) {
// In GLES2, valid formats for glCopyTexImage2D are: GL_ALPHA, GL_LUMINANCE,
// GL_LUMINANCE_ALPHA, GL_RGB, or GL_RGBA.
// Extensions typically used for glTexImage2D do not also work for
@@ -151,6 +153,23 @@ gfx::BufferFormat BufferFormat(ResourceFormat format) {
return gfx::BufferFormat::RGBA_8888;
}
+GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
+ switch (format) {
+ case RGBA_8888:
+ return kRGBA_8888_GrPixelConfig;
+ case BGRA_8888:
+ return kBGRA_8888_GrPixelConfig;
+ case RGBA_4444:
+ return kRGBA_4444_GrPixelConfig;
+ case RGBA_F16:
+ return kRGBA_half_GrPixelConfig;
+ default:
+ break;
+ }
+ DCHECK(false) << "Unsupported resource format.";
+ return kSkia8888_GrPixelConfig;
+}
+
bool IsResourceFormatCompressed(ResourceFormat format) {
return format == ETC1;
}
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index 935ccc8796e..262d5d67a93 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -5,22 +5,35 @@
#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
-#include "components/viz/common/quads/resource_format.h"
-#include "components/viz/common/viz_common_export.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/viz_resource_format_export.h"
#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
+#include "ui/gfx/buffer_types.h"
namespace viz {
-VIZ_COMMON_EXPORT SkColorType
+VIZ_RESOURCE_FORMAT_EXPORT SkColorType
ResourceFormatToClosestSkColorType(ResourceFormat format);
-VIZ_COMMON_EXPORT int BitsPerPixel(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLDataType(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLDataFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLInternalFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLCopyTextureInternalFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT gfx::BufferFormat BufferFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT bool IsResourceFormatCompressed(ResourceFormat format);
-VIZ_COMMON_EXPORT bool DoesResourceFormatSupportAlpha(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT int BitsPerPixel(ResourceFormat format);
+
+// The following functions use unsigned int instead of GLenum, since including
+// third_party/khronos/GLES2/gl2.h causes redefinition errors as
+// macros/functions defined in it conflict with macros/functions defined in
+// ui/gl/gl_bindings.h. See http://crbug.com/512833 for more information.
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataType(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataFormat(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLInternalFormat(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLCopyTextureInternalFormat(
+ ResourceFormat format);
+
+VIZ_RESOURCE_FORMAT_EXPORT gfx::BufferFormat BufferFormat(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT bool IsResourceFormatCompressed(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT bool DoesResourceFormatSupportAlpha(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT GrPixelConfig ToGrPixelConfig(ResourceFormat format);
} // namespace viz
diff --git a/chromium/components/viz/common/resources/resource_id.h b/chromium/components/viz/common/resources/resource_id.h
new file mode 100644
index 00000000000..b7a3a48c1b1
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_id.h
@@ -0,0 +1,19 @@
+// 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_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
+
+#include <stdint.h>
+
+#include "base/containers/flat_set.h"
+
+namespace viz {
+
+using ResourceId = uint32_t;
+using ResourceIdSet = base::flat_set<ResourceId>;
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
diff --git a/chromium/components/viz/common/resources/returned_resource.h b/chromium/components/viz/common/resources/returned_resource.h
new file mode 100644
index 00000000000..6e60a51e72a
--- /dev/null
+++ b/chromium/components/viz/common/resources/returned_resource.h
@@ -0,0 +1,56 @@
+// 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_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
+
+#include <vector>
+
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/command_buffer/common/sync_token.h"
+
+namespace viz {
+
+// A ReturnedResource is a struct passed along to a child compositor from a
+// parent compositor that corresponds to a TransferableResource that was
+// first passed to the parent compositor.
+struct VIZ_COMMON_EXPORT ReturnedResource {
+ ReturnedResource() : id(0), count(0), lost(false) {}
+
+ bool operator==(const ReturnedResource& other) const {
+ return id == other.id && sync_token == other.sync_token &&
+ count == other.count && lost == other.lost;
+ }
+
+ bool operator!=(const ReturnedResource& other) const {
+ return !(*this == other);
+ }
+
+ // |id| is an identifier generated by the child compositor that uniquely
+ // identifies a resource. This is the same ID space as TransferableResource.
+ ResourceId id;
+
+ // A |sync_token| is an identifier for a point in the parent compositor's
+ // command buffer. The child compositor then issues a WaitSyncPointCHROMIUM
+ // command with this |sync_token| as a parameter into its own command buffer.
+ // This ensures that uses of the resource submitted by the parent compositor
+ // are executed before commands submitted by the child.
+ gpu::SyncToken sync_token;
+
+ // |count| is a reference count for this resource. A resource may be used
+ // by mulitple compositor frames submitted to the parent compositor. |count|
+ // is the number of references being returned back to the child compositor.
+ int count;
+
+ // If the resource is lost, then the returner cannot give a sync point for it,
+ // and so it has taken ownership of the resource. The receiver cannot do
+ // anything with the resource except delete it.
+ bool lost;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
diff --git a/chromium/components/viz/common/resources/transferable_resource.cc b/chromium/components/viz/common/resources/transferable_resource.cc
new file mode 100644
index 00000000000..7d44148cf52
--- /dev/null
+++ b/chromium/components/viz/common/resources/transferable_resource.cc
@@ -0,0 +1,48 @@
+// Copyright 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/viz/common/resources/transferable_resource.h"
+#include "components/viz/common/resources/returned_resource.h"
+
+namespace viz {
+
+TransferableResource::TransferableResource()
+ : id(0),
+ format(RGBA_8888),
+ buffer_format(gfx::BufferFormat::RGBA_8888),
+ filter(0),
+ read_lock_fences_enabled(false),
+ is_software(false),
+ shared_bitmap_sequence_number(0),
+#if defined(OS_ANDROID)
+ is_backed_by_surface_texture(false),
+ wants_promotion_hint(false),
+#endif
+ is_overlay_candidate(false) {
+}
+
+TransferableResource::TransferableResource(const TransferableResource& other) =
+ default;
+
+TransferableResource::~TransferableResource() {}
+
+ReturnedResource TransferableResource::ToReturnedResource() const {
+ ReturnedResource returned;
+ returned.id = id;
+ returned.sync_token = mailbox_holder.sync_token;
+ returned.count = 1;
+ return returned;
+}
+
+// static
+std::vector<ReturnedResource> TransferableResource::ReturnResources(
+ const std::vector<TransferableResource>& input) {
+ std::vector<ReturnedResource> out;
+ out.reserve(input.size());
+ for (const auto& r : input)
+ out.push_back(r.ToReturnedResource());
+ return out;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/resources/transferable_resource.h b/chromium/components/viz/common/resources/transferable_resource.h
new file mode 100644
index 00000000000..c85f6917a0d
--- /dev/null
+++ b/chromium/components/viz/common/resources/transferable_resource.h
@@ -0,0 +1,54 @@
+// Copyright 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_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+struct ReturnedResource;
+
+struct VIZ_COMMON_EXPORT TransferableResource {
+ TransferableResource();
+ TransferableResource(const TransferableResource& other);
+ ~TransferableResource();
+
+ ReturnedResource ToReturnedResource() const;
+ static std::vector<ReturnedResource> ReturnResources(
+ const std::vector<TransferableResource>& input);
+
+ ResourceId id;
+ // Refer to ResourceProvider::Resource for the meaning of the following data.
+ ResourceFormat format;
+ gfx::BufferFormat buffer_format;
+ uint32_t filter;
+ gfx::Size size;
+ gpu::MailboxHolder mailbox_holder;
+ bool read_lock_fences_enabled;
+ bool is_software;
+ uint32_t shared_bitmap_sequence_number;
+#if defined(OS_ANDROID)
+ bool is_backed_by_surface_texture;
+ bool wants_promotion_hint;
+#endif
+ bool is_overlay_candidate;
+ gfx::ColorSpace color_space;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
diff --git a/chromium/components/viz/common/surfaces/DEPS b/chromium/components/viz/common/surfaces/DEPS
index 826db9ece7e..16764a92a85 100644
--- a/chromium/components/viz/common/surfaces/DEPS
+++ b/chromium/components/viz/common/surfaces/DEPS
@@ -1,4 +1,3 @@
include_rules = [
"+mojo/public/cpp/bindings",
- "+ui/gfx/geometry",
]
diff --git a/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h b/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
index 93fa9534bf2..c3cbde918b3 100644
--- a/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
+++ b/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
@@ -13,7 +13,7 @@ namespace viz {
// A surface reference factory that uses SurfaceSequence.
class VIZ_COMMON_EXPORT SequenceSurfaceReferenceFactory
- : public NON_EXPORTED_BASE(SurfaceReferenceFactory) {
+ : public SurfaceReferenceFactory {
public:
SequenceSurfaceReferenceFactory() = default;
diff --git a/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc
new file mode 100644
index 00000000000..e5d2ce50a92
--- /dev/null
+++ b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc
@@ -0,0 +1,17 @@
+// 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/viz/common/surfaces/stub_surface_reference_factory.h"
+
+#include "base/callback.h"
+
+namespace viz {
+
+base::Closure StubSurfaceReferenceFactory::CreateReference(
+ SurfaceReferenceOwner* owner,
+ const SurfaceId& surface_id) const {
+ return base::Closure();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h
new file mode 100644
index 00000000000..156809c777c
--- /dev/null
+++ b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h
@@ -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.
+
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
+
+#include "base/compiler_specific.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+// A stub implementation that creates a closure which does nothing.
+// TODO(kylechar): Delete this class and all usage of
+// SurfaceReferenceFactory when surface references are enabled by default.
+class VIZ_COMMON_EXPORT StubSurfaceReferenceFactory
+ : public SurfaceReferenceFactory {
+ public:
+ StubSurfaceReferenceFactory() = default;
+
+ // SurfaceReferenceFactory:
+ base::Closure CreateReference(SurfaceReferenceOwner* owner,
+ const SurfaceId& surface_id) const override;
+
+ protected:
+ ~StubSurfaceReferenceFactory() override = default;
+
+ DISALLOW_COPY_AND_ASSIGN(StubSurfaceReferenceFactory);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
diff --git a/chromium/components/viz/common/surfaces/surface_id.h b/chromium/components/viz/common/surfaces/surface_id.h
index b008abaf288..dda288c13f2 100644
--- a/chromium/components/viz/common/surfaces/surface_id.h
+++ b/chromium/components/viz/common/surfaces/surface_id.h
@@ -17,13 +17,11 @@
#include "components/viz/common/viz_common_export.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
-namespace cc {
+namespace viz {
+
namespace mojom {
class SurfaceIdDataView;
}
-} // namespace cc
-
-namespace viz {
class VIZ_COMMON_EXPORT SurfaceId {
public:
@@ -70,7 +68,7 @@ class VIZ_COMMON_EXPORT SurfaceId {
}
private:
- friend struct mojo::StructTraits<cc::mojom::SurfaceIdDataView, SurfaceId>;
+ friend struct mojo::StructTraits<mojom::SurfaceIdDataView, SurfaceId>;
FrameSinkId frame_sink_id_;
LocalSurfaceId local_surface_id_;
diff --git a/chromium/components/viz/common/surfaces/surface_info.h b/chromium/components/viz/common/surfaces/surface_info.h
index 1e21fda57d8..b40092bcb4c 100644
--- a/chromium/components/viz/common/surfaces/surface_info.h
+++ b/chromium/components/viz/common/surfaces/surface_info.h
@@ -13,13 +13,11 @@ template <class T>
struct ParamTraits;
} // namespace IPC
-namespace cc {
+namespace viz {
+
namespace mojom {
class SurfaceInfoDataView;
-}
-} // namespace cc
-
-namespace viz {
+} // namespace mojom
// This class contains information about the surface that is being embedded.
class SurfaceInfo {
@@ -50,7 +48,7 @@ class SurfaceInfo {
const gfx::Size& size_in_pixels() const { return size_in_pixels_; }
private:
- friend struct mojo::StructTraits<cc::mojom::SurfaceInfoDataView, SurfaceInfo>;
+ friend struct mojo::StructTraits<mojom::SurfaceInfoDataView, SurfaceInfo>;
friend struct IPC::ParamTraits<SurfaceInfo>;
SurfaceId id_;
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
new file mode 100644
index 00000000000..ee13e20ad7f
--- /dev/null
+++ b/chromium/components/viz/common/switches.cc
@@ -0,0 +1,18 @@
+// 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/viz/common/switches.h"
+
+namespace switches {
+
+// Disable surface lifetime management using surface references. This enables
+// adding surface sequences and disables adding temporary references.
+const char kDisableSurfaceReferences[] = "disable-surface-references";
+
+// Enables multi-client Surface synchronization. In practice, this indicates
+// that LayerTreeHost expects to be given a valid viz::LocalSurfaceId provided
+// by the parent compositor.
+const char kEnableSurfaceSynchronization[] = "enable-surface-synchronization";
+
+} // namespace switches
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
new file mode 100644
index 00000000000..69bd3077588
--- /dev/null
+++ b/chromium/components/viz/common/switches.h
@@ -0,0 +1,18 @@
+// 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_VIZ_COMMON_SWITCHES_H_
+#define COMPONENTS_VIZ_COMMON_SWITCHES_H_
+
+#include "components/viz/common/viz_common_export.h"
+
+namespace switches {
+
+// Keep list in alphabetical order.
+VIZ_COMMON_EXPORT extern const char kDisableSurfaceReferences[];
+VIZ_COMMON_EXPORT extern const char kEnableSurfaceSynchronization[];
+
+} // namespace switches
+
+#endif // COMPONENTS_VIZ_COMMON_SWITCHES_H_
diff --git a/chromium/components/viz/common/traced_value.cc b/chromium/components/viz/common/traced_value.cc
new file mode 100644
index 00000000000..b3a23c2f16d
--- /dev/null
+++ b/chromium/components/viz/common/traced_value.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 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/viz/common/traced_value.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace viz {
+
+void TracedValue::AppendIDRef(const void* id,
+ base::trace_event::TracedValue* state) {
+ state->BeginDictionary();
+ state->SetString("id_ref", base::StringPrintf("%p", id));
+ state->EndDictionary();
+}
+
+void TracedValue::SetIDRef(const void* id,
+ base::trace_event::TracedValue* state,
+ const char* name) {
+ state->BeginDictionary(name);
+ state->SetString("id_ref", base::StringPrintf("%p", id));
+ state->EndDictionary();
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshot(
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("id", base::StringPrintf("%s/%p", object_name, id));
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("cat", category);
+ MakeDictIntoImplicitSnapshot(dict, object_name, id);
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("cat", category);
+ dict->SetString("base_type", object_base_type_name);
+ MakeDictIntoImplicitSnapshot(dict, object_name, id);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/traced_value.h b/chromium/components/viz/common/traced_value.h
new file mode 100644
index 00000000000..2f2d144aa5d
--- /dev/null
+++ b/chromium/components/viz/common/traced_value.h
@@ -0,0 +1,43 @@
+// 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_VIZ_COMMON_TRACED_VALUE_H_
+#define COMPONENTS_VIZ_COMMON_TRACED_VALUE_H_
+
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+} // namespace base
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT TracedValue {
+ public:
+ static void AppendIDRef(const void* id,
+ base::trace_event::TracedValue* array);
+ static void SetIDRef(const void* id,
+ base::trace_event::TracedValue* dict,
+ const char* name);
+ static void MakeDictIntoImplicitSnapshot(base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id);
+ static void MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id);
+ static void MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_TRACED_VALUE_H_
diff --git a/chromium/components/viz/common/viz_resource_format_export.h b/chromium/components/viz/common/viz_resource_format_export.h
new file mode 100644
index 00000000000..549ac8c357f
--- /dev/null
+++ b/chromium/components/viz/common/viz_resource_format_export.h
@@ -0,0 +1,29 @@
+// 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_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_
+#define COMPONENTS_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+#define VIZ_RESOURCE_FORMAT_EXPORT __declspec(dllexport)
+#else
+#define VIZ_RESOURCE_FORMAT_EXPORT __declspec(dllimport)
+#endif // defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+#define VIZ_RESOURCE_FORMAT_EXPORT __attribute__((visibility("default")))
+#else
+#define VIZ_RESOURCE_FORMAT_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define VIZ_RESOURCE_FORMAT_EXPORT
+#endif
+
+#endif // COMPONENTS_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_
diff --git a/chromium/components/viz/host/BUILD.gn b/chromium/components/viz/host/BUILD.gn
index e5d833ecb92..ecc77423a9d 100644
--- a/chromium/components/viz/host/BUILD.gn
+++ b/chromium/components/viz/host/BUILD.gn
@@ -8,9 +8,13 @@ viz_component("host") {
defines = [ "VIZ_HOST_IMPLEMENTATION" ]
sources = [
- "frame_sink_observer.h",
+ "hit_test/hit_test_query.cc",
+ "hit_test/hit_test_query.h",
+ "host_frame_sink_client.h",
"host_frame_sink_manager.cc",
"host_frame_sink_manager.h",
+ "renderer_settings_creation.cc",
+ "renderer_settings_creation.h",
"server_gpu_memory_buffer_manager.cc",
"server_gpu_memory_buffer_manager.h",
"viz_host_export.h",
@@ -19,10 +23,12 @@ viz_component("host") {
deps = [
"//base",
"//cc/ipc:interfaces",
- "//cc/surfaces",
+ "//components/viz/common",
"//gpu/ipc/client",
"//gpu/ipc/common",
"//services/ui/gpu/interfaces",
+ "//ui/base",
+ "//ui/gfx",
# TODO(kylechar): This is temporary and will be removed when all host to
# service communication is over Mojo.
@@ -32,6 +38,9 @@ viz_component("host") {
public_deps = [
"//gpu/command_buffer/client",
"//gpu/ipc/host",
+ "//services/viz/privileged/interfaces/compositing",
+ "//services/viz/public/interfaces",
+ "//ui/gfx/geometry",
]
}
@@ -39,6 +48,7 @@ viz_source_set("unit_tests") {
testonly = true
sources = [
+ "hit_test/hit_test_query_unittest.cc",
"host_frame_sink_manager_unittests.cc",
"server_gpu_memory_buffer_manager_unittest.cc",
]
@@ -48,10 +58,10 @@ viz_source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//cc/ipc:interfaces",
- "//cc/surfaces",
"//gpu/ipc/host",
"//mojo/public/cpp/bindings",
"//services/ui/gpu/interfaces",
+ "//services/viz/public/interfaces",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/viz/host/DEPS b/chromium/components/viz/host/DEPS
index b6198f4bd8b..9093d0e1161 100644
--- a/chromium/components/viz/host/DEPS
+++ b/chromium/components/viz/host/DEPS
@@ -1,23 +1,23 @@
include_rules = [
"+cc/ipc",
- "+cc/surfaces",
+ "-components/viz/common/switches.h",
"+components/viz/host",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
"+gpu/ipc/client",
"+gpu/ipc/common",
"+gpu/ipc/host",
- "+mojo/public/cpp/bindings",
- "+services/ui/gpu/interfaces",
- "+ui/gfx",
+ "+mojo/public/cpp",
+ "+services/viz/privileged/interfaces",
+ "+services/viz/public/interfaces",
]
specific_include_rules = {
- "host_frame_sink_manager.*": [
+ "host_frame_sink_manager*": [
"+components/viz/service/frame_sinks/compositor_frame_sink_support.h",
"+components/viz/service/frame_sinks/compositor_frame_sink_support_client.h",
- "+components/viz/service/frame_sinks/frame_sink_manager.h",
- "+components/viz/service/frame_sinks/frame_sink_manager_impl.h",
"+components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h",
+ "+components/viz/service/frame_sinks/frame_sink_manager_impl.h",
+ "+components/viz/service/surfaces/surface_manager.h",
]
}
diff --git a/chromium/components/viz/host/OWNERS b/chromium/components/viz/host/OWNERS
deleted file mode 100644
index c795b67cbd8..00000000000
--- a/chromium/components/viz/host/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-kylechar@chromium.org \ No newline at end of file
diff --git a/chromium/components/viz/host/frame_sink_observer.h b/chromium/components/viz/host/frame_sink_observer.h
deleted file mode 100644
index eaa0acff3cf..00000000000
--- a/chromium/components/viz/host/frame_sink_observer.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
-#define COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
-
-namespace cc {
-class SurfaceInfo;
-}
-
-namespace viz {
-
-class FrameSinkObserver {
- public:
- // Runs when a CompositorFrame is received for the given SurfaceInfo for the
- // first time.
- virtual void OnSurfaceCreated(const SurfaceInfo& surface_info) = 0;
-
- protected:
- ~FrameSinkObserver() {}
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
diff --git a/chromium/components/viz/host/hit_test/DEPS b/chromium/components/viz/host/hit_test/DEPS
new file mode 100644
index 00000000000..d4886fc180f
--- /dev/null
+++ b/chromium/components/viz/host/hit_test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+services/viz/public/interfaces",
+]
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.cc b/chromium/components/viz/host/hit_test/hit_test_query.cc
new file mode 100644
index 00000000000..2faf20cf2b1
--- /dev/null
+++ b/chromium/components/viz/host/hit_test/hit_test_query.cc
@@ -0,0 +1,95 @@
+// 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/viz/host/hit_test/hit_test_query.h"
+
+#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
+
+namespace viz {
+
+HitTestQuery::HitTestQuery() = default;
+
+HitTestQuery::~HitTestQuery() = default;
+
+void HitTestQuery::OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
+ DCHECK(active_handle.is_valid() && idle_handle.is_valid());
+ handle_buffer_sizes_[0] = active_handle_size;
+ handle_buffers_[0] = active_handle->Map(handle_buffer_sizes_[0] *
+ sizeof(AggregatedHitTestRegion));
+ handle_buffer_sizes_[1] = idle_handle_size;
+ handle_buffers_[1] = idle_handle->Map(handle_buffer_sizes_[1] *
+ sizeof(AggregatedHitTestRegion));
+ if (!handle_buffers_[0] || !handle_buffers_[1]) {
+ // TODO(riajiang): Report security fault. http://crbug.com/746470
+ NOTREACHED();
+ return;
+ }
+ SwitchActiveAggregatedHitTestRegionList(0);
+}
+
+void HitTestQuery::SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) {
+ DCHECK(active_handle_index == 0u || active_handle_index == 1u);
+ active_hit_test_list_ = static_cast<AggregatedHitTestRegion*>(
+ handle_buffers_[active_handle_index].get());
+ active_hit_test_list_size_ = handle_buffer_sizes_[active_handle_index];
+}
+
+Target HitTestQuery::FindTargetForLocation(
+ const gfx::Point& location_in_root) const {
+ Target target;
+ if (!active_hit_test_list_size_)
+ return target;
+
+ FindTargetInRegionForLocation(location_in_root, active_hit_test_list_,
+ &target);
+ return target;
+}
+
+bool HitTestQuery::FindTargetInRegionForLocation(
+ const gfx::Point& location_in_parent,
+ AggregatedHitTestRegion* region,
+ Target* target) const {
+ gfx::Point location_transformed(location_in_parent);
+ region->transform.TransformPoint(&location_transformed);
+ if (!region->rect.Contains(location_transformed))
+ return false;
+
+ if (region->child_count < 0 ||
+ region->child_count >
+ (active_hit_test_list_ + active_hit_test_list_size_ - region - 1)) {
+ return false;
+ }
+ AggregatedHitTestRegion* child_region = region + 1;
+ AggregatedHitTestRegion* child_region_end =
+ child_region + region->child_count;
+ gfx::Point location_in_target(location_transformed);
+ location_in_target.Offset(-region->rect.x(), -region->rect.y());
+ while (child_region < child_region_end) {
+ if (FindTargetInRegionForLocation(location_in_target, child_region,
+ target)) {
+ return true;
+ }
+
+ if (child_region->child_count < 0 ||
+ child_region->child_count >= region->child_count) {
+ return false;
+ }
+ child_region = child_region + child_region->child_count + 1;
+ }
+
+ if (region->flags & mojom::kHitTestMine) {
+ target->frame_sink_id = region->frame_sink_id;
+ target->location_in_target = location_in_target;
+ target->flags = region->flags;
+ return true;
+ }
+ return false;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.h b/chromium/components/viz/host/hit_test/hit_test_query.h
new file mode 100644
index 00000000000..a99f7457a43
--- /dev/null
+++ b/chromium/components/viz/host/hit_test/hit_test_query.h
@@ -0,0 +1,95 @@
+// 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_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
+#define COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "components/viz/host/viz_host_export.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace viz {
+
+struct Target {
+ FrameSinkId frame_sink_id;
+ // Coordinates in the coordinate system of the target FrameSinkId.
+ gfx::Point location_in_target;
+ // Different flags are defined in services/viz/public/interfaces/hit_test/
+ // hit_test_region_list.mojom.
+ uint32_t flags = 0;
+};
+
+// Finds the target for a given location based on the AggregatedHitTestRegion
+// list aggregated by HitTestAggregator.
+// TODO(riajiang): Handle 3d space cases correctly.
+class VIZ_HOST_EXPORT HitTestQuery {
+ public:
+ HitTestQuery();
+ ~HitTestQuery();
+
+ // TODO(riajiang): Need to validate the data received.
+ // http://crbug.com/746470
+ // HitTestAggregator should only send new active_handle and idle_handle when
+ // they are initialized or replaced with OnAggregatedHitTestRegionListUpdated.
+ // Both handles must be valid. HitTestQuery would store and update these two
+ // handles received.
+ // HitTestAggregator would tell HitTestQuery to update its active hit test
+ // list based on |active_handle_index| with
+ // SwitchActiveAggregatedHitTestRegionList if HitTestAggregator only swapped
+ // handles.
+ void OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size);
+ void SwitchActiveAggregatedHitTestRegionList(uint8_t active_handle_index);
+
+ // Finds Target for |location_in_root|, including the FrameSinkId of the
+ // target, updated location in the coordinate system of the target and
+ // hit-test flags for the target.
+ // Assumptions about the AggregatedHitTestRegion list received.
+ // 1. The list is in ascending (front to back) z-order.
+ // 2. Children count includes children of children.
+ // 3. After applying transform to the incoming point, point is in the same
+ // coordinate system as the bounds it is comparing against.
+ // For example,
+ // +e-------------+
+ // | +c---------|
+ // | 1 |+a--+ |
+ // | || 2 | |
+ // | |+b--------|
+ // | || |
+ // | || 3 |
+ // +--------------+
+ // In this case, after applying identity transform, 1 is in the coordinate
+ // system of e; apply the transfrom-from-e-to-c and transform-from-c-to-a
+ // then we get 2 in the coordinate system of a; apply the
+ // transfrom-from-e-to-c and transform-from-c-to-b then we get 3 in the
+ // coordinate system of b.
+ Target FindTargetForLocation(const gfx::Point& location_in_root) const;
+
+ private:
+ // Helper function to find |target| for |location_in_parent| in the |region|,
+ // returns true if a target is found and false otherwise. |location_in_parent|
+ // is in the coordinate space of |region|'s parent.
+ bool FindTargetInRegionForLocation(const gfx::Point& location_in_parent,
+ AggregatedHitTestRegion* region,
+ Target* target) const;
+
+ uint32_t handle_buffer_sizes_[2];
+ mojo::ScopedSharedBufferMapping handle_buffers_[2];
+
+ AggregatedHitTestRegion* active_hit_test_list_ = nullptr;
+ uint32_t active_hit_test_list_size_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestQuery);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
diff --git a/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc b/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc
new file mode 100644
index 00000000000..7b1101aee69
--- /dev/null
+++ b/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc
@@ -0,0 +1,668 @@
+// 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/viz/host/hit_test/hit_test_query.h"
+
+#include <cstdint>
+
+#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace test {
+
+class HitTestQueryTest : public testing::Test {
+ public:
+ HitTestQueryTest() = default;
+ ~HitTestQueryTest() override = default;
+
+ protected:
+ HitTestQuery& hit_test_query() { return hit_test_query_; }
+ AggregatedHitTestRegion* aggregated_hit_test_region() {
+ return static_cast<AggregatedHitTestRegion*>(active_buffer_.get());
+ }
+
+ private:
+ // testing::Test:
+ void SetUp() override {
+ uint32_t handle_size = 100;
+ size_t num_bytes = handle_size * sizeof(AggregatedHitTestRegion);
+ mojo::ScopedSharedBufferHandle active_handle =
+ mojo::SharedBufferHandle::Create(num_bytes);
+ mojo::ScopedSharedBufferHandle idle_handle =
+ mojo::SharedBufferHandle::Create(num_bytes);
+ active_buffer_ = active_handle->Map(num_bytes);
+ hit_test_query_.OnAggregatedHitTestRegionListUpdated(
+ std::move(active_handle), handle_size, std::move(idle_handle),
+ handle_size);
+ }
+ void TearDown() override {}
+
+ HitTestQuery hit_test_query_;
+ mojo::ScopedSharedBufferMapping active_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestQueryTest);
+};
+
+// One surface.
+//
+// +e---------+
+// | |
+// | |
+// | |
+// +----------+
+//
+TEST_F(HitTestQueryTest, OneSurface) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ gfx::Rect e_bounds = gfx::Rect(0, 0, 600, 600);
+ gfx::Transform transform_e_to_e;
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds, transform_e_to_e, 0); // e
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(600, 600);
+ gfx::Point point3(0, 0);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ // point2 is on the bounds of e so no target found.
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target2.location_in_target, gfx::Point());
+ EXPECT_FALSE(target2.flags);
+
+ // There's a valid Target for point3, see Rect::Contains.
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, e_id);
+ EXPECT_EQ(target3.location_in_target, point3);
+ EXPECT_EQ(target3.flags, mojom::kHitTestMine);
+}
+
+// One embedder with two children.
+//
+// +e------------+ Point maps to
+// | +c1-+ +c2---| ----- -------
+// |1| | | | 1 e
+// | | 2 | | 3 | 4 2 c1
+// | +---+ | | 3 c2
+// +-------------+ 4 none
+//
+TEST_F(HitTestQueryTest, OneEmbedderTwoChildren) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId c2_id = FrameSinkId(3, 3);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 400, 400);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_e_to_c2.Translate(-300, -300);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 2); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c1_id, mojom::kHitTestMine, c1_bounds_in_e, transform_e_to_c1, 0); // c1
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ c2_id, mojom::kHitTestMine, c2_bounds_in_e, transform_e_to_c2, 0); // c2
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(400, 400);
+ gfx::Point point4(650, 350);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, c1_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(50, 50));
+ EXPECT_EQ(target2.flags, mojom::kHitTestMine);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, c2_id);
+ EXPECT_EQ(target3.location_in_target, gfx::Point(100, 100));
+ EXPECT_EQ(target3.flags, mojom::kHitTestMine);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target4.location_in_target, gfx::Point());
+ EXPECT_FALSE(target4.flags);
+}
+
+// One embedder with a rotated child.
+TEST_F(HitTestQueryTest, OneEmbedderRotatedChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Transform transform_e_to_e, transform_e_to_c;
+ transform_e_to_c.Translate(-100, -100);
+ transform_e_to_c.Skew(2, 3);
+ transform_e_to_c.Scale(.5f, .7f);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 1); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c_bounds_in_e,
+ transform_e_to_c, 0); // c
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(150, 120); // Point(-22, -12) after transform.
+ gfx::Point point2(550, 400); // Point(185, 194) after transform.
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, c_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(185, 194));
+ EXPECT_EQ(target2.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+}
+
+// One embedder with a clipped child with a tab and transparent background.
+//
+// +e-------------+
+// | +c---------| Point maps to
+// | 1 |+a--+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b--------| 2 a
+// | || | 3 e ( transparent area in c )
+// | || 4 | 4 b
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildWithTabAndTransparentBackground) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2); // c
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0); // a
+ aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0); // b
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(403, 103);
+ gfx::Point point4(202, 202);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, a_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target2.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, e_id);
+ EXPECT_EQ(target3.location_in_target, point3);
+ EXPECT_EQ(target3.flags, mojom::kHitTestMine);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, b_id);
+ EXPECT_EQ(target4.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target4.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+}
+
+// One embedder with a clipped child with a tab and transparent background, and
+// a child d under that.
+//
+// +e-------------+
+// | +d------|
+// | +c-|-------| Point maps to
+// | 1 |+a|-+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b|-------| 2 a
+// | || | | 3 d
+// | || | 4 | 4 b
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildWithChildUnderneath) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId d_id = FrameSinkId(5, 5);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Rect d_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b, transform_e_to_d;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ transform_e_to_d.Translate(-400, -50);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 4); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2); // c
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0); // a
+ aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0); // b
+ aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
+ d_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, d_bounds_in_e,
+ transform_e_to_d, 0); // d
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(450, 150);
+ gfx::Point point4(202, 202);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, a_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target2.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, d_id);
+ EXPECT_EQ(target3.location_in_target, gfx::Point(50, 100));
+ EXPECT_EQ(target3.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, b_id);
+ EXPECT_EQ(target4.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target4.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+}
+
+// One embedder with two clipped children with a tab and transparent background.
+//
+// +e-------------+
+// | +c1--------| Point maps to
+// | 1 |+a--+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b--------| 2 a
+// | || | 3 e ( transparent area in c1 )
+// | || 4 | 4 b
+// | +----------| 5 g
+// | +c2--------| 6 e ( transparent area in c2 )
+// | |+g--+ | 7 h
+// | || 5 | 6 |
+// | |+h--------|
+// | || |
+// | || 7 |
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildrenWithTabAndTransparentBackground) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId c2_id = FrameSinkId(5, 5);
+ FrameSinkId g_id = FrameSinkId(6, 6);
+ FrameSinkId h_id = FrameSinkId(7, 7);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 1200);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 500);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c1 = gfx::Rect(0, 0, 800, 400);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 500);
+ gfx::Rect g_bounds_in_c2 = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect h_bounds_in_c2 = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_c1_to_b, transform_e_to_c2, transform_c2_to_g,
+ transform_c2_to_h;
+ transform_e_to_c1.Translate(-200, -100);
+ transform_c1_to_b.Translate(0, -100);
+ transform_e_to_c2.Translate(-200, -700);
+ transform_c2_to_h.Translate(0, -100);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 6); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 2); // c1
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c1,
+ transform_c1_to_a, 0); // a
+ aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c1,
+ transform_c1_to_b, 0); // b
+ aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
+ c2_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c2_bounds_in_e, transform_e_to_c2, 2); // c2
+ aggregated_hit_test_region_list[5] = AggregatedHitTestRegion(
+ g_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, g_bounds_in_c2,
+ transform_c2_to_g, 0); // g
+ aggregated_hit_test_region_list[6] = AggregatedHitTestRegion(
+ h_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, h_bounds_in_c2,
+ transform_c2_to_h, 0); // h
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(403, 103);
+ gfx::Point point4(202, 202);
+ gfx::Point point5(250, 750);
+ gfx::Point point6(450, 750);
+ gfx::Point point7(350, 1100);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, a_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target2.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, e_id);
+ EXPECT_EQ(target3.location_in_target, point3);
+ EXPECT_EQ(target3.flags, mojom::kHitTestMine);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, b_id);
+ EXPECT_EQ(target4.location_in_target, gfx::Point(2, 2));
+ EXPECT_EQ(target4.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target5 = hit_test_query().FindTargetForLocation(point5);
+ EXPECT_EQ(target5.frame_sink_id, g_id);
+ EXPECT_EQ(target5.location_in_target, gfx::Point(50, 50));
+ EXPECT_EQ(target5.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target6 = hit_test_query().FindTargetForLocation(point6);
+ EXPECT_EQ(target6.frame_sink_id, e_id);
+ EXPECT_EQ(target6.location_in_target, point6);
+ EXPECT_EQ(target6.flags, mojom::kHitTestMine);
+
+ Target target7 = hit_test_query().FindTargetForLocation(point7);
+ EXPECT_EQ(target7.frame_sink_id, h_id);
+ EXPECT_EQ(target7.location_in_target, gfx::Point(150, 300));
+ EXPECT_EQ(target7.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+}
+
+// Children that are multiple layers deep.
+//
+// +e--------------------+
+// | +c2--------| Point maps to
+// | +c1------|----+ | ----- -------
+// |1| +a-----|---+| | 1 e
+// | | |+b----|--+|| | 2 g
+// | | ||+g--+| ||| | 3 b
+// | | ||| 2 || 3||| 4 | 4 c2
+// | | ||+---+| ||| |
+// | | |+-----|--+|| |
+// | | +------| --+| |
+// | +--------|----+ |
+// +---------------------+
+//
+TEST_F(HitTestQueryTest, MultipleLayerChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId g_id = FrameSinkId(5, 5);
+ FrameSinkId c2_id = FrameSinkId(6, 6);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 700, 700);
+ gfx::Rect b_bounds_in_a = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect g_bounds_in_b = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_a_to_b, transform_b_to_g, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_a_to_b.Translate(-50, -30);
+ transform_b_to_g.Translate(-150, -200);
+ transform_e_to_c2.Translate(-400, -50);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 5), // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3); // c1
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c1,
+ transform_c1_to_a, 2); // a
+ aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_a,
+ transform_a_to_b, 1); // b
+ aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
+ g_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, g_bounds_in_b,
+ transform_b_to_g, 0); // g
+ aggregated_hit_test_region_list[5] = AggregatedHitTestRegion(
+ c2_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c2_bounds_in_e,
+ transform_e_to_c2, 0); // c2
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(300, 350);
+ gfx::Point point3(550, 350);
+ gfx::Point point4(900, 350);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_EQ(target1.flags, mojom::kHitTestMine);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, g_id);
+ EXPECT_EQ(target2.location_in_target, gfx::Point(0, 20));
+ EXPECT_EQ(target2.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, b_id);
+ EXPECT_EQ(target3.location_in_target, gfx::Point(400, 220));
+ EXPECT_EQ(target3.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, c2_id);
+ EXPECT_EQ(target4.location_in_target, gfx::Point(500, 300));
+ EXPECT_EQ(target4.flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+}
+
+// Multiple layers deep of transparent children.
+//
+// +e--------------------+
+// | +c2--------| Point maps to
+// | +c1------|----+ | ----- -------
+// |1| +a-----|---+| | 1 e
+// | | |+b----|--+|| | 2 e
+// | | ||+g--+| ||| | 3 c2
+// | | ||| 2 || 3||| 4 | 4 c2
+// | | ||+---+| ||| |
+// | | |+-----|--+|| |
+// | | +------| --+| |
+// | +--------|----+ |
+// +---------------------+
+//
+TEST_F(HitTestQueryTest, MultipleLayerTransparentChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId g_id = FrameSinkId(5, 5);
+ FrameSinkId c2_id = FrameSinkId(6, 6);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 700, 700);
+ gfx::Rect b_bounds_in_a = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect g_bounds_in_b = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_a_to_b, transform_b_to_g, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_a_to_b.Translate(-50, -30);
+ transform_b_to_g.Translate(-150, -200);
+ transform_e_to_c2.Translate(-400, -50);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 5); // e
+ aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
+ c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3); // c1
+ aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, a_bounds_in_c1,
+ transform_c1_to_a, 2); // a
+ aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, b_bounds_in_a,
+ transform_a_to_b, 1); // b
+ aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
+ g_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, g_bounds_in_b,
+ transform_b_to_g, 0); // g
+ aggregated_hit_test_region_list[5] = AggregatedHitTestRegion(
+ c2_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c2_bounds_in_e,
+ transform_e_to_c2, 0); // c2
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(300, 350);
+ gfx::Point point3(450, 350);
+ gfx::Point point4(900, 350);
+
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, e_id);
+ EXPECT_EQ(target1.location_in_target, point1);
+ EXPECT_TRUE(target1.flags);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, e_id);
+ EXPECT_EQ(target2.location_in_target, point2);
+ EXPECT_TRUE(target2.flags);
+
+ Target target3 = hit_test_query().FindTargetForLocation(point3);
+ EXPECT_EQ(target3.frame_sink_id, c2_id);
+ EXPECT_EQ(target3.location_in_target, gfx::Point(50, 300));
+ EXPECT_TRUE(target3.flags);
+
+ Target target4 = hit_test_query().FindTargetForLocation(point4);
+ EXPECT_EQ(target4.frame_sink_id, c2_id);
+ EXPECT_EQ(target4.location_in_target, gfx::Point(500, 300));
+ EXPECT_TRUE(target4.flags);
+}
+
+TEST_F(HitTestQueryTest, InvalidAggregatedHitTestRegionData) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ AggregatedHitTestRegion* aggregated_hit_test_region_list_min =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list_min[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3); // e
+ aggregated_hit_test_region_list_min[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, INT32_MIN); // c
+ aggregated_hit_test_region_list_min[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0); // a
+ aggregated_hit_test_region_list_min[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0); // b
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+
+ // |child_count| is invalid, which is a security fault. For now, check to see
+ // if the returned Target is invalid.
+ Target target1 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target1.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target1.location_in_target, gfx::Point());
+ EXPECT_FALSE(target1.flags);
+
+ Target target2 = hit_test_query().FindTargetForLocation(point2);
+ EXPECT_EQ(target2.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target2.location_in_target, gfx::Point());
+ EXPECT_FALSE(target2.flags);
+
+ AggregatedHitTestRegion* aggregated_hit_test_region_list_max =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list_max[0] =
+ AggregatedHitTestRegion(e_id, mojom::kHitTestMine, e_bounds_in_e,
+ transform_e_to_e, INT32_MAX); // e
+ aggregated_hit_test_region_list_max[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2); // c
+ aggregated_hit_test_region_list_max[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0); // a
+ aggregated_hit_test_region_list_max[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0); // b
+
+ Target target3 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target3.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target3.location_in_target, gfx::Point());
+ EXPECT_FALSE(target3.flags);
+
+ AggregatedHitTestRegion* aggregated_hit_test_region_list_bigger =
+ aggregated_hit_test_region();
+ aggregated_hit_test_region_list_bigger[0] = AggregatedHitTestRegion(
+ e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3); // e
+ aggregated_hit_test_region_list_bigger[1] = AggregatedHitTestRegion(
+ c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 3); // c
+ aggregated_hit_test_region_list_bigger[2] = AggregatedHitTestRegion(
+ a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0); // a
+ aggregated_hit_test_region_list_bigger[3] = AggregatedHitTestRegion(
+ b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0); // b
+
+ Target target4 = hit_test_query().FindTargetForLocation(point1);
+ EXPECT_EQ(target4.frame_sink_id, FrameSinkId());
+ EXPECT_EQ(target4.location_in_target, gfx::Point());
+ EXPECT_FALSE(target4.flags);
+}
+
+} // namespace test
+} // namespace viz
diff --git a/chromium/components/viz/host/host_frame_sink_client.h b/chromium/components/viz/host/host_frame_sink_client.h
new file mode 100644
index 00000000000..d02f6617842
--- /dev/null
+++ b/chromium/components/viz/host/host_frame_sink_client.h
@@ -0,0 +1,24 @@
+// 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_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
+#define COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
+
+namespace viz {
+
+class SurfaceInfo;
+
+class HostFrameSinkClient {
+ public:
+ // Called when a CompositorFrame with a new SurfaceId activates for the first
+ // time.
+ virtual void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) = 0;
+
+ protected:
+ virtual ~HostFrameSinkClient() {}
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
diff --git a/chromium/components/viz/host/host_frame_sink_manager.cc b/chromium/components/viz/host/host_frame_sink_manager.cc
index 48ad64c117b..943ba996d9d 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/sequenced_task_runner.h"
+#include "base/stl_util.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
@@ -28,9 +29,9 @@ void HostFrameSinkManager::SetLocalManager(
}
void HostFrameSinkManager::BindAndSetManager(
- cc::mojom::FrameSinkManagerClientRequest request,
+ mojom::FrameSinkManagerClientRequest request,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- cc::mojom::FrameSinkManagerPtr ptr) {
+ mojom::FrameSinkManagerPtr ptr) {
DCHECK(!frame_sink_manager_impl_);
DCHECK(!binding_.is_bound());
@@ -40,67 +41,117 @@ void HostFrameSinkManager::BindAndSetManager(
frame_sink_manager_ = frame_sink_manager_ptr_.get();
}
-void HostFrameSinkManager::AddObserver(FrameSinkObserver* observer) {
- observers_.AddObserver(observer);
+void HostFrameSinkManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id,
+ HostFrameSinkClient* client) {
+ DCHECK(frame_sink_id.is_valid());
+ DCHECK(client);
+
+ FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+ DCHECK(!data.IsFrameSinkRegistered());
+ DCHECK(!data.HasCompositorFrameSinkData());
+ data.client = client;
+ frame_sink_manager_->RegisterFrameSinkId(frame_sink_id);
}
-void HostFrameSinkManager::RemoveObserver(FrameSinkObserver* observer) {
- observers_.RemoveObserver(observer);
+void HostFrameSinkManager::InvalidateFrameSinkId(
+ const FrameSinkId& frame_sink_id) {
+ DCHECK(frame_sink_id.is_valid());
+
+ FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+ DCHECK(data.IsFrameSinkRegistered());
+
+ // This will destroy |frame_sink_id| if using mojom::CompositorFrameSink.
+ frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id);
+ data.has_created_compositor_frame_sink = false;
+ data.client = nullptr;
+
+ // There may be frame sink hierarchy information left in FrameSinkData.
+ if (data.IsEmpty())
+ frame_sink_data_map_.erase(frame_sink_id);
+
+ display_hit_test_query_.erase(frame_sink_id);
}
-void HostFrameSinkManager::CreateCompositorFrameSink(
+void HostFrameSinkManager::CreateRootCompositorFrameSink(
const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkClientPtr client) {
- DCHECK_EQ(frame_sink_data_map_.count(frame_sink_id), 0u);
-
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request) {
FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
- data.is_root = false;
+ DCHECK(data.IsFrameSinkRegistered());
+ DCHECK(!data.HasCompositorFrameSinkData());
- frame_sink_manager_->CreateCompositorFrameSink(
- frame_sink_id, std::move(request),
- mojo::MakeRequest(&data.private_interface), std::move(client));
+ data.is_root = true;
+ data.has_created_compositor_frame_sink = true;
+
+ frame_sink_manager_->CreateRootCompositorFrameSink(
+ frame_sink_id, surface_handle, renderer_settings, std::move(request),
+ std::move(client), std::move(display_private_request));
+ display_hit_test_query_[frame_sink_id] = base::MakeUnique<HitTestQuery>();
}
-void HostFrameSinkManager::DestroyCompositorFrameSink(
- const FrameSinkId& frame_sink_id) {
- auto iter = frame_sink_data_map_.find(frame_sink_id);
- DCHECK(iter != frame_sink_data_map_.end());
+void HostFrameSinkManager::CreateCompositorFrameSink(
+ const FrameSinkId& frame_sink_id,
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client) {
+ FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+ DCHECK(data.IsFrameSinkRegistered());
+ DCHECK(!data.HasCompositorFrameSinkData());
- FrameSinkData& data = iter->second;
- if (data.parent.has_value())
- UnregisterFrameSinkHierarchy(data.parent.value(), frame_sink_id);
+ data.is_root = false;
+ data.has_created_compositor_frame_sink = true;
- // This destroys the CompositorFrameSinkPrivatePtr and closes the pipe.
- frame_sink_data_map_.erase(iter);
+ frame_sink_manager_->CreateCompositorFrameSink(
+ frame_sink_id, std::move(request), std::move(client));
}
void HostFrameSinkManager::RegisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) {
- DCHECK_EQ(frame_sink_data_map_.count(child_frame_sink_id), 1u);
-
- // Register and store the parent, either directly or over Mojo.
+ // Register and store the parent.
frame_sink_manager_->RegisterFrameSinkHierarchy(parent_frame_sink_id,
child_frame_sink_id);
- frame_sink_data_map_[child_frame_sink_id].parent = parent_frame_sink_id;
+ FrameSinkData& child_data = frame_sink_data_map_[child_frame_sink_id];
+ DCHECK(!base::ContainsValue(child_data.parents, parent_frame_sink_id));
+ child_data.parents.push_back(parent_frame_sink_id);
+
+ FrameSinkData& parent_data = frame_sink_data_map_[parent_frame_sink_id];
+ DCHECK(!base::ContainsValue(parent_data.children, child_frame_sink_id));
+ parent_data.children.push_back(child_frame_sink_id);
}
void HostFrameSinkManager::UnregisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) {
- auto iter = frame_sink_data_map_.find(child_frame_sink_id);
- DCHECK(iter != frame_sink_data_map_.end());
+ // Unregister and clear the stored parent.
+ FrameSinkData& child_data = frame_sink_data_map_[child_frame_sink_id];
+ DCHECK(base::ContainsValue(child_data.parents, parent_frame_sink_id));
+ base::Erase(child_data.parents, parent_frame_sink_id);
- FrameSinkData& data = iter->second;
- DCHECK_EQ(data.parent.value(), parent_frame_sink_id);
+ FrameSinkData& parent_data = frame_sink_data_map_[parent_frame_sink_id];
+ DCHECK(base::ContainsValue(parent_data.children, child_frame_sink_id));
+ base::Erase(parent_data.children, child_frame_sink_id);
- // Unregister and clear the stored parent, either directly or over Mojo.
frame_sink_manager_->UnregisterFrameSinkHierarchy(parent_frame_sink_id,
child_frame_sink_id);
- data.parent.reset();
+ if (child_data.IsEmpty())
+ frame_sink_data_map_.erase(child_frame_sink_id);
+ if (parent_data.IsEmpty())
+ frame_sink_data_map_.erase(parent_frame_sink_id);
+}
+
+void HostFrameSinkManager::AssignTemporaryReference(
+ const SurfaceId& surface_id,
+ const FrameSinkId& frame_sink_id) {
+ frame_sink_manager_->AssignTemporaryReference(surface_id, frame_sink_id);
+}
+
+void HostFrameSinkManager::DropTemporaryReference(const SurfaceId& surface_id) {
+ frame_sink_manager_->DropTemporaryReference(surface_id);
}
std::unique_ptr<CompositorFrameSinkSupport>
@@ -108,28 +159,93 @@ HostFrameSinkManager::CreateCompositorFrameSinkSupport(
CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_points) {
DCHECK(frame_sink_manager_impl_);
- DCHECK_EQ(frame_sink_data_map_.count(frame_sink_id), 0u);
+
+ FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+ DCHECK(data.IsFrameSinkRegistered());
+ DCHECK(!data.HasCompositorFrameSinkData());
auto support = CompositorFrameSinkSupport::Create(
client, frame_sink_manager_impl_, frame_sink_id, is_root,
- handles_frame_sink_id_invalidation, needs_sync_points);
+ needs_sync_points);
support->SetDestructionCallback(
- base::BindOnce(&HostFrameSinkManager::DestroyCompositorFrameSink,
+ base::BindOnce(&HostFrameSinkManager::CompositorFrameSinkSupportDestroyed,
weak_ptr_factory_.GetWeakPtr(), frame_sink_id));
- FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
data.support = support.get();
data.is_root = is_root;
return support;
}
-void HostFrameSinkManager::OnSurfaceCreated(const SurfaceInfo& surface_info) {
- for (auto& observer : observers_)
- observer.OnSurfaceCreated(surface_info);
+void HostFrameSinkManager::CompositorFrameSinkSupportDestroyed(
+ const FrameSinkId& frame_sink_id) {
+ auto iter = frame_sink_data_map_.find(frame_sink_id);
+ DCHECK(iter != frame_sink_data_map_.end());
+
+ iter->second.support = nullptr;
+ if (iter->second.IsEmpty())
+ frame_sink_data_map_.erase(iter);
+}
+
+void HostFrameSinkManager::PerformAssignTemporaryReference(
+ const SurfaceId& surface_id) {
+ // Find the expected embedder for the new surface and assign the temporary
+ // reference to it.
+ auto iter = frame_sink_data_map_.find(surface_id.frame_sink_id());
+ DCHECK(iter != frame_sink_data_map_.end());
+ const FrameSinkData& data = iter->second;
+
+ // Display roots don't have temporary references to assign.
+ if (data.is_root)
+ return;
+
+ // If the frame sink has already been invalidated then we just drop the
+ // temporary reference.
+ if (!data.IsFrameSinkRegistered()) {
+ frame_sink_manager_->DropTemporaryReference(surface_id);
+ return;
+ }
+
+ // Find the oldest non-invalidated parent.
+ for (const FrameSinkId& parent_id : data.parents) {
+ const FrameSinkData& parent_data = frame_sink_data_map_[parent_id];
+ if (parent_data.IsFrameSinkRegistered()) {
+ frame_sink_manager_impl_->AssignTemporaryReference(surface_id, parent_id);
+ return;
+ }
+ }
+ // TODO(kylechar): We might need to handle the case where there are multiple
+ // embedders better, so that the owner doesn't remove a surface reference
+ // until the other embedder has added a surface reference. Maybe just letting
+ // the client know what is the owner is sufficient, so the client can handle
+ // this.
+
+ // We don't have any hierarchy information for what will embed the new
+ // surface, drop the temporary reference.
+ frame_sink_manager_->DropTemporaryReference(surface_id);
+}
+
+void HostFrameSinkManager::OnFirstSurfaceActivation(
+ const SurfaceInfo& surface_info) {
+ auto it = frame_sink_data_map_.find(surface_info.id().frame_sink_id());
+ // If we've received a bogus or stale SurfaceId from Viz then just ignore it.
+ if (it == frame_sink_data_map_.end()) {
+ // We don't have any hierarchy information for what will embed the new
+ // surface, drop the temporary reference.
+ frame_sink_manager_->DropTemporaryReference(surface_info.id());
+ return;
+ }
+
+ FrameSinkData& frame_sink_data = it->second;
+ if (frame_sink_data.client)
+ frame_sink_data.client->OnFirstSurfaceActivation(surface_info);
+
+ if (frame_sink_manager_impl_ &&
+ frame_sink_manager_impl_->surface_manager()->using_surface_references()) {
+ PerformAssignTemporaryReference(surface_info.id());
+ }
}
void HostFrameSinkManager::OnClientConnectionClosed(
@@ -137,6 +253,40 @@ void HostFrameSinkManager::OnClientConnectionClosed(
// TODO(kylechar): Notify observers.
}
+void HostFrameSinkManager::OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
+ auto iter = display_hit_test_query_.find(frame_sink_id);
+ if (iter == display_hit_test_query_.end()) {
+ // TODO(riajiang): Report security fault. http://crbug.com/746470
+ // Or verify if it is the case that display got destroyed, but viz doesn't
+ // know it yet.
+ NOTREACHED();
+ return;
+ }
+ iter->second->OnAggregatedHitTestRegionListUpdated(
+ std::move(active_handle), active_handle_size, std::move(idle_handle),
+ idle_handle_size);
+}
+
+void HostFrameSinkManager::SwitchActiveAggregatedHitTestRegionList(
+ const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) {
+ auto iter = display_hit_test_query_.find(frame_sink_id);
+ if (iter == display_hit_test_query_.end() ||
+ (active_handle_index != 0u && active_handle_index != 1u)) {
+ // TODO(riajiang): Report security fault. http://crbug.com/746470
+ // Or verify if it is the case that display got destroyed, but viz doesn't
+ // know it yet.
+ NOTREACHED();
+ return;
+ }
+ iter->second->SwitchActiveAggregatedHitTestRegionList(active_handle_index);
+}
+
HostFrameSinkManager::FrameSinkData::FrameSinkData() = default;
HostFrameSinkManager::FrameSinkData::FrameSinkData(FrameSinkData&& other) =
diff --git a/chromium/components/viz/host/host_frame_sink_manager.h b/chromium/components/viz/host/host_frame_sink_manager.h
index bcfd9faeffe..3f153088198 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.h
+++ b/chromium/components/viz/host/host_frame_sink_manager.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_MANAGER_H_
#define COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_MANAGER_H_
+#include <memory>
+#include <vector>
+
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
@@ -12,84 +15,108 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
-#include "cc/ipc/frame_sink_manager.mojom.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
-#include "components/viz/host/frame_sink_observer.h"
+#include "components/viz/host/hit_test/hit_test_query.h"
+#include "components/viz/host/host_frame_sink_client.h"
#include "components/viz/host/viz_host_export.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
namespace base {
class SingleThreadTaskRunner;
}
-namespace cc {
-class SurfaceInfo;
-} // namespace cc
-
namespace viz {
class CompositorFrameSinkSupport;
class CompositorFrameSinkSupportClient;
class FrameSinkManagerImpl;
+class SurfaceInfo;
namespace test {
class HostFrameSinkManagerTest;
}
// Browser side wrapper of mojom::FrameSinkManager, to be used from the
-// UI thread. Manages frame sinks and is intended to replace SurfaceManager.
+// UI thread. Manages frame sinks and is intended to replace all usage of
+// FrameSinkManagerImpl.
class VIZ_HOST_EXPORT HostFrameSinkManager
- : public NON_EXPORTED_BASE(cc::mojom::FrameSinkManagerClient),
- public NON_EXPORTED_BASE(CompositorFrameSinkSupportManager) {
+ : public mojom::FrameSinkManagerClient,
+ public CompositorFrameSinkSupportManager {
public:
HostFrameSinkManager();
~HostFrameSinkManager() override;
+ using DisplayHitTestQueryMap =
+ base::flat_map<FrameSinkId, std::unique_ptr<HitTestQuery>>;
+ const DisplayHitTestQueryMap& display_hit_test_query() const {
+ return display_hit_test_query_;
+ }
+
// Sets a local FrameSinkManagerImpl instance and connects directly to it.
void SetLocalManager(FrameSinkManagerImpl* frame_sink_manager_impl);
// Binds |this| as a FrameSinkManagerClient for |request| on |task_runner|. On
// Mac |task_runner| will be the resize helper task runner. May only be called
- // once.
+ // once. If |task_runner| is null, it uses the default mojo task runner for
+ // the thread this call is made on.
void BindAndSetManager(
- cc::mojom::FrameSinkManagerClientRequest request,
+ mojom::FrameSinkManagerClientRequest request,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- cc::mojom::FrameSinkManagerPtr ptr);
-
- void AddObserver(FrameSinkObserver* observer);
- void RemoveObserver(FrameSinkObserver* observer);
+ mojom::FrameSinkManagerPtr ptr);
+
+ // Registers |frame_sink_id| will be used. This must be called before
+ // CreateCompositorFrameSink(Support) is called.
+ void RegisterFrameSinkId(const FrameSinkId& frame_sink_id,
+ HostFrameSinkClient* client);
+
+ // Invalidates |frame_sink_id| which cleans up any unsatisified surface
+ // sequences or dangling temporary references assigned to it. If there is a
+ // CompositorFrameSink for |frame_sink_id| then it will be destroyed and the
+ // message pipe to the client will be closed.
+ void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
+
+ // Creates a connection for a display root to viz. Provides the same
+ // interfaces as CreateCompositorFramesink() plus the priviledged
+ // DisplayPrivate interface. When no longer needed, call
+ // InvalidateFrameSinkId().
+ void CreateRootCompositorFrameSink(
+ const FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request);
// Creates a connection between client to viz, using |request| and |client|,
// that allows the client to submit CompositorFrames. When no longer needed,
- // call DestroyCompositorFrameSink().
- void CreateCompositorFrameSink(
- const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkClientPtr client);
+ // call InvalidateFrameSinkId().
+ void CreateCompositorFrameSink(const FrameSinkId& frame_sink_id,
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client);
- // Destroys a client connection. Will call UnregisterFrameSinkHierarchy() with
- // the registered parent if there is one.
- void DestroyCompositorFrameSink(const FrameSinkId& frame_sink_id);
-
- // Registers FrameSink hierarchy. Clients can call this multiple times to
- // reparent without calling UnregisterFrameSinkHierarchy(). If a client uses
- // CompositorFrameSink, then CreateCompositorFrameSink() should be called
- // before this.
+ // Registers frame sink hierarchy. A frame sink can have multiple parents.
void RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id);
- // Unregisters FrameSink hierarchy. Client must have registered FrameSink
+ // Unregisters FrameSink hierarchy. Client must have registered frame sink
// hierarchy before unregistering.
void UnregisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id);
+ // These two functions should only be used by WindowServer.
+ // TODO(riajiang): Find a better way for HostFrameSinkManager to do the assign
+ // and drop instead.
+ void AssignTemporaryReference(const SurfaceId& surface_id,
+ const FrameSinkId& owner);
+ void DropTemporaryReference(const SurfaceId& surface_id);
+
// CompositorFrameSinkSupportManager:
std::unique_ptr<CompositorFrameSinkSupport> CreateCompositorFrameSinkSupport(
CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_points) override;
private:
@@ -101,40 +128,71 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
~FrameSinkData();
FrameSinkData& operator=(FrameSinkData&& other);
+ bool IsFrameSinkRegistered() const { return client != nullptr; }
+
+ bool HasCompositorFrameSinkData() const {
+ return has_created_compositor_frame_sink || support;
+ }
+
+ // Returns true if there is nothing in FrameSinkData and it can be deleted.
+ bool IsEmpty() const {
+ return !IsFrameSinkRegistered() && !HasCompositorFrameSinkData() &&
+ parents.empty() && children.empty();
+ }
+
+ // The client to be notified of changes to this FrameSink.
+ HostFrameSinkClient* client = nullptr;
+
// If the frame sink is a root that corresponds to a Display.
bool is_root = false;
- // The FrameSinkId registered as the parent in the BeginFrame hierarchy.
- // This mirrors state in viz.
- base::Optional<FrameSinkId> parent;
-
- // The private interface that gives the host control over the
- // CompositorFrameSink connection between the client and viz. This will be
- // unbound if not using Mojo.
- cc::mojom::CompositorFrameSinkPrivatePtr private_interface;
+ // If a mojom::CompositorFrameSink was created for this FrameSinkId. This
+ // will always be false if not using Mojo.
+ bool has_created_compositor_frame_sink = false;
// This will be null if using Mojo.
CompositorFrameSinkSupport* support = nullptr;
+ // Track frame sink hierarchy in both directions.
+ std::vector<FrameSinkId> parents;
+ std::vector<FrameSinkId> children;
+
private:
DISALLOW_COPY_AND_ASSIGN(FrameSinkData);
};
- // cc::mojom::FrameSinkManagerClient:
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+ // Provided as a callback to clear state when a CompositorFrameSinkSupport is
+ // destroyed.
+ void CompositorFrameSinkSupportDestroyed(const FrameSinkId& frame_sink_id);
+
+ // Assigns the temporary reference to the frame sink that is expected to
+ // embeded |surface_id|, otherwise drops the temporary reference.
+ void PerformAssignTemporaryReference(const SurfaceId& surface_id);
+
+ // mojom::FrameSinkManagerClient:
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
void OnClientConnectionClosed(const FrameSinkId& frame_sink_id) override;
+ void OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_sizes) override;
+ void SwitchActiveAggregatedHitTestRegionList(
+ const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) override;
// This will point to |frame_sink_manager_ptr_| if using Mojo or
// |frame_sink_manager_impl_| if directly connected. Use this to make function
// calls.
- cc::mojom::FrameSinkManager* frame_sink_manager_ = nullptr;
+ mojom::FrameSinkManager* frame_sink_manager_ = nullptr;
// Mojo connection to the FrameSinkManager. If this is bound then
// |frame_sink_manager_impl_| must be null.
- cc::mojom::FrameSinkManagerPtr frame_sink_manager_ptr_;
+ mojom::FrameSinkManagerPtr frame_sink_manager_ptr_;
// Mojo connection back from the FrameSinkManager.
- mojo::Binding<cc::mojom::FrameSinkManagerClient> binding_;
+ mojo::Binding<mojom::FrameSinkManagerClient> binding_;
// A direct connection to FrameSinkManagerImpl. If this is set then
// |frame_sink_manager_ptr_| must be unbound. For use in browser process only,
@@ -144,8 +202,7 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
// Per CompositorFrameSink data.
base::flat_map<FrameSinkId, FrameSinkData> frame_sink_data_map_;
- // Local observers to that receive OnSurfaceCreated() messages from IPC.
- base::ObserverList<FrameSinkObserver> observers_;
+ DisplayHitTestQueryMap display_hit_test_query_;
base::WeakPtrFactory<HostFrameSinkManager> weak_ptr_factory_;
diff --git a/chromium/components/viz/host/host_frame_sink_manager_unittests.cc b/chromium/components/viz/host/host_frame_sink_manager_unittests.cc
index 84e288351cf..272a27815fe 100644
--- a/chromium/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -8,51 +8,50 @@
#include <utility>
#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "cc/ipc/frame_sink_manager.mojom.h"
+#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+
namespace viz {
namespace test {
namespace {
-constexpr FrameSinkId kFrameSinkId1(1, 1);
-constexpr FrameSinkId kFrameSinkId2(2, 1);
+constexpr FrameSinkId kFrameSinkParent1(1, 1);
+constexpr FrameSinkId kFrameSinkParent2(2, 1);
+constexpr FrameSinkId kFrameSinkChild1(3, 1);
+
+// Makes a SurfaceId with a default nonce.
+SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
+ return SurfaceId(
+ frame_sink_id,
+ LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
+}
-ACTION_P(InvokeClosure, closure) {
- closure.Run();
+// Makes a SurfaceInfo with a default device_scale_factor and size.
+SurfaceInfo MakeSurfaceInfo(const SurfaceId& surface_id) {
+ return SurfaceInfo(surface_id, 1.f, gfx::Size(1, 1));
}
-// A stub CompositorFrameSinkClient that does nothing.
-class StubCompositorFrameSinkClient
- : public cc::mojom::CompositorFrameSinkClient {
+// A fake (do-nothing) implementation of HostFrameSinkClient.
+class FakeHostFrameSinkClient : public HostFrameSinkClient {
public:
- StubCompositorFrameSinkClient() : binding_(this) {}
- ~StubCompositorFrameSinkClient() override = default;
+ FakeHostFrameSinkClient() = default;
+ ~FakeHostFrameSinkClient() override = default;
- cc::mojom::CompositorFrameSinkClientPtr GetInterfacePtr() {
- cc::mojom::CompositorFrameSinkClientPtr client;
- binding_.Bind(mojo::MakeRequest(&client));
- return client;
- }
+ // HostFrameSinkClient implementation.
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override {}
private:
- // cc::mojom::CompositorFrameSinkClient:
- void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override {}
- void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override {}
- void OnBeginFramePausedChanged(bool paused) override {}
- void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override {}
-
- mojo::Binding<cc::mojom::CompositorFrameSinkClient> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(StubCompositorFrameSinkClient);
+ DISALLOW_COPY_AND_ASSIGN(FakeHostFrameSinkClient);
};
// A mock implementation of mojom::FrameSinkManager.
@@ -61,15 +60,37 @@ class MockFrameSinkManagerImpl : public FrameSinkManagerImpl {
MockFrameSinkManagerImpl() = default;
~MockFrameSinkManagerImpl() override = default;
- // cc::mojom::FrameSinkManager:
+ // mojom::FrameSinkManager:
+ MOCK_METHOD1(RegisterFrameSinkId, void(const FrameSinkId& frame_sink_id));
+ MOCK_METHOD1(InvalidateFrameSinkId, void(const FrameSinkId& frame_sink_id));
+ // Work around for gmock not supporting move-only types.
+ void CreateCompositorFrameSink(
+ const FrameSinkId& frame_sink_id,
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client) override {
+ MockCreateCompositorFrameSink(frame_sink_id);
+ }
+ MOCK_METHOD1(MockCreateCompositorFrameSink,
+ void(const FrameSinkId& frame_sink_id));
+ void CreateRootCompositorFrameSink(
+ const FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request) override {
+ MockCreateRootCompositorFrameSink(frame_sink_id);
+ }
+ MOCK_METHOD1(MockCreateRootCompositorFrameSink,
+ void(const FrameSinkId& frame_sink_id));
MOCK_METHOD2(RegisterFrameSinkHierarchy,
void(const FrameSinkId& parent, const FrameSinkId& child));
MOCK_METHOD2(UnregisterFrameSinkHierarchy,
void(const FrameSinkId& parent, const FrameSinkId& child));
+ MOCK_METHOD2(AssignTemporaryReference,
+ void(const SurfaceId& surface_id, const FrameSinkId& owner));
MOCK_METHOD1(DropTemporaryReference, void(const SurfaceId& surface_id));
- // TODO(kylechar): See if we can mock functions with InterfacePtr parameters.
-
private:
DISALLOW_COPY_AND_ASSIGN(MockFrameSinkManagerImpl);
};
@@ -81,61 +102,336 @@ class HostFrameSinkManagerTest : public testing::Test {
HostFrameSinkManagerTest() = default;
~HostFrameSinkManagerTest() override = default;
- HostFrameSinkManager& host_manager() { return *host_manager_; }
+ HostFrameSinkManager& host() { return *host_manager_; }
- MockFrameSinkManagerImpl& manager_impl() { return *manager_impl_; }
+ MockFrameSinkManagerImpl& impl() { return *manager_impl_; }
- bool FrameSinkIdExists(const FrameSinkId& frame_sink_id) {
+ std::unique_ptr<CompositorFrameSinkSupport> CreateCompositorFrameSinkSupport(
+ const FrameSinkId& frame_sink_id,
+ bool is_root) {
+ return host_manager_->CreateCompositorFrameSinkSupport(
+ nullptr /* client */, frame_sink_id, is_root,
+ false /* needs_sync_points */);
+ }
+
+ mojom::FrameSinkManagerClient* GetFrameSinkManagerClient() {
+ return static_cast<mojom::FrameSinkManagerClient*>(host_manager_.get());
+ }
+
+ bool FrameSinkDataExists(const FrameSinkId& frame_sink_id) {
return host_manager_->frame_sink_data_map_.count(frame_sink_id) > 0;
}
+ bool DisplayHitTestQueryExists(const FrameSinkId& frame_sink_id) {
+ return host_manager_->display_hit_test_query_.count(frame_sink_id) > 0;
+ }
+
// testing::Test:
void SetUp() override {
- manager_impl_ = base::MakeUnique<MockFrameSinkManagerImpl>();
+ manager_impl_ =
+ base::MakeUnique<testing::NiceMock<MockFrameSinkManagerImpl>>();
host_manager_ = base::MakeUnique<HostFrameSinkManager>();
manager_impl_->SetLocalClient(host_manager_.get());
host_manager_->SetLocalManager(manager_impl_.get());
}
+ void TearDown() override {
+ host_manager_.reset();
+ manager_impl_.reset();
+ }
+
private:
std::unique_ptr<HostFrameSinkManager> host_manager_;
- std::unique_ptr<MockFrameSinkManagerImpl> manager_impl_;
+ std::unique_ptr<testing::NiceMock<MockFrameSinkManagerImpl>> manager_impl_;
DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManagerTest);
};
-// Verify that when destroying a CompositorFrameSink with registered FrameSink
-// hierarchy, the hierarchy is automatically unregistered.
-TEST_F(HostFrameSinkManagerTest, UnregisterHierarchyOnDestroy) {
- // Register is called explicitly.
- EXPECT_CALL(manager_impl(),
- RegisterFrameSinkHierarchy(kFrameSinkId2, kFrameSinkId1));
-
- // Unregister should be called when DestroyCompositorFrameSink() is called.
- EXPECT_CALL(manager_impl(),
- UnregisterFrameSinkHierarchy(kFrameSinkId2, kFrameSinkId1));
-
- cc::mojom::CompositorFrameSinkPtr frame_sink;
- StubCompositorFrameSinkClient frame_sink_client;
- host_manager().CreateCompositorFrameSink(kFrameSinkId1,
- mojo::MakeRequest(&frame_sink),
- frame_sink_client.GetInterfacePtr());
- host_manager().RegisterFrameSinkHierarchy(kFrameSinkId2, kFrameSinkId1);
- host_manager().DestroyCompositorFrameSink(kFrameSinkId1);
+// Verify that creating and destroying a CompositorFrameSink using
+// mojom::CompositorFrameSink works correctly.
+TEST_F(HostFrameSinkManagerTest, CreateMojomCompositorFrameSink) {
+ FakeHostFrameSinkClient host_client;
+
+ // Register then create CompositorFrameSink for child.
+ EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1));
+ host().RegisterFrameSinkId(kFrameSinkChild1, &host_client);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ EXPECT_CALL(impl(), MockCreateCompositorFrameSink(kFrameSinkChild1));
+ host().CreateCompositorFrameSink(kFrameSinkChild1, nullptr /* request */,
+ nullptr /* client */);
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // Register but don't actually create CompositorFrameSink for parent.
+ host().RegisterFrameSinkId(kFrameSinkParent1, &host_client);
+
+ // Register should call through to FrameSinkManagerImpl and should work even
+ // though |kFrameSinkParent1| was not created yet.
+ EXPECT_CALL(impl(),
+ RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
+ host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+
+ // Destroy the CompositorFrameSink.
+ EXPECT_CALL(impl(), InvalidateFrameSinkId(kFrameSinkChild1));
+ host().InvalidateFrameSinkId(kFrameSinkChild1);
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // Unregister should work after the CompositorFrameSink is destroyed.
+ EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
+ kFrameSinkChild1));
+ host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+
+ // Data for |kFrameSinkChild1| should be deleted now.
+ EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
+}
+
+// Verify that that creating two CompositorFrameSinkSupports works.
+TEST_F(HostFrameSinkManagerTest, CreateCompositorFrameSinkSupport) {
+ FakeHostFrameSinkClient host_client;
+
+ host().RegisterFrameSinkId(kFrameSinkChild1, &host_client);
+ auto support_child =
+ CreateCompositorFrameSinkSupport(kFrameSinkChild1, true /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ host().RegisterFrameSinkId(kFrameSinkParent1, &host_client);
+ auto support_parent =
+ CreateCompositorFrameSinkSupport(kFrameSinkParent1, true /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkParent1));
+
+ // Verify that registering and unregistering frame sink hierarchy works.
+ EXPECT_CALL(impl(),
+ RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
+ host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
+ kFrameSinkChild1));
+ host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+
+ // We should still have the CompositorFrameSink data for |kFrameSinkChild1|.
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ // Data for |kFrameSinkChild1| should be deleted when everything is destroyed.
+ support_child.reset();
+ host().InvalidateFrameSinkId(kFrameSinkChild1);
+ EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
+
+ // Data for |kFrameSinkParent1| should be deleted when everything is
+ // destroyed.
+ support_parent.reset();
+ host().InvalidateFrameSinkId(kFrameSinkParent1);
+ EXPECT_FALSE(FrameSinkDataExists(kFrameSinkParent1));
+}
+
+TEST_F(HostFrameSinkManagerTest, AssignTemporaryReference) {
+ FakeHostFrameSinkClient host_client;
+ host().RegisterFrameSinkId(kFrameSinkParent1, &host_client);
+
+ const SurfaceId surface_id = MakeSurfaceId(kFrameSinkChild1, 1);
+ host().RegisterFrameSinkId(surface_id.frame_sink_id(), &host_client);
+ auto support = CreateCompositorFrameSinkSupport(surface_id.frame_sink_id(),
+ false /* is_root */);
+
+ host().RegisterFrameSinkHierarchy(kFrameSinkParent1,
+ surface_id.frame_sink_id());
+
+ // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should assign
+ // the temporary reference to the registered parent |kFrameSinkParent1|.
+ EXPECT_CALL(impl(), AssignTemporaryReference(surface_id, kFrameSinkParent1));
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(surface_id));
}
-// Checks that creating a CompositorFrameSinkSupport registers it and destroying
-// the CompositorFrameSinkSupport unregisters it.
-TEST_F(HostFrameSinkManagerTest, CreateDestroyCompositorFrameSinkSupport) {
- auto support = host_manager().CreateCompositorFrameSinkSupport(
- nullptr /* client */, kFrameSinkId1, true /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
- false /* needs_sync_points */);
- EXPECT_TRUE(FrameSinkIdExists(kFrameSinkId1));
-
- support.reset();
- EXPECT_FALSE(FrameSinkIdExists(kFrameSinkId1));
+// Verify that we drop temporary reference to a surface that doesn't have any
+// registered parent.
+TEST_F(HostFrameSinkManagerTest, DropTemporaryReference) {
+ FakeHostFrameSinkClient host_client;
+
+ const SurfaceId surface_id = MakeSurfaceId(kFrameSinkChild1, 1);
+ host().RegisterFrameSinkId(surface_id.frame_sink_id(), &host_client);
+ auto support = CreateCompositorFrameSinkSupport(surface_id.frame_sink_id(),
+ false /* is_root */);
+
+ // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should find no
+ // registered parent and drop the temporary reference.
+ EXPECT_CALL(impl(), DropTemporaryReference(surface_id));
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(surface_id));
+}
+
+// Verify that we drop the temporary reference to a new surface if the frame
+// sink that corresponds to the new surface has been invalidated.
+TEST_F(HostFrameSinkManagerTest, DropTemporaryReferenceForStaleClient) {
+ FakeHostFrameSinkClient host_client;
+
+ host().RegisterFrameSinkId(kFrameSinkChild1, &host_client);
+ auto support_child =
+ CreateCompositorFrameSinkSupport(kFrameSinkChild1, false /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ host().RegisterFrameSinkId(kFrameSinkParent1, &host_client);
+ auto support_parent =
+ CreateCompositorFrameSinkSupport(kFrameSinkParent1, true /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkParent1));
+
+ // Register should call through to FrameSinkManagerImpl.
+ EXPECT_CALL(impl(),
+ RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
+ host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+
+ // Verify that temporary reference is assigned correctly before invalidation.
+ const SurfaceId client_surface_id = MakeSurfaceId(kFrameSinkChild1, 1);
+ EXPECT_CALL(impl(), DropTemporaryReference(client_surface_id)).Times(0);
+ EXPECT_CALL(impl(),
+ AssignTemporaryReference(client_surface_id, kFrameSinkParent1))
+ .Times(1);
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(client_surface_id));
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // Invaidating the child should cause the temporary reference to the next
+ // SurfaceId to be dropped.
+ support_child.reset();
+ host().InvalidateFrameSinkId(kFrameSinkChild1);
+
+ const SurfaceId client_surface_id2 = MakeSurfaceId(kFrameSinkChild1, 2);
+ EXPECT_CALL(impl(), DropTemporaryReference(client_surface_id2)).Times(1);
+ EXPECT_CALL(impl(), AssignTemporaryReference(client_surface_id2, _)).Times(0);
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(client_surface_id2));
+
+ support_parent.reset();
+ host().InvalidateFrameSinkId(kFrameSinkParent1);
+}
+
+// Verify that multiple parents in the frame sink hierarchy works.
+TEST_F(HostFrameSinkManagerTest, HierarchyMultipleParents) {
+ FakeHostFrameSinkClient host_client;
+
+ // Register two parent and child CompositorFrameSink.
+ const FrameSinkId& id_parent1 = kFrameSinkParent1;
+ host().RegisterFrameSinkId(id_parent1, &host_client);
+ auto support_parent1 =
+ CreateCompositorFrameSinkSupport(id_parent1, true /* is_root */);
+
+ const FrameSinkId& id_parent2 = kFrameSinkChild1;
+ host().RegisterFrameSinkId(id_parent2, &host_client);
+ auto support_parent2 =
+ CreateCompositorFrameSinkSupport(id_parent2, true /* is_root */);
+
+ const FrameSinkId& id_child = kFrameSinkParent2;
+ host().RegisterFrameSinkId(id_child, &host_client);
+ auto support_child =
+ CreateCompositorFrameSinkSupport(id_child, false /* is_root */);
+
+ // Register |id_parent1| in hierarchy first, this is the original window
+ // embedding.
+ EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent1, id_child));
+ host().RegisterFrameSinkHierarchy(id_parent1, id_child);
+
+ // Register |id_parent2| in hierarchy second, this is a second embedding for
+ // something like alt-tab on a different monitor.
+ EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent2, id_child));
+ host().RegisterFrameSinkHierarchy(id_parent2, id_child);
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // The oldest registered parent in the hierarchy is assigned the temporary
+ // reference.
+ const SurfaceId surface_id = MakeSurfaceId(id_child, 1);
+ EXPECT_CALL(impl(), AssignTemporaryReference(surface_id, id_parent1));
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(surface_id));
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // Unregistering hierarchy with multiple parents should also work.
+ EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent2, id_child));
+ host().UnregisterFrameSinkHierarchy(id_parent2, id_child);
+
+ EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent1, id_child));
+ host().UnregisterFrameSinkHierarchy(id_parent1, id_child);
+}
+
+// Verify that we drop the temporary reference to a new surface if the only
+// frame sink registered as an embedder has been invalidated.
+TEST_F(HostFrameSinkManagerTest, DropTemporaryReferenceForInvalidatedParent) {
+ FakeHostFrameSinkClient host_client;
+
+ host().RegisterFrameSinkId(kFrameSinkChild1, &host_client);
+ auto support_child =
+ CreateCompositorFrameSinkSupport(kFrameSinkChild1, false /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ host().RegisterFrameSinkId(kFrameSinkParent1, &host_client);
+ auto support_parent =
+ CreateCompositorFrameSinkSupport(kFrameSinkParent1, true /* is_root */);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkParent1));
+
+ // Register should call through to FrameSinkManagerImpl.
+ EXPECT_CALL(impl(),
+ RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
+ host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
+
+ // Verify that temporary reference is assigned correctly before invalidation.
+ const SurfaceId client_surface_id = MakeSurfaceId(kFrameSinkChild1, 1);
+ EXPECT_CALL(impl(), DropTemporaryReference(client_surface_id)).Times(0);
+ EXPECT_CALL(impl(),
+ AssignTemporaryReference(client_surface_id, kFrameSinkParent1))
+ .Times(1);
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(client_surface_id));
+ testing::Mock::VerifyAndClearExpectations(&impl());
+
+ // Invaidating the parent should cause the next SurfaceId to be dropped
+ // because there is no registered frame sink as the parent.
+ support_parent.reset();
+ host().InvalidateFrameSinkId(kFrameSinkParent1);
+
+ const SurfaceId client_surface_id2 = MakeSurfaceId(kFrameSinkChild1, 2);
+ EXPECT_CALL(impl(), DropTemporaryReference(client_surface_id2)).Times(1);
+ EXPECT_CALL(impl(), AssignTemporaryReference(client_surface_id2, _)).Times(0);
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(client_surface_id2));
+
+ support_child.reset();
+ host().InvalidateFrameSinkId(kFrameSinkChild1);
+}
+
+TEST_F(HostFrameSinkManagerTest, DisplayRootTemporaryReference) {
+ FakeHostFrameSinkClient host_client;
+
+ const SurfaceId surface_id = MakeSurfaceId(kFrameSinkParent1, 1);
+ host().RegisterFrameSinkId(surface_id.frame_sink_id(), &host_client);
+ auto support = CreateCompositorFrameSinkSupport(surface_id.frame_sink_id(),
+ true /* is_root */);
+
+ // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should do
+ // nothing since |kFrameSinkParent1| is a display root.
+ EXPECT_CALL(impl(), DropTemporaryReference(surface_id)).Times(0);
+ EXPECT_CALL(impl(), AssignTemporaryReference(surface_id, _)).Times(0);
+ GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+ MakeSurfaceInfo(surface_id));
+}
+
+// Test the creation and desctruction of HitTestQuery, which is stored in
+// HostFrameSinkManager::display_hit_test_query_.
+TEST_F(HostFrameSinkManagerTest, DisplayHitTestQueryMap) {
+ FakeHostFrameSinkClient client;
+ EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
+ host().RegisterFrameSinkId(kFrameSinkChild1, &client);
+ EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
+
+ EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkChild1));
+ host().CreateRootCompositorFrameSink(
+ kFrameSinkChild1, 0 /* surface_handle */,
+ RendererSettings() /* renderer_settings */, nullptr /* request */,
+ nullptr /* client */, nullptr /* display_private_request */);
+ EXPECT_TRUE(DisplayHitTestQueryExists(kFrameSinkChild1));
+
+ host().InvalidateFrameSinkId(kFrameSinkChild1);
+ EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
+ EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkChild1));
}
} // namespace test
diff --git a/chromium/components/viz/host/renderer_settings_creation.cc b/chromium/components/viz/host/renderer_settings_creation.cc
new file mode 100644
index 00000000000..13bef1debb6
--- /dev/null
+++ b/chromium/components/viz/host/renderer_settings_creation.cc
@@ -0,0 +1,82 @@
+// 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/viz/host/renderer_settings_creation.h"
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gfx/color_space_switches.h"
+
+namespace viz {
+
+namespace {
+
+bool GetSwitchValueAsInt(const base::CommandLine* command_line,
+ const std::string& switch_string,
+ int min_value,
+ int max_value,
+ int* result) {
+ std::string string_value = command_line->GetSwitchValueASCII(switch_string);
+ int int_value;
+ if (base::StringToInt(string_value, &int_value) && int_value >= min_value &&
+ int_value <= max_value) {
+ *result = int_value;
+ return true;
+ } else {
+ LOG(WARNING) << "Failed to parse switch " << switch_string << ": "
+ << string_value;
+ return false;
+ }
+}
+
+} // namespace
+
+ResourceSettings CreateResourceSettings(
+ const BufferToTextureTargetMap& image_targets) {
+ ResourceSettings resource_settings;
+ resource_settings.buffer_to_texture_target_map = image_targets;
+ return resource_settings;
+}
+
+RendererSettings CreateRendererSettings(
+ const BufferToTextureTargetMap& image_targets) {
+ RendererSettings renderer_settings;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ renderer_settings.partial_swap_enabled =
+ !command_line->HasSwitch(switches::kUIDisablePartialSwap);
+#if defined(OS_WIN)
+ renderer_settings.finish_rendering_on_resize = true;
+#elif defined(OS_MACOSX)
+ renderer_settings.release_overlay_resources_after_gpu_query = true;
+#endif
+ renderer_settings.gl_composited_overlay_candidate_quad_border =
+ command_line->HasSwitch(
+ switches::kGlCompositedOverlayCandidateQuadBorder);
+ renderer_settings.show_overdraw_feedback =
+ command_line->HasSwitch(switches::kShowOverdrawFeedback);
+ renderer_settings.enable_color_correct_rendering =
+ base::FeatureList::IsEnabled(features::kColorCorrectRendering);
+ renderer_settings.resource_settings = CreateResourceSettings(image_targets);
+ renderer_settings.disallow_non_exact_resource_reuse =
+ command_line->HasSwitch(switches::kDisallowNonExactResourceReuse);
+ renderer_settings.allow_antialiasing =
+ !command_line->HasSwitch(switches::kDisableCompositedAntialiasing);
+ renderer_settings.use_skia_renderer =
+ command_line->HasSwitch(switches::kUseSkiaRenderer);
+ if (command_line->HasSwitch(switches::kSlowDownCompositingScaleFactor)) {
+ const int kMinSlowDownScaleFactor = 1;
+ const int kMaxSlowDownScaleFactor = 1000;
+ GetSwitchValueAsInt(command_line, switches::kSlowDownCompositingScaleFactor,
+ kMinSlowDownScaleFactor, kMaxSlowDownScaleFactor,
+ &renderer_settings.slow_down_compositing_scale_factor);
+ }
+
+ return renderer_settings;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/host/renderer_settings_creation.h b/chromium/components/viz/host/renderer_settings_creation.h
new file mode 100644
index 00000000000..3c8459a7945
--- /dev/null
+++ b/chromium/components/viz/host/renderer_settings_creation.h
@@ -0,0 +1,30 @@
+// 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_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_
+#define COMPONENTS_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_
+
+#include <stdint.h>
+
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
+#include "components/viz/host/viz_host_export.h"
+
+namespace viz {
+class RendererSettings;
+class ResourceSettings;
+} // namespace viz
+
+namespace viz {
+
+// |image_targets| is a map from every supported pair of GPU memory buffer
+// usage/format to its GL texture target.
+VIZ_HOST_EXPORT ResourceSettings
+CreateResourceSettings(const BufferToTextureTargetMap& image_targets);
+
+VIZ_HOST_EXPORT RendererSettings
+CreateRendererSettings(const BufferToTextureTargetMap& image_targets);
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_
diff --git a/chromium/components/viz/host/server_gpu_memory_buffer_manager.cc b/chromium/components/viz/host/server_gpu_memory_buffer_manager.cc
index afbc5e144ad..c90add6b40e 100644
--- a/chromium/components/viz/host/server_gpu_memory_buffer_manager.cc
+++ b/chromium/components/viz/host/server_gpu_memory_buffer_manager.cc
@@ -6,29 +6,41 @@
#include "base/logging.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
#include "gpu/ipc/client/gpu_memory_buffer_impl.h"
#include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
-#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
+#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
#include "ui/gfx/buffer_format_util.h"
-#include "ui/gfx/gpu_memory_buffer_tracing.h"
namespace viz {
+namespace {
+
+void OnGpuMemoryBufferDestroyed(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const gpu::GpuMemoryBufferImpl::DestructionCallback& callback,
+ const gpu::SyncToken& sync_token) {
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, sync_token));
+}
+
+} // namespace
+
ServerGpuMemoryBufferManager::BufferInfo::BufferInfo() = default;
ServerGpuMemoryBufferManager::BufferInfo::~BufferInfo() = default;
ServerGpuMemoryBufferManager::ServerGpuMemoryBufferManager(
- ui::mojom::GpuService* gpu_service,
+ mojom::GpuService* gpu_service,
int client_id)
: gpu_service_(gpu_service),
client_id_(client_id),
native_configurations_(gpu::GetNativeGpuMemoryBufferConfigurations()),
- task_runner_(base::SequencedTaskRunnerHandle::Get()),
- weak_factory_(this) {}
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ weak_factory_(this) {
+ weak_ptr_ = weak_factory_.GetWeakPtr();
+}
ServerGpuMemoryBufferManager::~ServerGpuMemoryBufferManager() {}
@@ -49,7 +61,7 @@ void ServerGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
gpu_service_->CreateGpuMemoryBuffer(
id, size, format, usage, client_id, surface_handle,
base::Bind(&ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated,
- weak_factory_.GetWeakPtr(), client_id,
+ weak_ptr_, client_id,
gfx::BufferSizeForBufferFormat(size, format),
base::Passed(std::move(callback))));
return;
@@ -108,10 +120,15 @@ ServerGpuMemoryBufferManager::CreateGpuMemoryBuffer(
wait_event.Wait();
if (handle.is_null())
return nullptr;
+ // The destruction callback can be called on any thread. So use an
+ // intermediate callback here as the destruction callback, which bounces off
+ // onto the |task_runner_| thread to do the real work.
return gpu::GpuMemoryBufferImpl::CreateFromHandle(
handle, size, format, usage,
- base::Bind(&ServerGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
- weak_factory_.GetWeakPtr(), id, client_id_));
+ base::Bind(
+ &OnGpuMemoryBufferDestroyed, task_runner_,
+ base::Bind(&ServerGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
+ weak_ptr_, id, client_id_)));
}
void ServerGpuMemoryBufferManager::SetDestructionSyncToken(
@@ -146,11 +163,8 @@ bool ServerGpuMemoryBufferManager::OnMemoryDump(
uint64_t client_tracing_process_id = ClientIdToTracingId(client_id);
if (buffer_info.type == gfx::SHARED_MEMORY_BUFFER) {
- auto shared_buffer_guid = gfx::GetSharedMemoryGUIDForTracing(
- client_tracing_process_id, buffer_id);
- pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_buffer_guid,
- buffer_info.shared_memory_guid,
- 0 /* importance */);
+ pmd->CreateSharedMemoryOwnershipEdge(
+ dump->guid(), buffer_info.shared_memory_guid, 0 /* importance */);
} else {
auto shared_buffer_guid = gfx::GetGenericSharedGpuMemoryGUIDForTracing(
client_tracing_process_id, buffer_id);
diff --git a/chromium/components/viz/host/server_gpu_memory_buffer_manager.h b/chromium/components/viz/host/server_gpu_memory_buffer_manager.h
index 5ae16d953ef..039ae9ceb51 100644
--- a/chromium/components/viz/host/server_gpu_memory_buffer_manager.h
+++ b/chromium/components/viz/host/server_gpu_memory_buffer_manager.h
@@ -9,20 +9,18 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/viz/host/viz_host_export.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/ipc/host/gpu_memory_buffer_support.h"
-namespace ui {
+namespace viz {
+
namespace mojom {
class GpuService;
}
-} // namespace ui
-
-namespace viz {
// This GpuMemoryBufferManager implementation is for [de]allocating gpu memory
// from the gpu process over the mojom.GpuService api.
@@ -32,8 +30,7 @@ class VIZ_HOST_EXPORT ServerGpuMemoryBufferManager
: public gpu::GpuMemoryBufferManager,
public base::trace_event::MemoryDumpProvider {
public:
- ServerGpuMemoryBufferManager(ui::mojom::GpuService* gpu_service,
- int client_id);
+ ServerGpuMemoryBufferManager(mojom::GpuService* gpu_service, int client_id);
~ServerGpuMemoryBufferManager() override;
void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
@@ -72,7 +69,7 @@ class VIZ_HOST_EXPORT ServerGpuMemoryBufferManager
base::OnceCallback<void(const gfx::GpuMemoryBufferHandle&)> callback,
const gfx::GpuMemoryBufferHandle& handle);
- ui::mojom::GpuService* gpu_service_;
+ mojom::GpuService* gpu_service_;
const int client_id_;
int next_gpu_memory_id_ = 1;
@@ -92,7 +89,8 @@ class VIZ_HOST_EXPORT ServerGpuMemoryBufferManager
std::unordered_set<int> pending_buffers_;
const gpu::GpuMemoryBufferConfigurationSet native_configurations_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ base::WeakPtr<ServerGpuMemoryBufferManager> weak_ptr_;
base::WeakPtrFactory<ServerGpuMemoryBufferManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServerGpuMemoryBufferManager);
diff --git a/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
index 6737f18f795..f3e03590d06 100644
--- a/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
+++ b/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -7,7 +7,7 @@
#include "base/run_loop.h"
#include "base/threading/thread.h"
#include "gpu/ipc/host/gpu_memory_buffer_support.h"
-#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
+#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/client_native_pixmap_factory.h"
@@ -15,7 +15,7 @@ namespace viz {
namespace {
-class TestGpuService : public ui::mojom::GpuService {
+class TestGpuService : public mojom::GpuService {
public:
TestGpuService() {}
~TestGpuService() override {}
@@ -37,43 +37,42 @@ class TestGpuService : public ui::mojom::GpuService {
}
void SatisfyAllocationRequest(gfx::GpuMemoryBufferId id, int client_id) {
- for (const auto& req : allocation_requests_) {
+ for (auto& req : allocation_requests_) {
if (req.id == id && req.client_id == client_id) {
gfx::GpuMemoryBufferHandle handle;
handle.id = id;
handle.type = gfx::SHARED_MEMORY_BUFFER;
- req.callback.Run(handle);
+ DCHECK(req.callback);
+ std::move(req.callback).Run(handle);
return;
}
}
NOTREACHED();
}
- // ui::mojom::GpuService:
- void EstablishGpuChannel(
- int32_t client_id,
- uint64_t client_tracing_id,
- bool is_gpu_host,
- const EstablishGpuChannelCallback& callback) override {}
+ // mojom::GpuService:
+ void EstablishGpuChannel(int32_t client_id,
+ uint64_t client_tracing_id,
+ bool is_gpu_host,
+ EstablishGpuChannelCallback callback) override {}
void CloseChannel(int32_t client_id) override {}
void CreateJpegDecodeAccelerator(
media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override {}
- void CreateVideoEncodeAccelerator(
- media::mojom::VideoEncodeAcceleratorRequest vea_request) override {}
+ void CreateVideoEncodeAcceleratorProvider(
+ media::mojom::VideoEncodeAcceleratorProviderRequest request) override {}
- void CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle,
- const CreateGpuMemoryBufferCallback& callback) override {
+ void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ int client_id,
+ gpu::SurfaceHandle surface_handle,
+ CreateGpuMemoryBufferCallback callback) override {
allocation_requests_.push_back(
- {id, size, format, usage, client_id, callback});
+ {id, size, format, usage, client_id, std::move(callback)});
}
void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
@@ -83,16 +82,16 @@ class TestGpuService : public ui::mojom::GpuService {
}
void GetVideoMemoryUsageStats(
- const GetVideoMemoryUsageStatsCallback& callback) override {}
+ GetVideoMemoryUsageStatsCallback callback) override {}
void RequestCompleteGpuInfo(
- const RequestCompleteGpuInfoCallback& callback) override {}
+ RequestCompleteGpuInfoCallback callback) override {}
void LoadedShader(const std::string& key, const std::string& data) override {}
void DestroyingVideoSurface(
int32_t surface_id,
- const DestroyingVideoSurfaceCallback& callback) override {}
+ DestroyingVideoSurfaceCallback callback) override {}
void WakeUpGpu() override {}
@@ -106,7 +105,7 @@ class TestGpuService : public ui::mojom::GpuService {
void ThrowJavaException() override {}
- void Stop(const StopCallback& callback) override {}
+ void Stop(StopCallback callback) override {}
private:
struct AllocationRequest {
@@ -115,7 +114,7 @@ class TestGpuService : public ui::mojom::GpuService {
const gfx::BufferFormat format;
const gfx::BufferUsage usage;
const int client_id;
- const CreateGpuMemoryBufferCallback callback;
+ CreateGpuMemoryBufferCallback callback;
};
std::vector<AllocationRequest> allocation_requests_;
@@ -160,6 +159,28 @@ class ServerGpuMemoryBufferManagerTest : public ::testing::Test {
ServerGpuMemoryBufferManagerTest() = default;
~ServerGpuMemoryBufferManagerTest() override = default;
+ std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferSync(
+ ServerGpuMemoryBufferManager* manager) {
+ base::Thread diff_thread("TestThread");
+ diff_thread.Start();
+ std::unique_ptr<gfx::GpuMemoryBuffer> buffer;
+ base::RunLoop run_loop;
+ diff_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(
+ [](ServerGpuMemoryBufferManager* manager,
+ std::unique_ptr<gfx::GpuMemoryBuffer>* out_buffer,
+ const base::Closure& callback) {
+ *out_buffer = manager->CreateGpuMemoryBuffer(
+ gfx::Size(64, 64), gfx::BufferFormat::YVU_420,
+ gfx::BufferUsage::GPU_READ,
+ gpu::kNullSurfaceHandle);
+ callback.Run();
+ },
+ manager, &buffer, run_loop.QuitClosure()));
+ run_loop.Run();
+ return buffer;
+ }
+
// ::testing::Test:
void SetUp() override {
gfx::ClientNativePixmapFactory::ResetInstance();
@@ -265,24 +286,25 @@ TEST_F(ServerGpuMemoryBufferManagerTest, GpuMemoryBufferDestroyed) {
gfx::ClientNativePixmapFactory::ResetInstance();
TestGpuService gpu_service;
ServerGpuMemoryBufferManager manager(&gpu_service, 1);
- base::Thread diff_thread("TestThread");
- ASSERT_TRUE(diff_thread.Start());
- std::unique_ptr<gfx::GpuMemoryBuffer> buffer;
- base::RunLoop run_loop;
- ASSERT_TRUE(diff_thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(
- [](ServerGpuMemoryBufferManager* manager,
- std::unique_ptr<gfx::GpuMemoryBuffer>* out_buffer,
- const base::Closure& callback) {
- *out_buffer = manager->CreateGpuMemoryBuffer(
- gfx::Size(64, 64), gfx::BufferFormat::YVU_420,
- gfx::BufferUsage::GPU_READ, gpu::kNullSurfaceHandle);
- callback.Run();
- },
- &manager, &buffer, run_loop.QuitClosure())));
- run_loop.Run();
+ auto buffer = AllocateGpuMemoryBufferSync(&manager);
EXPECT_TRUE(buffer);
buffer.reset();
}
+TEST_F(ServerGpuMemoryBufferManagerTest,
+ GpuMemoryBufferDestroyedOnDifferentThread) {
+ gfx::ClientNativePixmapFactory::ResetInstance();
+ TestGpuService gpu_service;
+ ServerGpuMemoryBufferManager manager(&gpu_service, 1);
+ auto buffer = AllocateGpuMemoryBufferSync(&manager);
+ EXPECT_TRUE(buffer);
+ // Destroy the buffer in a different thread.
+ base::Thread diff_thread("DestroyThread");
+ ASSERT_TRUE(diff_thread.Start());
+ diff_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind([](std::unique_ptr<gfx::GpuMemoryBuffer> buffer) {},
+ base::Passed(&buffer)));
+ diff_thread.Stop();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/presubmit_checks.py b/chromium/components/viz/presubmit_checks.py
new file mode 100644
index 00000000000..da6c89dbc10
--- /dev/null
+++ b/chromium/components/viz/presubmit_checks.py
@@ -0,0 +1,339 @@
+# 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.
+
+"""Presubmit checks used in viz"""
+
+import re
+import string
+
+def CheckChangeLintsClean(input_api, output_api, white_list, black_list=None):
+ source_filter = lambda x: input_api.FilterSourceFile(
+ x, white_list=white_list, black_list=black_list)
+
+ return input_api.canned_checks.CheckChangeLintsClean(
+ input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+
+def CheckAsserts(input_api, output_api, white_list, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list)
+
+ assert_files = []
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ # WebKit ASSERT() is not allowed.
+ if re.search(r"\bASSERT\(", contents):
+ assert_files.append(f.LocalPath())
+
+ if assert_files:
+ return [output_api.PresubmitError(
+ 'These files use ASSERT instead of using DCHECK:',
+ items=assert_files)]
+ return []
+
+def CheckStdAbs(input_api, output_api,
+ white_list, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+
+ using_std_abs_files = []
+ found_fabs_files = []
+ missing_std_prefix_files = []
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if re.search(r"using std::f?abs;", contents):
+ using_std_abs_files.append(f.LocalPath())
+ if re.search(r"\bfabsf?\(", contents):
+ found_fabs_files.append(f.LocalPath());
+
+ no_std_prefix = r"(?<!std::)"
+ # Matches occurrences of abs/absf/fabs/fabsf without a "std::" prefix.
+ abs_without_prefix = r"%s(\babsf?\()" % no_std_prefix
+ fabs_without_prefix = r"%s(\bfabsf?\()" % no_std_prefix
+ # Skips matching any lines that have "// NOLINT".
+ no_nolint = r"(?![^\n]*//\s+NOLINT)"
+
+ expression = re.compile("(%s|%s)%s" %
+ (abs_without_prefix, fabs_without_prefix, no_nolint))
+ if expression.search(contents):
+ missing_std_prefix_files.append(f.LocalPath())
+
+ result = []
+ if using_std_abs_files:
+ result.append(output_api.PresubmitError(
+ 'These files have "using std::abs" which is not permitted.',
+ items=using_std_abs_files))
+ if found_fabs_files:
+ result.append(output_api.PresubmitError(
+ 'std::abs() should be used instead of std::fabs() for consistency.',
+ items=found_fabs_files))
+ if missing_std_prefix_files:
+ result.append(output_api.PresubmitError(
+ 'These files use abs(), absf(), fabs(), or fabsf() without qualifying '
+ 'the std namespace. Please use std::abs() in all places.',
+ items=missing_std_prefix_files))
+ return result
+
+def CheckPassByValue(input_api,
+ output_api,
+ white_list,
+ black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+
+ local_errors = []
+
+ # Well-defined simple classes the same size as a primitive type.
+ pass_by_value_types = ['base::Time',
+ 'base::TimeTicks',
+ ]
+
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ match = re.search(
+ r'\bconst +' + '(?P<type>(%s))&' %
+ string.join(pass_by_value_types, '|'),
+ contents)
+ if match:
+ local_errors.append(output_api.PresubmitError(
+ '%s passes %s by const ref instead of by value.' %
+ (f.LocalPath(), match.group('type'))))
+ return local_errors
+
+def CheckTodos(input_api, output_api):
+ errors = []
+
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if ('FIX'+'ME') in contents:
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError(
+ 'All TODO comments should be of the form TODO(name/bug). ' +
+ 'Use TODO instead of FIX' + 'ME',
+ items=errors)]
+ return []
+
+def CheckDoubleAngles(input_api, output_api, white_list,
+ black_list=None):
+ errors = []
+
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if ('> >') in contents:
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError('Use >> instead of > >:', items=errors)]
+ return []
+
+def CheckUniquePtr(input_api, output_api,
+ white_list, black_list=None):
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ errors = []
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ for line_number, line in f.ChangedContents():
+ # Disallow:
+ # return std::unique_ptr<T>(foo);
+ # bar = std::unique_ptr<T>(foo);
+ # But allow:
+ # return std::unique_ptr<T[]>(foo);
+ # bar = std::unique_ptr<T[]>(foo);
+ if re.search(r'(=|\breturn)\s*std::unique_ptr<.*?(?<!])>\([^)]+\)', line):
+ errors.append(output_api.PresubmitError(
+ ('%s:%d uses explicit std::unique_ptr constructor. ' +
+ 'Use base::MakeUnique<T>() instead.') %
+ (f.LocalPath(), line_number)))
+ # Disallow:
+ # std::unique_ptr<T>()
+ if re.search(r'\bstd::unique_ptr<.*?>\(\)', line):
+ errors.append(output_api.PresubmitError(
+ '%s:%d uses std::unique_ptr<T>(). Use nullptr instead.' %
+ (f.LocalPath(), line_number)))
+ return errors
+
+def FindUnquotedQuote(contents, pos):
+ match = re.search(r"(?<!\\)(?P<quote>\")", contents[pos:])
+ return -1 if not match else match.start("quote") + pos
+
+def FindUselessIfdefs(input_api, output_api):
+ errors = []
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if re.search(r'#if\s*0\s', contents):
+ errors.append(f.LocalPath())
+ if errors:
+ return [output_api.PresubmitError(
+ 'Don\'t use #if '+'0; just delete the code.',
+ items=errors)]
+ return []
+
+def FindNamespaceInBlock(pos, namespace, contents, whitelist=[]):
+ open_brace = -1
+ close_brace = -1
+ quote = -1
+ name = -1
+ brace_count = 1
+ quote_count = 0
+ while pos < len(contents) and brace_count > 0:
+ if open_brace < pos: open_brace = contents.find("{", pos)
+ if close_brace < pos: close_brace = contents.find("}", pos)
+ if quote < pos: quote = FindUnquotedQuote(contents, pos)
+ if name < pos: name = contents.find(("%s::" % namespace), pos)
+
+ if name < 0:
+ return False # The namespace is not used at all.
+ if open_brace < 0:
+ open_brace = len(contents)
+ if close_brace < 0:
+ close_brace = len(contents)
+ if quote < 0:
+ quote = len(contents)
+
+ next = min(open_brace, min(close_brace, min(quote, name)))
+
+ if next == open_brace:
+ brace_count += 1
+ elif next == close_brace:
+ brace_count -= 1
+ elif next == quote:
+ quote_count = 0 if quote_count else 1
+ elif next == name and not quote_count:
+ in_whitelist = False
+ for w in whitelist:
+ if re.match(w, contents[next:]):
+ in_whitelist = True
+ break
+ if not in_whitelist:
+ return True
+ pos = next + 1
+ return False
+
+# Checks for the use of viz:: within the viz namespace, which is usually
+# redundant.
+def CheckNamespace(input_api, output_api):
+ errors = []
+
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ match = re.search(r'namespace\s*viz\s*{', contents)
+ if match:
+ whitelist = []
+ if FindNamespaceInBlock(match.end(), 'viz', contents, whitelist=whitelist):
+ errors.append(f.LocalPath())
+
+ if errors:
+ return [output_api.PresubmitError(
+ 'Do not use viz:: inside of the viz namespace.',
+ items=errors)]
+ return []
+
+# Verifies that we use the right module name (viz.mojom) in mojom files and we
+# don't specify module name viz.mojom when referring to types in viz.mojom.
+def CheckMojoms(input_api, output_api):
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ ['.*\.mojom$'],
+ [])
+ wrong_module_name=[]
+ omit_module_name=[]
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if 'module viz.mojom;' not in contents:
+ wrong_module_name.append(f.LocalPath())
+ elif 'viz.mojom.' in contents:
+ omit_module_name.append(f.LocalPath())
+
+ errors=[]
+ if wrong_module_name:
+ errors.append(output_api.PresubmitError(
+ 'Use viz.mojom as the module name in mojom files.',
+ items=wrong_module_name))
+ if omit_module_name:
+ errors.append(output_api.PresubmitError(
+ 'Do not specify module name viz.mojom when referring to types '
+ + 'in the same module.', items=omit_module_name))
+ return errors
+
+def CheckForUseOfWrongClock(input_api,
+ output_api,
+ white_list,
+ black_list=None):
+ """Make sure new lines of code don't use a clock susceptible to skew."""
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ # Regular expression that should detect any explicit references to the
+ # base::Time type (or base::Clock/DefaultClock), whether in using decls,
+ # typedefs, or to call static methods.
+ base_time_type_pattern = r'(^|\W)base::(Time|Clock|DefaultClock)(\W|$)'
+
+ # Regular expression that should detect references to the base::Time class
+ # members, such as a call to base::Time::Now.
+ base_time_member_pattern = r'(^|\W)(Time|Clock|DefaultClock)::'
+
+ # Regular expression to detect "using base::Time" declarations. We want to
+ # prevent these from triggerring a warning. For example, it's perfectly
+ # reasonable for code to be written like this:
+ #
+ # using base::Time;
+ # ...
+ # int64 foo_us = foo_s * Time::kMicrosecondsPerSecond;
+ using_base_time_decl_pattern = r'^\s*using\s+(::)?base::Time\s*;'
+
+ # Regular expression to detect references to the kXXX constants in the
+ # base::Time class. We want to prevent these from triggerring a warning.
+ base_time_konstant_pattern = r'(^|\W)Time::k\w+'
+
+ problem_re = input_api.re.compile(
+ r'(' + base_time_type_pattern + r')|(' + base_time_member_pattern + r')')
+ exception_re = input_api.re.compile(
+ r'(' + using_base_time_decl_pattern + r')|(' +
+ base_time_konstant_pattern + r')')
+ problems = []
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ for line_number, line in f.ChangedContents():
+ if problem_re.search(line):
+ if not exception_re.search(line):
+ problems.append(
+ ' %s:%d\n %s' % (f.LocalPath(), line_number, line.strip()))
+
+ if problems:
+ return [output_api.PresubmitPromptOrNotify(
+ 'You added one or more references to the base::Time class and/or one\n'
+ 'of its member functions (or base::Clock/DefaultClock). In cc code,\n'
+ 'it is most certainly incorrect! Instead use base::TimeTicks.\n\n'
+ '\n'.join(problems))]
+ else:
+ return []
+
+def RunAllChecks(input_api, output_api, white_list):
+ results = []
+ results += CheckAsserts(input_api, output_api, white_list)
+ results += CheckStdAbs(input_api, output_api, white_list)
+ results += CheckPassByValue(input_api, output_api, white_list)
+ results += CheckChangeLintsClean(input_api, output_api, white_list)
+ results += CheckTodos(input_api, output_api)
+ results += CheckDoubleAngles(input_api, output_api, white_list)
+ results += CheckUniquePtr(input_api, output_api, white_list)
+ results += CheckNamespace(input_api, output_api)
+ results += CheckMojoms(input_api, output_api)
+ results += CheckForUseOfWrongClock(input_api, output_api, white_list)
+ results += FindUselessIfdefs(input_api, output_api)
+ return results
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index 22a0b3cdc14..de26799be63 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -10,11 +10,29 @@ config("viz_service_implementation") {
viz_component("service") {
sources = [
+ "display/color_lut_cache.cc",
+ "display/color_lut_cache.h",
"display/display.cc",
"display/display.h",
"display/display_client.h",
"display/display_scheduler.cc",
"display/display_scheduler.h",
+ "display/dynamic_geometry_binding.cc",
+ "display/dynamic_geometry_binding.h",
+ "display/geometry_binding.cc",
+ "display/geometry_binding.h",
+ "display/gl_renderer.cc",
+ "display/gl_renderer.h",
+ "display/gl_renderer_draw_cache.cc",
+ "display/gl_renderer_draw_cache.h",
+ "display/program_binding.cc",
+ "display/program_binding.h",
+ "display/shader.cc",
+ "display/shader.h",
+ "display/skia_renderer.cc",
+ "display/skia_renderer.h",
+ "display/static_geometry_binding.cc",
+ "display/static_geometry_binding.h",
"display/surface_aggregator.cc",
"display/surface_aggregator.h",
"display_embedder/buffer_queue.cc",
@@ -31,6 +49,8 @@ viz_component("service") {
"display_embedder/server_shared_bitmap_manager.h",
"display_embedder/shared_bitmap_allocation_notifier_impl.cc",
"display_embedder/shared_bitmap_allocation_notifier_impl.h",
+ "frame_sinks/compositor_frame_sink_impl.cc",
+ "frame_sinks/compositor_frame_sink_impl.h",
"frame_sinks/compositor_frame_sink_support.cc",
"frame_sinks/compositor_frame_sink_support.h",
"frame_sinks/compositor_frame_sink_support_client.h",
@@ -44,19 +64,37 @@ viz_component("service") {
"frame_sinks/frame_sink_manager_client.h",
"frame_sinks/frame_sink_manager_impl.cc",
"frame_sinks/frame_sink_manager_impl.h",
- "frame_sinks/gpu_compositor_frame_sink.cc",
- "frame_sinks/gpu_compositor_frame_sink.h",
- "frame_sinks/gpu_root_compositor_frame_sink.cc",
- "frame_sinks/gpu_root_compositor_frame_sink.h",
"frame_sinks/primary_begin_frame_source.cc",
"frame_sinks/primary_begin_frame_source.h",
"frame_sinks/referenced_surface_tracker.cc",
"frame_sinks/referenced_surface_tracker.h",
+ "frame_sinks/root_compositor_frame_sink_impl.cc",
+ "frame_sinks/root_compositor_frame_sink_impl.h",
"frame_sinks/surface_resource_holder.cc",
"frame_sinks/surface_resource_holder.h",
"frame_sinks/surface_resource_holder_client.h",
+ "gl/gpu_service_impl.cc",
+ "gl/gpu_service_impl.h",
"hit_test/hit_test_aggregator.cc",
"hit_test/hit_test_aggregator.h",
+ "hit_test/hit_test_aggregator_delegate.h",
+ "surfaces/direct_surface_reference_factory.cc",
+ "surfaces/direct_surface_reference_factory.h",
+ "surfaces/surface.cc",
+ "surfaces/surface.h",
+ "surfaces/surface_client.h",
+ "surfaces/surface_deadline_observer.h",
+ "surfaces/surface_dependency_deadline.cc",
+ "surfaces/surface_dependency_deadline.h",
+ "surfaces/surface_dependency_tracker.cc",
+ "surfaces/surface_dependency_tracker.h",
+ "surfaces/surface_hittest.cc",
+ "surfaces/surface_hittest.h",
+ "surfaces/surface_hittest_delegate.h",
+ "surfaces/surface_manager.cc",
+ "surfaces/surface_manager.h",
+ "surfaces/surface_reference.cc",
+ "surfaces/surface_reference.h",
"viz_service_export.h",
]
@@ -72,6 +110,10 @@ viz_component("service") {
"//gpu/ipc/client",
"//gpu/ipc/service",
"//gpu/vulkan:features",
+ "//media",
+ "//media/gpu/ipc/service",
+ "//media/mojo/services",
+ "//services/ui/gpu/interfaces",
"//skia",
"//ui/display/types",
]
@@ -79,11 +121,12 @@ viz_component("service") {
public_deps = [
"//base",
"//cc",
+ "//cc/debug",
"//cc/ipc:interfaces",
- "//cc/surfaces",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/ipc:command_buffer",
- "//services/viz/hit_test/public/interfaces",
+ "//services/viz/privileged/interfaces/compositing",
+ "//services/viz/public/interfaces",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/latency",
@@ -127,6 +170,8 @@ viz_source_set("unit_tests") {
sources = [
"display/display_scheduler_unittest.cc",
"display/display_unittest.cc",
+ "display/gl_renderer_unittest.cc",
+ "display/shader_unittest.cc",
"display/surface_aggregator_pixeltest.cc",
"display/surface_aggregator_unittest.cc",
"display_embedder/buffer_queue_unittest.cc",
@@ -137,7 +182,10 @@ viz_source_set("unit_tests") {
"frame_sinks/referenced_surface_tracker_unittest.cc",
"frame_sinks/surface_references_unittest.cc",
"frame_sinks/surface_synchronization_unittest.cc",
+ "gl/gpu_service_impl_unittest.cc",
"hit_test/hit_test_aggregator_unittest.cc",
+ "surfaces/surface_hittest_unittest.cc",
+ "surfaces/surface_unittest.cc",
]
if (!use_aura && !is_mac) {
@@ -155,11 +203,14 @@ viz_source_set("unit_tests") {
"//base/test:test_support",
"//cc:test_support",
"//components/viz/common",
+ "//components/viz/host",
+ "//components/viz/test:test_support",
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_implementation",
"//gpu/ipc:gl_in_process_context",
"//media",
- "//services/viz/hit_test/public/interfaces",
+ "//services/ui/public/interfaces",
+ "//services/viz/public/interfaces",
"//skia",
"//testing/gmock",
"//testing/gtest",
@@ -178,6 +229,7 @@ viz_source_set("perf_tests") {
"//base",
"//cc:test_support",
"//cc/base",
+ "//components/viz/test:test_support",
"//testing/gtest",
"//testing/perf",
]
diff --git a/chromium/components/viz/service/DEPS b/chromium/components/viz/service/DEPS
index 19ccf893a16..68254d64874 100644
--- a/chromium/components/viz/service/DEPS
+++ b/chromium/components/viz/service/DEPS
@@ -1,8 +1,15 @@
include_rules = [
"+cc",
+ "-components/viz/common/switches.h",
"+components/viz/service",
+ "+services/viz/privileged/interfaces",
+ "+services/viz/public/interfaces",
"+third_party/skia",
- "+ui/gfx",
- "+ui/gfx/geometry",
"+ui/latency",
]
+
+specific_include_rules = {
+ ".*_unittest\.cc": [
+ "+components/viz/test",
+ ]
+}
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index e8ecaf1670f..e0ec6c36551 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -6,12 +6,14 @@ include_rules = [
"+cc/quads",
"+cc/resources",
"+cc/scheduler",
- "+cc/surfaces",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
+ "+gpu/GLES2",
"+gpu/vulkan",
+ "+media/base",
+ "+skia",
"+third_party/skia",
- "+ui/gfx",
+ "+third_party/khronos",
"+ui/latency",
]
@@ -19,6 +21,7 @@ specific_include_rules = {
".*_(unit|pixel|perf)test\.cc": [
"+cc/test",
"+components/viz/service/frame_sinks",
+ "+components/viz/test",
"+gpu/GLES2",
],
}
diff --git a/chromium/components/viz/service/display/color_lut_cache.cc b/chromium/components/viz/service/display/color_lut_cache.cc
new file mode 100644
index 00000000000..38d1a8ca0bf
--- /dev/null
+++ b/chromium/components/viz/service/display/color_lut_cache.cc
@@ -0,0 +1,134 @@
+// 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/viz/service/display/color_lut_cache.h"
+
+#include <stdint.h>
+#include <cmath>
+#include <vector>
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/color_transform.h"
+#include "ui/gfx/half_float.h"
+
+// After a LUT has not been used for this many frames, we release it.
+const uint32_t kMaxFramesUnused = 10;
+
+ColorLUTCache::ColorLUTCache(gpu::gles2::GLES2Interface* gl,
+ bool texture_half_float_linear)
+ : lut_cache_(0),
+ gl_(gl),
+ texture_half_float_linear_(texture_half_float_linear) {}
+
+ColorLUTCache::~ColorLUTCache() {
+ GLuint textures[10];
+ size_t n = 0;
+ for (const auto& cache_entry : lut_cache_) {
+ textures[n++] = cache_entry.second.lut.texture;
+ if (n == arraysize(textures)) {
+ gl_->DeleteTextures(n, textures);
+ n = 0;
+ }
+ }
+ if (n)
+ gl_->DeleteTextures(n, textures);
+}
+
+namespace {
+
+void FloatToLUT(const float* f, gfx::HalfFloat* out, size_t num) {
+ gfx::FloatToHalfFloat(f, out, num);
+}
+
+void FloatToLUT(float* f, unsigned char* out, size_t num) {
+ for (size_t i = 0; i < num; i++) {
+ out[i] = std::min<int>(255, std::max<int>(0, floorf(f[i] * 255.0f + 0.5f)));
+ }
+}
+
+} // namespace
+
+template <typename T>
+unsigned int ColorLUTCache::MakeLUT(const gfx::ColorTransform* transform,
+ int lut_samples) {
+ int lut_entries = lut_samples * lut_samples * lut_samples;
+ float inverse = 1.0f / (lut_samples - 1);
+ std::vector<T> lut(lut_entries * 4);
+ std::vector<gfx::ColorTransform::TriStim> samples(lut_samples);
+ T* lutp = lut.data();
+ float one = 1.0f;
+ T alpha;
+ FloatToLUT(&one, &alpha, 1);
+ for (int v = 0; v < lut_samples; v++) {
+ for (int u = 0; u < lut_samples; u++) {
+ for (int y = 0; y < lut_samples; y++) {
+ samples[y].set_x(y * inverse);
+ samples[y].set_y(u * inverse);
+ samples[y].set_z(v * inverse);
+ }
+ transform->Transform(samples.data(), samples.size());
+ T* lutp2 = lutp + lut_samples;
+ FloatToLUT(reinterpret_cast<float*>(samples.data()), lutp2,
+ lut_samples * 3);
+ for (int i = 0; i < lut_samples; i++) {
+ *(lutp++) = *(lutp2++);
+ *(lutp++) = *(lutp2++);
+ *(lutp++) = *(lutp2++);
+ *(lutp++) = alpha;
+ }
+ }
+ }
+
+ GLuint previously_bound_texture = 0;
+ GLuint lut_texture = 0;
+ gl_->GetIntegerv(GL_TEXTURE_BINDING_2D,
+ reinterpret_cast<GLint*>(&previously_bound_texture));
+ gl_->GenTextures(1, &lut_texture);
+ gl_->BindTexture(GL_TEXTURE_2D, lut_texture);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ 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_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lut_samples,
+ lut_samples * lut_samples, 0, GL_RGBA,
+ sizeof(T) == 1 ? GL_UNSIGNED_BYTE : GL_HALF_FLOAT_OES,
+ lut.data());
+ gl_->BindTexture(GL_TEXTURE_2D, previously_bound_texture);
+ return lut_texture;
+}
+
+ColorLUTCache::LUT ColorLUTCache::GetLUT(const gfx::ColorTransform* transform) {
+ auto iter = lut_cache_.Get(transform);
+ if (iter != lut_cache_.end()) {
+ iter->second.last_used_frame = current_frame_;
+ return iter->second.lut;
+ }
+
+ LUT lut;
+ // If input is HDR, and the output is full range, we're going to need
+ // to produce values outside of 0-1, so we'll need to make a half-float
+ // LUT. Also, we'll need to build a larger lut to maintain accuracy.
+ // All LUT sizes should be odd as some transforms have a knee at 0.5.
+ if (transform->GetDstColorSpace().FullRangeEncodedValues() &&
+ transform->GetSrcColorSpace().IsHDR() && texture_half_float_linear_) {
+ lut.size = 37;
+ lut.texture = MakeLUT<uint16_t>(transform, lut.size);
+ } else {
+ lut.size = 17;
+ lut.texture = MakeLUT<unsigned char>(transform, lut.size);
+ }
+ lut_cache_.Put(transform, CacheVal(lut, current_frame_));
+ return lut;
+}
+
+void ColorLUTCache::Swap() {
+ current_frame_++;
+ while (!lut_cache_.empty() &&
+ current_frame_ - lut_cache_.rbegin()->second.last_used_frame >
+ kMaxFramesUnused) {
+ gl_->DeleteTextures(1, &lut_cache_.rbegin()->second.lut.texture);
+ lut_cache_.ShrinkToSize(lut_cache_.size() - 1);
+ }
+}
diff --git a/chromium/components/viz/service/display/color_lut_cache.h b/chromium/components/viz/service/display/color_lut_cache.h
new file mode 100644
index 00000000000..b437d2b9c49
--- /dev/null
+++ b/chromium/components/viz/service/display/color_lut_cache.h
@@ -0,0 +1,61 @@
+// 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_VIZ_SERVICE_DISPLAY_COLOR_LUT_CACHE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_COLOR_LUT_CACHE_H_
+
+#include <map>
+
+#include "base/containers/mru_cache.h"
+#include "base/macros.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gfx/color_space.h"
+
+namespace gfx {
+class ColorTransform;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
+class VIZ_SERVICE_EXPORT ColorLUTCache {
+ public:
+ explicit ColorLUTCache(gpu::gles2::GLES2Interface* gl,
+ bool texture_half_float_linear);
+ ~ColorLUTCache();
+
+ struct LUT {
+ unsigned int texture;
+ int size;
+ };
+
+ LUT GetLUT(const gfx::ColorTransform* transform);
+
+ // End of frame, assume all LUTs handed out are no longer used.
+ void Swap();
+
+ private:
+ template <typename T>
+ unsigned int MakeLUT(const gfx::ColorTransform* transform, int lut_samples);
+
+ typedef const gfx::ColorTransform* CacheKey;
+
+ struct CacheVal {
+ CacheVal(LUT lut, uint32_t last_used_frame)
+ : lut(lut), last_used_frame(last_used_frame) {}
+ LUT lut;
+ uint32_t last_used_frame;
+ };
+
+ base::MRUCache<CacheKey, CacheVal> lut_cache_;
+ uint32_t current_frame_;
+ gpu::gles2::GLES2Interface* gl_;
+ bool texture_half_float_linear_;
+ DISALLOW_COPY_AND_ASSIGN(ColorLUTCache);
+};
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_COLOR_LUT_CACHE_H_
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index 2af77eaa229..8bb2de60980 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -13,16 +13,18 @@
#include "cc/benchmarks/benchmark_instrumentation.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/direct_renderer.h"
-#include "cc/output/gl_renderer.h"
+#include "cc/output/output_surface.h"
#include "cc/output/software_renderer.h"
#include "cc/output/texture_mailbox_deleter.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.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_client.h"
#include "components/viz/service/display/display_scheduler.h"
+#include "components/viz/service/display/gl_renderer.h"
+#include "components/viz/service/display/skia_renderer.h"
#include "components/viz/service/display/surface_aggregator.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/vulkan/features.h"
#include "ui/gfx/buffer_types.h"
@@ -64,7 +66,7 @@ Display::~Display() {
}
if (aggregator_) {
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
- cc::Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
+ Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
if (surface)
surface->RunDrawCallback();
}
@@ -72,7 +74,7 @@ Display::~Display() {
}
void Display::Initialize(DisplayClient* client,
- cc::SurfaceManager* surface_manager) {
+ SurfaceManager* surface_manager) {
DCHECK(client);
DCHECK(surface_manager);
client_ = client;
@@ -95,6 +97,14 @@ void Display::Initialize(DisplayClient* client,
}
}
+void Display::AddObserver(DisplayObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void Display::RemoveObserver(DisplayObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
void Display::SetLocalSurfaceId(const LocalSurfaceId& id,
float device_scale_factor) {
if (current_surface_id_.local_surface_id() == id &&
@@ -173,16 +183,21 @@ void Display::SetOutputIsSecure(bool secure) {
void Display::InitializeRenderer() {
// Not relevant for display compositor since it's not delegated.
constexpr bool delegated_sync_points_required = false;
- resource_provider_ = base::MakeUnique<cc::ResourceProvider>(
+ resource_provider_ = base::MakeUnique<cc::DisplayResourceProvider>(
output_surface_->context_provider(), bitmap_manager_,
gpu_memory_buffer_manager_, nullptr, delegated_sync_points_required,
settings_.enable_color_correct_rendering, settings_.resource_settings);
if (output_surface_->context_provider()) {
DCHECK(texture_mailbox_deleter_);
- renderer_ = base::MakeUnique<cc::GLRenderer>(
- &settings_, output_surface_.get(), resource_provider_.get(),
- texture_mailbox_deleter_.get());
+ if (!settings_.use_skia_renderer) {
+ renderer_ = base::MakeUnique<GLRenderer>(
+ &settings_, output_surface_.get(), resource_provider_.get(),
+ texture_mailbox_deleter_.get());
+ } else {
+ renderer_ = base::MakeUnique<SkiaRenderer>(
+ &settings_, output_surface_.get(), resource_provider_.get());
+ }
} else if (output_surface_->vulkan_context_provider()) {
#if defined(ENABLE_VULKAN)
DCHECK(texture_mailbox_deleter_);
@@ -213,7 +228,7 @@ void Display::InitializeRenderer() {
}
void Display::UpdateRootSurfaceResourcesLocked() {
- cc::Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id_);
+ Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id_);
bool root_surface_resources_locked = !surface || !surface->HasActiveFrame();
if (scheduler_)
scheduler_->SetRootSurfaceResourcesLocked(root_surface_resources_locked);
@@ -253,7 +268,7 @@ bool Display::DrawAndSwap() {
// Run callbacks early to allow pipelining.
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
- cc::Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
+ Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
if (surface)
surface->RunDrawCallback();
}
@@ -376,19 +391,19 @@ void Display::DidReceiveTextureInUseResponses(
void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
aggregator_->SetFullDamageForSurface(current_surface_id_);
if (scheduler_) {
- cc::BeginFrameAck ack;
+ BeginFrameAck ack;
ack.has_damage = true;
scheduler_->ProcessSurfaceDamage(current_surface_id_, ack, true);
}
}
bool Display::SurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) {
+ const BeginFrameAck& ack) {
bool display_damaged = false;
if (ack.has_damage) {
if (aggregator_ &&
aggregator_->previous_contained_surfaces().count(surface_id)) {
- cc::Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
+ Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
if (surface) {
DCHECK(surface->HasActiveFrame());
if (surface->GetActiveFrame().resource_list.empty())
@@ -415,13 +430,18 @@ bool Display::SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const {
if (!surface_manager_)
return false;
- cc::Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
+ Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
if (!surface)
return false;
return surface->HasUndrawnActiveFrame();
}
+void Display::DidFinishFrame(const BeginFrameAck& ack) {
+ for (auto& observer : observers_)
+ observer.OnDisplayDidFinishFrame(ack);
+}
+
const SurfaceId& Display::CurrentSurfaceId() {
return current_surface_id_;
}
diff --git a/chromium/components/viz/service/display/display.h b/chromium/components/viz/service/display/display.h
index 33f4a3f0123..553995ab96e 100644
--- a/chromium/components/viz/service/display/display.h
+++ b/chromium/components/viz/service/display/display.h
@@ -9,14 +9,16 @@
#include <vector>
#include "base/macros.h"
+#include "base/observer_list.h"
#include "cc/output/output_surface_client.h"
-#include "cc/resources/returned_resource.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_manager.h"
+#include "cc/resources/display_resource_provider.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#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_scheduler.h"
#include "components/viz/service/display/surface_aggregator.h"
+#include "components/viz/service/surfaces/surface_manager.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "ui/gfx/color_space.h"
@@ -24,9 +26,9 @@
namespace cc {
class DirectRenderer;
+class DisplayResourceProvider;
class OutputSurface;
class RendererSettings;
-class ResourceProvider;
class SoftwareRenderer;
class TextureMailboxDeleter;
} // namespace cc
@@ -44,6 +46,13 @@ namespace viz {
class DisplayClient;
class SharedBitmapManager;
+class VIZ_SERVICE_EXPORT DisplayObserver {
+ public:
+ virtual ~DisplayObserver() {}
+
+ virtual void OnDisplayDidFinishFrame(const BeginFrameAck& ack) = 0;
+};
+
// A Display produces a surface that can be used to draw to a physical display
// (OutputSurface). The client is responsible for creating and sizing the
// surface IDs used to draw into the display and deciding when to draw.
@@ -62,7 +71,10 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
~Display() override;
- void Initialize(DisplayClient* client, cc::SurfaceManager* surface_manager);
+ void Initialize(DisplayClient* client, SurfaceManager* surface_manager);
+
+ void AddObserver(DisplayObserver* observer);
+ void RemoveObserver(DisplayObserver* observer);
// device_scale_factor is used to communicate to the external window system
// what scale this was rendered at.
@@ -79,8 +91,9 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
bool DrawAndSwap() override;
bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const override;
bool SurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) override;
+ const BeginFrameAck& ack) override;
void SurfaceDiscarded(const SurfaceId& surface_id) override;
+ void DidFinishFrame(const BeginFrameAck& ack) override;
// OutputSurfaceClient implementation.
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
@@ -106,7 +119,8 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
const RendererSettings settings_;
DisplayClient* client_ = nullptr;
- cc::SurfaceManager* surface_manager_ = nullptr;
+ base::ObserverList<DisplayObserver> observers_;
+ SurfaceManager* surface_manager_ = nullptr;
const FrameSinkId frame_sink_id_;
SurfaceId current_surface_id_;
gfx::Size current_surface_size_;
@@ -119,7 +133,7 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
std::unique_ptr<cc::OutputSurface> output_surface_;
std::unique_ptr<DisplayScheduler> scheduler_;
- std::unique_ptr<cc::ResourceProvider> resource_provider_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
std::unique_ptr<cc::TextureMailboxDeleter> texture_mailbox_deleter_;
std::unique_ptr<cc::DirectRenderer> renderer_;
diff --git a/chromium/components/viz/service/display/display_scheduler.cc b/chromium/components/viz/service/display/display_scheduler.cc
index 647554967a2..012e3900498 100644
--- a/chromium/components/viz/service/display/display_scheduler.cc
+++ b/chromium/components/viz/service/display/display_scheduler.cc
@@ -14,7 +14,7 @@
namespace viz {
-DisplayScheduler::DisplayScheduler(cc::BeginFrameSource* begin_frame_source,
+DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source,
base::SingleThreadTaskRunner* task_runner,
int max_pending_swaps,
bool wait_for_all_surfaces_before_draw)
@@ -87,7 +87,7 @@ void DisplayScheduler::DisplayResized() {
void DisplayScheduler::SetNewRootSurface(const SurfaceId& root_surface_id) {
TRACE_EVENT0("viz", "DisplayScheduler::SetNewRootSurface");
root_surface_id_ = root_surface_id;
- cc::BeginFrameAck ack;
+ BeginFrameAck ack;
ack.has_damage = true;
ProcessSurfaceDamage(root_surface_id, ack, true);
}
@@ -96,7 +96,7 @@ void DisplayScheduler::SetNewRootSurface(const SurfaceId& root_surface_id) {
// Has some logic to wait for multiple active surfaces before
// triggering the deadline.
void DisplayScheduler::ProcessSurfaceDamage(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack,
+ const BeginFrameAck& ack,
bool display_damaged) {
TRACE_EVENT1("viz", "DisplayScheduler::SurfaceDamaged", "surface_id",
surface_id.ToString());
@@ -116,8 +116,7 @@ void DisplayScheduler::ProcessSurfaceDamage(const SurfaceId& surface_id,
}
// Update surface state.
- bool valid_ack =
- ack.sequence_number != cc::BeginFrameArgs::kInvalidFrameNumber;
+ bool valid_ack = ack.sequence_number != BeginFrameArgs::kInvalidFrameNumber;
if (valid_ack) {
auto it = surface_states_.find(surface_id);
if (it != surface_states_.end())
@@ -201,7 +200,7 @@ bool DisplayScheduler::DrawAndSwap() {
return true;
}
-bool DisplayScheduler::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
+bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) {
base::TimeTicks now = base::TimeTicks::Now();
TRACE_EVENT2("viz", "DisplayScheduler::BeginFrame", "args", args.AsValue(),
"now", now);
@@ -211,7 +210,7 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
// callstack. Otherwise we end up running unexpected scheduler actions
// immediately while inside some other action (such as submitting a
// CompositorFrame for a SurfaceFactory).
- DCHECK_EQ(args.type, cc::BeginFrameArgs::MISSED);
+ DCHECK_EQ(args.type, BeginFrameArgs::MISSED);
DCHECK(missed_begin_frame_task_.IsCancelled());
missed_begin_frame_task_.Reset(base::Bind(
base::IgnoreResult(&DisplayScheduler::OnBeginFrameDerivedImpl),
@@ -225,7 +224,7 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
// Save the |BeginFrameArgs| as the callback (missed_begin_frame_task_) can be
// destroyed if we StopObservingBeginFrames(), and it would take the |args|
// with it. Instead save the args and cancel the |missed_begin_frame_task_|.
- cc::BeginFrameArgs save_args = args;
+ BeginFrameArgs save_args = args;
// If we get another BeginFrame before a posted missed frame, just drop the
// missed frame. Also if this was the missed frame, drop the Callback inside
// it.
@@ -239,7 +238,7 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) {
// Schedule the deadline.
current_begin_frame_args_ = save_args;
current_begin_frame_args_.deadline -=
- cc::BeginFrameArgs::DefaultEstimatedParentDrawTime();
+ BeginFrameArgs::DefaultEstimatedParentDrawTime();
inside_begin_frame_deadline_interval_ = true;
UpdateHasPendingSurfaces();
ScheduleBeginFrameDeadline();
@@ -278,7 +277,10 @@ void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) {
NOTIMPLEMENTED();
}
-void DisplayScheduler::OnSurfaceCreated(const SurfaceInfo& surface_info) {}
+void DisplayScheduler::OnFirstSurfaceActivation(
+ const SurfaceInfo& surface_info) {}
+
+void DisplayScheduler::OnSurfaceActivated(const SurfaceId& surface_id) {}
void DisplayScheduler::OnSurfaceDestroyed(const SurfaceId& surface_id) {
auto it = surface_states_.find(surface_id);
@@ -290,7 +292,7 @@ void DisplayScheduler::OnSurfaceDestroyed(const SurfaceId& surface_id) {
}
bool DisplayScheduler::OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) {
+ const BeginFrameAck& ack) {
bool damaged = client_->SurfaceDamaged(surface_id, ack);
ProcessSurfaceDamage(surface_id, ack, damaged);
@@ -302,7 +304,7 @@ void DisplayScheduler::OnSurfaceDiscarded(const SurfaceId& surface_id) {
}
void DisplayScheduler::OnSurfaceDamageExpected(const SurfaceId& surface_id,
- const cc::BeginFrameArgs& args) {
+ const BeginFrameArgs& args) {
TRACE_EVENT1("viz", "DisplayScheduler::SurfaceDamageExpected", "surface_id",
surface_id.ToString());
// Insert a new state for the surface if we don't know of it yet. We don't use
@@ -472,8 +474,11 @@ void DisplayScheduler::OnBeginFrameDeadline() {
void DisplayScheduler::DidFinishFrame(bool did_draw) {
DCHECK(begin_frame_source_);
- // TODO(eseckler): Let client know that frame was completed.
begin_frame_source_->DidFinishFrame(this);
+
+ BeginFrameAck ack(current_begin_frame_args_.source_id,
+ current_begin_frame_args_.sequence_number, did_draw);
+ client_->DidFinishFrame(ack);
}
void DisplayScheduler::DidSwapBuffers() {
diff --git a/chromium/components/viz/service/display/display_scheduler.h b/chromium/components/viz/service/display/display_scheduler.h
index 652208db836..3e82f91c389 100644
--- a/chromium/components/viz/service/display/display_scheduler.h
+++ b/chromium/components/viz/service/display/display_scheduler.h
@@ -12,10 +12,10 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_observer.h"
#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
@@ -30,14 +30,15 @@ class VIZ_SERVICE_EXPORT DisplaySchedulerClient {
virtual bool DrawAndSwap() = 0;
virtual bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const = 0;
virtual bool SurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) = 0;
+ const BeginFrameAck& ack) = 0;
virtual void SurfaceDiscarded(const SurfaceId& surface_id) = 0;
+ virtual void DidFinishFrame(const BeginFrameAck& ack) = 0;
};
-class VIZ_SERVICE_EXPORT DisplayScheduler : public cc::BeginFrameObserverBase,
- public cc::SurfaceObserver {
+class VIZ_SERVICE_EXPORT DisplayScheduler : public BeginFrameObserverBase,
+ public SurfaceObserver {
public:
- DisplayScheduler(cc::BeginFrameSource* begin_frame_source,
+ DisplayScheduler(BeginFrameSource* begin_frame_source,
base::SingleThreadTaskRunner* task_runner,
int max_pending_swaps,
bool wait_for_all_surfaces_before_draw = false);
@@ -51,7 +52,7 @@ class VIZ_SERVICE_EXPORT DisplayScheduler : public cc::BeginFrameObserverBase,
virtual void DisplayResized();
virtual void SetNewRootSurface(const SurfaceId& root_surface_id);
virtual void ProcessSurfaceDamage(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack,
+ const BeginFrameAck& ack,
bool display_damaged);
virtual void DidSwapBuffers();
@@ -60,17 +61,18 @@ class VIZ_SERVICE_EXPORT DisplayScheduler : public cc::BeginFrameObserverBase,
void OutputSurfaceLost();
// BeginFrameObserverBase implementation.
- bool OnBeginFrameDerivedImpl(const cc::BeginFrameArgs& args) override;
+ bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override;
void OnBeginFrameSourcePausedChanged(bool paused) override;
// SurfaceObserver implementation.
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
+ void OnSurfaceActivated(const SurfaceId& surface_id) override;
void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
bool OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) override;
+ const BeginFrameAck& ack) override;
void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
void OnSurfaceDamageExpected(const SurfaceId& surface_id,
- const cc::BeginFrameArgs& args) override;
+ const BeginFrameArgs& args) override;
void OnSurfaceWillDraw(const SurfaceId& surface_id) override;
protected:
@@ -90,10 +92,10 @@ class VIZ_SERVICE_EXPORT DisplayScheduler : public cc::BeginFrameObserverBase,
bool UpdateHasPendingSurfaces();
DisplaySchedulerClient* client_;
- cc::BeginFrameSource* begin_frame_source_;
+ BeginFrameSource* begin_frame_source_;
base::SingleThreadTaskRunner* task_runner_;
- cc::BeginFrameArgs current_begin_frame_args_;
+ BeginFrameArgs current_begin_frame_args_;
base::Closure begin_frame_deadline_closure_;
base::CancelableClosure begin_frame_deadline_task_;
base::TimeTicks begin_frame_deadline_task_time_;
@@ -111,8 +113,8 @@ class VIZ_SERVICE_EXPORT DisplayScheduler : public cc::BeginFrameObserverBase,
bool has_pending_surfaces_;
struct SurfaceBeginFrameState {
- cc::BeginFrameArgs last_args;
- cc::BeginFrameAck last_ack;
+ BeginFrameArgs last_args;
+ BeginFrameAck last_ack;
};
base::flat_map<SurfaceId, SurfaceBeginFrameState> surface_states_;
diff --git a/chromium/components/viz/service/display/display_scheduler_unittest.cc b/chromium/components/viz/service/display/display_scheduler_unittest.cc
index 1f1f84927ba..b69c42b43fb 100644
--- a/chromium/components/viz/service/display/display_scheduler_unittest.cc
+++ b/chromium/components/viz/service/display/display_scheduler_unittest.cc
@@ -9,11 +9,12 @@
#include "base/test/null_task_runner.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/trace_event/trace_event.h"
-#include "cc/output/begin_frame_args.h"
-#include "cc/test/fake_external_begin_frame_source.h"
#include "cc/test/scheduler_test_common.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/display/display.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -46,12 +47,16 @@ class FakeDisplaySchedulerClient : public DisplaySchedulerClient {
}
bool SurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) override {
+ const BeginFrameAck& ack) override {
return false;
}
void SurfaceDiscarded(const SurfaceId& surface_id) override {}
+ void DidFinishFrame(const BeginFrameAck& ack) override {
+ last_begin_frame_ack_ = ack;
+ }
+
int draw_and_swap_count() const { return draw_and_swap_count_; }
void SetNextDrawAndSwapFails() { next_draw_and_swap_fails_ = true; }
@@ -60,16 +65,19 @@ class FakeDisplaySchedulerClient : public DisplaySchedulerClient {
undrawn_surfaces_.insert(surface_id);
}
+ const BeginFrameAck& last_begin_frame_ack() { return last_begin_frame_ack_; }
+
protected:
int draw_and_swap_count_;
bool next_draw_and_swap_fails_;
std::set<SurfaceId> undrawn_surfaces_;
+ BeginFrameAck last_begin_frame_ack_;
};
class TestDisplayScheduler : public DisplayScheduler {
public:
- TestDisplayScheduler(cc::BeginFrameSource* begin_frame_source,
- cc::SurfaceManager* surface_manager,
+ TestDisplayScheduler(BeginFrameSource* begin_frame_source,
+ SurfaceManager* surface_manager,
base::SingleThreadTaskRunner* task_runner,
int max_pending_swaps,
bool wait_for_all_surfaces_before_draw)
@@ -152,18 +160,18 @@ class DisplaySchedulerTest : public testing::Test {
base::SimpleTestTickClock& now_src() { return now_src_; }
FakeDisplaySchedulerClient& client() { return client_; }
DisplayScheduler& scheduler() { return scheduler_; }
- cc::BeginFrameAck AckForCurrentBeginFrame() {
+ BeginFrameAck AckForCurrentBeginFrame() {
DCHECK(last_begin_frame_args_.IsValid());
- return cc::BeginFrameAck(last_begin_frame_args_.source_id,
- last_begin_frame_args_.sequence_number, true);
+ return BeginFrameAck(last_begin_frame_args_.source_id,
+ last_begin_frame_args_.sequence_number, true);
}
- cc::FakeExternalBeginFrameSource fake_begin_frame_source_;
- cc::BeginFrameArgs last_begin_frame_args_;
+ FakeExternalBeginFrameSource fake_begin_frame_source_;
+ BeginFrameArgs last_begin_frame_args_;
base::SimpleTestTickClock now_src_;
scoped_refptr<base::NullTaskRunner> task_runner_;
- cc::SurfaceManager surface_manager_;
+ SurfaceManager surface_manager_;
FakeDisplaySchedulerClient client_;
TestDisplayScheduler scheduler_;
};
@@ -189,7 +197,7 @@ TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilNewRootSurface) {
// Resize on the next begin frame cycle should cause the deadline to wait
// for a new root surface.
AdvanceTimeAndBeginFrameForTest({root_surface_id1});
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
SurfaceDamaged(sid1);
EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.DisplayResized();
@@ -201,7 +209,7 @@ TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilNewRootSurface) {
scheduler_.BeginFrameDeadlineForTest();
// Verify deadline goes back to normal after resize.
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
AdvanceTimeAndBeginFrameForTest({root_surface_id2, sid1});
SurfaceDamaged(sid1);
EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
@@ -229,7 +237,7 @@ TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilDamagedSurface) {
// Resize on the next begin frame cycle should cause the deadline to wait
// for a new root surface.
AdvanceTimeAndBeginFrameForTest({root_surface_id});
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
SurfaceDamaged(sid1);
EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.DisplayResized();
@@ -241,7 +249,7 @@ TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilDamagedSurface) {
// Verify deadline goes back to normal after resize.
AdvanceTimeAndBeginFrameForTest({root_surface_id, sid1});
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
SurfaceDamaged(sid1);
EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
SurfaceDamaged(root_surface_id);
@@ -261,9 +269,11 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
scheduler_.SetVisible(true);
scheduler_.SetNewRootSurface(root_surface_id);
+ EXPECT_EQ(BeginFrameAck(), client_.last_begin_frame_ack());
// Set surface1 as active via SurfaceDamageExpected().
AdvanceTimeAndBeginFrameForTest({sid1});
+ EXPECT_EQ(BeginFrameAck(), client_.last_begin_frame_ack());
// Damage only from surface 2 (inactive) does not trigger deadline early.
SurfaceDamaged(sid2);
@@ -277,6 +287,9 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
EXPECT_GE(now_src().NowTicks(),
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.BeginFrameDeadlineForTest();
+ EXPECT_EQ(BeginFrameAck(last_begin_frame_args_.source_id,
+ last_begin_frame_args_.sequence_number, true),
+ client_.last_begin_frame_ack());
// Set both surface 1 and 2 as active via SurfaceDamageExpected().
AdvanceTimeAndBeginFrameForTest({sid1, sid2});
@@ -291,6 +304,9 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
EXPECT_GE(now_src().NowTicks(),
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.BeginFrameDeadlineForTest();
+ EXPECT_EQ(BeginFrameAck(last_begin_frame_args_.source_id,
+ last_begin_frame_args_.sequence_number, true),
+ client_.last_begin_frame_ack());
// Surface damage with |!has_damage| triggers early deadline if other damage
// exists.
@@ -300,7 +316,7 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
SurfaceDamaged(sid2);
EXPECT_LT(now_src().NowTicks(),
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
- cc::BeginFrameAck ack = AckForCurrentBeginFrame();
+ BeginFrameAck ack = AckForCurrentBeginFrame();
ack.has_damage = false;
scheduler_.ProcessSurfaceDamage(sid1, ack, false);
EXPECT_GE(now_src().NowTicks(),
@@ -318,6 +334,9 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
EXPECT_LT(now_src().NowTicks(),
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.BeginFrameDeadlineForTest();
+ EXPECT_EQ(BeginFrameAck(last_begin_frame_args_.source_id,
+ last_begin_frame_args_.sequence_number, false),
+ client_.last_begin_frame_ack());
// System should be idle now.
AdvanceTimeAndBeginFrameForTest(std::vector<SurfaceId>());
@@ -384,7 +403,7 @@ TEST_F(DisplaySchedulerWaitForAllSurfacesTest, WaitForAllSurfacesBeforeDraw) {
SurfaceDamaged(sid2);
EXPECT_EQ(base::TimeTicks::Max(),
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
- cc::BeginFrameAck ack = AckForCurrentBeginFrame();
+ BeginFrameAck ack = AckForCurrentBeginFrame();
ack.has_damage = false;
scheduler_.ProcessSurfaceDamage(sid1, ack, false);
EXPECT_GE(now_src().NowTicks(),
@@ -586,7 +605,7 @@ TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) {
// Deadline triggers late while root resources are locked.
AdvanceTimeAndBeginFrameForTest({sid1});
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
SurfaceDamaged(sid1);
EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.SetRootSurfaceResourcesLocked(true);
@@ -600,7 +619,7 @@ TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) {
// Deadline triggers normally when root resources are unlocked.
AdvanceTimeAndBeginFrameForTest({sid1, root_surface_id});
- late_deadline = now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
SurfaceDamaged(sid1);
EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
scheduler_.SetRootSurfaceResourcesLocked(false);
@@ -641,7 +660,7 @@ TEST_F(DisplaySchedulerTest, DidSwapBuffers) {
// Deadline triggers late when swap throttled.
AdvanceTimeAndBeginFrameForTest({sid1, sid2});
base::TimeTicks late_deadline =
- now_src().NowTicks() + cc::BeginFrameArgs::DefaultInterval();
+ now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
// Damage surface 1, but not surface 2 so we avoid triggering deadline
// early because all surfaces are ready.
SurfaceDamaged(sid1);
@@ -658,7 +677,7 @@ TEST_F(DisplaySchedulerTest, DidSwapBuffers) {
AdvanceTimeAndBeginFrameForTest({sid2});
base::TimeTicks expected_deadline =
scheduler_.LastUsedBeginFrameArgs().deadline -
- cc::BeginFrameArgs::DefaultEstimatedParentDrawTime();
+ BeginFrameArgs::DefaultEstimatedParentDrawTime();
EXPECT_EQ(expected_deadline,
scheduler_.DesiredBeginFrameDeadlineTimeForTest());
// Still waiting for surface 2. Once it updates, deadline should trigger
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index aa68584504c..81f28181555 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -9,16 +9,13 @@
#include "base/memory/ptr_util.h"
#include "base/test/null_task_runner.h"
#include "cc/output/compositor_frame.h"
-#include "cc/output/copy_output_result.h"
#include "cc/output/texture_mailbox_deleter.h"
#include "cc/quads/render_pass.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/scheduler_test_common.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/quads/copy_output_result.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
@@ -26,6 +23,9 @@
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -48,7 +48,7 @@ class TestSoftwareOutputDevice : public cc::SoftwareOutputDevice {
class TestDisplayScheduler : public DisplayScheduler {
public:
- explicit TestDisplayScheduler(cc::BeginFrameSource* begin_frame_source,
+ explicit TestDisplayScheduler(BeginFrameSource* begin_frame_source,
base::SingleThreadTaskRunner* task_runner)
: DisplayScheduler(begin_frame_source, task_runner, 1),
damaged(false),
@@ -65,7 +65,7 @@ class TestDisplayScheduler : public DisplayScheduler {
}
void ProcessSurfaceDamage(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack,
+ const BeginFrameAck& ack,
bool display_damaged) override {
if (display_damaged) {
damaged = true;
@@ -90,20 +90,19 @@ class TestDisplayScheduler : public DisplayScheduler {
class DisplayTest : public testing::Test {
public:
DisplayTest()
- : support_(CompositorFrameSinkSupport::Create(
- nullptr,
- &manager_,
- kArbitraryFrameSinkId,
- true /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
- true /* needs_sync_points */)),
+ : support_(
+ CompositorFrameSinkSupport::Create(nullptr,
+ &manager_,
+ kArbitraryFrameSinkId,
+ true /* is_root */,
+ true /* needs_sync_points */)),
task_runner_(new base::NullTaskRunner) {}
~DisplayTest() override { support_->EvictCurrentSurface(); }
void SetUpDisplay(const RendererSettings& settings,
std::unique_ptr<cc::TestWebGraphicsContext3D> context) {
- begin_frame_source_.reset(new cc::StubBeginFrameSource);
+ begin_frame_source_.reset(new StubBeginFrameSource);
std::unique_ptr<cc::FakeOutputSurface> output_surface;
if (context) {
@@ -148,7 +147,7 @@ class DisplayTest : public testing::Test {
protected:
void SubmitCompositorFrame(cc::RenderPassList* pass_list,
const LocalSurfaceId& local_surface_id) {
- cc::CompositorFrame frame = cc::test::MakeCompositorFrame();
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
pass_list->swap(frame.render_pass_list);
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -159,7 +158,7 @@ class DisplayTest : public testing::Test {
LocalSurfaceIdAllocator id_allocator_;
scoped_refptr<base::NullTaskRunner> task_runner_;
cc::TestSharedBitmapManager shared_bitmap_manager_;
- std::unique_ptr<cc::BeginFrameSource> begin_frame_source_;
+ std::unique_ptr<BeginFrameSource> begin_frame_source_;
std::unique_ptr<Display> display_;
TestSoftwareOutputDevice* software_output_device_ = nullptr;
cc::FakeOutputSurface* output_surface_ = nullptr;
@@ -175,7 +174,7 @@ class StubDisplayClient : public DisplayClient {
void DisplayDidDrawAndSwap() override {}
};
-void CopyCallback(bool* called, std::unique_ptr<cc::CopyOutputResult> result) {
+void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
*called = true;
}
@@ -330,7 +329,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass->output_rect = gfx::Rect(0, 0, 100, 100);
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
bool copy_called = false;
- pass->copy_requests.push_back(cc::CopyOutputRequest::CreateRequest(
+ pass->copy_requests.push_back(CopyOutputRequest::CreateRequest(
base::BindOnce(&CopyCallback, &copy_called)));
pass->id = 1u;
@@ -359,7 +358,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
- cc::CompositorFrame frame = cc::test::MakeCompositorFrame();
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
pass_list.swap(frame.render_pass_list);
frame.metadata.latency_info.push_back(ui::LatencyInfo());
@@ -391,7 +390,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
- cc::CompositorFrame frame = cc::test::MakeCompositorFrame();
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
pass_list.swap(frame.render_pass_list);
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -479,7 +478,7 @@ TEST_F(DisplayTest, MaxLatencyInfoCap) {
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
- cc::CompositorFrame frame = cc::test::MakeCompositorFrame();
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
pass_list.swap(frame.render_pass_list);
frame.metadata.latency_info.push_back(ui::LatencyInfo());
@@ -613,9 +612,8 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) {
// Set up second frame sink + display.
auto support2 = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kAnotherFrameSinkId, true /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
true /* needs_sync_points */);
- auto begin_frame_source2 = base::MakeUnique<cc::StubBeginFrameSource>();
+ auto begin_frame_source2 = base::MakeUnique<StubBeginFrameSource>();
auto scheduler_for_display2 = base::MakeUnique<TestDisplayScheduler>(
begin_frame_source2.get(), task_runner_.get());
TestDisplayScheduler* scheduler2 = scheduler_for_display2.get();
diff --git a/chromium/components/viz/service/display/dynamic_geometry_binding.cc b/chromium/components/viz/service/display/dynamic_geometry_binding.cc
new file mode 100644
index 00000000000..bb47dba7320
--- /dev/null
+++ b/chromium/components/viz/service/display/dynamic_geometry_binding.cc
@@ -0,0 +1,68 @@
+// 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/viz/service/display/dynamic_geometry_binding.h"
+
+#include <stdint.h>
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace viz {
+
+DynamicGeometryBinding::DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
+ GLuint buffers[2];
+ gl_->GenBuffers(2, buffers);
+ quad_vertices_vbo_ = buffers[0];
+ quad_elements_vbo_ = buffers[1];
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad), nullptr,
+ GL_DYNAMIC_DRAW);
+
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
+ gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GeometryBindingQuadIndex),
+ nullptr, GL_DYNAMIC_DRAW);
+}
+
+DynamicGeometryBinding::~DynamicGeometryBinding() {
+ GLuint buffers[2] = {quad_vertices_vbo_, quad_elements_vbo_};
+ gl_->DeleteBuffers(2, buffers);
+}
+
+void DynamicGeometryBinding::InitializeCustomQuad(const gfx::QuadF& quad) {
+ float uv[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
+ InitializeCustomQuadWithUVs(quad, uv);
+}
+
+void DynamicGeometryBinding::InitializeCustomQuadWithUVs(const gfx::QuadF& quad,
+ const float uv[8]) {
+ GeometryBindingVertex v0 = {
+ {quad.p1().x(), quad.p1().y(), 0.0f}, {uv[0], uv[1]}, 0.0f};
+ GeometryBindingVertex v1 = {
+ {quad.p2().x(), quad.p2().y(), 0.0f}, {uv[2], uv[3]}, 1.0f};
+ GeometryBindingVertex v2 = {
+ {quad.p3().x(), quad.p3().y(), 0.0f}, {uv[4], uv[5]}, 2.0f};
+ GeometryBindingVertex v3 = {
+ {quad.p4().x(), quad.p4().y(), 0.0f}, {uv[6], uv[7]}, 3.0f};
+
+ GeometryBindingQuad local_quad = {v0, v1, v2, v3};
+ GeometryBindingQuadIndex quad_index(
+ static_cast<uint16_t>(0), static_cast<uint16_t>(1),
+ static_cast<uint16_t>(2), static_cast<uint16_t>(3),
+ static_cast<uint16_t>(0), static_cast<uint16_t>(2));
+
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GeometryBindingQuad),
+ &local_quad);
+ gl_->BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0,
+ sizeof(GeometryBindingQuadIndex), &quad_index);
+}
+
+void DynamicGeometryBinding::PrepareForDraw() {
+ SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/dynamic_geometry_binding.h b/chromium/components/viz/service/display/dynamic_geometry_binding.h
new file mode 100644
index 00000000000..a319c2daac7
--- /dev/null
+++ b/chromium/components/viz/service/display/dynamic_geometry_binding.h
@@ -0,0 +1,38 @@
+// 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_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
+
+#include "base/macros.h"
+#include "components/viz/service/display/geometry_binding.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace gfx {
+class QuadF;
+}
+
+namespace viz {
+
+class VIZ_SERVICE_EXPORT DynamicGeometryBinding {
+ public:
+ explicit DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl);
+ ~DynamicGeometryBinding();
+
+ void PrepareForDraw();
+ void InitializeCustomQuad(const gfx::QuadF& quad);
+ void InitializeCustomQuadWithUVs(const gfx::QuadF& quad, const float uv[8]);
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ GLuint quad_vertices_vbo_;
+ GLuint quad_elements_vbo_;
+
+ DISALLOW_COPY_AND_ASSIGN(DynamicGeometryBinding);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/geometry_binding.cc b/chromium/components/viz/service/display/geometry_binding.cc
new file mode 100644
index 00000000000..6207d228189
--- /dev/null
+++ b/chromium/components/viz/service/display/geometry_binding.cc
@@ -0,0 +1,74 @@
+// Copyright 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/viz/service/display/geometry_binding.h"
+
+#include <stdint.h>
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace viz {
+
+void SetupGLContext(gpu::gles2::GLES2Interface* gl,
+ GLuint quad_elements_vbo,
+ GLuint quad_vertices_vbo) {
+ gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo);
+
+ gl->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo);
+ // OpenGL defines the last parameter to VertexAttribPointer as type
+ // "const GLvoid*" even though it is actually an offset into the buffer
+ // object's data store and not a pointer to the client's address space.
+ const void* offsets[3] = {
+ 0, reinterpret_cast<const void*>(3 * sizeof(float)),
+ reinterpret_cast<const void*>(5 * sizeof(float)),
+ };
+
+ gl->VertexAttribPointer(GeometryBinding::PositionAttribLocation(), 3,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[0]);
+ gl->VertexAttribPointer(GeometryBinding::TexCoordAttribLocation(), 2,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[1]);
+ gl->VertexAttribPointer(GeometryBinding::TriangleIndexAttribLocation(), 1,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[2]);
+ gl->EnableVertexAttribArray(GeometryBinding::PositionAttribLocation());
+ gl->EnableVertexAttribArray(GeometryBinding::TexCoordAttribLocation());
+ gl->EnableVertexAttribArray(GeometryBinding::TriangleIndexAttribLocation());
+}
+
+GeometryBindingQuad::GeometryBindingQuad() {
+ v0 = {{0, 0, 0}, {0, 0}, 0};
+ v1 = {{0, 0, 0}, {0, 0}, 0};
+ v2 = {{0, 0, 0}, {0, 0}, 0};
+ v3 = {{0, 0, 0}, {0, 0}, 0};
+}
+
+GeometryBindingQuad::GeometryBindingQuad(const GeometryBindingVertex& vert0,
+ const GeometryBindingVertex& vert1,
+ const GeometryBindingVertex& vert2,
+ const GeometryBindingVertex& vert3) {
+ v0 = vert0;
+ v1 = vert1;
+ v2 = vert2;
+ v3 = vert3;
+}
+
+GeometryBindingQuadIndex::GeometryBindingQuadIndex() {
+ memset(data, 0x0, sizeof(data));
+}
+
+GeometryBindingQuadIndex::GeometryBindingQuadIndex(uint16_t index0,
+ uint16_t index1,
+ uint16_t index2,
+ uint16_t index3,
+ uint16_t index4,
+ uint16_t index5) {
+ data[0] = index0;
+ data[1] = index1;
+ data[2] = index2;
+ data[3] = index3;
+ data[4] = index4;
+ data[5] = index5;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/geometry_binding.h b/chromium/components/viz/service/display/geometry_binding.h
new file mode 100644
index 00000000000..64bdf0b9ae4
--- /dev/null
+++ b/chromium/components/viz/service/display/geometry_binding.h
@@ -0,0 +1,64 @@
+// Copyright 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_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
+
+#include <stdint.h>
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace viz {
+
+struct GeometryBindingVertex {
+ float a_position[3];
+ float a_texCoord[2];
+ // Index of the vertex, divide by 4 to have the matrix for this quad.
+ float a_index;
+};
+
+struct GeometryBindingQuad {
+ GeometryBindingQuad();
+ GeometryBindingQuad(const GeometryBindingVertex& vert0,
+ const GeometryBindingVertex& vert1,
+ const GeometryBindingVertex& vert2,
+ const GeometryBindingVertex& vert3);
+ GeometryBindingVertex v0, v1, v2, v3;
+};
+static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
+ "struct Quad should be densely packed");
+
+struct GeometryBindingQuadIndex {
+ GeometryBindingQuadIndex();
+ GeometryBindingQuadIndex(uint16_t index0,
+ uint16_t index1,
+ uint16_t index2,
+ uint16_t index3,
+ uint16_t index4,
+ uint16_t index5);
+
+ uint16_t data[6];
+};
+static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
+ "struct QuadIndex should be densely packed");
+
+struct GeometryBinding {
+ // All layer shaders share the same attribute locations for the vertex
+ // positions and texture coordinates. This allows switching shaders without
+ // rebinding attribute arrays.
+ static int PositionAttribLocation() { return 0; }
+ static int TexCoordAttribLocation() { return 1; }
+ static int TriangleIndexAttribLocation() { return 2; }
+};
+
+void SetupGLContext(gpu::gles2::GLES2Interface* gl,
+ GLuint quad_elements_vbo,
+ GLuint quad_vertices_vbo);
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
new file mode 100644
index 00000000000..1032a546857
--- /dev/null
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -0,0 +1,3730 @@
+// Copyright 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.
+
+#include "components/viz/service/display/gl_renderer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <numeric>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "cc/base/container_util.h"
+#include "cc/base/math_util.h"
+#include "cc/base/render_surface_filters.h"
+#include "cc/debug/debug_colors.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "cc/output/layer_quad.h"
+#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_frame.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/quads/draw_polygon.h"
+#include "cc/quads/picture_draw_quad.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/raster/scoped_gpu_raster.h"
+#include "cc/resources/resource_pool.h"
+#include "cc/resources/scoped_resource.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/service/display/dynamic_geometry_binding.h"
+#include "components/viz/service/display/static_geometry_binding.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/common/gpu_memory_allocation.h"
+#include "media/base/media_switches.h"
+#include "skia/ext/texture_handle.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/color_transform.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace viz {
+namespace {
+
+Float4 UVTransform(const cc::TextureDrawQuad* quad) {
+ gfx::PointF uv0 = quad->uv_top_left;
+ gfx::PointF uv1 = quad->uv_bottom_right;
+ Float4 xform = {{uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y()}};
+ if (quad->y_flipped) {
+ xform.data[1] = 1.0f - xform.data[1];
+ xform.data[3] = -xform.data[3];
+ }
+ return xform;
+}
+
+// To prevent sampling outside the visible rect.
+Float4 UVClampRect(gfx::RectF uv_visible_rect,
+ const gfx::Size& texture_size,
+ SamplerType sampler) {
+ gfx::SizeF half_texel(0.5f, 0.5f);
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
+ half_texel.Scale(1.f / texture_size.width(), 1.f / texture_size.height());
+ } else {
+ uv_visible_rect.Scale(texture_size.width(), texture_size.height());
+ }
+ uv_visible_rect.Inset(half_texel.width(), half_texel.height());
+ return {{uv_visible_rect.x(), uv_visible_rect.y(), uv_visible_rect.right(),
+ uv_visible_rect.bottom()}};
+}
+
+Float4 PremultipliedColor(SkColor color, float opacity) {
+ const float factor = 1.0f / 255.0f;
+ const float alpha = opacity * SkColorGetA(color) * factor;
+
+ Float4 result = {{SkColorGetR(color) * factor * alpha,
+ SkColorGetG(color) * factor * alpha,
+ SkColorGetB(color) * factor * alpha, alpha}};
+ return result;
+}
+
+SamplerType SamplerTypeFromTextureTarget(GLenum target) {
+ switch (target) {
+ case GL_TEXTURE_2D:
+ return SAMPLER_TYPE_2D;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ return SAMPLER_TYPE_2D_RECT;
+ case GL_TEXTURE_EXTERNAL_OES:
+ return SAMPLER_TYPE_EXTERNAL_OES;
+ default:
+ NOTREACHED();
+ return SAMPLER_TYPE_2D;
+ }
+}
+
+BlendMode BlendModeFromSkXfermode(SkBlendMode mode) {
+ switch (mode) {
+ case SkBlendMode::kSrcOver:
+ return BLEND_MODE_NORMAL;
+ case SkBlendMode::kDstIn:
+ return BLEND_MODE_DESTINATION_IN;
+ case SkBlendMode::kScreen:
+ return BLEND_MODE_SCREEN;
+ case SkBlendMode::kOverlay:
+ return BLEND_MODE_OVERLAY;
+ case SkBlendMode::kDarken:
+ return BLEND_MODE_DARKEN;
+ case SkBlendMode::kLighten:
+ return BLEND_MODE_LIGHTEN;
+ case SkBlendMode::kColorDodge:
+ return BLEND_MODE_COLOR_DODGE;
+ case SkBlendMode::kColorBurn:
+ return BLEND_MODE_COLOR_BURN;
+ case SkBlendMode::kHardLight:
+ return BLEND_MODE_HARD_LIGHT;
+ case SkBlendMode::kSoftLight:
+ return BLEND_MODE_SOFT_LIGHT;
+ case SkBlendMode::kDifference:
+ return BLEND_MODE_DIFFERENCE;
+ case SkBlendMode::kExclusion:
+ return BLEND_MODE_EXCLUSION;
+ case SkBlendMode::kMultiply:
+ return BLEND_MODE_MULTIPLY;
+ case SkBlendMode::kHue:
+ return BLEND_MODE_HUE;
+ case SkBlendMode::kSaturation:
+ return BLEND_MODE_SATURATION;
+ case SkBlendMode::kColor:
+ return BLEND_MODE_COLOR;
+ case SkBlendMode::kLuminosity:
+ return BLEND_MODE_LUMINOSITY;
+ default:
+ NOTREACHED();
+ return BLEND_MODE_NONE;
+ }
+}
+
+// Smallest unit that impact anti-aliasing output. We use this to
+// determine when anti-aliasing is unnecessary.
+const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
+
+// Block or crash if the number of pending sync queries reach this high as
+// something is seriously wrong on the service side if this happens.
+const size_t kMaxPendingSyncQueries = 16;
+} // anonymous namespace
+
+// Parameters needed to draw a cc::RenderPassDrawQuad.
+struct DrawRenderPassDrawQuadParams {
+ DrawRenderPassDrawQuadParams() {}
+ ~DrawRenderPassDrawQuadParams() {}
+
+ // Required Inputs.
+ const cc::RenderPassDrawQuad* quad = nullptr;
+ const cc::Resource* contents_texture = nullptr;
+ const gfx::QuadF* clip_region = nullptr;
+ bool flip_texture = false;
+ gfx::Transform window_matrix;
+ gfx::Transform projection_matrix;
+ gfx::Transform quad_to_target_transform;
+ const cc::FilterOperations* filters = nullptr;
+ const cc::FilterOperations* background_filters = nullptr;
+
+ // Whether the texture to be sampled from needs to be flipped.
+ bool source_needs_flip = false;
+
+ float edge[24];
+ SkScalar color_matrix[20];
+
+ // Blending refers to modifications to the backdrop.
+ bool use_shaders_for_blending = false;
+
+ bool use_aa = false;
+
+ // Some filters affect pixels outside the original contents bounds. This
+ // requires translation of the source when texturing, as well as a change in
+ // the bounds of the destination.
+ gfx::Point src_offset;
+ gfx::RectF dst_rect;
+
+ // A Skia image that should be sampled from instead of the original
+ // contents.
+ sk_sp<SkImage> filter_image;
+
+ // The original contents, bound for sampling.
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL>
+ contents_resource_lock;
+
+ // A mask to be applied when drawing the RPDQ.
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL>
+ mask_resource_lock;
+
+ // Original background texture.
+ std::unique_ptr<cc::ScopedResource> background_texture;
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL>
+ shader_background_sampler_lock;
+
+ // Backdrop bounding box.
+ gfx::Rect background_rect;
+
+ // Filtered background texture.
+ sk_sp<SkImage> background_image;
+ GLuint background_image_id = 0;
+
+ // Whether the original background texture is needed for the mask.
+ bool mask_for_background = false;
+
+ // Whether a color matrix needs to be applied by the shaders when drawing
+ // the RPDQ.
+ bool use_color_matrix = false;
+
+ gfx::QuadF surface_quad;
+
+ gfx::Transform contents_device_transform;
+
+ gfx::RectF tex_coord_rect;
+
+ // The color space of the texture bound for sampling (from filter_image or
+ // contents_resource_lock, depending on the path taken).
+ gfx::ColorSpace contents_color_space;
+};
+
+static GLint GetActiveTextureUnit(GLES2Interface* gl) {
+ GLint active_unit = 0;
+ gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
+ return active_unit;
+}
+
+class GLRenderer::ScopedUseGrContext {
+ public:
+ static std::unique_ptr<ScopedUseGrContext> Create(GLRenderer* renderer) {
+ // GrContext for filters is created lazily, and may fail if the context
+ // is lost.
+ // TODO(vmiura,bsalomon): crbug.com/487850 Ensure that
+ // ContextProvider::GrContext() does not return NULL.
+ if (renderer->output_surface_->context_provider()->GrContext())
+ return base::WrapUnique(new ScopedUseGrContext(renderer));
+ return nullptr;
+ }
+
+ ~ScopedUseGrContext() {
+ // Pass context control back to GLrenderer.
+ scoped_gpu_raster_ = nullptr;
+ renderer_->RestoreGLState();
+ }
+
+ GrContext* context() const {
+ return renderer_->output_surface_->context_provider()->GrContext();
+ }
+
+ private:
+ explicit ScopedUseGrContext(GLRenderer* renderer)
+ : scoped_gpu_raster_(new cc::ScopedGpuRaster(
+ renderer->output_surface_->context_provider())),
+ renderer_(renderer) {
+ // scoped_gpu_raster_ passes context control to Skia.
+ }
+
+ std::unique_ptr<cc::ScopedGpuRaster> scoped_gpu_raster_;
+ GLRenderer* renderer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedUseGrContext);
+};
+
+struct GLRenderer::PendingAsyncReadPixels {
+ PendingAsyncReadPixels() : buffer(0) {}
+
+ std::unique_ptr<CopyOutputRequest> copy_request;
+ unsigned buffer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PendingAsyncReadPixels);
+};
+
+class GLRenderer::SyncQuery {
+ public:
+ explicit SyncQuery(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), query_id_(0u), is_pending_(false), weak_ptr_factory_(this) {
+ gl_->GenQueriesEXT(1, &query_id_);
+ }
+ virtual ~SyncQuery() { gl_->DeleteQueriesEXT(1, &query_id_); }
+
+ scoped_refptr<cc::ResourceProvider::Fence> Begin() {
+ DCHECK(!IsPending());
+ // Invalidate weak pointer held by old fence.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ // Note: In case the set of drawing commands issued before End() do not
+ // depend on the query, defer BeginQueryEXT call until Set() is called and
+ // query is required.
+ return make_scoped_refptr<cc::ResourceProvider::Fence>(
+ new Fence(weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void Set() {
+ if (is_pending_)
+ return;
+
+ // Note: BeginQueryEXT on GL_COMMANDS_COMPLETED_CHROMIUM is effectively a
+ // noop relative to GL, so it doesn't matter where it happens but we still
+ // make sure to issue this command when Set() is called (prior to issuing
+ // any drawing commands that depend on query), in case some future extension
+ // can take advantage of this.
+ gl_->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query_id_);
+ is_pending_ = true;
+ }
+
+ void End() {
+ if (!is_pending_)
+ return;
+
+ gl_->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
+ }
+
+ bool IsPending() {
+ if (!is_pending_)
+ return false;
+
+ unsigned result_available = 1;
+ gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_AVAILABLE_EXT,
+ &result_available);
+ is_pending_ = !result_available;
+ return is_pending_;
+ }
+
+ void Wait() {
+ if (!is_pending_)
+ return;
+
+ unsigned result = 0;
+ gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+ is_pending_ = false;
+ }
+
+ private:
+ class Fence : public cc::ResourceProvider::Fence {
+ public:
+ explicit Fence(base::WeakPtr<GLRenderer::SyncQuery> query)
+ : query_(query) {}
+
+ // Overridden from cc::ResourceProvider::Fence:
+ void Set() override {
+ DCHECK(query_);
+ query_->Set();
+ }
+ bool HasPassed() override { return !query_ || !query_->IsPending(); }
+ void Wait() override {
+ if (query_)
+ query_->Wait();
+ }
+
+ private:
+ ~Fence() override {}
+
+ base::WeakPtr<SyncQuery> query_;
+
+ DISALLOW_COPY_AND_ASSIGN(Fence);
+ };
+
+ gpu::gles2::GLES2Interface* gl_;
+ unsigned query_id_;
+ bool is_pending_;
+ base::WeakPtrFactory<SyncQuery> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncQuery);
+};
+
+GLRenderer::GLRenderer(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider,
+ cc::TextureMailboxDeleter* texture_mailbox_deleter)
+ : cc::DirectRenderer(settings, output_surface, resource_provider),
+ shared_geometry_quad_(QuadVertexRect()),
+ gl_(output_surface->context_provider()->ContextGL()),
+ context_support_(output_surface->context_provider()->ContextSupport()),
+ texture_mailbox_deleter_(texture_mailbox_deleter),
+ gl_composited_overlay_candidate_quad_border_(
+ settings->gl_composited_overlay_candidate_quad_border),
+ bound_geometry_(NO_BINDING),
+ color_lut_cache_(gl_,
+ output_surface_->context_provider()
+ ->ContextCapabilities()
+ .texture_half_float_linear),
+ weak_ptr_factory_(this) {
+ DCHECK(gl_);
+ DCHECK(context_support_);
+
+ const auto& context_caps =
+ output_surface_->context_provider()->ContextCapabilities();
+ DCHECK(!context_caps.iosurface || context_caps.texture_rectangle);
+
+ use_discard_framebuffer_ = context_caps.discard_framebuffer;
+ use_sync_query_ = context_caps.sync_query;
+ use_blend_equation_advanced_ = context_caps.blend_equation_advanced;
+ use_blend_equation_advanced_coherent_ =
+ context_caps.blend_equation_advanced_coherent;
+ use_occlusion_query_ = context_caps.occlusion_query;
+ use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
+
+ InitializeSharedObjects();
+}
+
+GLRenderer::~GLRenderer() {
+ CleanupSharedObjects();
+
+ if (context_visibility_) {
+ auto* context_provider = output_surface_->context_provider();
+ auto* cache_controller = context_provider->CacheController();
+ cache_controller->ClientBecameNotVisible(std::move(context_visibility_));
+ }
+}
+
+bool GLRenderer::CanPartialSwap() {
+ if (use_swap_with_bounds_)
+ return false;
+ auto* context_provider = output_surface_->context_provider();
+ return context_provider->ContextCapabilities().post_sub_buffer;
+}
+
+ResourceFormat GLRenderer::BackbufferFormat() const {
+ if (current_frame()->current_render_pass->color_space.IsHDR() &&
+ resource_provider_->IsRenderBufferFormatSupported(RGBA_F16)) {
+ return RGBA_F16;
+ }
+ return resource_provider_->best_texture_format();
+}
+
+void GLRenderer::DidChangeVisibility() {
+ if (visible_) {
+ output_surface_->EnsureBackbuffer();
+ } else {
+ TRACE_EVENT0("cc", "GLRenderer::DidChangeVisibility dropping resources");
+ ReleaseRenderPassTextures();
+ output_surface_->DiscardBackbuffer();
+ gl_->ReleaseShaderCompiler();
+ }
+
+ PrepareGeometry(NO_BINDING);
+
+ auto* context_provider = output_surface_->context_provider();
+ auto* cache_controller = context_provider->CacheController();
+ if (visible_) {
+ DCHECK(!context_visibility_);
+ context_visibility_ = cache_controller->ClientBecameVisible();
+ } else {
+ DCHECK(context_visibility_);
+ cache_controller->ClientBecameNotVisible(std::move(context_visibility_));
+ }
+}
+
+void GLRenderer::ReleaseRenderPassTextures() {
+ render_pass_textures_.clear();
+}
+
+void GLRenderer::DiscardPixels() {
+ if (!use_discard_framebuffer_)
+ return;
+ bool using_default_framebuffer =
+ !current_framebuffer_lock_ &&
+ output_surface_->capabilities().uses_default_gl_framebuffer;
+ GLenum attachments[] = {static_cast<GLenum>(
+ using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)};
+ gl_->DiscardFramebufferEXT(GL_FRAMEBUFFER, arraysize(attachments),
+ attachments);
+}
+
+void GLRenderer::PrepareSurfaceForPass(
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ SetViewport();
+
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ DiscardPixels();
+ ClearFramebuffer();
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer();
+ break;
+ }
+}
+
+void GLRenderer::ClearFramebuffer() {
+ // On DEBUG builds, opaque render passes are cleared to blue to easily see
+ // regions that were not drawn on the screen.
+ if (current_frame()->current_render_pass->has_transparent_background)
+ gl_->ClearColor(0, 0, 0, 0);
+ else
+ gl_->ClearColor(0, 0, 1, 1);
+
+ gl_->ClearStencil(0);
+
+ bool always_clear = overdraw_feedback_;
+#ifndef NDEBUG
+ always_clear = true;
+#endif
+ if (always_clear ||
+ current_frame()->current_render_pass->has_transparent_background) {
+ GLbitfield clear_bits = GL_COLOR_BUFFER_BIT;
+ if (always_clear)
+ clear_bits |= GL_STENCIL_BUFFER_BIT;
+ gl_->Clear(clear_bits);
+ }
+}
+
+void GLRenderer::BeginDrawingFrame() {
+ TRACE_EVENT0("cc", "GLRenderer::BeginDrawingFrame");
+
+ scoped_refptr<cc::ResourceProvider::Fence> read_lock_fence;
+ if (use_sync_query_) {
+ // Block until oldest sync query has passed if the number of pending queries
+ // ever reach kMaxPendingSyncQueries.
+ if (pending_sync_queries_.size() >= kMaxPendingSyncQueries) {
+ LOG(ERROR) << "Reached limit of pending sync queries.";
+
+ pending_sync_queries_.front()->Wait();
+ DCHECK(!pending_sync_queries_.front()->IsPending());
+ }
+
+ while (!pending_sync_queries_.empty()) {
+ if (pending_sync_queries_.front()->IsPending())
+ break;
+
+ available_sync_queries_.push_back(cc::PopFront(&pending_sync_queries_));
+ }
+
+ current_sync_query_ = available_sync_queries_.empty()
+ ? base::MakeUnique<SyncQuery>(gl_)
+ : cc::PopFront(&available_sync_queries_);
+
+ read_lock_fence = current_sync_query_->Begin();
+ } else {
+ read_lock_fence =
+ make_scoped_refptr(new cc::ResourceProvider::SynchronousFence(gl_));
+ }
+ resource_provider_->SetReadLockFence(read_lock_fence.get());
+
+ // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the frame,
+ // so that drawing can proceed without GL context switching interruptions.
+ cc::ResourceProvider* resource_provider = resource_provider_;
+ for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
+ for (auto* quad : pass->quad_list) {
+ for (ResourceId resource_id : quad->resources)
+ resource_provider->WaitSyncToken(resource_id);
+ }
+ }
+
+ // TODO(enne): Do we need to reinitialize all of this state per frame?
+ ReinitializeGLState();
+
+ num_triangles_drawn_ = 0;
+}
+
+void GLRenderer::DoDrawQuad(const cc::DrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ DCHECK(quad->rect.Contains(quad->visible_rect));
+ if (quad->material != cc::DrawQuad::TEXTURE_CONTENT) {
+ FlushTextureQuadCache(SHARED_BINDING);
+ }
+
+ switch (quad->material) {
+ case cc::DrawQuad::INVALID:
+ NOTREACHED();
+ break;
+ case cc::DrawQuad::DEBUG_BORDER:
+ DrawDebugBorderQuad(cc::DebugBorderDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::PICTURE_CONTENT:
+ // PictureDrawQuad should only be used for resourceless software draws.
+ NOTREACHED();
+ break;
+ case cc::DrawQuad::RENDER_PASS:
+ DrawRenderPassQuad(cc::RenderPassDrawQuad::MaterialCast(quad),
+ clip_region);
+ break;
+ case cc::DrawQuad::SOLID_COLOR:
+ DrawSolidColorQuad(cc::SolidColorDrawQuad::MaterialCast(quad),
+ clip_region);
+ break;
+ case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+ DrawStreamVideoQuad(cc::StreamVideoDrawQuad::MaterialCast(quad),
+ clip_region);
+ break;
+ case cc::DrawQuad::SURFACE_CONTENT:
+ // Surface content should be fully resolved to other quad types before
+ // reaching a direct renderer.
+ NOTREACHED();
+ break;
+ case cc::DrawQuad::TEXTURE_CONTENT:
+ EnqueueTextureQuad(cc::TextureDrawQuad::MaterialCast(quad), clip_region);
+ break;
+ case cc::DrawQuad::TILED_CONTENT:
+ DrawTileQuad(cc::TileDrawQuad::MaterialCast(quad), clip_region);
+ break;
+ case cc::DrawQuad::YUV_VIDEO_CONTENT:
+ DrawYUVVideoQuad(cc::YUVVideoDrawQuad::MaterialCast(quad), clip_region);
+ break;
+ }
+}
+
+// This function does not handle 3D sorting right now, since the debug border
+// quads are just drawn as their original quads and not in split pieces. This
+// results in some debug border quads drawing over foreground quads.
+void GLRenderer::DrawDebugBorderQuad(const cc::DebugBorderDrawQuad* quad) {
+ SetBlendEnabled(quad->ShouldDrawWithBlending());
+
+ SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB());
+
+ // Use the full quad_rect for debug quads to not move the edges based on
+ // partial swaps.
+ gfx::Rect layer_rect = quad->rect;
+ gfx::Transform render_matrix;
+ QuadRectTransform(&render_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(layer_rect));
+ SetShaderMatrix(current_frame()->projection_matrix * render_matrix);
+ SetShaderColor(quad->color, 1.f);
+
+ gl_->LineWidth(quad->width);
+
+ // The indices for the line are stored in the same array as the triangle
+ // indices.
+ gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
+}
+
+static sk_sp<SkImage> WrapTexture(
+ const cc::DisplayResourceProvider::ScopedReadLockGL& lock,
+ GrContext* context,
+ bool flip_texture) {
+ // Wrap a given texture in a Ganesh backend texture.
+ GrGLTextureInfo texture_info;
+ texture_info.fTarget = lock.target();
+ texture_info.fID = lock.texture_id();
+ GrBackendTexture backend_texture(lock.size().width(), lock.size().height(),
+ kSkia8888_GrPixelConfig, texture_info);
+ GrSurfaceOrigin origin =
+ flip_texture ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
+
+ return SkImage::MakeFromTexture(context, backend_texture, origin,
+ kPremul_SkAlphaType, nullptr);
+}
+
+static sk_sp<SkImage> ApplyImageFilter(
+ std::unique_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
+ const gfx::RectF& src_rect,
+ const gfx::RectF& dst_rect,
+ const gfx::Vector2dF& scale,
+ sk_sp<SkImageFilter> filter,
+ const cc::DisplayResourceProvider::ScopedReadLockGL& source_texture_lock,
+ SkIPoint* offset,
+ SkIRect* subset,
+ bool flip_texture,
+ const gfx::PointF& origin) {
+ if (!filter || !use_gr_context)
+ return nullptr;
+
+ sk_sp<SkImage> src_image =
+ WrapTexture(source_texture_lock, use_gr_context->context(), flip_texture);
+
+ if (!src_image) {
+ TRACE_EVENT_INSTANT0("cc",
+ "ApplyImageFilter wrap background texture failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return nullptr;
+ }
+
+ // Big filters can sometimes fallback to CPU. Therefore, we need
+ // to disable subnormal floats for performance and security reasons.
+ cc::ScopedSubnormalFloatDisabler disabler;
+ SkMatrix local_matrix;
+ local_matrix.setTranslate(origin.x(), origin.y());
+ local_matrix.postScale(scale.x(), scale.y());
+ local_matrix.postTranslate(-src_rect.x(), -src_rect.y());
+
+ SkIRect clip_bounds = gfx::RectFToSkRect(dst_rect).roundOut();
+ clip_bounds.offset(-src_rect.x(), -src_rect.y());
+ filter = filter->makeWithLocalMatrix(local_matrix);
+ SkIRect in_subset = SkIRect::MakeWH(src_rect.width(), src_rect.height());
+ sk_sp<SkImage> image = src_image->makeWithFilter(filter.get(), in_subset,
+ clip_bounds, subset, offset);
+
+ if (!image || !image->isTextureBacked()) {
+ return nullptr;
+ }
+
+ // Force a flush of the Skia pipeline before we switch back to the compositor
+ // context.
+ image->getTextureHandle(true);
+ CHECK(image->isTextureBacked());
+ return image;
+}
+
+bool GLRenderer::CanApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode) {
+ return use_blend_equation_advanced_ || blend_mode == SkBlendMode::kSrcOver ||
+ blend_mode == SkBlendMode::kDstIn ||
+ blend_mode == SkBlendMode::kScreen;
+}
+
+void GLRenderer::ApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode) {
+ // Any modes set here must be reset in RestoreBlendFuncToDefault
+ if (blend_mode == SkBlendMode::kSrcOver) {
+ // Left no-op intentionally.
+ } else if (blend_mode == SkBlendMode::kDstIn) {
+ gl_->BlendFunc(GL_ZERO, GL_SRC_ALPHA);
+ } else if (blend_mode == SkBlendMode::kDstOut) {
+ gl_->BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
+ } else if (blend_mode == SkBlendMode::kScreen) {
+ gl_->BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
+ } else {
+ DCHECK(use_blend_equation_advanced_);
+ GLenum equation = GL_FUNC_ADD;
+ switch (blend_mode) {
+ case SkBlendMode::kScreen:
+ equation = GL_SCREEN_KHR;
+ break;
+ case SkBlendMode::kOverlay:
+ equation = GL_OVERLAY_KHR;
+ break;
+ case SkBlendMode::kDarken:
+ equation = GL_DARKEN_KHR;
+ break;
+ case SkBlendMode::kLighten:
+ equation = GL_LIGHTEN_KHR;
+ break;
+ case SkBlendMode::kColorDodge:
+ equation = GL_COLORDODGE_KHR;
+ break;
+ case SkBlendMode::kColorBurn:
+ equation = GL_COLORBURN_KHR;
+ break;
+ case SkBlendMode::kHardLight:
+ equation = GL_HARDLIGHT_KHR;
+ break;
+ case SkBlendMode::kSoftLight:
+ equation = GL_SOFTLIGHT_KHR;
+ break;
+ case SkBlendMode::kDifference:
+ equation = GL_DIFFERENCE_KHR;
+ break;
+ case SkBlendMode::kExclusion:
+ equation = GL_EXCLUSION_KHR;
+ break;
+ case SkBlendMode::kMultiply:
+ equation = GL_MULTIPLY_KHR;
+ break;
+ case SkBlendMode::kHue:
+ equation = GL_HSL_HUE_KHR;
+ break;
+ case SkBlendMode::kSaturation:
+ equation = GL_HSL_SATURATION_KHR;
+ break;
+ case SkBlendMode::kColor:
+ equation = GL_HSL_COLOR_KHR;
+ break;
+ case SkBlendMode::kLuminosity:
+ equation = GL_HSL_LUMINOSITY_KHR;
+ break;
+ default:
+ NOTREACHED() << "Unexpected blend mode: SkBlendMode::k"
+ << SkBlendMode_Name(blend_mode);
+ return;
+ }
+ gl_->BlendEquation(equation);
+ }
+}
+
+void GLRenderer::RestoreBlendFuncToDefault(SkBlendMode blend_mode) {
+ switch (blend_mode) {
+ case SkBlendMode::kSrcOver:
+ break;
+ case SkBlendMode::kDstIn:
+ case SkBlendMode::kDstOut:
+ case SkBlendMode::kScreen:
+ gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ default:
+ DCHECK(use_blend_equation_advanced_);
+ gl_->BlendEquation(GL_FUNC_ADD);
+ }
+}
+
+bool GLRenderer::ShouldApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations* background_filters) {
+ if (!background_filters)
+ return false;
+ DCHECK(!background_filters->IsEmpty());
+
+ // TODO(hendrikw): Look into allowing background filters to see pixels from
+ // other render targets. See crbug.com/314867.
+
+ return true;
+}
+
+// This takes a gfx::Rect and a clip region quad in the same space,
+// and returns a quad with the same proportions in the space -0.5->0.5.
+bool GetScaledRegion(const gfx::Rect& rect,
+ const gfx::QuadF* clip,
+ gfx::QuadF* scaled_region) {
+ if (!clip)
+ return false;
+
+ gfx::PointF p1(((clip->p1().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p1().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p2(((clip->p2().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p2().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p3(((clip->p3().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p3().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p4(((clip->p4().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p4().y() - rect.y()) / rect.height()) - 0.5f);
+ *scaled_region = gfx::QuadF(p1, p2, p3, p4);
+ return true;
+}
+
+// This takes a gfx::Rect and a clip region quad in the same space,
+// and returns the proportional uv's in the space 0->1.
+bool GetScaledUVs(const gfx::Rect& rect, const gfx::QuadF* clip, float uvs[8]) {
+ if (!clip)
+ return false;
+
+ uvs[0] = ((clip->p1().x() - rect.x()) / rect.width());
+ uvs[1] = ((clip->p1().y() - rect.y()) / rect.height());
+ uvs[2] = ((clip->p2().x() - rect.x()) / rect.width());
+ uvs[3] = ((clip->p2().y() - rect.y()) / rect.height());
+ uvs[4] = ((clip->p3().x() - rect.x()) / rect.width());
+ uvs[5] = ((clip->p3().y() - rect.y()) / rect.height());
+ uvs[6] = ((clip->p4().x() - rect.x()) / rect.width());
+ uvs[7] = ((clip->p4().y() - rect.y()) / rect.height());
+ return true;
+}
+
+gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::Transform& contents_device_transform,
+ const cc::FilterOperations* filters,
+ const cc::FilterOperations* background_filters,
+ const gfx::QuadF* clip_region,
+ bool use_aa,
+ gfx::Rect* unclipped_rect) {
+ gfx::QuadF scaled_region;
+ if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
+ scaled_region = SharedGeometryQuad().BoundingBox();
+ }
+
+ gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
+ contents_device_transform, scaled_region.BoundingBox()));
+
+ if (ShouldApplyBackgroundFilters(quad, background_filters)) {
+ SkMatrix matrix;
+ matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
+ if (FlippedFramebuffer()) {
+ // TODO(jbroman): This probably isn't the right way to account for this.
+ // Probably some combination of current_frame()->projection_matrix,
+ // current_frame()->window_matrix and contents_device_transform?
+ matrix.postScale(1, -1);
+ }
+ backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix);
+ }
+
+ if (!backdrop_rect.IsEmpty() && use_aa) {
+ const int kOutsetForAntialiasing = 1;
+ backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing);
+ }
+
+ if (filters) {
+ DCHECK(!filters->IsEmpty());
+ // If we have filters, grab an extra one-pixel border around the
+ // background, so texture edge clamping gives us a transparent border
+ // in case the filter expands the result.
+ backdrop_rect.Inset(-1, -1, -1, -1);
+ }
+
+ *unclipped_rect = backdrop_rect;
+ backdrop_rect.Intersect(MoveFromDrawToWindowSpace(
+ current_frame()->current_render_pass->output_rect));
+ return backdrop_rect;
+}
+
+std::unique_ptr<cc::ScopedResource> GLRenderer::GetBackdropTexture(
+ const gfx::Rect& bounding_rect) {
+ auto device_background_texture =
+ base::MakeUnique<cc::ScopedResource>(resource_provider_);
+ // CopyTexImage2D fails when called on a texture having immutable storage.
+ device_background_texture->Allocate(
+ bounding_rect.size(), cc::ResourceProvider::TEXTURE_HINT_DEFAULT,
+ BackbufferFormat(), current_frame()->current_render_pass->color_space);
+ {
+ cc::ResourceProvider::ScopedWriteLockGL lock(
+ resource_provider_, device_background_texture->id());
+ GetFramebufferTexture(lock.GetTexture(), bounding_rect);
+ }
+ return device_background_texture;
+}
+
+sk_sp<SkImage> GLRenderer::ApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations& background_filters,
+ cc::ScopedResource* background_texture,
+ const gfx::RectF& rect,
+ const gfx::RectF& unclipped_rect) {
+ DCHECK(ShouldApplyBackgroundFilters(quad, &background_filters));
+ auto use_gr_context = ScopedUseGrContext::Create(this);
+
+ gfx::Vector2dF clipping_offset =
+ (rect.top_right() - unclipped_rect.top_right()) +
+ (rect.bottom_left() - unclipped_rect.bottom_left());
+ sk_sp<SkImageFilter> filter = cc::RenderSurfaceFilters::BuildImageFilter(
+ background_filters, gfx::SizeF(background_texture->size()),
+ clipping_offset);
+
+ // TODO(senorblanco): background filters should be moved to the
+ // makeWithFilter fast-path, and go back to calling ApplyImageFilter().
+ // See http://crbug.com/613233.
+ if (!filter || !use_gr_context)
+ return nullptr;
+
+ cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ background_texture->id());
+
+ bool flip_texture = true;
+ sk_sp<SkImage> src_image =
+ WrapTexture(lock, use_gr_context->context(), flip_texture);
+ if (!src_image) {
+ TRACE_EVENT_INSTANT0(
+ "cc", "ApplyBackgroundFilters wrap background texture failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return nullptr;
+ }
+
+ // Create surface to draw into.
+ SkImageInfo dst_info =
+ SkImageInfo::MakeN32Premul(rect.width(), rect.height());
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
+ use_gr_context->context(), SkBudgeted::kYes, dst_info);
+ if (!surface) {
+ TRACE_EVENT_INSTANT0("cc",
+ "ApplyBackgroundFilters surface allocation failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return nullptr;
+ }
+
+ // Big filters can sometimes fallback to CPU. Therefore, we need
+ // to disable subnormal floats for performance and security reasons.
+ cc::ScopedSubnormalFloatDisabler disabler;
+ SkMatrix local_matrix;
+ local_matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
+
+ SkPaint paint;
+ paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix));
+ surface->getCanvas()->translate(-rect.x(), -rect.y());
+ surface->getCanvas()->drawImage(src_image, rect.x(), rect.y(), &paint);
+ // Flush the drawing before source texture read lock goes out of scope.
+ // Skia API does not guarantee that when the SkImage goes out of scope,
+ // its externally referenced resources would force the rendering to be
+ // flushed.
+ surface->getCanvas()->flush();
+ sk_sp<SkImage> image = surface->makeImageSnapshot();
+ if (!image || !image->isTextureBacked()) {
+ return nullptr;
+ }
+
+ return image;
+}
+
+// Map device space quad to local space. Device_transform has no 3d
+// component since it was flattened, so we don't need to project. We should
+// have already checked that the transform was uninvertible before this call.
+gfx::QuadF MapQuadToLocalSpace(const gfx::Transform& device_transform,
+ const gfx::QuadF& device_quad) {
+ gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
+ DCHECK(device_transform.IsInvertible());
+ bool did_invert = device_transform.GetInverse(&inverse_device_transform);
+ DCHECK(did_invert);
+ bool clipped = false;
+ gfx::QuadF local_quad =
+ cc::MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped);
+ // We should not DCHECK(!clipped) here, because anti-aliasing inflation may
+ // cause device_quad to become clipped. To our knowledge this scenario does
+ // not need to be handled differently than the unclipped case.
+ return local_quad;
+}
+
+const cc::TileDrawQuad* GLRenderer::CanPassBeDrawnDirectly(
+ const cc::RenderPass* pass) {
+ // Can only collapse a single tile quad.
+ if (pass->quad_list.size() != 1)
+ return nullptr;
+ // If we need copy requests, then render pass has to exist.
+ if (!pass->copy_requests.empty())
+ return nullptr;
+
+ const cc::DrawQuad* quad = *pass->quad_list.BackToFrontBegin();
+ // Hack: this could be supported by concatenating transforms, but
+ // in practice if there is one quad, it is at the origin of the render pass
+ // and has the same size as the pass.
+ if (!quad->shared_quad_state->quad_to_target_transform.IsIdentity() ||
+ quad->rect != pass->output_rect)
+ return nullptr;
+ // The quad is expected to be the entire layer so that AA edges are correct.
+ if (quad->shared_quad_state->quad_layer_rect != quad->rect)
+ return nullptr;
+ if (quad->material != cc::DrawQuad::TILED_CONTENT)
+ return nullptr;
+
+ // TODO(chrishtr): support could be added for opacity, but care needs
+ // to be taken to make sure it is correct w.r.t. non-commutative filters etc.
+ if (quad->shared_quad_state->opacity != 1.0f)
+ return nullptr;
+
+ const cc::TileDrawQuad* tile_quad = cc::TileDrawQuad::MaterialCast(quad);
+ // Hack: this could be supported by passing in a subrectangle to draw
+ // render pass, although in practice if there is only one quad there
+ // will be no border texels on the input.
+ if (tile_quad->tex_coord_rect != gfx::RectF(tile_quad->rect))
+ return nullptr;
+ // Tile quad features not supported in render pass shaders.
+ if (tile_quad->swizzle_contents || tile_quad->nearest_neighbor)
+ return nullptr;
+ // BUG=skia:3868, Skia currently doesn't support texture rectangle inputs.
+ // See also the DCHECKs about GL_TEXTURE_2D in DrawRenderPassQuad.
+ GLenum target =
+ resource_provider_->GetResourceTextureTarget(tile_quad->resource_id());
+ if (target != GL_TEXTURE_2D)
+ return nullptr;
+#if defined(OS_MACOSX)
+ // On Macs, this path can sometimes lead to all black output.
+ // TODO(enne): investigate this and remove this hack.
+ return nullptr;
+#endif
+
+ return tile_quad;
+}
+
+void GLRenderer::DrawRenderPassQuad(const cc::RenderPassDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ auto bypass = render_pass_bypass_quads_.find(quad->render_pass_id);
+ DrawRenderPassDrawQuadParams params;
+ params.quad = quad;
+ params.clip_region = clip_region;
+ params.window_matrix = current_frame()->window_matrix;
+ params.projection_matrix = current_frame()->projection_matrix;
+ params.tex_coord_rect = quad->tex_coord_rect;
+ if (bypass != render_pass_bypass_quads_.end()) {
+ cc::TileDrawQuad* tile_quad = &bypass->second;
+ // RGBA_8888 and the gfx::ColorSpace() here are arbitrary and unused.
+ cc::Resource tile_resource(tile_quad->resource_id(),
+ tile_quad->texture_size,
+ ResourceFormat::RGBA_8888, gfx::ColorSpace());
+ // The projection matrix used by GLRenderer has a flip. As tile texture
+ // inputs are oriented opposite to framebuffer outputs, don't flip via
+ // texture coords and let the projection matrix naturallyd o it.
+ params.flip_texture = false;
+ params.contents_texture = &tile_resource;
+ DrawRenderPassQuadInternal(&params);
+ } else {
+ cc::ScopedResource* contents_texture =
+ render_pass_textures_[quad->render_pass_id].get();
+ DCHECK(contents_texture);
+ DCHECK(contents_texture->id());
+ // See above comments about texture flipping. When the input is a
+ // render pass, it needs to an extra flip to be oriented correctly.
+ params.flip_texture = true;
+ params.contents_texture = contents_texture;
+ DrawRenderPassQuadInternal(&params);
+ }
+}
+
+void GLRenderer::DrawRenderPassQuadInternal(
+ DrawRenderPassDrawQuadParams* params) {
+ params->quad_to_target_transform =
+ params->quad->shared_quad_state->quad_to_target_transform;
+ if (!InitializeRPDQParameters(params))
+ return;
+ UpdateRPDQShadersForBlending(params);
+ if (!UpdateRPDQWithSkiaFilters(params))
+ return;
+ UseRenderPass(current_frame()->current_render_pass);
+ SetViewport();
+ UpdateRPDQTexturesForSampling(params);
+ UpdateRPDQBlendMode(params);
+ ChooseRPDQProgram(params);
+ UpdateRPDQUniforms(params);
+ DrawRPDQ(*params);
+}
+
+bool GLRenderer::InitializeRPDQParameters(
+ DrawRenderPassDrawQuadParams* params) {
+ const cc::RenderPassDrawQuad* quad = params->quad;
+ SkMatrix local_matrix;
+ local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y());
+ local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y());
+ params->filters = FiltersForPass(quad->render_pass_id);
+ params->background_filters = BackgroundFiltersForPass(quad->render_pass_id);
+ gfx::Rect dst_rect = params->filters
+ ? params->filters->MapRect(quad->rect, local_matrix)
+ : quad->rect;
+ params->dst_rect.SetRect(static_cast<float>(dst_rect.x()),
+ static_cast<float>(dst_rect.y()),
+ static_cast<float>(dst_rect.width()),
+ static_cast<float>(dst_rect.height()));
+ gfx::Transform quad_rect_matrix;
+ gfx::Rect quad_layer_rect(quad->shared_quad_state->quad_layer_rect);
+ if (params->filters)
+ quad_layer_rect = params->filters->MapRect(quad_layer_rect, local_matrix);
+ QuadRectTransform(&quad_rect_matrix, params->quad_to_target_transform,
+ gfx::RectF(quad_layer_rect));
+ params->contents_device_transform =
+ params->window_matrix * params->projection_matrix * quad_rect_matrix;
+ params->contents_device_transform.FlattenTo2d();
+
+ // Can only draw surface if device matrix is invertible.
+ if (!params->contents_device_transform.IsInvertible())
+ return false;
+
+ // TODO(sunxd): unify the anti-aliasing logic of RPDQ and cc::TileDrawQuad.
+ params->surface_quad = SharedGeometryQuad();
+ gfx::QuadF device_layer_quad;
+ if (settings_->allow_antialiasing && quad->IsEdge()) {
+ bool clipped = false;
+ device_layer_quad = cc::MathUtil::MapQuad(params->contents_device_transform,
+ params->surface_quad, &clipped);
+ params->use_aa = ShouldAntialiasQuad(device_layer_quad, clipped,
+ settings_->force_antialiasing);
+ }
+
+ const gfx::QuadF* aa_quad = params->use_aa ? &device_layer_quad : nullptr;
+ SetupRenderPassQuadForClippingAndAntialiasing(
+ params->contents_device_transform, quad, aa_quad, params->clip_region,
+ &params->surface_quad, params->edge);
+
+ return true;
+}
+
+void GLRenderer::UpdateRPDQShadersForBlending(
+ DrawRenderPassDrawQuadParams* params) {
+ const cc::RenderPassDrawQuad* quad = params->quad;
+ SkBlendMode blend_mode = quad->shared_quad_state->blend_mode;
+ params->use_shaders_for_blending =
+ !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
+ ShouldApplyBackgroundFilters(quad, params->background_filters) ||
+ settings_->force_blending_with_shaders;
+
+ if (params->use_shaders_for_blending) {
+ // Compute a bounding box around the pixels that will be visible through
+ // the quad.
+ gfx::Rect unclipped_rect;
+ params->background_rect = GetBackdropBoundingBoxForRenderPassQuad(
+ quad, params->contents_device_transform, params->filters,
+ params->background_filters, params->clip_region, params->use_aa,
+ &unclipped_rect);
+
+ if (!params->background_rect.IsEmpty()) {
+ // The pixels from the filtered background should completely replace the
+ // current pixel values.
+ if (blend_enabled())
+ SetBlendEnabled(false);
+
+ // Read the pixels in the bounding box into a buffer R.
+ // This function allocates a texture, which should contribute to the
+ // amount of memory used by render surfaces:
+ // LayerTreeHost::CalculateMemoryForRenderSurfaces.
+ params->background_texture = GetBackdropTexture(params->background_rect);
+
+ if (ShouldApplyBackgroundFilters(quad, params->background_filters) &&
+ params->background_texture) {
+ // Apply the background filters to R, so that it is applied in the
+ // pixels' coordinate space.
+ params->background_image = ApplyBackgroundFilters(
+ quad, *params->background_filters, params->background_texture.get(),
+ gfx::RectF(params->background_rect), gfx::RectF(unclipped_rect));
+ if (params->background_image) {
+ params->background_image_id =
+ skia::GrBackendObjectToGrGLTextureInfo(
+ params->background_image->getTextureHandle(true))
+ ->fID;
+ DCHECK(params->background_image_id);
+ }
+ }
+ }
+
+ if (!params->background_texture) {
+ // Something went wrong with reading the backdrop.
+ DCHECK(!params->background_image_id);
+ params->use_shaders_for_blending = false;
+ } else if (params->background_image_id) {
+ // Reset original background texture if there is not any mask
+ if (!quad->mask_resource_id())
+ params->background_texture.reset();
+ } else if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ ShouldApplyBackgroundFilters(quad, params->background_filters)) {
+ // Something went wrong with applying background filters to the backdrop.
+ params->use_shaders_for_blending = false;
+ params->background_texture.reset();
+ }
+ }
+ // Need original background texture for mask?
+ params->mask_for_background =
+ params->background_texture && // Have original background texture
+ params->background_image_id && // Have filtered background texture
+ quad->mask_resource_id(); // Have mask texture
+ DCHECK_EQ(params->background_texture || params->background_image_id,
+ params->use_shaders_for_blending);
+}
+
+bool GLRenderer::UpdateRPDQWithSkiaFilters(
+ DrawRenderPassDrawQuadParams* params) {
+ const cc::RenderPassDrawQuad* quad = params->quad;
+ // Apply filters to the contents texture.
+ if (params->filters) {
+ DCHECK(!params->filters->IsEmpty());
+ sk_sp<SkImageFilter> filter = cc::RenderSurfaceFilters::BuildImageFilter(
+ *params->filters, gfx::SizeF(params->contents_texture->size()));
+ if (filter) {
+ SkColorFilter* colorfilter_rawptr = NULL;
+ filter->asColorFilter(&colorfilter_rawptr);
+ sk_sp<SkColorFilter> cf(colorfilter_rawptr);
+
+ if (cf && cf->asColorMatrix(params->color_matrix)) {
+ // We have a color matrix at the root of the filter DAG; apply it
+ // locally in the compositor and process the rest of the DAG (if any)
+ // in Skia.
+ params->use_color_matrix = true;
+ filter = sk_ref_sp(filter->getInput(0));
+ }
+ if (filter) {
+ gfx::Rect clip_rect = quad->shared_quad_state->clip_rect;
+ if (clip_rect.IsEmpty()) {
+ clip_rect = current_draw_rect_;
+ }
+ gfx::Transform transform = params->quad_to_target_transform;
+ gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect));
+ gfx::QuadF local_clip = MapQuadToLocalSpace(transform, clip_quad);
+ params->dst_rect.Intersect(local_clip.BoundingBox());
+ // If we've been fully clipped out (by crop rect or clipping), there's
+ // nothing to draw.
+ if (params->dst_rect.IsEmpty()) {
+ return false;
+ }
+ SkIPoint offset;
+ SkIRect subset;
+ gfx::RectF src_rect(quad->rect);
+
+ cc::DisplayResourceProvider::ScopedReadLockGL
+ prefilter_contents_texture_lock(resource_provider_,
+ params->contents_texture->id());
+ params->contents_color_space =
+ prefilter_contents_texture_lock.color_space();
+ params->filter_image = ApplyImageFilter(
+ ScopedUseGrContext::Create(this), src_rect, params->dst_rect,
+ quad->filters_scale, std::move(filter),
+ prefilter_contents_texture_lock, &offset, &subset,
+ params->flip_texture, quad->filters_origin);
+ if (!params->filter_image)
+ return false;
+ params->dst_rect =
+ gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
+ subset.width(), subset.height());
+ params->src_offset.SetPoint(subset.x(), subset.y());
+ gfx::RectF tex_rect = gfx::RectF(gfx::PointF(params->src_offset),
+ params->dst_rect.size());
+ params->tex_coord_rect = tex_rect;
+ }
+ }
+ }
+ return true;
+}
+
+void GLRenderer::UpdateRPDQTexturesForSampling(
+ DrawRenderPassDrawQuadParams* params) {
+ if (params->quad->mask_resource_id()) {
+ params->mask_resource_lock.reset(
+ new cc::DisplayResourceProvider::ScopedSamplerGL(
+ resource_provider_, params->quad->mask_resource_id(), GL_TEXTURE1,
+ GL_LINEAR));
+ }
+
+ if (params->filter_image) {
+ GrSurfaceOrigin origin;
+ GLuint filter_image_id =
+ skia::GrBackendObjectToGrGLTextureInfo(
+ params->filter_image->getTextureHandle(true, &origin))
+ ->fID;
+ DCHECK(filter_image_id);
+ DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
+ gl_->BindTexture(GL_TEXTURE_2D, filter_image_id);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // |params->contents_color_space| was populated when |params->filter_image|
+ // was populated.
+ params->source_needs_flip = kBottomLeft_GrSurfaceOrigin == origin;
+ } else {
+ params->contents_resource_lock =
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedSamplerGL>(
+ resource_provider_, params->contents_texture->id(), GL_LINEAR);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ params->contents_resource_lock->target());
+ params->contents_color_space =
+ params->contents_resource_lock->color_space();
+ params->source_needs_flip = params->flip_texture;
+ }
+}
+
+void GLRenderer::UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params) {
+ SkBlendMode blend_mode = params->quad->shared_quad_state->blend_mode;
+ SetBlendEnabled(!params->use_shaders_for_blending &&
+ (params->quad->ShouldDrawWithBlending() ||
+ !IsDefaultBlendMode(blend_mode)));
+ if (!params->use_shaders_for_blending) {
+ if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
+ gl_->BlendBarrierKHR();
+
+ ApplyBlendModeUsingBlendFunc(blend_mode);
+ }
+}
+
+void GLRenderer::ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params) {
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ params->quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
+
+ BlendMode shader_blend_mode =
+ params->use_shaders_for_blending
+ ? BlendModeFromSkXfermode(params->quad->shared_quad_state->blend_mode)
+ : BLEND_MODE_NONE;
+
+ SamplerType sampler_type = SAMPLER_TYPE_2D;
+ MaskMode mask_mode = NO_MASK;
+ bool mask_for_background = params->mask_for_background;
+ if (params->mask_resource_lock) {
+ mask_mode = HAS_MASK;
+ sampler_type =
+ SamplerTypeFromTextureTarget(params->mask_resource_lock->target());
+ }
+ SetUseProgram(ProgramKey::RenderPass(
+ tex_coord_precision, sampler_type, shader_blend_mode,
+ params->use_aa ? USE_AA : NO_AA, mask_mode,
+ mask_for_background, params->use_color_matrix),
+ params->contents_color_space);
+}
+
+void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
+ gfx::RectF tex_rect = params->tex_coord_rect;
+
+ gfx::Size texture_size;
+ if (params->filter_image) {
+ texture_size.set_width(params->filter_image->width());
+ texture_size.set_height(params->filter_image->height());
+ } else {
+ texture_size = params->contents_texture->size();
+ }
+ tex_rect.Scale(1.0f / texture_size.width(), 1.0f / texture_size.height());
+
+ DCHECK(current_program_->vertex_tex_transform_location() != -1 ||
+ IsContextLost());
+ if (params->source_needs_flip) {
+ // Flip the content vertically in the shader, as the cc::RenderPass input
+ // texture is already oriented the same way as the framebuffer, but the
+ // projection transform does a flip.
+ gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
+ tex_rect.x(), 1.0f - tex_rect.y(), tex_rect.width(),
+ -tex_rect.height());
+ } else {
+ // Tile textures are oriented opposite the framebuffer, so can use
+ // the projection transform to do the flip.
+ gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
+ tex_rect.x(), tex_rect.y(), tex_rect.width(),
+ tex_rect.height());
+ }
+
+ GLint last_texture_unit = 0;
+ if (current_program_->mask_sampler_location() != -1) {
+ DCHECK(params->mask_resource_lock);
+ DCHECK_NE(current_program_->mask_tex_coord_scale_location(), 1);
+ DCHECK_NE(current_program_->mask_tex_coord_offset_location(), 1);
+ gl_->Uniform1i(current_program_->mask_sampler_location(), 1);
+
+ gfx::RectF mask_uv_rect = params->quad->mask_uv_rect;
+ if (SamplerTypeFromTextureTarget(params->mask_resource_lock->target()) !=
+ SAMPLER_TYPE_2D) {
+ mask_uv_rect.Scale(params->quad->mask_texture_size.width(),
+ params->quad->mask_texture_size.height());
+ }
+
+ SkMatrix tex_to_mask = SkMatrix::MakeRectToRect(RectFToSkRect(tex_rect),
+ RectFToSkRect(mask_uv_rect),
+ SkMatrix::kFill_ScaleToFit);
+
+ if (params->source_needs_flip) {
+ // Mask textures are oriented vertically flipped relative to the
+ // framebuffer and the cc::RenderPass contents texture, so we flip the tex
+ // coords from the cc::RenderPass texture to find the mask texture coords.
+ tex_to_mask.preTranslate(0, 1);
+ tex_to_mask.preScale(1, -1);
+ }
+
+ gl_->Uniform2f(current_program_->mask_tex_coord_offset_location(),
+ tex_to_mask.getTranslateX(), tex_to_mask.getTranslateY());
+ gl_->Uniform2f(current_program_->mask_tex_coord_scale_location(),
+ tex_to_mask.getScaleX(), tex_to_mask.getScaleY());
+ last_texture_unit = 1;
+ }
+
+ if (current_program_->edge_location() != -1)
+ gl_->Uniform3fv(current_program_->edge_location(), 8, params->edge);
+
+ if (current_program_->color_matrix_location() != -1) {
+ float matrix[16];
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j)
+ matrix[i * 4 + j] = SkScalarToFloat(params->color_matrix[j * 5 + i]);
+ }
+ gl_->UniformMatrix4fv(current_program_->color_matrix_location(), 1, false,
+ matrix);
+ }
+ static const float kScale = 1.0f / 255.0f;
+ if (current_program_->color_offset_location() != -1) {
+ float offset[4];
+ for (int i = 0; i < 4; ++i)
+ offset[i] = SkScalarToFloat(params->color_matrix[i * 5 + 4]) * kScale;
+
+ gl_->Uniform4fv(current_program_->color_offset_location(), 1, offset);
+ }
+
+ if (current_program_->backdrop_location() != -1) {
+ DCHECK(params->background_texture || params->background_image_id);
+ DCHECK_NE(current_program_->backdrop_location(), 0);
+ DCHECK_NE(current_program_->backdrop_rect_location(), 0);
+
+ gl_->Uniform1i(current_program_->backdrop_location(), ++last_texture_unit);
+
+ gl_->Uniform4f(current_program_->backdrop_rect_location(),
+ params->background_rect.x(), params->background_rect.y(),
+ params->background_rect.width(),
+ params->background_rect.height());
+
+ if (params->background_image_id) {
+ gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit);
+ gl_->BindTexture(GL_TEXTURE_2D, params->background_image_id);
+ gl_->ActiveTexture(GL_TEXTURE0);
+ if (params->mask_for_background)
+ gl_->Uniform1i(current_program_->original_backdrop_location(),
+ ++last_texture_unit);
+ }
+ if (params->background_texture) {
+ params->shader_background_sampler_lock =
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedSamplerGL>(
+ resource_provider_, params->background_texture->id(),
+ GL_TEXTURE0 + last_texture_unit, GL_LINEAR);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ params->shader_background_sampler_lock->target());
+ }
+ }
+
+ SetShaderOpacity(params->quad);
+ SetShaderQuadF(params->surface_quad);
+}
+
+void GLRenderer::DrawRPDQ(const DrawRenderPassDrawQuadParams& params) {
+ DrawQuadGeometry(params.projection_matrix, params.quad_to_target_transform,
+ params.dst_rect);
+
+ // Flush the compositor context before the filter bitmap goes out of
+ // scope, so the draw gets processed before the filter texture gets deleted.
+ if (params.filter_image)
+ gl_->Flush();
+
+ if (!params.use_shaders_for_blending)
+ RestoreBlendFuncToDefault(params.quad->shared_quad_state->blend_mode);
+}
+
+namespace {
+// These functions determine if a quad, clipped by a clip_region contains
+// the entire {top|bottom|left|right} edge.
+bool is_top(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+ if (!quad->IsTopEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p1().y()) < kAntiAliasingEpsilon &&
+ std::abs(clip_region->p2().y()) < kAntiAliasingEpsilon;
+}
+
+bool is_bottom(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+ if (!quad->IsBottomEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p3().y() -
+ quad->shared_quad_state->quad_layer_rect.height()) <
+ kAntiAliasingEpsilon &&
+ std::abs(clip_region->p4().y() -
+ quad->shared_quad_state->quad_layer_rect.height()) <
+ kAntiAliasingEpsilon;
+}
+
+bool is_left(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+ if (!quad->IsLeftEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p1().x()) < kAntiAliasingEpsilon &&
+ std::abs(clip_region->p4().x()) < kAntiAliasingEpsilon;
+}
+
+bool is_right(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+ if (!quad->IsRightEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p2().x() -
+ quad->shared_quad_state->quad_layer_rect.width()) <
+ kAntiAliasingEpsilon &&
+ std::abs(clip_region->p3().x() -
+ quad->shared_quad_state->quad_layer_rect.width()) <
+ kAntiAliasingEpsilon;
+}
+} // anonymous namespace
+
+static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges(
+ const cc::LayerQuad& device_layer_edges,
+ const gfx::Transform& device_transform,
+ const gfx::QuadF& tile_quad,
+ const gfx::QuadF* clip_region,
+ const cc::DrawQuad* quad) {
+ auto tile_rect = gfx::RectF(quad->visible_rect);
+
+ gfx::PointF bottom_right = tile_quad.p3();
+ gfx::PointF bottom_left = tile_quad.p4();
+ gfx::PointF top_left = tile_quad.p1();
+ gfx::PointF top_right = tile_quad.p2();
+ bool clipped = false;
+
+ // Map points to device space. We ignore |clipped|, since the result of
+ // |MapPoint()| still produces a valid point to draw the quad with. When
+ // clipped, the point will be outside of the viewport. See crbug.com/416367.
+ bottom_right =
+ cc::MathUtil::MapPoint(device_transform, bottom_right, &clipped);
+ bottom_left = cc::MathUtil::MapPoint(device_transform, bottom_left, &clipped);
+ top_left = cc::MathUtil::MapPoint(device_transform, top_left, &clipped);
+ top_right = cc::MathUtil::MapPoint(device_transform, top_right, &clipped);
+
+ cc::LayerQuad::Edge bottom_edge(bottom_right, bottom_left);
+ cc::LayerQuad::Edge left_edge(bottom_left, top_left);
+ cc::LayerQuad::Edge top_edge(top_left, top_right);
+ cc::LayerQuad::Edge right_edge(top_right, bottom_right);
+
+ // Only apply anti-aliasing to edges not clipped by culling or scissoring.
+ // If an edge is degenerate we do not want to replace it with a "proper" edge
+ // as that will cause the quad to possibly expand in strange ways.
+ if (!top_edge.degenerate() && is_top(clip_region, quad) &&
+ tile_rect.y() == quad->rect.y()) {
+ top_edge = device_layer_edges.top();
+ }
+ if (!left_edge.degenerate() && is_left(clip_region, quad) &&
+ tile_rect.x() == quad->rect.x()) {
+ left_edge = device_layer_edges.left();
+ }
+ if (!right_edge.degenerate() && is_right(clip_region, quad) &&
+ tile_rect.right() == quad->rect.right()) {
+ right_edge = device_layer_edges.right();
+ }
+ if (!bottom_edge.degenerate() && is_bottom(clip_region, quad) &&
+ tile_rect.bottom() == quad->rect.bottom()) {
+ bottom_edge = device_layer_edges.bottom();
+ }
+
+ float sign = tile_quad.IsCounterClockwise() ? -1 : 1;
+ bottom_edge.scale(sign);
+ left_edge.scale(sign);
+ top_edge.scale(sign);
+ right_edge.scale(sign);
+
+ // Create device space quad.
+ return cc::LayerQuad(left_edge, top_edge, right_edge, bottom_edge).ToQuadF();
+}
+
+float GetTotalQuadError(const gfx::QuadF* clipped_quad,
+ const gfx::QuadF* ideal_rect) {
+ return (clipped_quad->p1() - ideal_rect->p1()).LengthSquared() +
+ (clipped_quad->p2() - ideal_rect->p2()).LengthSquared() +
+ (clipped_quad->p3() - ideal_rect->p3()).LengthSquared() +
+ (clipped_quad->p4() - ideal_rect->p4()).LengthSquared();
+}
+
+// Attempt to rotate the clipped quad until it lines up the most
+// correctly. This is necessary because we check the edges of this
+// quad against the expected left/right/top/bottom for anti-aliasing.
+void AlignQuadToBoundingBox(gfx::QuadF* clipped_quad) {
+ auto bounding_quad = gfx::QuadF(clipped_quad->BoundingBox());
+ gfx::QuadF best_rotation = *clipped_quad;
+ float least_error_amount = GetTotalQuadError(clipped_quad, &bounding_quad);
+ for (size_t i = 1; i < 4; ++i) {
+ clipped_quad->Realign(1);
+ float new_error = GetTotalQuadError(clipped_quad, &bounding_quad);
+ if (new_error < least_error_amount) {
+ least_error_amount = new_error;
+ best_rotation = *clipped_quad;
+ }
+ }
+ *clipped_quad = best_rotation;
+}
+
+void InflateAntiAliasingDistances(const gfx::QuadF& quad,
+ cc::LayerQuad* device_layer_edges,
+ float edge[24]) {
+ DCHECK(!quad.BoundingBox().IsEmpty());
+ cc::LayerQuad device_layer_bounds(gfx::QuadF(quad.BoundingBox()));
+
+ device_layer_edges->InflateAntiAliasingDistance();
+ device_layer_edges->ToFloatArray(edge);
+
+ device_layer_bounds.InflateAntiAliasingDistance();
+ device_layer_bounds.ToFloatArray(&edge[12]);
+}
+
+// static
+bool GLRenderer::ShouldAntialiasQuad(const gfx::QuadF& device_layer_quad,
+ bool clipped,
+ bool force_aa) {
+ // AAing clipped quads is not supported by the code yet.
+ if (clipped)
+ return false;
+ if (device_layer_quad.BoundingBox().IsEmpty())
+ return false;
+ if (force_aa)
+ return true;
+
+ bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear();
+ bool is_nearest_rect_within_epsilon =
+ is_axis_aligned_in_target &&
+ gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(),
+ kAntiAliasingEpsilon);
+ return !is_nearest_rect_within_epsilon;
+}
+
+// static
+void GLRenderer::SetupQuadForClippingAndAntialiasing(
+ const gfx::Transform& device_transform,
+ const cc::DrawQuad* quad,
+ const gfx::QuadF* aa_quad,
+ const gfx::QuadF* clip_region,
+ gfx::QuadF* local_quad,
+ float edge[24]) {
+ gfx::QuadF rotated_clip;
+ const gfx::QuadF* local_clip_region = clip_region;
+ if (local_clip_region) {
+ rotated_clip = *clip_region;
+ AlignQuadToBoundingBox(&rotated_clip);
+ local_clip_region = &rotated_clip;
+ }
+
+ if (!aa_quad) {
+ if (local_clip_region)
+ *local_quad = *local_clip_region;
+ return;
+ }
+
+ cc::LayerQuad device_layer_edges(*aa_quad);
+ InflateAntiAliasingDistances(*aa_quad, &device_layer_edges, edge);
+
+ // If we have a clip region then we are split, and therefore
+ // by necessity, at least one of our edges is not an external
+ // one.
+ bool is_full_rect = quad->visible_rect == quad->rect;
+
+ bool region_contains_all_outside_edges =
+ is_full_rect &&
+ (is_top(local_clip_region, quad) && is_left(local_clip_region, quad) &&
+ is_bottom(local_clip_region, quad) && is_right(local_clip_region, quad));
+
+ bool use_aa_on_all_four_edges =
+ !local_clip_region && region_contains_all_outside_edges;
+
+ gfx::QuadF device_quad;
+ if (use_aa_on_all_four_edges) {
+ device_quad = device_layer_edges.ToQuadF();
+ } else {
+ gfx::QuadF tile_quad(local_clip_region
+ ? *local_clip_region
+ : gfx::QuadF(gfx::RectF(quad->visible_rect)));
+ device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges(
+ device_layer_edges, device_transform, tile_quad, local_clip_region,
+ quad);
+ }
+
+ *local_quad = MapQuadToLocalSpace(device_transform, device_quad);
+}
+
+// static
+void GLRenderer::SetupRenderPassQuadForClippingAndAntialiasing(
+ const gfx::Transform& device_transform,
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::QuadF* aa_quad,
+ const gfx::QuadF* clip_region,
+ gfx::QuadF* local_quad,
+ float edge[24]) {
+ gfx::QuadF rotated_clip;
+ const gfx::QuadF* local_clip_region = clip_region;
+ if (local_clip_region) {
+ rotated_clip = *clip_region;
+ AlignQuadToBoundingBox(&rotated_clip);
+ local_clip_region = &rotated_clip;
+ }
+
+ if (!aa_quad) {
+ GetScaledRegion(quad->rect, local_clip_region, local_quad);
+ return;
+ }
+
+ cc::LayerQuad device_layer_edges(*aa_quad);
+ InflateAntiAliasingDistances(*aa_quad, &device_layer_edges, edge);
+
+ gfx::QuadF device_quad;
+
+ // Apply anti-aliasing only to the edges that are not being clipped
+ if (local_clip_region) {
+ gfx::QuadF tile_quad(gfx::RectF(quad->visible_rect));
+ GetScaledRegion(quad->rect, local_clip_region, &tile_quad);
+ device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges(
+ device_layer_edges, device_transform, tile_quad, local_clip_region,
+ quad);
+ } else {
+ device_quad = device_layer_edges.ToQuadF();
+ }
+
+ *local_quad = MapQuadToLocalSpace(device_transform, device_quad);
+}
+
+void GLRenderer::DrawSolidColorQuad(const cc::SolidColorDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ gfx::Rect tile_rect = quad->visible_rect;
+
+ SkColor color = quad->color;
+ float opacity = quad->shared_quad_state->opacity;
+ float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
+
+ // Early out if alpha is small enough that quad doesn't contribute to output.
+ if (alpha < std::numeric_limits<float>::epsilon() &&
+ quad->ShouldDrawWithBlending() &&
+ quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver)
+ return;
+
+ gfx::Transform device_transform =
+ current_frame()->window_matrix * current_frame()->projection_matrix *
+ quad->shared_quad_state->quad_to_target_transform;
+ device_transform.FlattenTo2d();
+ if (!device_transform.IsInvertible())
+ return;
+
+ auto local_quad = gfx::QuadF(gfx::RectF(tile_rect));
+
+ gfx::QuadF device_layer_quad;
+ bool use_aa = false;
+ bool allow_aa = settings_->allow_antialiasing &&
+ !quad->force_anti_aliasing_off && quad->IsEdge();
+
+ if (allow_aa) {
+ bool clipped = false;
+ bool force_aa = false;
+ device_layer_quad = cc::MathUtil::MapQuad(
+ device_transform,
+ gfx::QuadF(
+ gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)),
+ &clipped);
+ use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa);
+ }
+
+ float edge[24];
+ const gfx::QuadF* aa_quad = use_aa ? &device_layer_quad : nullptr;
+ SetupQuadForClippingAndAntialiasing(device_transform, quad, aa_quad,
+ clip_region, &local_quad, edge);
+
+ // TODO(ccameron): Solid color draw quads need to specify their implied
+ // color space. Assume SRGB (which is wrong) for now.
+ gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB();
+ SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA),
+ quad_color_space);
+ SetShaderColor(color, opacity);
+
+ 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);
+
+ // Antialising requires a normalized quad, but this could lead to floating
+ // point precision errors, so only normalize when antialising is on.
+ if (use_aa) {
+ // Normalize to tile_rect.
+ local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
+
+ SetShaderQuadF(local_quad);
+
+ // The transform and vertex data are used to figure out the extents that the
+ // un-antialiased quad should have and which vertex this is and the float
+ // quad passed in via uniform is the actual geometry that gets used to draw
+ // it. This is why this centered rect is used and not the original
+ // quad_rect.
+ gfx::RectF centered_rect(
+ gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
+ gfx::SizeF(tile_rect.size()));
+ DrawQuadGeometry(current_frame()->projection_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ centered_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, 0);
+ num_triangles_drawn_ += 2;
+ }
+ RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
+}
+
+void GLRenderer::DrawTileQuad(const cc::TileDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ DrawContentQuad(quad, quad->resource_id(), clip_region);
+ // Draw the border if requested.
+ if (gl_composited_overlay_candidate_quad_border_) {
+ float gl_matrix[16];
+ // Generate the transform matrix
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect));
+ quad_rect_matrix = current_frame()->projection_matrix * quad_rect_matrix;
+ ToGLMatrix(gl_matrix, quad_rect_matrix);
+
+ DrawOverlayCandidateQuadBorder(gl_matrix);
+ }
+}
+
+void GLRenderer::DrawContentQuad(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::QuadF* clip_region) {
+ gfx::Transform device_transform =
+ current_frame()->window_matrix * current_frame()->projection_matrix *
+ quad->shared_quad_state->quad_to_target_transform;
+ device_transform.FlattenTo2d();
+
+ gfx::QuadF device_layer_quad;
+ bool use_aa = false;
+ bool allow_aa = settings_->allow_antialiasing && quad->IsEdge();
+ if (allow_aa) {
+ bool clipped = false;
+ bool force_aa = false;
+ device_layer_quad = cc::MathUtil::MapQuad(
+ device_transform,
+ gfx::QuadF(
+ gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)),
+ &clipped);
+ use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa);
+ }
+
+ // TODO(timav): simplify coordinate transformations in DrawContentQuadAA
+ // similar to the way DrawContentQuadNoAA works and then consider
+ // combining DrawContentQuadAA and DrawContentQuadNoAA into one method.
+ if (use_aa)
+ DrawContentQuadAA(quad, resource_id, device_transform, device_layer_quad,
+ clip_region);
+ else
+ DrawContentQuadNoAA(quad, resource_id, clip_region);
+}
+
+void GLRenderer::DrawContentQuadAA(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::Transform& device_transform,
+ const gfx::QuadF& aa_quad,
+ const gfx::QuadF* clip_region) {
+ if (!device_transform.IsInvertible())
+ return;
+
+ gfx::Rect tile_rect = quad->visible_rect;
+
+ gfx::RectF tex_coord_rect = cc::MathUtil::ScaleRectProportional(
+ quad->tex_coord_rect, gfx::RectF(quad->rect), gfx::RectF(tile_rect));
+ float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
+ float tex_to_geom_scale_y =
+ quad->rect.height() / quad->tex_coord_rect.height();
+
+ gfx::RectF clamp_geom_rect(tile_rect);
+ gfx::RectF clamp_tex_rect(tex_coord_rect);
+ // Clamp texture coordinates to avoid sampling outside the layer
+ // by deflating the tile region half a texel or half a texel
+ // minus epsilon for one pixel layers. The resulting clamp region
+ // is mapped to the unit square by the vertex shader and mapped
+ // back to normalized texture coordinates by the fragment shader
+ // after being clamped to 0-1 range.
+ float tex_clamp_x =
+ std::min(0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon);
+ float tex_clamp_y =
+ std::min(0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon);
+ float geom_clamp_x =
+ std::min(tex_clamp_x * tex_to_geom_scale_x,
+ 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon);
+ float geom_clamp_y =
+ std::min(tex_clamp_y * tex_to_geom_scale_y,
+ 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon);
+ clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y);
+ clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y);
+
+ // Map clamping rectangle to unit square.
+ float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width();
+ float vertex_tex_translate_y =
+ -clamp_geom_rect.y() / clamp_geom_rect.height();
+ float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width();
+ float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
+
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->texture_size);
+
+ auto local_quad = gfx::QuadF(gfx::RectF(tile_rect));
+ float edge[24];
+ SetupQuadForClippingAndAntialiasing(device_transform, quad, &aa_quad,
+ clip_region, &local_quad, edge);
+ cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
+ resource_provider_, resource_id,
+ quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR);
+ SamplerType sampler =
+ SamplerTypeFromTextureTarget(quad_resource_lock.target());
+
+ float fragment_tex_translate_x = clamp_tex_rect.x();
+ float fragment_tex_translate_y = clamp_tex_rect.y();
+ float fragment_tex_scale_x = clamp_tex_rect.width();
+ float fragment_tex_scale_y = clamp_tex_rect.height();
+
+ // Map to normalized texture coordinates.
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
+ gfx::Size texture_size = quad->texture_size;
+ DCHECK(!texture_size.IsEmpty());
+ fragment_tex_translate_x /= texture_size.width();
+ fragment_tex_translate_y /= texture_size.height();
+ fragment_tex_scale_x /= texture_size.width();
+ fragment_tex_scale_y /= texture_size.height();
+ }
+
+ SetUseProgram(
+ ProgramKey::Tile(tex_coord_precision, sampler, USE_AA,
+ quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE, false),
+ quad_resource_lock.color_space());
+
+ gl_->Uniform3fv(current_program_->edge_location(), 8, edge);
+
+ gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
+ vertex_tex_translate_x, vertex_tex_translate_y,
+ vertex_tex_scale_x, vertex_tex_scale_y);
+ gl_->Uniform4f(current_program_->fragment_tex_transform_location(),
+ fragment_tex_translate_x, fragment_tex_translate_y,
+ fragment_tex_scale_x, fragment_tex_scale_y);
+
+ // Blending is required for antialiasing.
+ SetBlendEnabled(true);
+
+ // Normalize to tile_rect.
+ local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
+
+ SetShaderOpacity(quad);
+ SetShaderQuadF(local_quad);
+
+ // The transform and vertex data are used to figure out the extents that the
+ // un-antialiased quad should have and which vertex this is and the float
+ // quad passed in via uniform is the actual geometry that gets used to draw
+ // it. This is why this centered rect is used and not the original quad_rect.
+ gfx::RectF centered_rect(
+ gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
+ gfx::SizeF(tile_rect.size()));
+ DrawQuadGeometry(current_frame()->projection_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ centered_rect);
+}
+
+void GLRenderer::DrawContentQuadNoAA(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::QuadF* clip_region) {
+ gfx::RectF tex_coord_rect = cc::MathUtil::ScaleRectProportional(
+ quad->tex_coord_rect, gfx::RectF(quad->rect),
+ gfx::RectF(quad->visible_rect));
+ float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
+ float tex_to_geom_scale_y =
+ quad->rect.height() / quad->tex_coord_rect.height();
+
+ bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
+ GLenum filter = (scaled || !quad->shared_quad_state->quad_to_target_transform
+ .IsIdentityOrIntegerTranslation()) &&
+ !quad->nearest_neighbor
+ ? GL_LINEAR
+ : GL_NEAREST;
+
+ cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
+ resource_provider_, resource_id, filter);
+ SamplerType sampler =
+ SamplerTypeFromTextureTarget(quad_resource_lock.target());
+
+ float vertex_tex_translate_x = tex_coord_rect.x();
+ float vertex_tex_translate_y = tex_coord_rect.y();
+ float vertex_tex_scale_x = tex_coord_rect.width();
+ float vertex_tex_scale_y = tex_coord_rect.height();
+
+ // Map to normalized texture coordinates.
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
+ gfx::Size texture_size = quad->texture_size;
+ DCHECK(!texture_size.IsEmpty());
+ vertex_tex_translate_x /= texture_size.width();
+ vertex_tex_translate_y /= texture_size.height();
+ vertex_tex_scale_x /= texture_size.width();
+ vertex_tex_scale_y /= texture_size.height();
+ }
+
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->texture_size);
+
+ SetUseProgram(
+ ProgramKey::Tile(tex_coord_precision, sampler, NO_AA,
+ quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE,
+ !quad->ShouldDrawWithBlending()),
+ quad_resource_lock.color_space());
+
+ gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
+ vertex_tex_translate_x, vertex_tex_translate_y,
+ vertex_tex_scale_x, vertex_tex_scale_y);
+
+ SetBlendEnabled(quad->ShouldDrawWithBlending());
+
+ SetShaderOpacity(quad);
+
+ // Pass quad coordinates to the uniform in the same order as GeometryBinding
+ // does, then vertices will match the texture mapping in the vertex buffer.
+ // The method SetShaderQuadF() changes the order of vertices and so it's
+ // not used here.
+ auto tile_quad = gfx::QuadF(gfx::RectF(quad->visible_rect));
+ float width = quad->visible_rect.width();
+ float height = quad->visible_rect.height();
+ auto top_left = gfx::PointF(quad->visible_rect.origin());
+ if (clip_region) {
+ tile_quad = *clip_region;
+ float gl_uv[8] = {
+ (tile_quad.p4().x() - top_left.x()) / width,
+ (tile_quad.p4().y() - top_left.y()) / height,
+ (tile_quad.p1().x() - top_left.x()) / width,
+ (tile_quad.p1().y() - top_left.y()) / height,
+ (tile_quad.p2().x() - top_left.x()) / width,
+ (tile_quad.p2().y() - top_left.y()) / height,
+ (tile_quad.p3().x() - top_left.x()) / width,
+ (tile_quad.p3().y() - top_left.y()) / height,
+ };
+ PrepareGeometry(CLIPPED_BINDING);
+ clipped_geometry_->InitializeCustomQuadWithUVs(
+ gfx::QuadF(gfx::RectF(quad->visible_rect)), gl_uv);
+ } else {
+ PrepareGeometry(SHARED_BINDING);
+ }
+ float gl_quad[8] = {
+ tile_quad.p4().x(), tile_quad.p4().y(), tile_quad.p1().x(),
+ tile_quad.p1().y(), tile_quad.p2().x(), tile_quad.p2().y(),
+ tile_quad.p3().x(), tile_quad.p3().y(),
+ };
+ gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
+
+ SetShaderMatrix(current_frame()->projection_matrix *
+ quad->shared_quad_state->quad_to_target_transform);
+
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+ num_triangles_drawn_ += 2;
+}
+
+void GLRenderer::DrawYUVVideoQuad(const cc::YUVVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ SetBlendEnabled(quad->ShouldDrawWithBlending());
+
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
+ YUVAlphaTextureMode alpha_texture_mode = quad->a_plane_resource_id()
+ ? YUV_HAS_ALPHA_TEXTURE
+ : YUV_NO_ALPHA_TEXTURE;
+ UVTextureMode uv_texture_mode =
+ quad->v_plane_resource_id() == quad->u_plane_resource_id()
+ ? UV_TEXTURE_MODE_UV
+ : UV_TEXTURE_MODE_U_V;
+
+ // TODO(ccameron): There are currently three sources of the color space: the
+ // resource, quad->color_space, and quad->video_color_space. Remove two of
+ // them.
+ gfx::ColorSpace src_color_space = quad->video_color_space;
+ gfx::ColorSpace dst_color_space =
+ current_frame()->current_render_pass->color_space;
+ if (!base::FeatureList::IsEnabled(media::kVideoColorManagement) &&
+ !settings_->enable_color_correct_rendering) {
+ dst_color_space = gfx::ColorSpace();
+ switch (quad->color_space) {
+ case cc::YUVVideoDrawQuad::REC_601:
+ src_color_space = gfx::ColorSpace::CreateREC601();
+ break;
+ case cc::YUVVideoDrawQuad::REC_709:
+ src_color_space = gfx::ColorSpace::CreateREC709();
+ break;
+ case cc::YUVVideoDrawQuad::JPEG:
+ src_color_space = gfx::ColorSpace::CreateJpeg();
+ break;
+ }
+ }
+ // Invalid or unspecified color spaces should be treated as REC709.
+ if (!src_color_space.IsValid())
+ src_color_space = gfx::ColorSpace::CreateREC709();
+
+ // The source color space should never be RGB.
+ DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB());
+
+ cc::DisplayResourceProvider::ScopedSamplerGL y_plane_lock(
+ resource_provider_, quad->y_plane_resource_id(), GL_TEXTURE1, GL_LINEAR);
+ if (base::FeatureList::IsEnabled(media::kVideoColorManagement))
+ DCHECK_EQ(src_color_space, y_plane_lock.color_space());
+ cc::DisplayResourceProvider::ScopedSamplerGL u_plane_lock(
+ resource_provider_, quad->u_plane_resource_id(), GL_TEXTURE2, GL_LINEAR);
+ DCHECK_EQ(y_plane_lock.target(), u_plane_lock.target());
+ DCHECK_EQ(y_plane_lock.color_space(), u_plane_lock.color_space());
+ // TODO(jbauman): Use base::Optional when available.
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> v_plane_lock;
+
+ if (uv_texture_mode == UV_TEXTURE_MODE_U_V) {
+ v_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL(
+ resource_provider_, quad->v_plane_resource_id(), GL_TEXTURE3,
+ GL_LINEAR));
+ DCHECK_EQ(y_plane_lock.target(), v_plane_lock->target());
+ DCHECK_EQ(y_plane_lock.color_space(), v_plane_lock->color_space());
+ }
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> a_plane_lock;
+ if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE) {
+ a_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL(
+ resource_provider_, quad->a_plane_resource_id(), GL_TEXTURE4,
+ GL_LINEAR));
+ DCHECK_EQ(y_plane_lock.target(), a_plane_lock->target());
+ }
+
+ // All planes must have the same sampler type.
+ SamplerType sampler = SamplerTypeFromTextureTarget(y_plane_lock.target());
+
+ SetUseProgram(ProgramKey::YUVVideo(tex_coord_precision, sampler,
+ alpha_texture_mode, uv_texture_mode),
+ src_color_space, dst_color_space);
+
+ gfx::SizeF ya_tex_scale(1.0f, 1.0f);
+ gfx::SizeF uv_tex_scale(1.0f, 1.0f);
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
+ DCHECK(!quad->ya_tex_size.IsEmpty());
+ DCHECK(!quad->uv_tex_size.IsEmpty());
+ ya_tex_scale = gfx::SizeF(1.0f / quad->ya_tex_size.width(),
+ 1.0f / quad->ya_tex_size.height());
+ uv_tex_scale = gfx::SizeF(1.0f / quad->uv_tex_size.width(),
+ 1.0f / quad->uv_tex_size.height());
+ }
+
+ float ya_vertex_tex_translate_x =
+ quad->ya_tex_coord_rect.x() * ya_tex_scale.width();
+ float ya_vertex_tex_translate_y =
+ quad->ya_tex_coord_rect.y() * ya_tex_scale.height();
+ float ya_vertex_tex_scale_x =
+ quad->ya_tex_coord_rect.width() * ya_tex_scale.width();
+ float ya_vertex_tex_scale_y =
+ quad->ya_tex_coord_rect.height() * ya_tex_scale.height();
+
+ float uv_vertex_tex_translate_x =
+ quad->uv_tex_coord_rect.x() * uv_tex_scale.width();
+ float uv_vertex_tex_translate_y =
+ quad->uv_tex_coord_rect.y() * uv_tex_scale.height();
+ float uv_vertex_tex_scale_x =
+ quad->uv_tex_coord_rect.width() * uv_tex_scale.width();
+ float uv_vertex_tex_scale_y =
+ quad->uv_tex_coord_rect.height() * uv_tex_scale.height();
+
+ gl_->Uniform2f(current_program_->ya_tex_scale_location(),
+ ya_vertex_tex_scale_x, ya_vertex_tex_scale_y);
+ gl_->Uniform2f(current_program_->ya_tex_offset_location(),
+ ya_vertex_tex_translate_x, ya_vertex_tex_translate_y);
+ gl_->Uniform2f(current_program_->uv_tex_scale_location(),
+ uv_vertex_tex_scale_x, uv_vertex_tex_scale_y);
+ gl_->Uniform2f(current_program_->uv_tex_offset_location(),
+ uv_vertex_tex_translate_x, uv_vertex_tex_translate_y);
+
+ gfx::RectF ya_clamp_rect(ya_vertex_tex_translate_x, ya_vertex_tex_translate_y,
+ ya_vertex_tex_scale_x, ya_vertex_tex_scale_y);
+ ya_clamp_rect.Inset(0.5f * ya_tex_scale.width(),
+ 0.5f * ya_tex_scale.height());
+ gfx::RectF uv_clamp_rect(uv_vertex_tex_translate_x, uv_vertex_tex_translate_y,
+ uv_vertex_tex_scale_x, uv_vertex_tex_scale_y);
+ uv_clamp_rect.Inset(0.5f * uv_tex_scale.width(),
+ 0.5f * uv_tex_scale.height());
+ gl_->Uniform4f(current_program_->ya_clamp_rect_location(), ya_clamp_rect.x(),
+ ya_clamp_rect.y(), ya_clamp_rect.right(),
+ ya_clamp_rect.bottom());
+ gl_->Uniform4f(current_program_->uv_clamp_rect_location(), uv_clamp_rect.x(),
+ uv_clamp_rect.y(), uv_clamp_rect.right(),
+ uv_clamp_rect.bottom());
+
+ gl_->Uniform1i(current_program_->y_texture_location(), 1);
+ if (uv_texture_mode == UV_TEXTURE_MODE_UV) {
+ gl_->Uniform1i(current_program_->uv_texture_location(), 2);
+ } else {
+ gl_->Uniform1i(current_program_->u_texture_location(), 2);
+ gl_->Uniform1i(current_program_->v_texture_location(), 3);
+ }
+ if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE)
+ gl_->Uniform1i(current_program_->a_texture_location(), 4);
+
+ gl_->Uniform1f(current_program_->resource_multiplier_location(),
+ quad->resource_multiplier);
+ gl_->Uniform1f(current_program_->resource_offset_location(),
+ quad->resource_offset);
+
+ // The transform and vertex data are used to figure out the extents that the
+ // un-antialiased quad should have and which vertex this is and the float
+ // quad passed in via uniform is the actual geometry that gets used to draw
+ // it. This is why this centered rect is used and not the original quad_rect.
+ auto tile_rect = gfx::RectF(quad->rect);
+
+ SetShaderOpacity(quad);
+ if (!clip_region) {
+ DrawQuadGeometry(current_frame()->projection_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ tile_rect);
+ } else {
+ float uvs[8] = {0};
+ GetScaledUVs(quad->visible_rect, clip_region, uvs);
+ gfx::QuadF region_quad = *clip_region;
+ region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
+ region_quad -= gfx::Vector2dF(0.5f, 0.5f);
+ DrawQuadGeometryClippedByQuadF(
+ quad->shared_quad_state->quad_to_target_transform, tile_rect,
+ region_quad, uvs);
+ }
+}
+
+void GLRenderer::DrawStreamVideoQuad(const cc::StreamVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ SetBlendEnabled(quad->ShouldDrawWithBlending());
+
+ DCHECK(output_surface_->context_provider()
+ ->ContextCapabilities()
+ .egl_image_external);
+
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
+
+ cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ quad->resource_id());
+
+ SetUseProgram(ProgramKey::VideoStream(tex_coord_precision),
+ lock.color_space());
+
+ DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
+ gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id());
+
+ static float gl_matrix[16];
+ ToGLMatrix(&gl_matrix[0], quad->matrix);
+ gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+ current_program_->tex_matrix_location(), false, gl_matrix);
+
+ SetShaderOpacity(quad);
+ gfx::Size texture_size = lock.size();
+ gfx::Vector2dF uv = quad->matrix.Scale2d();
+ gfx::RectF uv_visible_rect(0, 0, uv.x(), uv.y());
+ const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
+ Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
+ gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
+ tex_clamp_rect.data[0], tex_clamp_rect.data[1],
+ tex_clamp_rect.data[2], tex_clamp_rect.data[3]);
+
+ if (!clip_region) {
+ DrawQuadGeometry(current_frame()->projection_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect));
+ } else {
+ gfx::QuadF region_quad(*clip_region);
+ region_quad.Scale(1.0f / quad->rect.width(), 1.0f / quad->rect.height());
+ region_quad -= gfx::Vector2dF(0.5f, 0.5f);
+ float uvs[8] = {0};
+ GetScaledUVs(quad->visible_rect, clip_region, uvs);
+ DrawQuadGeometryClippedByQuadF(
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect), region_quad, uvs);
+ }
+}
+
+void GLRenderer::DrawOverlayCandidateQuadBorder(float* gl_matrix) {
+ SetBlendEnabled(false);
+ SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB());
+
+ gl_->UniformMatrix4fv(current_program_->matrix_location(), 1, false,
+ gl_matrix);
+
+ // Pick a random color based on the scale on X and Y.
+ int colorIndex = static_cast<int>(gl_matrix[0] * gl_matrix[5]);
+ SkColor color =
+ cc::DebugColors::GLCompositedTextureQuadBorderColor(colorIndex);
+ SetShaderColor(color, 1.f);
+
+ gl_->LineWidth(cc::DebugColors::GLCompositedTextureQuadBoderWidth());
+ // The indices for the line are stored in the same array as the triangle
+ // indices.
+ gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
+}
+
+void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
+ // Check to see if we have anything to draw.
+ if (draw_cache_.is_empty)
+ return;
+
+ PrepareGeometry(flush_binding);
+
+ // Set the correct blending mode.
+ SetBlendEnabled(draw_cache_.needs_blending);
+
+ // Assume the current active textures is 0.
+ cc::DisplayResourceProvider::ScopedSamplerGL locked_quad(
+ resource_provider_, draw_cache_.resource_id,
+ draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR);
+
+ // Bind the program to the GL state.
+ SetUseProgram(draw_cache_.program_key, locked_quad.color_space());
+
+ DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
+ gl_->BindTexture(locked_quad.target(), locked_quad.texture_id());
+
+ static_assert(sizeof(Float4) == 4 * sizeof(float),
+ "Float4 struct should be densely packed");
+ static_assert(sizeof(Float16) == 16 * sizeof(float),
+ "Float16 struct should be densely packed");
+
+ // Upload the tranforms for both points and uvs.
+ gl_->UniformMatrix4fv(
+ current_program_->matrix_location(),
+ static_cast<int>(draw_cache_.matrix_data.size()), false,
+ reinterpret_cast<float*>(&draw_cache_.matrix_data.front()));
+ gl_->Uniform4fv(current_program_->vertex_tex_transform_location(),
+ static_cast<int>(draw_cache_.uv_xform_data.size()),
+ reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()));
+
+ if (current_program_->tex_clamp_rect_location() != -1) {
+ // Draw batching is not allowed with texture clamping.
+ DCHECK_EQ(1u, draw_cache_.matrix_data.size());
+ gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
+ draw_cache_.tex_clamp_rect_data.data[0],
+ draw_cache_.tex_clamp_rect_data.data[1],
+ draw_cache_.tex_clamp_rect_data.data[2],
+ draw_cache_.tex_clamp_rect_data.data[3]);
+ }
+
+ if (draw_cache_.background_color != SK_ColorTRANSPARENT) {
+ Float4 background_color =
+ PremultipliedColor(draw_cache_.background_color, 1.f);
+ gl_->Uniform4fv(current_program_->background_color_location(), 1,
+ background_color.data);
+ }
+
+ gl_->Uniform1fv(
+ current_program_->vertex_opacity_location(),
+ static_cast<int>(draw_cache_.vertex_opacity_data.size()),
+ static_cast<float*>(&draw_cache_.vertex_opacity_data.front()));
+
+ DCHECK_LE(draw_cache_.matrix_data.size(),
+ static_cast<size_t>(std::numeric_limits<int>::max()) / 6u);
+ // Draw the quads!
+ gl_->DrawElements(GL_TRIANGLES,
+ 6 * static_cast<int>(draw_cache_.matrix_data.size()),
+ GL_UNSIGNED_SHORT, 0);
+ num_triangles_drawn_ += 2 * static_cast<int>(draw_cache_.matrix_data.size());
+
+ // Draw the border if requested.
+ if (gl_composited_overlay_candidate_quad_border_) {
+ // When we draw the composited borders we have one flush per quad.
+ DCHECK_EQ(1u, draw_cache_.matrix_data.size());
+ DrawOverlayCandidateQuadBorder(
+ reinterpret_cast<float*>(&draw_cache_.matrix_data.front()));
+ }
+
+ // Clear the cache.
+ draw_cache_.is_empty = true;
+ draw_cache_.resource_id = -1;
+ draw_cache_.uv_xform_data.resize(0);
+ draw_cache_.vertex_opacity_data.resize(0);
+ draw_cache_.matrix_data.resize(0);
+ draw_cache_.tex_clamp_rect_data = Float4();
+
+ // If we had a clipped binding, prepare the shared binding for the
+ // next inserts.
+ if (flush_binding == CLIPPED_BINDING) {
+ PrepareGeometry(SHARED_BINDING);
+ }
+}
+
+void GLRenderer::EnqueueTextureQuad(const cc::TextureDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ // If we have a clip_region then we have to render the next quad
+ // with dynamic geometry, therefore we must flush all pending
+ // texture quads.
+ if (clip_region) {
+ // We send in false here because we want to flush what's currently in the
+ // queue using the shared_geometry and not clipped_geometry
+ FlushTextureQuadCache(SHARED_BINDING);
+ }
+
+ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
+
+ cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ quad->resource_id());
+ const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
+
+ bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() &&
+ (quad->uv_top_left != gfx::PointF(0, 0) ||
+ quad->uv_bottom_right != gfx::PointF(1, 1));
+ ProgramKey program_key = ProgramKey::Texture(
+ tex_coord_precision, sampler,
+ quad->premultiplied_alpha ? PREMULTIPLIED_ALPHA : NON_PREMULTIPLIED_ALPHA,
+ quad->background_color != SK_ColorTRANSPARENT, need_tex_clamp_rect);
+ int resource_id = quad->resource_id();
+
+ size_t max_quads = StaticGeometryBinding::NUM_QUADS;
+ if (draw_cache_.is_empty || draw_cache_.program_key != program_key ||
+ draw_cache_.resource_id != resource_id ||
+ draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
+ draw_cache_.nearest_neighbor != quad->nearest_neighbor ||
+ draw_cache_.background_color != quad->background_color ||
+ draw_cache_.matrix_data.size() >= max_quads) {
+ FlushTextureQuadCache(SHARED_BINDING);
+ draw_cache_.is_empty = false;
+ draw_cache_.program_key = program_key;
+ draw_cache_.resource_id = resource_id;
+ draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
+ draw_cache_.nearest_neighbor = quad->nearest_neighbor;
+ draw_cache_.background_color = quad->background_color;
+ }
+
+ // Generate the uv-transform
+ Float4 uv_transform = {{0.0f, 0.0f, 1.0f, 1.0f}};
+ if (!clip_region)
+ uv_transform = UVTransform(quad);
+ if (sampler == SAMPLER_TYPE_2D_RECT) {
+ // Un-normalize the texture coordiantes for rectangle targets.
+ gfx::Size texture_size = lock.size();
+ uv_transform.data[0] *= texture_size.width();
+ uv_transform.data[2] *= texture_size.width();
+ uv_transform.data[1] *= texture_size.height();
+ uv_transform.data[3] *= texture_size.height();
+ }
+ draw_cache_.uv_xform_data.push_back(uv_transform);
+
+ if (need_tex_clamp_rect) {
+ DCHECK_EQ(1u, draw_cache_.uv_xform_data.size());
+ gfx::Size texture_size = quad->resource_size_in_pixels();
+ DCHECK(!texture_size.IsEmpty());
+ gfx::RectF uv_visible_rect(
+ quad->uv_top_left.x(), quad->uv_top_left.y(),
+ quad->uv_bottom_right.x() - quad->uv_top_left.x(),
+ quad->uv_bottom_right.y() - quad->uv_top_left.y());
+ Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
+ draw_cache_.tex_clamp_rect_data = tex_clamp_rect;
+ }
+
+ // Generate the vertex opacity
+ const float opacity = quad->shared_quad_state->opacity;
+ draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
+ draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
+ draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
+ draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity);
+
+ // Generate the transform matrix
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect));
+ quad_rect_matrix = current_frame()->projection_matrix * quad_rect_matrix;
+
+ Float16 m;
+ quad_rect_matrix.matrix().asColMajorf(m.data);
+ draw_cache_.matrix_data.push_back(m);
+
+ if (clip_region) {
+ gfx::QuadF scaled_region;
+ if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
+ scaled_region = SharedGeometryQuad().BoundingBox();
+ }
+ // Both the scaled region and the SharedGeomtryQuad are in the space
+ // -0.5->0.5. We need to move that to the space 0->1.
+ float uv[8];
+ uv[0] = scaled_region.p1().x() + 0.5f;
+ uv[1] = scaled_region.p1().y() + 0.5f;
+ uv[2] = scaled_region.p2().x() + 0.5f;
+ uv[3] = scaled_region.p2().y() + 0.5f;
+ uv[4] = scaled_region.p3().x() + 0.5f;
+ uv[5] = scaled_region.p3().y() + 0.5f;
+ uv[6] = scaled_region.p4().x() + 0.5f;
+ uv[7] = scaled_region.p4().y() + 0.5f;
+ PrepareGeometry(CLIPPED_BINDING);
+ clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv);
+ FlushTextureQuadCache(CLIPPED_BINDING);
+ } else if (gl_composited_overlay_candidate_quad_border_ ||
+ need_tex_clamp_rect) {
+ FlushTextureQuadCache(SHARED_BINDING);
+ }
+}
+
+void GLRenderer::FinishDrawingFrame() {
+ if (use_sync_query_) {
+ DCHECK(current_sync_query_);
+ current_sync_query_->End();
+ pending_sync_queries_.push_back(std::move(current_sync_query_));
+ }
+
+ swap_buffer_rect_.Union(current_frame()->root_damage_rect);
+ if (overdraw_feedback_)
+ FlushOverdrawFeedback(swap_buffer_rect_);
+
+ if (use_swap_with_bounds_)
+ swap_content_bounds_ = current_frame()->root_content_bounds;
+
+ current_framebuffer_lock_ = nullptr;
+
+ gl_->Disable(GL_BLEND);
+ blend_shadow_ = false;
+
+ ScheduleCALayers();
+ ScheduleDCLayers();
+ ScheduleOverlays();
+
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.triangles"),
+ "Triangles Drawn", num_triangles_drawn_);
+}
+
+void GLRenderer::FinishDrawingQuadList() {
+ FlushTextureQuadCache(SHARED_BINDING);
+}
+
+void GLRenderer::SetEnableDCLayers(bool enable) {
+ gl_->SetEnableDCLayersCHROMIUM(enable);
+}
+
+bool GLRenderer::FlippedFramebuffer() const {
+ if (force_drawing_frame_framebuffer_unflipped_)
+ return false;
+ if (current_frame()->current_render_pass != current_frame()->root_render_pass)
+ return true;
+ return FlippedRootFramebuffer();
+}
+
+bool GLRenderer::FlippedRootFramebuffer() const {
+ // GL is normally flipped, so a flipped output results in an unflipping.
+ return !output_surface_->capabilities().flipped_output_surface;
+}
+
+void GLRenderer::EnsureScissorTestEnabled() {
+ if (is_scissor_enabled_)
+ return;
+
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Enable(GL_SCISSOR_TEST);
+ is_scissor_enabled_ = true;
+}
+
+void GLRenderer::EnsureScissorTestDisabled() {
+ if (!is_scissor_enabled_)
+ return;
+
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Disable(GL_SCISSOR_TEST);
+ is_scissor_enabled_ = false;
+}
+
+void GLRenderer::CopyCurrentRenderPassToBitmap(
+ std::unique_ptr<CopyOutputRequest> request) {
+ TRACE_EVENT0("cc", "GLRenderer::CopyCurrentRenderPassToBitmap");
+ gfx::Rect copy_rect = current_frame()->current_render_pass->output_rect;
+ if (request->has_area())
+ copy_rect.Intersect(request->area());
+ GetFramebufferPixelsAsync(copy_rect, std::move(request));
+}
+
+void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
+ transform.matrix().asColMajorf(gl_matrix);
+}
+
+void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad) {
+ if (!current_program_ || current_program_->quad_location() == -1)
+ return;
+ float gl_quad[8];
+ gl_quad[0] = quad.p1().x();
+ gl_quad[1] = quad.p1().y();
+ gl_quad[2] = quad.p2().x();
+ gl_quad[3] = quad.p2().y();
+ gl_quad[4] = quad.p3().x();
+ gl_quad[5] = quad.p3().y();
+ gl_quad[6] = quad.p4().x();
+ gl_quad[7] = quad.p4().y();
+ gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
+}
+
+void GLRenderer::SetShaderOpacity(const cc::DrawQuad* quad) {
+ if (!current_program_ || current_program_->alpha_location() == -1)
+ return;
+ gl_->Uniform1f(current_program_->alpha_location(),
+ quad->shared_quad_state->opacity);
+}
+
+void GLRenderer::SetShaderMatrix(const gfx::Transform& transform) {
+ if (!current_program_ || current_program_->matrix_location() == -1)
+ return;
+ float gl_matrix[16];
+ ToGLMatrix(gl_matrix, transform);
+ gl_->UniformMatrix4fv(current_program_->matrix_location(), 1, false,
+ gl_matrix);
+}
+
+void GLRenderer::SetShaderColor(SkColor color, float opacity) {
+ if (!current_program_ || current_program_->color_location() == -1)
+ return;
+ Float4 float_color = PremultipliedColor(color, opacity);
+ gl_->Uniform4fv(current_program_->color_location(), 1, float_color.data);
+}
+
+void GLRenderer::SetStencilEnabled(bool enabled) {
+ if (enabled == stencil_shadow_)
+ return;
+
+ if (enabled)
+ gl_->Enable(GL_STENCIL_TEST);
+ else
+ gl_->Disable(GL_STENCIL_TEST);
+ stencil_shadow_ = enabled;
+}
+
+void GLRenderer::SetBlendEnabled(bool enabled) {
+ if (enabled == blend_shadow_)
+ return;
+
+ if (enabled)
+ gl_->Enable(GL_BLEND);
+ else
+ gl_->Disable(GL_BLEND);
+ blend_shadow_ = enabled;
+}
+
+void GLRenderer::DrawQuadGeometryClippedByQuadF(
+ const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect,
+ const gfx::QuadF& clipping_region_quad,
+ const float* uvs) {
+ PrepareGeometry(CLIPPED_BINDING);
+ if (uvs) {
+ clipped_geometry_->InitializeCustomQuadWithUVs(clipping_region_quad, uvs);
+ } else {
+ clipped_geometry_->InitializeCustomQuad(clipping_region_quad);
+ }
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
+ SetShaderMatrix(current_frame()->projection_matrix * quad_rect_matrix);
+
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,
+ reinterpret_cast<const void*>(0));
+ num_triangles_drawn_ += 2;
+}
+
+void GLRenderer::DrawQuadGeometry(const gfx::Transform& projection_matrix,
+ const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect) {
+ PrepareGeometry(SHARED_BINDING);
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
+ SetShaderMatrix(projection_matrix * quad_rect_matrix);
+
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+ num_triangles_drawn_ += 2;
+}
+
+void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
+ DCHECK(visible_);
+
+ TRACE_EVENT0("cc", "GLRenderer::SwapBuffers");
+ // We're done! Time to swapbuffers!
+
+ gfx::Size surface_size = surface_size_for_swap_buffers();
+
+ cc::OutputSurfaceFrame output_frame;
+ output_frame.latency_info = std::move(latency_info);
+ output_frame.size = surface_size;
+ if (use_swap_with_bounds_) {
+ output_frame.content_bounds = std::move(swap_content_bounds_);
+ } else if (use_partial_swap_) {
+ // If supported, we can save significant bandwidth by only swapping the
+ // damaged/scissored region (clamped to the viewport).
+ swap_buffer_rect_.Intersect(gfx::Rect(surface_size));
+ int flipped_y_pos_of_rect_bottom = surface_size.height() -
+ swap_buffer_rect_.y() -
+ swap_buffer_rect_.height();
+ output_frame.sub_buffer_rect =
+ gfx::Rect(swap_buffer_rect_.x(),
+ FlippedRootFramebuffer() ? flipped_y_pos_of_rect_bottom
+ : swap_buffer_rect_.y(),
+ swap_buffer_rect_.width(), swap_buffer_rect_.height());
+ } else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) {
+ output_frame.sub_buffer_rect = swap_buffer_rect_;
+ }
+
+ swapping_overlay_resources_.push_back(std::move(pending_overlay_resources_));
+ pending_overlay_resources_.clear();
+
+ output_surface_->SwapBuffers(std::move(output_frame));
+
+ swap_buffer_rect_ = gfx::Rect();
+}
+
+void GLRenderer::SwapBuffersComplete() {
+ if (settings_->release_overlay_resources_after_gpu_query) {
+ // Once a resource has been swap-ACKed, send a query to the GPU process to
+ // ask if the resource is no longer being consumed by the system compositor.
+ // The response will come with the next swap-ACK.
+ if (!swapping_overlay_resources_.empty()) {
+ for (OverlayResourceLock& lock : swapping_overlay_resources_.front()) {
+ unsigned texture = lock->texture_id();
+ if (swapped_and_acked_overlay_resources_.find(texture) ==
+ swapped_and_acked_overlay_resources_.end()) {
+ swapped_and_acked_overlay_resources_[texture] = std::move(lock);
+ }
+ }
+ swapping_overlay_resources_.pop_front();
+ }
+
+ if (!swapped_and_acked_overlay_resources_.empty()) {
+ std::vector<unsigned> textures;
+ textures.reserve(swapped_and_acked_overlay_resources_.size());
+ for (auto& pair : swapped_and_acked_overlay_resources_) {
+ textures.push_back(pair.first);
+ }
+ gl_->ScheduleCALayerInUseQueryCHROMIUM(textures.size(), textures.data());
+ }
+ } else if (swapping_overlay_resources_.size() > 1) {
+ cc::DisplayResourceProvider::ScopedBatchReturnResources returner(
+ resource_provider_);
+
+ // If a query is not needed to release the overlay buffers, we can assume
+ // that once a swap buffer has completed we can remove the oldest buffers
+ // from the queue.
+ swapping_overlay_resources_.pop_front();
+ }
+}
+
+void GLRenderer::DidReceiveTextureInUseResponses(
+ const gpu::TextureInUseResponses& responses) {
+ DCHECK(settings_->release_overlay_resources_after_gpu_query);
+ cc::DisplayResourceProvider::ScopedBatchReturnResources returner(
+ resource_provider_);
+ for (const gpu::TextureInUseResponse& response : responses) {
+ if (!response.in_use) {
+ swapped_and_acked_overlay_resources_.erase(response.texture);
+ }
+ }
+ color_lut_cache_.Swap();
+}
+
+void GLRenderer::GetFramebufferPixelsAsync(
+ const gfx::Rect& rect,
+ std::unique_ptr<CopyOutputRequest> request) {
+ DCHECK(!request->IsEmpty());
+ if (request->IsEmpty())
+ return;
+ if (rect.IsEmpty())
+ return;
+
+ if (overdraw_feedback_)
+ FlushOverdrawFeedback(rect);
+
+ gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
+ DCHECK_LE(window_rect.right(), current_surface_size_.width());
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
+
+ if (!request->force_bitmap_result()) {
+ bool own_mailbox = !request->has_texture_mailbox();
+
+ GLuint texture_id = 0;
+ gpu::Mailbox mailbox;
+ if (own_mailbox) {
+ gl_->GenMailboxCHROMIUM(mailbox.name);
+ gl_->GenTextures(1, &texture_id);
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id);
+
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ 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_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ } else {
+ mailbox = request->texture_mailbox().mailbox();
+ DCHECK_EQ(static_cast<unsigned>(GL_TEXTURE_2D),
+ request->texture_mailbox().target());
+ DCHECK(!mailbox.IsZero());
+ const gpu::SyncToken& incoming_sync_token =
+ request->texture_mailbox().sync_token();
+ if (incoming_sync_token.HasData())
+ gl_->WaitSyncTokenCHROMIUM(incoming_sync_token.GetConstData());
+
+ texture_id =
+ gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ }
+ GetFramebufferTexture(texture_id, window_rect);
+
+ const GLuint64 fence_sync = gl_->InsertFenceSyncCHROMIUM();
+ gl_->ShallowFlushCHROMIUM();
+
+ gpu::SyncToken sync_token;
+ gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+
+ TextureMailbox texture_mailbox(mailbox, sync_token, GL_TEXTURE_2D);
+
+ std::unique_ptr<SingleReleaseCallback> release_callback;
+ if (own_mailbox) {
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+ release_callback = texture_mailbox_deleter_->GetReleaseCallback(
+ output_surface_->context_provider(), texture_id);
+ } else {
+ gl_->DeleteTextures(1, &texture_id);
+ }
+
+ request->SendTextureResult(window_rect.size(), texture_mailbox,
+ std::move(release_callback));
+ return;
+ }
+
+ DCHECK(request->force_bitmap_result());
+
+ std::unique_ptr<PendingAsyncReadPixels> pending_read(
+ new PendingAsyncReadPixels);
+ pending_read->copy_request = std::move(request);
+ pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
+ std::move(pending_read));
+
+ GLuint buffer = 0;
+ gl_->GenBuffers(1, &buffer);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, buffer);
+ gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ 4 * window_rect.size().GetArea(), NULL, GL_STREAM_READ);
+
+ GLuint query = 0;
+ gl_->GenQueriesEXT(1, &query);
+ gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query);
+
+ gl_->ReadPixels(window_rect.x(), window_rect.y(), window_rect.width(),
+ window_rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+
+ // Save the buffer to verify the callbacks happen in the expected order.
+ pending_async_read_pixels_.front()->buffer = buffer;
+
+ gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
+ context_support_->SignalQuery(
+ query,
+ base::Bind(&GLRenderer::FinishedReadback, weak_ptr_factory_.GetWeakPtr(),
+ buffer, query, window_rect.size()));
+}
+
+void GLRenderer::FinishedReadback(unsigned source_buffer,
+ unsigned query,
+ const gfx::Size& size) {
+ DCHECK(!pending_async_read_pixels_.empty());
+
+ if (query != 0) {
+ gl_->DeleteQueriesEXT(1, &query);
+ }
+
+ // Make sure we are servicing the right readback. There is no guarantee that
+ // callbacks to this function are in the same order as we post the copy
+ // requests.
+ // Nevertheless, it is very likely that the order is preserved, and thus
+ // start searching from back to the front.
+ auto iter = pending_async_read_pixels_.rbegin();
+ const auto& reverse_end = pending_async_read_pixels_.rend();
+ while (iter != reverse_end && (*iter)->buffer != source_buffer)
+ ++iter;
+
+ DCHECK(iter != reverse_end);
+ PendingAsyncReadPixels* current_read = iter->get();
+
+ uint8_t* src_pixels = NULL;
+ std::unique_ptr<SkBitmap> bitmap;
+
+ if (source_buffer != 0) {
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, source_buffer);
+ src_pixels = static_cast<uint8_t*>(gl_->MapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+
+ if (src_pixels) {
+ bitmap.reset(new SkBitmap);
+ bitmap->allocN32Pixels(size.width(), size.height());
+ uint8_t* dest_pixels = static_cast<uint8_t*>(bitmap->getPixels());
+
+ size_t row_bytes = size.width() * 4;
+ int num_rows = size.height();
+ size_t total_bytes = num_rows * row_bytes;
+ for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
+ // Flip Y axis.
+ size_t src_y = total_bytes - dest_y - row_bytes;
+ // Swizzle OpenGL -> Skia byte order.
+ for (size_t x = 0; x < row_bytes; x += 4) {
+ dest_pixels[dest_y + x + SK_R32_SHIFT / 8] =
+ src_pixels[src_y + x + 0];
+ dest_pixels[dest_y + x + SK_G32_SHIFT / 8] =
+ src_pixels[src_y + x + 1];
+ dest_pixels[dest_y + x + SK_B32_SHIFT / 8] =
+ src_pixels[src_y + x + 2];
+ dest_pixels[dest_y + x + SK_A32_SHIFT / 8] =
+ src_pixels[src_y + x + 3];
+ }
+ }
+
+ gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+ }
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ gl_->DeleteBuffers(1, &source_buffer);
+ }
+
+ if (bitmap)
+ current_read->copy_request->SendBitmapResult(std::move(bitmap));
+
+ // Conversion from reverse iterator to iterator:
+ // Iterator |iter.base() - 1| points to the same element with reverse iterator
+ // |iter|. The difference |-1| is due to the fact of correspondence of end()
+ // with rbegin().
+ pending_async_read_pixels_.erase(iter.base() - 1);
+}
+
+void GLRenderer::GetFramebufferTexture(unsigned texture_id,
+ const gfx::Rect& window_rect) {
+ DCHECK(texture_id);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
+ DCHECK_LE(window_rect.right(), current_surface_size_.width());
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
+
+ // If copying a non-root renderpass then use the format of the bound
+ // texture. Otherwise, we use the format of the default framebuffer.
+ GLenum format = current_framebuffer_lock_
+ ? GLCopyTextureInternalFormat(current_framebuffer_format_)
+ : output_surface_->GetFramebufferCopyTextureFormat();
+ // Verify the format is valid for GLES2's glCopyTexImage2D.
+ DCHECK(format == GL_ALPHA || format == GL_LUMINANCE ||
+ format == GL_LUMINANCE_ALPHA || format == GL_RGB || format == GL_RGBA)
+ << format;
+
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id);
+ gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, format, window_rect.x(),
+ window_rect.y(), window_rect.width(),
+ window_rect.height(), 0);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+}
+
+void GLRenderer::BindFramebufferToOutputSurface() {
+ current_framebuffer_lock_ = nullptr;
+ output_surface_->BindFramebuffer();
+
+ if (overdraw_feedback_) {
+ // Output surfaces that require an external stencil test should not allow
+ // overdraw feedback by setting |supports_stencil| to false.
+ DCHECK(!output_surface_->HasExternalStencilTest());
+ SetupOverdrawFeedback();
+ SetStencilEnabled(true);
+ } else if (output_surface_->HasExternalStencilTest()) {
+ output_surface_->ApplyExternalStencil();
+ SetStencilEnabled(true);
+ } else {
+ SetStencilEnabled(false);
+ }
+}
+
+bool GLRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
+ DCHECK(texture->id());
+
+ // Explicitly release lock, otherwise we can crash when try to lock
+ // same texture again.
+ current_framebuffer_lock_ = nullptr;
+
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_);
+ current_framebuffer_lock_ =
+ base::MakeUnique<cc::ResourceProvider::ScopedWriteLockGL>(
+ resource_provider_, texture->id());
+ current_framebuffer_format_ = texture->format();
+ GLuint texture_id = current_framebuffer_lock_->GetTexture();
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture_id, 0);
+ if (overdraw_feedback_) {
+ if (!offscreen_stencil_renderbuffer_id_)
+ gl_->GenRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
+ if (texture->size() != offscreen_stencil_renderbuffer_size_) {
+ gl_->BindRenderbuffer(GL_RENDERBUFFER,
+ offscreen_stencil_renderbuffer_id_);
+ gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+ texture->size().width(),
+ texture->size().height());
+ gl_->BindRenderbuffer(GL_RENDERBUFFER, 0);
+ offscreen_stencil_renderbuffer_size_ = texture->size();
+ }
+ gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER,
+ offscreen_stencil_renderbuffer_id_);
+ }
+
+ DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
+ GL_FRAMEBUFFER_COMPLETE ||
+ IsContextLost());
+
+ if (overdraw_feedback_) {
+ SetupOverdrawFeedback();
+ SetStencilEnabled(true);
+ } else {
+ SetStencilEnabled(false);
+ }
+ return true;
+}
+
+void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
+ EnsureScissorTestEnabled();
+
+ // Don't unnecessarily ask the context to change the scissor, because it
+ // may cause undesired GPU pipeline flushes.
+ if (scissor_rect == scissor_rect_)
+ return;
+
+ scissor_rect_ = scissor_rect;
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Scissor(scissor_rect.x(), scissor_rect.y(), scissor_rect.width(),
+ scissor_rect.height());
+}
+
+void GLRenderer::SetViewport() {
+ gl_->Viewport(current_window_space_viewport_.x(),
+ current_window_space_viewport_.y(),
+ current_window_space_viewport_.width(),
+ current_window_space_viewport_.height());
+}
+
+void GLRenderer::InitializeSharedObjects() {
+ TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects");
+
+ // Create an FBO for doing offscreen rendering.
+ gl_->GenFramebuffers(1, &offscreen_framebuffer_id_);
+
+ shared_geometry_ =
+ base::MakeUnique<StaticGeometryBinding>(gl_, QuadVertexRect());
+ clipped_geometry_ = base::MakeUnique<DynamicGeometryBinding>(gl_);
+}
+
+void GLRenderer::PrepareGeometry(BoundGeometry binding) {
+ if (binding == bound_geometry_) {
+ return;
+ }
+
+ switch (binding) {
+ case SHARED_BINDING:
+ shared_geometry_->PrepareForDraw();
+ break;
+ case CLIPPED_BINDING:
+ clipped_geometry_->PrepareForDraw();
+ break;
+ case NO_BINDING:
+ break;
+ }
+ bound_geometry_ = binding;
+}
+
+void GLRenderer::SetUseProgram(const ProgramKey& program_key,
+ const gfx::ColorSpace& src_color_space) {
+ // The source color space for non-YUV draw quads should always be full-range
+ // RGB.
+ if (!disable_color_checks_for_testing_)
+ DCHECK_EQ(src_color_space, src_color_space.GetAsFullRangeRGB());
+
+ // Ensure that we do not apply any color conversion unless the color correct
+ // rendering flag has been specified. This is because media mailboxes will
+ // provide YUV color spaces despite YUV to RGB conversion already having been
+ // performed.
+ if (settings_->enable_color_correct_rendering) {
+ SetUseProgram(program_key, src_color_space,
+ current_frame()->current_render_pass->color_space);
+ } else {
+ SetUseProgram(program_key, gfx::ColorSpace(), gfx::ColorSpace());
+ }
+}
+
+void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color,
+ const gfx::ColorSpace& src_color_space,
+ const gfx::ColorSpace& dst_color_space) {
+ ProgramKey program_key = program_key_no_color;
+ const gfx::ColorTransform* color_transform =
+ GetColorTransform(src_color_space, dst_color_space);
+ program_key.SetColorTransform(color_transform);
+
+ // Create and set the program if needed.
+ std::unique_ptr<Program>& program = program_cache_[program_key];
+ if (!program) {
+ program.reset(new Program);
+ program->Initialize(output_surface_->context_provider(), program_key);
+ }
+ DCHECK(program);
+ if (current_program_ != program.get()) {
+ current_program_ = program.get();
+ gl_->UseProgram(current_program_->program());
+ }
+ if (!current_program_->initialized()) {
+ DCHECK(IsContextLost());
+ return;
+ }
+
+ // Set uniforms that are common to all programs.
+ if (current_program_->sampler_location() != -1)
+ gl_->Uniform1i(current_program_->sampler_location(), 0);
+ if (current_program_->viewport_location() != -1) {
+ float viewport[4] = {
+ static_cast<float>(current_window_space_viewport_.x()),
+ static_cast<float>(current_window_space_viewport_.y()),
+ static_cast<float>(current_window_space_viewport_.width()),
+ static_cast<float>(current_window_space_viewport_.height()),
+ };
+ gl_->Uniform4fv(current_program_->viewport_location(), 1, viewport);
+ }
+ if (current_program_->lut_texture_location() != -1) {
+ ColorLUTCache::LUT lut = color_lut_cache_.GetLUT(color_transform);
+ gl_->ActiveTexture(GL_TEXTURE5);
+ gl_->BindTexture(GL_TEXTURE_2D, lut.texture);
+ gl_->Uniform1i(current_program_->lut_texture_location(), 5);
+ gl_->Uniform1f(current_program_->lut_size_location(), lut.size);
+ gl_->ActiveTexture(GL_TEXTURE0);
+ }
+}
+
+const Program* GLRenderer::GetProgramIfInitialized(
+ const ProgramKey& desc) const {
+ const auto found = program_cache_.find(desc);
+ if (found == program_cache_.end())
+ return nullptr;
+ return found->second.get();
+}
+
+const gfx::ColorTransform* GLRenderer::GetColorTransform(
+ const gfx::ColorSpace& src,
+ const gfx::ColorSpace& dst) {
+ std::unique_ptr<gfx::ColorTransform>& transform =
+ color_transform_cache_[dst][src];
+ if (!transform) {
+ transform = gfx::ColorTransform::NewColorTransform(
+ src, dst, gfx::ColorTransform::Intent::INTENT_PERCEPTUAL);
+ }
+ return transform.get();
+}
+
+void GLRenderer::CleanupSharedObjects() {
+ shared_geometry_ = nullptr;
+
+ gl_->ReleaseShaderCompiler();
+ for (auto& iter : program_cache_)
+ iter.second->Cleanup(gl_);
+ program_cache_.clear();
+ color_transform_cache_.clear();
+
+ if (offscreen_framebuffer_id_)
+ gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_);
+
+ if (offscreen_stencil_renderbuffer_id_)
+ gl_->DeleteRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
+
+ ReleaseRenderPassTextures();
+}
+
+void GLRenderer::ReinitializeGLState() {
+ is_scissor_enabled_ = false;
+ scissor_rect_ = gfx::Rect();
+ stencil_shadow_ = false;
+ blend_shadow_ = true;
+ current_program_ = nullptr;
+
+ RestoreGLState();
+}
+
+void GLRenderer::RestoreGLState() {
+ // This restores the current GLRenderer state to the GL context.
+ bound_geometry_ = NO_BINDING;
+ PrepareGeometry(SHARED_BINDING);
+
+ gl_->Disable(GL_DEPTH_TEST);
+ gl_->Disable(GL_CULL_FACE);
+ gl_->ColorMask(true, true, true, true);
+ gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ gl_->ActiveTexture(GL_TEXTURE0);
+
+ if (current_program_)
+ gl_->UseProgram(current_program_->program());
+
+ if (stencil_shadow_)
+ gl_->Enable(GL_STENCIL_TEST);
+ else
+ gl_->Disable(GL_STENCIL_TEST);
+
+ if (blend_shadow_)
+ gl_->Enable(GL_BLEND);
+ else
+ gl_->Disable(GL_BLEND);
+
+ 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());
+}
+
+bool GLRenderer::IsContextLost() {
+ return gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+}
+
+void GLRenderer::ScheduleCALayers() {
+ if (overlay_resource_pool_) {
+ overlay_resource_pool_->CheckBusyResources();
+ }
+
+ scoped_refptr<cc::CALayerOverlaySharedState> shared_state;
+ size_t copied_render_pass_count = 0;
+ for (const cc::CALayerOverlay& ca_layer_overlay :
+ current_frame()->ca_layer_overlay_list) {
+ if (ca_layer_overlay.rpdq) {
+ ScheduleRenderPassDrawQuad(&ca_layer_overlay);
+ shared_state = nullptr;
+ ++copied_render_pass_count;
+ continue;
+ }
+
+ ResourceId contents_resource_id = ca_layer_overlay.contents_resource_id;
+ unsigned texture_id = 0;
+ if (contents_resource_id) {
+ pending_overlay_resources_.push_back(
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ resource_provider_, contents_resource_id));
+ texture_id = pending_overlay_resources_.back()->texture_id();
+ }
+ GLfloat contents_rect[4] = {
+ ca_layer_overlay.contents_rect.x(), ca_layer_overlay.contents_rect.y(),
+ ca_layer_overlay.contents_rect.width(),
+ ca_layer_overlay.contents_rect.height(),
+ };
+ GLfloat bounds_rect[4] = {
+ ca_layer_overlay.bounds_rect.x(), ca_layer_overlay.bounds_rect.y(),
+ ca_layer_overlay.bounds_rect.width(),
+ ca_layer_overlay.bounds_rect.height(),
+ };
+ GLboolean is_clipped = ca_layer_overlay.shared_state->is_clipped;
+ GLfloat clip_rect[4] = {ca_layer_overlay.shared_state->clip_rect.x(),
+ ca_layer_overlay.shared_state->clip_rect.y(),
+ ca_layer_overlay.shared_state->clip_rect.width(),
+ ca_layer_overlay.shared_state->clip_rect.height()};
+ GLint sorting_context_id =
+ ca_layer_overlay.shared_state->sorting_context_id;
+ GLfloat transform[16];
+ ca_layer_overlay.shared_state->transform.asColMajorf(transform);
+ unsigned filter = ca_layer_overlay.filter;
+
+ if (ca_layer_overlay.shared_state != shared_state) {
+ shared_state = ca_layer_overlay.shared_state;
+ gl_->ScheduleCALayerSharedStateCHROMIUM(
+ ca_layer_overlay.shared_state->opacity, is_clipped, clip_rect,
+ sorting_context_id, transform);
+ }
+ gl_->ScheduleCALayerCHROMIUM(
+ texture_id, contents_rect, ca_layer_overlay.background_color,
+ ca_layer_overlay.edge_aa_mask, bounds_rect, filter);
+ }
+
+ // Take the number of copied render passes in this frame, and use 3 times that
+ // amount as the cache limit.
+ if (overlay_resource_pool_) {
+ overlay_resource_pool_->SetResourceUsageLimits(
+ std::numeric_limits<std::size_t>::max(), copied_render_pass_count * 5);
+ }
+}
+
+void GLRenderer::ScheduleDCLayers() {
+ if (overlay_resource_pool_) {
+ overlay_resource_pool_->CheckBusyResources();
+ }
+
+ scoped_refptr<cc::DCLayerOverlaySharedState> shared_state;
+ size_t copied_render_pass_count = 0;
+ for (cc::DCLayerOverlay& dc_layer_overlay :
+ current_frame()->dc_layer_overlay_list) {
+ DCHECK(!dc_layer_overlay.rpdq);
+
+ int i = 0;
+ unsigned texture_ids[cc::DrawQuad::Resources::kMaxResourceIdCount] = {};
+ int ids_to_send = 0;
+
+ for (const auto& contents_resource_id : dc_layer_overlay.resources) {
+ if (contents_resource_id) {
+ pending_overlay_resources_.push_back(
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ resource_provider_, contents_resource_id));
+ texture_ids[i] = pending_overlay_resources_.back()->texture_id();
+ ids_to_send = i + 1;
+ }
+ i++;
+ }
+ GLfloat contents_rect[4] = {
+ dc_layer_overlay.contents_rect.x(), dc_layer_overlay.contents_rect.y(),
+ dc_layer_overlay.contents_rect.width(),
+ dc_layer_overlay.contents_rect.height(),
+ };
+ GLfloat bounds_rect[4] = {
+ dc_layer_overlay.bounds_rect.x(), dc_layer_overlay.bounds_rect.y(),
+ dc_layer_overlay.bounds_rect.width(),
+ dc_layer_overlay.bounds_rect.height(),
+ };
+ GLboolean is_clipped = dc_layer_overlay.shared_state->is_clipped;
+ GLfloat clip_rect[4] = {dc_layer_overlay.shared_state->clip_rect.x(),
+ dc_layer_overlay.shared_state->clip_rect.y(),
+ dc_layer_overlay.shared_state->clip_rect.width(),
+ dc_layer_overlay.shared_state->clip_rect.height()};
+ GLint z_order = dc_layer_overlay.shared_state->z_order;
+ GLfloat transform[16];
+ dc_layer_overlay.shared_state->transform.asColMajorf(transform);
+ unsigned filter = dc_layer_overlay.filter;
+
+ if (dc_layer_overlay.shared_state != shared_state) {
+ shared_state = dc_layer_overlay.shared_state;
+ gl_->ScheduleDCLayerSharedStateCHROMIUM(
+ dc_layer_overlay.shared_state->opacity, is_clipped, clip_rect,
+ z_order, transform);
+ }
+ if (ids_to_send > 0) {
+ gl_->SetColorSpaceForScanoutCHROMIUM(
+ texture_ids[0],
+ reinterpret_cast<GLColorSpace>(&dc_layer_overlay.color_space));
+ }
+ gl_->ScheduleDCLayerCHROMIUM(ids_to_send, texture_ids, contents_rect,
+ dc_layer_overlay.background_color,
+ dc_layer_overlay.edge_aa_mask, bounds_rect,
+ filter);
+ }
+
+ // Take the number of copied render passes in this frame, and use 3 times that
+ // amount as the cache limit.
+ if (overlay_resource_pool_) {
+ overlay_resource_pool_->SetResourceUsageLimits(
+ std::numeric_limits<std::size_t>::max(), copied_render_pass_count * 5);
+ }
+}
+
+void GLRenderer::ScheduleOverlays() {
+ if (current_frame()->overlay_list.empty())
+ return;
+
+ cc::OverlayCandidateList& overlays = current_frame()->overlay_list;
+ for (const cc::OverlayCandidate& overlay : overlays) {
+ unsigned texture_id = 0;
+ if (overlay.use_output_surface_for_resource) {
+ texture_id = output_surface_->GetOverlayTextureId();
+ DCHECK(texture_id || IsContextLost());
+ } else {
+ pending_overlay_resources_.push_back(
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ resource_provider_, overlay.resource_id));
+ texture_id = pending_overlay_resources_.back()->texture_id();
+ }
+
+ context_support_->ScheduleOverlayPlane(
+ overlay.plane_z_order, overlay.transform, texture_id,
+ ToNearestRect(overlay.display_rect), overlay.uv_rect);
+ }
+}
+
+// This function draws the cc::RenderPassDrawQuad into a temporary
+// texture/framebuffer, and then copies the result into an IOSurface. The
+// inefficient (but simple) way to do this would be to:
+// 1. Allocate a framebuffer the size of the screen.
+// 2. Draw using all the normal RPDQ draw logic.
+//
+// Instead, this method does the following:
+// 1. Configure parameters as if drawing to a framebuffer the size of the
+// screen. This reuses most of the RPDQ draw logic.
+// 2. Update parameters to draw into a framebuffer only as large as needed.
+// 3. Fix shader uniforms that were broken by (2).
+//
+// Then:
+// 4. Allocate an IOSurface as the drawing destination.
+// 5. Draw the RPDQ.
+void GLRenderer::CopyRenderPassDrawQuadToOverlayResource(
+ const cc::CALayerOverlay* ca_layer_overlay,
+ cc::Resource** resource,
+ gfx::RectF* new_bounds) {
+ // Don't carry over any GL state from previous cc::RenderPass draw operations.
+ ReinitializeGLState();
+
+ cc::ScopedResource* contents_texture =
+ render_pass_textures_[ca_layer_overlay->rpdq->render_pass_id].get();
+ DCHECK(contents_texture);
+
+ // Configure parameters as if drawing to a framebuffer the size of the
+ // screen.
+ DrawRenderPassDrawQuadParams params;
+ params.quad = ca_layer_overlay->rpdq;
+ params.flip_texture = true;
+ params.contents_texture = contents_texture;
+ params.quad_to_target_transform =
+ params.quad->shared_quad_state->quad_to_target_transform;
+ params.tex_coord_rect = params.quad->tex_coord_rect;
+
+ // Calculate projection and window matrices using InitializeViewport(). This
+ // requires creating a dummy DrawingFrame.
+ {
+ DrawingFrame dummy_frame;
+ gfx::Rect frame_rect(current_frame()->device_viewport_size);
+ force_drawing_frame_framebuffer_unflipped_ = true;
+ InitializeViewport(&dummy_frame, frame_rect, frame_rect, frame_rect.size());
+ force_drawing_frame_framebuffer_unflipped_ = false;
+ params.projection_matrix = dummy_frame.projection_matrix;
+ params.window_matrix = dummy_frame.window_matrix;
+ }
+
+ // Perform basic initialization with the screen-sized viewport.
+ if (!InitializeRPDQParameters(&params))
+ return;
+
+ if (!UpdateRPDQWithSkiaFilters(&params))
+ return;
+
+ // |params.dst_rect| now contain values that reflect a potentially increased
+ // size quad.
+ gfx::RectF updated_dst_rect = params.dst_rect;
+
+ // Round the size of the IOSurface to a multiple of 64 pixels. This reduces
+ // memory fragmentation. https://crbug.com/146070. This also allows IOSurfaces
+ // to be more easily reused during a resize operation.
+ uint32_t iosurface_multiple = 64;
+ uint32_t iosurface_width = cc::MathUtil::UncheckedRoundUp(
+ static_cast<uint32_t>(updated_dst_rect.width()), iosurface_multiple);
+ uint32_t iosurface_height = cc::MathUtil::UncheckedRoundUp(
+ static_cast<uint32_t>(updated_dst_rect.height()), iosurface_multiple);
+
+ *resource = overlay_resource_pool_->AcquireResource(
+ gfx::Size(iosurface_width, iosurface_height), ResourceFormat::RGBA_8888,
+ current_frame()->current_render_pass->color_space);
+ *new_bounds =
+ gfx::RectF(updated_dst_rect.x(), updated_dst_rect.y(),
+ (*resource)->size().width(), (*resource)->size().height());
+
+ // Calculate new projection and window matrices for a minimally sized viewport
+ // using InitializeViewport(). This requires creating a dummy DrawingFrame.
+ {
+ DrawingFrame dummy_frame;
+ force_drawing_frame_framebuffer_unflipped_ = true;
+ gfx::Rect frame_rect =
+ gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
+ InitializeViewport(&dummy_frame, frame_rect, frame_rect, frame_rect.size());
+ force_drawing_frame_framebuffer_unflipped_ = false;
+ params.projection_matrix = dummy_frame.projection_matrix;
+ params.window_matrix = dummy_frame.window_matrix;
+ }
+
+ // Calculate a new quad_to_target_transform.
+ params.quad_to_target_transform = gfx::Transform();
+ params.quad_to_target_transform.Translate(-updated_dst_rect.x(),
+ -updated_dst_rect.y());
+
+ // Antialiasing works by fading out content that is close to the edge of the
+ // viewport. All of these values need to be recalculated.
+ if (params.use_aa) {
+ current_window_space_viewport_ =
+ gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix, params.quad_to_target_transform,
+ updated_dst_rect);
+ params.contents_device_transform =
+ params.window_matrix * params.projection_matrix * quad_rect_matrix;
+ bool clipped = false;
+ params.contents_device_transform.FlattenTo2d();
+ gfx::QuadF device_layer_quad = cc::MathUtil::MapQuad(
+ params.contents_device_transform, SharedGeometryQuad(), &clipped);
+ cc::LayerQuad device_layer_edges(device_layer_quad);
+ InflateAntiAliasingDistances(device_layer_quad, &device_layer_edges,
+ params.edge);
+ }
+
+ // Establish destination texture.
+ cc::ResourceProvider::ScopedWriteLockGL destination(resource_provider_,
+ (*resource)->id());
+ GLuint temp_fbo;
+
+ gl_->GenFramebuffers(1, &temp_fbo);
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ destination.target(), destination.GetTexture(), 0);
+ DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
+ GL_FRAMEBUFFER_COMPLETE);
+
+ // Clear to 0 to ensure the background is transparent.
+ gl_->ClearColor(0, 0, 0, 0);
+ gl_->Clear(GL_COLOR_BUFFER_BIT);
+
+ UpdateRPDQTexturesForSampling(&params);
+ UpdateRPDQBlendMode(&params);
+ ChooseRPDQProgram(&params);
+ UpdateRPDQUniforms(&params);
+
+ // Prior to drawing, set up the destination framebuffer and viewport.
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo);
+ gl_->Viewport(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
+
+ DrawRPDQ(params);
+ gl_->DeleteFramebuffers(1, &temp_fbo);
+}
+
+void GLRenderer::ScheduleRenderPassDrawQuad(
+ const cc::CALayerOverlay* ca_layer_overlay) {
+ DCHECK(ca_layer_overlay->rpdq);
+
+ if (!overlay_resource_pool_) {
+ overlay_resource_pool_ =
+ cc::ResourcePool::CreateForGpuMemoryBufferResources(
+ resource_provider_, base::ThreadTaskRunnerHandle::Get().get(),
+ gfx::BufferUsage::SCANOUT, base::TimeDelta::FromSeconds(3),
+ settings_->disallow_non_exact_resource_reuse);
+ }
+
+ cc::Resource* resource = nullptr;
+ gfx::RectF new_bounds;
+ CopyRenderPassDrawQuadToOverlayResource(ca_layer_overlay, &resource,
+ &new_bounds);
+ if (!resource || !resource->id())
+ return;
+
+ pending_overlay_resources_.push_back(
+ base::MakeUnique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ resource_provider_, resource->id()));
+ unsigned texture_id = pending_overlay_resources_.back()->texture_id();
+
+ // Once a resource is released, it is marked as "busy". It will be
+ // available for reuse after the ScopedReadLockGL is destroyed.
+ overlay_resource_pool_->ReleaseResource(resource);
+
+ GLfloat contents_rect[4] = {
+ ca_layer_overlay->contents_rect.x(), ca_layer_overlay->contents_rect.y(),
+ ca_layer_overlay->contents_rect.width(),
+ ca_layer_overlay->contents_rect.height(),
+ };
+ GLfloat bounds_rect[4] = {
+ new_bounds.x(), new_bounds.y(), new_bounds.width(), new_bounds.height(),
+ };
+ GLboolean is_clipped = ca_layer_overlay->shared_state->is_clipped;
+ GLfloat clip_rect[4] = {ca_layer_overlay->shared_state->clip_rect.x(),
+ ca_layer_overlay->shared_state->clip_rect.y(),
+ ca_layer_overlay->shared_state->clip_rect.width(),
+ ca_layer_overlay->shared_state->clip_rect.height()};
+ GLint sorting_context_id = ca_layer_overlay->shared_state->sorting_context_id;
+ SkMatrix44 transform = ca_layer_overlay->shared_state->transform;
+ GLfloat gl_transform[16];
+ transform.asColMajorf(gl_transform);
+ unsigned filter = ca_layer_overlay->filter;
+
+ // The alpha has already been applied when copying the RPDQ to an IOSurface.
+ GLfloat alpha = 1;
+ gl_->ScheduleCALayerSharedStateCHROMIUM(alpha, is_clipped, clip_rect,
+ sorting_context_id, gl_transform);
+ gl_->ScheduleCALayerCHROMIUM(
+ texture_id, contents_rect, ca_layer_overlay->background_color,
+ ca_layer_overlay->edge_aa_mask, bounds_rect, filter);
+}
+
+void GLRenderer::SetupOverdrawFeedback() {
+ gl_->StencilFunc(GL_ALWAYS, 1, 0xffffffff);
+ // First two values are ignored as test always passes.
+ gl_->StencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+ gl_->StencilMask(0xffffffff);
+}
+
+void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) {
+ DCHECK(stencil_shadow_);
+
+ // Test only, keep everything.
+ gl_->StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ EnsureScissorTestDisabled();
+ SetBlendEnabled(true);
+
+ PrepareGeometry(SHARED_BINDING);
+
+ SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB());
+
+ gfx::Transform render_matrix;
+ render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(),
+ 0.5 * output_rect.height() + output_rect.y());
+ render_matrix.Scale(output_rect.width(), output_rect.height());
+ SetShaderMatrix(current_frame()->projection_matrix * render_matrix);
+
+ // Produce hinting for the amount of overdraw on screen for each pixel by
+ // drawing hint colors to the framebuffer based on the current stencil value.
+ struct {
+ int multiplier;
+ GLenum func;
+ GLint ref;
+ SkColor color;
+ } stencil_tests[] = {
+ {1, GL_EQUAL, 2, 0x2f0000ff}, // Blue: Overdrawn once.
+ {2, GL_EQUAL, 3, 0x2f00ff00}, // Green: Overdrawn twice.
+ {3, GL_EQUAL, 4, 0x3fff0000}, // Pink: Overdrawn three times.
+ {4, GL_LESS, 4, 0x7fff0000}, // Red: Overdrawn four or more times.
+ };
+
+ // Occlusion queries can be expensive, so only collect trace data if we select
+ // cc.debug.overdraw.
+ bool tracing_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.overdraw"), &tracing_enabled);
+
+ // Trace only the root render pass.
+ if (current_frame()->current_render_pass != current_frame()->root_render_pass)
+ tracing_enabled = false;
+
+ // ARB_occlusion_query is required for tracing.
+ if (!use_occlusion_query_)
+ tracing_enabled = false;
+
+ // Use the current surface area as max result. The effect is that overdraw
+ // is reported as a percentage of the output surface size. ie. 2x overdraw
+ // for the whole screen is reported as 200.
+ int max_result = current_surface_size_.GetArea();
+ DCHECK_GT(max_result, 0);
+
+ OverdrawFeedbackCallback overdraw_feedback_callback = base::Bind(
+ &GLRenderer::ProcessOverdrawFeedback, weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(new std::vector<int>), arraysize(stencil_tests), max_result);
+
+ for (const auto& test : stencil_tests) {
+ GLuint query = 0;
+ if (tracing_enabled) {
+ gl_->GenQueriesEXT(1, &query);
+ gl_->BeginQueryEXT(GL_SAMPLES_PASSED_ARB, query);
+ }
+
+ gl_->StencilFunc(test.func, test.ref, 0xffffffff);
+ // Transparent color unless color-coding of overdraw is enabled.
+ SetShaderColor(settings_->show_overdraw_feedback ? test.color : 0, 1.f);
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+
+ if (query) {
+ gl_->EndQueryEXT(GL_SAMPLES_PASSED_ARB);
+ context_support_->SignalQuery(
+ query,
+ base::Bind(overdraw_feedback_callback, query, test.multiplier));
+ }
+ }
+}
+
+void GLRenderer::ProcessOverdrawFeedback(std::vector<int>* overdraw,
+ size_t num_expected_results,
+ int max_result,
+ unsigned query,
+ int multiplier) {
+ unsigned result = 0;
+ if (query) {
+ gl_->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
+ gl_->DeleteQueriesEXT(1, &query);
+ }
+
+ // Apply multiplier to get the amount of overdraw.
+ overdraw->push_back(result * multiplier);
+
+ // Return early if we are expecting more results.
+ if (overdraw->size() < num_expected_results)
+ return;
+
+ // Report GPU overdraw as a percentage of |max_result|.
+ TRACE_COUNTER1(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.overdraw"), "GPU Overdraw",
+ (std::accumulate(overdraw->begin(), overdraw->end(), 0) * 100) /
+ max_result);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
new file mode 100644
index 00000000000..34e73cb415e
--- /dev/null
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -0,0 +1,381 @@
+// Copyright 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "base/cancelable_callback.h"
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "cc/output/direct_renderer.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
+#include "components/viz/common/gpu/context_cache_controller.h"
+#include "components/viz/service/display/color_lut_cache.h"
+#include "components/viz/service/display/gl_renderer_draw_cache.h"
+#include "components/viz/service/display/program_binding.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/latency/latency_info.h"
+
+namespace cc {
+class GLRendererShaderTest;
+class OutputSurface;
+class Resource;
+class ResourcePool;
+class ScopedResource;
+class TextureMailboxDeleter;
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
+} // namespace cc
+
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
+namespace viz {
+
+class DynamicGeometryBinding;
+class StaticGeometryBinding;
+struct DrawRenderPassDrawQuadParams;
+
+// Class that handles drawing of composited render layers using GL.
+class VIZ_SERVICE_EXPORT GLRenderer : public cc::DirectRenderer {
+ public:
+ class ScopedUseGrContext;
+
+ GLRenderer(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider,
+ cc::TextureMailboxDeleter* texture_mailbox_deleter);
+ ~GLRenderer() override;
+
+ bool use_swap_with_bounds() const { return use_swap_with_bounds_; }
+
+ void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
+ void SwapBuffersComplete() override;
+
+ void DidReceiveTextureInUseResponses(
+ const gpu::TextureInUseResponses& responses) override;
+
+ virtual bool IsContextLost();
+
+ protected:
+ void DidChangeVisibility() override;
+
+ const gfx::QuadF& SharedGeometryQuad() const { return shared_geometry_quad_; }
+ const StaticGeometryBinding* SharedGeometry() const {
+ return shared_geometry_.get();
+ }
+
+ void GetFramebufferPixelsAsync(const gfx::Rect& rect,
+ std::unique_ptr<CopyOutputRequest> request);
+ void GetFramebufferTexture(unsigned texture_id, const gfx::Rect& device_rect);
+ void ReleaseRenderPassTextures();
+ enum BoundGeometry { NO_BINDING, SHARED_BINDING, CLIPPED_BINDING };
+ void PrepareGeometry(BoundGeometry geometry_to_bind);
+ void SetStencilEnabled(bool enabled);
+ bool stencil_enabled() const { return stencil_shadow_; }
+ void SetBlendEnabled(bool enabled);
+ bool blend_enabled() const { return blend_shadow_; }
+
+ bool CanPartialSwap() override;
+ ResourceFormat BackbufferFormat() const override;
+ void BindFramebufferToOutputSurface() override;
+ bool BindFramebufferToTexture(const cc::ScopedResource* resource) override;
+ void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
+ void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
+ void DoDrawQuad(const class cc::DrawQuad*,
+ const gfx::QuadF* draw_region) override;
+ void BeginDrawingFrame() override;
+ void FinishDrawingFrame() override;
+ bool FlippedFramebuffer() const override;
+ bool FlippedRootFramebuffer() const;
+ void EnsureScissorTestEnabled() override;
+ void EnsureScissorTestDisabled() override;
+ void CopyCurrentRenderPassToBitmap(
+ std::unique_ptr<CopyOutputRequest> request) override;
+ void SetEnableDCLayers(bool enable) override;
+ void FinishDrawingQuadList() override;
+
+ // Returns true if quad requires antialiasing and false otherwise.
+ static bool ShouldAntialiasQuad(const gfx::QuadF& device_layer_quad,
+ bool clipped,
+ bool force_aa);
+
+ // Inflate the quad and fill edge array for fragment shader.
+ // |local_quad| is set to inflated quad. |edge| array is filled with
+ // inflated quad's edge data.
+ static void SetupQuadForClippingAndAntialiasing(
+ const gfx::Transform& device_transform,
+ const cc::DrawQuad* quad,
+ const gfx::QuadF* device_layer_quad,
+ const gfx::QuadF* clip_region,
+ gfx::QuadF* local_quad,
+ float edge[24]);
+ static void SetupRenderPassQuadForClippingAndAntialiasing(
+ const gfx::Transform& device_transform,
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::QuadF* device_layer_quad,
+ const gfx::QuadF* clip_region,
+ gfx::QuadF* local_quad,
+ float edge[24]);
+
+ private:
+ friend class GLRendererShaderPixelTest;
+ friend class GLRendererShaderTest;
+
+ // If any of the following functions returns false, then it means that drawing
+ // is not possible.
+ bool InitializeRPDQParameters(DrawRenderPassDrawQuadParams* params);
+ void UpdateRPDQShadersForBlending(DrawRenderPassDrawQuadParams* params);
+ bool UpdateRPDQWithSkiaFilters(DrawRenderPassDrawQuadParams* params);
+ void UpdateRPDQTexturesForSampling(DrawRenderPassDrawQuadParams* params);
+ void UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params);
+ void ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params);
+ void UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params);
+ void DrawRPDQ(const DrawRenderPassDrawQuadParams& params);
+
+ static void ToGLMatrix(float* gl_matrix, const gfx::Transform& transform);
+
+ void DiscardPixels();
+ void ClearFramebuffer();
+ void SetViewport();
+
+ void DrawDebugBorderQuad(const cc::DebugBorderDrawQuad* quad);
+ static bool IsDefaultBlendMode(SkBlendMode blend_mode) {
+ return blend_mode == SkBlendMode::kSrcOver;
+ }
+ bool CanApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode);
+ void ApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode);
+ void RestoreBlendFuncToDefault(SkBlendMode blend_mode);
+
+ gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::Transform& contents_device_transform,
+ const cc::FilterOperations* filters,
+ const cc::FilterOperations* background_filters,
+ const gfx::QuadF* clip_region,
+ bool use_aa,
+ gfx::Rect* unclipped_rect);
+ std::unique_ptr<cc::ScopedResource> GetBackdropTexture(
+ const gfx::Rect& bounding_rect);
+
+ static bool ShouldApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations* background_filters);
+ sk_sp<SkImage> ApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations& background_filters,
+ cc::ScopedResource* background_texture,
+ const gfx::RectF& rect,
+ const gfx::RectF& unclipped_rect);
+
+ const cc::TileDrawQuad* CanPassBeDrawnDirectly(
+ const cc::RenderPass* pass) override;
+
+ void DrawRenderPassQuad(const cc::RenderPassDrawQuad* quadi,
+ const gfx::QuadF* clip_region);
+ void DrawRenderPassQuadInternal(DrawRenderPassDrawQuadParams* params);
+ void DrawSolidColorQuad(const cc::SolidColorDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void DrawStreamVideoQuad(const cc::StreamVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void EnqueueTextureQuad(const cc::TextureDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void FlushTextureQuadCache(BoundGeometry flush_binding);
+ void DrawTileQuad(const cc::TileDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void DrawContentQuad(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::QuadF* clip_region);
+ void DrawContentQuadAA(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::Transform& device_transform,
+ const gfx::QuadF& aa_quad,
+ const gfx::QuadF* clip_region);
+ void DrawContentQuadNoAA(const cc::ContentDrawQuadBase* quad,
+ ResourceId resource_id,
+ const gfx::QuadF* clip_region);
+ void DrawYUVVideoQuad(const cc::YUVVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void DrawOverlayCandidateQuadBorder(float* gl_matrix);
+
+ void SetShaderOpacity(const cc::DrawQuad* quad);
+ void SetShaderQuadF(const gfx::QuadF& quad);
+ void SetShaderMatrix(const gfx::Transform& transform);
+ void SetShaderColor(SkColor color, float opacity);
+ void DrawQuadGeometryClippedByQuadF(const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect,
+ const gfx::QuadF& clipping_region_quad,
+ const float uv[8]);
+ void DrawQuadGeometry(const gfx::Transform& projection_matrix,
+ const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect);
+
+ // If |dst_color_space| is invalid, then no color conversion (apart from
+ // YUV to RGB conversion) is performed. This explicit argument is available
+ // so that video color conversion can be enabled separately from general color
+ // conversion.
+ // TODO(ccameron): Remove the version with an explicit |dst_color_space|,
+ // since that will always be the device color space.
+ void SetUseProgram(const ProgramKey& program_key,
+ const gfx::ColorSpace& src_color_space,
+ const gfx::ColorSpace& dst_color_space);
+ void SetUseProgram(const ProgramKey& program_key,
+ const gfx::ColorSpace& src_color_space);
+
+ bool MakeContextCurrent();
+
+ void InitializeSharedObjects();
+ void CleanupSharedObjects();
+
+ typedef base::Callback<void(std::unique_ptr<CopyOutputRequest> copy_request,
+ bool success)>
+ AsyncGetFramebufferPixelsCleanupCallback;
+ void FinishedReadback(unsigned source_buffer,
+ unsigned query,
+ const gfx::Size& size);
+
+ void ReinitializeGLState();
+ void RestoreGLState();
+
+ void ScheduleCALayers();
+ void ScheduleDCLayers();
+ void ScheduleOverlays();
+
+ // Copies the contents of the render pass draw quad, including filter effects,
+ // to an overlay resource, returned in |resource|. The resource is allocated
+ // from |overlay_resource_pool_|.
+ // The resulting cc::Resource may be larger than the original quad. The new
+ // size and position is placed in |new_bounds|.
+ void CopyRenderPassDrawQuadToOverlayResource(
+ const cc::CALayerOverlay* ca_layer_overlay,
+ cc::Resource** resource,
+ gfx::RectF* new_bounds);
+
+ // Schedules the |ca_layer_overlay|, which is guaranteed to have a non-null
+ // |rpdq| parameter.
+ void ScheduleRenderPassDrawQuad(const cc::CALayerOverlay* ca_layer_overlay);
+
+ // Setup/flush all pending overdraw feedback to framebuffer.
+ void SetupOverdrawFeedback();
+ void FlushOverdrawFeedback(const gfx::Rect& output_rect);
+ // Process overdraw feedback from query.
+ using OverdrawFeedbackCallback = base::Callback<void(unsigned, int)>;
+ void ProcessOverdrawFeedback(std::vector<int>* overdraw,
+ size_t num_expected_results,
+ int max_result,
+ unsigned query,
+ int multiplier);
+
+ using OverlayResourceLock =
+ std::unique_ptr<cc::DisplayResourceProvider::ScopedReadLockGL>;
+ using OverlayResourceLockList = std::vector<OverlayResourceLock>;
+
+ // Resources that have been sent to the GPU process, but not yet swapped.
+ OverlayResourceLockList pending_overlay_resources_;
+
+ // Resources that should be shortly swapped by the GPU process.
+ base::circular_deque<OverlayResourceLockList> swapping_overlay_resources_;
+
+ // Resources that the GPU process has finished swapping. The key is the
+ // texture id of the resource.
+ std::map<unsigned, OverlayResourceLock> swapped_and_acked_overlay_resources_;
+
+ unsigned offscreen_framebuffer_id_ = 0u;
+
+ std::unique_ptr<StaticGeometryBinding> shared_geometry_;
+ std::unique_ptr<DynamicGeometryBinding> clipped_geometry_;
+ gfx::QuadF shared_geometry_quad_;
+
+ // This will return nullptr if the requested program has not yet been
+ // initialized.
+ const Program* GetProgramIfInitialized(const ProgramKey& key) const;
+
+ std::unordered_map<ProgramKey, std::unique_ptr<Program>, ProgramKeyHash>
+ program_cache_;
+
+ const gfx::ColorTransform* GetColorTransform(const gfx::ColorSpace& src,
+ const gfx::ColorSpace& dst);
+ std::map<gfx::ColorSpace,
+ std::map<gfx::ColorSpace, std::unique_ptr<gfx::ColorTransform>>>
+ color_transform_cache_;
+
+ gpu::gles2::GLES2Interface* gl_;
+ gpu::ContextSupport* context_support_;
+ std::unique_ptr<ContextCacheController::ScopedVisibility> context_visibility_;
+
+ cc::TextureMailboxDeleter* texture_mailbox_deleter_;
+
+ gfx::Rect swap_buffer_rect_;
+ std::vector<gfx::Rect> swap_content_bounds_;
+ gfx::Rect scissor_rect_;
+ bool is_scissor_enabled_ = false;
+ bool stencil_shadow_ = false;
+ bool blend_shadow_ = false;
+ const Program* current_program_ = nullptr;
+ TexturedQuadDrawCache draw_cache_;
+ int highp_threshold_cache_ = 0;
+
+ struct PendingAsyncReadPixels;
+ std::vector<std::unique_ptr<PendingAsyncReadPixels>>
+ pending_async_read_pixels_;
+
+ std::unique_ptr<cc::ResourceProvider::ScopedWriteLockGL>
+ current_framebuffer_lock_;
+ // This is valid when current_framebuffer_lock_ is not null.
+ ResourceFormat current_framebuffer_format_;
+
+ class SyncQuery;
+ base::circular_deque<std::unique_ptr<SyncQuery>> pending_sync_queries_;
+ base::circular_deque<std::unique_ptr<SyncQuery>> available_sync_queries_;
+ std::unique_ptr<SyncQuery> current_sync_query_;
+ bool use_discard_framebuffer_ = false;
+ bool use_sync_query_ = false;
+ bool use_blend_equation_advanced_ = false;
+ bool use_blend_equation_advanced_coherent_ = false;
+ bool use_occlusion_query_ = false;
+ bool use_swap_with_bounds_ = false;
+
+ // Some overlays require that content is copied from a render pass into an
+ // overlay resource. This means the GLRenderer needs its own cc::ResourcePool.
+ std::unique_ptr<cc::ResourcePool> overlay_resource_pool_;
+
+ // If true, draw a green border after compositing a overlay candidate quad
+ // using GL.
+ bool gl_composited_overlay_candidate_quad_border_;
+
+ // 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;
+
+ BoundGeometry bound_geometry_;
+ ColorLUTCache color_lut_cache_;
+
+ unsigned offscreen_stencil_renderbuffer_id_ = 0;
+ gfx::Size offscreen_stencil_renderbuffer_size_;
+
+ unsigned num_triangles_drawn_ = 0;
+
+ base::WeakPtrFactory<GLRenderer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLRenderer);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
diff --git a/chromium/components/viz/service/display/gl_renderer_draw_cache.cc b/chromium/components/viz/service/display/gl_renderer_draw_cache.cc
new file mode 100644
index 00000000000..887eec8c2af
--- /dev/null
+++ b/chromium/components/viz/service/display/gl_renderer_draw_cache.cc
@@ -0,0 +1,13 @@
+// Copyright 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/viz/service/display/gl_renderer_draw_cache.h"
+
+namespace viz {
+
+TexturedQuadDrawCache::TexturedQuadDrawCache() = default;
+
+TexturedQuadDrawCache::~TexturedQuadDrawCache() = default;
+
+} // 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
new file mode 100644
index 00000000000..e81f88f153e
--- /dev/null
+++ b/chromium/components/viz/service/display/gl_renderer_draw_cache.h
@@ -0,0 +1,56 @@
+// Copyright 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_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/viz/service/display/program_binding.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace viz {
+
+// Collects 4 floats at a time for easy upload to GL.
+struct Float4 {
+ float data[4];
+};
+
+// Collects 16 floats at a time for easy upload to GL.
+struct Float16 {
+ float data[16];
+};
+
+// A cache for storing textured quads to be drawn. Stores the minimum required
+// data to tell if two back to back draws only differ in their transform. Quads
+// that only differ by transform may be coalesced into a single draw call.
+struct TexturedQuadDrawCache {
+ TexturedQuadDrawCache();
+ ~TexturedQuadDrawCache();
+
+ bool is_empty = true;
+
+ // Values tracked to determine if textured quads may be coalesced.
+ ProgramKey program_key;
+ int resource_id = -1;
+ bool needs_blending = false;
+ bool nearest_neighbor = false;
+ SkColor background_color = 0;
+
+ // A cache for the coalesced quad data.
+ std::vector<Float4> uv_xform_data;
+ std::vector<float> vertex_opacity_data;
+ std::vector<Float16> matrix_data;
+
+ // Don't batch if tex clamp rect is given.
+ Float4 tex_clamp_rect_data;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TexturedQuadDrawCache);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
new file mode 100644
index 00000000000..fd7e7019f08
--- /dev/null
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -0,0 +1,2531 @@
+// Copyright 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/viz/service/display/gl_renderer.h"
+
+#include <stdint.h>
+
+#include <set>
+#include <vector>
+
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "cc/base/math_util.h"
+#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/output/overlay_strategy_underlay.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/test/fake_impl_task_runner_provider.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_resource_provider.h"
+#include "cc/test/pixel_test.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_gles2_interface.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/quads/copy_output_result.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
+#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
+#include "ui/gfx/transform.h"
+#include "ui/latency/latency_info.h"
+
+using testing::_;
+using testing::AnyNumber;
+using testing::Args;
+using testing::AtLeast;
+using testing::ElementsAre;
+using testing::Expectation;
+using testing::InSequence;
+using testing::Mock;
+using testing::Return;
+using testing::StrictMock;
+
+namespace viz {
+
+MATCHER_P(MatchesSyncToken, sync_token, "") {
+ gpu::SyncToken other;
+ memcpy(&other, arg, sizeof(other));
+ return other == sync_token;
+}
+
+class GLRendererTest : public testing::Test {
+ protected:
+ cc::RenderPass* root_render_pass() {
+ return render_passes_in_draw_order_.back().get();
+ }
+ void DrawFrame(GLRenderer* renderer, const gfx::Size& viewport_size) {
+ renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size);
+ }
+
+ cc::RenderPassList render_passes_in_draw_order_;
+};
+
+#define EXPECT_PROGRAM_VALID(program_binding) \
+ do { \
+ ASSERT_TRUE(program_binding); \
+ EXPECT_TRUE((program_binding)->program()); \
+ EXPECT_TRUE((program_binding)->initialized()); \
+ } while (false)
+
+static inline SkBlendMode BlendModeToSkXfermode(BlendMode blend_mode) {
+ switch (blend_mode) {
+ case BLEND_MODE_NONE:
+ case BLEND_MODE_NORMAL:
+ return SkBlendMode::kSrcOver;
+ case BLEND_MODE_DESTINATION_IN:
+ return SkBlendMode::kDstIn;
+ case BLEND_MODE_SCREEN:
+ return SkBlendMode::kScreen;
+ case BLEND_MODE_OVERLAY:
+ return SkBlendMode::kOverlay;
+ case BLEND_MODE_DARKEN:
+ return SkBlendMode::kDarken;
+ case BLEND_MODE_LIGHTEN:
+ return SkBlendMode::kLighten;
+ case BLEND_MODE_COLOR_DODGE:
+ return SkBlendMode::kColorDodge;
+ case BLEND_MODE_COLOR_BURN:
+ return SkBlendMode::kColorBurn;
+ case BLEND_MODE_HARD_LIGHT:
+ return SkBlendMode::kHardLight;
+ case BLEND_MODE_SOFT_LIGHT:
+ return SkBlendMode::kSoftLight;
+ case BLEND_MODE_DIFFERENCE:
+ return SkBlendMode::kDifference;
+ case BLEND_MODE_EXCLUSION:
+ return SkBlendMode::kExclusion;
+ case BLEND_MODE_MULTIPLY:
+ return SkBlendMode::kMultiply;
+ case BLEND_MODE_HUE:
+ return SkBlendMode::kHue;
+ case BLEND_MODE_SATURATION:
+ return SkBlendMode::kSaturation;
+ case BLEND_MODE_COLOR:
+ return SkBlendMode::kColor;
+ case BLEND_MODE_LUMINOSITY:
+ return SkBlendMode::kLuminosity;
+ }
+ return SkBlendMode::kSrcOver;
+}
+
+// Explicitly named to be a friend in GLRenderer for shader access.
+class GLRendererShaderPixelTest : public cc::GLRendererPixelTest {
+ public:
+ void SetUp() override {
+ cc::GLRendererPixelTest::SetUp();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TearDown() override {
+ cc::GLRendererPixelTest::TearDown();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TestShader(const ProgramKey& program_key) {
+ renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame());
+ const size_t kNumSrcColorSpaces = 4;
+ gfx::ColorSpace src_color_spaces[kNumSrcColorSpaces] = {
+ gfx::ColorSpace(), gfx::ColorSpace::CreateSRGB(),
+ gfx::ColorSpace::CreateREC709(), gfx::ColorSpace::CreateExtendedSRGB(),
+ };
+ const size_t kNumDstColorSpaces = 3;
+ gfx::ColorSpace dst_color_spaces[kNumDstColorSpaces] = {
+ gfx::ColorSpace(), gfx::ColorSpace::CreateSRGB(),
+ gfx::ColorSpace::CreateSCRGBLinear(),
+ };
+ for (size_t i = 0; i < kNumDstColorSpaces; ++i) {
+ for (size_t j = 0; j < kNumSrcColorSpaces; ++j) {
+ renderer()->SetUseProgram(program_key, src_color_spaces[j],
+ dst_color_spaces[i]);
+ EXPECT_TRUE(renderer()->current_program_->initialized());
+ }
+ }
+ }
+
+ void TestBasicShaders() {
+ TestShader(ProgramKey::DebugBorder());
+ TestShader(ProgramKey::SolidColor(NO_AA));
+ TestShader(ProgramKey::SolidColor(USE_AA));
+ }
+
+ void TestColorShaders() {
+ const size_t kNumTransferFns = 7;
+ SkColorSpaceTransferFn transfer_fns[kNumTransferFns] = {
+ // The identity.
+ {1.f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f},
+ // The identity, with an if statement.
+ {1.f, 1.f, 0.f, 1.f, 0.5f, 0.f, 0.f},
+ // Just the power function.
+ {1.1f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f},
+ // Everything but the power function, nonlinear only.
+ {1.f, 0.9f, 0.1f, 0.9f, 0.f, 0.1f, 0.1f},
+ // Everything, nonlinear only.
+ {1.1f, 0.9f, 0.1f, 0.9f, 0.f, 0.1f, 0.1f},
+ // Everything but the power function.
+ {1.f, 0.9f, 0.1f, 0.9f, 0.5f, 0.1f, 0.1f},
+ // Everything.
+ {1.1f, 0.9f, 0.1f, 0.9f, 0.5f, 0.1f, 0.1f},
+ };
+
+ for (size_t i = 0; i < kNumTransferFns; ++i) {
+ SkMatrix44 primaries;
+ gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&primaries);
+ gfx::ColorSpace src =
+ gfx::ColorSpace::CreateCustom(primaries, transfer_fns[i]);
+
+ renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame());
+ renderer()->SetUseProgram(ProgramKey::SolidColor(NO_AA), src,
+ gfx::ColorSpace::CreateXYZD50());
+ EXPECT_TRUE(renderer()->current_program_->initialized());
+ }
+ }
+
+ void TestShadersWithPrecision(TexCoordPrecision precision) {
+ // This program uses external textures and sampler, so it won't compile
+ // everywhere.
+ if (context_provider()->ContextCapabilities().egl_image_external) {
+ TestShader(ProgramKey::VideoStream(precision));
+ }
+ }
+
+ void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
+ NO_AA, NO_MASK, false, false));
+ TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
+ USE_AA, NO_MASK, false, false));
+ }
+
+ void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision,
+ SamplerType sampler) {
+ if (!context_provider()->ContextCapabilities().egl_image_external &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
+ TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
+ false, true));
+ TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
+ false, false));
+ TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
+ true, true));
+ TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
+ true, false));
+ TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
+ false, true));
+ TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
+ false, false));
+ TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
+ true, true));
+ TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
+ true, false));
+ TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, false));
+ TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, false));
+ TestShader(ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE, false));
+ TestShader(ProgramKey::Tile(precision, sampler, USE_AA, DO_SWIZZLE, false));
+ TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, true));
+ TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, true));
+
+ // Iterate over alpha plane, nv12, and color_lut parameters.
+ UVTextureMode uv_modes[2] = {UV_TEXTURE_MODE_UV, UV_TEXTURE_MODE_U_V};
+ YUVAlphaTextureMode a_modes[2] = {YUV_NO_ALPHA_TEXTURE,
+ YUV_HAS_ALPHA_TEXTURE};
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ TestShader(
+ ProgramKey::YUVVideo(precision, sampler, a_modes[j], uv_modes[k]));
+ }
+ }
+ }
+
+ void TestShadersWithMasks(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
+ if (!context_provider()->ContextCapabilities().egl_image_external &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
+ TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
+ HAS_MASK, mask_for_background, false));
+ TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
+ HAS_MASK, mask_for_background, true));
+ TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
+ HAS_MASK, mask_for_background, false));
+ TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
+ HAS_MASK, mask_for_background, true));
+ }
+};
+
+namespace {
+
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
+static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
+ TEX_COORD_PRECISION_HIGH};
+
+static const BlendMode kBlendModeList[LAST_BLEND_MODE + 1] = {
+ BLEND_MODE_NONE, BLEND_MODE_NORMAL, BLEND_MODE_DESTINATION_IN,
+ BLEND_MODE_SCREEN, BLEND_MODE_OVERLAY, BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN, BLEND_MODE_COLOR_DODGE, BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT, BLEND_MODE_SOFT_LIGHT, BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION, BLEND_MODE_MULTIPLY, BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION, BLEND_MODE_COLOR, BLEND_MODE_LUMINOSITY,
+};
+
+static const SamplerType kSamplerList[] = {
+ SAMPLER_TYPE_2D, SAMPLER_TYPE_2D_RECT, SAMPLER_TYPE_EXTERNAL_OES,
+};
+
+TEST_F(GLRendererShaderPixelTest, BasicShadersCompile) {
+ TestBasicShaders();
+}
+
+TEST_F(GLRendererShaderPixelTest, TestColorShadersCompile) {
+ TestColorShaders();
+}
+
+class PrecisionShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<TexCoordPrecision> {};
+
+TEST_P(PrecisionShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecision(GetParam());
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionShadersCompile,
+ PrecisionShaderPixelTest,
+ ::testing::ValuesIn(kPrecisionList));
+
+class PrecisionBlendShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, BlendMode>> {};
+
+TEST_P(PrecisionBlendShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndBlend(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PrecisionBlendShadersCompile,
+ PrecisionBlendShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kBlendModeList)));
+
+class PrecisionSamplerShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType>> {};
+
+TEST_P(PrecisionSamplerShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndSampler(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionSamplerShadersCompile,
+ PrecisionSamplerShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList)));
+
+class MaskShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType, BlendMode, bool>> {};
+
+TEST_P(MaskShaderPixelTest, ShadersCompile) {
+ TestShadersWithMasks(
+ std::tr1::get<0>(GetParam()), std::tr1::get<1>(GetParam()),
+ std::tr1::get<2>(GetParam()), std::tr1::get<3>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MaskShadersCompile,
+ MaskShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList),
+ ::testing::ValuesIn(kBlendModeList),
+ ::testing::Bool()));
+
+#endif
+
+class FakeRendererGL : public GLRenderer {
+ public:
+ FakeRendererGL(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider)
+ : GLRenderer(settings, output_surface, resource_provider, nullptr) {}
+
+ FakeRendererGL(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider,
+ cc::TextureMailboxDeleter* texture_mailbox_deleter)
+ : GLRenderer(settings,
+ output_surface,
+ resource_provider,
+ texture_mailbox_deleter) {}
+
+ void SetOverlayProcessor(cc::OverlayProcessor* processor) {
+ overlay_processor_.reset(processor);
+ }
+
+ // GLRenderer methods.
+
+ // Changing visibility to public.
+ using GLRenderer::DoDrawQuad;
+ using GLRenderer::BeginDrawingFrame;
+ using GLRenderer::FinishDrawingQuadList;
+ using GLRenderer::stencil_enabled;
+};
+
+class GLRendererWithDefaultHarnessTest : public GLRendererTest {
+ protected:
+ GLRendererWithDefaultHarnessTest() {
+ output_surface_ = cc::FakeOutputSurface::Create3d();
+ output_surface_->BindToClient(&output_surface_client_);
+
+ shared_bitmap_manager_.reset(new cc::TestSharedBitmapManager());
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface_->context_provider(), shared_bitmap_manager_.get());
+ renderer_ = base::MakeUnique<FakeRendererGL>(
+ &settings_, output_surface_.get(), resource_provider_.get());
+ renderer_->Initialize();
+ renderer_->SetVisible(true);
+ }
+
+ void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); }
+
+ RendererSettings settings_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface_;
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<FakeRendererGL> renderer_;
+};
+
+// Closing the namespace here so that GLRendererShaderTest can take advantage
+// of the friend relationship with GLRenderer and all of the mock classes
+// declared above it.
+} // namespace
+
+class GLRendererShaderTest : public GLRendererTest {
+ protected:
+ GLRendererShaderTest() {
+ output_surface_ = cc::FakeOutputSurface::Create3d();
+ output_surface_->BindToClient(&output_surface_client_);
+
+ shared_bitmap_manager_.reset(new cc::TestSharedBitmapManager());
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface_->context_provider(), shared_bitmap_manager_.get());
+ renderer_.reset(new FakeRendererGL(&settings_, output_surface_.get(),
+ resource_provider_.get()));
+ renderer_->Initialize();
+ renderer_->SetVisible(true);
+ }
+
+ void TestRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ const Program* program = renderer_->GetProgramIfInitialized(
+ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
+ NO_MASK, false, false));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ const Program* program = renderer_->GetProgramIfInitialized(
+ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
+ NO_MASK, false, true));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassMaskProgram(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ const Program* program =
+ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass(
+ precision, sampler, blend_mode, NO_AA, HAS_MASK, false, false));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ const Program* program =
+ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass(
+ precision, sampler, blend_mode, NO_AA, HAS_MASK, false, true));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ const Program* program = renderer_->GetProgramIfInitialized(
+ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
+ NO_MASK, false, false));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ const Program* program = renderer_->GetProgramIfInitialized(
+ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
+ NO_MASK, false, true));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassMaskProgramAA(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ const Program* program =
+ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass(
+ precision, sampler, blend_mode, USE_AA, HAS_MASK, false, false));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ const Program* program =
+ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass(
+ precision, sampler, blend_mode, USE_AA, HAS_MASK, false, true));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ void TestSolidColorProgramAA() {
+ const Program* program =
+ renderer_->GetProgramIfInitialized(ProgramKey::SolidColor(USE_AA));
+ EXPECT_PROGRAM_VALID(program);
+ EXPECT_EQ(program, renderer_->current_program_);
+ }
+
+ RendererSettings settings_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface_;
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<FakeRendererGL> renderer_;
+};
+
+namespace {
+
+TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
+ gfx::Size viewport_size(1, 1);
+ EXPECT_FALSE(renderer_->stencil_enabled());
+
+ output_surface_->set_has_external_stencil_test(true);
+
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+
+ DrawFrame(renderer_.get(), viewport_size);
+ EXPECT_TRUE(renderer_->stencil_enabled());
+}
+
+class ForbidSynchronousCallContext : public cc::TestWebGraphicsContext3D {
+ public:
+ ForbidSynchronousCallContext() {}
+
+ void getAttachedShaders(GLuint program,
+ GLsizei max_count,
+ GLsizei* count,
+ GLuint* shaders) override {
+ ADD_FAILURE();
+ }
+ GLint getAttribLocation(GLuint program, const GLchar* name) override {
+ ADD_FAILURE();
+ return 0;
+ }
+ void getBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
+ void getBufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLenum getError() override {
+ ADD_FAILURE();
+ return GL_NO_ERROR;
+ }
+ void getFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
+ void getFramebufferAttachmentParameteriv(GLenum target,
+ GLenum attachment,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+ void getIntegerv(GLenum pname, GLint* value) override {
+ if (pname == GL_MAX_TEXTURE_SIZE) {
+ // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
+ *value = 1024;
+ } else {
+ ADD_FAILURE();
+ }
+ }
+
+ // We allow querying the shader compilation and program link status in debug
+ // mode, but not release.
+ void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
+#ifndef NDEBUG
+ *value = 1;
+#else
+ ADD_FAILURE();
+#endif
+ }
+
+ void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
+#ifndef NDEBUG
+ *value = 1;
+#else
+ ADD_FAILURE();
+#endif
+ }
+
+ void getRenderbufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) override {
+ ADD_FAILURE();
+ }
+
+ void getShaderPrecisionFormat(GLenum shadertype,
+ GLenum precisiontype,
+ GLint* range,
+ GLint* precision) override {
+ ADD_FAILURE();
+ }
+ void getTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
+ ADD_FAILURE();
+ }
+ void getUniformfv(GLuint program, GLint location, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getUniformiv(GLuint program, GLint location, GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLint getUniformLocation(GLuint program, const GLchar* name) override {
+ ADD_FAILURE();
+ return 0;
+ }
+ void getVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
+ ADD_FAILURE();
+ }
+ void getVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
+ ADD_FAILURE();
+ }
+ GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname) override {
+ ADD_FAILURE();
+ return 0;
+ }
+};
+TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
+ auto context = base::MakeUnique<ForbidSynchronousCallContext>();
+ auto provider = cc::TestContextProvider::Create(std::move(context));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+}
+
+class LoseContextOnFirstGetContext : public cc::TestWebGraphicsContext3D {
+ public:
+ LoseContextOnFirstGetContext() {}
+
+ void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
+ context_lost_ = true;
+ *value = 0;
+ }
+
+ void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
+ context_lost_ = true;
+ *value = 0;
+ }
+};
+
+TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
+ auto context = base::MakeUnique<LoseContextOnFirstGetContext>();
+ auto provider = cc::TestContextProvider::Create(std::move(context));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+}
+
+class ClearCountingContext : public cc::TestWebGraphicsContext3D {
+ public:
+ ClearCountingContext() { test_capabilities_.discard_framebuffer = true; }
+
+ MOCK_METHOD3(discardFramebufferEXT,
+ void(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments));
+ MOCK_METHOD1(clear, void(GLbitfield mask));
+};
+
+TEST_F(GLRendererTest, OpaqueBackground) {
+ std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(context_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(1, 1);
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+
+ // On DEBUG builds, render passes with opaque background clear to blue to
+ // easily see regions that were not drawn on the screen.
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
+ .Times(1);
+#ifdef NDEBUG
+ EXPECT_CALL(*context, clear(_)).Times(0);
+#else
+ EXPECT_CALL(*context, clear(_)).Times(1);
+#endif
+ DrawFrame(&renderer, viewport_size);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+TEST_F(GLRendererTest, TransparentBackground) {
+ std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(context_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(1, 1);
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = true;
+
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
+ EXPECT_CALL(*context, clear(_)).Times(1);
+ DrawFrame(&renderer, viewport_size);
+
+ Mock::VerifyAndClearExpectations(context);
+}
+
+TEST_F(GLRendererTest, OffscreenOutputSurface) {
+ std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+ ClearCountingContext* context = context_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(context_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::CreateOffscreen(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(1, 1);
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+
+ EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
+ .Times(1);
+ EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
+ DrawFrame(&renderer, viewport_size);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+class TextureStateTrackingContext : public cc::TestWebGraphicsContext3D {
+ public:
+ TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
+ test_capabilities_.egl_image_external = true;
+ }
+
+ MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
+ MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+
+ virtual void activeTexture(GLenum texture) {
+ EXPECT_NE(texture, active_texture_);
+ active_texture_ = texture;
+ }
+
+ GLenum active_texture() const { return active_texture_; }
+
+ private:
+ GLenum active_texture_;
+};
+
+TEST_F(GLRendererTest, ActiveTextureState) {
+ std::unique_ptr<TextureStateTrackingContext> context_owned(
+ new TextureStateTrackingContext);
+ TextureStateTrackingContext* context = context_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(context_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ // During initialization we are allowed to set any texture parameters.
+ EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
+
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(100, 100),
+ gfx::Transform(), cc::FilterOperations());
+ gpu::SyncToken mailbox_sync_token;
+ AddOneOfEveryQuadType(root_pass, resource_provider.get(), 0,
+ &mailbox_sync_token);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+
+ // Set up expected texture filter state transitions that match the quads
+ // created in AppendOneOfEveryQuadType().
+ Mock::VerifyAndClearExpectations(context);
+ {
+ InSequence sequence;
+
+ // The sync points for all quads are waited on first. This sync point is
+ // for a texture quad drawn later in the frame.
+ EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(mailbox_sync_token)))
+ .Times(1);
+
+ // yuv_quad is drawn with the default linear filter.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // tile_quad is drawn with GL_NEAREST because it is not transformed or
+ // scaled.
+ EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST));
+ EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST));
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // transformed_tile_quad uses GL_LINEAR.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // scaled_tile_quad also uses GL_LINEAR.
+ EXPECT_CALL(*context, drawElements(_, _, _, _));
+
+ // The remaining quads also use GL_LINEAR because nearest neighbor
+ // filtering is currently only used with tile quads.
+ EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(5);
+ }
+
+ gfx::Size viewport_size(100, 100);
+ DrawFrame(&renderer, viewport_size);
+ Mock::VerifyAndClearExpectations(context);
+}
+
+class NoClearRootRenderPassMockContext : public cc::TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD1(clear, void(GLbitfield mask));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+};
+
+TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
+ std::unique_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
+ new NoClearRootRenderPassMockContext);
+ NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
+
+ auto provider =
+ cc::TestContextProvider::Create(std::move(mock_context_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ settings.should_clear_root_render_pass = false;
+
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(10, 10);
+
+ int child_pass_id = 2;
+ cc::RenderPass* child_pass = AddRenderPass(
+ &render_passes_in_draw_order_, child_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(child_pass, gfx::Rect(viewport_size), SK_ColorBLUE);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+
+ AddRenderPassQuad(root_pass, child_pass);
+
+#ifdef NDEBUG
+ GLint clear_bits = GL_COLOR_BUFFER_BIT;
+#else
+ GLint clear_bits = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
+#endif
+
+ // First render pass is not the root one, clearing should happen.
+ EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1));
+
+ Expectation first_render_pass =
+ EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1);
+
+ // The second render pass is the root one, clearing should be prevented.
+ EXPECT_CALL(*mock_context, clear(clear_bits))
+ .Times(0)
+ .After(first_render_pass);
+
+ EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
+ .Times(AnyNumber())
+ .After(first_render_pass);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+
+ // In multiple render passes all but the root pass should clear the
+ // framebuffer.
+ Mock::VerifyAndClearExpectations(&mock_context);
+}
+
+class ScissorTestOnClearCheckingGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ ScissorTestOnClearCheckingGLES2Interface() = default;
+
+ void Clear(GLbitfield) override { EXPECT_FALSE(scissor_enabled_); }
+
+ void Enable(GLenum cap) override {
+ if (cap == GL_SCISSOR_TEST)
+ scissor_enabled_ = true;
+ }
+
+ void Disable(GLenum cap) override {
+ if (cap == GL_SCISSOR_TEST)
+ scissor_enabled_ = false;
+ }
+
+ private:
+ bool scissor_enabled_ = false;
+};
+
+TEST_F(GLRendererTest, ScissorTestWhenClearing) {
+ auto gl_owned = base::MakeUnique<ScissorTestOnClearCheckingGLES2Interface>();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ EXPECT_FALSE(renderer.use_partial_swap());
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(100, 100);
+
+ gfx::Rect grand_child_rect(25, 25);
+ int grand_child_pass_id = 3;
+ cc::RenderPass* grand_child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, grand_child_pass_id,
+ grand_child_rect, gfx::Transform(), cc::FilterOperations());
+ AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW);
+
+ gfx::Rect child_rect(50, 50);
+ int child_pass_id = 2;
+ cc::RenderPass* child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(child_pass, child_rect, SK_ColorBLUE);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+
+ AddRenderPassQuad(root_pass, child_pass);
+ AddRenderPassQuad(child_pass, grand_child_pass);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+}
+
+class DiscardCheckingGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ DiscardCheckingGLES2Interface() = default;
+
+ void InitializeTestContext(cc::TestWebGraphicsContext3D* context) override {
+ context->set_have_post_sub_buffer(true);
+ context->set_have_discard_framebuffer(true);
+ }
+
+ void DiscardFramebufferEXT(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments) override {
+ ++discarded_;
+ }
+
+ int discarded() const { return discarded_; }
+ void reset_discarded() { discarded_ = 0; }
+
+ private:
+ int discarded_ = 0;
+};
+
+TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
+ auto gl_owned = base::MakeUnique<DiscardCheckingGLES2Interface>();
+ auto* gl = gl_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ auto output_surface = cc::FakeOutputSurface::Create3d(std::move(provider));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ settings.partial_swap_enabled = true;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ EXPECT_TRUE(renderer.use_partial_swap());
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(100, 100);
+
+ {
+ // Partial frame, should not discard.
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+ root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ EXPECT_EQ(0, gl->discarded());
+ gl->reset_discarded();
+ }
+ {
+ // Full frame, should discard.
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ EXPECT_EQ(1, gl->discarded());
+ gl->reset_discarded();
+ }
+ {
+ // Full frame, external scissor is set, should not discard.
+ output_surface->set_has_external_stencil_test(true);
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+ root_pass->damage_rect = root_pass->output_rect;
+ root_pass->has_transparent_background = false;
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ EXPECT_EQ(0, gl->discarded());
+ gl->reset_discarded();
+ output_surface->set_has_external_stencil_test(false);
+ }
+}
+
+class ResourceTrackingGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ ResourceTrackingGLES2Interface() = default;
+ ~ResourceTrackingGLES2Interface() override { CheckNoResources(); }
+
+ void CheckNoResources() {
+ EXPECT_TRUE(textures_.empty());
+ EXPECT_TRUE(buffers_.empty());
+ EXPECT_TRUE(framebuffers_.empty());
+ EXPECT_TRUE(renderbuffers_.empty());
+ EXPECT_TRUE(queries_.empty());
+ EXPECT_TRUE(shaders_.empty());
+ EXPECT_TRUE(programs_.empty());
+ }
+
+ void GenTextures(GLsizei n, GLuint* textures) override {
+ GenIds(&textures_, n, textures);
+ }
+
+ void GenBuffers(GLsizei n, GLuint* buffers) override {
+ GenIds(&buffers_, n, buffers);
+ }
+
+ void GenFramebuffers(GLsizei n, GLuint* framebuffers) override {
+ GenIds(&framebuffers_, n, framebuffers);
+ }
+
+ void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override {
+ GenIds(&renderbuffers_, n, renderbuffers);
+ }
+
+ void GenQueriesEXT(GLsizei n, GLuint* queries) override {
+ GenIds(&queries_, n, queries);
+ }
+
+ GLuint CreateProgram() override { return GenId(&programs_); }
+
+ GLuint CreateShader(GLenum type) override { return GenId(&shaders_); }
+
+ void BindTexture(GLenum target, GLuint texture) override {
+ CheckId(&textures_, texture);
+ }
+
+ void BindBuffer(GLenum target, GLuint buffer) override {
+ CheckId(&buffers_, buffer);
+ }
+
+ void BindRenderbuffer(GLenum target, GLuint renderbuffer) override {
+ CheckId(&renderbuffers_, renderbuffer);
+ }
+
+ void BindFramebuffer(GLenum target, GLuint framebuffer) override {
+ CheckId(&framebuffers_, framebuffer);
+ }
+
+ void UseProgram(GLuint program) override { CheckId(&programs_, program); }
+
+ void DeleteTextures(GLsizei n, const GLuint* textures) override {
+ DeleteIds(&textures_, n, textures);
+ }
+
+ void DeleteBuffers(GLsizei n, const GLuint* buffers) override {
+ DeleteIds(&buffers_, n, buffers);
+ }
+
+ void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) override {
+ DeleteIds(&framebuffers_, n, framebuffers);
+ }
+
+ void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override {
+ DeleteIds(&renderbuffers_, n, renderbuffers);
+ }
+
+ void DeleteQueriesEXT(GLsizei n, const GLuint* queries) override {
+ DeleteIds(&queries_, n, queries);
+ }
+
+ void DeleteProgram(GLuint program) override { DeleteId(&programs_, program); }
+
+ void DeleteShader(GLuint shader) override { DeleteId(&shaders_, shader); }
+
+ void BufferData(GLenum target,
+ GLsizeiptr size,
+ const void* data,
+ GLenum usage) override {}
+
+ private:
+ GLuint GenId(std::set<GLuint>* resource_set) {
+ GLuint id = next_id_++;
+ resource_set->insert(id);
+ return id;
+ }
+
+ void GenIds(std::set<GLuint>* resource_set, GLsizei n, GLuint* ids) {
+ for (GLsizei i = 0; i < n; ++i)
+ ids[i] = GenId(resource_set);
+ }
+
+ void CheckId(std::set<GLuint>* resource_set, GLuint id) {
+ if (id == 0)
+ return;
+ EXPECT_TRUE(resource_set->find(id) != resource_set->end());
+ }
+
+ void DeleteId(std::set<GLuint>* resource_set, GLuint id) {
+ if (id == 0)
+ return;
+ size_t num_erased = resource_set->erase(id);
+ EXPECT_EQ(1u, num_erased);
+ }
+
+ void DeleteIds(std::set<GLuint>* resource_set, GLsizei n, const GLuint* ids) {
+ for (GLsizei i = 0; i < n; ++i)
+ DeleteId(resource_set, ids[i]);
+ }
+
+ GLuint next_id_ = 1;
+ std::set<GLuint> textures_;
+ std::set<GLuint> buffers_;
+ std::set<GLuint> framebuffers_;
+ std::set<GLuint> renderbuffers_;
+ std::set<GLuint> queries_;
+ std::set<GLuint> shaders_;
+ std::set<GLuint> programs_;
+};
+
+TEST_F(GLRendererTest, NoResourceLeak) {
+ auto gl_owned = base::MakeUnique<ResourceTrackingGLES2Interface>();
+ auto* gl = gl_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ auto output_surface = cc::FakeOutputSurface::Create3d(std::move(provider));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ {
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(100, 100);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+ root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ }
+ gl->CheckNoResources();
+}
+
+class DrawElementsGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ void InitializeTestContext(cc::TestWebGraphicsContext3D* context) override {
+ context->set_have_post_sub_buffer(true);
+ }
+
+ MOCK_METHOD4(
+ DrawElements,
+ void(GLenum mode, GLsizei count, GLenum type, const void* indices));
+};
+
+class GLRendererSkipTest : public GLRendererTest {
+ protected:
+ GLRendererSkipTest() {
+ auto gl_owned = base::MakeUnique<StrictMock<DrawElementsGLES2Interface>>();
+ gl_ = gl_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ output_surface_ = cc::FakeOutputSurface::Create3d(std::move(provider));
+ output_surface_->BindToClient(&output_surface_client_);
+
+ shared_bitmap_manager_.reset(new cc::TestSharedBitmapManager());
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface_->context_provider(), shared_bitmap_manager_.get());
+ settings_.partial_swap_enabled = true;
+ renderer_ = base::MakeUnique<FakeRendererGL>(
+ &settings_, output_surface_.get(), resource_provider_.get());
+ renderer_->Initialize();
+ renderer_->SetVisible(true);
+ }
+
+ StrictMock<DrawElementsGLES2Interface>* gl_;
+ RendererSettings settings_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface_;
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<FakeRendererGL> renderer_;
+};
+
+TEST_F(GLRendererSkipTest, DrawQuad) {
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
+
+ gfx::Size viewport_size(100, 100);
+ gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
+ AddQuad(root_pass, quad_rect, SK_ColorGREEN);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+}
+
+TEST_F(GLRendererSkipTest, SkipVisibleRect) {
+ gfx::Size viewport_size(100, 100);
+ gfx::Rect quad_rect = gfx::Rect(0, 0, 40, 40);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = gfx::Rect(0, 0, 10, 10);
+ AddQuad(root_pass, quad_rect, SK_ColorGREEN);
+ root_pass->shared_quad_state_list.front()->is_clipped = true;
+ root_pass->shared_quad_state_list.front()->clip_rect =
+ gfx::Rect(0, 0, 40, 40);
+ root_pass->quad_list.front()->visible_rect = gfx::Rect(20, 20, 20, 20);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ // DrawElements should not be called because the visible rect is outside the
+ // scissor, even though the clip rect and quad rect intersect the scissor.
+}
+
+TEST_F(GLRendererSkipTest, SkipClippedQuads) {
+ gfx::Size viewport_size(100, 100);
+ gfx::Rect quad_rect = gfx::Rect(25, 25, 90, 90);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
+ AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
+ root_pass->quad_list.front()->rect = gfx::Rect(20, 20, 20, 20);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ // DrawElements should not be called because the clip rect is outside the
+ // scissor.
+}
+
+TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) {
+ // When using render-to-FBO to display the surface, all rendering is done
+ // to a non-zero FBO. Make sure that the framebuffer is always restored to
+ // the correct framebuffer during rendering, if changed.
+ // Note: there is one path that will set it to 0, but that is after the render
+ // has finished.
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d());
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ EXPECT_FALSE(renderer.use_partial_swap());
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(100, 100);
+ gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
+
+ unsigned fbo;
+ gpu::gles2::GLES2Interface* gl =
+ output_surface->context_provider()->ContextGL();
+ gl->GenFramebuffers(1, &fbo);
+ output_surface->set_framebuffer(fbo, GL_RGB);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+
+ int bound_fbo;
+ gl->GetIntegerv(GL_FRAMEBUFFER_BINDING, &bound_fbo);
+ EXPECT_EQ(static_cast<int>(fbo), bound_fbo);
+}
+
+TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
+ gfx::Size viewport_size(60, 75);
+
+ gfx::Rect child_rect(50, 50);
+ int child_pass_id = 2;
+ cc::RenderPass* child_pass;
+
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass;
+
+ ResourceId mask = resource_provider_->CreateResource(
+ gfx::Size(20, 12), cc::DisplayResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ resource_provider_->best_texture_format(), gfx::ColorSpace());
+ resource_provider_->AllocateForTesting(mask);
+
+ SkScalar matrix[20];
+ float amount = 0.5f;
+ matrix[0] = 0.213f + 0.787f * amount;
+ matrix[1] = 0.715f - 0.715f * amount;
+ matrix[2] = 1.f - (matrix[0] + matrix[1]);
+ matrix[3] = matrix[4] = 0;
+ matrix[5] = 0.213f - 0.213f * amount;
+ matrix[6] = 0.715f + 0.285f * amount;
+ matrix[7] = 1.f - (matrix[5] + matrix[6]);
+ matrix[8] = matrix[9] = 0;
+ matrix[10] = 0.213f - 0.213f * amount;
+ matrix[11] = 0.715f - 0.715f * amount;
+ matrix[12] = 1.f - (matrix[10] + matrix[11]);
+ matrix[13] = matrix[14] = 0;
+ matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
+ matrix[18] = 1;
+ cc::FilterOperations filters;
+ filters.Append(
+ cc::FilterOperation::CreateReferenceFilter(SkColorFilterImageFilter::Make(
+ SkColorFilter::MakeMatrixFilterRowMajor255(matrix), nullptr)));
+
+ gfx::Transform transform_causing_aa;
+ transform_causing_aa.Rotate(20.0);
+
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ SkBlendMode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ settings_.force_blending_with_shaders = (blend_mode != BLEND_MODE_NONE);
+ // RenderPassProgram
+ render_passes_in_draw_order_.clear();
+ child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ gfx::Transform(), cc::FilterOperations());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, 0, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassColorMatrixProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+ child_rect, transform_causing_aa, filters);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, 0, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassMaskProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ gfx::Transform(), cc::FilterOperations());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, mask, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassMaskProgram(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
+
+ // RenderPassMaskColorMatrixProgram
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+ child_rect, gfx::Transform(), filters);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, mask, gfx::Transform(), xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassMaskColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
+
+ // RenderPassProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ transform_causing_aa, cc::FilterOperations());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, 0, transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+ child_rect, transform_causing_aa, filters);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, 0, transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
+
+ // RenderPassMaskProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ transform_causing_aa, cc::FilterOperations());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, mask, transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassMaskProgramAA(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
+
+ // RenderPassMaskColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
+
+ child_pass = AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+ child_rect, transform_causing_aa, filters);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), transform_causing_aa,
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, mask, transform_causing_aa,
+ xfer_mode);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+ TestRenderPassMaskColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
+ }
+}
+
+// At this time, the AA code path cannot be taken if the surface's rect would
+// project incorrectly by the given transform, because of w<0 clipping.
+TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
+ gfx::Rect child_rect(50, 50);
+ int child_pass_id = 2;
+ cc::RenderPass* child_pass;
+
+ gfx::Size viewport_size(100, 100);
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass;
+
+ gfx::Transform transform_preventing_aa;
+ transform_preventing_aa.ApplyPerspectiveDepth(40.0);
+ transform_preventing_aa.RotateAboutYAxis(-20.0);
+ transform_preventing_aa.Scale(30.0, 1.0);
+
+ // Verify that the test transform and test rect actually do cause the clipped
+ // flag to trigger. Otherwise we are not testing the intended scenario.
+ bool clipped = false;
+ cc::MathUtil::MapQuad(transform_preventing_aa,
+ gfx::QuadF(gfx::RectF(child_rect)), &clipped);
+ ASSERT_TRUE(clipped);
+
+ child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect,
+ transform_preventing_aa, cc::FilterOperations());
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ AddRenderPassQuad(root_pass, child_pass, 0, transform_preventing_aa,
+ SkBlendMode::kSrcOver);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+
+ // If use_aa incorrectly ignores clipping, it will use the
+ // RenderPassProgramAA shader instead of the RenderPassProgram.
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, BLEND_MODE_NONE);
+}
+
+TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
+ gfx::Size viewport_size(30, 30); // Don't translate out of the viewport.
+ gfx::Size quad_size(3, 3);
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass;
+
+ gfx::Transform pixel_aligned_transform_causing_aa;
+ pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f);
+ pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f);
+
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+ AddTransformedQuad(root_pass, gfx::Rect(quad_size), SK_ColorYELLOW,
+ pixel_aligned_transform_causing_aa);
+
+ renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(renderer_.get(), viewport_size);
+
+ TestSolidColorProgramAA();
+}
+
+class OutputSurfaceMockContext : public cc::TestWebGraphicsContext3D {
+ public:
+ OutputSurfaceMockContext() { test_capabilities_.post_sub_buffer = true; }
+
+ // Specifically override methods even if they are unused (used in conjunction
+ // with StrictMock). We need to make sure that GLRenderer does not issue
+ // framebuffer-related GLuint calls directly. Instead these are supposed to go
+ // through the cc::OutputSurface abstraction.
+ MOCK_METHOD2(bindFramebuffer, void(GLenum target, GLuint framebuffer));
+ MOCK_METHOD3(reshapeWithScaleFactor,
+ void(int width, int height, float scale_factor));
+ MOCK_METHOD4(drawElements,
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+};
+
+class MockOutputSurface : public cc::OutputSurface {
+ public:
+ explicit MockOutputSurface(scoped_refptr<ContextProvider> provider)
+ : cc::OutputSurface(std::move(provider)) {}
+ virtual ~MockOutputSurface() {}
+
+ void BindToClient(cc::OutputSurfaceClient*) override {}
+
+ MOCK_METHOD0(EnsureBackbuffer, void());
+ MOCK_METHOD0(DiscardBackbuffer, void());
+ MOCK_METHOD5(Reshape,
+ void(const gfx::Size& size,
+ float scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha,
+ bool use_stencil));
+ MOCK_METHOD0(BindFramebuffer, void());
+ MOCK_METHOD1(SetDrawRectangle, void(const gfx::Rect&));
+ MOCK_METHOD0(GetFramebufferCopyTextureFormat, GLenum());
+ MOCK_METHOD1(SwapBuffers_, void(cc::OutputSurfaceFrame& frame)); // NOLINT
+ void SwapBuffers(cc::OutputSurfaceFrame frame) override {
+ SwapBuffers_(frame);
+ }
+ MOCK_CONST_METHOD0(GetOverlayCandidateValidator,
+ cc::OverlayCandidateValidator*());
+ MOCK_CONST_METHOD0(IsDisplayedAsOverlayPlane, bool());
+ MOCK_CONST_METHOD0(GetOverlayTextureId, unsigned());
+ MOCK_CONST_METHOD0(GetOverlayBufferFormat, gfx::BufferFormat());
+ MOCK_CONST_METHOD0(SurfaceIsSuspendForRecycle, bool());
+ MOCK_CONST_METHOD0(HasExternalStencilTest, bool());
+ MOCK_METHOD0(ApplyExternalStencil, void());
+};
+
+class MockOutputSurfaceTest : public GLRendererTest {
+ protected:
+ void SetUp() override {
+ auto context = base::MakeUnique<StrictMock<OutputSurfaceMockContext>>();
+ context_ = context.get();
+ auto provider = cc::TestContextProvider::Create(std::move(context));
+ provider->BindToCurrentThread();
+ output_surface_ =
+ base::MakeUnique<StrictMock<MockOutputSurface>>(std::move(provider));
+
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ output_surface_->BindToClient(&output_surface_client_);
+
+ shared_bitmap_manager_.reset(new cc::TestSharedBitmapManager());
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface_->context_provider(), shared_bitmap_manager_.get());
+
+ renderer_.reset(new FakeRendererGL(&settings_, output_surface_.get(),
+ resource_provider_.get()));
+ EXPECT_CALL(*output_surface_, GetOverlayCandidateValidator()).Times(1);
+ renderer_->Initialize();
+
+ EXPECT_CALL(*output_surface_, EnsureBackbuffer()).Times(1);
+ renderer_->SetVisible(true);
+ Mock::VerifyAndClearExpectations(output_surface_.get());
+ }
+
+ void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); }
+
+ void DrawFrame(float device_scale_factor,
+ const gfx::Size& viewport_size,
+ bool transparent) {
+ int render_pass_id = 1;
+ cc::RenderPass* render_pass = AddRenderPass(
+ &render_passes_in_draw_order_, render_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ AddQuad(render_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
+ render_pass->has_transparent_background = transparent;
+
+ EXPECT_CALL(*output_surface_, EnsureBackbuffer()).WillRepeatedly(Return());
+
+ EXPECT_CALL(*output_surface_,
+ Reshape(viewport_size, device_scale_factor, _, transparent, _))
+ .Times(1);
+
+ EXPECT_CALL(*output_surface_, BindFramebuffer()).Times(1);
+
+ EXPECT_CALL(*context_, drawElements(_, _, _, _)).Times(1);
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor,
+ viewport_size);
+ }
+
+ RendererSettings settings_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ OutputSurfaceMockContext* context_ = nullptr;
+ std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_;
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<FakeRendererGL> renderer_;
+};
+
+TEST_F(MockOutputSurfaceTest, BackbufferDiscard) {
+ // Drop backbuffer on hide.
+ EXPECT_CALL(*output_surface_, DiscardBackbuffer()).Times(1);
+ renderer_->SetVisible(false);
+ Mock::VerifyAndClearExpectations(output_surface_.get());
+
+ // Restore backbuffer on show.
+ EXPECT_CALL(*output_surface_, EnsureBackbuffer()).Times(1);
+ renderer_->SetVisible(true);
+ Mock::VerifyAndClearExpectations(output_surface_.get());
+}
+
+class TestOverlayProcessor : public cc::OverlayProcessor {
+ public:
+ class Strategy : public cc::OverlayProcessor::Strategy {
+ public:
+ Strategy() {}
+ ~Strategy() override {}
+ MOCK_METHOD4(Attempt,
+ bool(cc::DisplayResourceProvider* resource_provider,
+ cc::RenderPass* render_pass,
+ cc::OverlayCandidateList* candidates,
+ std::vector<gfx::Rect>* content_bounds));
+ };
+
+ class Validator : public cc::OverlayCandidateValidator {
+ public:
+ void GetStrategies(
+ cc::OverlayProcessor::StrategyList* strategies) override {}
+
+ // Returns true if draw quads can be represented as CALayers (Mac only).
+ MOCK_METHOD0(AllowCALayerOverlays, bool());
+ MOCK_METHOD0(AllowDCLayerOverlays, bool());
+
+ // A list of possible overlay candidates is presented to this function.
+ // The expected result is that those candidates that can be in a separate
+ // plane are marked with |overlay_handled| set to true, otherwise they are
+ // to be traditionally composited. Candidates with |overlay_handled| set to
+ // true must also have their |display_rect| converted to integer
+ // coordinates if necessary.
+ void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) {}
+ };
+
+ explicit TestOverlayProcessor(cc::OutputSurface* surface)
+ : cc::OverlayProcessor(surface) {}
+ ~TestOverlayProcessor() override {}
+ void Initialize() override {
+ strategy_ = new Strategy();
+ strategies_.push_back(base::WrapUnique(strategy_));
+ }
+
+ Strategy* strategy_;
+};
+
+void MailboxReleased(const gpu::SyncToken& sync_token,
+ bool lost_resource,
+ cc::BlockingTaskRunner* main_thread_task_runner) {}
+
+void IgnoreCopyResult(std::unique_ptr<CopyOutputResult> result) {}
+
+TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d());
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+ std::unique_ptr<cc::TextureMailboxDeleter> mailbox_deleter(
+ new cc::TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get(), mailbox_deleter.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ TestOverlayProcessor* processor =
+ new TestOverlayProcessor(output_surface.get());
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+ std::unique_ptr<TestOverlayProcessor::Validator> validator(
+ new TestOverlayProcessor::Validator);
+ output_surface->SetOverlayCandidateValidator(validator.get());
+
+ gfx::Size viewport_size(1, 1);
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+ root_pass->copy_requests.push_back(
+ CopyOutputRequest::CreateRequest(base::BindOnce(&IgnoreCopyResult)));
+
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), gpu::SyncToken(), GL_TEXTURE_2D,
+ gfx::Size(256, 256), true, false);
+ std::unique_ptr<cc::SingleReleaseCallbackImpl> release_callback =
+ cc::SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+ ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, std::move(release_callback));
+ bool needs_blending = false;
+ bool premultiplied_alpha = false;
+ bool flipped = false;
+ bool nearest_neighbor = false;
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ cc::TextureDrawQuad* overlay_quad =
+ root_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
+ overlay_quad->SetNew(
+ root_pass->CreateAndAppendSharedQuadState(), gfx::Rect(viewport_size),
+ gfx::Rect(viewport_size), needs_blending, resource_id,
+ premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
+ SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor, false);
+
+ // DirectRenderer::DrawFrame calls into OverlayProcessor::ProcessForOverlays.
+ // Attempt will be called for each strategy in OverlayProcessor. We have
+ // added a fake strategy, so checking for Attempt calls checks if there was
+ // 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.
+ EXPECT_CALL(*processor->strategy_, Attempt(_, _, _, _)).Times(0);
+ EXPECT_CALL(*validator, AllowCALayerOverlays()).Times(0);
+ EXPECT_CALL(*validator, AllowDCLayerOverlays()).Times(0);
+ DrawFrame(&renderer, viewport_size);
+ Mock::VerifyAndClearExpectations(processor->strategy_);
+ Mock::VerifyAndClearExpectations(validator.get());
+
+ // Without a copy request Attempt() should be called once.
+ root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+
+ overlay_quad = root_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
+ overlay_quad->SetNew(
+ root_pass->CreateAndAppendSharedQuadState(), gfx::Rect(viewport_size),
+ gfx::Rect(viewport_size), needs_blending, resource_id,
+ premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
+ SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor, false);
+ EXPECT_CALL(*validator, AllowCALayerOverlays())
+ .Times(1)
+ .WillOnce(::testing::Return(false));
+ EXPECT_CALL(*validator, AllowDCLayerOverlays())
+ .Times(1)
+ .WillOnce(::testing::Return(false));
+ EXPECT_CALL(*processor->strategy_, Attempt(_, _, _, _)).Times(1);
+ DrawFrame(&renderer, viewport_size);
+
+ // If the CALayerOverlay path is taken, then the ordinary overlay path should
+ // not be called.
+ root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+
+ overlay_quad = root_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
+ overlay_quad->SetNew(
+ root_pass->CreateAndAppendSharedQuadState(), gfx::Rect(viewport_size),
+ gfx::Rect(viewport_size), needs_blending, resource_id,
+ premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
+ SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor, false);
+ EXPECT_CALL(*validator, AllowCALayerOverlays())
+ .Times(1)
+ .WillOnce(::testing::Return(true));
+ EXPECT_CALL(*processor->strategy_, Attempt(_, _, _, _)).Times(0);
+ DrawFrame(&renderer, viewport_size);
+}
+
+class SingleOverlayOnTopProcessor : public cc::OverlayProcessor {
+ public:
+ class SingleOverlayValidator : public cc::OverlayCandidateValidator {
+ public:
+ void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
+ strategies->push_back(
+ base::MakeUnique<cc::OverlayStrategySingleOnTop>(this));
+ strategies->push_back(
+ base::MakeUnique<cc::OverlayStrategyUnderlay>(this));
+ }
+
+ bool AllowCALayerOverlays() override { return false; }
+ bool AllowDCLayerOverlays() override { return false; }
+
+ void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {
+ ASSERT_EQ(1U, surfaces->size());
+ cc::OverlayCandidate& candidate = surfaces->back();
+ candidate.overlay_handled = true;
+ }
+ };
+
+ explicit SingleOverlayOnTopProcessor(cc::OutputSurface* surface)
+ : OverlayProcessor(surface) {}
+
+ void Initialize() override {
+ strategies_.push_back(
+ base::MakeUnique<cc::OverlayStrategySingleOnTop>(&validator_));
+ }
+
+ SingleOverlayValidator validator_;
+};
+
+class WaitSyncTokenCountingContext : public cc::TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
+};
+
+class MockOverlayScheduler {
+ public:
+ MOCK_METHOD5(Schedule,
+ void(int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ unsigned overlay_texture_id,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& uv_rect));
+};
+
+TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
+ std::unique_ptr<WaitSyncTokenCountingContext> context_owned(
+ new WaitSyncTokenCountingContext);
+ WaitSyncTokenCountingContext* context = context_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(context_owned));
+ provider->BindToCurrentThread();
+
+ MockOverlayScheduler overlay_scheduler;
+ provider->support()->SetScheduleOverlayPlaneCallback(base::Bind(
+ &MockOverlayScheduler::Schedule, base::Unretained(&overlay_scheduler)));
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::OutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new cc::TestSharedBitmapManager());
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), shared_bitmap_manager.get());
+ std::unique_ptr<cc::TextureMailboxDeleter> mailbox_deleter(
+ new cc::TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get(), mailbox_deleter.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+
+ SingleOverlayOnTopProcessor* processor =
+ new SingleOverlayOnTopProcessor(output_surface.get());
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+
+ gfx::Size viewport_size(1, 1);
+ cc::RenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->has_transparent_background = false;
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
+ gpu::CommandBufferId::FromUnsafeValue(0x123), 29);
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), sync_token, GL_TEXTURE_2D,
+ gfx::Size(256, 256), true, false);
+ std::unique_ptr<cc::SingleReleaseCallbackImpl> release_callback =
+ cc::SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+ ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, std::move(release_callback));
+ bool needs_blending = false;
+ bool premultiplied_alpha = false;
+ bool flipped = false;
+ bool nearest_neighbor = false;
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ gfx::PointF uv_top_left(0, 0);
+ gfx::PointF uv_bottom_right(1, 1);
+
+ cc::TextureDrawQuad* overlay_quad =
+ root_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
+ SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
+ shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
+ gfx::Rect(viewport_size), gfx::Rect(viewport_size),
+ false, 1, SkBlendMode::kSrcOver, 0);
+ overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
+ gfx::Rect(viewport_size), needs_blending, resource_id,
+ premultiplied_alpha, uv_top_left, uv_bottom_right,
+ SK_ColorTRANSPARENT, vertex_opacity, flipped,
+ nearest_neighbor, false);
+
+ // Verify that overlay_quad actually gets turned into an overlay, and even
+ // though it's not drawn, that its sync point is waited on.
+ EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1);
+ EXPECT_CALL(
+ overlay_scheduler,
+ Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, gfx::Rect(viewport_size),
+ BoundingRect(uv_top_left, uv_bottom_right)))
+ .Times(1);
+
+ DrawFrame(&renderer, viewport_size);
+}
+
+class PartialSwapMockGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ explicit PartialSwapMockGLES2Interface(bool support_dc_layers)
+ : support_dc_layers_(support_dc_layers) {}
+
+ void InitializeTestContext(cc::TestWebGraphicsContext3D* context) override {
+ context->set_have_post_sub_buffer(true);
+ context->set_enable_dc_layers(support_dc_layers_);
+ }
+
+ MOCK_METHOD1(Enable, void(GLenum cap));
+ MOCK_METHOD1(Disable, void(GLenum cap));
+ MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
+ MOCK_METHOD1(SetEnableDCLayersCHROMIUM, void(GLboolean enable));
+
+ private:
+ bool support_dc_layers_;
+};
+
+class GLRendererPartialSwapTest : public GLRendererTest {
+ protected:
+ void RunTest(bool partial_swap, bool set_draw_rectangle) {
+ auto gl_owned =
+ base::MakeUnique<PartialSwapMockGLES2Interface>(set_draw_rectangle);
+ auto* gl = gl_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), nullptr);
+
+ RendererSettings settings;
+ settings.partial_swap_enabled = partial_swap;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ EXPECT_EQ(partial_swap, renderer.use_partial_swap());
+ renderer.SetVisible(true);
+
+ gfx::Size viewport_size(100, 100);
+ gfx::Rect root_pass_output_rect(80, 80);
+ gfx::Rect root_pass_damage_rect(2, 2, 3, 3);
+
+ for (int i = 0; i < 2; ++i) {
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, root_pass_output_rect,
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ AddQuad(root_pass, gfx::Rect(root_pass_output_rect), SK_ColorGREEN);
+
+ InSequence seq;
+
+ // A bunch of initialization that happens.
+ 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));
+
+ // Partial frame, we should use a scissor to swap only that part when
+ // partial swap is enabled. With SetDrawRectangle the first frame will
+ // have its damage expanded to cover the entire output rect.
+ bool draw_rectangle_needs_full_damage = set_draw_rectangle && (i == 0);
+ bool frame_has_partial_damage =
+ partial_swap && !draw_rectangle_needs_full_damage;
+ gfx::Rect output_rectangle = frame_has_partial_damage
+ ? root_pass_damage_rect
+ : gfx::Rect(viewport_size);
+
+ 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()));
+ }
+
+ // The quad doesn't need blending.
+ EXPECT_CALL(*gl, Disable(GL_BLEND));
+
+ // Blending is disabled at the end of the frame.
+ EXPECT_CALL(*gl, Disable(GL_BLEND));
+
+ renderer.DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+
+ if (set_draw_rectangle) {
+ EXPECT_EQ(output_rectangle, output_surface->last_set_draw_rectangle());
+ }
+
+ Mock::VerifyAndClearExpectations(gl);
+ }
+ }
+};
+
+TEST_F(GLRendererPartialSwapTest, PartialSwap) {
+ RunTest(true, false);
+}
+
+TEST_F(GLRendererPartialSwapTest, NoPartialSwap) {
+ RunTest(false, false);
+}
+
+TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_PartialSwap) {
+ RunTest(true, true);
+}
+
+TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_NoPartialSwap) {
+ RunTest(false, true);
+}
+
+class DCLayerValidator : public cc::OverlayCandidateValidator {
+ public:
+ void GetStrategies(cc::OverlayProcessor::StrategyList* strategies) override {}
+ bool AllowCALayerOverlays() override { return false; }
+ bool AllowDCLayerOverlays() override { return true; }
+ void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+};
+
+// 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 = base::MakeUnique<PartialSwapMockGLES2Interface>(true);
+ auto* gl = gl_owned.get();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), nullptr);
+
+ RendererSettings settings;
+ settings.partial_swap_enabled = true;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ renderer.SetVisible(true);
+ TestOverlayProcessor* processor =
+ new TestOverlayProcessor(output_surface.get());
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+ std::unique_ptr<DCLayerValidator> validator(new DCLayerValidator);
+ output_surface->SetOverlayCandidateValidator(validator.get());
+
+ gfx::Size viewport_size(100, 100);
+
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), gpu::SyncToken(), GL_TEXTURE_2D,
+ gfx::Size(256, 256), true, false);
+ std::unique_ptr<cc::SingleReleaseCallbackImpl> release_callback =
+ cc::SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+ ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, std::move(release_callback));
+
+ for (int i = 0; i < 65; i++) {
+ int root_pass_id = 1;
+ cc::RenderPass* root_pass = AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ if (i == 0) {
+ gfx::Rect rect(0, 0, 100, 100);
+ bool needs_blending = false;
+ gfx::RectF tex_coord_rect(0, 0, 1, 1);
+ SharedQuadState* shared_state =
+ root_pass->CreateAndAppendSharedQuadState();
+ shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
+ SkBlendMode::kSrcOver, 0);
+ cc::YUVVideoDrawQuad* quad =
+ root_pass->CreateAndAppendDrawQuad<cc::YUVVideoDrawQuad>();
+ quad->SetNew(shared_state, rect, rect, needs_blending, tex_coord_rect,
+ tex_coord_rect, rect.size(), rect.size(), resource_id,
+ resource_id, resource_id, resource_id,
+ cc::YUVVideoDrawQuad::REC_601, gfx::ColorSpace(), 0, 1.0, 8);
+ }
+
+ // A bunch of initialization that happens.
+ EXPECT_CALL(*gl, Disable(_)).Times(AnyNumber());
+ EXPECT_CALL(*gl, Enable(_)).Times(AnyNumber());
+ EXPECT_CALL(*gl, Scissor(_, _, _, _)).Times(AnyNumber());
+
+ // Partial frame, we should use a scissor to swap only that part when
+ // partial swap is enabled.
+ root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
+ // Frame 0 should be completely damaged because it's the first.
+ // Frame 1 should be because it changed. Frame 60 should be
+ // because it's disabling DC layers.
+ gfx::Rect output_rectangle = (i == 0 || i == 1 || i == 60)
+ ? root_pass->output_rect
+ : root_pass->damage_rect;
+
+ // Frame 0 should have DC Layers enabled because of the overlay.
+ // After 60 frames of no overlays DC layers should be disabled again.
+ if (i < 60)
+ EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_TRUE));
+ else
+ EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_FALSE));
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ EXPECT_EQ(output_rectangle, output_surface->last_set_draw_rectangle());
+ testing::Mock::VerifyAndClearExpectations(gl);
+ }
+}
+
+class GLRendererWithMockContextTest : public ::testing::Test {
+ protected:
+ class MockContextSupport : public cc::TestContextSupport {
+ public:
+ MockContextSupport() {}
+ MOCK_METHOD1(SetAggressivelyFreeResources,
+ void(bool aggressively_free_resources));
+ };
+
+ void SetUp() override {
+ auto context_support = base::MakeUnique<MockContextSupport>();
+ context_support_ptr_ = context_support.get();
+ auto context_provider = cc::TestContextProvider::Create(
+ cc::TestWebGraphicsContext3D::Create(), std::move(context_support));
+ context_provider->BindToCurrentThread();
+ output_surface_ =
+ cc::FakeOutputSurface::Create3d(std::move(context_provider));
+ output_surface_->BindToClient(&output_surface_client_);
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface_->context_provider(), nullptr);
+ renderer_ = base::MakeUnique<GLRenderer>(&settings_, output_surface_.get(),
+ resource_provider_.get(), nullptr);
+ renderer_->Initialize();
+ }
+
+ RendererSettings settings_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ MockContextSupport* context_support_ptr_;
+ std::unique_ptr<cc::OutputSurface> output_surface_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<GLRenderer> renderer_;
+};
+
+TEST_F(GLRendererWithMockContextTest,
+ ContextPurgedWhenRendererBecomesInvisible) {
+ EXPECT_CALL(*context_support_ptr_, SetAggressivelyFreeResources(false));
+ renderer_->SetVisible(true);
+ Mock::VerifyAndClearExpectations(context_support_ptr_);
+
+ EXPECT_CALL(*context_support_ptr_, SetAggressivelyFreeResources(true));
+ renderer_->SetVisible(false);
+ Mock::VerifyAndClearExpectations(context_support_ptr_);
+}
+
+class SwapWithBoundsMockGLES2Interface : public cc::TestGLES2Interface {
+ public:
+ void InitializeTestContext(cc::TestWebGraphicsContext3D* context) override {
+ context->set_have_swap_buffers_with_bounds(true);
+ }
+};
+
+class ContentBoundsOverlayProcessor : public cc::OverlayProcessor {
+ public:
+ class Strategy : public OverlayProcessor::Strategy {
+ public:
+ explicit Strategy(const std::vector<gfx::Rect>& content_bounds)
+ : content_bounds_(content_bounds) {}
+ ~Strategy() override {}
+ bool Attempt(cc::DisplayResourceProvider* resource_provider,
+ cc::RenderPass* render_pass,
+ cc::OverlayCandidateList* candidates,
+ std::vector<gfx::Rect>* content_bounds) override {
+ content_bounds->insert(content_bounds->end(), content_bounds_.begin(),
+ content_bounds_.end());
+ return true;
+ }
+
+ const std::vector<gfx::Rect> content_bounds_;
+ };
+
+ ContentBoundsOverlayProcessor(cc::OutputSurface* surface,
+ const std::vector<gfx::Rect>& content_bounds)
+ : OverlayProcessor(surface), content_bounds_(content_bounds) {}
+
+ void Initialize() override {
+ strategy_ = new Strategy(content_bounds_);
+ strategies_.push_back(base::WrapUnique(strategy_));
+ }
+
+ Strategy* strategy_;
+ const std::vector<gfx::Rect> content_bounds_;
+};
+
+class GLRendererSwapWithBoundsTest : public GLRendererTest {
+ protected:
+ void RunTest(const std::vector<gfx::Rect>& content_bounds) {
+ auto gl_owned = base::MakeUnique<SwapWithBoundsMockGLES2Interface>();
+
+ auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ cc::FakeOutputSurfaceClient output_surface_client;
+ std::unique_ptr<cc::FakeOutputSurface> output_surface(
+ cc::FakeOutputSurface::Create3d(std::move(provider)));
+ output_surface->BindToClient(&output_surface_client);
+
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ output_surface->context_provider(), nullptr);
+
+ RendererSettings settings;
+ FakeRendererGL renderer(&settings, output_surface.get(),
+ resource_provider.get());
+ renderer.Initialize();
+ EXPECT_EQ(true, renderer.use_swap_with_bounds());
+ renderer.SetVisible(true);
+
+ cc::OverlayProcessor* processor =
+ new ContentBoundsOverlayProcessor(output_surface.get(), content_bounds);
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+
+ gfx::Size viewport_size(100, 100);
+
+ {
+ int root_pass_id = 1;
+ AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
+ gfx::Rect(viewport_size), gfx::Transform(),
+ cc::FilterOperations());
+
+ renderer.DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(&renderer, viewport_size);
+ renderer.SwapBuffers(std::vector<ui::LatencyInfo>());
+
+ std::vector<gfx::Rect> expected_content_bounds;
+ EXPECT_EQ(content_bounds,
+ output_surface->last_sent_frame()->content_bounds);
+ }
+ }
+};
+
+TEST_F(GLRendererSwapWithBoundsTest, EmptyContent) {
+ std::vector<gfx::Rect> content_bounds;
+ RunTest(content_bounds);
+}
+
+TEST_F(GLRendererSwapWithBoundsTest, NonEmpty) {
+ std::vector<gfx::Rect> content_bounds;
+ content_bounds.push_back(gfx::Rect(0, 0, 10, 10));
+ content_bounds.push_back(gfx::Rect(20, 20, 30, 30));
+ RunTest(content_bounds);
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/service/display/program_binding.cc b/chromium/components/viz/service/display/program_binding.cc
new file mode 100644
index 00000000000..172c339b72a
--- /dev/null
+++ b/chromium/components/viz/service/display/program_binding.cc
@@ -0,0 +1,277 @@
+// Copyright 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/viz/service/display/program_binding.h"
+
+#include "base/trace_event/trace_event.h"
+#include "components/viz/service/display/geometry_binding.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/color_transform.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace viz {
+
+ProgramKey::ProgramKey() = default;
+
+ProgramKey::ProgramKey(const ProgramKey& other) = default;
+
+ProgramKey::~ProgramKey() = default;
+
+bool ProgramKey::operator==(const ProgramKey& other) const {
+ return type_ == other.type_ && precision_ == other.precision_ &&
+ sampler_ == other.sampler_ && blend_mode_ == other.blend_mode_ &&
+ aa_mode_ == other.aa_mode_ && swizzle_mode_ == other.swizzle_mode_ &&
+ is_opaque_ == other.is_opaque_ &&
+ premultiplied_alpha_ == other.premultiplied_alpha_ &&
+ has_background_color_ == other.has_background_color_ &&
+ has_tex_clamp_rect_ == other.has_tex_clamp_rect_ &&
+ mask_mode_ == other.mask_mode_ &&
+ mask_for_background_ == other.mask_for_background_ &&
+ has_color_matrix_ == other.has_color_matrix_ &&
+ yuv_alpha_texture_mode_ == other.yuv_alpha_texture_mode_ &&
+ uv_texture_mode_ == other.uv_texture_mode_ &&
+ color_conversion_mode_ == other.color_conversion_mode_ &&
+ color_transform_ == other.color_transform_;
+}
+
+bool ProgramKey::operator!=(const ProgramKey& other) const {
+ return !(*this == other);
+}
+
+// static
+ProgramKey ProgramKey::DebugBorder() {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_DEBUG_BORDER;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::SolidColor(AAMode aa_mode) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_SOLID_COLOR;
+ result.aa_mode_ = aa_mode;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::Tile(TexCoordPrecision precision,
+ SamplerType sampler,
+ AAMode aa_mode,
+ SwizzleMode swizzle_mode,
+ bool is_opaque) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_TILE;
+ result.precision_ = precision;
+ result.sampler_ = sampler;
+ result.aa_mode_ = aa_mode;
+ result.swizzle_mode_ = swizzle_mode;
+ result.is_opaque_ = is_opaque;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::Texture(TexCoordPrecision precision,
+ SamplerType sampler,
+ PremultipliedAlphaMode premultiplied_alpha,
+ bool has_background_color,
+ bool has_tex_clamp_rect) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_TEXTURE;
+ result.precision_ = precision;
+ result.sampler_ = sampler;
+ result.premultiplied_alpha_ = premultiplied_alpha;
+ result.has_background_color_ = has_background_color;
+ result.has_tex_clamp_rect_ = has_tex_clamp_rect;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::RenderPass(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ AAMode aa_mode,
+ MaskMode mask_mode,
+ bool mask_for_background,
+ bool has_color_matrix) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_RENDER_PASS;
+ result.precision_ = precision;
+ result.sampler_ = sampler;
+ result.blend_mode_ = blend_mode;
+ result.aa_mode_ = aa_mode;
+ result.mask_mode_ = mask_mode;
+ result.mask_for_background_ = mask_for_background;
+ result.has_color_matrix_ = has_color_matrix;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::VideoStream(TexCoordPrecision precision) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_VIDEO_STREAM;
+ result.precision_ = precision;
+ result.sampler_ = SAMPLER_TYPE_EXTERNAL_OES;
+ return result;
+}
+
+// static
+ProgramKey ProgramKey::YUVVideo(TexCoordPrecision precision,
+ SamplerType sampler,
+ YUVAlphaTextureMode yuv_alpha_texture_mode,
+ UVTextureMode uv_texture_mode) {
+ ProgramKey result;
+ result.type_ = PROGRAM_TYPE_YUV_VIDEO;
+ result.precision_ = precision;
+ result.sampler_ = sampler;
+ result.yuv_alpha_texture_mode_ = yuv_alpha_texture_mode;
+ DCHECK(yuv_alpha_texture_mode == YUV_NO_ALPHA_TEXTURE ||
+ yuv_alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE);
+ result.uv_texture_mode_ = uv_texture_mode;
+ DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV ||
+ uv_texture_mode == UV_TEXTURE_MODE_U_V);
+ return result;
+}
+
+void ProgramKey::SetColorTransform(const gfx::ColorTransform* transform) {
+ color_transform_ = nullptr;
+ if (transform->IsIdentity()) {
+ color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
+ } else if (transform->CanGetShaderSource()) {
+ color_conversion_mode_ = COLOR_CONVERSION_MODE_SHADER;
+ color_transform_ = transform;
+ } else {
+ color_conversion_mode_ = COLOR_CONVERSION_MODE_LUT;
+ }
+}
+
+ProgramBindingBase::ProgramBindingBase()
+ : program_(0),
+ vertex_shader_id_(0),
+ fragment_shader_id_(0),
+ initialized_(false) {}
+
+ProgramBindingBase::~ProgramBindingBase() {
+ // If you hit these asserts, you initialized but forgot to call Cleanup().
+ DCHECK(!program_);
+ DCHECK(!vertex_shader_id_);
+ DCHECK(!fragment_shader_id_);
+ DCHECK(!initialized_);
+}
+
+bool ProgramBindingBase::Init(GLES2Interface* context,
+ const std::string& vertex_shader,
+ const std::string& fragment_shader) {
+ TRACE_EVENT0("cc", "ProgramBindingBase::init");
+ vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
+ if (!vertex_shader_id_)
+ return false;
+
+ fragment_shader_id_ =
+ LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
+ if (!fragment_shader_id_) {
+ context->DeleteShader(vertex_shader_id_);
+ vertex_shader_id_ = 0;
+ return false;
+ }
+
+ program_ =
+ CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
+ return !!program_;
+}
+
+bool ProgramBindingBase::Link(GLES2Interface* context) {
+ context->LinkProgram(program_);
+ CleanupShaders(context);
+ if (!program_)
+ return false;
+#ifndef NDEBUG
+ int linked = 0;
+ context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ char buffer[1024] = "";
+ context->GetProgramInfoLog(program_, sizeof(buffer), nullptr, buffer);
+ DLOG(ERROR) << "Error compiling shader: " << buffer;
+ return false;
+ }
+#endif
+ return true;
+}
+
+void ProgramBindingBase::Cleanup(GLES2Interface* context) {
+ initialized_ = false;
+ if (!program_)
+ return;
+
+ DCHECK(context);
+ context->DeleteProgram(program_);
+ program_ = 0;
+
+ CleanupShaders(context);
+}
+
+unsigned ProgramBindingBase::LoadShader(GLES2Interface* context,
+ unsigned type,
+ const std::string& shader_source) {
+ unsigned shader = context->CreateShader(type);
+ if (!shader)
+ return 0u;
+
+ const char* shader_source_str[] = {shader_source.data()};
+ int shader_length[] = {static_cast<int>(shader_source.length())};
+ context->ShaderSource(shader, 1, shader_source_str, shader_length);
+ context->CompileShader(shader);
+#if DCHECK_IS_ON()
+ int compiled = 0;
+ context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ char buffer[1024] = "";
+ context->GetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
+ DLOG(ERROR) << "Error compiling shader: " << buffer
+ << "\n shader program: " << shader_source;
+ return 0u;
+ }
+#endif
+ return shader;
+}
+
+unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context,
+ unsigned vertex_shader,
+ unsigned fragment_shader) {
+ unsigned program_object = context->CreateProgram();
+ if (!program_object)
+ return 0;
+
+ context->AttachShader(program_object, vertex_shader);
+ context->AttachShader(program_object, fragment_shader);
+
+ // Bind the common attrib locations.
+ context->BindAttribLocation(
+ program_object, GeometryBinding::PositionAttribLocation(), "a_position");
+ context->BindAttribLocation(
+ program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord");
+ context->BindAttribLocation(program_object,
+ GeometryBinding::TriangleIndexAttribLocation(),
+ "a_index");
+
+ return program_object;
+}
+
+void ProgramBindingBase::CleanupShaders(GLES2Interface* context) {
+ if (vertex_shader_id_) {
+ context->DeleteShader(vertex_shader_id_);
+ vertex_shader_id_ = 0;
+ }
+ if (fragment_shader_id_) {
+ context->DeleteShader(fragment_shader_id_);
+ fragment_shader_id_ = 0;
+ }
+}
+
+bool ProgramBindingBase::IsContextLost(GLES2Interface* context) {
+ return context->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/program_binding.h b/chromium/components/viz/service/display/program_binding.h
new file mode 100644
index 00000000000..70f1ff97b1a
--- /dev/null
+++ b/chromium/components/viz/service/display/program_binding.h
@@ -0,0 +1,446 @@
+// Copyright 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_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/service/display/shader.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace gfx {
+class ColorTransform;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
+namespace viz {
+
+class VIZ_SERVICE_EXPORT ProgramBindingBase {
+ public:
+ ProgramBindingBase();
+ ~ProgramBindingBase();
+
+ bool Init(gpu::gles2::GLES2Interface* context,
+ const std::string& vertex_shader,
+ const std::string& fragment_shader);
+ bool Link(gpu::gles2::GLES2Interface* context);
+ void Cleanup(gpu::gles2::GLES2Interface* context);
+
+ unsigned program() const { return program_; }
+ bool initialized() const { return initialized_; }
+
+ protected:
+ unsigned LoadShader(gpu::gles2::GLES2Interface* context,
+ unsigned type,
+ const std::string& shader_source);
+ unsigned CreateShaderProgram(gpu::gles2::GLES2Interface* context,
+ unsigned vertex_shader,
+ unsigned fragment_shader);
+ void CleanupShaders(gpu::gles2::GLES2Interface* context);
+
+ bool IsContextLost(gpu::gles2::GLES2Interface* context);
+
+ unsigned program_;
+ unsigned vertex_shader_id_;
+ unsigned fragment_shader_id_;
+ bool initialized_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProgramBindingBase);
+};
+
+enum ProgramType {
+ PROGRAM_TYPE_DEBUG_BORDER,
+ PROGRAM_TYPE_SOLID_COLOR,
+ PROGRAM_TYPE_TILE,
+ PROGRAM_TYPE_TEXTURE,
+ PROGRAM_TYPE_RENDER_PASS,
+ PROGRAM_TYPE_VIDEO_STREAM,
+ PROGRAM_TYPE_YUV_VIDEO,
+};
+
+class VIZ_SERVICE_EXPORT ProgramKey {
+ public:
+ ProgramKey();
+ ProgramKey(const ProgramKey& other);
+ ~ProgramKey();
+
+ static ProgramKey DebugBorder();
+ static ProgramKey SolidColor(AAMode aa_mode);
+ static ProgramKey Tile(TexCoordPrecision precision,
+ SamplerType sampler,
+ AAMode aa_mode,
+ SwizzleMode swizzle_mode,
+ bool is_opaque);
+ static ProgramKey Texture(TexCoordPrecision precision,
+ SamplerType sampler,
+ PremultipliedAlphaMode premultiplied_alpha,
+ bool has_background_color,
+ bool has_tex_clamp_rect);
+
+ // TODO(ccameron): Merge |mask_for_background| into MaskMode.
+ static ProgramKey RenderPass(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ AAMode aa_mode,
+ MaskMode mask_mode,
+ bool mask_for_background,
+ bool has_color_matrix);
+ static ProgramKey VideoStream(TexCoordPrecision precision);
+ static ProgramKey YUVVideo(TexCoordPrecision precision,
+ SamplerType sampler,
+ YUVAlphaTextureMode yuv_alpha_texture_mode,
+ UVTextureMode uv_texture_mode);
+
+ bool operator==(const ProgramKey& other) const;
+ bool operator!=(const ProgramKey& other) const;
+
+ void SetColorTransform(const gfx::ColorTransform* transform);
+
+ private:
+ friend struct ProgramKeyHash;
+ friend class Program;
+
+ ProgramType type_ = PROGRAM_TYPE_DEBUG_BORDER;
+ TexCoordPrecision precision_ = TEX_COORD_PRECISION_NA;
+ SamplerType sampler_ = SAMPLER_TYPE_NA;
+ BlendMode blend_mode_ = BLEND_MODE_NONE;
+ AAMode aa_mode_ = NO_AA;
+ SwizzleMode swizzle_mode_ = NO_SWIZZLE;
+ bool is_opaque_ = false;
+
+ PremultipliedAlphaMode premultiplied_alpha_ = PREMULTIPLIED_ALPHA;
+ bool has_background_color_ = false;
+
+ MaskMode mask_mode_ = NO_MASK;
+ bool mask_for_background_ = false;
+ bool has_color_matrix_ = false;
+
+ YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_NO_ALPHA_TEXTURE;
+ UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_NA;
+
+ ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
+ const gfx::ColorTransform* color_transform_ = nullptr;
+
+ bool has_tex_clamp_rect_ = false;
+};
+
+struct ProgramKeyHash {
+ size_t operator()(const ProgramKey& key) const {
+ return (static_cast<size_t>(key.type_) << 0) ^
+ (static_cast<size_t>(key.precision_) << 3) ^
+ (static_cast<size_t>(key.sampler_) << 6) ^
+ (static_cast<size_t>(key.blend_mode_) << 9) ^
+ (static_cast<size_t>(key.aa_mode_) << 15) ^
+ (static_cast<size_t>(key.swizzle_mode_) << 16) ^
+ (static_cast<size_t>(key.is_opaque_) << 17) ^
+ (static_cast<size_t>(key.premultiplied_alpha_) << 19) ^
+ (static_cast<size_t>(key.has_background_color_) << 20) ^
+ (static_cast<size_t>(key.mask_mode_) << 21) ^
+ (static_cast<size_t>(key.mask_for_background_) << 22) ^
+ (static_cast<size_t>(key.has_color_matrix_) << 23) ^
+ (static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^
+ (static_cast<size_t>(key.uv_texture_mode_) << 25) ^
+ (static_cast<size_t>(key.color_conversion_mode_) << 26) ^
+ (static_cast<size_t>(key.has_tex_clamp_rect_) << 28);
+ }
+};
+
+class VIZ_SERVICE_EXPORT Program : public ProgramBindingBase {
+ public:
+ Program() {}
+
+ void Initialize(ContextProvider* context_provider, const ProgramKey& key) {
+ // Set parameters that are common to all sub-classes.
+ vertex_shader_.aa_mode_ = key.aa_mode_;
+ fragment_shader_.aa_mode_ = key.aa_mode_;
+ fragment_shader_.blend_mode_ = key.blend_mode_;
+ fragment_shader_.tex_coord_precision_ = key.precision_;
+ fragment_shader_.sampler_type_ = key.sampler_;
+ fragment_shader_.swizzle_mode_ = key.swizzle_mode_;
+ fragment_shader_.premultiply_alpha_mode_ = key.premultiplied_alpha_;
+ fragment_shader_.mask_mode_ = key.mask_mode_;
+ fragment_shader_.mask_for_background_ = key.mask_for_background_;
+ fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_;
+ fragment_shader_.color_transform_ = key.color_transform_;
+
+ switch (key.type_) {
+ case PROGRAM_TYPE_DEBUG_BORDER:
+ InitializeDebugBorderProgram();
+ break;
+ case PROGRAM_TYPE_SOLID_COLOR:
+ InitializeSolidColorProgram(key);
+ break;
+ case PROGRAM_TYPE_TILE:
+ InitializeTileProgram(key);
+ break;
+ case PROGRAM_TYPE_TEXTURE:
+ InitializeTextureProgram(key);
+ break;
+ case PROGRAM_TYPE_RENDER_PASS:
+ InitializeRenderPassProgram(key);
+ break;
+ case PROGRAM_TYPE_VIDEO_STREAM:
+ InitializeVideoStreamProgram(key);
+ break;
+ case PROGRAM_TYPE_YUV_VIDEO:
+ InitializeYUVVideo(key);
+ break;
+ }
+ InitializeInternal(context_provider);
+ }
+
+ const VertexShader& vertex_shader() const { return vertex_shader_; }
+ const FragmentShader& fragment_shader() const { return fragment_shader_; }
+
+ // Functions for querying uniform locations.
+ int vertex_tex_transform_location() const {
+ return vertex_shader_.vertex_tex_transform_location_;
+ }
+ int tex_matrix_location() const {
+ return vertex_shader_.tex_matrix_location_;
+ }
+ int ya_tex_scale_location() const {
+ return vertex_shader_.ya_tex_scale_location_;
+ }
+ int ya_tex_offset_location() const {
+ return vertex_shader_.ya_tex_offset_location_;
+ }
+ int uv_tex_scale_location() const {
+ return vertex_shader_.uv_tex_scale_location_;
+ }
+ int uv_tex_offset_location() const {
+ return vertex_shader_.uv_tex_offset_location_;
+ }
+ int matrix_location() const { return vertex_shader_.matrix_location_; }
+ int vertex_opacity_location() const {
+ return vertex_shader_.vertex_opacity_location_;
+ }
+ int viewport_location() const { return vertex_shader_.viewport_location_; }
+ int edge_location() const { return vertex_shader_.edge_location_; }
+ int quad_location() const { return vertex_shader_.quad_location_; }
+
+ int sampler_location() const { return fragment_shader_.sampler_location_; }
+ int alpha_location() const { return fragment_shader_.alpha_location_; }
+ int color_location() const { return fragment_shader_.color_location_; }
+ int background_color_location() const {
+ return fragment_shader_.background_color_location_;
+ }
+ int fragment_tex_transform_location() const {
+ return fragment_shader_.fragment_tex_transform_location_;
+ }
+ int backdrop_location() const { return fragment_shader_.backdrop_location_; }
+ int backdrop_rect_location() const {
+ return fragment_shader_.backdrop_rect_location_;
+ }
+ int original_backdrop_location() const {
+ return fragment_shader_.original_backdrop_location_;
+ }
+ int mask_sampler_location() const {
+ return fragment_shader_.mask_sampler_location_;
+ }
+ int mask_tex_coord_scale_location() const {
+ return fragment_shader_.mask_tex_coord_scale_location_;
+ }
+ int mask_tex_coord_offset_location() const {
+ return fragment_shader_.mask_tex_coord_offset_location_;
+ }
+ int color_matrix_location() const {
+ return fragment_shader_.color_matrix_location_;
+ }
+ int color_offset_location() const {
+ return fragment_shader_.color_offset_location_;
+ }
+ int tex_clamp_rect_location() const {
+ return fragment_shader_.tex_clamp_rect_location_;
+ }
+ int y_texture_location() const {
+ return fragment_shader_.y_texture_location_;
+ }
+ int u_texture_location() const {
+ return fragment_shader_.u_texture_location_;
+ }
+ int v_texture_location() const {
+ return fragment_shader_.v_texture_location_;
+ }
+ int uv_texture_location() const {
+ return fragment_shader_.uv_texture_location_;
+ }
+ int a_texture_location() const {
+ return fragment_shader_.a_texture_location_;
+ }
+ int lut_texture_location() const {
+ return fragment_shader_.lut_texture_location_;
+ }
+ int lut_size_location() const { return fragment_shader_.lut_size_location_; }
+ int resource_multiplier_location() const {
+ return fragment_shader_.resource_multiplier_location_;
+ }
+ int resource_offset_location() const {
+ return fragment_shader_.resource_offset_location_;
+ }
+ int ya_clamp_rect_location() const {
+ return fragment_shader_.ya_clamp_rect_location_;
+ }
+ int uv_clamp_rect_location() const {
+ return fragment_shader_.uv_clamp_rect_location_;
+ }
+
+ private:
+ void InitializeDebugBorderProgram() {
+ // Initialize vertex program.
+ vertex_shader_.has_matrix_ = true;
+
+ // Initialize fragment program.
+ fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
+ fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
+ }
+
+ void InitializeSolidColorProgram(const ProgramKey& key) {
+ // Initialize vertex program.
+ vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
+ vertex_shader_.has_matrix_ = true;
+#if defined(OS_ANDROID)
+ if (key.aa_mode_ == NO_AA)
+ vertex_shader_.has_dummy_variables_ = true;
+#endif
+
+ // Initialize fragment program.
+ fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
+ fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
+ }
+
+ void InitializeTileProgram(const ProgramKey& key) {
+ // Initialize vertex program.
+ vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
+ vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
+ vertex_shader_.has_matrix_ = true;
+
+ // Initialize fragment program.
+ if (key.is_opaque_) {
+ DCHECK_EQ(key.aa_mode_, NO_AA);
+ fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_OPAQUE;
+ } else {
+ // TODO(ccameron): This branch shouldn't be needed (this is always
+ // BLEND_MODE_NONE).
+ if (key.aa_mode_ == NO_AA && key.swizzle_mode_ == NO_SWIZZLE)
+ fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
+ fragment_shader_.has_uniform_alpha_ = true;
+ }
+
+ // AA changes the texture coordinate mode (affecting both shaders).
+ if (key.aa_mode_ == USE_AA) {
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
+ vertex_shader_.aa_mode_ = USE_AA;
+ fragment_shader_.has_rgba_fragment_tex_transform_ = true;
+ }
+ }
+
+ void InitializeTextureProgram(const ProgramKey& key) {
+ // Initialize vertex program.
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
+ vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
+ vertex_shader_.has_matrix_ = true;
+ vertex_shader_.has_vertex_opacity_ = true;
+ vertex_shader_.use_uniform_arrays_ = !key.has_tex_clamp_rect_;
+
+ // Initialize fragment program.
+ fragment_shader_.has_varying_alpha_ = true;
+ fragment_shader_.has_background_color_ = key.has_background_color_;
+ fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
+ }
+
+ void InitializeRenderPassProgram(const ProgramKey& key) {
+ // Initialize vertex program.
+ vertex_shader_.has_matrix_ = true;
+ if (key.aa_mode_ == NO_AA) {
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
+ vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
+ vertex_shader_.has_vertex_opacity_ = true;
+ vertex_shader_.use_uniform_arrays_ = true;
+ } else {
+ vertex_shader_.position_source_ =
+ POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
+ vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_TRANSLATED_VEC4;
+ }
+
+ // Initialize fragment program.
+ fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
+ fragment_shader_.has_uniform_alpha_ = true;
+ fragment_shader_.has_color_matrix_ = key.has_color_matrix_;
+ if (key.mask_mode_ == HAS_MASK) {
+ fragment_shader_.ignore_sampler_type_ = true;
+ } else {
+ DCHECK(!key.mask_for_background_);
+ }
+ }
+
+ void InitializeVideoStreamProgram(const ProgramKey& key) {
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
+ vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_MATRIX;
+ vertex_shader_.has_matrix_ = true;
+ DCHECK_EQ(key.sampler_, SAMPLER_TYPE_EXTERNAL_OES);
+ }
+
+ void InitializeYUVVideo(const ProgramKey& key) {
+ vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
+ vertex_shader_.has_matrix_ = true;
+ vertex_shader_.is_ya_uv_ = true;
+
+ fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_YUV_TEXTURES;
+ fragment_shader_.has_uniform_alpha_ = true;
+ fragment_shader_.yuv_alpha_texture_mode_ = key.yuv_alpha_texture_mode_;
+ fragment_shader_.uv_texture_mode_ = key.uv_texture_mode_;
+ }
+
+ void InitializeInternal(ContextProvider* context_provider) {
+ DCHECK(context_provider);
+ DCHECK(!initialized_);
+
+ if (IsContextLost(context_provider->ContextGL()))
+ return;
+
+ if (!ProgramBindingBase::Init(context_provider->ContextGL(),
+ vertex_shader_.GetShaderString(),
+ fragment_shader_.GetShaderString())) {
+ DCHECK(IsContextLost(context_provider->ContextGL()));
+ return;
+ }
+
+ int base_uniform_index = 0;
+ vertex_shader_.Init(context_provider->ContextGL(), program_,
+ &base_uniform_index);
+ fragment_shader_.Init(context_provider->ContextGL(), program_,
+ &base_uniform_index);
+
+ // Link after binding uniforms
+ if (!Link(context_provider->ContextGL())) {
+ DCHECK(IsContextLost(context_provider->ContextGL()));
+ return;
+ }
+
+ initialized_ = true;
+ }
+
+ VertexShader vertex_shader_;
+ FragmentShader fragment_shader_;
+
+ DISALLOW_COPY_AND_ASSIGN(Program);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
diff --git a/chromium/components/viz/service/display/shader.cc b/chromium/components/viz/service/display/shader.cc
new file mode 100644
index 00000000000..108b4441bfa
--- /dev/null
+++ b/chromium/components/viz/service/display/shader.cc
@@ -0,0 +1,1026 @@
+// Copyright 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/viz/service/display/shader.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "components/viz/service/display/static_geometry_binding.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/color_transform.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+template <size_t size>
+std::string StripLambda(const char (&shader)[size]) {
+ // Must contain at least "[]() {}" and trailing null (included in size).
+ static_assert(size >= 8,
+ "String passed to StripLambda must be at least 8 characters");
+ DCHECK_EQ(strncmp("[]() {", shader, 6), 0);
+ DCHECK_EQ(shader[size - 2], '}');
+ return std::string(shader + 6, shader + size - 2);
+}
+
+// Shaders are passed in with lambda syntax, which tricks clang-format into
+// handling them correctly. StipLambda removes this.
+#define SHADER0(Src) StripLambda(#Src)
+
+#define HDR(x) \
+ do { \
+ header += x + std::string("\n"); \
+ } while (0)
+#define SRC(x) \
+ do { \
+ source += std::string(" ") + x + std::string("\n"); \
+ } while (0)
+
+using gpu::gles2::GLES2Interface;
+
+namespace viz {
+
+namespace {
+
+static void GetProgramUniformLocations(GLES2Interface* context,
+ unsigned program,
+ size_t count,
+ const char** uniforms,
+ int* locations,
+ int* base_uniform_index) {
+ for (size_t i = 0; i < count; i++) {
+ locations[i] = (*base_uniform_index)++;
+ context->BindUniformLocationCHROMIUM(program, locations[i], uniforms[i]);
+ }
+}
+
+static std::string SetFragmentTexCoordPrecision(
+ TexCoordPrecision requested_precision,
+ std::string shader_string) {
+ std::string prefix;
+ switch (requested_precision) {
+ case TEX_COORD_PRECISION_HIGH:
+ DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
+ prefix =
+ "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
+ " #define TexCoordPrecision highp\n"
+ "#else\n"
+ " #define TexCoordPrecision mediump\n"
+ "#endif\n";
+ break;
+ case TEX_COORD_PRECISION_MEDIUM:
+ DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
+ prefix = "#define TexCoordPrecision mediump\n";
+ break;
+ case TEX_COORD_PRECISION_NA:
+ DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos);
+ DCHECK_EQ(shader_string.find("texture2D"), std::string::npos);
+ DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ std::string lut_prefix = "#define LutLookup texture2D\n";
+ return prefix + lut_prefix + shader_string;
+}
+
+TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ int x,
+ int y) {
+ if (*highp_threshold_cache == 0) {
+ // Initialize range and precision with minimum spec values for when
+ // GetShaderPrecisionFormat is a test stub.
+ // TODO(brianderson): Implement better stubs of GetShaderPrecisionFormat
+ // everywhere.
+ GLint range[2] = {14, 14};
+ GLint precision = 10;
+ context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
+ range, &precision);
+ *highp_threshold_cache = 1 << precision;
+ }
+
+ int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
+ if (x > highp_threshold || y > highp_threshold)
+ return TEX_COORD_PRECISION_HIGH;
+ return TEX_COORD_PRECISION_MEDIUM;
+}
+
+static std::string SetFragmentSamplerType(SamplerType requested_type,
+ std::string shader_string) {
+ switch (requested_type) {
+ case SAMPLER_TYPE_2D:
+ DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
+ DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
+ return "#define SamplerType sampler2D\n"
+ "#define TextureLookup texture2D\n" +
+ shader_string;
+ case SAMPLER_TYPE_2D_RECT:
+ DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
+ DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
+ return "#extension GL_ARB_texture_rectangle : require\n"
+ "#define SamplerType sampler2DRect\n"
+ "#define TextureLookup texture2DRect\n" +
+ shader_string;
+ case SAMPLER_TYPE_EXTERNAL_OES:
+ DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
+ DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
+ return "#extension GL_OES_EGL_image_external : enable\n"
+ "#extension GL_NV_EGL_stream_consumer_external : enable\n"
+ "#define SamplerType samplerExternalOES\n"
+ "#define TextureLookup texture2D\n" +
+ shader_string;
+ case SAMPLER_TYPE_NA:
+ DCHECK_EQ(shader_string.find("SamplerType"), std::string::npos);
+ DCHECK_EQ(shader_string.find("TextureLookup"), std::string::npos);
+ return shader_string;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return shader_string;
+}
+
+} // namespace
+
+TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ const gfx::Point& max_coordinate) {
+ return TexCoordPrecisionRequired(context, highp_threshold_cache,
+ highp_threshold_min, max_coordinate.x(),
+ max_coordinate.y());
+}
+
+TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ const gfx::Size& max_size) {
+ return TexCoordPrecisionRequired(context, highp_threshold_cache,
+ highp_threshold_min, max_size.width(),
+ max_size.height());
+}
+
+VertexShader::VertexShader() {}
+
+void VertexShader::Init(GLES2Interface* context,
+ unsigned program,
+ int* base_uniform_index) {
+ std::vector<const char*> uniforms;
+ std::vector<int> locations;
+
+ switch (tex_coord_transform_) {
+ case TEX_COORD_TRANSFORM_NONE:
+ break;
+ case TEX_COORD_TRANSFORM_VEC4:
+ case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
+ uniforms.push_back("vertexTexTransform");
+ break;
+ case TEX_COORD_TRANSFORM_MATRIX:
+ uniforms.push_back("texMatrix");
+ break;
+ }
+ if (is_ya_uv_) {
+ uniforms.push_back("yaTexScale");
+ uniforms.push_back("yaTexOffset");
+ uniforms.push_back("uvTexScale");
+ uniforms.push_back("uvTexOffset");
+ }
+ if (has_matrix_)
+ uniforms.push_back("matrix");
+ if (has_vertex_opacity_)
+ uniforms.push_back("opacity");
+ if (aa_mode_ == USE_AA) {
+ uniforms.push_back("viewport");
+ uniforms.push_back("edge");
+ }
+ if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
+ uniforms.push_back("quad");
+
+ locations.resize(uniforms.size());
+
+ GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
+ locations.data(), base_uniform_index);
+
+ size_t index = 0;
+ switch (tex_coord_transform_) {
+ case TEX_COORD_TRANSFORM_NONE:
+ break;
+ case TEX_COORD_TRANSFORM_VEC4:
+ case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
+ vertex_tex_transform_location_ = locations[index++];
+ break;
+ case TEX_COORD_TRANSFORM_MATRIX:
+ tex_matrix_location_ = locations[index++];
+ break;
+ }
+ if (is_ya_uv_) {
+ ya_tex_scale_location_ = locations[index++];
+ ya_tex_offset_location_ = locations[index++];
+ uv_tex_scale_location_ = locations[index++];
+ uv_tex_offset_location_ = locations[index++];
+ }
+ if (has_matrix_)
+ matrix_location_ = locations[index++];
+ if (has_vertex_opacity_)
+ vertex_opacity_location_ = locations[index++];
+ if (aa_mode_ == USE_AA) {
+ viewport_location_ = locations[index++];
+ edge_location_ = locations[index++];
+ }
+ if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
+ quad_location_ = locations[index++];
+}
+
+std::string VertexShader::GetShaderString() const {
+ // We unconditionally use highp in the vertex shader since
+ // we are unlikely to be vertex shader bound when drawing large quads.
+ // Also, some vertex shaders mutate the texture coordinate in such a
+ // way that the effective precision might be lower than expected.
+ std::string header = "#define TexCoordPrecision highp\n";
+ std::string source = "void main() {\n";
+
+ // Define the size of quads for attribute indexed uniform arrays.
+ if (use_uniform_arrays_) {
+ header += base::StringPrintf("#define NUM_QUADS %d\n",
+ StaticGeometryBinding::NUM_QUADS);
+ }
+
+ // Read the index variables.
+ if (use_uniform_arrays_ || has_vertex_opacity_ ||
+ position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM) {
+ HDR("attribute float a_index;");
+ SRC("// Compute indices for uniform arrays.");
+ SRC("int vertex_index = int(a_index);");
+ if (use_uniform_arrays_)
+ SRC("int quad_index = int(a_index * 0.25);");
+ SRC("");
+ }
+
+ // Read the position and compute gl_Position.
+ HDR("attribute TexCoordPrecision vec4 a_position;");
+ SRC("// Compute the position.");
+ switch (position_source_) {
+ case POSITION_SOURCE_ATTRIBUTE:
+ SRC("vec4 pos = a_position;");
+ break;
+ case POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM:
+ HDR("uniform TexCoordPrecision vec2 quad[4];");
+ SRC("vec4 pos = vec4(quad[vertex_index], a_position.z, a_position.w);");
+ break;
+ }
+ if (has_matrix_) {
+ if (use_uniform_arrays_) {
+ HDR("uniform mat4 matrix[NUM_QUADS];");
+ SRC("gl_Position = matrix[quad_index] * pos;");
+ } else {
+ HDR("uniform mat4 matrix;");
+ SRC("gl_Position = matrix * pos;");
+ }
+ } else {
+ SRC("gl_Position = pos;");
+ }
+
+ // Compute the anti-aliasing edge distances.
+ if (aa_mode_ == USE_AA) {
+ HDR("uniform TexCoordPrecision vec3 edge[8];");
+ HDR("uniform vec4 viewport;");
+ HDR("varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.");
+ SRC("// Compute anti-aliasing properties.\n");
+ SRC("vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);");
+ SRC("vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);");
+ SRC("edge_dist[0] = vec4(dot(edge[0], screen_pos),");
+ SRC(" dot(edge[1], screen_pos),");
+ SRC(" dot(edge[2], screen_pos),");
+ SRC(" dot(edge[3], screen_pos)) * gl_Position.w;");
+ SRC("edge_dist[1] = vec4(dot(edge[4], screen_pos),");
+ SRC(" dot(edge[5], screen_pos),");
+ SRC(" dot(edge[6], screen_pos),");
+ SRC(" dot(edge[7], screen_pos)) * gl_Position.w;");
+ }
+
+ // Read, transform, and write texture coordinates.
+ if (tex_coord_source_ != TEX_COORD_SOURCE_NONE) {
+ if (is_ya_uv_) {
+ HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
+ HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
+ } else {
+ HDR("varying TexCoordPrecision vec2 v_texCoord;");
+ }
+
+ SRC("// Compute texture coordinates.");
+ // Read coordinates.
+ switch (tex_coord_source_) {
+ case TEX_COORD_SOURCE_NONE:
+ break;
+ case TEX_COORD_SOURCE_POSITION:
+ SRC("vec2 texCoord = pos.xy;");
+ break;
+ case TEX_COORD_SOURCE_ATTRIBUTE:
+ HDR("attribute TexCoordPrecision vec2 a_texCoord;");
+ SRC("vec2 texCoord = a_texCoord;");
+ break;
+ }
+ // Transform coordinates (except YUV).
+ switch (tex_coord_transform_) {
+ case TEX_COORD_TRANSFORM_NONE:
+ break;
+ case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
+ SRC("texCoord = texCoord + vec2(0.5);");
+ // Fall through...
+ case TEX_COORD_TRANSFORM_VEC4:
+ if (use_uniform_arrays_) {
+ HDR("uniform TexCoordPrecision vec4 vertexTexTransform[NUM_QUADS];");
+ SRC("TexCoordPrecision vec4 texTrans =");
+ SRC(" vertexTexTransform[quad_index];");
+ SRC("texCoord = texCoord * texTrans.zw + texTrans.xy;");
+ } else {
+ HDR("uniform TexCoordPrecision vec4 vertexTexTransform;");
+ SRC("texCoord = texCoord * vertexTexTransform.zw +");
+ SRC(" vertexTexTransform.xy;");
+ }
+ break;
+ case TEX_COORD_TRANSFORM_MATRIX:
+ HDR("uniform TexCoordPrecision mat4 texMatrix;");
+ SRC("texCoord = (texMatrix * vec4(texCoord.xy, 0.0, 1.0)).xy;");
+ break;
+ }
+ // Write the output texture coordinates.
+ if (is_ya_uv_) {
+ HDR("uniform TexCoordPrecision vec2 uvTexOffset;");
+ HDR("uniform TexCoordPrecision vec2 uvTexScale;");
+ HDR("uniform TexCoordPrecision vec2 yaTexOffset;");
+ HDR("uniform TexCoordPrecision vec2 yaTexScale;");
+ SRC("v_yaTexCoord = texCoord * yaTexScale + yaTexOffset;");
+ SRC("v_uvTexCoord = texCoord * uvTexScale + uvTexOffset;");
+ } else {
+ SRC("v_texCoord = texCoord;");
+ }
+ }
+
+ // Write varying vertex opacity.
+ if (has_vertex_opacity_) {
+ HDR("varying float v_alpha;");
+ if (use_uniform_arrays_) {
+ HDR("uniform float opacity[NUM_QUADS * 4];");
+ } else {
+ HDR("uniform float opacity[4];");
+ }
+ SRC("v_alpha = opacity[vertex_index];");
+ }
+
+ // Add cargo-culted dummy variables for Android.
+ if (has_dummy_variables_) {
+ HDR("uniform TexCoordPrecision vec2 dummy_uniform;");
+ HDR("varying TexCoordPrecision vec2 dummy_varying;");
+ SRC("dummy_varying = dummy_uniform;");
+ }
+
+ source += "}\n";
+ return header + source;
+}
+
+FragmentShader::FragmentShader() {}
+
+std::string FragmentShader::GetShaderString() const {
+ TexCoordPrecision precision = tex_coord_precision_;
+ // The AA shader values will use TexCoordPrecision.
+ if (aa_mode_ == USE_AA && precision == TEX_COORD_PRECISION_NA)
+ precision = TEX_COORD_PRECISION_MEDIUM;
+ return SetFragmentTexCoordPrecision(
+ precision, SetFragmentSamplerType(
+ sampler_type_, SetBlendModeFunctions(GetShaderSource())));
+}
+
+void FragmentShader::Init(GLES2Interface* context,
+ unsigned program,
+ int* base_uniform_index) {
+ std::vector<const char*> uniforms;
+ std::vector<int> locations;
+ if (has_blend_mode()) {
+ uniforms.push_back("s_backdropTexture");
+ uniforms.push_back("s_originalBackdropTexture");
+ uniforms.push_back("backdropRect");
+ }
+ if (mask_mode_ != NO_MASK) {
+ uniforms.push_back("s_mask");
+ uniforms.push_back("maskTexCoordScale");
+ uniforms.push_back("maskTexCoordOffset");
+ }
+ if (has_color_matrix_) {
+ uniforms.push_back("colorMatrix");
+ uniforms.push_back("colorOffset");
+ }
+ if (has_uniform_alpha_)
+ uniforms.push_back("alpha");
+ if (has_background_color_)
+ uniforms.push_back("background_color");
+ if (has_tex_clamp_rect_)
+ uniforms.push_back("tex_clamp_rect");
+ switch (input_color_type_) {
+ case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
+ uniforms.push_back("s_texture");
+ if (has_rgba_fragment_tex_transform_)
+ uniforms.push_back("fragmentTexTransform");
+ break;
+ case INPUT_COLOR_SOURCE_YUV_TEXTURES:
+ uniforms.push_back("y_texture");
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
+ uniforms.push_back("uv_texture");
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
+ uniforms.push_back("u_texture");
+ uniforms.push_back("v_texture");
+ }
+ if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
+ uniforms.push_back("a_texture");
+ uniforms.push_back("ya_clamp_rect");
+ uniforms.push_back("uv_clamp_rect");
+ uniforms.push_back("resource_multiplier");
+ uniforms.push_back("resource_offset");
+ break;
+ case INPUT_COLOR_SOURCE_UNIFORM:
+ uniforms.push_back("color");
+ break;
+ }
+ if (color_conversion_mode_ == COLOR_CONVERSION_MODE_LUT) {
+ uniforms.push_back("lut_texture");
+ uniforms.push_back("lut_size");
+ }
+
+ locations.resize(uniforms.size());
+
+ GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
+ locations.data(), base_uniform_index);
+
+ size_t index = 0;
+ if (has_blend_mode()) {
+ backdrop_location_ = locations[index++];
+ original_backdrop_location_ = locations[index++];
+ backdrop_rect_location_ = locations[index++];
+ }
+ if (mask_mode_ != NO_MASK) {
+ mask_sampler_location_ = locations[index++];
+ mask_tex_coord_scale_location_ = locations[index++];
+ mask_tex_coord_offset_location_ = locations[index++];
+ }
+ if (has_color_matrix_) {
+ color_matrix_location_ = locations[index++];
+ color_offset_location_ = locations[index++];
+ }
+ if (has_uniform_alpha_)
+ alpha_location_ = locations[index++];
+ if (has_background_color_)
+ background_color_location_ = locations[index++];
+ if (has_tex_clamp_rect_)
+ tex_clamp_rect_location_ = locations[index++];
+ switch (input_color_type_) {
+ case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
+ sampler_location_ = locations[index++];
+ if (has_rgba_fragment_tex_transform_)
+ fragment_tex_transform_location_ = locations[index++];
+ break;
+ case INPUT_COLOR_SOURCE_YUV_TEXTURES:
+ y_texture_location_ = locations[index++];
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
+ uv_texture_location_ = locations[index++];
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
+ u_texture_location_ = locations[index++];
+ v_texture_location_ = locations[index++];
+ }
+ if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
+ a_texture_location_ = locations[index++];
+ ya_clamp_rect_location_ = locations[index++];
+ uv_clamp_rect_location_ = locations[index++];
+ resource_multiplier_location_ = locations[index++];
+ resource_offset_location_ = locations[index++];
+ break;
+ case INPUT_COLOR_SOURCE_UNIFORM:
+ color_location_ = locations[index++];
+ break;
+ }
+ if (color_conversion_mode_ == COLOR_CONVERSION_MODE_LUT) {
+ lut_texture_location_ = locations[index++];
+ lut_size_location_ = locations[index++];
+ }
+ DCHECK_EQ(index, locations.size());
+}
+
+std::string FragmentShader::SetBlendModeFunctions(
+ const std::string& shader_string) const {
+ if (shader_string.find("ApplyBlendMode") == std::string::npos)
+ return shader_string;
+
+ if (!has_blend_mode()) {
+ return "#define ApplyBlendMode(X, Y) (X)\n" + shader_string;
+ }
+
+ static const std::string kUniforms = SHADER0([]() {
+ uniform sampler2D s_backdropTexture;
+ uniform sampler2D s_originalBackdropTexture;
+ uniform TexCoordPrecision vec4 backdropRect;
+ });
+
+ std::string mixFunction;
+ if (mask_for_background_) {
+ mixFunction = SHADER0([]() {
+ vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
+ vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord);
+ vec4 original_backdrop =
+ texture2D(s_originalBackdropTexture, bgTexCoord);
+ return mix(original_backdrop, backdrop, mask);
+ }
+ });
+ } else {
+ mixFunction = SHADER0([]() {
+ vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
+ return texture2D(s_backdropTexture, bgTexCoord);
+ }
+ });
+ }
+
+ static const std::string kFunctionApplyBlendMode = SHADER0([]() {
+ vec4 GetBackdropColor(float mask) {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord.x /= backdropRect.z;
+ bgTexCoord.y /= backdropRect.w;
+ return MixBackdrop(bgTexCoord, mask);
+ }
+
+ vec4 ApplyBlendMode(vec4 src, float mask) {
+ vec4 dst = GetBackdropColor(mask);
+ return Blend(src, dst);
+ }
+ });
+
+ return "precision mediump float;" + GetHelperFunctions() +
+ GetBlendFunction() + kUniforms + mixFunction +
+ kFunctionApplyBlendMode + shader_string;
+}
+
+std::string FragmentShader::GetHelperFunctions() const {
+ static const std::string kFunctionHardLight = SHADER0([]() {
+ vec3 hardLight(vec4 src, vec4 dst) {
+ vec3 result;
+ result.r =
+ (2.0 * src.r <= src.a)
+ ? (2.0 * src.r * dst.r)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
+ result.g =
+ (2.0 * src.g <= src.a)
+ ? (2.0 * src.g * dst.g)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
+ result.b =
+ (2.0 * src.b <= src.a)
+ ? (2.0 * src.b * dst.b)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
+ result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+ return result;
+ }
+ });
+
+ static const std::string kFunctionColorDodgeComponent = SHADER0([]() {
+ float getColorDodgeComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (0.0 == dstc)
+ return srcc * (1.0 - dsta);
+ float d = srca - srcc;
+ if (0.0 == d)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ d = min(dsta, dstc * srca / d);
+ return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ });
+
+ static const std::string kFunctionColorBurnComponent = SHADER0([]() {
+ float getColorBurnComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (dsta == dstc)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ if (0.0 == srcc)
+ return dstc * (1.0 - srca);
+ float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
+ return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ });
+
+ static const std::string kFunctionSoftLightComponentPosDstAlpha =
+ SHADER0([]() {
+ float getSoftLightComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (2.0 * srcc <= srca) {
+ return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
+ (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
+ } else if (4.0 * dstc <= dsta) {
+ float DSqd = dstc * dstc;
+ float DCub = DSqd * dstc;
+ float DaSqd = dsta * dsta;
+ float DaCub = DaSqd * dsta;
+ return (-DaCub * srcc +
+ DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
+ 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
+ 16.0 * DCub * (srca - 2.0 * srcc)) /
+ DaSqd;
+ } else {
+ return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
+ dstc * (srca - 2.0 * srcc + 1.0) + srcc;
+ }
+ }
+ });
+
+ static const std::string kFunctionLum = SHADER0([]() {
+ float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
+
+ vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
+ float diff = luminance(lumColor - hueSat);
+ vec3 outColor = hueSat + diff;
+ float outLum = luminance(outColor);
+ float minComp = min(min(outColor.r, outColor.g), outColor.b);
+ float maxComp = max(max(outColor.r, outColor.g), outColor.b);
+ if (minComp < 0.0 && outLum != minComp) {
+ outColor =
+ outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
+ (outLum - minComp);
+ }
+ if (maxComp > alpha && maxComp != outLum) {
+ outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) *
+ (alpha - outLum)) /
+ (maxComp - outLum);
+ }
+ return outColor;
+ }
+ });
+
+ static const std::string kFunctionSat = SHADER0([]() {
+ float saturation(vec3 color) {
+ return max(max(color.r, color.g), color.b) -
+ min(min(color.r, color.g), color.b);
+ }
+
+ vec3 set_saturation_helper(float minComp, float midComp, float maxComp,
+ float sat) {
+ if (minComp < maxComp) {
+ vec3 result;
+ result.r = 0.0;
+ result.g = sat * (midComp - minComp) / (maxComp - minComp);
+ result.b = sat;
+ return result;
+ } else {
+ return vec3(0, 0, 0);
+ }
+ }
+
+ vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
+ float sat = saturation(satColor);
+ if (hueLumColor.r <= hueLumColor.g) {
+ if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.rgb = set_saturation_helper(hueLumColor.r, hueLumColor.g,
+ hueLumColor.b, sat);
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.rbg = set_saturation_helper(hueLumColor.r, hueLumColor.b,
+ hueLumColor.g, sat);
+ } else {
+ hueLumColor.brg = set_saturation_helper(hueLumColor.b, hueLumColor.r,
+ hueLumColor.g, sat);
+ }
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.grb = set_saturation_helper(hueLumColor.g, hueLumColor.r,
+ hueLumColor.b, sat);
+ } else if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.gbr = set_saturation_helper(hueLumColor.g, hueLumColor.b,
+ hueLumColor.r, sat);
+ } else {
+ hueLumColor.bgr = set_saturation_helper(hueLumColor.b, hueLumColor.g,
+ hueLumColor.r, sat);
+ }
+ return hueLumColor;
+ }
+ });
+
+ switch (blend_mode_) {
+ case BLEND_MODE_OVERLAY:
+ case BLEND_MODE_HARD_LIGHT:
+ return kFunctionHardLight;
+ case BLEND_MODE_COLOR_DODGE:
+ return kFunctionColorDodgeComponent;
+ case BLEND_MODE_COLOR_BURN:
+ return kFunctionColorBurnComponent;
+ case BLEND_MODE_SOFT_LIGHT:
+ return kFunctionSoftLightComponentPosDstAlpha;
+ case BLEND_MODE_HUE:
+ case BLEND_MODE_SATURATION:
+ return kFunctionLum + kFunctionSat;
+ case BLEND_MODE_COLOR:
+ case BLEND_MODE_LUMINOSITY:
+ return kFunctionLum;
+ default:
+ return std::string();
+ }
+}
+
+std::string FragmentShader::GetBlendFunction() const {
+ return "vec4 Blend(vec4 src, vec4 dst) {"
+ " vec4 result;" +
+ GetBlendFunctionBodyForAlpha() + GetBlendFunctionBodyForRGB() +
+ " return result;"
+ "}";
+}
+
+std::string FragmentShader::GetBlendFunctionBodyForAlpha() const {
+ if (blend_mode_ == BLEND_MODE_DESTINATION_IN)
+ return "result.a = src.a * dst.a;";
+ else
+ return "result.a = src.a + (1.0 - src.a) * dst.a;";
+}
+
+std::string FragmentShader::GetBlendFunctionBodyForRGB() const {
+ switch (blend_mode_) {
+ case BLEND_MODE_NORMAL:
+ return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
+ case BLEND_MODE_DESTINATION_IN:
+ return "result.rgb = dst.rgb * src.a;";
+ case BLEND_MODE_SCREEN:
+ return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
+ case BLEND_MODE_LIGHTEN:
+ return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BLEND_MODE_OVERLAY:
+ return "result.rgb = hardLight(dst, src);";
+ case BLEND_MODE_DARKEN:
+ return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BLEND_MODE_COLOR_DODGE:
+ return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
+ case BLEND_MODE_COLOR_BURN:
+ return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
+ case BLEND_MODE_HARD_LIGHT:
+ return "result.rgb = hardLight(src, dst);";
+ case BLEND_MODE_SOFT_LIGHT:
+ return "if (0.0 == dst.a) {"
+ " result.rgb = src.rgb;"
+ "} else {"
+ " result.r = getSoftLightComponent(src.r, src.a, dst.r, dst.a);"
+ " result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
+ " result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
+ "}";
+ case BLEND_MODE_DIFFERENCE:
+ return "result.rgb = src.rgb + dst.rgb -"
+ " 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
+ case BLEND_MODE_EXCLUSION:
+ return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
+ case BLEND_MODE_MULTIPLY:
+ return "result.rgb = (1.0 - src.a) * dst.rgb +"
+ " (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
+ case BLEND_MODE_HUE:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb ="
+ " set_luminance(set_saturation(src.rgb * dst.a,"
+ " dstSrcAlpha.rgb),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BLEND_MODE_SATURATION:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
+ " src.rgb * dst.a),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BLEND_MODE_COLOR:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(srcDstAlpha.rgb,"
+ " srcDstAlpha.a,"
+ " dst.rgb * src.a);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BLEND_MODE_LUMINOSITY:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(dst.rgb * src.a,"
+ " srcDstAlpha.a,"
+ " srcDstAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BLEND_MODE_NONE:
+ NOTREACHED();
+ }
+ return "result = vec4(1.0, 0.0, 0.0, 1.0);";
+}
+
+std::string FragmentShader::GetShaderSource() const {
+ std::string header = "precision mediump float;\n";
+ std::string source = "void main() {\n";
+
+ // Read the input into vec4 texColor.
+ switch (input_color_type_) {
+ case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
+ if (ignore_sampler_type_)
+ HDR("uniform sampler2D s_texture;");
+ else
+ HDR("uniform SamplerType s_texture;");
+ HDR("varying TexCoordPrecision vec2 v_texCoord;");
+ if (has_rgba_fragment_tex_transform_) {
+ HDR("uniform TexCoordPrecision vec4 fragmentTexTransform;");
+ SRC("// Transformed texture lookup");
+ SRC("TexCoordPrecision vec2 texCoord =");
+ SRC(" clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +");
+ SRC(" fragmentTexTransform.xy;");
+ SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
+ DCHECK(!ignore_sampler_type_);
+ DCHECK(!has_tex_clamp_rect_);
+ } else {
+ SRC("// Texture lookup");
+ if (ignore_sampler_type_) {
+ SRC("vec4 texColor = texture2D(s_texture, v_texCoord);");
+ DCHECK(!has_tex_clamp_rect_);
+ } else {
+ SRC("TexCoordPrecision vec2 texCoord = v_texCoord;");
+ if (has_tex_clamp_rect_) {
+ HDR("uniform vec4 tex_clamp_rect;");
+ SRC("texCoord = max(tex_clamp_rect.xy,");
+ SRC(" min(tex_clamp_rect.zw, texCoord));");
+ }
+ SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
+ }
+ }
+ break;
+ case INPUT_COLOR_SOURCE_YUV_TEXTURES:
+ DCHECK(!has_tex_clamp_rect_);
+ // Compute the clamped texture coordinates for the YA and UV textures.
+ HDR("uniform SamplerType y_texture;");
+ SRC("// YUV texture lookup and conversion to RGB.");
+ SRC("vec2 ya_clamped =");
+ SRC(" max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));");
+ SRC("vec2 uv_clamped =");
+ SRC(" max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));");
+ // Read the Y and UV or U and V textures into |yuv|.
+ SRC("vec4 texColor;");
+ SRC("texColor.w = 1.0;");
+ SRC("texColor.x = TextureLookup(y_texture, ya_clamped).x;");
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) {
+ HDR("uniform SamplerType uv_texture;");
+ SRC("texColor.yz = TextureLookup(uv_texture, uv_clamped).xy;");
+ }
+ if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
+ HDR("uniform SamplerType u_texture;");
+ HDR("uniform SamplerType v_texture;");
+ SRC("texColor.y = TextureLookup(u_texture, uv_clamped).x;");
+ SRC("texColor.z = TextureLookup(v_texture, uv_clamped).x;");
+ }
+ if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
+ HDR("uniform SamplerType a_texture;");
+ HDR("uniform vec4 ya_clamp_rect;");
+ HDR("uniform vec4 uv_clamp_rect;");
+ HDR("uniform float resource_multiplier;");
+ HDR("uniform float resource_offset;");
+ HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
+ HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
+ SRC("texColor.xyz -= vec3(resource_offset);");
+ SRC("texColor.xyz *= resource_multiplier;");
+ break;
+ case INPUT_COLOR_SOURCE_UNIFORM:
+ DCHECK(!ignore_sampler_type_);
+ DCHECK(!has_rgba_fragment_tex_transform_);
+ DCHECK(!has_tex_clamp_rect_);
+ HDR("uniform vec4 color;");
+ SRC("// Uniform color");
+ SRC("vec4 texColor = color;");
+ break;
+ }
+
+ // Apply LUT based color conversion.
+ switch (color_conversion_mode_) {
+ case COLOR_CONVERSION_MODE_LUT:
+ HDR("uniform sampler2D lut_texture;");
+ HDR("uniform float lut_size;");
+ HDR("vec4 LUT(sampler2D sampler, vec3 pos, float size) {");
+ HDR(" pos *= size - 1.0;");
+ HDR(" // Select layer");
+ HDR(" float layer = min(floor(pos.z), size - 2.0);");
+ HDR(" // Compress the xy coordinates so they stay within");
+ HDR(" // [0.5 .. 31.5] / N (assuming a LUT size of 17^3)");
+ HDR(" pos.xy = (pos.xy + vec2(0.5)) / size;");
+ HDR(" pos.y = (pos.y + layer) / size;");
+ HDR(" return mix(LutLookup(sampler, pos.xy),");
+ HDR(" LutLookup(sampler, pos.xy + vec2(0, 1.0 / size)),");
+ HDR(" pos.z - layer);");
+ HDR("}");
+ SRC("texColor.rgb = LUT(lut_texture, texColor.xyz, lut_size).xyz;");
+ break;
+ case COLOR_CONVERSION_MODE_SHADER:
+ header += color_transform_->GetShaderSource();
+ SRC("texColor.rgb = DoColorConversion(texColor.xyz);");
+ break;
+ case COLOR_CONVERSION_MODE_NONE:
+ break;
+ }
+
+ // Apply the color matrix to texColor.
+ if (has_color_matrix_) {
+ HDR("uniform mat4 colorMatrix;");
+ HDR("uniform vec4 colorOffset;");
+ SRC("// Apply color matrix");
+ SRC("float nonZeroAlpha = max(texColor.a, 0.00001);");
+ SRC("texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);");
+ SRC("texColor = colorMatrix * texColor + colorOffset;");
+ SRC("texColor.rgb *= texColor.a;");
+ SRC("texColor = clamp(texColor, 0.0, 1.0);");
+ }
+
+ // Read the mask texture.
+ if (mask_mode_ != NO_MASK) {
+ HDR("uniform SamplerType s_mask;");
+ HDR("uniform vec2 maskTexCoordScale;");
+ HDR("uniform vec2 maskTexCoordOffset;");
+ SRC("// Read the mask");
+ SRC("TexCoordPrecision vec2 maskTexCoord =");
+ SRC(" vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,");
+ SRC(" maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);");
+ SRC("vec4 maskColor = TextureLookup(s_mask, maskTexCoord);");
+ }
+
+ // Compute AA.
+ if (aa_mode_ == USE_AA) {
+ HDR("varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.");
+ SRC("// Compute AA");
+ SRC("vec4 d4 = min(edge_dist[0], edge_dist[1]);");
+ SRC("vec2 d2 = min(d4.xz, d4.yw);");
+ SRC("float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);");
+ }
+
+ // Premultiply by alpha.
+ if (premultiply_alpha_mode_ == NON_PREMULTIPLIED_ALPHA) {
+ SRC("// Premultiply alpha");
+ SRC("texColor.rgb *= texColor.a;");
+ }
+
+ // Apply background texture.
+ if (has_background_color_) {
+ HDR("uniform vec4 background_color;");
+ SRC("// Apply uniform background color blending");
+ SRC("texColor += background_color * (1.0 - texColor.a);");
+ }
+
+ // Apply swizzle.
+ if (swizzle_mode_ == DO_SWIZZLE) {
+ SRC("// Apply swizzle");
+ SRC("texColor = texColor.bgra;\n");
+ }
+
+ // Include header text for alpha.
+ if (has_uniform_alpha_) {
+ HDR("uniform float alpha;");
+ }
+ if (has_varying_alpha_) {
+ HDR("varying float v_alpha;");
+ }
+
+ // Apply uniform alpha, aa, varying alpha, and the mask.
+ if (has_varying_alpha_ || aa_mode_ == USE_AA || has_uniform_alpha_ ||
+ mask_mode_ != NO_MASK) {
+ SRC("// Apply alpha from uniform, varying, aa, and mask.");
+ std::string line = " texColor = texColor";
+ if (has_varying_alpha_)
+ line += " * v_alpha";
+ if (has_uniform_alpha_)
+ line += " * alpha";
+ if (aa_mode_ == USE_AA)
+ line += " * aa";
+ if (mask_mode_ != NO_MASK)
+ line += " * maskColor.a";
+ if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
+ line += " * TextureLookup(a_texture, ya_clamped).x";
+ line += ";\n";
+ source += line;
+ }
+
+ // Write the fragment color.
+ SRC("// Write the fragment color");
+ switch (frag_color_mode_) {
+ case FRAG_COLOR_MODE_DEFAULT:
+ DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
+ SRC("gl_FragColor = texColor;");
+ break;
+ case FRAG_COLOR_MODE_OPAQUE:
+ DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
+ SRC("gl_FragColor = vec4(texColor.rgb, 1.0);");
+ break;
+ case FRAG_COLOR_MODE_APPLY_BLEND_MODE:
+ if (mask_mode_ != NO_MASK)
+ SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);");
+ else
+ SRC("gl_FragColor = ApplyBlendMode(texColor, 0.0);");
+ break;
+ }
+ source += "}\n";
+
+ return header + source;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/shader.h b/chromium/components/viz/service/display/shader.h
new file mode 100644
index 00000000000..f003b853a3d
--- /dev/null
+++ b/chromium/components/viz/service/display/shader.h
@@ -0,0 +1,326 @@
+// Copyright 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_VIZ_SERVICE_DISPLAY_SHADER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_SHADER_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace gfx {
+class ColorTransform;
+class Point;
+class Size;
+} // namespace gfx
+
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
+namespace viz {
+
+enum TexCoordPrecision {
+ TEX_COORD_PRECISION_NA = 0,
+ TEX_COORD_PRECISION_MEDIUM = 1,
+ TEX_COORD_PRECISION_HIGH = 2,
+};
+
+// Texture coordinate sources for the vertex shader.
+enum TexCoordSource {
+ // Vertex shader does not populate a texture coordinate.
+ TEX_COORD_SOURCE_NONE,
+ // Texture coordinate is set to the untransformed position.
+ TEX_COORD_SOURCE_POSITION,
+ // Texture coordinate has its own attribute.
+ TEX_COORD_SOURCE_ATTRIBUTE,
+};
+
+// Texture coordinate transformation modes for the vertex shader.
+enum TexCoordTransform {
+ // Texture coordinates are not transformed.
+ TEX_COORD_TRANSFORM_NONE,
+ // Texture coordinates are transformed by a uniform vec4, scaling by zw and
+ // then translating by xy.
+ TEX_COORD_TRANSFORM_VEC4,
+ // Same as the above, but add vec2(0.5) to the texture coordinate first.
+ TEX_COORD_TRANSFORM_TRANSLATED_VEC4,
+ // Texture coordiantes are transformed by a uniform mat4.
+ TEX_COORD_TRANSFORM_MATRIX,
+};
+
+// Position source for the vertex shader.
+enum PositionSource {
+ // The position is read directly from the position attribute.
+ POSITION_SOURCE_ATTRIBUTE,
+ // The position is read by attribute index into a uniform array for xy, and
+ // getting zw from the attribute.
+ POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM,
+};
+
+enum AAMode {
+ NO_AA = 0,
+ USE_AA = 1,
+};
+
+enum SwizzleMode {
+ NO_SWIZZLE = 0,
+ DO_SWIZZLE = 1,
+};
+
+enum PremultipliedAlphaMode {
+ PREMULTIPLIED_ALPHA = 0,
+ NON_PREMULTIPLIED_ALPHA = 1,
+};
+
+enum SamplerType {
+ SAMPLER_TYPE_NA = 0,
+ SAMPLER_TYPE_2D = 1,
+ SAMPLER_TYPE_2D_RECT = 2,
+ SAMPLER_TYPE_EXTERNAL_OES = 3,
+};
+
+enum BlendMode {
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_DESTINATION_IN,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+ LAST_BLEND_MODE = BLEND_MODE_LUMINOSITY
+};
+
+enum InputColorSource {
+ // This includes RGB and RGBA textures.
+ INPUT_COLOR_SOURCE_RGBA_TEXTURE,
+ // This includes Y and either UV or U-and-V textures.
+ INPUT_COLOR_SOURCE_YUV_TEXTURES,
+ // A solid color specified as a uniform value.
+ INPUT_COLOR_SOURCE_UNIFORM,
+};
+
+enum UVTextureMode {
+ // Shader does not use YUV textures.
+ UV_TEXTURE_MODE_NA,
+ // UV plane is a single texture.
+ UV_TEXTURE_MODE_UV,
+ // U and V planes have separate textures.
+ UV_TEXTURE_MODE_U_V,
+};
+
+enum YUVAlphaTextureMode {
+ YUV_ALPHA_TEXTURE_MODE_NA,
+ YUV_NO_ALPHA_TEXTURE,
+ YUV_HAS_ALPHA_TEXTURE,
+};
+
+enum ColorConversionMode {
+ // No color conversion is performed.
+ COLOR_CONVERSION_MODE_NONE,
+ // Conversion is done directly from input RGB space (or YUV space if
+ // applicable) to output RGB space, via a 3D texture represented as a 2D
+ // texture.
+ COLOR_CONVERSION_MODE_LUT,
+ // Conversion is done analytically in the shader.
+ COLOR_CONVERSION_MODE_SHADER,
+};
+
+// TODO(ccameron): Merge this with BlendMode.
+enum FragColorMode {
+ FRAG_COLOR_MODE_DEFAULT,
+ FRAG_COLOR_MODE_OPAQUE,
+ FRAG_COLOR_MODE_APPLY_BLEND_MODE,
+};
+
+enum MaskMode {
+ NO_MASK = 0,
+ HAS_MASK = 1,
+};
+
+// Note: The highp_threshold_cache must be provided by the caller to make
+// the caching multi-thread/context safe in an easy low-overhead manner.
+// The caller must make sure to clear highp_threshold_cache to 0, so it can be
+// reinitialized, if a new or different context is used.
+VIZ_SERVICE_EXPORT TexCoordPrecision
+TexCoordPrecisionRequired(gpu::gles2::GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ const gfx::Point& max_coordinate);
+
+VIZ_SERVICE_EXPORT TexCoordPrecision
+TexCoordPrecisionRequired(gpu::gles2::GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ const gfx::Size& max_size);
+
+class VIZ_SERVICE_EXPORT VertexShader {
+ public:
+ VertexShader();
+ void Init(gpu::gles2::GLES2Interface* context,
+ unsigned program,
+ int* base_uniform_index);
+ std::string GetShaderString() const;
+
+ protected:
+ friend class Program;
+
+ // Use arrays of uniforms for matrix, texTransform, and opacity.
+ bool use_uniform_arrays_ = false;
+
+ PositionSource position_source_ = POSITION_SOURCE_ATTRIBUTE;
+ TexCoordSource tex_coord_source_ = TEX_COORD_SOURCE_NONE;
+ TexCoordTransform tex_coord_transform_ = TEX_COORD_TRANSFORM_NONE;
+
+ // Used only with TEX_COORD_TRANSFORM_VEC4.
+ int vertex_tex_transform_location_ = -1;
+
+ // Used only with TEX_COORD_TRANSFORM_MATRIX.
+ int tex_matrix_location_ = -1;
+
+ // Uniforms for YUV textures.
+ bool is_ya_uv_ = false;
+ int ya_tex_scale_location_ = -1;
+ int ya_tex_offset_location_ = -1;
+ int uv_tex_scale_location_ = -1;
+ int uv_tex_offset_location_ = -1;
+
+ // Matrix to transform the position.
+ bool has_matrix_ = false;
+ int matrix_location_ = -1;
+
+ // Used only with POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM.
+ int quad_location_ = -1;
+
+ // Extra dummy variables to work around bugs on Android.
+ // TODO(ccameron): This is likley unneeded cargo-culting.
+ // http://crbug.com/240602
+ bool has_dummy_variables_ = false;
+
+ bool has_vertex_opacity_ = false;
+ int vertex_opacity_location_ = -1;
+
+ AAMode aa_mode_ = NO_AA;
+ int viewport_location_ = -1;
+ int edge_location_ = -1;
+};
+
+class VIZ_SERVICE_EXPORT FragmentShader {
+ public:
+ virtual void Init(gpu::gles2::GLES2Interface* context,
+ unsigned program,
+ int* base_uniform_index);
+ std::string GetShaderString() const;
+
+ protected:
+ FragmentShader();
+ virtual std::string GetShaderSource() const;
+ bool has_blend_mode() const { return blend_mode_ != BLEND_MODE_NONE; }
+
+ std::string SetBlendModeFunctions(const std::string& shader_string) const;
+
+ // Settings that are modified by sub-classes.
+ AAMode aa_mode_ = NO_AA;
+ bool has_varying_alpha_ = false;
+ SwizzleMode swizzle_mode_ = NO_SWIZZLE;
+ PremultipliedAlphaMode premultiply_alpha_mode_ = PREMULTIPLIED_ALPHA;
+ FragColorMode frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
+ InputColorSource input_color_type_ = INPUT_COLOR_SOURCE_RGBA_TEXTURE;
+
+ // Used only if |blend_mode_| is not BLEND_MODE_NONE.
+ int backdrop_location_ = -1;
+ int original_backdrop_location_ = -1;
+ int backdrop_rect_location_ = -1;
+
+ // Used only if |input_color_type_| is INPUT_COLOR_SOURCE_RGBA_TEXTURE.
+ bool has_rgba_fragment_tex_transform_ = false;
+ int sampler_location_ = -1;
+ int fragment_tex_transform_location_ = -1;
+
+ // Always use sampler2D and texture2D for the RGBA texture, regardless of the
+ // specified SamplerType.
+ // TODO(ccameron): Change GLRenderer to always specify the correct
+ // SamplerType.
+ bool ignore_sampler_type_ = false;
+
+ // Used only if |input_color_type_| is INPUT_COLOR_SOURCE_UNIFORM.
+ int color_location_ = -1;
+
+ MaskMode mask_mode_ = NO_MASK;
+ int mask_sampler_location_ = -1;
+ int mask_tex_coord_scale_location_ = -1;
+ int mask_tex_coord_offset_location_ = -1;
+
+ bool has_color_matrix_ = false;
+ int color_matrix_location_ = -1;
+ int color_offset_location_ = -1;
+
+ bool has_uniform_alpha_ = false;
+ int alpha_location_ = -1;
+
+ bool has_background_color_ = false;
+ int background_color_location_ = -1;
+
+ bool has_tex_clamp_rect_ = false;
+ int tex_clamp_rect_location_ = -1;
+
+ TexCoordPrecision tex_coord_precision_ = TEX_COORD_PRECISION_NA;
+ SamplerType sampler_type_ = SAMPLER_TYPE_NA;
+
+ BlendMode blend_mode_ = BLEND_MODE_NONE;
+ bool mask_for_background_ = false;
+
+ // YUV-only parameters.
+ YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_ALPHA_TEXTURE_MODE_NA;
+ UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_UV;
+
+ ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
+ const gfx::ColorTransform* color_transform_ = nullptr;
+
+ // YUV uniform locations.
+ int y_texture_location_ = -1;
+ int u_texture_location_ = -1;
+ int v_texture_location_ = -1;
+ int uv_texture_location_ = -1;
+ int a_texture_location_ = -1;
+ int ya_clamp_rect_location_ = -1;
+ int uv_clamp_rect_location_ = -1;
+
+ // The resource offset and multiplier to adjust for bit depth.
+ int resource_multiplier_location_ = -1;
+ int resource_offset_location_ = -1;
+
+ // LUT YUV to color-converted RGB.
+ int lut_texture_location_ = -1;
+ int lut_size_location_ = -1;
+
+ private:
+ friend class Program;
+
+ std::string GetHelperFunctions() const;
+ std::string GetBlendFunction() const;
+ std::string GetBlendFunctionBodyForAlpha() const;
+ std::string GetBlendFunctionBodyForRGB() const;
+
+ DISALLOW_COPY_AND_ASSIGN(FragmentShader);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SHADER_H_
diff --git a/chromium/components/viz/service/display/shader_unittest.cc b/chromium/components/viz/service/display/shader_unittest.cc
new file mode 100644
index 00000000000..02c9382f141
--- /dev/null
+++ b/chromium/components/viz/service/display/shader_unittest.cc
@@ -0,0 +1,59 @@
+// 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/viz/service/display/shader.h"
+
+#include "cc/test/test_gles2_interface.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+TEST(ShaderTest, HighpThresholds) {
+ // The test context always uses a mediump precision of 10 bits which
+ // corresponds to a native highp threshold of 2^10 = 1024
+ std::unique_ptr<cc::TestWebGraphicsContext3D> test_context =
+ cc::TestWebGraphicsContext3D::Create();
+ cc::TestGLES2Interface test_gl;
+ test_gl.set_test_context(test_context.get());
+
+ int threshold_cache = 0;
+ int threshold_min;
+ gfx::Point closePoint(512, 512);
+ gfx::Size smallSize(512, 512);
+ gfx::Point farPoint(2560, 2560);
+ gfx::Size bigSize(2560, 2560);
+
+ threshold_min = 0;
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ bigSize));
+
+ threshold_min = 3000;
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ bigSize));
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
new file mode 100644
index 00000000000..4ab0fc9df34
--- /dev/null
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -0,0 +1,704 @@
+// Copyright 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/viz/service/display/skia_renderer.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/base/math_util.h"
+#include "cc/base/render_surface_filters.h"
+#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_frame.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/picture_draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
+#include "cc/resources/scoped_resource.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "skia/ext/opacity_filter_canvas.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkOverdrawCanvas.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkPoint.h"
+#include "third_party/skia/include/core/SkShader.h"
+#include "third_party/skia/include/effects/SkLayerRasterizer.h"
+#include "third_party/skia/include/effects/SkOverdrawColorFilter.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/transform.h"
+
+namespace viz {
+namespace {
+
+static inline bool IsScalarNearlyInteger(SkScalar scalar) {
+ return SkScalarNearlyZero(scalar - SkScalarRoundToScalar(scalar));
+}
+
+bool IsScaleAndIntegerTranslate(const SkMatrix& matrix) {
+ return IsScalarNearlyInteger(matrix[SkMatrix::kMTransX]) &&
+ IsScalarNearlyInteger(matrix[SkMatrix::kMTransY]) &&
+ SkScalarNearlyZero(matrix[SkMatrix::kMSkewX]) &&
+ SkScalarNearlyZero(matrix[SkMatrix::kMSkewY]) &&
+ SkScalarNearlyZero(matrix[SkMatrix::kMPersp0]) &&
+ SkScalarNearlyZero(matrix[SkMatrix::kMPersp1]) &&
+ SkScalarNearlyZero(matrix[SkMatrix::kMPersp2] - 1.0f);
+}
+
+} // anonymous namespace
+
+SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider)
+ : DirectRenderer(settings, output_surface, resource_provider) {
+ const auto& context_caps =
+ output_surface_->context_provider()->ContextCapabilities();
+ use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
+}
+
+SkiaRenderer::~SkiaRenderer() {}
+
+bool SkiaRenderer::CanPartialSwap() {
+ if (use_swap_with_bounds_)
+ return false;
+ auto* context_provider = output_surface_->context_provider();
+ return context_provider->ContextCapabilities().post_sub_buffer;
+}
+
+ResourceFormat SkiaRenderer::BackbufferFormat() const {
+ // From GL Renderer.
+ if (current_frame()->current_render_pass->color_space.IsHDR() &&
+ resource_provider_->IsRenderBufferFormatSupported(RGBA_F16)) {
+ return RGBA_F16;
+ }
+ return resource_provider_->best_texture_format();
+}
+
+void SkiaRenderer::BeginDrawingFrame() {
+ TRACE_EVENT0("cc", "SkiaRenderer::BeginDrawingFrame");
+ // Copied from GLRenderer.
+ bool use_sync_query_ = false;
+ scoped_refptr<cc::ResourceProvider::Fence> read_lock_fence;
+ // TODO(weiliangc): Implement use_sync_query_. (crbug.com/644851)
+ if (use_sync_query_) {
+ NOTIMPLEMENTED();
+ } else {
+ read_lock_fence =
+ make_scoped_refptr(new cc::ResourceProvider::SynchronousFence(
+ output_surface_->context_provider()->ContextGL()));
+ }
+ resource_provider_->SetReadLockFence(read_lock_fence.get());
+
+ // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the frame,
+ // so that drawing can proceed without GL context switching interruptions.
+ cc::ResourceProvider* resource_provider = resource_provider_;
+ for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
+ for (auto* quad : pass->quad_list) {
+ for (ResourceId resource_id : quad->resources)
+ resource_provider->WaitSyncToken(resource_id);
+ }
+ }
+}
+
+void SkiaRenderer::FinishDrawingFrame() {
+ TRACE_EVENT0("cc", "SkiaRenderer::FinishDrawingFrame");
+ if (settings_->show_overdraw_feedback) {
+ sk_sp<SkImage> image = overdraw_surface_->makeImageSnapshot();
+ SkPaint paint;
+ static const SkPMColor colors[SkOverdrawColorFilter::kNumColors] = {
+ 0x00000000, 0x00000000, 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000,
+ };
+ sk_sp<SkColorFilter> color_filter = SkOverdrawColorFilter::Make(colors);
+ paint.setColorFilter(color_filter);
+ root_surface_->getCanvas()->drawImage(image.get(), 0, 0, &paint);
+ root_surface_->getCanvas()->flush();
+ }
+ current_framebuffer_surface_lock_ = nullptr;
+ current_framebuffer_lock_ = nullptr;
+ current_canvas_ = nullptr;
+
+ swap_buffer_rect_ = current_frame()->root_damage_rect;
+
+ if (use_swap_with_bounds_)
+ swap_content_bounds_ = current_frame()->root_content_bounds;
+}
+
+void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
+ DCHECK(visible_);
+ TRACE_EVENT0("cc,benchmark", "SkiaRenderer::SwapBuffers");
+ cc::OutputSurfaceFrame output_frame;
+ output_frame.latency_info = std::move(latency_info);
+ output_frame.size = surface_size_for_swap_buffers();
+ if (use_swap_with_bounds_) {
+ output_frame.content_bounds = std::move(swap_content_bounds_);
+ } else if (use_partial_swap_) {
+ swap_buffer_rect_.Intersect(gfx::Rect(surface_size_for_swap_buffers()));
+ output_frame.sub_buffer_rect = swap_buffer_rect_;
+ } else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) {
+ output_frame.sub_buffer_rect = swap_buffer_rect_;
+ }
+ output_surface_->SwapBuffers(std::move(output_frame));
+
+ swap_buffer_rect_ = gfx::Rect();
+}
+
+bool SkiaRenderer::FlippedFramebuffer() const {
+ // TODO(weiliangc): Make sure flipped correctly for Windows.
+ // (crbug.com/644851)
+ return false;
+}
+
+void SkiaRenderer::EnsureScissorTestEnabled() {
+ is_scissor_enabled_ = true;
+}
+
+void SkiaRenderer::EnsureScissorTestDisabled() {
+ is_scissor_enabled_ = false;
+}
+
+void SkiaRenderer::BindFramebufferToOutputSurface() {
+ DCHECK(!output_surface_->HasExternalStencilTest());
+ current_framebuffer_lock_ = nullptr;
+
+ // TODO(weiliangc): Set up correct can_use_lcd_text and
+ // use_distance_field_text for SkSurfaceProps flags. How to setup is in
+ // ResourceProvider. (crbug.com/644851)
+
+ GrContext* gr_context = output_surface_->context_provider()->GrContext();
+ if (!root_canvas_ || root_canvas_->getGrContext() != gr_context ||
+ gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) !=
+ current_frame()->device_viewport_size) {
+ // Either no SkSurface setup yet, or new GrContext, need to create new
+ // surface.
+ GrGLFramebufferInfo framebuffer_info;
+ framebuffer_info.fFBOID = 0;
+ GrBackendRenderTarget render_target(
+ current_frame()->device_viewport_size.width(),
+ current_frame()->device_viewport_size.height(), 0, 8,
+ kRGBA_8888_GrPixelConfig, framebuffer_info);
+
+ // This is for use_distance_field_text false, and can_use_lcd_text true.
+ // LegacyFontHost will get LCD text and skia figures out what type to use.
+ SkSurfaceProps surface_props =
+ SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+
+ root_surface_ = SkSurface::MakeFromBackendRenderTarget(
+ gr_context, render_target, kBottomLeft_GrSurfaceOrigin, nullptr,
+ &surface_props);
+ }
+
+ root_canvas_ = root_surface_->getCanvas();
+ if (settings_->show_overdraw_feedback) {
+ const gfx::Size size(root_surface_->width(), root_surface_->height());
+ overdraw_surface_ = root_surface_->makeSurface(
+ SkImageInfo::MakeA8(size.width(), size.height()));
+ nway_canvas_ = std::make_unique<SkNWayCanvas>(size.width(), size.height());
+ overdraw_canvas_ =
+ std::make_unique<SkOverdrawCanvas>(overdraw_surface_->getCanvas());
+ nway_canvas_->addCanvas(overdraw_canvas_.get());
+ nway_canvas_->addCanvas(root_canvas_);
+ current_canvas_ = nway_canvas_.get();
+ } else {
+ current_canvas_ = root_canvas_;
+ }
+}
+
+bool SkiaRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
+ DCHECK(texture->id());
+
+ // Explicitly release lock, otherwise we can crash when try to lock
+ // same texture again.
+ current_framebuffer_surface_lock_ = nullptr;
+ current_framebuffer_lock_ = nullptr;
+ current_framebuffer_lock_ =
+ base::WrapUnique(new cc::ResourceProvider::ScopedWriteLockGL(
+ resource_provider_, texture->id()));
+
+ current_framebuffer_surface_lock_ =
+ base::WrapUnique(new cc::ResourceProvider::ScopedSkSurface(
+ output_surface_->context_provider()->GrContext(),
+ current_framebuffer_lock_->GetTexture(),
+ current_framebuffer_lock_->target(),
+ current_framebuffer_lock_->size(),
+ current_framebuffer_lock_->format(), false, true, 0));
+
+ current_canvas_ = current_framebuffer_surface_lock_->surface()->getCanvas();
+ return true;
+}
+
+void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
+ is_scissor_enabled_ = true;
+ scissor_rect_ = scissor_rect;
+}
+
+void SkiaRenderer::SetClipRect(const gfx::Rect& rect) {
+ if (!current_canvas_)
+ return;
+ // Skia applies the current matrix to clip rects so we reset it temporary.
+ SkMatrix current_matrix = current_canvas_->getTotalMatrix();
+ current_canvas_->resetMatrix();
+ // SetClipRect is assumed to be applied temporarily, on an
+ // otherwise-unclipped canvas.
+ DCHECK_EQ(current_canvas_->getDeviceClipBounds().width(),
+ current_canvas_->imageInfo().width());
+ DCHECK_EQ(current_canvas_->getDeviceClipBounds().height(),
+ current_canvas_->imageInfo().height());
+ current_canvas_->clipRect(gfx::RectToSkRect(rect));
+ current_canvas_->setMatrix(current_matrix);
+}
+
+void SkiaRenderer::ClearCanvas(SkColor color) {
+ if (!current_canvas_)
+ return;
+
+ if (is_scissor_enabled_) {
+ // The same paint used by SkCanvas::clear, but applied to the scissor rect.
+ SkPaint clear_paint;
+ clear_paint.setColor(color);
+ clear_paint.setBlendMode(SkBlendMode::kSrc);
+ current_canvas_->drawRect(gfx::RectToSkRect(scissor_rect_), clear_paint);
+ } else {
+ current_canvas_->clear(color);
+ }
+}
+
+void SkiaRenderer::ClearFramebuffer() {
+ if (current_frame()->current_render_pass->has_transparent_background) {
+ ClearCanvas(SkColorSetARGB(0, 0, 0, 0));
+ } else {
+#ifndef NDEBUG
+ // On DEBUG builds, opaque render passes are cleared to blue
+ // to easily see regions that were not drawn on the screen.
+ ClearCanvas(SkColorSetARGB(255, 0, 0, 255));
+#endif
+ }
+}
+
+void SkiaRenderer::PrepareSurfaceForPass(
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ ClearFramebuffer();
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer();
+ break;
+ }
+}
+
+bool SkiaRenderer::IsSoftwareResource(ResourceId resource_id) const {
+ switch (resource_provider_->GetResourceType(resource_id)) {
+ case cc::ResourceProvider::RESOURCE_TYPE_GPU_MEMORY_BUFFER:
+ case cc::ResourceProvider::RESOURCE_TYPE_GL_TEXTURE:
+ return true;
+ case cc::ResourceProvider::RESOURCE_TYPE_BITMAP:
+ return false;
+ }
+
+ LOG(FATAL) << "Invalid resource type.";
+ return false;
+}
+
+void SkiaRenderer::DoDrawQuad(const cc::DrawQuad* quad,
+ const gfx::QuadF* draw_region) {
+ if (!current_canvas_)
+ return;
+ if (draw_region) {
+ current_canvas_->save();
+ }
+
+ TRACE_EVENT0("cc", "SkiaRenderer::DoDrawQuad");
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect));
+ gfx::Transform contents_device_transform =
+ current_frame()->window_matrix * current_frame()->projection_matrix *
+ quad_rect_matrix;
+ contents_device_transform.FlattenTo2d();
+ SkMatrix sk_device_matrix;
+ gfx::TransformToFlattenedSkMatrix(contents_device_transform,
+ &sk_device_matrix);
+ current_canvas_->setMatrix(sk_device_matrix);
+
+ current_paint_.reset();
+ if (settings_->force_antialiasing ||
+ !IsScaleAndIntegerTranslate(sk_device_matrix)) {
+ // TODO(danakj): Until we can enable AA only on exterior edges of the
+ // layer, disable AA if any interior edges are present. crbug.com/248175
+ bool all_four_edges_are_exterior =
+ quad->IsTopEdge() && quad->IsLeftEdge() && quad->IsBottomEdge() &&
+ quad->IsRightEdge();
+ if (settings_->allow_antialiasing &&
+ (settings_->force_antialiasing || all_four_edges_are_exterior))
+ current_paint_.setAntiAlias(true);
+ current_paint_.setFilterQuality(kLow_SkFilterQuality);
+ }
+
+ if (quad->ShouldDrawWithBlending() ||
+ quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver) {
+ current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
+ current_paint_.setBlendMode(
+ static_cast<SkBlendMode>(quad->shared_quad_state->blend_mode));
+ } else {
+ current_paint_.setBlendMode(SkBlendMode::kSrc);
+ }
+
+ if (draw_region) {
+ gfx::QuadF local_draw_region(*draw_region);
+ SkPath draw_region_clip_path;
+ local_draw_region -=
+ gfx::Vector2dF(quad->visible_rect.x(), quad->visible_rect.y());
+ local_draw_region.Scale(1.0f / quad->visible_rect.width(),
+ 1.0f / quad->visible_rect.height());
+ local_draw_region -= gfx::Vector2dF(0.5f, 0.5f);
+
+ SkPoint clip_points[4];
+ QuadFToSkPoints(local_draw_region, clip_points);
+ draw_region_clip_path.addPoly(clip_points, 4, true);
+
+ current_canvas_->clipPath(draw_region_clip_path);
+ }
+
+ switch (quad->material) {
+ case cc::DrawQuad::DEBUG_BORDER:
+ DrawDebugBorderQuad(cc::DebugBorderDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::PICTURE_CONTENT:
+ DrawPictureQuad(cc::PictureDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::RENDER_PASS:
+ DrawRenderPassQuad(cc::RenderPassDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::SOLID_COLOR:
+ DrawSolidColorQuad(cc::SolidColorDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::TEXTURE_CONTENT:
+ DrawTextureQuad(cc::TextureDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::TILED_CONTENT:
+ DrawTileQuad(cc::TileDrawQuad::MaterialCast(quad));
+ break;
+ case cc::DrawQuad::SURFACE_CONTENT:
+ // Surface content should be fully resolved to other quad types before
+ // reaching a direct renderer.
+ NOTREACHED();
+ break;
+ case cc::DrawQuad::INVALID:
+ case cc::DrawQuad::YUV_VIDEO_CONTENT:
+ case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+ DrawUnsupportedQuad(quad);
+ NOTREACHED();
+ break;
+ }
+
+ current_canvas_->resetMatrix();
+ if (draw_region) {
+ current_canvas_->restore();
+ }
+}
+
+void SkiaRenderer::DrawDebugBorderQuad(const cc::DebugBorderDrawQuad* quad) {
+ // We need to apply the matrix manually to have pixel-sized stroke width.
+ SkPoint vertices[4];
+ gfx::RectFToSkRect(QuadVertexRect()).toQuad(vertices);
+ SkPoint transformed_vertices[4];
+ current_canvas_->getTotalMatrix().mapPoints(transformed_vertices, vertices,
+ 4);
+ current_canvas_->resetMatrix();
+
+ current_paint_.setColor(quad->color);
+ current_paint_.setAlpha(quad->shared_quad_state->opacity *
+ SkColorGetA(quad->color));
+ current_paint_.setStyle(SkPaint::kStroke_Style);
+ current_paint_.setStrokeWidth(quad->width);
+ current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode, 4,
+ transformed_vertices, current_paint_);
+}
+
+void SkiaRenderer::DrawPictureQuad(const cc::PictureDrawQuad* quad) {
+ SkMatrix content_matrix;
+ content_matrix.setRectToRect(gfx::RectFToSkRect(quad->tex_coord_rect),
+ gfx::RectFToSkRect(QuadVertexRect()),
+ SkMatrix::kFill_ScaleToFit);
+ current_canvas_->concat(content_matrix);
+
+ const bool needs_transparency =
+ SkScalarRoundToInt(quad->shared_quad_state->opacity * 255) < 255;
+ const bool disable_image_filtering =
+ disable_picture_quad_image_filtering_ || quad->nearest_neighbor;
+
+ TRACE_EVENT0("cc", "SkiaRenderer::DrawPictureQuad");
+
+ // TODO(ccameron): Determin a color space strategy for software rendering.
+ gfx::ColorSpace canvas_color_space;
+ if (settings_->enable_color_correct_rendering)
+ canvas_color_space = gfx::ColorSpace::CreateSRGB();
+
+ cc::RasterSource::PlaybackSettings playback_settings;
+ playback_settings.playback_to_shared_canvas = true;
+ if (needs_transparency || disable_image_filtering) {
+ // TODO(aelias): This isn't correct in all cases. We should detect these
+ // cases and fall back to a persistent bitmap backing
+ // (http://crbug.com/280374).
+ // TODO(vmpstr): Fold this canvas into playback and have raster source
+ // accept a set of settings on playback that will determine which canvas to
+ // apply. (http://crbug.com/594679)
+ skia::OpacityFilterCanvas filtered_canvas(current_canvas_,
+ quad->shared_quad_state->opacity,
+ disable_image_filtering);
+ quad->raster_source->PlaybackToCanvas(
+ &filtered_canvas, canvas_color_space, quad->content_rect,
+ quad->content_rect,
+ gfx::AxisTransform2d(quad->contents_scale, gfx::Vector2dF()),
+ playback_settings);
+ } else {
+ quad->raster_source->PlaybackToCanvas(
+ current_canvas_, canvas_color_space, quad->content_rect,
+ quad->content_rect,
+ gfx::AxisTransform2d(quad->contents_scale, gfx::Vector2dF()),
+ playback_settings);
+ }
+}
+
+void SkiaRenderer::DrawSolidColorQuad(const cc::SolidColorDrawQuad* quad) {
+ gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
+ QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
+ current_paint_.setColor(quad->color);
+ current_paint_.setAlpha(quad->shared_quad_state->opacity *
+ SkColorGetA(quad->color));
+ current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
+ current_paint_);
+}
+
+void SkiaRenderer::DrawTextureQuad(const cc::TextureDrawQuad* quad) {
+ if (!IsSoftwareResource(quad->resource_id())) {
+ DrawUnsupportedQuad(quad);
+ return;
+ }
+
+ // TODO(skaslev): Add support for non-premultiplied alpha.
+ cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
+ quad->resource_id());
+ const SkImage* image = lock.sk_image();
+ if (!image)
+ return;
+ gfx::RectF uv_rect = gfx::ScaleRect(
+ gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right),
+ image->width(), image->height());
+ gfx::RectF visible_uv_rect = cc::MathUtil::ScaleRectProportional(
+ uv_rect, gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
+ SkRect sk_uv_rect = gfx::RectFToSkRect(visible_uv_rect);
+ gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
+ QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
+ SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect);
+
+ if (quad->y_flipped)
+ current_canvas_->scale(1, -1);
+
+ bool blend_background =
+ quad->background_color != SK_ColorTRANSPARENT && !image->isOpaque();
+ bool needs_layer = blend_background && (current_paint_.getAlpha() != 0xFF);
+ if (needs_layer) {
+ current_canvas_->saveLayerAlpha(&quad_rect, current_paint_.getAlpha());
+ current_paint_.setAlpha(0xFF);
+ }
+ if (blend_background) {
+ SkPaint background_paint;
+ background_paint.setColor(quad->background_color);
+ current_canvas_->drawRect(quad_rect, background_paint);
+ }
+ current_paint_.setFilterQuality(
+ quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
+ current_canvas_->drawImageRect(image, sk_uv_rect, quad_rect, &current_paint_);
+ if (needs_layer)
+ current_canvas_->restore();
+}
+
+void SkiaRenderer::DrawTileQuad(const cc::TileDrawQuad* quad) {
+ // |resource_provider_| can be NULL in resourceless software draws, which
+ // should never produce tile quads in the first place.
+ DCHECK(resource_provider_);
+ DCHECK(IsSoftwareResource(quad->resource_id()));
+ cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
+ quad->resource_id());
+ if (!lock.sk_image())
+ return;
+ gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
+ quad->tex_coord_rect, gfx::RectF(quad->rect),
+ gfx::RectF(quad->visible_rect));
+ gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
+ QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
+
+ SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
+ current_paint_.setFilterQuality(
+ quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
+ current_canvas_->drawImageRect(lock.sk_image(), uv_rect,
+ gfx::RectFToSkRect(visible_quad_vertex_rect),
+ &current_paint_);
+}
+
+void SkiaRenderer::DrawRenderPassQuad(const cc::RenderPassDrawQuad* quad) {
+ cc::ScopedResource* content_texture =
+ render_pass_textures_[quad->render_pass_id].get();
+ DCHECK(content_texture);
+ DCHECK(content_texture->id());
+ DCHECK(IsSoftwareResource(content_texture->id()));
+ cc::DisplayResourceProvider::ScopedReadLockSkImage lock(
+ resource_provider_, content_texture->id());
+ if (!lock.sk_image())
+ return;
+
+ SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
+ SkRect dest_visible_rect =
+ gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
+ QuadVertexRect(), gfx::RectF(quad->rect),
+ gfx::RectF(quad->visible_rect)));
+ SkRect content_rect = RectFToSkRect(quad->tex_coord_rect);
+
+ const SkImage* content = lock.sk_image();
+
+ current_canvas_->drawImageRect(lock.sk_image(), content_rect,
+ dest_visible_rect, &current_paint_);
+
+ const cc::FilterOperations* filters = FiltersForPass(quad->render_pass_id);
+
+ // TODO(weiliangc): Implement filters. (crbug.com/644851)
+ if (filters) {
+ NOTIMPLEMENTED();
+ }
+
+ SkMatrix content_mat;
+ content_mat.setRectToRect(content_rect, dest_rect,
+ SkMatrix::kFill_ScaleToFit);
+
+ sk_sp<SkShader> shader;
+ shader = content->makeShader(SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode, &content_mat);
+
+ // TODO(weiliangc): Implement mask. (crbug.com/644851)
+ if (quad->mask_resource_id()) {
+ NOTIMPLEMENTED();
+ }
+
+ // TODO(weiliangc): If we have a background filter shader, render its results
+ // first. (crbug.com/644851)
+
+ current_paint_.setShader(std::move(shader));
+ current_canvas_->drawRect(dest_visible_rect, current_paint_);
+}
+
+void SkiaRenderer::DrawUnsupportedQuad(const cc::DrawQuad* quad) {
+ // TODO(weiliangc): Make sure unsupported quads work. (crbug.com/644851)
+ NOTIMPLEMENTED();
+#ifdef NDEBUG
+ current_paint_.setColor(SK_ColorWHITE);
+#else
+ current_paint_.setColor(SK_ColorMAGENTA);
+#endif
+ current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
+ current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()),
+ current_paint_);
+}
+
+void SkiaRenderer::CopyCurrentRenderPassToBitmap(
+ std::unique_ptr<CopyOutputRequest> request) {
+ // TODO(weiliangc): Make copy request work. (crbug.com/644851)
+ NOTIMPLEMENTED();
+}
+
+void SkiaRenderer::SetEnableDCLayers(bool enable) {
+ // TODO(crbug.com/678800): Part of surport overlay on Windows.
+ NOTIMPLEMENTED();
+}
+
+void SkiaRenderer::DidChangeVisibility() {
+ if (visible_)
+ output_surface_->EnsureBackbuffer();
+ else
+ output_surface_->DiscardBackbuffer();
+}
+
+void SkiaRenderer::FinishDrawingQuadList() {
+ current_canvas_->flush();
+}
+
+bool SkiaRenderer::ShouldApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations* background_filters) const {
+ if (!background_filters)
+ return false;
+ DCHECK(!background_filters->IsEmpty());
+
+ // TODO(hendrikw): Look into allowing background filters to see pixels from
+ // other render targets. See crbug.com/314867.
+
+ return true;
+}
+
+// If non-null, auto_bounds will be filled with the automatically-computed
+// destination bounds. If null, the output will be the same size as the
+// input bitmap.
+sk_sp<SkImage> SkiaRenderer::ApplyImageFilter(
+ SkImageFilter* filter,
+ const cc::RenderPassDrawQuad* quad,
+ const SkBitmap& to_filter,
+ SkIRect* auto_bounds) const {
+ // TODO(weiliangc): Implement image filter. (crbug.com/644851)
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+SkBitmap SkiaRenderer::GetBackdropBitmap(const gfx::Rect& bounding_rect) const {
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(),
+ bounding_rect.height()));
+ if (!current_canvas_->readPixels(bitmap, bounding_rect.x(),
+ bounding_rect.y()))
+ bitmap.reset();
+ return bitmap;
+}
+
+gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad(
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::Transform& contents_device_transform,
+ const cc::FilterOperations* background_filters) const {
+ DCHECK(ShouldApplyBackgroundFilters(quad, background_filters));
+ gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
+ contents_device_transform, QuadVertexRect()));
+
+ SkMatrix matrix;
+ matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
+ backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix);
+
+ backdrop_rect.Intersect(MoveFromDrawToWindowSpace(
+ current_frame()->current_render_pass->output_rect));
+
+ return backdrop_rect;
+}
+
+sk_sp<SkShader> SkiaRenderer::GetBackgroundFilterShader(
+ const cc::RenderPassDrawQuad* quad,
+ SkShader::TileMode content_tile_mode) const {
+ // TODO(weiliangc): properly implement background filters. (crbug.com/644851)
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h
new file mode 100644
index 00000000000..fa37d206b57
--- /dev/null
+++ b/chromium/components/viz/service/display/skia_renderer.h
@@ -0,0 +1,119 @@
+// Copyright 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_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
+
+#include "base/macros.h"
+#include "cc/cc_export.h"
+#include "cc/output/direct_renderer.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/latency/latency_info.h"
+
+class SkNWayCanvas;
+
+namespace cc {
+class DebugBorderDrawQuad;
+class OutputSurface;
+class PictureDrawQuad;
+class RenderPassDrawQuad;
+class ResourceProvider;
+class SolidColorDrawQuad;
+class TextureDrawQuad;
+class TileDrawQuad;
+} // namespace cc
+
+namespace viz {
+class VIZ_SERVICE_EXPORT SkiaRenderer : public cc::DirectRenderer {
+ public:
+ SkiaRenderer(const RendererSettings* settings,
+ cc::OutputSurface* output_surface,
+ cc::DisplayResourceProvider* resource_provider);
+
+ ~SkiaRenderer() override;
+
+ void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
+
+ void SetDisablePictureQuadImageFiltering(bool disable) {
+ disable_picture_quad_image_filtering_ = disable;
+ }
+
+ protected:
+ bool CanPartialSwap() override;
+ ResourceFormat BackbufferFormat() const override;
+ void BindFramebufferToOutputSurface() override;
+ bool BindFramebufferToTexture(const cc::ScopedResource* texture) override;
+ void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
+ void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
+ void DoDrawQuad(const cc::DrawQuad* quad,
+ const gfx::QuadF* draw_region) override;
+ void BeginDrawingFrame() override;
+ void FinishDrawingFrame() override;
+ bool FlippedFramebuffer() const override;
+ void EnsureScissorTestEnabled() override;
+ void EnsureScissorTestDisabled() override;
+ void CopyCurrentRenderPassToBitmap(
+ std::unique_ptr<CopyOutputRequest> request) override;
+ void SetEnableDCLayers(bool enable) override;
+ void DidChangeVisibility() override;
+ void FinishDrawingQuadList() override;
+
+ private:
+ void ClearCanvas(SkColor color);
+ void ClearFramebuffer();
+ void SetClipRect(const gfx::Rect& rect);
+ bool IsSoftwareResource(ResourceId resource_id) const;
+
+ void DrawDebugBorderQuad(const cc::DebugBorderDrawQuad* quad);
+ void DrawPictureQuad(const cc::PictureDrawQuad* quad);
+ void DrawRenderPassQuad(const cc::RenderPassDrawQuad* quad);
+ void DrawSolidColorQuad(const cc::SolidColorDrawQuad* quad);
+ void DrawTextureQuad(const cc::TextureDrawQuad* quad);
+ void DrawTileQuad(const cc::TileDrawQuad* quad);
+ void DrawUnsupportedQuad(const cc::DrawQuad* quad);
+ bool ShouldApplyBackgroundFilters(
+ const cc::RenderPassDrawQuad* quad,
+ const cc::FilterOperations* background_filters) const;
+ sk_sp<SkImage> ApplyImageFilter(SkImageFilter* filter,
+ const cc::RenderPassDrawQuad* quad,
+ const SkBitmap& to_filter,
+ SkIRect* auto_bounds) const;
+ gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
+ const cc::RenderPassDrawQuad* quad,
+ const gfx::Transform& contents_device_transform,
+ const cc::FilterOperations* background_filters) const;
+ SkBitmap GetBackdropBitmap(const gfx::Rect& bounding_rect) const;
+ sk_sp<SkShader> GetBackgroundFilterShader(
+ const cc::RenderPassDrawQuad* quad,
+ SkShader::TileMode content_tile_mode) const;
+
+ bool disable_picture_quad_image_filtering_ = false;
+
+ bool is_scissor_enabled_ = false;
+ gfx::Rect scissor_rect_;
+
+ sk_sp<SkSurface> root_surface_;
+ sk_sp<SkSurface> overdraw_surface_;
+ std::unique_ptr<SkCanvas> overdraw_canvas_;
+ std::unique_ptr<SkNWayCanvas> nway_canvas_;
+ SkCanvas* root_canvas_ = nullptr;
+ SkCanvas* current_canvas_ = nullptr;
+ SkPaint current_paint_;
+ std::unique_ptr<cc::ResourceProvider::ScopedWriteLockGL>
+ current_framebuffer_lock_;
+ std::unique_ptr<cc::ResourceProvider::ScopedSkSurface>
+ current_framebuffer_surface_lock_;
+
+ bool use_swap_with_bounds_ = false;
+
+ gfx::Rect swap_buffer_rect_;
+ std::vector<gfx::Rect> swap_content_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(SkiaRenderer);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
diff --git a/chromium/components/viz/service/display/static_geometry_binding.cc b/chromium/components/viz/service/display/static_geometry_binding.cc
new file mode 100644
index 00000000000..1dc0e9b717a
--- /dev/null
+++ b/chromium/components/viz/service/display/static_geometry_binding.cc
@@ -0,0 +1,74 @@
+// 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/viz/service/display/static_geometry_binding.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace viz {
+
+StaticGeometryBinding::StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
+ const gfx::RectF& quad_vertex_rect)
+ : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
+ GeometryBindingQuad quads[NUM_QUADS];
+ GeometryBindingQuadIndex quad_indices[NUM_QUADS];
+
+ static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
+ "struct Quad should be densely packed");
+ static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
+ "struct QuadIndex should be densely packed");
+
+ for (size_t i = 0; i < NUM_QUADS; i++) {
+ GeometryBindingVertex v0 = {
+ {quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f},
+ {0.0f, 1.0f},
+ i * 4.0f + 0.0f};
+ GeometryBindingVertex v1 = {
+ {quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f},
+ {0.0f, 0.0f},
+ i * 4.0f + 1.0f};
+ GeometryBindingVertex v2 = {
+ {quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f},
+ {1.0f, 0.0f},
+ i * 4.0f + 2.0f};
+ GeometryBindingVertex v3 = {
+ {quad_vertex_rect.right(), quad_vertex_rect.bottom(), 0.0f},
+ {1.0f, 1.0f},
+ i * 4.0f + 3.0f};
+ GeometryBindingQuad x(v0, v1, v2, v3);
+ quads[i] = x;
+ GeometryBindingQuadIndex y(
+ static_cast<uint16_t>(0 + 4 * i), static_cast<uint16_t>(1 + 4 * i),
+ static_cast<uint16_t>(2 + 4 * i), static_cast<uint16_t>(3 + 4 * i),
+ static_cast<uint16_t>(0 + 4 * i), static_cast<uint16_t>(2 + 4 * i));
+ quad_indices[i] = y;
+ }
+
+ gl_->GenBuffers(1, &quad_vertices_vbo_);
+ gl_->GenBuffers(1, &quad_elements_vbo_);
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad) * NUM_QUADS,
+ quads, GL_STATIC_DRAW);
+
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
+ gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(GeometryBindingQuadIndex) * NUM_QUADS, &quad_indices,
+ GL_STATIC_DRAW);
+}
+
+StaticGeometryBinding::~StaticGeometryBinding() {
+ gl_->DeleteBuffers(1, &quad_vertices_vbo_);
+ gl_->DeleteBuffers(1, &quad_elements_vbo_);
+}
+
+void StaticGeometryBinding::PrepareForDraw() {
+ SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/static_geometry_binding.h b/chromium/components/viz/service/display/static_geometry_binding.h
new file mode 100644
index 00000000000..b4204bedc94
--- /dev/null
+++ b/chromium/components/viz/service/display/static_geometry_binding.h
@@ -0,0 +1,39 @@
+// 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_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
+
+#include "base/macros.h"
+#include "components/viz/service/display/geometry_binding.h"
+#include "components/viz/service/viz_service_export.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace viz {
+
+class VIZ_SERVICE_EXPORT StaticGeometryBinding {
+ public:
+ StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
+ const gfx::RectF& quad_vertex_rect);
+ ~StaticGeometryBinding();
+
+ void PrepareForDraw();
+
+ enum {
+ NUM_QUADS = 9,
+ };
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ GLuint quad_vertices_vbo_;
+ GLuint quad_elements_vbo_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticGeometryBinding);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index 0d6cdc7e90c..41604d70d59 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -20,15 +20,15 @@
#include "cc/output/compositor_frame.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/render_pass_draw_quad.h"
-#include "cc/quads/shared_quad_state.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_client.h"
-#include "cc/surfaces/surface_manager.h"
+#include "cc/resources/display_resource_provider.h"
+#include "components/viz/common/quads/shared_quad_state.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_client.h"
+#include "components/viz/service/surfaces/surface_manager.h"
namespace viz {
namespace {
@@ -45,9 +45,9 @@ const char kUmaNoActiveFrame[] =
void MoveMatchingRequests(
cc::RenderPassId render_pass_id,
- std::multimap<cc::RenderPassId, std::unique_ptr<cc::CopyOutputRequest>>*
+ std::multimap<cc::RenderPassId, std::unique_ptr<CopyOutputRequest>>*
copy_requests,
- std::vector<std::unique_ptr<cc::CopyOutputRequest>>* output_requests) {
+ std::vector<std::unique_ptr<CopyOutputRequest>>* output_requests) {
auto request_range = copy_requests->equal_range(render_pass_id);
for (auto it = request_range.first; it != request_range.second; ++it) {
DCHECK(it->second);
@@ -76,8 +76,8 @@ bool CalculateQuadSpaceDamageRect(
} // namespace
-SurfaceAggregator::SurfaceAggregator(cc::SurfaceManager* manager,
- cc::ResourceProvider* provider,
+SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
+ cc::DisplayResourceProvider* provider,
bool aggregate_only_damaged)
: manager_(manager),
provider_(provider),
@@ -138,7 +138,7 @@ cc::RenderPassId SurfaceAggregator::RemapPassId(
return render_pass_info.id;
}
-int SurfaceAggregator::ChildIdForSurface(cc::Surface* surface) {
+int SurfaceAggregator::ChildIdForSurface(Surface* surface) {
auto it = surface_id_to_resource_child_id_.find(surface->surface_id());
if (it == surface_id_to_resource_child_id_.end()) {
int child_id = provider_->CreateChild(
@@ -152,13 +152,13 @@ int SurfaceAggregator::ChildIdForSurface(cc::Surface* surface) {
}
gfx::Rect SurfaceAggregator::DamageRectForSurface(
- const cc::Surface* surface,
+ const Surface* surface,
const cc::RenderPass& source,
const gfx::Rect& full_rect) const {
auto it = previous_contained_surfaces_.find(surface->surface_id());
if (it != previous_contained_surfaces_.end()) {
- int previous_index = it->second;
- if (previous_index == surface->frame_index())
+ uint64_t previous_index = it->second;
+ if (previous_index == surface->GetActiveFrameIndex())
return gfx::Rect();
}
const SurfaceId& previous_surface_id = surface->previous_frame_surface_id();
@@ -167,8 +167,8 @@ gfx::Rect SurfaceAggregator::DamageRectForSurface(
it = previous_contained_surfaces_.find(previous_surface_id);
}
if (it != previous_contained_surfaces_.end()) {
- int previous_index = it->second;
- if (previous_index == surface->frame_index() - 1)
+ uint64_t previous_index = it->second;
+ if (previous_index == surface->GetActiveFrameIndex() - 1)
return source.damage_rect;
}
@@ -177,8 +177,8 @@ gfx::Rect SurfaceAggregator::DamageRectForSurface(
// static
void SurfaceAggregator::UnrefResources(
- base::WeakPtr<cc::SurfaceClient> surface_client,
- const std::vector<cc::ReturnedResource>& resources,
+ base::WeakPtr<SurfaceClient> surface_client,
+ const std::vector<ReturnedResource>& resources,
cc::BlockingTaskRunner* main_thread_task_runner) {
if (surface_client)
surface_client->UnrefResources(resources);
@@ -197,7 +197,7 @@ void SurfaceAggregator::HandleSurfaceQuad(
// a cycle in the graph and should be dropped.
if (referenced_surfaces_.count(surface_id))
return;
- cc::Surface* surface = manager_->GetSurfaceForId(surface_id);
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
if (!surface || !surface->HasActiveFrame()) {
if (surface_quad->fallback_quad) {
HandleSurfaceQuad(surface_quad->fallback_quad, target_transform,
@@ -205,8 +205,10 @@ void SurfaceAggregator::HandleSurfaceQuad(
damage_rect_in_quad_space,
damage_rect_in_quad_space_valid);
} else if (!surface) {
+ DLOG(ERROR) << surface_id << " is missing during aggregation";
++uma_stats_.missing_surface;
} else {
+ DLOG(ERROR) << surface_id << " has no active frame during aggregation";
++uma_stats_.no_active_frame;
}
return;
@@ -228,8 +230,8 @@ void SurfaceAggregator::HandleSurfaceQuad(
const cc::CompositorFrame& frame = surface->GetActiveFrame();
- // A map keyed by RenderPass id.
- cc::Surface::CopyRequestsMap copy_requests;
+ // A map keyed by cc::RenderPass id.
+ Surface::CopyRequestsMap copy_requests;
surface->TakeCopyOutputRequests(&copy_requests);
const cc::RenderPassList& render_pass_list = frame.render_pass_list;
@@ -379,9 +381,13 @@ void SurfaceAggregator::AddColorConversionPass() {
auto* shared_quad_state =
color_conversion_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->quad_layer_rect = output_rect;
- shared_quad_state->visible_quad_layer_rect = output_rect;
- shared_quad_state->opacity = 1.f;
+ shared_quad_state->SetAll(
+ /*quad_to_target_transform=*/gfx::Transform(),
+ /*quad_layer_rect=*/output_rect,
+ /*visible_quad_layer_rect=*/output_rect,
+ /*clip_rect=*/gfx::Rect(),
+ /*is_clipped=*/false, /*opacity=*/1.f,
+ /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
auto* quad =
color_conversion_pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>();
@@ -391,42 +397,42 @@ void SurfaceAggregator::AddColorConversionPass() {
dest_pass_list_->push_back(std::move(color_conversion_pass));
}
-cc::SharedQuadState* SurfaceAggregator::CopySharedQuadState(
- const cc::SharedQuadState* source_sqs,
+SharedQuadState* SurfaceAggregator::CopySharedQuadState(
+ const SharedQuadState* source_sqs,
const gfx::Transform& target_transform,
const ClipData& clip_rect,
cc::RenderPass* dest_render_pass) {
auto* copy_shared_quad_state =
dest_render_pass->CreateAndAppendSharedQuadState();
- *copy_shared_quad_state = *source_sqs;
// target_transform contains any transformation that may exist
// between the context that these quads are being copied from (i.e. the
// surface's draw transform when aggregated from within a surface) to the
// target space of the pass. This will be identity except when copying the
// root draw pass from a surface into a pass when the surface draw quad's
// transform is not identity.
- copy_shared_quad_state->quad_to_target_transform.ConcatTransform(
- target_transform);
-
+ gfx::Transform new_transform = source_sqs->quad_to_target_transform;
+ new_transform.ConcatTransform(target_transform);
ClipData new_clip_rect = CalculateClipRect(
clip_rect, ClipData(source_sqs->is_clipped, source_sqs->clip_rect),
target_transform);
- copy_shared_quad_state->is_clipped = new_clip_rect.is_clipped;
- copy_shared_quad_state->clip_rect = new_clip_rect.rect;
+ copy_shared_quad_state->SetAll(new_transform, source_sqs->quad_layer_rect,
+ source_sqs->visible_quad_layer_rect,
+ new_clip_rect.rect, new_clip_rect.is_clipped,
+ source_sqs->opacity, source_sqs->blend_mode,
+ source_sqs->sorting_context_id);
+
return copy_shared_quad_state;
}
void SurfaceAggregator::CopyQuadsToPass(
const cc::QuadList& source_quad_list,
const cc::SharedQuadStateList& source_shared_quad_state_list,
- const std::unordered_map<cc::ResourceId, cc::ResourceId>&
- child_to_parent_map,
+ const std::unordered_map<ResourceId, ResourceId>& child_to_parent_map,
const gfx::Transform& target_transform,
const ClipData& clip_rect,
cc::RenderPass* dest_pass,
const SurfaceId& surface_id) {
- const cc::SharedQuadState* last_copied_source_shared_quad_state = nullptr;
- const cc::SharedQuadState* dest_shared_quad_state = nullptr;
+ const SharedQuadState* last_copied_source_shared_quad_state = nullptr;
// If the current frame has copy requests or cached render passes, then
// aggregate the entire thing, as otherwise parts of the copy requests may be
// ignored and we could cache partially drawn render pass.
@@ -460,7 +466,7 @@ void SurfaceAggregator::CopyQuadsToPass(
last_copied_source_shared_quad_state = nullptr;
// The primary SurfaceDrawQuad should have already dealt with the fallback
- // DrawQuad.
+ // cc::DrawQuad.
if (surface_quad->surface_draw_quad_type ==
cc::SurfaceDrawQuadType::FALLBACK)
continue;
@@ -470,7 +476,7 @@ void SurfaceAggregator::CopyQuadsToPass(
&damage_rect_in_quad_space_valid);
} else {
if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
- dest_shared_quad_state = CopySharedQuadState(
+ const SharedQuadState* dest_shared_quad_state = CopySharedQuadState(
quad->shared_quad_state, target_transform, clip_rect, dest_pass);
last_copied_source_shared_quad_state = quad->shared_quad_state;
if (aggregate_only_damaged_ && !has_copy_requests_ &&
@@ -502,31 +508,30 @@ void SurfaceAggregator::CopyQuadsToPass(
dest_pass->has_damage_from_contributing_content = true;
dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
- pass_quad, dest_shared_quad_state, remapped_pass_id);
+ pass_quad, remapped_pass_id);
} else if (quad->material == cc::DrawQuad::TEXTURE_CONTENT) {
const auto* texture_quad = cc::TextureDrawQuad::MaterialCast(quad);
if (texture_quad->secure_output_only &&
(!output_is_secure_ || copy_request_passes_.count(dest_pass->id))) {
auto* solid_color_quad =
dest_pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
- solid_color_quad->SetNew(dest_shared_quad_state, quad->rect,
- quad->visible_rect, SK_ColorBLACK, false);
+ solid_color_quad->SetNew(dest_pass->shared_quad_state_list.back(),
+ quad->rect, quad->visible_rect,
+ SK_ColorBLACK, false);
dest_quad = solid_color_quad;
} else {
- dest_quad = dest_pass->CopyFromAndAppendDrawQuad(
- quad, dest_shared_quad_state);
+ dest_quad = dest_pass->CopyFromAndAppendDrawQuad(quad);
}
} else {
- dest_quad =
- dest_pass->CopyFromAndAppendDrawQuad(quad, dest_shared_quad_state);
+ dest_quad = dest_pass->CopyFromAndAppendDrawQuad(quad);
}
if (!child_to_parent_map.empty()) {
- for (cc::ResourceId& resource_id : dest_quad->resources) {
+ for (ResourceId& resource_id : dest_quad->resources) {
auto it = child_to_parent_map.find(resource_id);
DCHECK(it != child_to_parent_map.end());
DCHECK_EQ(it->first, resource_id);
- cc::ResourceId remapped_id = it->second;
+ ResourceId remapped_id = it->second;
resource_id = remapped_id;
}
}
@@ -535,11 +540,11 @@ void SurfaceAggregator::CopyQuadsToPass(
}
void SurfaceAggregator::CopyPasses(const cc::CompositorFrame& frame,
- cc::Surface* surface) {
+ Surface* surface) {
// The root surface is allowed to have copy output requests, so grab them
// off its render passes. This map contains a set of CopyOutputRequests
- // keyed by each RenderPass id.
- cc::Surface::CopyRequestsMap copy_requests;
+ // keyed by each cc::RenderPass id.
+ Surface::CopyRequestsMap copy_requests;
surface->TakeCopyOutputRequests(&copy_requests);
const auto& source_pass_list = frame.render_pass_list;
@@ -610,7 +615,7 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
}
// Notify client of removed surface.
- cc::Surface* surface_ptr = manager_->GetSurfaceForId(surface.first);
+ Surface* surface_ptr = manager_->GetSurfaceForId(surface.first);
if (surface_ptr) {
surface_ptr->RunDrawCallback();
}
@@ -632,12 +637,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
if (referenced_surfaces_.count(surface_id))
return gfx::Rect();
- cc::Surface* surface = manager_->GetSurfaceForId(surface_id);
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
if (!surface) {
contained_surfaces_[surface_id] = 0;
return gfx::Rect();
}
- contained_surfaces_[surface_id] = surface->frame_index();
+ contained_surfaces_[surface_id] = surface->GetActiveFrameIndex();
if (!surface->HasActiveFrame())
return gfx::Rect();
const cc::CompositorFrame& frame = surface->GetActiveFrame();
@@ -650,7 +655,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
}
CHECK(debug_weak_this.get());
- std::vector<cc::ResourceId> referenced_resources;
+ std::vector<ResourceId> referenced_resources;
size_t reserve_size = frame.resource_list.size();
referenced_resources.reserve(reserve_size);
@@ -739,7 +744,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
if (!provider_)
continue;
- for (cc::ResourceId resource_id : quad->resources) {
+ for (ResourceId resource_id : quad->resources) {
if (!child_to_parent_map.count(resource_id)) {
invalid_frame = true;
break;
@@ -754,8 +759,8 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
CHECK(debug_weak_this.get());
valid_surfaces_.insert(surface->surface_id());
- cc::ResourceIdSet resource_set(std::move(referenced_resources),
- base::KEEP_FIRST_OF_DUPES);
+ ResourceIdSet resource_set(std::move(referenced_resources),
+ base::KEEP_FIRST_OF_DUPES);
if (provider_)
provider_->DeclareUsedResourcesFromChild(child_id, resource_set);
CHECK(debug_weak_this.get());
@@ -814,7 +819,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
has_cached_render_passes_ = true;
}
- referenced_surfaces_.erase(referenced_surfaces_.find(surface->surface_id()));
+ // TODO(jbauman): Remove when https://crbug.com/745684 fixed.
+ CHECK(surface->surface_id() == surface_id);
+ auto it = referenced_surfaces_.find(surface_id);
+ // TODO(jbauman): Remove when https://crbug.com/745684 fixed.
+ CHECK(referenced_surfaces_.end() != it);
+ referenced_surfaces_.erase(it);
if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video)
result->may_contain_video = true;
@@ -834,7 +844,7 @@ void SurfaceAggregator::CopyUndrawnSurfaces(PrewalkResult* prewalk_result) {
for (size_t i = 0; i < surfaces_to_copy.size(); i++) {
SurfaceId surface_id = surfaces_to_copy[i];
- cc::Surface* surface = manager_->GetSurfaceForId(surface_id);
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
if (!surface)
continue;
if (!surface->HasActiveFrame())
@@ -870,7 +880,7 @@ void SurfaceAggregator::PropagateCopyRequestPasses() {
std::vector<cc::RenderPassId> copy_requests_to_iterate(
copy_request_passes_.begin(), copy_request_passes_.end());
while (!copy_requests_to_iterate.empty()) {
- int first = copy_requests_to_iterate.back();
+ cc::RenderPassId first = copy_requests_to_iterate.back();
copy_requests_to_iterate.pop_back();
auto it = render_pass_dependencies_.find(first);
if (it == render_pass_dependencies_.end())
@@ -886,9 +896,9 @@ void SurfaceAggregator::PropagateCopyRequestPasses() {
cc::CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
uma_stats_.Reset();
- cc::Surface* surface = manager_->GetSurfaceForId(surface_id);
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
DCHECK(surface);
- contained_surfaces_[surface_id] = surface->frame_index();
+ contained_surfaces_[surface_id] = surface->GetActiveFrameIndex();
if (!surface->HasActiveFrame())
return {};
@@ -942,7 +952,7 @@ cc::CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
contained_surfaces_.clear();
for (auto it : previous_contained_surfaces_) {
- cc::Surface* surface = manager_->GetSurfaceForId(it.first);
+ Surface* surface = manager_->GetSurfaceForId(it.first);
if (surface)
surface->TakeLatencyInfo(&frame.metadata.latency_info);
}
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index f6cff7bde45..106a4faf4f7 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -14,7 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/render_pass.h"
-#include "cc/resources/transferable_resource.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/color_space.h"
@@ -22,21 +22,22 @@
namespace cc {
class BlockingTaskRunner;
class CompositorFrame;
-class ResourceProvider;
-class Surface;
-class SurfaceClient;
+class DisplayResourceProvider;
class SurfaceDrawQuad;
-class SurfaceManager;
} // namespace cc
namespace viz {
+class Surface;
+class SurfaceClient;
+class SurfaceManager;
+
class VIZ_SERVICE_EXPORT SurfaceAggregator {
public:
- using SurfaceIndexMap = base::flat_map<SurfaceId, int>;
+ using SurfaceIndexMap = base::flat_map<SurfaceId, uint64_t>;
- SurfaceAggregator(cc::SurfaceManager* manager,
- cc::ResourceProvider* provider,
+ SurfaceAggregator(SurfaceManager* manager,
+ cc::DisplayResourceProvider* provider,
bool aggregate_only_damaged);
~SurfaceAggregator();
@@ -48,7 +49,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void SetFullDamageForSurface(const SurfaceId& surface_id);
void set_output_is_secure(bool secure) { output_is_secure_ = secure; }
- // Set the color spaces for the created RenderPasses, which is propagated
+ // Set the color spaces for the created cc::RenderPasses, which is propagated
// to the output surface.
void SetOutputColorSpace(const gfx::ColorSpace& blending_color_space,
const gfx::ColorSpace& output_color_space);
@@ -109,16 +110,14 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid);
- cc::SharedQuadState* CopySharedQuadState(
- const cc::SharedQuadState* source_sqs,
- const gfx::Transform& target_transform,
- const ClipData& clip_rect,
- cc::RenderPass* dest_render_pass);
+ SharedQuadState* CopySharedQuadState(const SharedQuadState* source_sqs,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
+ cc::RenderPass* dest_render_pass);
void CopyQuadsToPass(
const cc::QuadList& source_quad_list,
const cc::SharedQuadStateList& source_shared_quad_state_list,
- const std::unordered_map<cc::ResourceId, cc::ResourceId>&
- resource_to_child_map,
+ const std::unordered_map<ResourceId, ResourceId>& resource_to_child_map,
const gfx::Transform& target_transform,
const ClipData& clip_rect,
cc::RenderPass* dest_pass,
@@ -128,7 +127,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
int parent_pass,
PrewalkResult* result);
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
- void CopyPasses(const cc::CompositorFrame& frame, cc::Surface* surface);
+ void CopyPasses(const cc::CompositorFrame& frame, Surface* surface);
void AddColorConversionPass();
// Remove Surfaces that were referenced before but aren't currently
@@ -139,20 +138,20 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void PropagateCopyRequestPasses();
- int ChildIdForSurface(cc::Surface* surface);
- gfx::Rect DamageRectForSurface(const cc::Surface* surface,
+ int ChildIdForSurface(Surface* surface);
+ gfx::Rect DamageRectForSurface(const Surface* surface,
const cc::RenderPass& source,
const gfx::Rect& full_rect) const;
- static void UnrefResources(base::WeakPtr<cc::SurfaceClient> surface_client,
- const std::vector<cc::ReturnedResource>& resources,
+ static void UnrefResources(base::WeakPtr<SurfaceClient> surface_client,
+ const std::vector<ReturnedResource>& resources,
cc::BlockingTaskRunner* main_thread_task_runner);
- cc::SurfaceManager* manager_;
- cc::ResourceProvider* provider_;
+ SurfaceManager* manager_;
+ cc::DisplayResourceProvider* provider_;
- // Every Surface has its own RenderPass ID namespace. This structure maps
- // each source (SurfaceId, RenderPass id) to a unified ID namespace that's
+ // Every Surface has its own cc::RenderPass ID namespace. This structure maps
+ // each source (SurfaceId, cc::RenderPass id) to a unified ID namespace that's
// used in the aggregated frame. An entry is removed from the map if it's not
// used for one output frame.
base::flat_map<std::pair<SurfaceId, cc::RenderPassId>, RenderPassInfo>
@@ -205,7 +204,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
base::flat_set<cc::RenderPassId> contributing_content_damaged_passes_;
// This maps each aggregated pass id to the set of (aggregated) pass ids
- // that its RenderPassDrawQuads depend on
+ // that its cc::RenderPassDrawQuads depend on
base::flat_map<cc::RenderPassId, base::flat_set<cc::RenderPassId>>
render_pass_dependencies_;
diff --git a/chromium/components/viz/service/display/surface_aggregator_perftest.cc b/chromium/components/viz/service/display/surface_aggregator_perftest.cc
index ab49928a818..9e3a58845f6 100644
--- a/chromium/components/viz/service/display/surface_aggregator_perftest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_perftest.cc
@@ -7,8 +7,7 @@
#include "cc/output/compositor_frame.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/compositor_frame_helpers.h"
+#include "cc/resources/display_resource_provider.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_resource_provider.h"
#include "cc/test/test_context_provider.h"
@@ -16,6 +15,8 @@
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -24,7 +25,6 @@ namespace {
constexpr bool kIsRoot = true;
constexpr bool kIsChildRoot = false;
-constexpr bool kHandlesFrameSinkIdInvalidation = true;
constexpr bool kNeedsSyncPoints = true;
const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
@@ -36,8 +36,9 @@ class SurfaceAggregatorPerfTest : public testing::Test {
context_provider_->BindToCurrentThread();
shared_bitmap_manager_ = base::MakeUnique<cc::TestSharedBitmapManager>();
- resource_provider_ = cc::FakeResourceProvider::Create(
- context_provider_.get(), shared_bitmap_manager_.get());
+ resource_provider_ =
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ context_provider_.get(), shared_bitmap_manager_.get());
}
void RunTest(int num_surfaces,
@@ -51,7 +52,7 @@ class SurfaceAggregatorPerfTest : public testing::Test {
for (int i = 0; i < num_surfaces; i++) {
child_supports[i] = CompositorFrameSinkSupport::Create(
nullptr, &manager_, FrameSinkId(1, i + 1), kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
}
aggregator_ = base::MakeUnique<SurfaceAggregator>(
manager_.surface_manager(), resource_provider_.get(), optimize_damage);
@@ -61,18 +62,17 @@ class SurfaceAggregatorPerfTest : public testing::Test {
auto pass = cc::RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 1, 2);
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
auto* sqs = pass->CreateAndAppendSharedQuadState();
for (int j = 0; j < num_textures; j++) {
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = j;
resource.is_software = true;
frame.resource_list.push_back(resource);
auto* quad = pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
const gfx::Rect rect(0, 0, 1, 2);
- const gfx::Rect opaque_rect;
// Half of rects should be visible with partial damage.
gfx::Rect visible_rect =
j % 2 == 0 ? gfx::Rect(0, 0, 1, 2) : gfx::Rect(0, 1, 1, 1);
@@ -84,9 +84,9 @@ class SurfaceAggregatorPerfTest : public testing::Test {
const float vertex_opacity[4] = {0.f, 0.f, 1.f, 1.f};
bool flipped = false;
bool nearest_neighbor = false;
- quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending, j,
- gfx::Size(), premultiplied_alpha, uv_top_left,
- uv_bottom_right, background_color, vertex_opacity, flipped,
+ quad->SetAll(sqs, rect, visible_rect, needs_blending, j, gfx::Size(),
+ premultiplied_alpha, uv_top_left, uv_bottom_right,
+ background_color, vertex_opacity, flipped,
nearest_neighbor, false);
}
sqs = pass->CreateAndAppendSharedQuadState();
@@ -107,11 +107,11 @@ class SurfaceAggregatorPerfTest : public testing::Test {
auto root_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, FrameSinkId(1, num_surfaces + 1), kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
timer_.Reset();
do {
auto pass = cc::RenderPass::Create();
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
auto* sqs = pass->CreateAndAppendSharedQuadState();
auto* surface_quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
@@ -150,7 +150,7 @@ class SurfaceAggregatorPerfTest : public testing::Test {
FrameSinkManagerImpl manager_;
scoped_refptr<cc::TestContextProvider> context_provider_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::ResourceProvider> resource_provider_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
cc::LapTimer timer_;
};
diff --git a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
index 91c06d9956f..d6a54fda148 100644
--- a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -7,15 +7,15 @@
#include "cc/quads/render_pass.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/surface_draw_quad.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(OS_ANDROID)
@@ -29,20 +29,16 @@ constexpr FrameSinkId kArbitraryLeftFrameSinkId(3, 3);
constexpr FrameSinkId kArbitraryRightFrameSinkId(4, 4);
constexpr bool kIsRoot = true;
constexpr bool kIsChildRoot = false;
-constexpr bool kHandlesFrameSinkIdInvalidation = true;
constexpr bool kNeedsSyncPoints = true;
-class SurfaceAggregatorPixelTest
- : public cc::RendererPixelTest<cc::GLRenderer> {
+class SurfaceAggregatorPixelTest : public cc::RendererPixelTest<GLRenderer> {
public:
SurfaceAggregatorPixelTest()
- : support_(
- CompositorFrameSinkSupport::Create(nullptr,
- &manager_,
- kArbitraryRootFrameSinkId,
- kIsRoot,
- kHandlesFrameSinkIdInvalidation,
- kNeedsSyncPoints)) {}
+ : support_(CompositorFrameSinkSupport::Create(nullptr,
+ &manager_,
+ kArbitraryRootFrameSinkId,
+ kIsRoot,
+ kNeedsSyncPoints)) {}
~SurfaceAggregatorPixelTest() override { support_->EvictCurrentSurface(); }
protected:
@@ -51,7 +47,7 @@ class SurfaceAggregatorPixelTest
std::unique_ptr<CompositorFrameSinkSupport> support_;
};
-cc::SharedQuadState* CreateAndAppendTestSharedQuadState(
+SharedQuadState* CreateAndAppendTestSharedQuadState(
cc::RenderPass* render_pass,
const gfx::Transform& transform,
const gfx::Size& size) {
@@ -82,7 +78,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawSimpleFrame) {
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SK_ColorGREEN, force_anti_aliasing_off);
- auto root_frame = cc::test::MakeCompositorFrame();
+ auto root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
LocalSurfaceId root_local_surface_id = allocator_.GenerateId();
@@ -105,9 +101,9 @@ TEST_F(SurfaceAggregatorPixelTest, DrawSimpleFrame) {
TEST_F(SurfaceAggregatorPixelTest, DrawSimpleAggregatedFrame) {
gfx::Size child_size(200, 100);
std::unique_ptr<CompositorFrameSinkSupport> child_support =
- CompositorFrameSinkSupport::Create(
- nullptr, &manager_, kArbitraryChildFrameSinkId, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ CompositorFrameSinkSupport::Create(nullptr, &manager_,
+ kArbitraryChildFrameSinkId,
+ kIsChildRoot, kNeedsSyncPoints);
LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
SurfaceId child_surface_id(child_support->frame_sink_id(),
@@ -135,7 +131,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawSimpleAggregatedFrame) {
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SK_ColorYELLOW, force_anti_aliasing_off);
- auto root_frame = cc::test::MakeCompositorFrame();
+ auto root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
support_->SubmitCompositorFrame(root_local_surface_id,
@@ -156,7 +152,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawSimpleAggregatedFrame) {
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SK_ColorBLUE, force_anti_aliasing_off);
- auto child_frame = cc::test::MakeCompositorFrame();
+ auto child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
child_support->SubmitCompositorFrame(child_local_surface_id,
@@ -189,13 +185,13 @@ TEST_F(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
// right_child -> top_blue_quad (100x100 @ 0x0),
// bottom_green_quad (100x100 @ 0x100)
std::unique_ptr<CompositorFrameSinkSupport> left_support =
- CompositorFrameSinkSupport::Create(
- nullptr, &manager_, kArbitraryLeftFrameSinkId, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ CompositorFrameSinkSupport::Create(nullptr, &manager_,
+ kArbitraryLeftFrameSinkId,
+ kIsChildRoot, kNeedsSyncPoints);
std::unique_ptr<CompositorFrameSinkSupport> right_support =
- CompositorFrameSinkSupport::Create(
- nullptr, &manager_, kArbitraryRightFrameSinkId, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ CompositorFrameSinkSupport::Create(nullptr, &manager_,
+ kArbitraryRightFrameSinkId,
+ kIsChildRoot, kNeedsSyncPoints);
LocalSurfaceId left_child_local_id = allocator_.GenerateId();
SurfaceId left_child_id(left_support->frame_sink_id(), left_child_local_id);
LocalSurfaceId right_child_local_id = allocator_.GenerateId();
@@ -232,7 +228,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
right_child_id, cc::SurfaceDrawQuadType::PRIMARY,
nullptr);
- auto root_frame = cc::test::MakeCompositorFrame();
+ auto root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
support_->SubmitCompositorFrame(root_local_surface_id,
@@ -261,7 +257,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
pass->shared_quad_state_list.back(), gfx::Rect(0, 100, 100, 100),
gfx::Rect(0, 100, 100, 100), SK_ColorBLUE, force_anti_aliasing_off);
- auto child_frame = cc::test::MakeCompositorFrame();
+ auto child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
left_support->SubmitCompositorFrame(left_child_local_id,
@@ -290,7 +286,7 @@ TEST_F(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
pass->shared_quad_state_list.back(), gfx::Rect(0, 100, 100, 100),
gfx::Rect(0, 100, 100, 100), SK_ColorGREEN, force_anti_aliasing_off);
- auto child_frame = cc::test::MakeCompositorFrame();
+ auto child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
right_support->SubmitCompositorFrame(right_child_local_id,
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index 78f35d4de81..63bb8275a45 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -19,18 +19,19 @@
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/compositor_frame_helpers.h"
+#include "cc/resources/display_resource_provider.h"
#include "cc/test/fake_compositor_frame_sink_support_client.h"
#include "cc/test/fake_resource_provider.h"
-#include "cc/test/fake_surface_observer.h"
#include "cc/test/render_pass_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/fake_surface_observer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -47,7 +48,6 @@ constexpr FrameSinkId kArbitraryFrameSinkId3(6, 6);
const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
constexpr bool kRootIsRoot = true;
constexpr bool kChildIsRoot = false;
-constexpr bool kHandlesFrameSinkIdInvalidation = true;
constexpr bool kNeedsSyncPoints = false;
SurfaceId InvalidSurfaceId() {
@@ -65,13 +65,11 @@ class SurfaceAggregatorTest : public testing::Test {
public:
explicit SurfaceAggregatorTest(bool use_damage_rect)
: observer_(false),
- support_(
- CompositorFrameSinkSupport::Create(&fake_client_,
- &manager_,
- kArbitraryRootFrameSinkId,
- kRootIsRoot,
- kHandlesFrameSinkIdInvalidation,
- kNeedsSyncPoints)),
+ support_(CompositorFrameSinkSupport::Create(&fake_client_,
+ &manager_,
+ kArbitraryRootFrameSinkId,
+ kRootIsRoot,
+ kNeedsSyncPoints)),
aggregator_(manager_.surface_manager(), NULL, use_damage_rect) {
manager_.surface_manager()->AddObserver(&observer_);
}
@@ -111,13 +109,13 @@ class SurfaceAggregatorTest : public testing::Test {
}
cc::DrawQuad::Material material;
- // Set when material==DrawQuad::SURFACE_CONTENT.
+ // Set when material==cc::DrawQuad::SURFACE_CONTENT.
SurfaceId primary_surface_id;
SurfaceId fallback_surface_id;
float opacity;
- // Set when material==DrawQuad::SOLID_COLOR.
+ // Set when material==cc::DrawQuad::SOLID_COLOR.
SkColor color;
- // Set when material==DrawQuad::RENDER_PASS.
+ // Set when material==cc::DrawQuad::RENDER_PASS.
cc::RenderPassId render_pass_id;
private:
@@ -271,7 +269,7 @@ class SurfaceAggregatorTest : public testing::Test {
protected:
FrameSinkManagerImpl manager_;
- cc::FakeSurfaceObserver observer_;
+ FakeSurfaceObserver observer_;
cc::FakeCompositorFrameSinkSupportClient fake_client_;
std::unique_ptr<CompositorFrameSinkSupport> support_;
SurfaceAggregator aggregator_;
@@ -286,7 +284,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
&manager_,
kArbitraryReservedFrameSinkId,
kChildIsRoot,
- kHandlesFrameSinkIdInvalidation,
+
kNeedsSyncPoints)) {}
SurfaceAggregatorValidSurfaceTest()
: SurfaceAggregatorValidSurfaceTest(false) {}
@@ -331,7 +329,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
void SubmitPassListAsFrame(CompositorFrameSinkSupport* support,
const LocalSurfaceId& local_surface_id,
cc::RenderPassList* pass_list) {
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
pass_list->swap(frame.render_pass_list);
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -349,7 +347,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
void QueuePassAsFrame(std::unique_ptr<cc::RenderPass> pass,
const LocalSurfaceId& local_surface_id,
CompositorFrameSinkSupport* support) {
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
support->SubmitCompositorFrame(local_surface_id, std::move(child_frame));
@@ -357,7 +355,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
protected:
LocalSurfaceId root_local_surface_id_;
- cc::Surface* root_surface_;
+ Surface* root_surface_;
LocalSurfaceIdAllocator allocator_;
std::unique_ptr<CompositorFrameSinkSupport> child_support_;
LocalSurfaceIdAllocator child_allocator_;
@@ -389,7 +387,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) {
TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
auto embedded_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
@@ -500,7 +498,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassDeallocation) {
TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
auto embedded_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
@@ -538,14 +536,14 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReference) {
auto primary_child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId primary_child_local_surface_id = allocator_.GenerateId();
SurfaceId primary_child_surface_id(primary_child_support->frame_sink_id(),
primary_child_local_surface_id);
auto fallback_child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId fallback_child_local_surface_id = allocator_.GenerateId();
SurfaceId fallback_child_surface_id(fallback_child_support->frame_sink_id(),
fallback_child_local_surface_id);
@@ -620,7 +618,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReference) {
TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReferenceWithPrimary) {
auto primary_child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId primary_child_local_surface_id = allocator_.GenerateId();
SurfaceId primary_child_surface_id(primary_child_support->frame_sink_id(),
primary_child_local_surface_id);
@@ -636,7 +634,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReferenceWithPrimary) {
auto fallback_child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId fallback_child_local_surface_id = allocator_.GenerateId();
SurfaceId fallback_child_surface_id(fallback_child_support->frame_sink_id(),
fallback_child_local_surface_id);
@@ -679,7 +677,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReferenceWithPrimary) {
TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
auto embedded_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
@@ -689,7 +687,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
SubmitCompositorFrame(embedded_support.get(), embedded_passes,
arraysize(embedded_passes), embedded_local_surface_id);
- auto copy_request = cc::CopyOutputRequest::CreateEmptyRequest();
+ auto copy_request = CopyOutputRequest::CreateEmptyRequest();
auto* copy_request_ptr = copy_request.get();
embedded_support->RequestCopyOfSurface(std::move(copy_request));
@@ -734,7 +732,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
auto embedded_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
@@ -744,9 +742,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
SubmitCompositorFrame(embedded_support.get(), embedded_passes,
arraysize(embedded_passes), embedded_local_surface_id);
- auto copy_request(cc::CopyOutputRequest::CreateEmptyRequest());
+ auto copy_request(CopyOutputRequest::CreateEmptyRequest());
auto* copy_request_ptr = copy_request.get();
- auto copy_request2(cc::CopyOutputRequest::CreateEmptyRequest());
+ auto copy_request2(CopyOutputRequest::CreateEmptyRequest());
auto* copy_request2_ptr = copy_request2.get();
Quad root_quads[] = {
@@ -757,7 +755,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
Pass root_passes[] = {Pass(root_quads, arraysize(root_quads), 1),
Pass(root_quads2, arraysize(root_quads2), 2)};
{
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
frame.render_pass_list[0]->copy_requests.push_back(std::move(copy_request));
@@ -810,10 +808,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
auto embedded_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
auto parent_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId2, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
@@ -825,7 +823,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
SubmitCompositorFrame(embedded_support.get(), embedded_passes,
arraysize(embedded_passes), embedded_local_surface_id);
- auto copy_request(cc::CopyOutputRequest::CreateEmptyRequest());
+ auto copy_request(CopyOutputRequest::CreateEmptyRequest());
auto* copy_request_ptr = copy_request.get();
embedded_support->RequestCopyOfSurface(std::move(copy_request));
@@ -840,7 +838,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
Pass parent_passes[] = {Pass(parent_quads, arraysize(parent_quads))};
{
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), parent_passes,
arraysize(parent_passes));
@@ -856,7 +854,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
Pass root_passes[] = {Pass(root_quads, arraysize(root_quads))};
{
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1264,13 +1262,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
};
auto grandchild_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
auto child_one_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
auto child_two_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId3, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
int pass_id = 1;
LocalSurfaceId grandchild_local_surface_id = allocator_.GenerateId();
SurfaceId grandchild_surface_id(grandchild_support->frame_sink_id(),
@@ -1388,7 +1386,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
auto middle_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
// Innermost child surface.
LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
SurfaceId child_surface_id(child_support_->frame_sink_id(),
@@ -1403,7 +1401,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
Pass(child_quads[0], arraysize(child_quads[0]), child_pass_id[0]),
Pass(child_quads[1], arraysize(child_quads[1]), child_pass_id[1])};
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1434,7 +1432,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
Pass(middle_quads, arraysize(middle_quads)),
};
- cc::CompositorFrame middle_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame middle_frame = test::MakeEmptyCompositorFrame();
AddPasses(&middle_frame.render_pass_list, gfx::Rect(SurfaceSize()),
middle_passes, arraysize(middle_passes));
@@ -1457,7 +1455,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
Pass root_passes[] = {Pass(secondary_quads, arraysize(secondary_quads)),
Pass(root_quads, arraysize(root_quads))};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1553,11 +1551,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
auto parent_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
Quad child_quads[] = {Quad::RenderPassQuad(1)};
Pass child_passes[] = {Pass(child_quads, arraysize(child_quads), 1)};
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1578,8 +1576,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
// Parent surface is only used to test if the transform is applied correctly
// to the child surface's damage.
- cc::CompositorFrame parent_surface_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame parent_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&parent_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
parent_surface_passes, arraysize(parent_surface_passes));
@@ -1597,7 +1594,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
Pass(root_surface_quads, arraysize(root_surface_quads), 1),
Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1622,7 +1619,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
aggregated_pass_list[1]->damage_rect.Contains(gfx::Rect(SurfaceSize())));
{
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1650,7 +1647,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
}
{
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1664,7 +1661,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
}
{
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1730,7 +1727,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SwitchSurfaceDamage) {
Pass root_passes[] = {
Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1763,7 +1760,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SwitchSurfaceDamage) {
Pass root_passes[] = {
Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1941,7 +1938,7 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
auto* child_root_pass = child_pass_list[1].get();
child_root_pass->copy_requests.push_back(
- cc::CopyOutputRequest::CreateEmptyRequest());
+ CopyOutputRequest::CreateEmptyRequest());
child_root_pass->damage_rect = gfx::Rect();
SubmitPassListAsFrame(child_support_.get(), child_local_surface_id,
&child_pass_list);
@@ -2133,7 +2130,8 @@ class SurfaceAggregatorWithResourcesTest : public testing::Test {
void SetUp() override {
shared_bitmap_manager_ = base::MakeUnique<cc::TestSharedBitmapManager>();
resource_provider_ =
- cc::FakeResourceProvider::Create(nullptr, shared_bitmap_manager_.get());
+ cc::FakeResourceProvider::Create<cc::DisplayResourceProvider>(
+ nullptr, shared_bitmap_manager_.get());
aggregator_ = base::MakeUnique<SurfaceAggregator>(
manager_.surface_manager(), resource_provider_.get(), false);
@@ -2143,17 +2141,17 @@ class SurfaceAggregatorWithResourcesTest : public testing::Test {
protected:
FrameSinkManagerImpl manager_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::ResourceProvider> resource_provider_;
+ std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
};
-void SubmitCompositorFrameWithResources(cc::ResourceId* resource_ids,
+void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
size_t num_resource_ids,
bool valid,
SurfaceId child_id,
CompositorFrameSinkSupport* support,
SurfaceId surface_id) {
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
auto pass = cc::RenderPass::Create();
pass->SetNew(1, gfx::Rect(0, 0, 20, 20), gfx::Rect(), gfx::Transform());
auto* sqs = pass->CreateAndAppendSharedQuadState();
@@ -2165,14 +2163,13 @@ void SubmitCompositorFrameWithResources(cc::ResourceId* resource_ids,
}
for (size_t i = 0u; i < num_resource_ids; ++i) {
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = resource_ids[i];
// ResourceProvider is software, so only software resources are valid.
resource.is_software = valid;
frame.resource_list.push_back(resource);
auto* quad = pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
const gfx::Rect rect;
- const gfx::Rect opaque_rect;
const gfx::Rect visible_rect;
bool needs_blending = false;
bool premultiplied_alpha = false;
@@ -2183,10 +2180,10 @@ void SubmitCompositorFrameWithResources(cc::ResourceId* resource_ids,
bool flipped = false;
bool nearest_neighbor = false;
bool secure_output_only = true;
- quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending,
- resource_ids[i], gfx::Size(), premultiplied_alpha, uv_top_left,
- uv_bottom_right, background_color, vertex_opacity, flipped,
- nearest_neighbor, secure_output_only);
+ quad->SetAll(sqs, rect, visible_rect, needs_blending, resource_ids[i],
+ gfx::Size(), premultiplied_alpha, uv_top_left, uv_bottom_right,
+ background_color, vertex_opacity, flipped, nearest_neighbor,
+ secure_output_only);
}
frame.render_pass_list.push_back(std::move(pass));
support->SubmitCompositorFrame(surface_id.local_surface_id(),
@@ -2197,11 +2194,11 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
cc::FakeCompositorFrameSinkSupportClient client;
auto support = CompositorFrameSinkSupport::Create(
&client, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
SurfaceId surface_id(support->frame_sink_id(), local_surface_id);
- cc::ResourceId ids[] = {11, 12, 13};
+ ResourceId ids[] = {11, 12, 13};
SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
support.get(), surface_id);
@@ -2216,7 +2213,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
frame = aggregator_->Aggregate(surface_id);
ASSERT_EQ(3u, client.returned_resources().size());
- cc::ResourceId returned_ids[3];
+ ResourceId returned_ids[3];
for (size_t i = 0; i < 3; ++i) {
returned_ids[i] = client.returned_resources()[i].id;
}
@@ -2233,13 +2230,13 @@ TEST_F(SurfaceAggregatorWithResourcesTest, ReturnResourcesAsSurfacesChange) {
cc::FakeCompositorFrameSinkSupportClient client;
auto support = CompositorFrameSinkSupport::Create(
&client, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId local_surface_id1(7u, base::UnguessableToken::Create());
LocalSurfaceId local_surface_id2(8u, base::UnguessableToken::Create());
SurfaceId surface_id1(support->frame_sink_id(), local_surface_id1);
SurfaceId surface_id2(support->frame_sink_id(), local_surface_id2);
- cc::ResourceId ids[] = {11, 12, 13};
+ ResourceId ids[] = {11, 12, 13};
SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
support.get(), surface_id1);
@@ -2256,7 +2253,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, ReturnResourcesAsSurfacesChange) {
frame = aggregator_->Aggregate(surface_id2);
ASSERT_EQ(3u, client.returned_resources().size());
- cc::ResourceId returned_ids[3];
+ ResourceId returned_ids[3];
for (size_t i = 0; i < 3; ++i) {
returned_ids[i] = client.returned_resources()[i].id;
}
@@ -2270,12 +2267,12 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
cc::FakeCompositorFrameSinkSupportClient client;
auto support = CompositorFrameSinkSupport::Create(
&client, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
SurfaceId surface_id(support->frame_sink_id(), local_surface_id);
- cc::CompositorFrame frame = cc::test::MakeCompositorFrame();
- cc::TransferableResource resource;
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
+ TransferableResource resource;
resource.id = 11;
// ResourceProvider is software but resource is not, so it should be
// ignored.
@@ -2299,21 +2296,19 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
cc::FakeCompositorFrameSinkSupportClient client;
auto support1 = CompositorFrameSinkSupport::Create(
- &client, &manager_, FrameSinkId(1, 1), kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ &client, &manager_, FrameSinkId(1, 1), kChildIsRoot, kNeedsSyncPoints);
auto support2 = CompositorFrameSinkSupport::Create(
- &client, &manager_, FrameSinkId(2, 2), kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ &client, &manager_, FrameSinkId(2, 2), kChildIsRoot, kNeedsSyncPoints);
LocalSurfaceId local_frame1_id(7u, base::UnguessableToken::Create());
SurfaceId surface1_id(support1->frame_sink_id(), local_frame1_id);
LocalSurfaceId local_frame2_id(8u, base::UnguessableToken::Create());
SurfaceId surface2_id(support2->frame_sink_id(), local_frame2_id);
- cc::ResourceId ids[] = {11, 12, 13};
+ ResourceId ids[] = {11, 12, 13};
SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
support1.get(), surface1_id);
- cc::ResourceId ids2[] = {14, 15, 16};
+ ResourceId ids2[] = {14, 15, 16};
SubmitCompositorFrameWithResources(ids2, arraysize(ids2), true, SurfaceId(),
support2.get(), surface2_id);
@@ -2329,7 +2324,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
// surface1_id wasn't referenced, so its resources should be returned.
ASSERT_EQ(3u, client.returned_resources().size());
- cc::ResourceId returned_ids[3];
+ ResourceId returned_ids[3];
for (size_t i = 0; i < 3; ++i) {
returned_ids[i] = client.returned_resources()[i].id;
}
@@ -2346,13 +2341,13 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
auto root_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
auto middle_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
auto child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId root_local_surface_id(7u, kArbitraryToken);
SurfaceId root_surface_id(root_support->frame_sink_id(),
root_local_surface_id);
@@ -2363,16 +2358,16 @@ TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
SurfaceId child_surface_id(child_support->frame_sink_id(),
child_local_surface_id);
- cc::ResourceId ids[] = {14, 15, 16};
+ ResourceId ids[] = {14, 15, 16};
SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
child_support.get(), child_surface_id);
- cc::ResourceId ids2[] = {17, 18, 19};
+ ResourceId ids2[] = {17, 18, 19};
SubmitCompositorFrameWithResources(ids2, arraysize(ids2), false,
child_surface_id, middle_support.get(),
middle_surface_id);
- cc::ResourceId ids3[] = {20, 21, 22};
+ ResourceId ids3[] = {20, 21, 22};
SubmitCompositorFrameWithResources(ids3, arraysize(ids3), true,
middle_surface_id, root_support.get(),
root_surface_id);
@@ -2402,18 +2397,16 @@ TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
auto support1 = CompositorFrameSinkSupport::Create(
- nullptr, &manager_, FrameSinkId(1, 1), kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ nullptr, &manager_, FrameSinkId(1, 1), kChildIsRoot, kNeedsSyncPoints);
auto support2 = CompositorFrameSinkSupport::Create(
- nullptr, &manager_, FrameSinkId(2, 2), kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ nullptr, &manager_, FrameSinkId(2, 2), kChildIsRoot, kNeedsSyncPoints);
LocalSurfaceId local_frame1_id(7u, base::UnguessableToken::Create());
SurfaceId surface1_id(support1->frame_sink_id(), local_frame1_id);
LocalSurfaceId local_frame2_id(8u, base::UnguessableToken::Create());
SurfaceId surface2_id(support2->frame_sink_id(), local_frame2_id);
- cc::ResourceId ids[] = {11, 12, 13};
+ ResourceId ids[] = {11, 12, 13};
SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
support1.get(), surface1_id);
@@ -2434,9 +2427,9 @@ TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
surface1_id, cc::SurfaceDrawQuadType::PRIMARY,
nullptr);
- pass->copy_requests.push_back(cc::CopyOutputRequest::CreateEmptyRequest());
+ pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest());
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
frame.render_pass_list.push_back(std::move(pass));
support2->SubmitCompositorFrame(local_frame2_id, std::move(frame));
@@ -2514,8 +2507,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageByChangingChildSurface) {
Pass child_surface_passes[] = {
Pass(child_surface_quads, arraysize(child_surface_quads), 1)};
- cc::CompositorFrame child_surface_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_surface_passes, arraysize(child_surface_passes));
@@ -2530,7 +2522,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageByChangingChildSurface) {
Pass root_passes[] = {
Pass(root_surface_quads, arraysize(root_surface_quads), 1)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -2552,8 +2544,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageByChangingChildSurface) {
// Change child_frame with damage should set the flag.
{
- cc::CompositorFrame child_surface_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_surface_passes, arraysize(child_surface_passes));
child_support_->SubmitCompositorFrame(child_local_surface_id,
@@ -2568,8 +2559,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageByChangingChildSurface) {
// Change child_frame without damage should not set the flag.
{
- cc::CompositorFrame child_surface_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_surface_passes, arraysize(child_surface_passes));
child_surface_frame.render_pass_list[0]->damage_rect = gfx::Rect();
@@ -2590,14 +2580,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
HasDamageByChangingGrandChildSurface) {
auto grand_child_support = CompositorFrameSinkSupport::Create(
nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
Quad child_surface_quads[] = {Quad::RenderPassQuad(1)};
Pass child_surface_passes[] = {
Pass(child_surface_quads, arraysize(child_surface_quads), 1)};
- cc::CompositorFrame child_surface_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_surface_passes, arraysize(child_surface_passes));
@@ -2612,7 +2601,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
Pass root_passes[] = {
Pass(root_surface_quads, arraysize(root_surface_quads), 1)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -2640,8 +2629,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
SurfaceId grand_child_surface_id(grand_child_support->frame_sink_id(),
grand_child_local_surface_id);
{
- cc::CompositorFrame grand_child_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame grand_child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&grand_child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
grand_child_passes, arraysize(grand_child_passes));
@@ -2653,7 +2641,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
Quad::SurfaceQuad(grand_child_surface_id, InvalidSurfaceId(), 1.f)};
Pass new_child_surface_passes[] = {
Pass(new_child_surface_quads, arraysize(new_child_surface_quads), 1)};
- child_surface_frame = cc::test::MakeEmptyCompositorFrame();
+ child_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
new_child_surface_passes, arraysize(new_child_surface_passes));
child_support_->SubmitCompositorFrame(child_local_surface_id,
@@ -2676,8 +2664,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// Change grand_child_frame with damage should set the flag.
{
- cc::CompositorFrame grand_child_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame grand_child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&grand_child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
grand_child_passes, arraysize(grand_child_passes));
grand_child_support->SubmitCompositorFrame(grand_child_local_surface_id,
@@ -2692,8 +2679,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// Change grand_child_frame without damage should not set the flag.
{
- cc::CompositorFrame grand_child_frame =
- cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame grand_child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&grand_child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
grand_child_passes, arraysize(grand_child_passes));
grand_child_frame.render_pass_list[0]->damage_rect = gfx::Rect();
@@ -2716,7 +2702,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageFromRenderPassQuads) {
Quad child_quads[] = {Quad::RenderPassQuad(1)};
Pass child_passes[] = {Pass(child_quads, arraysize(child_quads), 1)};
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -2734,7 +2720,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageFromRenderPassQuads) {
Pass(root_surface_quads, arraysize(root_surface_quads), 1),
Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -2762,7 +2748,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, HasDamageFromRenderPassQuads) {
// Changing child_frame should damage both render_pass.
{
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
child_support_->SubmitCompositorFrame(child_local_surface_id,
@@ -2789,7 +2775,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectOfCachedRenderPass) {
Pass(root_quads[0], arraysize(root_quads[0]), pass_id[0]),
Pass(root_quads[1], arraysize(root_quads[1]), pass_id[1])};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -2812,7 +2798,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectOfCachedRenderPass) {
// For offscreen render pass, only the visible area is damaged.
{
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -2839,7 +2825,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectOfCachedRenderPass) {
// For offscreen cached render pass, should have full damage.
{
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -2878,7 +2864,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
Pass(child_quads[0], arraysize(child_quads[0]), pass_id[0]),
Pass(child_quads[1], arraysize(child_quads[1]), pass_id[1])};
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -2894,7 +2880,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
Pass root_passes[] = {
Pass(root_surface_quads, arraysize(root_surface_quads), 1)};
- cc::CompositorFrame root_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -2917,7 +2903,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// For offscreen render pass, only the visible area is damaged.
{
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -2944,7 +2930,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// For offscreen cached render pass, should have full damage.
{
- cc::CompositorFrame child_frame = cc::test::MakeEmptyCompositorFrame();
+ cc::CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS
index f97559d9f01..731d0f6f3d7 100644
--- a/chromium/components/viz/service/display_embedder/DEPS
+++ b/chromium/components/viz/service/display_embedder/DEPS
@@ -4,7 +4,6 @@ include_rules = [
"+cc/output",
"+cc/resources",
"+cc/scheduler",
- "+cc/surfaces",
"+gpu/GLES2",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
@@ -17,8 +16,6 @@ include_rules = [
"+mojo/public/cpp/system",
"+third_party/skia",
"+ui/display",
- "+ui/gfx",
- "+ui/gfx/geometry",
"+ui/gl",
"+ui/latency",
"+ui/ozone/public",
diff --git a/chromium/components/viz/service/display_embedder/OWNERS b/chromium/components/viz/service/display_embedder/OWNERS
deleted file mode 100644
index 68de279ade5..00000000000
--- a/chromium/components/viz/service/display_embedder/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-piman@chromium.org
-danakj@chromium.org
-jbauman@chromium.org
-ccameron@chromium.org
-
-# COMPONENT: Internals>Compositing
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue.h b/chromium/components/viz/service/display_embedder/buffer_queue.h
index 2ab4915857f..3fa44abfd0d 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue.h
+++ b/chromium/components/viz/service/display_embedder/buffer_queue.h
@@ -7,10 +7,10 @@
#include <stddef.h>
-#include <deque>
#include <memory>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/viz/service/viz_service_export.h"
@@ -124,7 +124,7 @@ class VIZ_SERVICE_EXPORT BufferQueue {
std::vector<std::unique_ptr<AllocatedSurface>> available_surfaces_;
// These have been swapped but are not displayed yet. Entries of this deque
// may be nullptr, if they represent frames that have been destroyed.
- std::deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
+ base::circular_deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
GLHelper* gl_helper_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
gpu::SurfaceHandle surface_handle_;
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
index e3bb2e77ed8..8d940ead820 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -13,9 +13,9 @@
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "cc/test/test_context_provider.h"
-#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "components/viz/common/gl_helper.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -59,7 +59,7 @@ class StubGpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
size_t* set_color_space_count_;
};
-class StubGpuMemoryBufferManager : public cc::TestGpuMemoryBufferManager {
+class StubGpuMemoryBufferManager : public TestGpuMemoryBufferManager {
public:
StubGpuMemoryBufferManager() : allocate_succeeds_(true) {}
@@ -139,7 +139,7 @@ class BufferQueueTest : public ::testing::Test {
available_surfaces() {
return output_surface_->available_surfaces_;
}
- std::deque<std::unique_ptr<BufferQueue::AllocatedSurface>>&
+ base::circular_deque<std::unique_ptr<BufferQueue::AllocatedSurface>>&
in_flight_surfaces() {
return output_surface_->in_flight_surfaces_;
}
diff --git a/chromium/components/viz/service/display_embedder/display_output_surface.cc b/chromium/components/viz/service/display_embedder/display_output_surface.cc
index b293f8b82ce..2efabbe12c2 100644
--- a/chromium/components/viz/service/display_embedder/display_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/display_output_surface.cc
@@ -11,16 +11,17 @@
#include "base/threading/thread_task_runner_handle.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/output_surface_frame.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/gpu/context_provider.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gl/gl_utils.h"
namespace viz {
DisplayOutputSurface::DisplayOutputSurface(
scoped_refptr<InProcessContextProvider> context_provider,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source)
+ SyntheticBeginFrameSource* synthetic_begin_frame_source)
: cc::OutputSurface(context_provider),
synthetic_begin_frame_source_(synthetic_begin_frame_source),
weak_ptr_factory_(this) {
@@ -74,7 +75,8 @@ void DisplayOutputSurface::Reshape(const gfx::Size& size,
size_ = size;
has_set_draw_rectangle_since_last_resize_ = false;
context_provider()->ContextGL()->ResizeCHROMIUM(
- size.width(), size.height(), device_scale_factor, has_alpha);
+ size.width(), size.height(), device_scale_factor,
+ gl::GetGLColorSpace(color_space), has_alpha);
}
void DisplayOutputSurface::SwapBuffers(cc::OutputSurfaceFrame frame) {
@@ -146,7 +148,7 @@ void DisplayOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase,
// TODO(brianderson): We should not be receiving 0 intervals.
synthetic_begin_frame_source_->OnUpdateVSyncParameters(
timebase,
- interval.is_zero() ? cc::BeginFrameArgs::DefaultInterval() : interval);
+ interval.is_zero() ? BeginFrameArgs::DefaultInterval() : interval);
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/display_output_surface.h b/chromium/components/viz/service/display_embedder/display_output_surface.h
index 7e59c6a160b..6981fb3cec5 100644
--- a/chromium/components/viz/service/display_embedder/display_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/display_output_surface.h
@@ -11,19 +11,16 @@
#include "components/viz/common/gpu/in_process_context_provider.h"
#include "ui/latency/latency_tracker.h"
-namespace cc {
-class SyntheticBeginFrameSource;
-}
-
namespace viz {
+class SyntheticBeginFrameSource;
+
// An OutputSurface implementation that directly draws and
// swaps to an actual GL surface.
class DisplayOutputSurface : public cc::OutputSurface {
public:
- DisplayOutputSurface(
- scoped_refptr<InProcessContextProvider> context_provider,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source);
+ DisplayOutputSurface(scoped_refptr<InProcessContextProvider> context_provider,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source);
~DisplayOutputSurface() override;
// cc::OutputSurface implementation
@@ -63,7 +60,7 @@ class DisplayOutputSurface : public cc::OutputSurface {
base::TimeDelta interval);
cc::OutputSurfaceClient* client_ = nullptr;
- cc::SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
+ SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
ui::LatencyTracker latency_tracker_;
bool set_draw_rectangle_for_frame_ = false;
diff --git a/chromium/components/viz/service/display_embedder/display_output_surface_ozone.cc b/chromium/components/viz/service/display_embedder/display_output_surface_ozone.cc
index 42df4118c21..6b3398be38b 100644
--- a/chromium/components/viz/service/display_embedder/display_output_surface_ozone.cc
+++ b/chromium/components/viz/service/display_embedder/display_output_surface_ozone.cc
@@ -10,7 +10,7 @@
#include "base/memory/ptr_util.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/output_surface_frame.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
#include "gpu/command_buffer/client/context_support.h"
@@ -22,7 +22,7 @@ namespace viz {
DisplayOutputSurfaceOzone::DisplayOutputSurfaceOzone(
scoped_refptr<InProcessContextProvider> context_provider,
gfx::AcceleratedWidget widget,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
uint32_t target,
uint32_t internalformat)
diff --git a/chromium/components/viz/service/display_embedder/display_output_surface_ozone.h b/chromium/components/viz/service/display_embedder/display_output_surface_ozone.h
index f49180cf708..4d448d2c662 100644
--- a/chromium/components/viz/service/display_embedder/display_output_surface_ozone.h
+++ b/chromium/components/viz/service/display_embedder/display_output_surface_ozone.h
@@ -18,10 +18,6 @@
#include "ui/gfx/swap_result.h"
#include "ui/gl/gl_surface.h"
-namespace cc {
-class SyntheticBeginFrameSource;
-}
-
namespace gpu {
class GpuMemoryBufferManager;
}
@@ -29,6 +25,7 @@ class GpuMemoryBufferManager;
namespace viz {
class BufferQueue;
+class SyntheticBeginFrameSource;
// An OutputSurface implementation that directly draws and swap to a GL
// "surfaceless" surface (aka one backed by a buffer managed explicitly in
@@ -39,7 +36,7 @@ class DisplayOutputSurfaceOzone : public DisplayOutputSurface {
DisplayOutputSurfaceOzone(
scoped_refptr<InProcessContextProvider> context_provider,
gfx::AcceleratedWidget widget,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
uint32_t target,
uint32_t internalformat);
diff --git a/chromium/components/viz/service/display_embedder/display_provider.h b/chromium/components/viz/service/display_embedder/display_provider.h
index a6cba01d045..d490bf29046 100644
--- a/chromium/components/viz/service/display_embedder/display_provider.h
+++ b/chromium/components/viz/service/display_embedder/display_provider.h
@@ -9,13 +9,12 @@
#include "gpu/ipc/common/surface_handle.h"
-namespace cc {
-class BeginFrameSource;
-class FrameSinkId;
-} // namespace cc
-
namespace viz {
+
+class BeginFrameSource;
class Display;
+class FrameSinkId;
+class RendererSettings;
// Handles creating Display and related classes for FrameSinkManagerImpl.
class DisplayProvider {
@@ -23,11 +22,12 @@ class DisplayProvider {
virtual ~DisplayProvider() {}
// Creates a new Display for |surface_handle| with |frame_sink_id|. Will
- // also create cc::BeginFrameSource and return it in |begin_frame_source|.
+ // also create BeginFrameSource and return it in |begin_frame_source|.
virtual std::unique_ptr<Display> CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
- std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) = 0;
+ const RendererSettings& renderer_settings,
+ std::unique_ptr<BeginFrameSource>* begin_frame_source) = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
index 57f6f16e8bb..e59a33fbc5b 100644
--- a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -11,7 +11,8 @@
#include "base/threading/thread_task_runner_handle.h"
#include "cc/base/switches.h"
#include "cc/output/texture_mailbox_deleter.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/gpu/in_process_context_provider.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/display_scheduler.h"
@@ -22,6 +23,7 @@
#include "gpu/command_buffer/service/image_factory.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
+#include "ui/base/ui_base_switches.h"
#if defined(USE_OZONE)
#include "components/viz/service/display_embedder/display_output_surface_ozone.h"
@@ -54,10 +56,11 @@ GpuDisplayProvider::~GpuDisplayProvider() = default;
std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
- std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) {
+ const RendererSettings& renderer_settings,
+ std::unique_ptr<BeginFrameSource>* begin_frame_source) {
auto synthetic_begin_frame_source =
- base::MakeUnique<cc::DelayBasedBeginFrameSource>(
- base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get()));
+ base::MakeUnique<DelayBasedBeginFrameSource>(
+ base::MakeUnique<DelayBasedTimeSource>(task_runner_.get()));
scoped_refptr<InProcessContextProvider> context_provider =
new InProcessContextProvider(gpu_service_, surface_handle,
@@ -91,17 +94,12 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
synthetic_begin_frame_source.get(), task_runner_.get(),
max_frames_pending);
- RendererSettings settings;
- settings.show_overdraw_feedback =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kShowOverdrawFeedback);
-
// The ownership of the BeginFrameSource is transfered to the caller.
*begin_frame_source = std::move(synthetic_begin_frame_source);
return base::MakeUnique<Display>(
ServerSharedBitmapManager::current(), gpu_memory_buffer_manager_.get(),
- settings, frame_sink_id, std::move(display_output_surface),
+ renderer_settings, frame_sink_id, std::move(display_output_surface),
std::move(scheduler),
base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get()));
}
diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.h b/chromium/components/viz/service/display_embedder/gpu_display_provider.h
index f9c320ccb18..833e05da9ac 100644
--- a/chromium/components/viz/service/display_embedder/gpu_display_provider.h
+++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.h
@@ -26,8 +26,7 @@ namespace viz {
class Display;
// In-process implementation of DisplayProvider.
-class VIZ_SERVICE_EXPORT GpuDisplayProvider
- : public NON_EXPORTED_BASE(DisplayProvider) {
+class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
public:
GpuDisplayProvider(
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
@@ -38,7 +37,8 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider
std::unique_ptr<Display> CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
- std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) override;
+ const RendererSettings& renderer_settings,
+ std::unique_ptr<BeginFrameSource>* begin_frame_source) override;
private:
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
index 07a45c9b72b..840bf1989cb 100644
--- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
+++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -139,17 +139,17 @@ bool ServerSharedBitmapManager::OnMemoryDump(
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
bitmap.second->buffer_size);
- // Generate a global GUID used to share this allocation with renderer
- // processes.
- auto guid = GetSharedBitmapGUIDForTracing(bitmap.first);
- base::UnguessableToken shared_memory_guid;
if (bitmap.second->memory) {
- shared_memory_guid = bitmap.second->memory->mapped_id();
+ base::UnguessableToken shared_memory_guid =
+ bitmap.second->memory->mapped_id();
if (!shared_memory_guid.is_empty()) {
- pmd->CreateSharedMemoryOwnershipEdge(
- dump->guid(), guid, shared_memory_guid, 0 /* importance*/);
+ pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid,
+ 0 /* importance*/);
}
} else {
+ // Generate a global GUID used to share this allocation with renderer
+ // processes.
+ auto guid = GetSharedBitmapGUIDForTracing(bitmap.first);
pmd->CreateSharedGlobalAllocatorDump(guid);
pmd->AddOwnershipEdge(dump->guid(), guid);
}
diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
index cd801a181e6..ebffeabcc09 100644
--- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
+++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
@@ -26,7 +26,7 @@ class BitmapData;
// malloc/free, but can only be used in the same process as the display
// compositor.
class VIZ_SERVICE_EXPORT ServerSharedBitmapManager
- : public NON_EXPORTED_BASE(SharedBitmapManager),
+ : public SharedBitmapManager,
public base::trace_event::MemoryDumpProvider {
public:
ServerSharedBitmapManager();
diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
index d320a3dee75..bc81f591acd 100644
--- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
+++ b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
@@ -21,7 +21,7 @@ SharedBitmapAllocationNotifierImpl::~SharedBitmapAllocationNotifierImpl() {
}
void SharedBitmapAllocationNotifierImpl::Bind(
- cc::mojom::SharedBitmapAllocationNotifierRequest request) {
+ mojom::SharedBitmapAllocationNotifierRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (binding_.is_bound()) {
DLOG(ERROR) << "Only one SharedBitmapAllocationNotifierRequest is "
diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
index 4e9330a5759..cd3faf241ae 100644
--- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
+++ b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
@@ -9,10 +9,10 @@
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
#include "components/viz/common/quads/shared_bitmap.h"
#include "components/viz/service/viz_service_export.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/public/interfaces/compositing/shared_bitmap_allocation_notifier.mojom.h"
namespace viz {
class ServerSharedBitmapManager;
@@ -23,7 +23,7 @@ class SharedBitmapAllocationObserver {
};
class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl
- : NON_EXPORTED_BASE(public cc::mojom::SharedBitmapAllocationNotifier) {
+ : public mojom::SharedBitmapAllocationNotifier {
public:
explicit SharedBitmapAllocationNotifierImpl(
ServerSharedBitmapManager* manager);
@@ -33,9 +33,9 @@ class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl
void AddObserver(SharedBitmapAllocationObserver* observer);
void RemoveObserver(SharedBitmapAllocationObserver* observer);
- void Bind(cc::mojom::SharedBitmapAllocationNotifierRequest request);
+ void Bind(mojom::SharedBitmapAllocationNotifierRequest request);
- // cc::mojom::SharedBitmapAllocationNotifier overrides:
+ // mojom::SharedBitmapAllocationNotifier overrides:
void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
const SharedBitmapId& id) override;
void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
@@ -51,7 +51,7 @@ class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl
private:
THREAD_CHECKER(thread_checker_);
ServerSharedBitmapManager* const manager_;
- mojo::Binding<cc::mojom::SharedBitmapAllocationNotifier> binding_;
+ mojo::Binding<mojom::SharedBitmapAllocationNotifier> binding_;
std::unordered_set<SharedBitmapId, SharedBitmapIdHash> owned_bitmaps_;
base::ObserverList<SharedBitmapAllocationObserver> observers_;
uint32_t last_sequence_number_ = 0;
diff --git a/chromium/components/viz/service/frame_sinks/DEPS b/chromium/components/viz/service/frame_sinks/DEPS
index af562e205c4..7b7b9b0af38 100644
--- a/chromium/components/viz/service/frame_sinks/DEPS
+++ b/chromium/components/viz/service/frame_sinks/DEPS
@@ -1,8 +1,8 @@
include_rules = [
"+cc/base",
"+cc/ipc",
- "+cc/surfaces",
"+cc/scheduler",
+ "+components/viz/service/surfaces",
"+gpu/ipc/common",
"+mojo/public/cpp/bindings",
]
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
new file mode 100644
index 00000000000..830ca2ccf8f
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -0,0 +1,86 @@
+// 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/viz/service/frame_sinks/compositor_frame_sink_impl.h"
+
+#include <utility>
+
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+
+namespace viz {
+
+CompositorFrameSinkImpl::CompositorFrameSinkImpl(
+ FrameSinkManagerImpl* frame_sink_manager,
+ const FrameSinkId& frame_sink_id,
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client)
+ : support_(
+ CompositorFrameSinkSupport::Create(this,
+ frame_sink_manager,
+ frame_sink_id,
+ false /* is_root */,
+ true /* needs_sync_points */)),
+ client_(std::move(client)),
+ compositor_frame_sink_binding_(this, std::move(request)) {
+ compositor_frame_sink_binding_.set_connection_error_handler(
+ base::Bind(&CompositorFrameSinkImpl::OnClientConnectionLost,
+ base::Unretained(this)));
+}
+
+CompositorFrameSinkImpl::~CompositorFrameSinkImpl() = default;
+
+void CompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) {
+ support_->SetNeedsBeginFrame(needs_begin_frame);
+}
+
+void CompositorFrameSinkImpl::SubmitCompositorFrame(
+ const LocalSurfaceId& local_surface_id,
+ cc::CompositorFrame frame,
+ mojom::HitTestRegionListPtr hit_test_region_list,
+ uint64_t submit_time) {
+ // TODO(gklassen): Route hit-test data to the appropriate HitTestAggregator.
+ if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
+ compositor_frame_sink_binding_.CloseWithReason(
+ 1, "Surface invariants violation");
+ OnClientConnectionLost();
+ }
+}
+
+void CompositorFrameSinkImpl::DidNotProduceFrame(
+ const BeginFrameAck& begin_frame_ack) {
+ support_->DidNotProduceFrame(begin_frame_ack);
+}
+
+void CompositorFrameSinkImpl::DidReceiveCompositorFrameAck(
+ const std::vector<ReturnedResource>& resources) {
+ if (client_)
+ client_->DidReceiveCompositorFrameAck(resources);
+}
+
+void CompositorFrameSinkImpl::OnBeginFrame(const BeginFrameArgs& args) {
+ if (client_)
+ client_->OnBeginFrame(args);
+}
+
+void CompositorFrameSinkImpl::OnBeginFramePausedChanged(bool paused) {
+ if (client_)
+ client_->OnBeginFramePausedChanged(paused);
+}
+
+void CompositorFrameSinkImpl::ReclaimResources(
+ const std::vector<ReturnedResource>& resources) {
+ if (client_)
+ client_->ReclaimResources(resources);
+}
+
+void CompositorFrameSinkImpl::WillDrawSurface(
+ const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) {}
+
+void CompositorFrameSinkImpl::OnClientConnectionLost() {
+ support_->frame_sink_manager()->OnClientConnectionLost(
+ support_->frame_sink_id());
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
new file mode 100644
index 00000000000..b32cd25f2f4
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -0,0 +1,64 @@
+// 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_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+
+namespace viz {
+
+// Server side representation of a WindowSurface.
+class CompositorFrameSinkImpl : public CompositorFrameSinkSupportClient,
+ public mojom::CompositorFrameSink {
+ public:
+ CompositorFrameSinkImpl(FrameSinkManagerImpl* frame_sink_manager,
+ const FrameSinkId& frame_sink_id,
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client);
+
+ ~CompositorFrameSinkImpl() override;
+
+ // mojom::CompositorFrameSink:
+ void SetNeedsBeginFrame(bool needs_begin_frame) override;
+ void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
+ cc::CompositorFrame frame,
+ mojom::HitTestRegionListPtr hit_test_region_list,
+ uint64_t submit_time) override;
+ void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override;
+
+ private:
+ // CompositorFrameSinkSupportClient implementation:
+ void DidReceiveCompositorFrameAck(
+ const std::vector<ReturnedResource>& resources) override;
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ void OnBeginFramePausedChanged(bool paused) override;
+ void ReclaimResources(
+ const std::vector<ReturnedResource>& resources) override;
+ void WillDrawSurface(const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) override;
+
+ void OnClientConnectionLost();
+
+ std::unique_ptr<CompositorFrameSinkSupport> support_;
+
+ mojom::CompositorFrameSinkClientPtr client_;
+ mojo::Binding<mojom::CompositorFrameSink> compositor_frame_sink_binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkImpl);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_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 c13c567fc5b..48f767d7529 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
@@ -8,13 +8,13 @@
#include <utility>
#include "cc/output/compositor_frame.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_reference.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_reference.h"
namespace viz {
@@ -24,12 +24,10 @@ std::unique_ptr<CompositorFrameSinkSupport> CompositorFrameSinkSupport::Create(
FrameSinkManagerImpl* frame_sink_manager,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_tokens) {
std::unique_ptr<CompositorFrameSinkSupport> support =
base::WrapUnique(new CompositorFrameSinkSupport(
- client, frame_sink_id, is_root, handles_frame_sink_id_invalidation,
- needs_sync_tokens));
+ client, frame_sink_id, is_root, needs_sync_tokens));
support->Init(frame_sink_manager);
return support;
}
@@ -38,8 +36,8 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() {
if (!destruction_callback_.is_null())
std::move(destruction_callback_).Run();
- // Unregister |this| as a cc::BeginFrameObserver so that the
- // cc::BeginFrameSource does not call into |this| after it's deleted.
+ // Unregister |this| as a BeginFrameObserver so that the
+ // BeginFrameSource does not call into |this| after it's deleted.
SetNeedsBeginFrame(false);
// For display root surfaces the surface is no longer going to be visible.
@@ -52,8 +50,6 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() {
EvictCurrentSurface();
frame_sink_manager_->UnregisterFrameSinkManagerClient(frame_sink_id_);
- if (handles_frame_sink_id_invalidation_)
- surface_manager_->InvalidateFrameSinkId(frame_sink_id_);
}
void CompositorFrameSinkSupport::SetDestructionCallback(
@@ -61,42 +57,26 @@ void CompositorFrameSinkSupport::SetDestructionCallback(
destruction_callback_ = std::move(callback);
}
-void CompositorFrameSinkSupport::OnSurfaceActivated(cc::Surface* surface) {
+void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
+ DCHECK(surface);
DCHECK(surface->HasActiveFrame());
- const cc::CompositorFrame& frame = surface->GetActiveFrame();
- if (!seen_first_frame_activation_) {
- // cc::SurfaceCreated only applies for the first cc::Surface activation.
- seen_first_frame_activation_ = true;
-
- gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
- surface_manager_->SurfaceCreated(SurfaceInfo(
- surface->surface_id(), frame.metadata.device_scale_factor, frame_size));
- }
- // Fire cc::SurfaceCreated first so that a temporary reference is added before
- // it is potentially transformed into a real reference by the client.
DCHECK(surface->active_referenced_surfaces());
UpdateSurfaceReferences(surface->surface_id().local_surface_id(),
*surface->active_referenced_surfaces());
- if (!surface_manager_->SurfaceModified(surface->surface_id(),
- frame.metadata.begin_frame_ack)) {
- TRACE_EVENT_INSTANT0("cc", "Damage not visible.", TRACE_EVENT_SCOPE_THREAD);
- surface->RunDrawCallback();
- }
- surface_manager_->SurfaceActivated(surface);
}
void CompositorFrameSinkSupport::RefResources(
- const std::vector<cc::TransferableResource>& resources) {
+ const std::vector<TransferableResource>& resources) {
surface_resource_holder_.RefResources(resources);
}
void CompositorFrameSinkSupport::UnrefResources(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
surface_resource_holder_.UnrefResources(resources);
}
void CompositorFrameSinkSupport::ReturnResources(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
if (resources.empty())
return;
if (!ack_pending_count_ && client_) {
@@ -109,12 +89,12 @@ void CompositorFrameSinkSupport::ReturnResources(
}
void CompositorFrameSinkSupport::ReceiveFromChild(
- const std::vector<cc::TransferableResource>& resources) {
+ const std::vector<TransferableResource>& resources) {
surface_resource_holder_.ReceiveFromChild(resources);
}
void CompositorFrameSinkSupport::SetBeginFrameSource(
- cc::BeginFrameSource* begin_frame_source) {
+ BeginFrameSource* begin_frame_source) {
if (begin_frame_source_ && added_frame_observer_) {
begin_frame_source_->RemoveObserver(this);
added_frame_observer_ = false;
@@ -136,12 +116,11 @@ void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) {
UpdateNeedsBeginFramesInternal();
}
-void CompositorFrameSinkSupport::DidNotProduceFrame(
- const cc::BeginFrameAck& ack) {
+void CompositorFrameSinkSupport::DidNotProduceFrame(const BeginFrameAck& ack) {
TRACE_EVENT2("cc", "CompositorFrameSinkSupport::DidNotProduceFrame",
"ack.source_id", ack.source_id, "ack.sequence_number",
ack.sequence_number);
- DCHECK_GE(ack.sequence_number, cc::BeginFrameArgs::kStartingFrameNumber);
+ DCHECK_GE(ack.sequence_number, BeginFrameArgs::kStartingFrameNumber);
// |has_damage| is not transmitted, but false by default.
DCHECK(!ack.has_damage);
@@ -160,12 +139,13 @@ bool CompositorFrameSinkSupport::SubmitCompositorFrame(
DCHECK(local_surface_id.is_valid());
DCHECK(!frame.render_pass_list.empty());
+ uint64_t frame_index = ++last_frame_index_;
++ack_pending_count_;
// |has_damage| is not transmitted.
frame.metadata.begin_frame_ack.has_damage = true;
- cc::BeginFrameAck ack = frame.metadata.begin_frame_ack;
- DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
+ BeginFrameAck ack = frame.metadata.begin_frame_ack;
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
if (!ui::LatencyInfo::Verify(frame.metadata.latency_info,
"RenderWidgetHostImpl::OnSwapCompositorFrame")) {
@@ -178,24 +158,23 @@ bool CompositorFrameSinkSupport::SubmitCompositorFrame(
}
}
- cc::Surface* prev_surface =
+ Surface* prev_surface =
surface_manager_->GetSurfaceForId(current_surface_id_);
- cc::Surface* current_surface = nullptr;
+ Surface* current_surface = nullptr;
if (prev_surface &&
local_surface_id == current_surface_id_.local_surface_id()) {
current_surface = prev_surface;
} else {
SurfaceId surface_id(frame_sink_id_, local_surface_id);
- gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
- float device_scale_factor = frame.metadata.device_scale_factor;
- SurfaceInfo surface_info(surface_id, device_scale_factor, frame_size);
+ SurfaceInfo surface_info(surface_id, frame.device_scale_factor(),
+ frame.size_in_pixels());
if (!surface_info.is_valid()) {
TRACE_EVENT_INSTANT0("cc", "Invalid SurfaceInfo",
TRACE_EVENT_SCOPE_THREAD);
EvictCurrentSurface();
- std::vector<cc::ReturnedResource> resources =
- cc::TransferableResource::ReturnResources(frame.resource_list);
+ std::vector<ReturnedResource> resources =
+ TransferableResource::ReturnResources(frame.resource_list);
ReturnResources(resources);
DidReceiveCompositorFrameAck();
return true;
@@ -208,9 +187,9 @@ bool CompositorFrameSinkSupport::SubmitCompositorFrame(
}
bool result = current_surface->QueueFrame(
- std::move(frame),
- base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck,
- weak_factory_.GetWeakPtr()),
+ std::move(frame), frame_index,
+ base::BindOnce(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck,
+ weak_factory_.GetWeakPtr()),
base::BindRepeating(&CompositorFrameSinkSupport::WillDrawSurface,
weak_factory_.GetWeakPtr()));
@@ -245,8 +224,8 @@ void CompositorFrameSinkSupport::UpdateSurfaceReferences(
// Populate list of surface references to add and remove by getting the
// difference between existing surface references and surface references for
// latest activated CompositorFrame.
- std::vector<cc::SurfaceReference> references_to_add;
- std::vector<cc::SurfaceReference> references_to_remove;
+ std::vector<SurfaceReference> references_to_add;
+ std::vector<SurfaceReference> references_to_remove;
GetSurfaceReferenceDifference(surface_id, existing_referenced_surfaces,
new_referenced_surfaces, &references_to_add,
&references_to_remove);
@@ -266,16 +245,16 @@ void CompositorFrameSinkSupport::UpdateSurfaceReferences(
referenced_local_surface_id_ = local_surface_id;
}
- // Modify surface references stored in cc::SurfaceManager.
+ // Modify surface references stored in SurfaceManager.
if (!references_to_add.empty())
surface_manager_->AddSurfaceReferences(references_to_add);
if (!references_to_remove.empty())
surface_manager_->RemoveSurfaceReferences(references_to_remove);
}
-cc::SurfaceReference CompositorFrameSinkSupport::MakeTopLevelRootReference(
+SurfaceReference CompositorFrameSinkSupport::MakeTopLevelRootReference(
const SurfaceId& surface_id) {
- return cc::SurfaceReference(surface_manager_->GetRootSurfaceId(), surface_id);
+ return SurfaceReference(surface_manager_->GetRootSurfaceId(), surface_id);
}
void CompositorFrameSinkSupport::DidReceiveCompositorFrameAck() {
@@ -295,45 +274,35 @@ void CompositorFrameSinkSupport::WillDrawSurface(
client_->WillDrawSurface(local_surface_id, damage_rect);
}
-void CompositorFrameSinkSupport::ClaimTemporaryReference(
- const SurfaceId& surface_id) {
- surface_manager_->AssignTemporaryReference(surface_id, frame_sink_id_);
-}
-
CompositorFrameSinkSupport::CompositorFrameSinkSupport(
CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_tokens)
: client_(client),
frame_sink_id_(frame_sink_id),
surface_resource_holder_(this),
is_root_(is_root),
needs_sync_tokens_(needs_sync_tokens),
- handles_frame_sink_id_invalidation_(handles_frame_sink_id_invalidation),
weak_factory_(this) {}
void CompositorFrameSinkSupport::Init(
FrameSinkManagerImpl* frame_sink_manager) {
frame_sink_manager_ = frame_sink_manager;
surface_manager_ = frame_sink_manager->surface_manager();
- if (handles_frame_sink_id_invalidation_)
- surface_manager_->RegisterFrameSinkId(frame_sink_id_);
frame_sink_manager_->RegisterFrameSinkManagerClient(frame_sink_id_, this);
}
-void CompositorFrameSinkSupport::OnBeginFrame(const cc::BeginFrameArgs& args) {
+void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) {
UpdateNeedsBeginFramesInternal();
- if (current_surface_id_.is_valid()) {
+ if (current_surface_id_.is_valid())
surface_manager_->SurfaceDamageExpected(current_surface_id_, args);
- }
last_begin_frame_args_ = args;
if (client_)
client_->OnBeginFrame(args);
}
-const cc::BeginFrameArgs& CompositorFrameSinkSupport::LastUsedBeginFrameArgs()
+const BeginFrameArgs& CompositorFrameSinkSupport::LastUsedBeginFrameArgs()
const {
return last_begin_frame_args_;
}
@@ -357,28 +326,27 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() {
begin_frame_source_->RemoveObserver(this);
}
-cc::Surface* CompositorFrameSinkSupport::CreateSurface(
+Surface* CompositorFrameSinkSupport::CreateSurface(
const SurfaceInfo& surface_info) {
- seen_first_frame_activation_ = false;
return surface_manager_->CreateSurface(
weak_factory_.GetWeakPtr(), surface_info,
frame_sink_manager_->GetPrimaryBeginFrameSource(), needs_sync_tokens_);
}
void CompositorFrameSinkSupport::RequestCopyOfSurface(
- std::unique_ptr<cc::CopyOutputRequest> copy_request) {
+ std::unique_ptr<CopyOutputRequest> copy_request) {
if (!current_surface_id_.is_valid())
return;
- cc::Surface* current_surface =
+ Surface* current_surface =
surface_manager_->GetSurfaceForId(current_surface_id_);
current_surface->RequestCopyOfOutput(std::move(copy_request));
- cc::BeginFrameAck ack;
+ BeginFrameAck ack;
ack.has_damage = true;
if (current_surface->HasActiveFrame())
surface_manager_->SurfaceModified(current_surface->surface_id(), ack);
}
-cc::Surface* CompositorFrameSinkSupport::GetCurrentSurfaceForTesting() {
+Surface* CompositorFrameSinkSupport::GetCurrentSurfaceForTesting() {
return surface_manager_->GetSurfaceForId(current_surface_id_);
}
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index ccf7f398c64..70d13c43478 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -13,37 +13,39 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "cc/output/compositor_frame.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_client.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_client.h"
#include "components/viz/service/frame_sinks/referenced_surface_tracker.h"
#include "components/viz/service/frame_sinks/surface_resource_holder.h"
#include "components/viz/service/frame_sinks/surface_resource_holder_client.h"
+#include "components/viz/service/surfaces/surface_client.h"
#include "components/viz/service/viz_service_export.h"
-namespace cc {
-class Surface;
-class SurfaceManager;
-} // namespace cc
+namespace {
+// The frame index starts at 2 so that empty frames will be treated as
+// completely damaged the first time they're drawn from.
+constexpr int kFrameIndexStart = 2;
+} // namespace
namespace viz {
class FrameSinkManagerImpl;
class CompositorFrameSinkSupportClient;
+class Surface;
+class SurfaceManager;
class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
- : public cc::BeginFrameObserver,
+ : public BeginFrameObserver,
public SurfaceResourceHolderClient,
public FrameSinkManagerClient,
- public cc::SurfaceClient {
+ public SurfaceClient {
public:
static std::unique_ptr<CompositorFrameSinkSupport> Create(
CompositorFrameSinkSupportClient* client,
FrameSinkManagerImpl* frame_sink_manager,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_tokens);
~CompositorFrameSinkSupport() override;
@@ -51,39 +53,35 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
const FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
FrameSinkManagerImpl* frame_sink_manager() { return frame_sink_manager_; }
- cc::SurfaceManager* surface_manager() { return surface_manager_; }
+ SurfaceManager* surface_manager() { return surface_manager_; }
void SetDestructionCallback(base::OnceCallback<void()> callback);
// SurfaceClient implementation.
- void OnSurfaceActivated(cc::Surface* surface) override;
+ void OnSurfaceActivated(Surface* surface) override;
void RefResources(
- const std::vector<cc::TransferableResource>& resources) override;
- void UnrefResources(
- const std::vector<cc::ReturnedResource>& resources) override;
- void ReturnResources(
- const std::vector<cc::ReturnedResource>& resources) override;
+ const std::vector<TransferableResource>& resources) override;
+ void UnrefResources(const std::vector<ReturnedResource>& resources) override;
+ void ReturnResources(const std::vector<ReturnedResource>& resources) override;
void ReceiveFromChild(
- const std::vector<cc::TransferableResource>& resources) override;
+ const std::vector<TransferableResource>& resources) override;
// FrameSinkManagerClient implementation.
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
+ void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override;
void EvictCurrentSurface();
void SetNeedsBeginFrame(bool needs_begin_frame);
- void DidNotProduceFrame(const cc::BeginFrameAck& ack);
+ void DidNotProduceFrame(const BeginFrameAck& ack);
bool SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
cc::CompositorFrame frame);
- void RequestCopyOfSurface(std::unique_ptr<cc::CopyOutputRequest> request);
- void ClaimTemporaryReference(const SurfaceId& surface_id);
+ void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> request);
- cc::Surface* GetCurrentSurfaceForTesting();
+ Surface* GetCurrentSurfaceForTesting();
protected:
CompositorFrameSinkSupport(CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_tokens);
void Init(FrameSinkManagerImpl* frame_sink_manager);
@@ -98,24 +96,24 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
const std::vector<SurfaceId>& active_referenced_surfaces);
// Creates a surface reference from the top-level root to |surface_id|.
- cc::SurfaceReference MakeTopLevelRootReference(const SurfaceId& surface_id);
+ SurfaceReference MakeTopLevelRootReference(const SurfaceId& surface_id);
void DidReceiveCompositorFrameAck();
void WillDrawSurface(const LocalSurfaceId& local_surface_id,
const gfx::Rect& damage_rect);
// BeginFrameObserver implementation.
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
- const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
void OnBeginFrameSourcePausedChanged(bool paused) override;
void UpdateNeedsBeginFramesInternal();
- cc::Surface* CreateSurface(const SurfaceInfo& surface_info);
+ Surface* CreateSurface(const SurfaceInfo& surface_info);
CompositorFrameSinkSupportClient* const client_;
FrameSinkManagerImpl* frame_sink_manager_ = nullptr;
- cc::SurfaceManager* surface_manager_ = nullptr;
+ SurfaceManager* surface_manager_ = nullptr;
const FrameSinkId frame_sink_id_;
SurfaceId current_surface_id_;
@@ -130,13 +128,13 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
// Counts the number of CompositorFrames that have been submitted and have not
// yet received an ACK.
int ack_pending_count_ = 0;
- std::vector<cc::ReturnedResource> surface_returned_resources_;
+ std::vector<ReturnedResource> surface_returned_resources_;
// The begin frame source being observered. Null if none.
- cc::BeginFrameSource* begin_frame_source_ = nullptr;
+ BeginFrameSource* begin_frame_source_ = nullptr;
// The last begin frame args generated by the begin frame source.
- cc::BeginFrameArgs last_begin_frame_args_;
+ BeginFrameArgs last_begin_frame_args_;
// Whether a request for begin frames has been issued.
bool needs_begin_frame_ = false;
@@ -146,23 +144,12 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
const bool is_root_;
const bool needs_sync_tokens_;
- bool seen_first_frame_activation_ = false;
-
- // TODO(staraz): Remove this flag once ui::Compositor no longer needs to call
- // RegisterFrameSinkId().
- // A surfaceSequence's validity is bound to the lifetime of the parent
- // FrameSink that created it. We track the lifetime of FrameSinks through
- // RegisterFrameSinkId and InvalidateFrameSinkId. During startup and GPU
- // restart, a SurfaceSequence created by the top most layer compositor may be
- // used prior to the creation of the associated CompositorFrameSinkSupport.
- // CompositorFrameSinkSupport is created asynchronously when a new GPU channel
- // is established. Once we switch to SurfaceReferences, this ordering concern
- // goes away and we can remove this bool.
- const bool handles_frame_sink_id_invalidation_;
// A callback that will be run at the start of the destructor if set.
base::OnceCallback<void()> destruction_callback_;
+ uint64_t last_frame_index_ = kFrameIndexStart;
+
base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupport);
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_client.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_client.h
index 792bd9dcb1d..f0176f8061f 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_client.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_client.h
@@ -5,18 +5,16 @@
#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_SUPPORT_CLIENT_H_
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_SUPPORT_CLIENT_H_
-#include "cc/resources/returned_resource.h"
-
-namespace cc {
-struct BeginFrameArgs;
-} // namespace cc
+#include "components/viz/common/resources/returned_resource.h"
namespace gfx {
class Rect;
}
namespace viz {
+
class LocalSurfaceId;
+struct BeginFrameArgs;
class CompositorFrameSinkSupportClient {
public:
@@ -28,14 +26,14 @@ class CompositorFrameSinkSupportClient {
// However, there's a fair amount of cleanup and refactoring necessary to get
// rid of it.
virtual void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) = 0;
+ const std::vector<ReturnedResource>& resources) = 0;
// Notification for the client to generate a CompositorFrame.
- virtual void OnBeginFrame(const cc::BeginFrameArgs& args) = 0;
+ virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
// Returns resources sent to SubmitCompositorFrame to be reused or freed.
virtual void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) = 0;
+ const std::vector<ReturnedResource>& resources) = 0;
// Called when surface is being scheduled for a draw.
virtual void WillDrawSurface(const LocalSurfaceId& local_surface_id,
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h
index 91a4e805709..c4f1026a0f0 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h
@@ -23,7 +23,6 @@ class CompositorFrameSinkSupportManager {
CreateCompositorFrameSinkSupport(CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_points) = 0;
protected:
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 e876d654a54..a4bb235b27d 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
@@ -6,19 +6,20 @@
#include "base/macros.h"
#include "cc/output/compositor_frame.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
#include "cc/resources/resource_provider.h"
-#include "cc/test/begin_frame_args_test.h"
-#include "cc/test/compositor_frame_helpers.h"
-#include "cc/test/fake_external_begin_frame_source.h"
-#include "cc/test/fake_surface_observer.h"
-#include "cc/test/mock_compositor_frame_sink_support_client.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/quads/copy_output_result.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
+#include "components/viz/test/fake_surface_observer.h"
+#include "components/viz/test/mock_compositor_frame_sink_support_client.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,14 +33,11 @@ using testing::Eq;
namespace viz {
namespace {
-constexpr bool kIsRoot = true;
-constexpr bool kIsChildRoot = false;
-constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kIsRoot = false;
constexpr bool kNeedsSyncPoints = true;
constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
constexpr FrameSinkId kAnotherArbitraryFrameSinkId(2, 2);
-constexpr FrameSinkId kYetAnotherArbitraryFrameSinkId(3, 3);
const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
const base::UnguessableToken kArbitrarySourceId1 =
@@ -54,6 +52,50 @@ gpu::SyncToken GenTestSyncToken(int id) {
return token;
}
+// A test mojom::FrameSinkManagerClient that by default drops temporary
+// references unless SetTemporaryReferenceToAssign() is used.
+class FakeFrameSinkManagerClient : public mojom::FrameSinkManagerClient {
+ public:
+ explicit FakeFrameSinkManagerClient(mojom::FrameSinkManager* manager)
+ : manager_(manager) {}
+ ~FakeFrameSinkManagerClient() override = default;
+
+ // Sets owner for |surface_id| when OnFirstSurfaceActivation() is called. If
+ // not set the temporary reference will be dropped.
+ void SetTemporaryReferenceToAssign(const SurfaceId& surface_id,
+ const FrameSinkId& frame_sink_id) {
+ temporary_references_to_assign_[surface_id] = frame_sink_id;
+ }
+
+ // mojom::FrameSinkManagerClient:
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override {
+ auto iter = temporary_references_to_assign_.find(surface_info.id());
+ if (iter == temporary_references_to_assign_.end()) {
+ manager_->DropTemporaryReference(surface_info.id());
+ return;
+ }
+
+ manager_->AssignTemporaryReference(surface_info.id(), iter->second);
+ temporary_references_to_assign_.erase(iter);
+ }
+ void OnClientConnectionClosed(const FrameSinkId& frame_sink_id) override {}
+ void OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_sizes) override {}
+ void SwitchActiveAggregatedHitTestRegionList(
+ const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) override {}
+
+ private:
+ mojom::FrameSinkManager* const manager_;
+ base::flat_map<SurfaceId, FrameSinkId> temporary_references_to_assign_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeFrameSinkManagerClient);
+};
+
class FakeCompositorFrameSinkSupportClient
: public CompositorFrameSinkSupportClient {
public:
@@ -61,14 +103,14 @@ class FakeCompositorFrameSinkSupportClient
~FakeCompositorFrameSinkSupportClient() override = default;
void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override {
+ const std::vector<ReturnedResource>& resources) override {
InsertResources(resources);
}
- void OnBeginFrame(const cc::BeginFrameArgs& args) override {}
+ void OnBeginFrame(const BeginFrameArgs& args) override {}
void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override {
+ const std::vector<ReturnedResource>& resources) override {
InsertResources(resources);
}
@@ -78,17 +120,17 @@ class FakeCompositorFrameSinkSupportClient
void OnBeginFramePausedChanged(bool paused) override {}
void clear_returned_resources() { returned_resources_.clear(); }
- const std::vector<cc::ReturnedResource>& returned_resources() {
+ const std::vector<ReturnedResource>& returned_resources() {
return returned_resources_;
}
private:
- void InsertResources(const std::vector<cc::ReturnedResource>& resources) {
+ void InsertResources(const std::vector<ReturnedResource>& resources) {
returned_resources_.insert(returned_resources_.end(), resources.begin(),
resources.end());
}
- std::vector<cc::ReturnedResource> returned_resources_;
+ std::vector<ReturnedResource> returned_resources_;
DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient);
};
@@ -96,30 +138,30 @@ class FakeCompositorFrameSinkSupportClient
class CompositorFrameSinkSupportTest : public testing::Test {
public:
CompositorFrameSinkSupportTest()
- : support_(
- CompositorFrameSinkSupport::Create(&fake_support_client_,
- &manager_,
- kArbitraryFrameSinkId,
- kIsRoot,
- kHandlesFrameSinkIdInvalidation,
- kNeedsSyncPoints)),
+ : frame_sink_manager_client_(&manager_),
begin_frame_source_(0.f, false),
local_surface_id_(3, kArbitraryToken),
frame_sync_token_(GenTestSyncToken(4)),
consumer_sync_token_(GenTestSyncToken(5)) {
+ manager_.SetLocalClient(&frame_sink_manager_client_);
manager_.surface_manager()->AddObserver(&surface_observer_);
+ manager_.RegisterFrameSinkId(kArbitraryFrameSinkId);
+ support_ = CompositorFrameSinkSupport::Create(
+ &fake_support_client_, &manager_, kArbitraryFrameSinkId, kIsRoot,
+ kNeedsSyncPoints);
support_->SetBeginFrameSource(&begin_frame_source_);
}
~CompositorFrameSinkSupportTest() override {
+ manager_.InvalidateFrameSinkId(kArbitraryFrameSinkId);
manager_.surface_manager()->RemoveObserver(&surface_observer_);
support_->EvictCurrentSurface();
}
- void SubmitCompositorFrameWithResources(cc::ResourceId* resource_ids,
+ void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
size_t num_resource_ids) {
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
for (size_t i = 0u; i < num_resource_ids; ++i) {
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = resource_ids[i];
resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
resource.mailbox_holder.sync_token = frame_sync_token_;
@@ -130,12 +172,12 @@ class CompositorFrameSinkSupportTest : public testing::Test {
local_surface_id_);
}
- void UnrefResources(cc::ResourceId* ids_to_unref,
+ void UnrefResources(ResourceId* ids_to_unref,
int* counts_to_unref,
size_t num_ids_to_unref) {
- std::vector<cc::ReturnedResource> unref_array;
+ std::vector<ReturnedResource> unref_array;
for (size_t i = 0; i < num_ids_to_unref; ++i) {
- cc::ReturnedResource resource;
+ ReturnedResource resource;
resource.sync_token = consumer_sync_token_;
resource.id = ids_to_unref[i];
resource.count = counts_to_unref[i];
@@ -144,16 +186,15 @@ class CompositorFrameSinkSupportTest : public testing::Test {
support_->UnrefResources(unref_array);
}
- void CheckReturnedResourcesMatchExpected(
- cc::ResourceId* expected_returned_ids,
- int* expected_returned_counts,
- size_t expected_resources,
- gpu::SyncToken expected_sync_token) {
- const std::vector<cc::ReturnedResource>& actual_resources =
+ void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids,
+ int* expected_returned_counts,
+ size_t expected_resources,
+ gpu::SyncToken expected_sync_token) {
+ const std::vector<ReturnedResource>& actual_resources =
fake_support_client_.returned_resources();
ASSERT_EQ(expected_resources, actual_resources.size());
for (size_t i = 0; i < expected_resources; ++i) {
- cc::ReturnedResource resource = actual_resources[i];
+ ReturnedResource resource = actual_resources[i];
EXPECT_EQ(expected_sync_token, resource.sync_token);
EXPECT_EQ(expected_returned_ids[i], resource.id);
EXPECT_EQ(expected_returned_counts[i], resource.count);
@@ -161,23 +202,24 @@ class CompositorFrameSinkSupportTest : public testing::Test {
fake_support_client_.clear_returned_resources();
}
- cc::Surface* GetSurfaceForId(const SurfaceId& id) {
+ Surface* GetSurfaceForId(const SurfaceId& id) {
return manager_.surface_manager()->GetSurfaceForId(id);
}
void RefCurrentFrameResources() {
- cc::Surface* surface = GetSurfaceForId(
+ Surface* surface = GetSurfaceForId(
SurfaceId(support_->frame_sink_id(), local_surface_id_));
support_->RefResources(surface->GetActiveFrame().resource_list);
}
protected:
FrameSinkManagerImpl manager_;
+ FakeFrameSinkManagerClient frame_sink_manager_client_;
FakeCompositorFrameSinkSupportClient fake_support_client_;
std::unique_ptr<CompositorFrameSinkSupport> support_;
- cc::FakeExternalBeginFrameSource begin_frame_source_;
+ FakeExternalBeginFrameSource begin_frame_source_;
LocalSurfaceId local_surface_id_;
- cc::FakeSurfaceObserver surface_observer_;
+ FakeSurfaceObserver surface_observer_;
// This is the sync token submitted with the frame. It should never be
// returned to the client.
@@ -191,7 +233,7 @@ class CompositorFrameSinkSupportTest : public testing::Test {
// Tests submitting a frame with resources followed by one with no resources
// with no resource provider action in between.
TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) {
- cc::ResourceId first_frame_ids[] = {1, 2, 3};
+ ResourceId first_frame_ids[] = {1, 2, 3};
SubmitCompositorFrameWithResources(first_frame_ids,
arraysize(first_frame_ids));
@@ -205,14 +247,14 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) {
// make all resources of first frame available to be returned.
SubmitCompositorFrameWithResources(NULL, 0);
- cc::ResourceId expected_returned_ids[] = {1, 2, 3};
+ ResourceId expected_returned_ids[] = {1, 2, 3};
int expected_returned_counts[] = {1, 1, 1};
// Resources were never consumed so no sync token should be set.
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
arraysize(expected_returned_counts), gpu::SyncToken());
- cc::ResourceId third_frame_ids[] = {4, 5, 6};
+ ResourceId third_frame_ids[] = {4, 5, 6};
SubmitCompositorFrameWithResources(third_frame_ids,
arraysize(third_frame_ids));
@@ -224,11 +266,11 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) {
// The forth frame references no resources of third frame and thus should
// make all resources of third frame available to be returned.
- cc::ResourceId forth_frame_ids[] = {7, 8, 9};
+ ResourceId forth_frame_ids[] = {7, 8, 9};
SubmitCompositorFrameWithResources(forth_frame_ids,
arraysize(forth_frame_ids));
- cc::ResourceId forth_expected_returned_ids[] = {4, 5, 6};
+ ResourceId forth_expected_returned_ids[] = {4, 5, 6};
int forth_expected_returned_counts[] = {1, 1, 1};
// Resources were never consumed so no sync token should be set.
CheckReturnedResourcesMatchExpected(
@@ -240,7 +282,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) {
// with the resource provider holding everything alive.
TEST_F(CompositorFrameSinkSupportTest,
ResourceLifetimeSimpleWithProviderHoldingAlive) {
- cc::ResourceId first_frame_ids[] = {1, 2, 3};
+ ResourceId first_frame_ids[] = {1, 2, 3};
SubmitCompositorFrameWithResources(first_frame_ids,
arraysize(first_frame_ids));
@@ -270,7 +312,7 @@ TEST_F(CompositorFrameSinkSupportTest,
// Submitting an empty frame causes previous resources referenced by the
// previous frame to be returned to client.
SubmitCompositorFrameWithResources(nullptr, 0);
- cc::ResourceId expected_returned_ids[] = {1, 2, 3};
+ ResourceId expected_returned_ids[] = {1, 2, 3};
int expected_returned_counts[] = {1, 1, 1};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -280,7 +322,7 @@ TEST_F(CompositorFrameSinkSupportTest,
// Tests referencing a resource, unref'ing it to zero, then using it again
// before returning it to the client.
TEST_F(CompositorFrameSinkSupportTest, ResourceReusedBeforeReturn) {
- cc::ResourceId first_frame_ids[] = {7};
+ ResourceId first_frame_ids[] = {7};
SubmitCompositorFrameWithResources(first_frame_ids,
arraysize(first_frame_ids));
@@ -297,7 +339,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceReusedBeforeReturn) {
// Now it should be returned.
// We don't care how many entries are in the returned array for 7, so long as
// the total returned count matches the submitted count.
- const std::vector<cc::ReturnedResource>& returned =
+ const std::vector<ReturnedResource>& returned =
fake_support_client_.returned_resources();
size_t return_count = 0;
for (size_t i = 0; i < returned.size(); ++i) {
@@ -310,7 +352,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceReusedBeforeReturn) {
// Tests having resources referenced multiple times, as if referenced by
// multiple providers.
TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
- cc::ResourceId first_frame_ids[] = {3, 4};
+ ResourceId first_frame_ids[] = {3, 4};
SubmitCompositorFrameWithResources(first_frame_ids,
arraysize(first_frame_ids));
@@ -318,7 +360,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
RefCurrentFrameResources();
RefCurrentFrameResources();
- cc::ResourceId second_frame_ids[] = {4, 5};
+ ResourceId second_frame_ids[] = {4, 5};
SubmitCompositorFrameWithResources(second_frame_ids,
arraysize(second_frame_ids));
@@ -340,7 +382,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
// 5 -> 3
{
SCOPED_TRACE("unref all 3");
- cc::ResourceId ids_to_unref[] = {3, 4, 5};
+ ResourceId ids_to_unref[] = {3, 4, 5};
int counts[] = {1, 1, 1};
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
@@ -349,7 +391,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
SubmitCompositorFrameWithResources(nullptr, 0);
- cc::ResourceId expected_returned_ids[] = {3};
+ ResourceId expected_returned_ids[] = {3};
int expected_returned_counts[] = {1};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -361,12 +403,12 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
// 5 -> 1
{
SCOPED_TRACE("unref 4 and 5");
- cc::ResourceId ids_to_unref[] = {4, 5};
+ ResourceId ids_to_unref[] = {4, 5};
int counts[] = {1, 1};
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
SubmitCompositorFrameWithResources(nullptr, 0);
- cc::ResourceId expected_returned_ids[] = {5};
+ ResourceId expected_returned_ids[] = {5};
int expected_returned_counts[] = {1};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -377,12 +419,12 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
// the returned count is correct.
{
SCOPED_TRACE("unref only 4");
- cc::ResourceId ids_to_unref[] = {4};
+ ResourceId ids_to_unref[] = {4};
int counts[] = {2};
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
SubmitCompositorFrameWithResources(nullptr, 0);
- cc::ResourceId expected_returned_ids[] = {4};
+ ResourceId expected_returned_ids[] = {4};
int expected_returned_counts[] = {2};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -391,7 +433,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
}
TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
- cc::ResourceId first_frame_ids[] = {1, 2, 3};
+ ResourceId first_frame_ids[] = {1, 2, 3};
SubmitCompositorFrameWithResources(first_frame_ids,
arraysize(first_frame_ids));
@@ -404,12 +446,12 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
// The second frame references some of the same resources, but some different
// ones. We expect to receive back resource 1 with a count of 1 since it was
// only referenced by the first frame.
- cc::ResourceId second_frame_ids[] = {2, 3, 4};
+ ResourceId second_frame_ids[] = {2, 3, 4};
SubmitCompositorFrameWithResources(second_frame_ids,
arraysize(second_frame_ids));
{
SCOPED_TRACE("second frame");
- cc::ResourceId expected_returned_ids[] = {1};
+ ResourceId expected_returned_ids[] = {1};
int expected_returned_counts[] = {1};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -420,13 +462,13 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
// receive back all resources from the first and second frames. Resource IDs 2
// and 3 will have counts of 2, since they were used in both frames, and
// resource ID 4 will have a count of 1.
- cc::ResourceId third_frame_ids[] = {10, 11, 12, 13};
+ ResourceId third_frame_ids[] = {10, 11, 12, 13};
SubmitCompositorFrameWithResources(third_frame_ids,
arraysize(third_frame_ids));
{
SCOPED_TRACE("third frame");
- cc::ResourceId expected_returned_ids[] = {2, 3, 4};
+ ResourceId expected_returned_ids[] = {2, 3, 4};
int expected_returned_counts[] = {2, 2, 1};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -436,7 +478,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
// Simulate a ResourceProvider taking a ref on all of the resources.
RefCurrentFrameResources();
- cc::ResourceId fourth_frame_ids[] = {12, 13};
+ ResourceId fourth_frame_ids[] = {12, 13};
SubmitCompositorFrameWithResources(fourth_frame_ids,
arraysize(fourth_frame_ids));
@@ -451,7 +493,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
// Release resources associated with the first RefCurrentFrameResources() call
// first.
{
- cc::ResourceId ids_to_unref[] = {10, 11, 12, 13};
+ ResourceId ids_to_unref[] = {10, 11, 12, 13};
int counts[] = {1, 1, 1, 1};
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
}
@@ -465,7 +507,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
}
{
- cc::ResourceId ids_to_unref[] = {12, 13};
+ ResourceId ids_to_unref[] = {12, 13};
int counts[] = {1, 1};
UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
}
@@ -480,7 +522,7 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
{
SCOPED_TRACE("fourth frame, second unref");
- cc::ResourceId expected_returned_ids[] = {10, 11, 12, 13};
+ ResourceId expected_returned_ids[] = {10, 11, 12, 13};
int expected_returned_counts[] = {1, 1, 2, 2};
CheckReturnedResourcesMatchExpected(
expected_returned_ids, expected_returned_counts,
@@ -489,242 +531,89 @@ TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
}
TEST_F(CompositorFrameSinkSupportTest, AddDuringEviction) {
- cc::test::MockCompositorFrameSinkSupportClient mock_client;
+ manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
+ test::MockCompositorFrameSinkSupportClient mock_client;
auto support = CompositorFrameSinkSupport::Create(
&mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId local_surface_id(6, kArbitraryToken);
- support->SubmitCompositorFrame(local_surface_id,
- cc::test::MakeCompositorFrame());
+ support->SubmitCompositorFrame(local_surface_id, test::MakeCompositorFrame());
EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(_))
.WillOnce(testing::InvokeWithoutArgs([&support, &mock_client]() {
LocalSurfaceId new_id(7, base::UnguessableToken::Create());
- support->SubmitCompositorFrame(new_id, cc::test::MakeCompositorFrame());
+ support->SubmitCompositorFrame(new_id, test::MakeCompositorFrame());
}))
.WillRepeatedly(testing::Return());
support->EvictCurrentSurface();
+ manager_.InvalidateFrameSinkId(kAnotherArbitraryFrameSinkId);
}
// Tests doing an EvictCurrentSurface before shutting down the factory.
TEST_F(CompositorFrameSinkSupportTest, EvictCurrentSurface) {
- cc::test::MockCompositorFrameSinkSupportClient mock_client;
+ manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
+ test::MockCompositorFrameSinkSupportClient mock_client;
auto support = CompositorFrameSinkSupport::Create(
&mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ kNeedsSyncPoints);
LocalSurfaceId local_surface_id(7, kArbitraryToken);
SurfaceId id(kAnotherArbitraryFrameSinkId, local_surface_id);
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = 1;
resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
frame.resource_list.push_back(resource);
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
EXPECT_EQ(surface_observer_.last_created_surface_id().local_surface_id(),
local_surface_id);
local_surface_id_ = LocalSurfaceId();
- std::vector<cc::ReturnedResource> returned_resources = {
+ std::vector<ReturnedResource> returned_resources = {
resource.ToReturnedResource()};
EXPECT_TRUE(GetSurfaceForId(id));
EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
.Times(1);
support->EvictCurrentSurface();
EXPECT_FALSE(GetSurfaceForId(id));
+ manager_.InvalidateFrameSinkId(kAnotherArbitraryFrameSinkId);
}
-// Tests doing an EvictCurrentSurface which has unregistered dependency.
-TEST_F(CompositorFrameSinkSupportTest,
- EvictCurrentSurfaceDependencyUnRegistered) {
- cc::test::MockCompositorFrameSinkSupportClient mock_client;
- auto support = CompositorFrameSinkSupport::Create(
- &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
- LocalSurfaceId local_surface_id(7, kArbitraryToken);
-
- cc::TransferableResource resource;
- resource.id = 1;
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- auto frame = cc::test::MakeCompositorFrame();
- frame.resource_list.push_back(resource);
- support->SubmitCompositorFrame(local_surface_id, std::move(frame));
- EXPECT_EQ(surface_observer_.last_created_surface_id().local_surface_id(),
- local_surface_id);
- local_surface_id_ = LocalSurfaceId();
-
- SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
- cc::Surface* surface = GetSurfaceForId(surface_id);
- surface->AddDestructionDependency(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
-
- std::vector<cc::ReturnedResource> returned_resource = {
- resource.ToReturnedResource()};
-
- EXPECT_TRUE(GetSurfaceForId(surface_id));
- EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resource))
- .Times(1);
- support->EvictCurrentSurface();
- EXPECT_FALSE(GetSurfaceForId(surface_id));
-}
-
-// Tests doing an EvictCurrentSurface which has registered dependency.
-TEST_F(CompositorFrameSinkSupportTest,
- EvictCurrentSurfaceDependencyRegistered) {
- cc::test::MockCompositorFrameSinkSupportClient mock_client;
- auto support = CompositorFrameSinkSupport::Create(
- &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
- LocalSurfaceId local_surface_id(7, kArbitraryToken);
-
- cc::TransferableResource resource;
- resource.id = 1;
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- auto frame = cc::test::MakeCompositorFrame();
- frame.resource_list.push_back(resource);
- uint32_t execute_count = 0;
- support->SubmitCompositorFrame(local_surface_id, std::move(frame));
- EXPECT_EQ(surface_observer_.last_created_surface_id().local_surface_id(),
- local_surface_id);
- local_surface_id_ = LocalSurfaceId();
-
- manager_.surface_manager()->RegisterFrameSinkId(
- kYetAnotherArbitraryFrameSinkId);
-
- SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
- cc::Surface* surface = GetSurfaceForId(surface_id);
- surface->AddDestructionDependency(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
-
- std::vector<cc::ReturnedResource> returned_resources;
- EXPECT_TRUE(GetSurfaceForId(surface_id));
- support->EvictCurrentSurface();
- EXPECT_TRUE(GetSurfaceForId(surface_id));
- EXPECT_EQ(0u, execute_count);
-
- returned_resources.push_back(resource.ToReturnedResource());
- EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
- .Times(1);
- manager_.surface_manager()->SatisfySequence(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
- EXPECT_FALSE(GetSurfaceForId(surface_id));
-}
-
-TEST_F(CompositorFrameSinkSupportTest, DestroySequence) {
- LocalSurfaceId local_surface_id2(5, kArbitraryToken);
- auto support2 = CompositorFrameSinkSupport::Create(
- &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId,
- kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
- SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2);
- support2->SubmitCompositorFrame(local_surface_id2,
- cc::test::MakeCompositorFrame());
-
- // Check that waiting before the sequence is satisfied works.
- GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
- support2->EvictCurrentSurface();
-
- DCHECK(GetSurfaceForId(id2));
- manager_.surface_manager()->SatisfySequence(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
- manager_.surface_manager()->SatisfySequence(
- SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 6));
- DCHECK(!GetSurfaceForId(id2));
-
- // Check that waiting after the sequence is satisfied works.
- support2->SubmitCompositorFrame(local_surface_id2,
- cc::test::MakeCompositorFrame());
- DCHECK(GetSurfaceForId(id2));
- GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 6));
- support2->EvictCurrentSurface();
- DCHECK(!GetSurfaceForId(id2));
-}
+// Verify that a temporary reference blocks surface eviction and that when the
+// temporary reference is removed due to frame sink invalidation the surface
+// is deleted.
+TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceWithTemporaryReference) {
+ constexpr FrameSinkId parent_frame_sink_id(1234, 5678);
+ manager_.RegisterFrameSinkId(parent_frame_sink_id);
-// Tests that SurfaceId namespace invalidation correctly allows
-// Sequences to be ignored.
-TEST_F(CompositorFrameSinkSupportTest, InvalidFrameSinkId) {
- FrameSinkId frame_sink_id(1234, 5678);
+ const LocalSurfaceId local_surface_id(5, kArbitraryToken);
+ const SurfaceId surface_id(support_->frame_sink_id(), local_surface_id);
- LocalSurfaceId local_surface_id(5, kArbitraryToken);
- SurfaceId id(support_->frame_sink_id(), local_surface_id);
+ // When CompositorFrame is submitted, a temporary refrence will be created and
+ // |parent_frame_sink_id| will be assigned as the owner.
+ frame_sink_manager_client_.SetTemporaryReferenceToAssign(
+ surface_id, parent_frame_sink_id);
support_->SubmitCompositorFrame(local_surface_id,
- cc::test::MakeCompositorFrame());
-
- manager_.surface_manager()->RegisterFrameSinkId(frame_sink_id);
- GetSurfaceForId(id)->AddDestructionDependency(
- SurfaceSequence(frame_sink_id, 4));
+ test::MakeCompositorFrame());
+ // Verify the temporary reference has prevented the surface from getting
+ // destroyed.
support_->EvictCurrentSurface();
+ EXPECT_TRUE(GetSurfaceForId(surface_id));
- // Verify the dependency has prevented the surface from getting destroyed.
- EXPECT_TRUE(GetSurfaceForId(id));
-
- manager_.surface_manager()->InvalidateFrameSinkId(frame_sink_id);
-
- // Verify that the invalidated namespace caused the unsatisfied sequence
- // to be ignored.
- EXPECT_FALSE(GetSurfaceForId(id));
-}
-
-TEST_F(CompositorFrameSinkSupportTest, DestroyCycle) {
- LocalSurfaceId local_surface_id2(5, kArbitraryToken);
- SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2);
- auto support2 = CompositorFrameSinkSupport::Create(
- &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId,
- kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
- manager_.surface_manager()->RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
- // Give local_surface_id_ an initial frame so another client can refer to
- // that surface.
- {
- auto frame = cc::test::MakeCompositorFrame();
- support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
- }
- // Give id2 a frame that references local_surface_id_.
- {
- auto frame = cc::test::MakeCompositorFrame();
- frame.metadata.referenced_surfaces.push_back(
- SurfaceId(support_->frame_sink_id(), local_surface_id_));
- support2->SubmitCompositorFrame(local_surface_id2, std::move(frame));
- EXPECT_EQ(surface_observer_.last_created_surface_id().local_surface_id(),
- local_surface_id2);
- }
- GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
- support2->EvictCurrentSurface();
- // Give local_surface_id_ a frame that references id2.
- {
- auto frame = cc::test::MakeCompositorFrame();
- frame.metadata.referenced_surfaces.push_back(id2);
- support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
- }
- support_->EvictCurrentSurface();
- EXPECT_TRUE(GetSurfaceForId(id2));
- // local_surface_id_ should be retained by reference from id2.
- EXPECT_TRUE(
- GetSurfaceForId(SurfaceId(support_->frame_sink_id(), local_surface_id_)));
-
- // Satisfy last destruction dependency for id2.
- manager_.surface_manager()->SatisfySequence(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
-
- // id2 and local_surface_id_ are in a reference cycle that has no surface
- // sequences holding on to it, so they should be destroyed.
- EXPECT_TRUE(!GetSurfaceForId(id2));
- EXPECT_TRUE(!GetSurfaceForId(
- SurfaceId(support_->frame_sink_id(), local_surface_id_)));
-
- local_surface_id_ = LocalSurfaceId();
+ // Verify the temporary reference is removed when the parent is invalidated.
+ manager_.InvalidateFrameSinkId(parent_frame_sink_id);
+ EXPECT_FALSE(GetSurfaceForId(surface_id));
}
void CopyRequestTestCallback(bool* called,
- std::unique_ptr<cc::CopyOutputResult> result) {
+ std::unique_ptr<CopyOutputResult> result) {
*called = true;
}
TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
{
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
frame.metadata.referenced_surfaces.push_back(
SurfaceId(support_->frame_sink_id(), local_surface_id_));
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
@@ -733,7 +622,7 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
}
bool called1 = false;
- auto request = cc::CopyOutputRequest::CreateRequest(
+ auto request = CopyOutputRequest::CreateRequest(
base::BindOnce(&CopyRequestTestCallback, &called1));
request->set_source(kArbitrarySourceId1);
@@ -741,7 +630,7 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
EXPECT_FALSE(called1);
bool called2 = false;
- request = cc::CopyOutputRequest::CreateRequest(
+ request = CopyOutputRequest::CreateRequest(
base::BindOnce(&CopyRequestTestCallback, &called2));
request->set_source(kArbitrarySourceId2);
@@ -751,7 +640,7 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
EXPECT_FALSE(called2);
bool called3 = false;
- request = cc::CopyOutputRequest::CreateRequest(
+ request = CopyOutputRequest::CreateRequest(
base::BindOnce(&CopyRequestTestCallback, &called3));
request->set_source(kArbitrarySourceId1);
@@ -771,7 +660,7 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
// Check whether the SurfaceInfo object is created and populated correctly
// after the frame submission.
TEST_F(CompositorFrameSinkSupportTest, SurfaceInfo) {
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
auto render_pass = cc::RenderPass::Create();
render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(), gfx::Transform());
@@ -795,7 +684,7 @@ TEST_F(CompositorFrameSinkSupportTest, SurfaceInfo) {
// a Surface for it.
TEST_F(CompositorFrameSinkSupportTest, ZeroFrameSize) {
SurfaceId id(support_->frame_sink_id(), local_surface_id_);
- auto frame = cc::test::MakeEmptyCompositorFrame();
+ auto frame = test::MakeEmptyCompositorFrame();
frame.render_pass_list.push_back(cc::RenderPass::Create());
EXPECT_TRUE(
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
@@ -806,7 +695,7 @@ TEST_F(CompositorFrameSinkSupportTest, ZeroFrameSize) {
// don't create a Surface for it.
TEST_F(CompositorFrameSinkSupportTest, ZeroDeviceScaleFactor) {
SurfaceId id(support_->frame_sink_id(), local_surface_id_);
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
frame.metadata.device_scale_factor = 0.f;
EXPECT_TRUE(
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
@@ -819,7 +708,7 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) {
SurfaceId id(support_->frame_sink_id(), local_surface_id_);
// Submit a frame with size (5,5).
- auto frame = cc::test::MakeEmptyCompositorFrame();
+ auto frame = test::MakeEmptyCompositorFrame();
auto pass = cc::RenderPass::Create();
pass->SetNew(1, gfx::Rect(5, 5), gfx::Rect(), gfx::Transform());
frame.render_pass_list.push_back(std::move(pass));
@@ -829,7 +718,7 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) {
// Submit a frame with size (5,4). This frame should be rejected and the
// surface should be destroyed.
- frame = cc::test::MakeEmptyCompositorFrame();
+ frame = test::MakeEmptyCompositorFrame();
pass = cc::RenderPass::Create();
pass->SetNew(1, gfx::Rect(5, 4), gfx::Rect(), gfx::Transform());
frame.render_pass_list.push_back(std::move(pass));
@@ -845,7 +734,7 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) {
SurfaceId id(support_->frame_sink_id(), local_surface_id_);
// Submit a frame with device scale factor of 0.5.
- auto frame = cc::test::MakeCompositorFrame();
+ auto frame = test::MakeCompositorFrame();
frame.metadata.device_scale_factor = 0.5f;
EXPECT_TRUE(
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
@@ -853,7 +742,7 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) {
// Submit a frame with device scale factor of 0.4. This frame should be
// rejected and the surface should be destroyed.
- frame = cc::test::MakeCompositorFrame();
+ frame = test::MakeCompositorFrame();
frame.metadata.device_scale_factor = 0.4f;
EXPECT_FALSE(
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
@@ -865,30 +754,50 @@ TEST_F(CompositorFrameSinkSupportTest, PassesOnBeginFrameAcks) {
support_->SetNeedsBeginFrame(true);
// Issue a BeginFrame.
- cc::BeginFrameArgs args =
- cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
begin_frame_source_.TestOnBeginFrame(args);
// Check that the support and SurfaceManager forward the BeginFrameAck
// attached to a CompositorFrame to the SurfaceObserver.
- cc::BeginFrameAck ack(0, 1, true);
- auto frame = cc::test::MakeCompositorFrame();
+ BeginFrameAck ack(0, 1, true);
+ auto frame = test::MakeCompositorFrame();
frame.metadata.begin_frame_ack = ack;
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
EXPECT_EQ(ack, surface_observer_.last_ack());
// Issue another BeginFrame.
- args = cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
+ args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
begin_frame_source_.TestOnBeginFrame(args);
// Check that the support and SurfaceManager forward a DidNotProduceFrame ack
// to the SurfaceObserver.
- cc::BeginFrameAck ack2(0, 2, false);
+ BeginFrameAck ack2(0, 2, false);
support_->DidNotProduceFrame(ack2);
EXPECT_EQ(ack2, surface_observer_.last_ack());
support_->SetNeedsBeginFrame(false);
}
+TEST_F(CompositorFrameSinkSupportTest, FrameIndexCarriedOverToNewSurface) {
+ LocalSurfaceId local_surface_id1(1, kArbitraryToken);
+ LocalSurfaceId local_surface_id2(2, kArbitraryToken);
+ SurfaceId id1(support_->frame_sink_id(), local_surface_id1);
+ SurfaceId id2(support_->frame_sink_id(), local_surface_id2);
+
+ // Submit a frame to |id1| and record the frame index.
+ support_->SubmitCompositorFrame(local_surface_id1,
+ test::MakeCompositorFrame());
+ Surface* surface1 = GetSurfaceForId(id1);
+ uint64_t frame_index = surface1->GetActiveFrameIndex();
+
+ // Submit a frame to |id2| and verify that the new frame index is one more
+ // than what we had before.
+ support_->SubmitCompositorFrame(local_surface_id2,
+ test::MakeCompositorFrame());
+ Surface* surface2 = GetSurfaceForId(id2);
+ EXPECT_EQ(frame_index + 1, surface2->GetActiveFrameIndex());
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
index d0e94605b3f..c3e3d8ae452 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
@@ -7,12 +7,12 @@
#include "base/bind.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/layer_tree_frame_sink_client.h"
-#include "cc/surfaces/surface.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
namespace viz {
@@ -45,7 +45,7 @@ DirectLayerTreeFrameSink::DirectLayerTreeFrameSink(
CompositorFrameSinkSupportManager* support_manager,
FrameSinkManagerImpl* frame_sink_manager,
Display* display,
- scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider)
+ scoped_refptr<VulkanContextProvider> vulkan_context_provider)
: LayerTreeFrameSink(std::move(vulkan_context_provider)),
frame_sink_id_(frame_sink_id),
support_manager_(support_manager),
@@ -73,11 +73,10 @@ bool DirectLayerTreeFrameSink::BindToClient(
cp->SetLostContextCallback(base::Closure());
constexpr bool is_root = true;
- constexpr bool handles_frame_sink_id_invalidation = false;
support_ = support_manager_->CreateCompositorFrameSinkSupport(
- this, frame_sink_id_, is_root, handles_frame_sink_id_invalidation,
+ this, frame_sink_id_, is_root,
capabilities_.delegated_sync_points_required);
- begin_frame_source_ = base::MakeUnique<cc::ExternalBeginFrameSource>(this);
+ begin_frame_source_ = base::MakeUnique<ExternalBeginFrameSource>(this);
client_->SetBeginFrameSource(begin_frame_source_.get());
// Avoid initializing GL context here, as this should be sharing the
@@ -100,15 +99,15 @@ void DirectLayerTreeFrameSink::DetachFromClient() {
void DirectLayerTreeFrameSink::SubmitCompositorFrame(
cc::CompositorFrame frame) {
DCHECK(frame.metadata.begin_frame_ack.has_damage);
- DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber,
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber,
frame.metadata.begin_frame_ack.sequence_number);
- gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
- if (!local_surface_id_.is_valid() || frame_size != last_swap_frame_size_ ||
- frame.metadata.device_scale_factor != device_scale_factor_) {
+ if (!local_surface_id_.is_valid() ||
+ frame.size_in_pixels() != last_swap_frame_size_ ||
+ frame.device_scale_factor() != device_scale_factor_) {
local_surface_id_ = local_surface_id_allocator_.GenerateId();
- last_swap_frame_size_ = frame_size;
- device_scale_factor_ = frame.metadata.device_scale_factor;
+ last_swap_frame_size_ = frame.size_in_pixels();
+ device_scale_factor_ = frame.device_scale_factor();
display_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_);
}
@@ -117,10 +116,9 @@ void DirectLayerTreeFrameSink::SubmitCompositorFrame(
DCHECK(result);
}
-void DirectLayerTreeFrameSink::DidNotProduceFrame(
- const cc::BeginFrameAck& ack) {
+void DirectLayerTreeFrameSink::DidNotProduceFrame(const BeginFrameAck& ack) {
DCHECK(!ack.has_damage);
- DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
support_->DidNotProduceFrame(ack);
}
@@ -142,17 +140,17 @@ void DirectLayerTreeFrameSink::DisplayDidDrawAndSwap() {
}
void DirectLayerTreeFrameSink::DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
client_->ReclaimResources(resources);
client_->DidReceiveCompositorFrameAck();
}
-void DirectLayerTreeFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
+void DirectLayerTreeFrameSink::OnBeginFrame(const BeginFrameArgs& args) {
begin_frame_source_->OnBeginFrame(args);
}
void DirectLayerTreeFrameSink::ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) {
+ const std::vector<ReturnedResource>& resources) {
client_->ReclaimResources(resources);
}
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
index 0a1724f2bf1..85b74c9d993 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "cc/output/layer_tree_frame_sink.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/service/display/display_client.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
@@ -28,9 +28,9 @@ class Display;
// client's frame being the root surface of the Display.
class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
: public cc::LayerTreeFrameSink,
- public NON_EXPORTED_BASE(CompositorFrameSinkSupportClient),
- public cc::ExternalBeginFrameSourceClient,
- public NON_EXPORTED_BASE(DisplayClient) {
+ public CompositorFrameSinkSupportClient,
+ public ExternalBeginFrameSourceClient,
+ public DisplayClient {
public:
// The underlying Display, FrameSinkManagerImpl, and LocalSurfaceIdAllocator
// must outlive this class.
@@ -48,14 +48,14 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
CompositorFrameSinkSupportManager* support_manager,
FrameSinkManagerImpl* frame_sink_manager,
Display* display,
- scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider);
+ scoped_refptr<VulkanContextProvider> vulkan_context_provider);
~DirectLayerTreeFrameSink() override;
// LayerTreeFrameSink implementation.
bool BindToClient(cc::LayerTreeFrameSinkClient* client) override;
void DetachFromClient() override;
void SubmitCompositorFrame(cc::CompositorFrame frame) override;
- void DidNotProduceFrame(const cc::BeginFrameAck& ack) override;
+ void DidNotProduceFrame(const BeginFrameAck& ack) override;
// DisplayClient implementation.
void DisplayOutputSurfaceLost() override;
@@ -69,10 +69,10 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
private:
// CompositorFrameSinkSupportClient implementation:
void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override;
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+ const std::vector<ReturnedResource>& resources) override;
+ void OnBeginFrame(const BeginFrameArgs& args) override;
void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override;
+ const std::vector<ReturnedResource>& resources) override;
void WillDrawSurface(const LocalSurfaceId& local_surface_id,
const gfx::Rect& damage_rect) override;
void OnBeginFramePausedChanged(bool paused) override;
@@ -92,7 +92,7 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
gfx::Size last_swap_frame_size_;
float device_scale_factor_ = 1.f;
bool is_lost_ = false;
- std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_;
DISALLOW_COPY_AND_ASSIGN(DirectLayerTreeFrameSink);
};
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
index 3b050b4c65d..2622c1e478b 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
@@ -8,23 +8,23 @@
#include "base/memory/ptr_util.h"
#include "cc/output/texture_mailbox_deleter.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/scheduler/delay_based_time_source.h"
-#include "cc/test/begin_frame_args_test.h"
-#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_layer_tree_frame_sink_client.h"
#include "cc/test/fake_output_surface.h"
-#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/test_context_provider.h"
-#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id_allocator.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/ordered_simple_task_runner.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -51,11 +51,9 @@ class TestCompositorFrameSinkSupportManager
CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation,
bool needs_sync_points) override {
return CompositorFrameSinkSupport::Create(
- client, frame_sink_manager_, frame_sink_id, is_root,
- handles_frame_sink_id_invalidation, needs_sync_points);
+ client, frame_sink_manager_, frame_sink_id, is_root, needs_sync_points);
}
private:
@@ -76,8 +74,8 @@ class DirectLayerTreeFrameSinkTest : public testing::Test {
auto display_output_surface = cc::FakeOutputSurface::Create3d();
display_output_surface_ = display_output_surface.get();
- begin_frame_source_ = base::MakeUnique<cc::BackToBackBeginFrameSource>(
- base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get()));
+ begin_frame_source_ = base::MakeUnique<BackToBackBeginFrameSource>(
+ base::MakeUnique<DelayBasedTimeSource>(task_runner_.get()));
int max_frames_pending = 2;
std::unique_ptr<DisplayScheduler> scheduler(new DisplayScheduler(
@@ -109,8 +107,8 @@ class DirectLayerTreeFrameSinkTest : public testing::Test {
auto render_pass = cc::RenderPass::Create();
render_pass->SetNew(1, display_rect_, damage_rect, gfx::Transform());
- cc::CompositorFrame frame = cc::test::MakeEmptyCompositorFrame();
- frame.metadata.begin_frame_ack = cc::BeginFrameAck(0, 1, true);
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
+ frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, true);
frame.render_pass_list.push_back(std::move(render_pass));
layer_tree_frame_sink_->SubmitCompositorFrame(std::move(frame));
@@ -134,11 +132,11 @@ class DirectLayerTreeFrameSinkTest : public testing::Test {
FrameSinkManagerImpl frame_sink_manager_;
TestCompositorFrameSinkSupportManager support_manager_;
cc::TestSharedBitmapManager bitmap_manager_;
- cc::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
+ TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
scoped_refptr<cc::TestContextProvider> context_provider_;
cc::FakeOutputSurface* display_output_surface_ = nullptr;
- std::unique_ptr<cc::BackToBackBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<BackToBackBeginFrameSource> begin_frame_source_;
std::unique_ptr<Display> display_;
cc::FakeLayerTreeFrameSinkClient layer_tree_frame_sink_client_;
std::unique_ptr<TestDirectLayerTreeFrameSink> layer_tree_frame_sink_;
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_client.h b/chromium/components/viz/service/frame_sinks/frame_sink_manager_client.h
index da079e95496..1dc5d33ca77 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_client.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_client.h
@@ -18,8 +18,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerClient {
virtual ~FrameSinkManagerClient() = default;
// This allows the FrameSinkManagerImpl to pass a BeginFrameSource to use.
- virtual void SetBeginFrameSource(
- cc::BeginFrameSource* begin_frame_source) = 0;
+ virtual void SetBeginFrameSource(BeginFrameSource* begin_frame_source) = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 8fed8fb7c03..111b3a70695 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -10,10 +10,10 @@
#include "base/logging.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display_embedder/display_provider.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_client.h"
-#include "components/viz/service/frame_sinks/gpu_compositor_frame_sink.h"
-#include "components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h"
#include "components/viz/service/frame_sinks/primary_begin_frame_source.h"
+#include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h"
#if DCHECK_IS_ON()
#include <sstream>
@@ -31,8 +31,8 @@ FrameSinkManagerImpl::FrameSinkSourceMapping::~FrameSinkSourceMapping() =
default;
FrameSinkManagerImpl::FrameSinkManagerImpl(
- DisplayProvider* display_provider,
- cc::SurfaceManager::LifetimeType lifetime_type)
+ SurfaceManager::LifetimeType lifetime_type,
+ DisplayProvider* display_provider)
: display_provider_(display_provider),
surface_manager_(lifetime_type),
binding_(this) {
@@ -50,9 +50,9 @@ FrameSinkManagerImpl::~FrameSinkManagerImpl() {
}
void FrameSinkManagerImpl::BindAndSetClient(
- cc::mojom::FrameSinkManagerRequest request,
+ mojom::FrameSinkManagerRequest request,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- cc::mojom::FrameSinkManagerClientPtr client) {
+ mojom::FrameSinkManagerClientPtr client) {
DCHECK(!client_);
DCHECK(!binding_.is_bound());
binding_.Bind(std::move(request), std::move(task_runner));
@@ -62,48 +62,58 @@ void FrameSinkManagerImpl::BindAndSetClient(
}
void FrameSinkManagerImpl::SetLocalClient(
- cc::mojom::FrameSinkManagerClient* client) {
+ mojom::FrameSinkManagerClient* client) {
DCHECK(!client_ptr_);
client_ = client;
}
+void FrameSinkManagerImpl::RegisterFrameSinkId(
+ const FrameSinkId& frame_sink_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ surface_manager_.RegisterFrameSinkId(frame_sink_id);
+}
+
+void FrameSinkManagerImpl::InvalidateFrameSinkId(
+ const FrameSinkId& frame_sink_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ compositor_frame_sinks_.erase(frame_sink_id);
+ surface_manager_.InvalidateFrameSinkId(frame_sink_id);
+}
+
void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
- cc::mojom::CompositorFrameSinkAssociatedRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request) {
+ const RendererSettings& renderer_settings,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
DCHECK(display_provider_);
- std::unique_ptr<cc::BeginFrameSource> begin_frame_source;
- auto display = display_provider_->CreateDisplay(frame_sink_id, surface_handle,
- &begin_frame_source);
+ std::unique_ptr<BeginFrameSource> begin_frame_source;
+ auto display = display_provider_->CreateDisplay(
+ frame_sink_id, surface_handle, renderer_settings, &begin_frame_source);
compositor_frame_sinks_[frame_sink_id] =
- base::MakeUnique<GpuRootCompositorFrameSink>(
+ base::MakeUnique<RootCompositorFrameSinkImpl>(
this, frame_sink_id, std::move(display),
- std::move(begin_frame_source), std::move(request),
- std::move(private_request), std::move(client),
+ std::move(begin_frame_source), std::move(request), std::move(client),
std::move(display_private_request));
}
void FrameSinkManagerImpl::CreateCompositorFrameSink(
const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client) {
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
compositor_frame_sinks_[frame_sink_id] =
- base::MakeUnique<GpuCompositorFrameSink>(
- this, frame_sink_id, std::move(request), std::move(private_request),
- std::move(client));
+ base::MakeUnique<CompositorFrameSinkImpl>(
+ this, frame_sink_id, std::move(request), std::move(client));
}
void FrameSinkManagerImpl::RegisterFrameSinkHierarchy(
@@ -121,7 +131,7 @@ void FrameSinkManagerImpl::RegisterFrameSinkHierarchy(
// If the parent has no source, then attaching it to this child will
// not change any downstream sources.
- cc::BeginFrameSource* parent_source =
+ BeginFrameSource* parent_source =
frame_sink_source_map_[parent_frame_sink_id].source;
if (!parent_source)
return;
@@ -165,7 +175,7 @@ void FrameSinkManagerImpl::UnregisterFrameSinkHierarchy(
// If the parent does not have a begin frame source, then disconnecting it
// will not change any of its children.
- cc::BeginFrameSource* parent_source = iter->second.source;
+ BeginFrameSource* parent_source = iter->second.source;
if (!parent_source)
return;
@@ -175,6 +185,11 @@ void FrameSinkManagerImpl::UnregisterFrameSinkHierarchy(
RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first);
}
+void FrameSinkManagerImpl::AssignTemporaryReference(const SurfaceId& surface_id,
+ const FrameSinkId& owner) {
+ surface_manager_.AssignTemporaryReference(surface_id, owner);
+}
+
void FrameSinkManagerImpl::DropTemporaryReference(const SurfaceId& surface_id) {
surface_manager_.DropTemporaryReference(surface_id);
}
@@ -207,7 +222,7 @@ void FrameSinkManagerImpl::UnregisterFrameSinkManagerClient(
}
void FrameSinkManagerImpl::RegisterBeginFrameSource(
- cc::BeginFrameSource* source,
+ BeginFrameSource* source,
const FrameSinkId& frame_sink_id) {
DCHECK(source);
DCHECK_EQ(registered_sources_.count(source), 0u);
@@ -219,7 +234,7 @@ void FrameSinkManagerImpl::RegisterBeginFrameSource(
}
void FrameSinkManagerImpl::UnregisterBeginFrameSource(
- cc::BeginFrameSource* source) {
+ BeginFrameSource* source) {
DCHECK(source);
DCHECK_EQ(registered_sources_.count(source), 1u);
@@ -240,13 +255,13 @@ void FrameSinkManagerImpl::UnregisterBeginFrameSource(
RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first);
}
-cc::BeginFrameSource* FrameSinkManagerImpl::GetPrimaryBeginFrameSource() {
+BeginFrameSource* FrameSinkManagerImpl::GetPrimaryBeginFrameSource() {
return &primary_source_;
}
void FrameSinkManagerImpl::RecursivelyAttachBeginFrameSource(
const FrameSinkId& frame_sink_id,
- cc::BeginFrameSource* source) {
+ BeginFrameSource* source) {
FrameSinkSourceMapping& mapping = frame_sink_source_map_[frame_sink_id];
if (!mapping.source) {
mapping.source = source;
@@ -266,7 +281,7 @@ void FrameSinkManagerImpl::RecursivelyAttachBeginFrameSource(
void FrameSinkManagerImpl::RecursivelyDetachBeginFrameSource(
const FrameSinkId& frame_sink_id,
- cc::BeginFrameSource* source) {
+ BeginFrameSource* source) {
auto iter = frame_sink_source_map_.find(frame_sink_id);
if (iter == frame_sink_source_map_.end())
return;
@@ -305,7 +320,8 @@ bool FrameSinkManagerImpl::ChildContains(
return false;
}
-void FrameSinkManagerImpl::OnSurfaceCreated(const SurfaceInfo& surface_info) {
+void FrameSinkManagerImpl::OnFirstSurfaceActivation(
+ const SurfaceInfo& surface_info) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_GT(surface_info.device_scale_factor(), 0.0f);
@@ -315,11 +331,13 @@ void FrameSinkManagerImpl::OnSurfaceCreated(const SurfaceInfo& surface_info) {
// temporary reference was created. It could be useful to let |client_| know
// if it should find an owner.
if (client_)
- client_->OnSurfaceCreated(surface_info);
+ client_->OnFirstSurfaceActivation(surface_info);
}
+void FrameSinkManagerImpl::OnSurfaceActivated(const SurfaceId& surface_id) {}
+
bool FrameSinkManagerImpl::OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) {
+ const BeginFrameAck& ack) {
return false;
}
@@ -327,9 +345,9 @@ void FrameSinkManagerImpl::OnSurfaceDiscarded(const SurfaceId& surface_id) {}
void FrameSinkManagerImpl::OnSurfaceDestroyed(const SurfaceId& surface_id) {}
-void FrameSinkManagerImpl::OnSurfaceDamageExpected(
- const SurfaceId& surface_id,
- const cc::BeginFrameArgs& args) {}
+void FrameSinkManagerImpl::OnSurfaceDamageExpected(const SurfaceId& surface_id,
+ const BeginFrameArgs& args) {
+}
void FrameSinkManagerImpl::OnSurfaceWillDraw(const SurfaceId& surface_id) {}
@@ -340,14 +358,28 @@ void FrameSinkManagerImpl::OnClientConnectionLost(
client_->OnClientConnectionClosed(frame_sink_id);
}
-void FrameSinkManagerImpl::OnPrivateConnectionLost(
- const FrameSinkId& frame_sink_id) {
+void FrameSinkManagerImpl::OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DestroyCompositorFrameSink(frame_sink_id);
+ if (client_) {
+ client_->OnAggregatedHitTestRegionListUpdated(
+ frame_sink_id, std::move(active_handle), active_handle_size,
+ std::move(idle_handle), idle_handle_size);
+ }
}
-void FrameSinkManagerImpl::DestroyCompositorFrameSink(FrameSinkId sink_id) {
- compositor_frame_sinks_.erase(sink_id);
+void FrameSinkManagerImpl::SwitchActiveAggregatedHitTestRegionList(
+ const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (client_) {
+ client_->SwitchActiveAggregatedHitTestRegionList(frame_sink_id,
+ active_handle_index);
+ }
}
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index e042b874e87..a9d23641934 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -14,14 +14,14 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
-#include "cc/ipc/frame_sink_manager.mojom.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_observer.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/service/frame_sinks/primary_begin_frame_source.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/ipc/common/surface_handle.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
namespace cc {
@@ -40,45 +40,46 @@ class FrameSinkManagerClient;
// FrameSinkManagerImpl manages BeginFrame hierarchy. This is the implementation
// detail for FrameSinkManagerImpl.
-class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
- : public cc::SurfaceObserver,
- public NON_EXPORTED_BASE(cc::mojom::FrameSinkManager) {
+class VIZ_SERVICE_EXPORT FrameSinkManagerImpl : public SurfaceObserver,
+ public mojom::FrameSinkManager {
public:
- FrameSinkManagerImpl(DisplayProvider* display_provider = nullptr,
- cc::SurfaceManager::LifetimeType lifetime_type =
- cc::SurfaceManager::LifetimeType::SEQUENCES);
+ FrameSinkManagerImpl(SurfaceManager::LifetimeType lifetime_type =
+ SurfaceManager::LifetimeType::REFERENCES,
+ DisplayProvider* display_provider = nullptr);
~FrameSinkManagerImpl() override;
// Binds |this| as a FrameSinkManagerImpl for |request| on |task_runner|. On
// Mac |task_runner| will be the resize helper task runner. May only be called
// once.
- void BindAndSetClient(cc::mojom::FrameSinkManagerRequest request,
+ void BindAndSetClient(mojom::FrameSinkManagerRequest request,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- cc::mojom::FrameSinkManagerClientPtr client);
+ mojom::FrameSinkManagerClientPtr client);
// Sets up a direction connection to |client| without using Mojo.
- void SetLocalClient(cc::mojom::FrameSinkManagerClient* client);
+ void SetLocalClient(mojom::FrameSinkManagerClient* client);
- // cc::mojom::FrameSinkManager implementation:
+ // mojom::FrameSinkManager implementation:
+ void RegisterFrameSinkId(const FrameSinkId& frame_sink_id) override;
+ void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) override;
void CreateRootCompositorFrameSink(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
- cc::mojom::CompositorFrameSinkAssociatedRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request)
- override;
+ const RendererSettings& renderer_settings,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request) override;
void CreateCompositorFrameSink(
const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client) override;
+ mojom::CompositorFrameSinkRequest request,
+ mojom::CompositorFrameSinkClientPtr client) override;
void RegisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) override;
void UnregisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) override;
+ void AssignTemporaryReference(const SurfaceId& surface_id,
+ const FrameSinkId& owner) override;
void DropTemporaryReference(const SurfaceId& surface_id) override;
// CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be
@@ -99,28 +100,37 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// Associates a |source| with a particular framesink. That framesink and
// any children of that framesink with valid clients can potentially use
// that |source|.
- void RegisterBeginFrameSource(cc::BeginFrameSource* source,
+ void RegisterBeginFrameSource(BeginFrameSource* source,
const FrameSinkId& frame_sink_id);
- void UnregisterBeginFrameSource(cc::BeginFrameSource* source);
+ void UnregisterBeginFrameSource(BeginFrameSource* source);
// Returns a stable BeginFrameSource that forwards BeginFrames from the first
// available BeginFrameSource.
- cc::BeginFrameSource* GetPrimaryBeginFrameSource();
+ BeginFrameSource* GetPrimaryBeginFrameSource();
- cc::SurfaceManager* surface_manager() { return &surface_manager_; }
+ SurfaceManager* surface_manager() { return &surface_manager_; }
- // cc::SurfaceObserver implementation.
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+ // SurfaceObserver implementation.
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
+ void OnSurfaceActivated(const SurfaceId& surface_id) override;
bool OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) override;
+ const BeginFrameAck& ack) override;
void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
void OnSurfaceDamageExpected(const SurfaceId& surface_id,
- const cc::BeginFrameArgs& args) override;
+ const BeginFrameArgs& args) override;
void OnSurfaceWillDraw(const SurfaceId& surface_id) override;
void OnClientConnectionLost(const FrameSinkId& frame_sink_id);
- void OnPrivateConnectionLost(const FrameSinkId& frame_sink_id);
+
+ void OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size);
+ void SwitchActiveAggregatedHitTestRegionList(const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index);
// It is necessary to pass |frame_sink_id| by value because the id
// is owned by the GpuCompositorFrameSink in the map. When the sink is
@@ -133,9 +143,9 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
friend class cc::test::SurfaceSynchronizationTest;
void RecursivelyAttachBeginFrameSource(const FrameSinkId& frame_sink_id,
- cc::BeginFrameSource* source);
+ BeginFrameSource* source);
void RecursivelyDetachBeginFrameSource(const FrameSinkId& frame_sink_id,
- cc::BeginFrameSource* source);
+ BeginFrameSource* source);
// Returns true if |child framesink| is or has |search_frame_sink_id| as a
// child.
@@ -151,7 +161,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
~FrameSinkSourceMapping();
bool has_children() const { return !children.empty(); }
// The currently assigned begin frame source for this client.
- cc::BeginFrameSource* source = nullptr;
+ BeginFrameSource* source = nullptr;
// This represents a dag of parent -> children mapping.
std::vector<FrameSinkId> children;
};
@@ -166,16 +176,16 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// Set of BeginFrameSource along with associated FrameSinkIds. Any child
// that is implicitly using this framesink must be reachable by the
// parent in the dag.
- std::unordered_map<cc::BeginFrameSource*, FrameSinkId> registered_sources_;
+ std::unordered_map<BeginFrameSource*, FrameSinkId> registered_sources_;
PrimaryBeginFrameSource primary_source_;
// |surface_manager_| should be placed under |primary_source_| so that all
// surfaces are destroyed before |primary_source_|.
- cc::SurfaceManager surface_manager_;
+ SurfaceManager surface_manager_;
std::unordered_map<FrameSinkId,
- std::unique_ptr<cc::mojom::CompositorFrameSink>,
+ std::unique_ptr<mojom::CompositorFrameSink>,
FrameSinkIdHash>
compositor_frame_sinks_;
@@ -183,10 +193,10 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// This will point to |client_ptr_| if using Mojo or a provided client if
// directly connected. Use this to make function calls.
- cc::mojom::FrameSinkManagerClient* client_ = nullptr;
+ mojom::FrameSinkManagerClient* client_ = nullptr;
- cc::mojom::FrameSinkManagerClientPtr client_ptr_;
- mojo::Binding<cc::mojom::FrameSinkManager> binding_;
+ mojom::FrameSinkManagerClientPtr client_ptr_;
+ mojo::Binding<mojom::FrameSinkManager> binding_;
DISALLOW_COPY_AND_ASSIGN(FrameSinkManagerImpl);
};
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
index 8fd888d7ba1..b5797143305 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
@@ -4,19 +4,17 @@
#include <stddef.h>
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/test/begin_frame_source_test.h"
-#include "cc/test/fake_external_begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_client.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/test/begin_frame_source_test.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
-
namespace {
constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
-}
class FakeFrameSinkManagerClient : public FrameSinkManagerClient {
public:
@@ -37,7 +35,7 @@ class FakeFrameSinkManagerClient : public FrameSinkManagerClient {
EXPECT_EQ(nullptr, source_);
}
- cc::BeginFrameSource* source() { return source_; }
+ BeginFrameSource* source() { return source_; }
const FrameSinkId& frame_sink_id() { return frame_sink_id_; }
void Register(FrameSinkManagerImpl* manager) {
@@ -53,13 +51,13 @@ class FakeFrameSinkManagerClient : public FrameSinkManagerClient {
}
// FrameSinkManagerClient implementation.
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override {
+ void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
DCHECK(!source_ || !begin_frame_source);
source_ = begin_frame_source;
}
private:
- cc::BeginFrameSource* source_;
+ BeginFrameSource* source_;
FrameSinkManagerImpl* manager_;
FrameSinkId frame_sink_id_;
};
@@ -67,7 +65,6 @@ class FakeFrameSinkManagerClient : public FrameSinkManagerClient {
class FrameSinkManagerTest : public testing::Test {
public:
FrameSinkManagerTest() = default;
-
~FrameSinkManagerTest() override = default;
protected:
@@ -77,7 +74,7 @@ class FrameSinkManagerTest : public testing::Test {
TEST_F(FrameSinkManagerTest, SingleClients) {
FakeFrameSinkManagerClient client(FrameSinkId(1, 1));
FakeFrameSinkManagerClient other_client(FrameSinkId(2, 2));
- cc::StubBeginFrameSource source;
+ StubBeginFrameSource source;
EXPECT_EQ(nullptr, client.source());
EXPECT_EQ(nullptr, other_client.source());
@@ -113,7 +110,7 @@ TEST_F(FrameSinkManagerTest, SingleClients) {
// after restart.
TEST_F(FrameSinkManagerTest, ClientRestart) {
FakeFrameSinkManagerClient client(kArbitraryFrameSinkId);
- cc::StubBeginFrameSource source;
+ StubBeginFrameSource source;
client.Register(&manager_);
manager_.RegisterBeginFrameSource(&source, kArbitraryFrameSinkId);
@@ -137,29 +134,27 @@ TEST_F(FrameSinkManagerTest, ClientRestart) {
TEST_F(FrameSinkManagerTest, PrimaryBeginFrameSource) {
// This PrimaryBeginFrameSource should track the first BeginFrameSource
// registered with the SurfaceManager.
- testing::NiceMock<cc::MockBeginFrameObserver> obs;
- cc::BeginFrameSource* begin_frame_source =
- manager_.GetPrimaryBeginFrameSource();
+ testing::NiceMock<MockBeginFrameObserver> obs;
+ BeginFrameSource* begin_frame_source = manager_.GetPrimaryBeginFrameSource();
begin_frame_source->AddObserver(&obs);
FakeFrameSinkManagerClient root1(FrameSinkId(1, 1), &manager_);
- std::unique_ptr<cc::FakeExternalBeginFrameSource> external_source1 =
- base::MakeUnique<cc::FakeExternalBeginFrameSource>(60.f, false);
+ std::unique_ptr<FakeExternalBeginFrameSource> external_source1 =
+ base::MakeUnique<FakeExternalBeginFrameSource>(60.f, false);
manager_.RegisterBeginFrameSource(external_source1.get(),
root1.frame_sink_id());
FakeFrameSinkManagerClient root2(FrameSinkId(2, 2), &manager_);
- std::unique_ptr<cc::FakeExternalBeginFrameSource> external_source2 =
- base::MakeUnique<cc::FakeExternalBeginFrameSource>(60.f, false);
+ std::unique_ptr<FakeExternalBeginFrameSource> external_source2 =
+ base::MakeUnique<FakeExternalBeginFrameSource>(60.f, false);
manager_.RegisterBeginFrameSource(external_source2.get(),
root2.frame_sink_id());
- cc::BeginFrameArgs args =
- cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
-
// Ticking |external_source2| does not propagate to |begin_frame_source|.
{
- EXPECT_CALL(obs, OnBeginFrame(args)).Times(0);
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, external_source2->source_id(), 1);
+ EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(0);
external_source2->TestOnBeginFrame(args);
testing::Mock::VerifyAndClearExpectations(&obs);
}
@@ -167,7 +162,9 @@ TEST_F(FrameSinkManagerTest, PrimaryBeginFrameSource) {
// Ticking |external_source1| does propagate to |begin_frame_source| and
// |obs|.
{
- EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(1);
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, external_source1->source_id(), 1);
+ EXPECT_CALL(obs, OnBeginFrame(args)).Times(1);
external_source1->TestOnBeginFrame(args);
testing::Mock::VerifyAndClearExpectations(&obs);
}
@@ -176,11 +173,17 @@ TEST_F(FrameSinkManagerTest, PrimaryBeginFrameSource) {
// propagate. Instead, |external_source2|'s BeginFrames will propagate
// to |begin_frame_source|.
{
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, external_source1->source_id(), 2);
manager_.UnregisterBeginFrameSource(external_source1.get());
EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(0);
external_source1->TestOnBeginFrame(args);
testing::Mock::VerifyAndClearExpectations(&obs);
+ }
+ {
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, external_source2->source_id(), 2);
EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(1);
external_source2->TestOnBeginFrame(args);
testing::Mock::VerifyAndClearExpectations(&obs);
@@ -192,8 +195,8 @@ TEST_F(FrameSinkManagerTest, PrimaryBeginFrameSource) {
}
TEST_F(FrameSinkManagerTest, MultipleDisplays) {
- cc::StubBeginFrameSource root1_source;
- cc::StubBeginFrameSource root2_source;
+ StubBeginFrameSource root1_source;
+ StubBeginFrameSource root2_source;
// root1 -> A -> B
// root2 -> C
@@ -262,7 +265,7 @@ TEST_F(FrameSinkManagerTest, MultipleDisplays) {
// FrameSinkId is preserved even if that FrameSinkId has no children
// and does not have a corresponding FrameSinkManagerClient.
TEST_F(FrameSinkManagerTest, ParentWithoutClientRetained) {
- cc::StubBeginFrameSource root_source;
+ StubBeginFrameSource root_source;
constexpr FrameSinkId kFrameSinkIdRoot(1, 1);
constexpr FrameSinkId kFrameSinkIdA(2, 2);
@@ -301,7 +304,7 @@ TEST_F(FrameSinkManagerTest, ParentWithoutClientRetained) {
// propagates all the way to C.
TEST_F(FrameSinkManagerTest,
ParentWithoutClientRetained_LateBeginFrameRegistration) {
- cc::StubBeginFrameSource root_source;
+ StubBeginFrameSource root_source;
constexpr FrameSinkId kFrameSinkIdRoot(1, 1);
constexpr FrameSinkId kFrameSinkIdA(2, 2);
@@ -439,7 +442,7 @@ class SurfaceManagerOrderingTest : public FrameSinkManagerTest {
AssertAllValidBFS();
}
- cc::StubBeginFrameSource source_;
+ StubBeginFrameSource source_;
// A -> B -> C hierarchy, with A always having the BFS.
FakeFrameSinkManagerClient client_a_;
FakeFrameSinkManagerClient client_b_;
@@ -526,4 +529,5 @@ INSTANTIATE_TEST_CASE_P(
::testing::ValuesIn(kUnregisterOrderList),
::testing::ValuesIn(kBFSOrderList)));
+} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc b/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc
deleted file mode 100644
index 12e0d5bc124..00000000000
--- a/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc
+++ /dev/null
@@ -1,106 +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/viz/service/frame_sinks/gpu_compositor_frame_sink.h"
-
-#include <utility>
-
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
-
-namespace viz {
-
-GpuCompositorFrameSink::GpuCompositorFrameSink(
- FrameSinkManagerImpl* frame_sink_manager,
- const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest
- compositor_frame_sink_private_request,
- cc::mojom::CompositorFrameSinkClientPtr client)
- : support_(CompositorFrameSinkSupport::Create(
- this,
- frame_sink_manager,
- frame_sink_id,
- false /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
- true /* needs_sync_points */)),
- client_(std::move(client)),
- compositor_frame_sink_binding_(this, std::move(request)),
- compositor_frame_sink_private_binding_(
- this,
- std::move(compositor_frame_sink_private_request)) {
- compositor_frame_sink_binding_.set_connection_error_handler(base::Bind(
- &GpuCompositorFrameSink::OnClientConnectionLost, base::Unretained(this)));
- compositor_frame_sink_private_binding_.set_connection_error_handler(
- base::Bind(&GpuCompositorFrameSink::OnPrivateConnectionLost,
- base::Unretained(this)));
-}
-
-GpuCompositorFrameSink::~GpuCompositorFrameSink() = default;
-
-void GpuCompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) {
- support_->SetNeedsBeginFrame(needs_begin_frame);
-}
-
-void GpuCompositorFrameSink::SubmitCompositorFrame(
- const LocalSurfaceId& local_surface_id,
- cc::CompositorFrame frame) {
- if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
- compositor_frame_sink_binding_.CloseWithReason(
- 1, "Surface invariants violation");
- OnClientConnectionLost();
- }
-}
-
-void GpuCompositorFrameSink::DidNotProduceFrame(
- const cc::BeginFrameAck& begin_frame_ack) {
- support_->DidNotProduceFrame(begin_frame_ack);
-}
-
-void GpuCompositorFrameSink::DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) {
- if (client_)
- client_->DidReceiveCompositorFrameAck(resources);
-}
-
-void GpuCompositorFrameSink::ClaimTemporaryReference(
- const SurfaceId& surface_id) {
- support_->ClaimTemporaryReference(surface_id);
-}
-
-void GpuCompositorFrameSink::RequestCopyOfSurface(
- std::unique_ptr<cc::CopyOutputRequest> request) {
- support_->RequestCopyOfSurface(std::move(request));
-}
-
-void GpuCompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
- if (client_)
- client_->OnBeginFrame(args);
-}
-
-void GpuCompositorFrameSink::OnBeginFramePausedChanged(bool paused) {
- if (client_)
- client_->OnBeginFramePausedChanged(paused);
-}
-
-void GpuCompositorFrameSink::ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) {
- if (client_)
- client_->ReclaimResources(resources);
-}
-
-void GpuCompositorFrameSink::WillDrawSurface(
- const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {}
-
-void GpuCompositorFrameSink::OnClientConnectionLost() {
- support_->frame_sink_manager()->OnClientConnectionLost(
- support_->frame_sink_id());
-}
-
-void GpuCompositorFrameSink::OnPrivateConnectionLost() {
- support_->frame_sink_manager()->OnPrivateConnectionLost(
- support_->frame_sink_id());
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h b/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h
deleted file mode 100644
index 54a40561929..00000000000
--- a/chromium/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
-#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "cc/ipc/compositor_frame_sink.mojom.h"
-#include "components/viz/common/surfaces/local_surface_id.h"
-#include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace viz {
-
-// Server side representation of a WindowSurface.
-class GpuCompositorFrameSink
- : public NON_EXPORTED_BASE(CompositorFrameSinkSupportClient),
- public NON_EXPORTED_BASE(cc::mojom::CompositorFrameSink),
- public NON_EXPORTED_BASE(cc::mojom::CompositorFrameSinkPrivate) {
- public:
- GpuCompositorFrameSink(
- FrameSinkManagerImpl* frame_sink_manager,
- const FrameSinkId& frame_sink_id,
- cc::mojom::CompositorFrameSinkRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client);
-
- ~GpuCompositorFrameSink() override;
-
- // cc::mojom::CompositorFrameSink:
- void SetNeedsBeginFrame(bool needs_begin_frame) override;
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
- cc::CompositorFrame frame) override;
- void DidNotProduceFrame(const cc::BeginFrameAck& begin_frame_ack) override;
-
- // cc::mojom::CompositorFrameSinkPrivate:
- void ClaimTemporaryReference(const SurfaceId& surface_id) override;
- void RequestCopyOfSurface(
- std::unique_ptr<cc::CopyOutputRequest> request) override;
-
- private:
- // CompositorFrameSinkSupportClient implementation:
- void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override;
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
- void OnBeginFramePausedChanged(bool paused) override;
- void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override;
- void WillDrawSurface(const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
-
- void OnClientConnectionLost();
- void OnPrivateConnectionLost();
-
- std::unique_ptr<CompositorFrameSinkSupport> support_;
-
- cc::mojom::CompositorFrameSinkClientPtr client_;
- mojo::Binding<cc::mojom::CompositorFrameSink> compositor_frame_sink_binding_;
- mojo::Binding<cc::mojom::CompositorFrameSinkPrivate>
- compositor_frame_sink_private_binding_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuCompositorFrameSink);
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_
diff --git a/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc b/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc
deleted file mode 100644
index 610d3f85c08..00000000000
--- a/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "components/viz/service/display/display.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
-
-namespace viz {
-
-GpuRootCompositorFrameSink::GpuRootCompositorFrameSink(
- FrameSinkManagerImpl* frame_sink_manager,
- const FrameSinkId& frame_sink_id,
- std::unique_ptr<Display> display,
- std::unique_ptr<cc::BeginFrameSource> begin_frame_source,
- cc::mojom::CompositorFrameSinkAssociatedRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest
- compositor_frame_sink_private_request,
- cc::mojom::CompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request)
- : support_(CompositorFrameSinkSupport::Create(
- this,
- frame_sink_manager,
- frame_sink_id,
- true /* is_root */,
- true /* handles_frame_sink_id_invalidation */,
- true /* needs_sync_points */)),
- display_begin_frame_source_(std::move(begin_frame_source)),
- display_(std::move(display)),
- client_(std::move(client)),
- compositor_frame_sink_binding_(this, std::move(request)),
- compositor_frame_sink_private_binding_(
- this,
- std::move(compositor_frame_sink_private_request)),
- display_private_binding_(this, std::move(display_private_request)) {
- DCHECK(display_begin_frame_source_);
- compositor_frame_sink_binding_.set_connection_error_handler(
- base::Bind(&GpuRootCompositorFrameSink::OnClientConnectionLost,
- base::Unretained(this)));
- compositor_frame_sink_private_binding_.set_connection_error_handler(
- base::Bind(&GpuRootCompositorFrameSink::OnPrivateConnectionLost,
- base::Unretained(this)));
- frame_sink_manager->RegisterBeginFrameSource(
- display_begin_frame_source_.get(), frame_sink_id);
- display_->Initialize(this, frame_sink_manager->surface_manager());
-}
-
-GpuRootCompositorFrameSink::~GpuRootCompositorFrameSink() {
- support_->frame_sink_manager()->UnregisterBeginFrameSource(
- display_begin_frame_source_.get());
-}
-
-void GpuRootCompositorFrameSink::SetDisplayVisible(bool visible) {
- DCHECK(display_);
- display_->SetVisible(visible);
-}
-
-void GpuRootCompositorFrameSink::ResizeDisplay(const gfx::Size& size) {
- DCHECK(display_);
- display_->Resize(size);
-}
-
-void GpuRootCompositorFrameSink::SetDisplayColorSpace(
- const gfx::ColorSpace& color_space) {
- DCHECK(display_);
- display_->SetColorSpace(color_space, color_space);
-}
-
-void GpuRootCompositorFrameSink::SetOutputIsSecure(bool secure) {
- DCHECK(display_);
- display_->SetOutputIsSecure(secure);
-}
-
-void GpuRootCompositorFrameSink::SetLocalSurfaceId(
- const LocalSurfaceId& local_surface_id,
- float scale_factor) {
- display_->SetLocalSurfaceId(local_surface_id, scale_factor);
-}
-
-void GpuRootCompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) {
- support_->SetNeedsBeginFrame(needs_begin_frame);
-}
-
-void GpuRootCompositorFrameSink::SubmitCompositorFrame(
- const LocalSurfaceId& local_surface_id,
- cc::CompositorFrame frame) {
- if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
- compositor_frame_sink_binding_.Close();
- OnClientConnectionLost();
- }
-}
-
-void GpuRootCompositorFrameSink::DidNotProduceFrame(
- const cc::BeginFrameAck& begin_frame_ack) {
- support_->DidNotProduceFrame(begin_frame_ack);
-}
-
-void GpuRootCompositorFrameSink::ClaimTemporaryReference(
- const SurfaceId& surface_id) {
- support_->ClaimTemporaryReference(surface_id);
-}
-
-void GpuRootCompositorFrameSink::RequestCopyOfSurface(
- std::unique_ptr<cc::CopyOutputRequest> request) {
- support_->RequestCopyOfSurface(std::move(request));
-}
-
-void GpuRootCompositorFrameSink::DisplayOutputSurfaceLost() {
- // TODO(staraz): Implement this. Client should hear about context/output
- // surface lost.
-}
-
-void GpuRootCompositorFrameSink::DisplayWillDrawAndSwap(
- bool will_draw_and_swap,
- const cc::RenderPassList& render_pass) {
- hit_test_aggregator_.PostTaskAggregate(display_->CurrentSurfaceId());
-}
-
-void GpuRootCompositorFrameSink::DisplayDidDrawAndSwap() {}
-
-void GpuRootCompositorFrameSink::DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) {
- if (client_)
- client_->DidReceiveCompositorFrameAck(resources);
-}
-
-void GpuRootCompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
- hit_test_aggregator_.Swap();
- if (client_)
- client_->OnBeginFrame(args);
-}
-
-void GpuRootCompositorFrameSink::OnBeginFramePausedChanged(bool paused) {
- if (client_)
- client_->OnBeginFramePausedChanged(paused);
-}
-
-void GpuRootCompositorFrameSink::ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) {
- if (client_)
- client_->ReclaimResources(resources);
-}
-
-void GpuRootCompositorFrameSink::WillDrawSurface(
- const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {}
-
-void GpuRootCompositorFrameSink::OnClientConnectionLost() {
- support_->frame_sink_manager()->OnClientConnectionLost(
- support_->frame_sink_id());
-}
-
-void GpuRootCompositorFrameSink::OnPrivateConnectionLost() {
- support_->frame_sink_manager()->OnPrivateConnectionLost(
- support_->frame_sink_id());
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h b/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h
deleted file mode 100644
index 05ef8d6cec0..00000000000
--- a/chromium/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
-#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
-
-#include <memory>
-
-#include "cc/ipc/compositor_frame_sink.mojom.h"
-#include "cc/ipc/frame_sink_manager.mojom.h"
-#include "components/viz/common/surfaces/local_surface_id.h"
-#include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/service/display/display_client.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
-#include "components/viz/service/hit_test/hit_test_aggregator.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace cc {
-class BeginFrameSource;
-}
-
-namespace viz {
-class CompositorFrameSinkSupport;
-class Display;
-class FrameSinkManagerImpl;
-
-class GpuRootCompositorFrameSink
- : public NON_EXPORTED_BASE(CompositorFrameSinkSupportClient),
- public NON_EXPORTED_BASE(cc::mojom::CompositorFrameSink),
- public NON_EXPORTED_BASE(cc::mojom::CompositorFrameSinkPrivate),
- public NON_EXPORTED_BASE(cc::mojom::DisplayPrivate),
- public NON_EXPORTED_BASE(DisplayClient) {
- public:
- GpuRootCompositorFrameSink(
- FrameSinkManagerImpl* frame_sink_manager,
- const FrameSinkId& frame_sink_id,
- std::unique_ptr<Display> display,
- std::unique_ptr<cc::BeginFrameSource> begin_frame_source,
- cc::mojom::CompositorFrameSinkAssociatedRequest request,
- cc::mojom::CompositorFrameSinkPrivateRequest private_request,
- cc::mojom::CompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request);
-
- ~GpuRootCompositorFrameSink() override;
-
- // cc::mojom::DisplayPrivate:
- void SetDisplayVisible(bool visible) override;
- void ResizeDisplay(const gfx::Size& size) override;
- void SetDisplayColorSpace(const gfx::ColorSpace& color_space) override;
- void SetOutputIsSecure(bool secure) override;
- void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id,
- float scale_factor) override;
-
- // cc::mojom::CompositorFrameSink:
- void SetNeedsBeginFrame(bool needs_begin_frame) override;
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
- cc::CompositorFrame frame) override;
- void DidNotProduceFrame(const cc::BeginFrameAck& begin_frame_ack) override;
-
- // cc::mojom::CompositorFrameSinkPrivate:
- void ClaimTemporaryReference(const SurfaceId& surface_id) override;
- void RequestCopyOfSurface(
- std::unique_ptr<cc::CopyOutputRequest> request) override;
-
- private:
- // DisplayClient:
- void DisplayOutputSurfaceLost() override;
- void DisplayWillDrawAndSwap(bool will_draw_and_swap,
- const cc::RenderPassList& render_passes) override;
- void DisplayDidDrawAndSwap() override;
-
- // CompositorFrameSinkSupportClient:
- void DidReceiveCompositorFrameAck(
- const std::vector<cc::ReturnedResource>& resources) override;
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
- void OnBeginFramePausedChanged(bool paused) override;
- void ReclaimResources(
- const std::vector<cc::ReturnedResource>& resources) override;
- void WillDrawSurface(const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
-
- void OnClientConnectionLost();
- void OnPrivateConnectionLost();
-
- std::unique_ptr<CompositorFrameSinkSupport> support_;
-
- // GpuRootCompositorFrameSink holds a Display and its BeginFrameSource if
- // it was created with a non-null gpu::SurfaceHandle.
- std::unique_ptr<cc::BeginFrameSource> display_begin_frame_source_;
- std::unique_ptr<Display> display_;
-
- cc::mojom::CompositorFrameSinkClientPtr client_;
- mojo::AssociatedBinding<cc::mojom::CompositorFrameSink>
- compositor_frame_sink_binding_;
- mojo::Binding<cc::mojom::CompositorFrameSinkPrivate>
- compositor_frame_sink_private_binding_;
- mojo::AssociatedBinding<cc::mojom::DisplayPrivate> display_private_binding_;
-
- HitTestAggregator hit_test_aggregator_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuRootCompositorFrameSink);
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_
diff --git a/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.cc b/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.cc
index 58ec08404e0..be6fa15ac19 100644
--- a/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.cc
+++ b/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.cc
@@ -12,7 +12,7 @@ PrimaryBeginFrameSource::PrimaryBeginFrameSource()
PrimaryBeginFrameSource::~PrimaryBeginFrameSource() = default;
void PrimaryBeginFrameSource::OnBeginFrameSourceAdded(
- cc::BeginFrameSource* begin_frame_source) {
+ BeginFrameSource* begin_frame_source) {
sources_.insert(begin_frame_source);
if (current_begin_frame_source_)
@@ -24,7 +24,7 @@ void PrimaryBeginFrameSource::OnBeginFrameSourceAdded(
}
void PrimaryBeginFrameSource::OnBeginFrameSourceRemoved(
- cc::BeginFrameSource* begin_frame_source) {
+ BeginFrameSource* begin_frame_source) {
sources_.erase(begin_frame_source);
if (current_begin_frame_source_ != begin_frame_source)
return;
@@ -41,27 +41,26 @@ void PrimaryBeginFrameSource::OnBeginFrameSourceRemoved(
current_begin_frame_source_->AddObserver(this);
}
-void PrimaryBeginFrameSource::OnBeginFrame(const cc::BeginFrameArgs& args) {
+void PrimaryBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
begin_frame_source_.OnBeginFrame(args);
last_begin_frame_args_ = args;
}
-const cc::BeginFrameArgs& PrimaryBeginFrameSource::LastUsedBeginFrameArgs()
- const {
+const BeginFrameArgs& PrimaryBeginFrameSource::LastUsedBeginFrameArgs() const {
return last_begin_frame_args_;
}
void PrimaryBeginFrameSource::OnBeginFrameSourcePausedChanged(bool paused) {}
-void PrimaryBeginFrameSource::DidFinishFrame(cc::BeginFrameObserver* obs) {
+void PrimaryBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs) {
begin_frame_source_.DidFinishFrame(obs);
}
-void PrimaryBeginFrameSource::AddObserver(cc::BeginFrameObserver* obs) {
+void PrimaryBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
begin_frame_source_.AddObserver(obs);
}
-void PrimaryBeginFrameSource::RemoveObserver(cc::BeginFrameObserver* obs) {
+void PrimaryBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
begin_frame_source_.RemoveObserver(obs);
}
diff --git a/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.h b/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.h
index 51aec3dc8cb..2576c7a4000 100644
--- a/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.h
+++ b/chromium/components/viz/service/frame_sinks/primary_begin_frame_source.h
@@ -6,7 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_PRIMARY_BEGIN_FRAME_SOURCE_H_
#include "base/containers/flat_set.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
@@ -15,40 +15,40 @@ namespace viz {
// If the first source goes away then it will echo the new first
// BeginFrameSource.
class VIZ_SERVICE_EXPORT PrimaryBeginFrameSource
- : public cc::BeginFrameSource,
- public cc::BeginFrameObserver,
- public cc::ExternalBeginFrameSourceClient {
+ : public BeginFrameSource,
+ public BeginFrameObserver,
+ public ExternalBeginFrameSourceClient {
public:
PrimaryBeginFrameSource();
~PrimaryBeginFrameSource() override;
- void OnBeginFrameSourceAdded(cc::BeginFrameSource* begin_frame_source);
- void OnBeginFrameSourceRemoved(cc::BeginFrameSource* begin_frame_source);
+ void OnBeginFrameSourceAdded(BeginFrameSource* begin_frame_source);
+ void OnBeginFrameSourceRemoved(BeginFrameSource* begin_frame_source);
- // cc::BeginFrameObserver implementation.
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
- const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ // BeginFrameObserver implementation.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
void OnBeginFrameSourcePausedChanged(bool paused) override;
- // cc::BeginFrameSource implementation.
- void DidFinishFrame(cc::BeginFrameObserver* obs) override;
- void AddObserver(cc::BeginFrameObserver* obs) override;
- void RemoveObserver(cc::BeginFrameObserver* obs) override;
+ // BeginFrameSource implementation.
+ void DidFinishFrame(BeginFrameObserver* obs) override;
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
bool IsThrottled() const override;
- // cc::ExternalBeginFrameSourceClient implementation.
+ // ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;
private:
- cc::ExternalBeginFrameSource begin_frame_source_;
- cc::BeginFrameSource* current_begin_frame_source_ = nullptr;
+ ExternalBeginFrameSource begin_frame_source_;
+ BeginFrameSource* current_begin_frame_source_ = nullptr;
// The last begin frame args generated by the begin frame source.
- cc::BeginFrameArgs last_begin_frame_args_;
+ BeginFrameArgs last_begin_frame_args_;
bool needs_begin_frames_ = false;
- base::flat_set<cc::BeginFrameSource*> sources_;
+ base::flat_set<BeginFrameSource*> sources_;
DISALLOW_COPY_AND_ASSIGN(PrimaryBeginFrameSource);
};
diff --git a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.cc b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.cc
index 6464e324d1c..30d7a1b134d 100644
--- a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.cc
+++ b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.cc
@@ -12,8 +12,8 @@ void GetSurfaceReferenceDifference(
const SurfaceId& parent_surface_id,
const base::flat_set<SurfaceId>& old_referenced_surfaces,
const base::flat_set<SurfaceId>& new_referenced_surfaces,
- std::vector<cc::SurfaceReference>* references_to_add,
- std::vector<cc::SurfaceReference>* references_to_remove) {
+ std::vector<SurfaceReference>* references_to_add,
+ std::vector<SurfaceReference>* references_to_remove) {
DCHECK(parent_surface_id.is_valid());
// Find SurfaceIds in |old_referenced_surfaces| that aren't referenced
@@ -21,7 +21,7 @@ void GetSurfaceReferenceDifference(
for (const SurfaceId& surface_id : old_referenced_surfaces) {
if (new_referenced_surfaces.count(surface_id) == 0) {
references_to_remove->push_back(
- cc::SurfaceReference(parent_surface_id, surface_id));
+ SurfaceReference(parent_surface_id, surface_id));
}
}
@@ -30,7 +30,7 @@ void GetSurfaceReferenceDifference(
for (const SurfaceId& surface_id : new_referenced_surfaces) {
if (old_referenced_surfaces.count(surface_id) == 0) {
references_to_add->push_back(
- cc::SurfaceReference(parent_surface_id, surface_id));
+ SurfaceReference(parent_surface_id, surface_id));
}
}
}
diff --git a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.h b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.h
index 4bed2beb346..1b45923baf7 100644
--- a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.h
+++ b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker.h
@@ -8,8 +8,8 @@
#include <vector>
#include "base/containers/flat_set.h"
-#include "cc/surfaces/surface_reference.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/surfaces/surface_reference.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
@@ -22,8 +22,8 @@ void VIZ_SERVICE_EXPORT GetSurfaceReferenceDifference(
const SurfaceId& parent_surface_id,
const base::flat_set<SurfaceId>& old_referenced_surfaces,
const base::flat_set<SurfaceId>& new_referenced_surfaces,
- std::vector<cc::SurfaceReference>* references_to_add,
- std::vector<cc::SurfaceReference>* references_to_remove);
+ std::vector<SurfaceReference>* references_to_add,
+ std::vector<SurfaceReference>* references_to_remove);
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker_unittest.cc b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker_unittest.cc
index 7ff2d17d26a..e9816711e2f 100644
--- a/chromium/components/viz/service/frame_sinks/referenced_surface_tracker_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/referenced_surface_tracker_unittest.cc
@@ -10,9 +10,9 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "cc/surfaces/surface_reference.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/surfaces/surface_reference.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -45,11 +45,11 @@ class ReferencedSurfaceTrackerTest : public testing::Test {
ReferencedSurfaceTrackerTest() {}
~ReferencedSurfaceTrackerTest() override {}
- const std::vector<cc::SurfaceReference>& references_to_remove() const {
+ const std::vector<SurfaceReference>& references_to_remove() const {
return references_to_remove_;
}
- const std::vector<cc::SurfaceReference>& references_to_add() const {
+ const std::vector<SurfaceReference>& references_to_add() const {
return references_to_add_;
}
@@ -65,8 +65,8 @@ class ReferencedSurfaceTrackerTest : public testing::Test {
}
private:
- std::vector<cc::SurfaceReference> references_to_add_;
- std::vector<cc::SurfaceReference> references_to_remove_;
+ std::vector<SurfaceReference> references_to_add_;
+ std::vector<SurfaceReference> references_to_remove_;
DISALLOW_COPY_AND_ASSIGN(ReferencedSurfaceTrackerTest);
};
@@ -74,7 +74,7 @@ class ReferencedSurfaceTrackerTest : public testing::Test {
TEST_F(ReferencedSurfaceTrackerTest, AddSurfaceReference) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const cc::SurfaceReference reference(parent_id, child_id1);
+ const SurfaceReference reference(parent_id, child_id1);
// Check that reference to |child_id1| is added.
UpdateReferences(parent_id, MakeReferenceSet({}),
@@ -86,7 +86,7 @@ TEST_F(ReferencedSurfaceTrackerTest, AddSurfaceReference) {
TEST_F(ReferencedSurfaceTrackerTest, NoChangeToReferences) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const cc::SurfaceReference reference(parent_id, child_id1);
+ const SurfaceReference reference(parent_id, child_id1);
// Check that no references are added or removed.
auto referenced_surfaces = MakeReferenceSet({child_id1});
@@ -98,7 +98,7 @@ TEST_F(ReferencedSurfaceTrackerTest, NoChangeToReferences) {
TEST_F(ReferencedSurfaceTrackerTest, RemoveSurfaceReference) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const cc::SurfaceReference reference(parent_id, child_id1);
+ const SurfaceReference reference(parent_id, child_id1);
// Check that reference to |child_id1| is removed.
UpdateReferences(parent_id, MakeReferenceSet({child_id1}),
@@ -111,8 +111,8 @@ TEST_F(ReferencedSurfaceTrackerTest, RemoveOneOfTwoSurfaceReferences) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1_first = MakeSurfaceId(kChildFrameSink1, 1);
const SurfaceId child_id1_second = MakeSurfaceId(kChildFrameSink1, 2);
- const cc::SurfaceReference reference_first(parent_id, child_id1_first);
- const cc::SurfaceReference reference_second(parent_id, child_id1_second);
+ const SurfaceReference reference_first(parent_id, child_id1_first);
+ const SurfaceReference reference_second(parent_id, child_id1_second);
// Check that reference to |child_id1_first| is removed and reference to
// |child_id1_second| is added.
@@ -126,8 +126,8 @@ TEST_F(ReferencedSurfaceTrackerTest, AddTwoThenRemoveOneSurfaceReferences) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 2);
- const cc::SurfaceReference reference1(parent_id, child_id1);
- const cc::SurfaceReference reference2(parent_id, child_id2);
+ const SurfaceReference reference1(parent_id, child_id1);
+ const SurfaceReference reference2(parent_id, child_id2);
// Check that first frame adds both surface references.
const auto initial_referenced = MakeReferenceSet({child_id1, child_id2});
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
new file mode 100644
index 00000000000..eb03cb18b30
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -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.
+
+#include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "components/viz/service/display/display.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+
+namespace viz {
+
+RootCompositorFrameSinkImpl::RootCompositorFrameSinkImpl(
+ FrameSinkManagerImpl* frame_sink_manager,
+ const FrameSinkId& frame_sink_id,
+ std::unique_ptr<Display> display,
+ std::unique_ptr<BeginFrameSource> begin_frame_source,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request)
+ : support_(
+ CompositorFrameSinkSupport::Create(this,
+ frame_sink_manager,
+ frame_sink_id,
+ true /* is_root */,
+ true /* needs_sync_points */)),
+ display_begin_frame_source_(std::move(begin_frame_source)),
+ display_(std::move(display)),
+ client_(std::move(client)),
+ compositor_frame_sink_binding_(this, std::move(request)),
+ display_private_binding_(this, std::move(display_private_request)),
+ hit_test_aggregator_(this) {
+ DCHECK(display_begin_frame_source_);
+ compositor_frame_sink_binding_.set_connection_error_handler(
+ base::Bind(&RootCompositorFrameSinkImpl::OnClientConnectionLost,
+ base::Unretained(this)));
+ frame_sink_manager->RegisterBeginFrameSource(
+ display_begin_frame_source_.get(), frame_sink_id);
+ display_->Initialize(this, frame_sink_manager->surface_manager());
+}
+
+RootCompositorFrameSinkImpl::~RootCompositorFrameSinkImpl() {
+ support_->frame_sink_manager()->UnregisterBeginFrameSource(
+ display_begin_frame_source_.get());
+}
+
+void RootCompositorFrameSinkImpl::SetDisplayVisible(bool visible) {
+ DCHECK(display_);
+ display_->SetVisible(visible);
+}
+
+void RootCompositorFrameSinkImpl::ResizeDisplay(const gfx::Size& size) {
+ DCHECK(display_);
+ display_->Resize(size);
+}
+
+void RootCompositorFrameSinkImpl::SetDisplayColorSpace(
+ const gfx::ColorSpace& color_space) {
+ DCHECK(display_);
+ display_->SetColorSpace(color_space, color_space);
+}
+
+void RootCompositorFrameSinkImpl::SetOutputIsSecure(bool secure) {
+ DCHECK(display_);
+ display_->SetOutputIsSecure(secure);
+}
+
+void RootCompositorFrameSinkImpl::SetLocalSurfaceId(
+ const LocalSurfaceId& local_surface_id,
+ float scale_factor) {
+ display_->SetLocalSurfaceId(local_surface_id, scale_factor);
+}
+
+void RootCompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) {
+ support_->SetNeedsBeginFrame(needs_begin_frame);
+}
+
+void RootCompositorFrameSinkImpl::SubmitCompositorFrame(
+ const LocalSurfaceId& local_surface_id,
+ cc::CompositorFrame frame,
+ mojom::HitTestRegionListPtr hit_test_region_list,
+ uint64_t submit_time) {
+ // TODO(gklassen): send |hit_test_region_list| to |support_|.
+ if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
+ compositor_frame_sink_binding_.Close();
+ OnClientConnectionLost();
+ }
+}
+
+void RootCompositorFrameSinkImpl::DidNotProduceFrame(
+ const BeginFrameAck& begin_frame_ack) {
+ support_->DidNotProduceFrame(begin_frame_ack);
+}
+
+void RootCompositorFrameSinkImpl::OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
+ support_->frame_sink_manager()->OnAggregatedHitTestRegionListUpdated(
+ support_->frame_sink_id(), std::move(active_handle), active_handle_size,
+ std::move(idle_handle), idle_handle_size);
+}
+
+void RootCompositorFrameSinkImpl::SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) {
+ support_->frame_sink_manager()->SwitchActiveAggregatedHitTestRegionList(
+ support_->frame_sink_id(), active_handle_index);
+}
+
+void RootCompositorFrameSinkImpl::DisplayOutputSurfaceLost() {
+ // TODO(staraz): Implement this. Client should hear about context/output
+ // surface lost.
+}
+
+void RootCompositorFrameSinkImpl::DisplayWillDrawAndSwap(
+ bool will_draw_and_swap,
+ const cc::RenderPassList& render_pass) {
+ hit_test_aggregator_.PostTaskAggregate(display_->CurrentSurfaceId());
+}
+
+void RootCompositorFrameSinkImpl::DisplayDidDrawAndSwap() {}
+
+void RootCompositorFrameSinkImpl::DidReceiveCompositorFrameAck(
+ const std::vector<ReturnedResource>& resources) {
+ if (client_)
+ client_->DidReceiveCompositorFrameAck(resources);
+}
+
+void RootCompositorFrameSinkImpl::OnBeginFrame(const BeginFrameArgs& args) {
+ hit_test_aggregator_.Swap();
+ if (client_)
+ client_->OnBeginFrame(args);
+}
+
+void RootCompositorFrameSinkImpl::OnBeginFramePausedChanged(bool paused) {
+ if (client_)
+ client_->OnBeginFramePausedChanged(paused);
+}
+
+void RootCompositorFrameSinkImpl::ReclaimResources(
+ const std::vector<ReturnedResource>& resources) {
+ if (client_)
+ client_->ReclaimResources(resources);
+}
+
+void RootCompositorFrameSinkImpl::WillDrawSurface(
+ const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) {}
+
+void RootCompositorFrameSinkImpl::OnClientConnectionLost() {
+ support_->frame_sink_manager()->OnClientConnectionLost(
+ support_->frame_sink_id());
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
new file mode 100644
index 00000000000..14c8ebb4eb4
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -0,0 +1,108 @@
+// 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_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_
+
+#include <memory>
+
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/display/display_client.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
+#include "components/viz/service/hit_test/hit_test_aggregator.h"
+#include "components/viz/service/hit_test/hit_test_aggregator_delegate.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+
+namespace viz {
+
+class BeginFrameSource;
+class CompositorFrameSinkSupport;
+class Display;
+class FrameSinkManagerImpl;
+
+class RootCompositorFrameSinkImpl : public CompositorFrameSinkSupportClient,
+ public mojom::CompositorFrameSink,
+ public mojom::DisplayPrivate,
+ public DisplayClient,
+ public HitTestAggregatorDelegate {
+ public:
+ RootCompositorFrameSinkImpl(
+ FrameSinkManagerImpl* frame_sink_manager,
+ const FrameSinkId& frame_sink_id,
+ std::unique_ptr<Display> display,
+ std::unique_ptr<BeginFrameSource> begin_frame_source,
+ mojom::CompositorFrameSinkAssociatedRequest request,
+ mojom::CompositorFrameSinkClientPtr client,
+ mojom::DisplayPrivateAssociatedRequest display_private_request);
+
+ ~RootCompositorFrameSinkImpl() override;
+
+ // mojom::DisplayPrivate:
+ void SetDisplayVisible(bool visible) override;
+ void ResizeDisplay(const gfx::Size& size) override;
+ void SetDisplayColorSpace(const gfx::ColorSpace& color_space) override;
+ void SetOutputIsSecure(bool secure) override;
+ void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id,
+ float scale_factor) override;
+
+ // mojom::CompositorFrameSink:
+ void SetNeedsBeginFrame(bool needs_begin_frame) override;
+ void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
+ cc::CompositorFrame frame,
+ mojom::HitTestRegionListPtr hit_test_region_list,
+ uint64_t submit_time) override;
+ void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override;
+
+ // HitTestAggregatorDelegate:
+ void OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) override;
+ void SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) override;
+
+ private:
+ // DisplayClient:
+ void DisplayOutputSurfaceLost() override;
+ void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+ const cc::RenderPassList& render_passes) override;
+ void DisplayDidDrawAndSwap() override;
+
+ // CompositorFrameSinkSupportClient:
+ void DidReceiveCompositorFrameAck(
+ const std::vector<ReturnedResource>& resources) override;
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ void OnBeginFramePausedChanged(bool paused) override;
+ void ReclaimResources(
+ const std::vector<ReturnedResource>& resources) override;
+ void WillDrawSurface(const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) override;
+
+ void OnClientConnectionLost();
+
+ std::unique_ptr<CompositorFrameSinkSupport> support_;
+
+ // RootCompositorFrameSinkImpl holds a Display and its BeginFrameSource if
+ // it was created with a non-null gpu::SurfaceHandle.
+ std::unique_ptr<BeginFrameSource> display_begin_frame_source_;
+ std::unique_ptr<Display> display_;
+
+ mojom::CompositorFrameSinkClientPtr client_;
+ mojo::AssociatedBinding<mojom::CompositorFrameSink>
+ compositor_frame_sink_binding_;
+ mojo::AssociatedBinding<mojom::DisplayPrivate> display_private_binding_;
+
+ HitTestAggregator hit_test_aggregator_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootCompositorFrameSinkImpl);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_
diff --git a/chromium/components/viz/service/frame_sinks/surface_references_unittest.cc b/chromium/components/viz/service/frame_sinks/surface_references_unittest.cc
index d0269dcc90d..d685482e81d 100644
--- a/chromium/components/viz/service/frame_sinks/surface_references_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/surface_references_unittest.cc
@@ -9,12 +9,12 @@
#include "base/containers/flat_set.h"
#include "base/memory/ptr_util.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/compositor_frame_helpers.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -34,12 +34,10 @@ constexpr FrameSinkId kFrameSink3(3, 0);
} // namespace
// Tests for reference tracking in CompositorFrameSinkSupport and
-// cc::SurfaceManager.
+// SurfaceManager.
class SurfaceReferencesTest : public testing::Test {
public:
- cc::SurfaceManager& GetSurfaceManager() {
- return *manager_->surface_manager();
- }
+ SurfaceManager& GetSurfaceManager() { return *manager_->surface_manager(); }
// Creates a new Surface with the provided |frame_sink_id| and |local_id|.
// Will first create a Surfacesupport for |frame_sink_id| if necessary.
@@ -47,8 +45,7 @@ class SurfaceReferencesTest : public testing::Test {
LocalSurfaceId local_surface_id(local_id,
base::UnguessableToken::Deserialize(0, 1u));
GetCompositorFrameSinkSupport(frame_sink_id)
- .SubmitCompositorFrame(local_surface_id,
- cc::test::MakeCompositorFrame());
+ .SubmitCompositorFrame(local_surface_id, MakeCompositorFrame());
return SurfaceId(frame_sink_id, local_surface_id);
}
@@ -62,12 +59,11 @@ class SurfaceReferencesTest : public testing::Test {
const FrameSinkId& frame_sink_id) {
auto& support_ptr = supports_[frame_sink_id];
if (!support_ptr) {
+ manager_->RegisterFrameSinkId(frame_sink_id);
constexpr bool is_root = false;
- constexpr bool handles_frame_sink_id_invalidation = true;
constexpr bool needs_sync_points = true;
support_ptr = CompositorFrameSinkSupport::Create(
- nullptr, manager_.get(), frame_sink_id, is_root,
- handles_frame_sink_id_invalidation, needs_sync_points);
+ nullptr, manager_.get(), frame_sink_id, is_root, needs_sync_points);
}
return *support_ptr;
}
@@ -76,18 +72,19 @@ class SurfaceReferencesTest : public testing::Test {
auto support_ptr = supports_.find(frame_sink_id);
ASSERT_NE(support_ptr, supports_.end());
supports_.erase(support_ptr);
+ manager_->InvalidateFrameSinkId(frame_sink_id);
}
void RemoveSurfaceReference(const SurfaceId& parent_id,
const SurfaceId& child_id) {
manager_->surface_manager()->RemoveSurfaceReferences(
- {cc::SurfaceReference(parent_id, child_id)});
+ {SurfaceReference(parent_id, child_id)});
}
void AddSurfaceReference(const SurfaceId& parent_id,
const SurfaceId& child_id) {
manager_->surface_manager()->AddSurfaceReferences(
- {cc::SurfaceReference(parent_id, child_id)});
+ {SurfaceReference(parent_id, child_id)});
}
// Returns all the references where |surface_id| is the parent.
@@ -102,7 +99,7 @@ class SurfaceReferencesTest : public testing::Test {
return GetSurfaceManager().GetSurfacesThatReferenceChild(surface_id);
}
- // Temporary references are stored as a map in cc::SurfaceManager. This method
+ // Temporary references are stored as a map in SurfaceManager. This method
// converts the map to a vector.
std::vector<SurfaceId> GetAllTempReferences() {
std::vector<SurfaceId> temp_references;
@@ -114,10 +111,8 @@ class SurfaceReferencesTest : public testing::Test {
protected:
// testing::Test:
void SetUp() override {
- // Start each test with a fresh cc::SurfaceManager instance.
- manager_ = base::MakeUnique<FrameSinkManagerImpl>(
- nullptr /* display_provider */,
- cc::SurfaceManager::LifetimeType::REFERENCES);
+ // Start each test with a fresh SurfaceManager instance.
+ manager_ = std::make_unique<FrameSinkManagerImpl>();
}
void TearDown() override {
for (auto& support : supports_)
@@ -273,6 +268,37 @@ TEST_F(SurfaceReferencesTest, GarbageCollectionWorksRecusively) {
EXPECT_EQ(nullptr, GetSurfaceManager().GetSurfaceForId(id3));
}
+// Verify that surfaces marked as live are not garbage collected and amy
+// dependencies are also not garbage collected.
+TEST_F(SurfaceReferencesTest, LiveSurfaceStillReachable) {
+ SurfaceId id1 = CreateSurface(kFrameSink1, 1);
+ SurfaceId id2 = CreateSurface(kFrameSink2, 1);
+ SurfaceId id3 = CreateSurface(kFrameSink3, 1);
+
+ AddSurfaceReference(GetSurfaceManager().GetRootSurfaceId(), id1);
+ AddSurfaceReference(id1, id2);
+ AddSurfaceReference(id2, id3);
+ ASSERT_THAT(GetAllTempReferences(), IsEmpty());
+
+ // Marking |id3| for destruction shouldn't cause it be garbage collected
+ // because |id2| is still reachable from the root.
+ DestroySurface(id3);
+ EXPECT_NE(nullptr, GetSurfaceManager().GetSurfaceForId(id3));
+
+ // Removing the surface reference to |id2| makes it not reachable from the
+ // root, however it's not marked as destroyed and is still live. Make sure we
+ // also don't delete any dependencies, such as |id3|, as well.
+ RemoveSurfaceReference(id1, id2);
+ EXPECT_NE(nullptr, GetSurfaceManager().GetSurfaceForId(id3));
+ EXPECT_NE(nullptr, GetSurfaceManager().GetSurfaceForId(id2));
+
+ // |id2| is unreachable and destroyed. Garbage collection should delete both
+ // |id2| and |id3| now.
+ DestroySurface(id2);
+ EXPECT_EQ(nullptr, GetSurfaceManager().GetSurfaceForId(id3));
+ EXPECT_EQ(nullptr, GetSurfaceManager().GetSurfaceForId(id2));
+}
+
TEST_F(SurfaceReferencesTest, TryAddReferenceSameReferenceTwice) {
SurfaceId id1 = CreateSurface(kFrameSink1, 1);
SurfaceId id2 = CreateSurface(kFrameSink2, 1);
diff --git a/chromium/components/viz/service/frame_sinks/surface_resource_holder.cc b/chromium/components/viz/service/frame_sinks/surface_resource_holder.cc
index 63d5d4e0e8a..6a742f4cadf 100644
--- a/chromium/components/viz/service/frame_sinks/surface_resource_holder.cc
+++ b/chromium/components/viz/service/frame_sinks/surface_resource_holder.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/frame_sinks/surface_resource_holder.h"
+#include "base/logging.h"
#include "components/viz/service/frame_sinks/surface_resource_holder_client.h"
namespace viz {
@@ -22,7 +23,7 @@ void SurfaceResourceHolder::Reset() {
}
void SurfaceResourceHolder::ReceiveFromChild(
- const std::vector<cc::TransferableResource>& resources) {
+ const std::vector<TransferableResource>& resources) {
for (const auto& resource : resources) {
ResourceRefs& ref = resource_id_info_map_[resource.id];
ref.refs_holding_resource_alive++;
@@ -31,7 +32,7 @@ void SurfaceResourceHolder::ReceiveFromChild(
}
void SurfaceResourceHolder::RefResources(
- const std::vector<cc::TransferableResource>& resources) {
+ const std::vector<TransferableResource>& resources) {
for (const auto& resource : resources) {
ResourceIdInfoMap::iterator count_it =
resource_id_info_map_.find(resource.id);
@@ -41,8 +42,8 @@ void SurfaceResourceHolder::RefResources(
}
void SurfaceResourceHolder::UnrefResources(
- const std::vector<cc::ReturnedResource>& resources) {
- std::vector<cc::ReturnedResource> resources_available_to_return;
+ const std::vector<ReturnedResource>& resources) {
+ std::vector<ReturnedResource> resources_available_to_return;
for (const auto& resource : resources) {
ResourceIdInfoMap::iterator count_it =
@@ -56,7 +57,7 @@ void SurfaceResourceHolder::UnrefResources(
if (resource.sync_token.HasData())
ref.sync_token = resource.sync_token;
if (ref.refs_holding_resource_alive == 0) {
- cc::ReturnedResource returned = resource;
+ ReturnedResource returned = resource;
returned.sync_token = ref.sync_token;
returned.count = ref.refs_received_from_child;
resources_available_to_return.push_back(returned);
diff --git a/chromium/components/viz/service/frame_sinks/surface_resource_holder.h b/chromium/components/viz/service/frame_sinks/surface_resource_holder.h
index 33aed9a322e..b5b56c4a5a8 100644
--- a/chromium/components/viz/service/frame_sinks/surface_resource_holder.h
+++ b/chromium/components/viz/service/frame_sinks/surface_resource_holder.h
@@ -8,9 +8,9 @@
#include <unordered_map>
#include "base/macros.h"
-#include "cc/base/resource_id.h"
-#include "cc/resources/returned_resource.h"
-#include "cc/resources/transferable_resource.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
@@ -26,9 +26,9 @@ class VIZ_SERVICE_EXPORT SurfaceResourceHolder {
~SurfaceResourceHolder();
void Reset();
- void ReceiveFromChild(const std::vector<cc::TransferableResource>& resources);
- void RefResources(const std::vector<cc::TransferableResource>& resources);
- void UnrefResources(const std::vector<cc::ReturnedResource>& resources);
+ void ReceiveFromChild(const std::vector<TransferableResource>& resources);
+ void RefResources(const std::vector<TransferableResource>& resources);
+ void UnrefResources(const std::vector<ReturnedResource>& resources);
private:
SurfaceResourceHolderClient* client_;
@@ -44,7 +44,7 @@ class VIZ_SERVICE_EXPORT SurfaceResourceHolder {
// ID we've received from the client. When this counter hits zero for a
// particular resource, that ID is available to return to the client with
// the most recently given non-empty sync token.
- using ResourceIdInfoMap = std::unordered_map<cc::ResourceId, ResourceRefs>;
+ using ResourceIdInfoMap = std::unordered_map<ResourceId, ResourceRefs>;
ResourceIdInfoMap resource_id_info_map_;
DISALLOW_COPY_AND_ASSIGN(SurfaceResourceHolder);
diff --git a/chromium/components/viz/service/frame_sinks/surface_resource_holder_client.h b/chromium/components/viz/service/frame_sinks/surface_resource_holder_client.h
index 31b56e17d93..9f97baedaba 100644
--- a/chromium/components/viz/service/frame_sinks/surface_resource_holder_client.h
+++ b/chromium/components/viz/service/frame_sinks/surface_resource_holder_client.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_SURFACE_RESOURCE_HOLDER_CLIENT_H_
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_SURFACE_RESOURCE_HOLDER_CLIENT_H_
-#include "cc/resources/returned_resource.h"
+#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
@@ -17,7 +17,7 @@ class VIZ_SERVICE_EXPORT SurfaceResourceHolderClient {
// ReturnResources gets called when the display compositor is done using the
// resources so that the client can use them.
virtual void ReturnResources(
- const std::vector<cc::ReturnedResource>& resources) = 0;
+ const std::vector<ReturnedResource>& resources) = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
index 245b52fcbbb..7e6b2bf952d 100644
--- a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
@@ -3,19 +3,19 @@
// found in the LICENSE file.
#include "base/containers/flat_set.h"
-#include "cc/test/begin_frame_args_test.h"
-#include "cc/test/compositor_frame_helpers.h"
-#include "cc/test/fake_external_begin_frame_source.h"
-#include "cc/test/fake_surface_observer.h"
-#include "cc/test/mock_compositor_frame_sink_support_client.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
+#include "components/viz/test/fake_surface_observer.h"
+#include "components/viz/test/mock_compositor_frame_sink_support_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using cc::test::MockCompositorFrameSinkSupportClient;
-using cc::test::MakeCompositorFrame;
+using viz::test::MockCompositorFrameSinkSupportClient;
+using viz::test::MakeCompositorFrame;
using testing::_;
using testing::Eq;
using testing::IsEmpty;
@@ -27,7 +27,6 @@ namespace {
constexpr bool kIsRoot = true;
constexpr bool kIsChildRoot = false;
-constexpr bool kHandlesFrameSinkIdInvalidation = true;
constexpr bool kNeedsSyncPoints = true;
constexpr FrameSinkId kDisplayFrameSink(2, 0);
constexpr FrameSinkId kParentFrameSink(3, 0);
@@ -48,19 +47,17 @@ SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
} // namespace
class FakeExternalBeginFrameSourceClient
- : public cc::FakeExternalBeginFrameSource::Client {
+ : public FakeExternalBeginFrameSource::Client {
public:
FakeExternalBeginFrameSourceClient() = default;
~FakeExternalBeginFrameSourceClient() = default;
bool has_observers() const { return observer_count_ > 0; }
- // cc::FakeExternalBeginFrameSource::Client implementation:
- void OnAddObserver(cc::BeginFrameObserver* obs) override {
- ++observer_count_;
- }
+ // FakeExternalBeginFrameSource::Client implementation:
+ void OnAddObserver(BeginFrameObserver* obs) override { ++observer_count_; }
- void OnRemoveObserver(cc::BeginFrameObserver* obs) override {
+ void OnRemoveObserver(BeginFrameObserver* obs) override {
DCHECK_GT(observer_count_, 0);
--observer_count_;
}
@@ -73,35 +70,42 @@ class FakeExternalBeginFrameSourceClient
class SurfaceSynchronizationTest : public testing::Test {
public:
- SurfaceSynchronizationTest()
- : frame_sink_manager_(nullptr /* display_provider */,
- cc::SurfaceManager::LifetimeType::REFERENCES),
- surface_observer_(false) {}
+ SurfaceSynchronizationTest() : surface_observer_(false) {}
~SurfaceSynchronizationTest() override {}
- CompositorFrameSinkSupport& display_support() { return *supports_[0]; }
- cc::Surface* display_surface() {
+ CompositorFrameSinkSupport& display_support() {
+ return *supports_[kDisplayFrameSink];
+ }
+ Surface* display_surface() {
return display_support().GetCurrentSurfaceForTesting();
}
- CompositorFrameSinkSupport& parent_support() { return *supports_[1]; }
- cc::Surface* parent_surface() {
+ CompositorFrameSinkSupport& parent_support() {
+ return *supports_[kParentFrameSink];
+ }
+ Surface* parent_surface() {
return parent_support().GetCurrentSurfaceForTesting();
}
- CompositorFrameSinkSupport& child_support1() { return *supports_[2]; }
- cc::Surface* child_surface1() {
+ CompositorFrameSinkSupport& child_support1() {
+ return *supports_[kChildFrameSink1];
+ }
+ Surface* child_surface1() {
return child_support1().GetCurrentSurfaceForTesting();
}
- CompositorFrameSinkSupport& child_support2() { return *supports_[3]; }
- cc::Surface* child_surface2() {
+ CompositorFrameSinkSupport& child_support2() {
+ return *supports_[kChildFrameSink2];
+ }
+ Surface* child_surface2() {
return child_support2().GetCurrentSurfaceForTesting();
}
- CompositorFrameSinkSupport& support(int index) { return *supports_[index]; }
- cc::Surface* surface(int index) {
- return support(index).GetCurrentSurfaceForTesting();
+ void DestroyFrameSink(const FrameSinkId& frame_sink_id) {
+ auto it = supports_.find(frame_sink_id);
+ if (it == supports_.end())
+ return;
+ supports_.erase(it);
}
FrameSinkManagerImpl& frame_sink_manager() { return frame_sink_manager_; }
@@ -120,42 +124,45 @@ class SurfaceSynchronizationTest : public testing::Test {
surface_id);
}
- cc::FakeExternalBeginFrameSource* begin_frame_source() {
+ FakeExternalBeginFrameSource* begin_frame_source() {
return begin_frame_source_.get();
}
void SendNextBeginFrame() {
- // Creep the time forward so that any cc::BeginFrameArgs is not equal to the
+ // Creep the time forward so that any BeginFrameArgs is not equal to the
// last one otherwise we violate the BeginFrameSource contract.
- now_src_->Advance(cc::BeginFrameArgs::DefaultInterval());
- cc::BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
+ now_src_->Advance(BeginFrameArgs::DefaultInterval());
+ BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
BEGINFRAME_FROM_HERE, now_src_.get());
begin_frame_source_->TestOnBeginFrame(args);
}
- cc::FakeSurfaceObserver& surface_observer() { return surface_observer_; }
+ FakeSurfaceObserver& surface_observer() { return surface_observer_; }
// testing::Test:
void SetUp() override {
testing::Test::SetUp();
begin_frame_source_ =
- base::MakeUnique<cc::FakeExternalBeginFrameSource>(0.f, false);
+ base::MakeUnique<FakeExternalBeginFrameSource>(0.f, false);
begin_frame_source_->SetClient(&begin_frame_source_client_);
now_src_ = base::MakeUnique<base::SimpleTestTickClock>();
frame_sink_manager_.surface_manager()->AddObserver(&surface_observer_);
- supports_.push_back(CompositorFrameSinkSupport::Create(
+ supports_[kDisplayFrameSink] = CompositorFrameSinkSupport::Create(
&support_client_, &frame_sink_manager_, kDisplayFrameSink, kIsRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
- supports_.push_back(CompositorFrameSinkSupport::Create(
+ kNeedsSyncPoints);
+
+ supports_[kParentFrameSink] = CompositorFrameSinkSupport::Create(
&support_client_, &frame_sink_manager_, kParentFrameSink, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
- supports_.push_back(CompositorFrameSinkSupport::Create(
+ kNeedsSyncPoints);
+
+ supports_[kChildFrameSink1] = CompositorFrameSinkSupport::Create(
&support_client_, &frame_sink_manager_, kChildFrameSink1, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
- supports_.push_back(CompositorFrameSinkSupport::Create(
+ kNeedsSyncPoints);
+
+ supports_[kChildFrameSink2] = CompositorFrameSinkSupport::Create(
&support_client_, &frame_sink_manager_, kChildFrameSink2, kIsChildRoot,
- kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
+ kNeedsSyncPoints);
// Normally, the BeginFrameSource would be registered by the Display. We
// register it here so that BeginFrames are received by the display support,
@@ -182,7 +189,7 @@ class SurfaceSynchronizationTest : public testing::Test {
surface_id);
}
- cc::Surface* GetSurfaceForId(const SurfaceId& surface_id) {
+ Surface* GetSurfaceForId(const SurfaceId& surface_id) {
return frame_sink_manager_.surface_manager()->GetSurfaceForId(surface_id);
}
@@ -191,11 +198,14 @@ class SurfaceSynchronizationTest : public testing::Test {
private:
FrameSinkManagerImpl frame_sink_manager_;
- cc::FakeSurfaceObserver surface_observer_;
+ FakeSurfaceObserver surface_observer_;
FakeExternalBeginFrameSourceClient begin_frame_source_client_;
- std::unique_ptr<cc::FakeExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_;
std::unique_ptr<base::SimpleTestTickClock> now_src_;
- std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_;
+ std::unordered_map<FrameSinkId,
+ std::unique_ptr<CompositorFrameSinkSupport>,
+ FrameSinkIdHash>
+ supports_;
DISALLOW_COPY_AND_ASSIGN(SurfaceSynchronizationTest);
};
@@ -229,11 +239,11 @@ TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) {
frame_sink_manager().surface_manager()->GetRootSurfaceId()),
UnorderedElementsAre(display_id_second));
- // cc::Surface |display_id_first| is unreachable and should get deleted.
+ // Surface |display_id_first| is unreachable and should get deleted.
EXPECT_EQ(nullptr, GetSurfaceForId(display_id_first));
}
-// The parent cc::Surface is blocked on |child_id1| and |child_id2|.
+// The parent Surface is blocked on |child_id1| and |child_id2|.
TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
@@ -242,7 +252,7 @@ TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// parent_support is blocked on |child_id1| and |child_id2|.
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -273,7 +283,7 @@ TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {
EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
}
-// The parent cc::Surface is blocked on |child_id2| which is blocked on
+// The parent Surface is blocked on |child_id2| which is blocked on
// |child_id3|.
TEST_F(SurfaceSynchronizationTest, BlockedChain) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
@@ -283,7 +293,7 @@ TEST_F(SurfaceSynchronizationTest, BlockedChain) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// parent_support is blocked on |child_id1|.
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -297,7 +307,7 @@ TEST_F(SurfaceSynchronizationTest, BlockedChain) {
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// child_support1 should now be blocked on |child_id2|.
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -318,7 +328,7 @@ TEST_F(SurfaceSynchronizationTest, BlockedChain) {
child_support2().SubmitCompositorFrame(
child_id2.local_surface_id(),
MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_FALSE(child_surface2()->has_deadline());
@@ -348,7 +358,7 @@ TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// parent_support is blocked on |child_id2|.
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -361,7 +371,7 @@ TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) {
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface1()->has_deadline());
EXPECT_FALSE(child_surface1()->HasActiveFrame());
@@ -401,7 +411,7 @@ TEST_F(SurfaceSynchronizationTest, DeadlineHits) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// parent_support is blocked on |child_id1|.
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -413,7 +423,7 @@ TEST_F(SurfaceSynchronizationTest, DeadlineHits) {
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// child_support1 should now be blocked on |child_id2|.
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -460,7 +470,7 @@ TEST_F(SurfaceSynchronizationTest, DeadlineHits) {
EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
}
-// This test verifies at the cc::Surface activates once a cc::CompositorFrame is
+// This test verifies at the Surface activates once a cc::CompositorFrame is
// submitted that has no unresolved dependencies.
TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
@@ -470,7 +480,7 @@ TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// Verify that the cc::CompositorFrame is blocked on |arbitrary_id|.
EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -520,7 +530,7 @@ TEST_F(SurfaceSynchronizationTest, OnlyActiveFramesAffectSurfaceReferences) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id2}, {child_id1},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_FALSE(parent_surface()->HasActiveFrame());
EXPECT_TRUE(parent_surface()->HasPendingFrame());
EXPECT_THAT(parent_surface()->activation_dependencies(),
@@ -564,12 +574,12 @@ TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
// The parent submits a cc::CompositorFrame that depends on |child_id| before
// the child submits a cc::CompositorFrame. The cc::CompositorFrame also has
// resources in its resource list.
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = 1337;
resource.format = ALPHA_8;
resource.filter = 1234;
resource.size = gfx::Size(1234, 5678);
- std::vector<cc::TransferableResource> resource_list = {resource};
+ std::vector<TransferableResource> resource_list = {resource};
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(), resource_list));
@@ -583,7 +593,7 @@ TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
child_support1().SubmitCompositorFrame(
child_id.local_surface_id(),
MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// Verify that the child cc::CompositorFrame activates immediately.
EXPECT_TRUE(child_surface1()->HasActiveFrame());
@@ -595,7 +605,7 @@ TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
- std::vector<cc::ReturnedResource> returned_resources = {
+ std::vector<ReturnedResource> returned_resources = {
resource.ToReturnedResource()};
EXPECT_CALL(support_client_,
DidReceiveCompositorFrameAck(returned_resources));
@@ -606,53 +616,10 @@ TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({empty_surface_ids()}, {empty_surface_ids()},
- std::vector<cc::TransferableResource>()));
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
-}
-
-// The parent cc::Surface is blocked on |child_id2| which is blocked on
-// |child_id3|. child_support1 evicts its blocked cc::Surface. The parent
-// surface should activate.
-TEST_F(SurfaceSynchronizationTest, EvictSurfaceWithPendingFrame) {
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- // Submit a cc::CompositorFrame that depends on |child_id1|.
- parent_support().SubmitCompositorFrame(
- parent_id1.local_surface_id(),
- MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
-
- // Verify that the cc::CompositorFrame is blocked on |child_id1|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->activation_dependencies(),
- UnorderedElementsAre(child_id1));
-
- // Submit a cc::CompositorFrame that depends on |child_id2|.
- child_support1().SubmitCompositorFrame(
- child_id1.local_surface_id(),
- MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
-
- // Verify that the cc::CompositorFrame is blocked on |child_id2|.
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->activation_dependencies(),
- UnorderedElementsAre(child_id2));
-
- // Evict child_support1's current cc::Surface.
- // TODO(fsamuel): EvictCurrentSurface => EvictCurrentSurface.
- child_support1().EvictCurrentSurface();
-
- // The parent cc::Surface should immediately activate.
+ std::vector<TransferableResource>()));
EXPECT_TRUE(parent_surface()->HasActiveFrame());
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
- EXPECT_FALSE(parent_surface()->has_deadline());
}
// This test verifies that if a surface has both a pending and active
@@ -671,7 +638,7 @@ TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// Verify that the cc::CompositorFrame is blocked on |child_id|.
EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -696,7 +663,7 @@ TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
EXPECT_FALSE(child_surface1()->HasPendingFrame());
EXPECT_THAT(child_surface1()->activation_dependencies(), IsEmpty());
- // Verify that the parent cc::Surface has activated.
+ // Verify that the parent Surface has activated.
EXPECT_TRUE(parent_surface()->HasActiveFrame());
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
@@ -705,9 +672,9 @@ TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame(empty_surface_ids(), {child_id1},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
- // Verify that the parent cc::Surface has activated.
+ // Verify that the parent Surface has activated.
EXPECT_TRUE(parent_surface()->HasActiveFrame());
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_THAT(parent_surface()->activation_dependencies(), IsEmpty());
@@ -724,7 +691,7 @@ TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
testing::Mock::VerifyAndClearExpectations(&support_client_);
// The parent surface should now have both a pending and activate
@@ -739,7 +706,7 @@ TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
MakeCompositorFrame());
- // Verify that the parent cc::Surface has activated and no longer has a
+ // Verify that the parent Surface has activated and no longer has a
// pending cc::CompositorFrame. Also verify that |child_id1| is no longer a
// child reference of |parent_id|.
EXPECT_TRUE(parent_surface()->HasActiveFrame());
@@ -775,7 +742,7 @@ TEST_F(SurfaceSynchronizationTest,
std::move(frame));
// Verify that the old surface has an active frame and no pending frame.
- cc::Surface* old_surface = GetSurfaceForId(parent_id1);
+ Surface* old_surface = GetSurfaceForId(parent_id1);
ASSERT_NE(nullptr, old_surface);
EXPECT_TRUE(old_surface->HasActiveFrame());
EXPECT_FALSE(old_surface->HasPendingFrame());
@@ -792,7 +759,7 @@ TEST_F(SurfaceSynchronizationTest,
std::move(frame2));
// Verify that the new surface has an active frame and no pending frames.
- cc::Surface* surface = GetSurfaceForId(parent_id2);
+ Surface* surface = GetSurfaceForId(parent_id2);
ASSERT_NE(nullptr, surface);
EXPECT_TRUE(surface->HasActiveFrame());
EXPECT_FALSE(surface->HasPendingFrame());
@@ -852,14 +819,14 @@ TEST_F(SurfaceSynchronizationTest,
info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
cc::CompositorFrame frame2 = MakeCompositorFrame(
- {child_id}, empty_surface_ids(), std::vector<cc::TransferableResource>());
+ {child_id}, empty_surface_ids(), std::vector<TransferableResource>());
frame2.metadata.latency_info.push_back(info2);
parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
std::move(frame2));
// Verify that the old surface has both an active and a pending frame.
- cc::Surface* old_surface = GetSurfaceForId(parent_id1);
+ Surface* old_surface = GetSurfaceForId(parent_id1);
ASSERT_NE(nullptr, old_surface);
EXPECT_TRUE(old_surface->HasActiveFrame());
EXPECT_TRUE(old_surface->HasPendingFrame());
@@ -869,7 +836,7 @@ TEST_F(SurfaceSynchronizationTest,
MakeCompositorFrame());
// Verify that the new surface has an active frame only.
- cc::Surface* surface = GetSurfaceForId(parent_id2);
+ Surface* surface = GetSurfaceForId(parent_id2);
ASSERT_NE(nullptr, surface);
EXPECT_TRUE(surface->HasActiveFrame());
EXPECT_FALSE(surface->HasPendingFrame());
@@ -926,7 +893,7 @@ TEST_F(SurfaceSynchronizationTest,
std::move(frame));
// Verify that the old surface has an active frame only.
- cc::Surface* old_surface = GetSurfaceForId(parent_id1);
+ Surface* old_surface = GetSurfaceForId(parent_id1);
ASSERT_NE(nullptr, old_surface);
EXPECT_TRUE(old_surface->HasActiveFrame());
EXPECT_FALSE(old_surface->HasPendingFrame());
@@ -937,14 +904,14 @@ TEST_F(SurfaceSynchronizationTest,
info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
cc::CompositorFrame frame2 = MakeCompositorFrame(
- {child_id}, empty_surface_ids(), std::vector<cc::TransferableResource>());
+ {child_id}, empty_surface_ids(), std::vector<TransferableResource>());
frame2.metadata.latency_info.push_back(info2);
parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
std::move(frame2));
// Verify that the new surface has a pending frame and no active frame.
- cc::Surface* surface = GetSurfaceForId(parent_id2);
+ Surface* surface = GetSurfaceForId(parent_id2);
ASSERT_NE(nullptr, surface);
EXPECT_TRUE(surface->HasPendingFrame());
EXPECT_FALSE(surface->HasActiveFrame());
@@ -982,14 +949,14 @@ TEST_F(SurfaceSynchronizationTest,
// Checks that resources and ack are sent together if possible.
TEST_F(SurfaceSynchronizationTest, ReturnResourcesWithAck) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = 1234;
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
{resource}));
- std::vector<cc::ReturnedResource> returned_resources =
- cc::TransferableResource::ReturnResources({resource});
+ std::vector<ReturnedResource> returned_resources =
+ TransferableResource::ReturnResources({resource});
EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
EXPECT_CALL(support_client_,
DidReceiveCompositorFrameAck(Eq(returned_resources)));
@@ -1009,14 +976,14 @@ TEST_F(SurfaceSynchronizationTest, SurfaceResurrection) {
MakeCompositorFrame());
// Verify that the child surface is created.
- cc::Surface* surface = GetSurfaceForId(child_id);
+ Surface* surface = GetSurfaceForId(child_id);
EXPECT_NE(nullptr, surface);
// Add a reference from the parent to the child.
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id}, {child_id},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// Attempt to destroy the child surface. The surface must still exist since
// the parent needs it but it will be marked as destroyed.
@@ -1032,7 +999,7 @@ TEST_F(SurfaceSynchronizationTest, SurfaceResurrection) {
// Verify that the surface that was marked destroyed is recovered and is being
// used again.
- cc::Surface* surface2 = GetSurfaceForId(child_id);
+ Surface* surface2 = GetSurfaceForId(child_id);
EXPECT_EQ(surface, surface2);
EXPECT_FALSE(IsMarkedForDestruction(child_id));
}
@@ -1052,7 +1019,7 @@ TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsReusable) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id}, {child_id},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// Remove the reference from parant. This allows us to destroy the surface.
parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
@@ -1085,11 +1052,11 @@ TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -1109,11 +1076,11 @@ TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) {
parent_support().SubmitCompositorFrame(
parent_id2.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
// The display surface now has two CompositorFrames. One that is pending,
// indirectly blocked on child_id and one that is active, also indirectly
@@ -1145,12 +1112,12 @@ TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id1}, {parent_id1},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->has_deadline());
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -1176,14 +1143,14 @@ TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) {
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->has_deadline());
// Now |parent_id1| is only kept alive by the active |display_id| frame.
parent_support().SubmitCompositorFrame(
parent_id2.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->has_deadline());
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -1215,7 +1182,7 @@ TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) {
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id1}, {parent_id2},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->HasPendingFrame());
EXPECT_FALSE(display_surface()->HasActiveFrame());
@@ -1250,7 +1217,7 @@ TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) {
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->HasPendingFrame());
EXPECT_FALSE(display_surface()->HasActiveFrame());
@@ -1272,7 +1239,7 @@ TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_FALSE(parent_surface()->has_deadline());
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_TRUE(parent_surface()->HasActiveFrame());
@@ -1289,7 +1256,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) {
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->HasPendingFrame());
EXPECT_FALSE(display_surface()->HasActiveFrame());
EXPECT_TRUE(display_surface()->has_deadline());
@@ -1310,7 +1277,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) {
child_support1().SubmitCompositorFrame(
child_id.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface1()->HasPendingFrame());
EXPECT_FALSE(child_surface1()->HasActiveFrame());
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -1322,7 +1289,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_TRUE(parent_surface()->HasActiveFrame());
EXPECT_FALSE(parent_surface()->has_deadline());
@@ -1346,16 +1313,16 @@ TEST_F(SurfaceSynchronizationTest, FallbackSurfacesClosed) {
// DidReceiveCompositorFrameAck should call on immediate activation.
// However, resources will not be returned because this frame is a candidate
// for display.
- cc::TransferableResource resource;
+ TransferableResource resource;
resource.id = 1337;
resource.format = ALPHA_8;
resource.filter = 1234;
resource.size = gfx::Size(1234, 5678);
- std::vector<cc::ReturnedResource> returned_resources =
- cc::TransferableResource::ReturnResources({resource});
+ std::vector<ReturnedResource> returned_resources =
+ TransferableResource::ReturnResources({resource});
EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(
- Eq(std::vector<cc::ReturnedResource>())));
+ Eq(std::vector<ReturnedResource>())));
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
@@ -1369,20 +1336,20 @@ TEST_F(SurfaceSynchronizationTest, FallbackSurfacesClosed) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id2}, {child_id1},
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(parent_surface()->has_deadline());
EXPECT_TRUE(parent_surface()->HasPendingFrame());
EXPECT_FALSE(parent_surface()->HasActiveFrame());
// Resources will be returned immediately because |child_id1|'s surface is
// closed.
- cc::TransferableResource resource2;
+ TransferableResource resource2;
resource2.id = 1246;
resource2.format = ALPHA_8;
resource2.filter = 1357;
resource2.size = gfx::Size(8765, 4321);
- std::vector<cc::ReturnedResource> returned_resources2 =
- cc::TransferableResource::ReturnResources({resource2});
+ std::vector<ReturnedResource> returned_resources2 =
+ TransferableResource::ReturnResources({resource2});
EXPECT_CALL(support_client_,
DidReceiveCompositorFrameAck(Eq(returned_resources2)));
child_support1().SubmitCompositorFrame(
@@ -1433,7 +1400,7 @@ TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_FALSE(parent_surface()->HasPendingFrame());
EXPECT_TRUE(parent_surface()->HasActiveFrame());
@@ -1444,7 +1411,7 @@ TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) {
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface1()->HasPendingFrame());
EXPECT_TRUE(child_surface1()->HasActiveFrame());
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -1458,7 +1425,7 @@ TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) {
child_support2().SubmitCompositorFrame(
child_id2.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface2()->HasPendingFrame());
EXPECT_TRUE(child_surface2()->HasActiveFrame());
EXPECT_TRUE(child_surface2()->has_deadline());
@@ -1501,7 +1468,7 @@ TEST_F(SurfaceSynchronizationTest, DeadlineInheritance) {
parent_support().SubmitCompositorFrame(
parent_id1.local_surface_id(),
MakeCompositorFrame({child_id1}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(parent_surface()->HasPendingFrame());
EXPECT_FALSE(parent_surface()->HasActiveFrame());
@@ -1514,7 +1481,7 @@ TEST_F(SurfaceSynchronizationTest, DeadlineInheritance) {
child_support1().SubmitCompositorFrame(
child_id1.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface1()->HasPendingFrame());
EXPECT_FALSE(child_surface1()->HasActiveFrame());
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -1550,7 +1517,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {
display_support().SubmitCompositorFrame(
display_id.local_surface_id(),
MakeCompositorFrame({parent_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(display_surface()->HasPendingFrame());
EXPECT_FALSE(display_surface()->HasActiveFrame());
EXPECT_TRUE(display_surface()->has_deadline());
@@ -1563,7 +1530,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {
child_support1().SubmitCompositorFrame(
child_id.local_surface_id(),
MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(child_surface1()->HasPendingFrame());
EXPECT_FALSE(child_surface1()->HasActiveFrame());
EXPECT_TRUE(child_surface1()->has_deadline());
@@ -1574,7 +1541,7 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {
parent_support().SubmitCompositorFrame(
parent_id.local_surface_id(),
MakeCompositorFrame({child_id}, empty_surface_ids(),
- std::vector<cc::TransferableResource>()));
+ std::vector<TransferableResource>()));
EXPECT_TRUE(parent_surface()->HasPendingFrame());
EXPECT_FALSE(parent_surface()->HasActiveFrame());
EXPECT_TRUE(parent_surface()->has_deadline());
@@ -1601,5 +1568,183 @@ TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {
EXPECT_FALSE(child_surface1()->has_deadline());
}
+// This test verifies that no crash occurs if a CompositorFrame activates AFTER
+// its FrameSink has been destroyed.
+TEST_F(SurfaceSynchronizationTest, FrameActivationAfterFrameSinkDestruction) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ EXPECT_FALSE(parent_surface()->has_deadline());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+
+ // Submit a CompositorFrame that refers to to |parent_id|.
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), {parent_id},
+ std::vector<TransferableResource>()));
+
+ EXPECT_FALSE(display_surface()->has_deadline());
+ EXPECT_FALSE(display_surface()->HasPendingFrame());
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+ EXPECT_THAT(GetChildReferences(display_id), UnorderedElementsAre(parent_id));
+
+ // Submit a new CompositorFrame to the parent CompositorFrameSink. It should
+ // now have a pending and active CompositorFrame.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ std::vector<TransferableResource>()));
+
+ EXPECT_TRUE(parent_surface()->has_deadline());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ surface_observer().Reset();
+
+ // Destroy the parent CompositorFrameSink. The parent_surface will be kept
+ // alive by the display.
+ DestroyFrameSink(kParentFrameSink);
+
+ Surface* parent_surface = GetSurfaceForId(parent_id);
+ ASSERT_NE(nullptr, parent_surface);
+
+ EXPECT_TRUE(parent_surface->has_deadline());
+ EXPECT_TRUE(parent_surface->HasActiveFrame());
+ EXPECT_TRUE(parent_surface->HasPendingFrame());
+
+ // Advance BeginFrames to trigger a deadline. This activates the
+ // cc::CompositorFrame submitted above.
+ for (int i = 0; i < 4; ++i)
+ SendNextBeginFrame();
+
+ // The parent surface stays alive through the display.
+ parent_surface = GetSurfaceForId(parent_id);
+ EXPECT_NE(nullptr, parent_surface);
+ EXPECT_TRUE(surface_observer().IsSurfaceDamaged(parent_id));
+
+ // Submitting a new CompositorFrame to the display should free the parent.
+ display_support().SubmitCompositorFrame(display_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ parent_surface = GetSurfaceForId(parent_id);
+ EXPECT_EQ(nullptr, parent_surface);
+}
+
+TEST_F(SurfaceSynchronizationTest, PreviousFrameSurfaceId) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ // Submit a frame with no dependencies to |parent_id1|.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ std::vector<TransferableResource>()));
+
+ // Submit a frame with unresolved dependencies to |parent_id2|. The frame
+ // should become pending and previous_frame_surface_id() should return
+ // |parent_id1|.
+ parent_support().SubmitCompositorFrame(
+ parent_id2.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ Surface* parent_surface2 =
+ frame_sink_manager().surface_manager()->GetSurfaceForId(parent_id2);
+ EXPECT_FALSE(parent_surface2->HasActiveFrame());
+ EXPECT_TRUE(parent_surface2->HasPendingFrame());
+ EXPECT_EQ(parent_id1, parent_surface2->previous_frame_surface_id());
+
+ // Activate the pending frame in |parent_id2|. previous_frame_surface_id()
+ // should still return |parent_id1|.
+ parent_surface2->ActivatePendingFrameForDeadline();
+ EXPECT_TRUE(parent_surface2->HasActiveFrame());
+ EXPECT_FALSE(parent_surface2->HasPendingFrame());
+ EXPECT_EQ(parent_id1, parent_surface2->previous_frame_surface_id());
+}
+
+TEST_F(SurfaceSynchronizationTest, FrameIndexWithPendingFrames) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ constexpr int n_iterations = 7;
+
+ // Submit a frame with no dependencies that will activate immediately. Record
+ // the initial frame index.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ Surface* parent_surface =
+ frame_sink_manager().surface_manager()->GetSurfaceForId(parent_id);
+ uint64_t initial_frame_index = parent_surface->GetActiveFrameIndex();
+
+ // Submit frames with unresolved dependencies. GetActiveFrameIndex should
+ // return the same value as before.
+ for (int i = 0; i < n_iterations; i++) {
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ EXPECT_EQ(initial_frame_index, parent_surface->GetActiveFrameIndex());
+ }
+
+ // Activate the pending frame. GetActiveFrameIndex should return the frame
+ // index of the newly activated frame.
+ parent_surface->ActivatePendingFrameForDeadline();
+ EXPECT_EQ(initial_frame_index + n_iterations,
+ parent_surface->GetActiveFrameIndex());
+}
+
+TEST_F(SurfaceSynchronizationTest, PendingSurfaceKeptAlive) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ // |display_id| depends on |parent_id1|. It shouldn't activate.
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id1}, empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ EXPECT_FALSE(GetSurfaceForId(display_id)->HasActiveFrame());
+ EXPECT_TRUE(GetSurfaceForId(display_id)->HasPendingFrame());
+
+ // |parent_id1| is created but it depends on |child_id|. |display_id| and
+ // |parent_id1| must remain pending.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ EXPECT_FALSE(GetSurfaceForId(display_id)->HasActiveFrame());
+ EXPECT_TRUE(GetSurfaceForId(display_id)->HasPendingFrame());
+ EXPECT_FALSE(GetSurfaceForId(parent_id1)->HasActiveFrame());
+ EXPECT_TRUE(GetSurfaceForId(parent_id1)->HasPendingFrame());
+
+ // Parent submits a new CompositorFrame to |parent_id2|. |display_id| and
+ // |parent_id1| should remain pending.
+ parent_support().SubmitCompositorFrame(
+ parent_id2.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ EXPECT_FALSE(GetSurfaceForId(display_id)->HasActiveFrame());
+ EXPECT_TRUE(GetSurfaceForId(display_id)->HasPendingFrame());
+ EXPECT_FALSE(GetSurfaceForId(parent_id1)->HasActiveFrame());
+ EXPECT_TRUE(GetSurfaceForId(parent_id1)->HasPendingFrame());
+
+ // |child_id| becomes available. |display_id| and |parent_id1| should
+ // activate.
+ child_support1().SubmitCompositorFrame(
+ child_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ std::vector<TransferableResource>()));
+ EXPECT_TRUE(GetSurfaceForId(display_id)->HasActiveFrame());
+ EXPECT_FALSE(GetSurfaceForId(display_id)->HasPendingFrame());
+ EXPECT_TRUE(GetSurfaceForId(parent_id1)->HasActiveFrame());
+ EXPECT_FALSE(GetSurfaceForId(parent_id1)->HasPendingFrame());
+}
+
} // namespace test
} // namespace viz
diff --git a/chromium/components/viz/service/gl/DEPS b/chromium/components/viz/service/gl/DEPS
new file mode 100644
index 00000000000..22ddce6eb8b
--- /dev/null
+++ b/chromium/components/viz/service/gl/DEPS
@@ -0,0 +1,19 @@
+include_rules = [
+ "+gpu/command_buffer",
+ "+gpu/config",
+ "+gpu/ipc",
+ "+gpu/ipc/common",
+ "+gpu/ipc/service",
+ "+ipc",
+ "+media/gpu",
+ "+media/mojo",
+ "+mojo/public/cpp",
+ "+services/ui/gpu/interfaces",
+ "+ui/gl",
+]
+
+specific_include_rules = {
+ "gpu_service_impl_unittest\.cc": [
+ "+services/ui/public/interfaces",
+ ]
+}
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
new file mode 100644
index 00000000000..e3df58b4e72
--- /dev/null
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -0,0 +1,568 @@
+// 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/viz/service/gl/gpu_service_impl.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/crash_logging.h"
+#include "base/lazy_instance.h"
+#include "base/memory/shared_memory.h"
+#include "base/run_loop.h"
+#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/viz/common/gpu/in_process_context_provider.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/scheduler.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/config/dx_diag_node.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_switches.h"
+#include "gpu/config/gpu_util.h"
+#include "gpu/ipc/common/gpu_memory_buffer_support.h"
+#include "gpu/ipc/common/memory_stats.h"
+#include "gpu/ipc/gpu_in_process_thread_service.h"
+#include "gpu/ipc/service/gpu_channel.h"
+#include "gpu/ipc/service/gpu_channel_manager.h"
+#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
+#include "gpu/ipc/service/gpu_watchdog_thread.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_sync_channel.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "media/gpu/gpu_video_encode_accelerator_factory.h"
+#include "media/gpu/ipc/service/gpu_jpeg_decode_accelerator_factory_provider.h"
+#include "media/gpu/ipc/service/gpu_video_decode_accelerator.h"
+#include "media/gpu/ipc/service/gpu_video_encode_accelerator.h"
+#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
+#include "media/mojo/services/mojo_video_encode_accelerator_provider.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_switches.h"
+#include "ui/gl/gpu_switching_manager.h"
+#include "ui/gl/init/gl_factory.h"
+#include "url/gurl.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/throw_uncaught_exception.h"
+#include "media/gpu/content_video_view_overlay_allocator.h"
+#endif
+
+namespace viz {
+
+namespace {
+
+static base::LazyInstance<base::Callback<
+ void(int severity, size_t message_start, const std::string& message)>>::
+ Leaky g_log_callback = LAZY_INSTANCE_INITIALIZER;
+
+bool GpuLogMessageHandler(int severity,
+ const char* file,
+ int line,
+ size_t message_start,
+ const std::string& message) {
+ g_log_callback.Get().Run(severity, message_start, message);
+ return false;
+}
+
+// Returns a callback which does a PostTask to run |callback| on the |runner|
+// task runner.
+template <typename Param>
+base::OnceCallback<void(const Param&)> WrapCallback(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ base::OnceCallback<void(const Param&)> callback) {
+ return base::BindOnce(
+ [](base::SingleThreadTaskRunner* runner,
+ base::OnceCallback<void(const Param&)> callback, const Param& param) {
+ runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), param));
+ },
+ base::RetainedRef(std::move(runner)), std::move(callback));
+}
+
+void DestroyBinding(mojo::BindingSet<mojom::GpuService>* binding,
+ base::WaitableEvent* wait) {
+ binding->CloseAllBindings();
+ wait->Signal();
+}
+
+} // namespace
+
+GpuServiceImpl::GpuServiceImpl(
+ const gpu::GPUInfo& gpu_info,
+ std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+ const gpu::GpuFeatureInfo& gpu_feature_info)
+ : main_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_runner_(std::move(io_runner)),
+ watchdog_thread_(std::move(watchdog_thread)),
+ gpu_memory_buffer_factory_(
+ gpu::GpuMemoryBufferFactory::CreateNativeType()),
+ gpu_info_(gpu_info),
+ gpu_feature_info_(gpu_feature_info),
+ bindings_(base::MakeUnique<mojo::BindingSet<mojom::GpuService>>()),
+ weak_ptr_factory_(this) {
+ DCHECK(!io_runner_->BelongsToCurrentThread());
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+}
+
+GpuServiceImpl::~GpuServiceImpl() {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ bind_task_tracker_.TryCancelAll();
+ logging::SetLogMessageHandler(nullptr);
+ g_log_callback.Get() =
+ base::Callback<void(int, size_t, const std::string&)>();
+ base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (io_runner_->PostTask(
+ FROM_HERE, base::Bind(&DestroyBinding, bindings_.get(), &wait))) {
+ wait.Wait();
+ }
+ media_gpu_channel_manager_.reset();
+ gpu_channel_manager_.reset();
+ owned_sync_point_manager_.reset();
+
+ // Signal this event before destroying the child process. That way all
+ // background threads can cleanup. For example, in the renderer the
+ // RenderThread instances will be able to notice shutdown before the render
+ // process begins waiting for them to exit.
+ if (owned_shutdown_event_)
+ owned_shutdown_event_->Signal();
+}
+
+void GpuServiceImpl::UpdateGPUInfoFromPreferences(
+ const gpu::GpuPreferences& preferences) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ DCHECK(!gpu_host_);
+ gpu_preferences_ = preferences;
+ gpu::GpuDriverBugWorkarounds gpu_workarounds(
+ gpu_feature_info_.enabled_gpu_driver_bug_workarounds);
+ gpu_info_.video_decode_accelerator_capabilities =
+ media::GpuVideoDecodeAccelerator::GetCapabilities(gpu_preferences_,
+ gpu_workarounds);
+ gpu_info_.video_encode_accelerator_supported_profiles =
+ media::GpuVideoEncodeAccelerator::GetSupportedProfiles(gpu_preferences_);
+ gpu_info_.jpeg_decode_accelerator_supported =
+ media::GpuJpegDecodeAcceleratorFactoryProvider::
+ IsAcceleratedJpegDecodeSupported();
+ // Record initialization only after collecting the GPU info because that can
+ // take a significant amount of time.
+ gpu_info_.initialization_time = base::Time::Now() - start_time_;
+}
+
+void GpuServiceImpl::InitializeWithHost(
+ ui::mojom::GpuHostPtr gpu_host,
+ gpu::GpuProcessActivityFlags activity_flags,
+ gpu::SyncPointManager* sync_point_manager,
+ base::WaitableEvent* shutdown_event) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ gpu_host->DidInitialize(gpu_info_, gpu_feature_info_);
+ gpu_host_ = ui::mojom::ThreadSafeGpuHostPtr::Create(gpu_host.PassInterface(),
+ io_runner_);
+ if (!in_host_process_) {
+ // The global callback is reset from the dtor. So Unretained() here is safe.
+ // Note that the callback can be called from any thread. Consequently, the
+ // callback cannot use a WeakPtr.
+ g_log_callback.Get() =
+ base::Bind(&GpuServiceImpl::RecordLogMessage, base::Unretained(this));
+ logging::SetLogMessageHandler(GpuLogMessageHandler);
+ }
+
+ sync_point_manager_ = sync_point_manager;
+ if (!sync_point_manager_) {
+ owned_sync_point_manager_ = base::MakeUnique<gpu::SyncPointManager>();
+ sync_point_manager_ = owned_sync_point_manager_.get();
+ }
+
+ shutdown_event_ = shutdown_event;
+ if (!shutdown_event_) {
+ owned_shutdown_event_ = base::MakeUnique<base::WaitableEvent>(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ shutdown_event_ = owned_shutdown_event_.get();
+ }
+
+ if (gpu_preferences_.enable_gpu_scheduler) {
+ scheduler_ = base::MakeUnique<gpu::Scheduler>(
+ base::ThreadTaskRunnerHandle::Get(), sync_point_manager_);
+ }
+
+ // Defer creation of the render thread. This is to prevent it from handling
+ // IPC messages before the sandbox has been enabled and all other necessary
+ // initialization has succeeded.
+ gpu_channel_manager_.reset(new gpu::GpuChannelManager(
+ gpu_preferences_, this, watchdog_thread_.get(), main_runner_, io_runner_,
+ scheduler_.get(), sync_point_manager_, gpu_memory_buffer_factory_.get(),
+ gpu_feature_info_, std::move(activity_flags)));
+
+ media_gpu_channel_manager_.reset(
+ new media::MediaGpuChannelManager(gpu_channel_manager_.get()));
+ if (watchdog_thread())
+ watchdog_thread()->AddPowerObserver();
+}
+
+void GpuServiceImpl::Bind(mojom::GpuServiceRequest request) {
+ if (main_runner_->BelongsToCurrentThread()) {
+ bind_task_tracker_.PostTask(
+ io_runner_.get(), FROM_HERE,
+ base::Bind(&GpuServiceImpl::Bind, base::Unretained(this),
+ base::Passed(std::move(request))));
+ return;
+ }
+ bindings_->AddBinding(this, std::move(request));
+}
+
+gpu::ImageFactory* GpuServiceImpl::gpu_image_factory() {
+ return gpu_memory_buffer_factory_
+ ? gpu_memory_buffer_factory_->AsImageFactory()
+ : nullptr;
+}
+
+void GpuServiceImpl::RecordLogMessage(int severity,
+ size_t message_start,
+ const std::string& str) {
+ // This can be run from any thread.
+ std::string header = str.substr(0, message_start);
+ std::string message = str.substr(message_start);
+ (*gpu_host_)->RecordLogMessage(severity, header, message);
+}
+
+void GpuServiceImpl::CreateJpegDecodeAccelerator(
+ media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ // TODO(c.padhi): Implement this, see https://crbug.com/699255.
+ NOTIMPLEMENTED();
+}
+
+void GpuServiceImpl::CreateVideoEncodeAcceleratorProvider(
+ media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ media::MojoVideoEncodeAcceleratorProvider::Create(
+ std::move(vea_provider_request),
+ base::Bind(&media::GpuVideoEncodeAcceleratorFactory::CreateVEA),
+ gpu_preferences_);
+}
+
+void GpuServiceImpl::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ int client_id,
+ gpu::SurfaceHandle surface_handle,
+ CreateGpuMemoryBufferCallback callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ // This needs to happen in the IO thread.
+ std::move(callback).Run(gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
+ id, size, format, usage, client_id, surface_handle));
+}
+
+void GpuServiceImpl::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id,
+ const gpu::SyncToken& sync_token) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(FROM_HERE,
+ base::Bind(&GpuServiceImpl::DestroyGpuMemoryBuffer,
+ weak_ptr_, id, client_id, sync_token));
+ return;
+ }
+ gpu_channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
+}
+
+void GpuServiceImpl::GetVideoMemoryUsageStats(
+ GetVideoMemoryUsageStatsCallback callback) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ auto wrap_callback = WrapCallback(io_runner_, std::move(callback));
+ main_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&GpuServiceImpl::GetVideoMemoryUsageStats,
+ weak_ptr_, std::move(wrap_callback)));
+ return;
+ }
+ gpu::VideoMemoryUsageStats video_memory_usage_stats;
+ gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
+ &video_memory_usage_stats);
+ std::move(callback).Run(video_memory_usage_stats);
+}
+
+void GpuServiceImpl::RequestCompleteGpuInfo(
+ RequestCompleteGpuInfoCallback callback) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ auto wrap_callback = WrapCallback(io_runner_, std::move(callback));
+ main_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&GpuServiceImpl::RequestCompleteGpuInfo,
+ weak_ptr_, std::move(wrap_callback)));
+ return;
+ }
+ DCHECK(main_runner_->BelongsToCurrentThread());
+
+ UpdateGpuInfoPlatform(base::BindOnce(
+ IgnoreResult(&base::TaskRunner::PostTask), main_runner_, FROM_HERE,
+ base::BindOnce(
+ [](GpuServiceImpl* gpu_service,
+ RequestCompleteGpuInfoCallback callback) {
+ std::move(callback).Run(gpu_service->gpu_info_);
+#if defined(OS_WIN)
+ if (!gpu_service->in_host_process_) {
+ // The unsandboxed GPU process fulfilled its duty. Rest
+ // in peace.
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
+ }
+#endif
+ },
+ this, std::move(callback))));
+}
+
+#if defined(OS_MACOSX)
+void GpuServiceImpl::UpdateGpuInfoPlatform(
+ base::OnceClosure on_gpu_info_updated) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ // gpu::CollectContextGraphicsInfo() is already called during gpu process
+ // initialization (see GpuInit::InitializeAndStartSandbox()) on non-mac
+ // platforms, and during in-browser gpu thread initialization on all platforms
+ // (See InProcessGpuThread::Init()).
+ if (in_host_process_)
+ return;
+
+ DCHECK_EQ(gpu::kCollectInfoNone, gpu_info_.context_info_state);
+ gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info_);
+ switch (result) {
+ case gpu::kCollectInfoFatalFailure:
+ LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
+ // TODO(piman): can we signal overall failure?
+ break;
+ case gpu::kCollectInfoNonFatalFailure:
+ DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
+ break;
+ case gpu::kCollectInfoNone:
+ NOTREACHED();
+ break;
+ case gpu::kCollectInfoSuccess:
+ break;
+ }
+ gpu::SetKeysForCrashLogging(gpu_info_);
+ std::move(on_gpu_info_updated).Run();
+}
+#elif defined(OS_WIN)
+void GpuServiceImpl::UpdateGpuInfoPlatform(
+ base::OnceClosure on_gpu_info_updated) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ // GPU full info collection should only happen on un-sandboxed GPU process
+ // or single process/in-process gpu mode on Windows.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process_);
+
+ // We can continue on shutdown here because we're not writing any critical
+ // state in this task.
+ base::PostTaskAndReplyWithResult(
+ base::CreateCOMSTATaskRunnerWithTraits(
+ {base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
+ .get(),
+ FROM_HERE, base::BindOnce([]() {
+ gpu::DxDiagNode dx_diag_node;
+ gpu::GetDxDiagnostics(&dx_diag_node);
+ return dx_diag_node;
+ }),
+ base::BindOnce(
+ [](GpuServiceImpl* gpu_service, base::OnceClosure on_gpu_info_updated,
+ const gpu::DxDiagNode& dx_diag_node) {
+ gpu_service->gpu_info_.dx_diagnostics = dx_diag_node;
+ gpu_service->gpu_info_.dx_diagnostics_info_state =
+ gpu::kCollectInfoSuccess;
+ std::move(on_gpu_info_updated).Run();
+ },
+ this, std::move(on_gpu_info_updated)));
+}
+#else
+void GpuServiceImpl::UpdateGpuInfoPlatform(
+ base::OnceClosure on_gpu_info_updated) {
+ std::move(on_gpu_info_updated).Run();
+}
+#endif
+
+void GpuServiceImpl::DidCreateOffscreenContext(const GURL& active_url) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidCreateOffscreenContext(active_url);
+}
+
+void GpuServiceImpl::DidDestroyChannel(int client_id) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ media_gpu_channel_manager_->RemoveChannel(client_id);
+ (*gpu_host_)->DidDestroyChannel(client_id);
+}
+
+void GpuServiceImpl::DidDestroyOffscreenContext(const GURL& active_url) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidDestroyOffscreenContext(active_url);
+}
+
+void GpuServiceImpl::DidLoseContext(bool offscreen,
+ gpu::error::ContextLostReason reason,
+ const GURL& active_url) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidLoseContext(offscreen, reason, active_url);
+}
+
+void GpuServiceImpl::StoreShaderToDisk(int client_id,
+ const std::string& key,
+ const std::string& shader) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->StoreShaderToDisk(client_id, key, shader);
+}
+
+#if defined(OS_WIN)
+void GpuServiceImpl::SendAcceleratedSurfaceCreatedChildWindow(
+ gpu::SurfaceHandle parent_window,
+ gpu::SurfaceHandle child_window) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->SetChildSurface(parent_window, child_window);
+}
+#endif
+
+void GpuServiceImpl::SetActiveURL(const GURL& url) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ constexpr char kActiveURL[] = "url-chunk";
+ base::debug::SetCrashKeyValue(kActiveURL, url.possibly_invalid_spec());
+}
+
+void GpuServiceImpl::EstablishGpuChannel(int32_t client_id,
+ uint64_t client_tracing_id,
+ bool is_gpu_host,
+ EstablishGpuChannelCallback callback) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ EstablishGpuChannelCallback wrap_callback = base::BindOnce(
+ [](scoped_refptr<base::SingleThreadTaskRunner> runner,
+ EstablishGpuChannelCallback cb,
+ mojo::ScopedMessagePipeHandle handle) {
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(cb), std::move(handle)));
+ },
+ io_runner_, std::move(callback));
+ main_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&GpuServiceImpl::EstablishGpuChannel,
+ weak_ptr_, client_id, client_tracing_id,
+ is_gpu_host, std::move(wrap_callback)));
+ return;
+ }
+
+ gpu::GpuChannel* gpu_channel = gpu_channel_manager_->EstablishChannel(
+ client_id, client_tracing_id, is_gpu_host);
+
+ mojo::MessagePipe pipe;
+ gpu_channel->Init(base::MakeUnique<gpu::SyncChannelFilteredSender>(
+ pipe.handle0.release(), gpu_channel, io_runner_, shutdown_event_));
+
+ media_gpu_channel_manager_->AddChannel(client_id);
+
+ std::move(callback).Run(std::move(pipe.handle1));
+}
+
+void GpuServiceImpl::CloseChannel(int32_t client_id) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(FROM_HERE, base::Bind(&GpuServiceImpl::CloseChannel,
+ weak_ptr_, client_id));
+ return;
+ }
+ gpu_channel_manager_->RemoveChannel(client_id);
+}
+
+void GpuServiceImpl::LoadedShader(const std::string& key,
+ const std::string& data) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(FROM_HERE, base::Bind(&GpuServiceImpl::LoadedShader,
+ weak_ptr_, key, data));
+ return;
+ }
+ gpu_channel_manager_->PopulateShaderCache(key, data);
+}
+
+void GpuServiceImpl::DestroyingVideoSurface(
+ int32_t surface_id,
+ DestroyingVideoSurfaceCallback callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+#if defined(OS_ANDROID)
+ main_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::BindOnce(
+ [](int32_t surface_id) {
+ media::ContentVideoViewOverlayAllocator::GetInstance()
+ ->OnSurfaceDestroyed(surface_id);
+ },
+ surface_id),
+ std::move(callback));
+#else
+ NOTREACHED() << "DestroyingVideoSurface() not supported on this platform.";
+#endif
+}
+
+void GpuServiceImpl::WakeUpGpu() {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(FROM_HERE,
+ base::Bind(&GpuServiceImpl::WakeUpGpu, weak_ptr_));
+ return;
+ }
+#if defined(OS_ANDROID)
+ gpu_channel_manager_->WakeUpGpu();
+#else
+ NOTREACHED() << "WakeUpGpu() not supported on this platform.";
+#endif
+}
+
+void GpuServiceImpl::GpuSwitched() {
+ DVLOG(1) << "GPU: GPU has switched";
+ if (!in_host_process_)
+ ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
+}
+
+void GpuServiceImpl::DestroyAllChannels() {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuServiceImpl::DestroyAllChannels, weak_ptr_));
+ return;
+ }
+ DVLOG(1) << "GPU: Removing all contexts";
+ gpu_channel_manager_->DestroyAllChannels();
+}
+
+void GpuServiceImpl::Crash() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ DVLOG(1) << "GPU: Simulating GPU crash";
+ // Good bye, cruel world.
+ volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
+ *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
+}
+
+void GpuServiceImpl::Hang() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+
+ main_runner_->PostTask(FROM_HERE, base::Bind([] {
+ DVLOG(1) << "GPU: Simulating GPU hang";
+ for (;;) {
+ // Do not sleep here. The GPU watchdog timer tracks
+ // the amount of user time this thread is using and
+ // it doesn't use much while calling Sleep.
+ }
+ }));
+}
+
+void GpuServiceImpl::ThrowJavaException() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+#if defined(OS_ANDROID)
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind([] { base::android::ThrowUncaughtException(); }));
+#else
+ NOTREACHED() << "Java exception not supported on this platform.";
+#endif
+}
+
+void GpuServiceImpl::Stop(StopCallback callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ main_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::BindOnce([] { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }),
+ std::move(callback));
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
new file mode 100644
index 00000000000..7d1d968944a
--- /dev/null
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -0,0 +1,210 @@
+// 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_VIZ_SERVICE_GL_GPU_SERVICE_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_GL_GPU_SERVICE_IMPL_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "components/viz/service/viz_service_export.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "gpu/command_buffer/common/activity_flags.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/service/gpu_channel.h"
+#include "gpu/ipc/service/gpu_channel_manager.h"
+#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
+#include "gpu/ipc/service/gpu_config.h"
+#include "gpu/ipc/service/x_util.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/ui/gpu/interfaces/gpu_host.mojom.h"
+#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace gpu {
+class GpuMemoryBufferFactory;
+class GpuWatchdogThread;
+class Scheduler;
+class SyncPointManager;
+} // namespace gpu
+
+namespace media {
+class MediaGpuChannelManager;
+}
+
+namespace viz {
+
+// This runs in the GPU process, and communicates with the gpu host (which is
+// the window server) over the mojom APIs. This is responsible for setting up
+// the connection to clients, allocating/free'ing gpu memory etc.
+class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
+ public mojom::GpuService {
+ public:
+ GpuServiceImpl(const gpu::GPUInfo& gpu_info,
+ std::unique_ptr<gpu::GpuWatchdogThread> watchdog,
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+ const gpu::GpuFeatureInfo& gpu_feature_info);
+
+ ~GpuServiceImpl() override;
+
+ void UpdateGPUInfoFromPreferences(const gpu::GpuPreferences& preferences);
+
+ void InitializeWithHost(ui::mojom::GpuHostPtr gpu_host,
+ gpu::GpuProcessActivityFlags activity_flags,
+ gpu::SyncPointManager* sync_point_manager = nullptr,
+ base::WaitableEvent* shutdown_event = nullptr);
+ void Bind(mojom::GpuServiceRequest request);
+
+ bool is_initialized() const { return !!gpu_host_; }
+
+ media::MediaGpuChannelManager* media_gpu_channel_manager() {
+ return media_gpu_channel_manager_.get();
+ }
+
+ gpu::GpuChannelManager* gpu_channel_manager() {
+ return gpu_channel_manager_.get();
+ }
+
+ gpu::ImageFactory* gpu_image_factory();
+ gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory() {
+ return gpu_memory_buffer_factory_.get();
+ }
+
+ gpu::gles2::MailboxManager* mailbox_manager() {
+ return gpu_channel_manager_->mailbox_manager();
+ }
+
+ gl::GLShareGroup* share_group() {
+ return gpu_channel_manager_->share_group();
+ }
+
+ gpu::SyncPointManager* sync_point_manager() { return sync_point_manager_; }
+
+ gpu::GpuWatchdogThread* watchdog_thread() { return watchdog_thread_.get(); }
+
+ const gpu::GpuFeatureInfo& gpu_feature_info() const {
+ return gpu_feature_info_;
+ }
+
+ void set_in_host_process(bool in_host_process) {
+ in_host_process_ = in_host_process;
+ }
+
+ void set_start_time(base::Time start_time) { start_time_ = start_time; }
+
+ const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
+
+ private:
+ void RecordLogMessage(int severity,
+ size_t message_start,
+ const std::string& message);
+
+ void UpdateGpuInfoPlatform(base::OnceClosure on_gpu_info_updated);
+
+ // gpu::GpuChannelManagerDelegate:
+ void DidCreateOffscreenContext(const GURL& active_url) override;
+ void DidDestroyChannel(int client_id) override;
+ void DidDestroyOffscreenContext(const GURL& active_url) override;
+ void DidLoseContext(bool offscreen,
+ gpu::error::ContextLostReason reason,
+ const GURL& active_url) override;
+ void StoreShaderToDisk(int client_id,
+ const std::string& key,
+ const std::string& shader) override;
+#if defined(OS_WIN)
+ void SendAcceleratedSurfaceCreatedChildWindow(
+ gpu::SurfaceHandle parent_window,
+ gpu::SurfaceHandle child_window) override;
+#endif
+ void SetActiveURL(const GURL& url) override;
+
+ // mojom::GpuService:
+ void EstablishGpuChannel(int32_t client_id,
+ uint64_t client_tracing_id,
+ bool is_gpu_host,
+ EstablishGpuChannelCallback callback) override;
+ void CloseChannel(int32_t client_id) override;
+ void CreateJpegDecodeAccelerator(
+ media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override;
+ void CreateVideoEncodeAcceleratorProvider(
+ media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request)
+ override;
+ void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ int client_id,
+ gpu::SurfaceHandle surface_handle,
+ CreateGpuMemoryBufferCallback callback) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ int client_id,
+ const gpu::SyncToken& sync_token) override;
+ void GetVideoMemoryUsageStats(
+ GetVideoMemoryUsageStatsCallback callback) override;
+ void RequestCompleteGpuInfo(RequestCompleteGpuInfoCallback callback) override;
+ void LoadedShader(const std::string& key, const std::string& data) override;
+ void DestroyingVideoSurface(int32_t surface_id,
+ DestroyingVideoSurfaceCallback callback) override;
+ void WakeUpGpu() override;
+ void GpuSwitched() override;
+ void DestroyAllChannels() override;
+ void Crash() override;
+ void Hang() override;
+ void ThrowJavaException() override;
+ void Stop(StopCallback callback) override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
+
+ std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread_;
+
+ std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
+
+ gpu::GpuPreferences gpu_preferences_;
+
+ // Information about the GPU, such as device and vendor ID.
+ gpu::GPUInfo gpu_info_;
+
+ // Information about general chrome feature support for the GPU.
+ gpu::GpuFeatureInfo gpu_feature_info_;
+
+ scoped_refptr<ui::mojom::ThreadSafeGpuHostPtr> gpu_host_;
+ std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
+ std::unique_ptr<media::MediaGpuChannelManager> media_gpu_channel_manager_;
+
+ // On some platforms (e.g. android webview), the SyncPointManager comes from
+ // external sources.
+ std::unique_ptr<gpu::SyncPointManager> owned_sync_point_manager_;
+ gpu::SyncPointManager* sync_point_manager_ = nullptr;
+
+ std::unique_ptr<gpu::Scheduler> scheduler_;
+
+ // An event that will be signalled when we shutdown. On some platforms it
+ // comes from external sources.
+ std::unique_ptr<base::WaitableEvent> owned_shutdown_event_;
+ base::WaitableEvent* shutdown_event_ = nullptr;
+
+ // Whether this is running in the same process as the gpu host.
+ bool in_host_process_ = false;
+ base::Time start_time_;
+
+ // Used to track the task to bind a GpuServiceRequest on the io thread.
+ base::CancelableTaskTracker bind_task_tracker_;
+ std::unique_ptr<mojo::BindingSet<mojom::GpuService>> bindings_;
+
+ base::WeakPtr<GpuServiceImpl> weak_ptr_;
+ base::WeakPtrFactory<GpuServiceImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuServiceImpl);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_GL_GPU_SERVICE_IMPL_H_
diff --git a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
new file mode 100644
index 00000000000..7d0629d6b08
--- /dev/null
+++ b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -0,0 +1,97 @@
+// 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/viz/service/gl/gpu_service_impl.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/ipc/service/gpu_watchdog_thread.h"
+#include "services/ui/public/interfaces/gpu.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace test {
+
+class GpuServiceTest : public testing::Test {
+ public:
+ GpuServiceTest()
+ : io_thread_("TestIOThread"),
+ wait_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+ ~GpuServiceTest() override {}
+
+ GpuServiceImpl* gpu_service() { return gpu_service_.get(); }
+
+ void DestroyService() { gpu_service_ = nullptr; }
+
+ void BlockIOThread() {
+ wait_.Reset();
+ io_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Wait,
+ base::Unretained(&wait_)));
+ }
+
+ void UnblockIOThread() {
+ DCHECK(!wait_.IsSignaled());
+ wait_.Signal();
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner() {
+ return io_thread_.task_runner();
+ }
+
+ // testing::Test
+ void SetUp() override {
+ ASSERT_TRUE(io_thread_.Start());
+ gpu_service_ = base::MakeUnique<GpuServiceImpl>(
+ gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(),
+ gpu::GpuFeatureInfo());
+ }
+
+ void TearDown() override {
+ DestroyService();
+ base::RunLoop runloop;
+ runloop.RunUntilIdle();
+ io_thread_.Stop();
+ }
+
+ private:
+ base::Thread io_thread_;
+ std::unique_ptr<GpuServiceImpl> gpu_service_;
+ base::WaitableEvent wait_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuServiceTest);
+};
+
+// Tests that GpuServiceImpl can be destroyed before Bind() succeeds on the IO
+// thread.
+TEST_F(GpuServiceTest, ServiceDestroyedBeforeBind) {
+ // Block the IO thread to make sure that the GpuServiceImpl is destroyed
+ // before the binding happens on the IO thread.
+ mojom::GpuServicePtr ptr;
+ BlockIOThread();
+ gpu_service()->Bind(mojo::MakeRequest(&ptr));
+ UnblockIOThread();
+ DestroyService();
+}
+
+// Tests ghat GpuServiceImpl can be destroyed after Bind() succeeds on the IO
+// thread.
+TEST_F(GpuServiceTest, ServiceDestroyedAfterBind) {
+ mojom::GpuServicePtr ptr;
+ gpu_service()->Bind(mojo::MakeRequest(&ptr));
+ base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ io_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait)));
+ wait.Wait();
+ DestroyService();
+}
+
+} // namespace test
+} // namespace viz
diff --git a/chromium/components/viz/service/hit_test/DEPS b/chromium/components/viz/service/hit_test/DEPS
index e207341147d..38ff3f7e806 100644
--- a/chromium/components/viz/service/hit_test/DEPS
+++ b/chromium/components/viz/service/hit_test/DEPS
@@ -1,5 +1,9 @@
include_rules = [
- "+components/viz/common",
- "+cc/surfaces/surface_observer.h",
- "+services/viz/hit_test/public/interfaces",
+ "+components/viz/service/surfaces",
]
+
+specific_include_rules = {
+ "hit_test_aggregator_unittest.cc": [
+ "+components/viz/host/host_frame_sink_manager.h",
+ ]
+}
diff --git a/chromium/components/viz/service/hit_test/OWNERS b/chromium/components/viz/service/hit_test/OWNERS
deleted file mode 100644
index 3940e4c511d..00000000000
--- a/chromium/components/viz/service/hit_test/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rjkroege@chromium.org \ No newline at end of file
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
index 72845f5de51..303907258f2 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -3,21 +3,24 @@
// found in the LICENSE file.
#include "components/viz/service/hit_test/hit_test_aggregator.h"
+
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "components/viz/service/hit_test/hit_test_aggregator_delegate.h"
namespace viz {
namespace {
// TODO(gklassen): Review and select appropriate sizes based on
// telemetry / UMA.
-constexpr int kInitialSize = 1024;
-constexpr int kIncrementalSize = 1024;
-constexpr int kMaxRegionsPerSurface = 1024;
-constexpr int kMaxSize = 100 * 1024;
+constexpr uint32_t kInitialSize = 1024;
+constexpr uint32_t kIncrementalSize = 1024;
+constexpr uint32_t kMaxRegionsPerSurface = 1024;
+constexpr uint32_t kMaxSize = 100 * 1024;
bool ValidateHitTestRegion(const mojom::HitTestRegionPtr& hit_test_region) {
- if (hit_test_region->flags == mojom::kHitTestChildSurface) {
- if (!hit_test_region->surface_id.is_valid())
+ if (hit_test_region->flags & mojom::kHitTestChildSurface) {
+ if (!hit_test_region->local_surface_id.has_value() ||
+ !hit_test_region->local_surface_id->is_valid())
return false;
}
@@ -37,23 +40,63 @@ bool ValidateHitTestRegionList(
} // namespace
-HitTestAggregator::HitTestAggregator() : weak_ptr_factory_(this) {
+HitTestAggregator::HitTestAggregator(HitTestAggregatorDelegate* delegate)
+ : delegate_(delegate), weak_ptr_factory_(this) {
AllocateHitTestRegionArray();
}
HitTestAggregator::~HitTestAggregator() = default;
void HitTestAggregator::SubmitHitTestRegionList(
+ const SurfaceId& frame_sink_id,
mojom::HitTestRegionListPtr hit_test_region_list) {
DCHECK(ValidateHitTestRegionList(hit_test_region_list));
// TODO(gklassen): Runtime validation that hit_test_region_list is valid.
// TODO(gklassen): Inform FrameSink that the hit_test_region_list is invalid.
// TODO(gklassen): FrameSink needs to inform the host of a difficult renderer.
- pending_[hit_test_region_list->surface_id] = std::move(hit_test_region_list);
+ pending_[frame_sink_id] = std::move(hit_test_region_list);
+}
+
+void HitTestAggregator::PostTaskAggregate(const SurfaceId& display_surface_id) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&HitTestAggregator::Aggregate,
+ weak_ptr_factory_.GetWeakPtr(), display_surface_id));
+}
+
+void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id) {
+ // Check to ensure that enough memory has been allocated.
+ uint32_t size = write_size_;
+ uint32_t max_size = active_region_count_ + active_.size() + 1;
+ if (max_size > kMaxSize)
+ max_size = kMaxSize;
+
+ if (max_size > size) {
+ size = (1 + max_size / kIncrementalSize) * kIncrementalSize;
+ AllocateHitTestRegionArray(size);
+ }
+
+ AppendRoot(display_surface_id);
+}
+
+void HitTestAggregator::Swap() {
+ SwapHandles();
+ if (!handle_replaced_) {
+ delegate_->SwitchActiveAggregatedHitTestRegionList(active_handle_index_);
+ return;
+ }
+
+ delegate_->OnAggregatedHitTestRegionListUpdated(
+ read_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
+ read_size_,
+ write_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
+ write_size_);
+ active_handle_index_ = 0;
+ handle_replaced_ = false;
}
bool HitTestAggregator::OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) {
+ const BeginFrameAck& ack) {
return false;
}
@@ -64,7 +107,7 @@ void HitTestAggregator::OnSurfaceDiscarded(const SurfaceId& surface_id) {
mojom::HitTestRegionList* old_hit_test_data = active_search->second.get();
active_region_count_ -= old_hit_test_data->regions.size();
}
- DCHECK_GE(active_region_count_, 0);
+ DCHECK_GE(active_region_count_, 0u);
pending_.erase(surface_id);
active_.erase(surface_id);
@@ -86,7 +129,7 @@ void HitTestAggregator::OnSurfaceWillDraw(const SurfaceId& surface_id) {
active_region_count_ -= old_hit_test_data->regions.size();
}
active_region_count_ += hit_test_region_list->regions.size();
- DCHECK_GE(active_region_count_, 0);
+ DCHECK_GE(active_region_count_, 0u);
active_[surface_id] = std::move(pending_[surface_id]);
pending_.erase(surface_id);
@@ -94,41 +137,29 @@ void HitTestAggregator::OnSurfaceWillDraw(const SurfaceId& surface_id) {
void HitTestAggregator::AllocateHitTestRegionArray() {
AllocateHitTestRegionArray(kInitialSize);
- Swap();
+ SwapHandles();
AllocateHitTestRegionArray(kInitialSize);
}
-void HitTestAggregator::AllocateHitTestRegionArray(int size) {
+void HitTestAggregator::AllocateHitTestRegionArray(uint32_t size) {
size_t num_bytes = size * sizeof(AggregatedHitTestRegion);
write_handle_ = mojo::SharedBufferHandle::Create(num_bytes);
write_size_ = size;
write_buffer_ = write_handle_->Map(num_bytes);
+ handle_replaced_ = true;
AggregatedHitTestRegion* region =
(AggregatedHitTestRegion*)write_buffer_.get();
region[0].child_count = kEndOfList;
}
-void HitTestAggregator::PostTaskAggregate(SurfaceId display_surface_id) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&HitTestAggregator::Aggregate,
- weak_ptr_factory_.GetWeakPtr(), display_surface_id));
-}
-
-void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id) {
- // Check to ensure that enough memory has been allocated.
- int size = write_size_;
- int max_size = active_region_count_ + active_.size() + 1;
- if (max_size > kMaxSize)
- max_size = kMaxSize;
-
- if (max_size > size) {
- size = (1 + max_size / kIncrementalSize) * kIncrementalSize;
- AllocateHitTestRegionArray(size);
- }
+void HitTestAggregator::SwapHandles() {
+ using std::swap;
- AppendRoot(display_surface_id);
+ swap(read_handle_, write_handle_);
+ swap(read_size_, write_size_);
+ swap(read_buffer_, write_buffer_);
+ active_handle_index_ = !active_handle_index_;
}
void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
@@ -141,41 +172,43 @@ void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
AggregatedHitTestRegion* regions =
static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
- regions[0].frame_sink_id = hit_test_region_list->surface_id.frame_sink_id();
+ regions[0].frame_sink_id = surface_id.frame_sink_id();
regions[0].flags = hit_test_region_list->flags;
regions[0].rect = hit_test_region_list->bounds;
regions[0].transform = hit_test_region_list->transform;
- int region_index = 1;
+ size_t region_index = 1;
for (const auto& region : hit_test_region_list->regions) {
if (region_index >= write_size_ - 1)
break;
region_index = AppendRegion(regions, region_index, region);
}
- DCHECK_GE(region_index, 1);
+ DCHECK_GE(region_index, 1u);
regions[0].child_count = region_index - 1;
regions[region_index].child_count = kEndOfList;
}
-int HitTestAggregator::AppendRegion(AggregatedHitTestRegion* regions,
- int region_index,
- const mojom::HitTestRegionPtr& region) {
+size_t HitTestAggregator::AppendRegion(AggregatedHitTestRegion* regions,
+ size_t region_index,
+ const mojom::HitTestRegionPtr& region) {
AggregatedHitTestRegion* element = &regions[region_index];
- element->frame_sink_id = region->surface_id.frame_sink_id();
+ element->frame_sink_id = region->frame_sink_id;
element->flags = region->flags;
element->rect = region->rect;
element->transform = region->transform;
- int parent_index = region_index++;
+ size_t parent_index = region_index++;
if (region_index >= write_size_ - 1) {
element->child_count = 0;
return region_index;
}
- if (region->flags == mojom::kHitTestChildSurface) {
- auto search = active_.find(region->surface_id);
+ if (region->flags & mojom::kHitTestChildSurface) {
+ auto surface_id =
+ SurfaceId(region->frame_sink_id, region->local_surface_id.value());
+ auto search = active_.find(surface_id);
if (search == active_.end()) {
// Surface HitTestRegionList not found - it may be late.
// Don't include this region so that it doesn't receive events.
@@ -197,17 +230,9 @@ int HitTestAggregator::AppendRegion(AggregatedHitTestRegion* regions,
break;
}
}
- DCHECK_GE(region_index - parent_index - 1, 0);
+ DCHECK_GE(region_index - parent_index - 1, 0u);
element->child_count = region_index - parent_index - 1;
return region_index;
}
-void HitTestAggregator::Swap() {
- using std::swap;
-
- swap(read_handle_, write_handle_);
- swap(read_size_, write_size_);
- swap(read_buffer_, write_buffer_);
-}
-
} // namespace viz
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.h b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
index 0b49a18201f..9d08d056b97 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
@@ -5,13 +5,14 @@
#ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_H_
#define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_H_
-#include "cc/surfaces/surface_observer.h"
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/viz_service_export.h"
-#include "services/viz/hit_test/public/interfaces/hit_test_region_list.mojom.h"
+#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
namespace viz {
+class HitTestAggregatorDelegate;
// HitTestAggregator collects HitTestRegionList objects from surfaces and
// aggregates them into a DisplayHitTesData structue made available in
@@ -19,39 +20,43 @@ namespace viz {
//
// This is intended to be created in the viz or GPU process. For mus+ash this
// will be true after the mus process split.
-class VIZ_SERVICE_EXPORT HitTestAggregator : public cc::SurfaceObserver {
+class VIZ_SERVICE_EXPORT HitTestAggregator : public SurfaceObserver {
public:
- HitTestAggregator();
+ // |delegate| owns and outlives HitTestAggregator.
+ explicit HitTestAggregator(HitTestAggregatorDelegate* delegate);
~HitTestAggregator();
// Called when HitTestRegionList is submitted along with every call
// to SubmitCompositorFrame. This is collected in pending_ until
// surfaces are aggregated and put on the display.
void SubmitHitTestRegionList(
+ const SurfaceId& surface_id,
mojom::HitTestRegionListPtr hit_test_region_list);
+ // Performs the work of Aggregate by creating a PostTask so that
+ // the work is not directly on the call.
+ void PostTaskAggregate(const SurfaceId& display_surface_id);
+
// Called after surfaces have been aggregated into the DisplayFrame.
// In this call HitTestRegionList structures received from active surfaces
// are aggregated into the HitTestRegionList structure in
// shared memory used for event targetting.
void Aggregate(const SurfaceId& display_surface_id);
- // Performs the work of Aggregate by creating a PostTask so that
- // the work is not directly on the call.
- void PostTaskAggregate(SurfaceId display_surface_id);
-
- // Called at BeginFrame. Swaps buffers in shared memory.
+ // Called at BeginFrame. Swaps buffers in shared memory and tells its
+ // delegate.
void Swap();
protected:
- // cc::SurfaceObserver:
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+ // SurfaceObserver:
+ void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override {}
+ void OnSurfaceActivated(const SurfaceId& surface_id) override {}
void OnSurfaceDestroyed(const SurfaceId& surface_id) override {}
bool OnSurfaceDamaged(const SurfaceId& surface_id,
- const cc::BeginFrameAck& ack) override;
+ const BeginFrameAck& ack) override;
void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
void OnSurfaceDamageExpected(const SurfaceId& surface_id,
- const cc::BeginFrameArgs& args) override {}
+ const BeginFrameArgs& args) override {}
// Called when a surface has been aggregated and added to the
// display frame. HitTestRegionList objects are held but ignored until
@@ -69,31 +74,40 @@ class VIZ_SERVICE_EXPORT HitTestAggregator : public cc::SurfaceObserver {
// Keeps track of the number of regions in the active list
// so that we know when we exceed the available length.
- int active_region_count_ = 0;
+ uint32_t active_region_count_ = 0;
mojo::ScopedSharedBufferHandle read_handle_;
mojo::ScopedSharedBufferHandle write_handle_;
// The number of elements allocated.
- int read_size_ = 0;
- int write_size_ = 0;
+ uint32_t read_size_ = 0;
+ uint32_t write_size_ = 0;
mojo::ScopedSharedBufferMapping read_buffer_;
mojo::ScopedSharedBufferMapping write_buffer_;
+ bool handle_replaced_ = false;
+
+ // Can only be 0 or 1 when we only have two buffers.
+ uint8_t active_handle_index_ = 0;
+
+ HitTestAggregatorDelegate* const delegate_;
+
private:
// Allocates memory for the AggregatedHitTestRegion array.
void AllocateHitTestRegionArray();
- void AllocateHitTestRegionArray(int length);
+ void AllocateHitTestRegionArray(uint32_t length);
+
+ void SwapHandles();
// Appends the root element to the AggregatedHitTestRegion array.
void AppendRoot(const SurfaceId& surface_id);
// Appends a region to the HitTestRegionList structure to recursively
// build the tree.
- int AppendRegion(AggregatedHitTestRegion* regions,
- int region_index,
- const mojom::HitTestRegionPtr& region);
+ size_t AppendRegion(AggregatedHitTestRegion* regions,
+ size_t region_index,
+ const mojom::HitTestRegionPtr& region);
// Handles the case when this object is deleted after
// the PostTaskAggregation call is scheduled but before invocation.
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h
new file mode 100644
index 00000000000..4d990d287d2
--- /dev/null
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h
@@ -0,0 +1,31 @@
+// 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_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_
+#define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_
+
+namespace viz {
+// Used by HitTestAggregator to talk to GpuRootCompositorFrameSink.
+class HitTestAggregatorDelegate {
+ public:
+ // Called if any of the buffer that stores the aggregated hit-test data is
+ // updated (e.g. destroyed, reallocated etc.). |active_handle| and
+ // |idle_handle| both must be valid.
+ virtual void OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) = 0;
+
+ virtual void SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) = 0;
+
+ protected:
+ // The dtor is protected so that HitTestAggregator does not take ownership.
+ virtual ~HitTestAggregatorDelegate() {}
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
index 4a23b4dca4a..7822bcc648c 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -4,9 +4,14 @@
#include "components/viz/service/hit_test/hit_test_aggregator.h"
+#include <map>
+
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/hit_test/hit_test_aggregator_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -21,11 +26,10 @@ SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
}
-} // namespace
-
-class TestHitTestAggregator : public HitTestAggregator {
+class TestHitTestAggregator final : public HitTestAggregator {
public:
- TestHitTestAggregator() = default;
+ explicit TestHitTestAggregator(HitTestAggregatorDelegate* delegate)
+ : HitTestAggregator(delegate) {}
~TestHitTestAggregator() = default;
void CallOnSurfaceWillDraw(SurfaceId surface_id) {
@@ -49,8 +53,8 @@ class TestHitTestAggregator : public HitTestAggregator {
int GetActiveCount() { return active_.size(); }
int GetActiveRegionCount() { return active_region_count_; }
int GetHitTestRegionListSize() { return read_size_; }
- AggregatedHitTestRegion* GetRegions() {
- return static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
+ void SwapHandles() {
+ delegate_->SwitchActiveAggregatedHitTestRegionList(active_handle_index_);
}
void Reset() {
@@ -66,16 +70,159 @@ class TestHitTestAggregator : public HitTestAggregator {
}
};
+class TestFrameSinkManagerImpl;
+
+class TestGpuRootCompositorFrameSink : public HitTestAggregatorDelegate {
+ public:
+ TestGpuRootCompositorFrameSink(TestFrameSinkManagerImpl* frame_sink_manager,
+ const FrameSinkId& frame_sink_id)
+ : frame_sink_manager_(frame_sink_manager),
+ frame_sink_id_(frame_sink_id),
+ aggregator_(base::MakeUnique<TestHitTestAggregator>(this)) {}
+ ~TestGpuRootCompositorFrameSink() override = default;
+
+ // HitTestAggregatorDelegate:
+ void OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) override;
+ void SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) override;
+
+ TestHitTestAggregator* aggregator() { return aggregator_.get(); }
+
+ private:
+ TestFrameSinkManagerImpl* frame_sink_manager_;
+ FrameSinkId frame_sink_id_;
+ std::unique_ptr<TestHitTestAggregator> aggregator_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestGpuRootCompositorFrameSink);
+};
+
+class TestHostFrameSinkManager : public HostFrameSinkManager {
+ public:
+ TestHostFrameSinkManager() = default;
+ ~TestHostFrameSinkManager() override = default;
+
+ void OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) override {
+ DCHECK(active_handle.is_valid() && idle_handle.is_valid());
+ buffer_frame_sink_id_ = frame_sink_id;
+ handle_buffers_[0] = active_handle->Map(active_handle_size *
+ sizeof(AggregatedHitTestRegion));
+ handle_buffers_[1] =
+ idle_handle->Map(idle_handle_size * sizeof(AggregatedHitTestRegion));
+ SwitchActiveAggregatedHitTestRegionList(buffer_frame_sink_id_, 0);
+ }
+
+ void SwitchActiveAggregatedHitTestRegionList(
+ const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) override {
+ active_list_ = static_cast<AggregatedHitTestRegion*>(
+ handle_buffers_[active_handle_index].get());
+ }
+
+ AggregatedHitTestRegion* regions() { return active_list_; }
+
+ const FrameSinkId& buffer_frame_sink_id() { return buffer_frame_sink_id_; }
+
+ private:
+ FrameSinkId buffer_frame_sink_id_;
+ mojo::ScopedSharedBufferMapping handle_buffers_[2];
+ AggregatedHitTestRegion* active_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestHostFrameSinkManager);
+};
+
+class TestFrameSinkManagerImpl : public FrameSinkManagerImpl {
+ public:
+ TestFrameSinkManagerImpl() = default;
+ ~TestFrameSinkManagerImpl() override = default;
+
+ void SetLocalClient(TestHostFrameSinkManager* client) {
+ host_client_ = client;
+ }
+
+ void OnAggregatedHitTestRegionListUpdated(
+ const FrameSinkId& frame_sink_id,
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
+ // Do not check if it's on valid thread for tests.
+ if (host_client_) {
+ host_client_->OnAggregatedHitTestRegionListUpdated(
+ frame_sink_id, std::move(active_handle), active_handle_size,
+ std::move(idle_handle), idle_handle_size);
+ }
+ }
+
+ void SwitchActiveAggregatedHitTestRegionList(const FrameSinkId& frame_sink_id,
+ uint8_t active_handle_index) {
+ // Do not check if it's on valid thread for tests.
+ if (host_client_) {
+ host_client_->SwitchActiveAggregatedHitTestRegionList(
+ frame_sink_id, active_handle_index);
+ }
+ }
+
+ void CreateRootCompositorFrameSinkLocal(const FrameSinkId& frame_sink_id) {
+ compositor_frame_sinks_[frame_sink_id] =
+ base::MakeUnique<TestGpuRootCompositorFrameSink>(this, frame_sink_id);
+ }
+
+ const std::map<FrameSinkId, std::unique_ptr<TestGpuRootCompositorFrameSink>>&
+ compositor_frame_sinks() {
+ return compositor_frame_sinks_;
+ }
+
+ private:
+ std::map<FrameSinkId, std::unique_ptr<TestGpuRootCompositorFrameSink>>
+ compositor_frame_sinks_;
+ TestHostFrameSinkManager* host_client_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(TestFrameSinkManagerImpl);
+};
+
+void TestGpuRootCompositorFrameSink::OnAggregatedHitTestRegionListUpdated(
+ mojo::ScopedSharedBufferHandle active_handle,
+ uint32_t active_handle_size,
+ mojo::ScopedSharedBufferHandle idle_handle,
+ uint32_t idle_handle_size) {
+ frame_sink_manager_->OnAggregatedHitTestRegionListUpdated(
+ frame_sink_id_, std::move(active_handle), active_handle_size,
+ std::move(idle_handle), idle_handle_size);
+}
+
+void TestGpuRootCompositorFrameSink::SwitchActiveAggregatedHitTestRegionList(
+ uint8_t active_handle_index) {
+ frame_sink_manager_->SwitchActiveAggregatedHitTestRegionList(
+ frame_sink_id_, active_handle_index);
+}
+
+} // namespace
+
class HitTestAggregatorTest : public testing::Test {
public:
HitTestAggregatorTest() = default;
~HitTestAggregatorTest() override = default;
// testing::Test:
- void SetUp() override {}
- void TearDown() override { aggregator_.Reset(); }
-
- TestHitTestAggregator aggregator_;
+ void SetUp() override {
+ frame_sink_manager_ = base::MakeUnique<TestFrameSinkManagerImpl>();
+ host_frame_sink_manager_ = base::MakeUnique<TestHostFrameSinkManager>();
+ frame_sink_manager_->SetLocalClient(host_frame_sink_manager_.get());
+ frame_sink_manager_->CreateRootCompositorFrameSinkLocal(kDisplayFrameSink);
+ }
+ void TearDown() override {
+ frame_sink_manager_.reset();
+ host_frame_sink_manager_.reset();
+ }
// Creates a hit test data element with 8 children recursively to
// the specified depth. SurfaceIds are generated in sequential order and
@@ -85,17 +232,18 @@ class HitTestAggregatorTest : public testing::Test {
id++;
auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->surface_id = surface_id;
hit_test_region_list->flags = mojom::kHitTestMine;
hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
for (int i = 0; i < 8; i++) {
auto hit_test_region = mojom::HitTestRegion::New();
hit_test_region->rect.SetRect(100, 100, 100, 100);
+ SurfaceId child_surface_id = MakeSurfaceId(kDisplayFrameSink, id);
+ hit_test_region->frame_sink_id = child_surface_id.frame_sink_id();
+ hit_test_region->local_surface_id = child_surface_id.local_surface_id();
if (depth > 0) {
hit_test_region->flags = mojom::kHitTestChildSurface;
- hit_test_region->surface_id = MakeSurfaceId(kDisplayFrameSink, id);
id = CreateAndSubmitHitTestRegionListWith8Children(id, depth - 1);
} else {
hit_test_region->flags = mojom::kHitTestMine;
@@ -103,9 +251,32 @@ class HitTestAggregatorTest : public testing::Test {
hit_test_region_list->regions.push_back(std::move(hit_test_region));
}
- aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list));
+ GetAggregator(kDisplayFrameSink)
+ ->SubmitHitTestRegionList(surface_id, std::move(hit_test_region_list));
return id;
}
+
+ protected:
+ TestHitTestAggregator* GetAggregator(const FrameSinkId& frame_sink_id) {
+ DCHECK(frame_sink_manager_->compositor_frame_sinks().count(frame_sink_id));
+ return frame_sink_manager_->compositor_frame_sinks()
+ .at(frame_sink_id)
+ ->aggregator();
+ }
+
+ AggregatedHitTestRegion* host_regions() {
+ return host_frame_sink_manager_->regions();
+ }
+
+ const FrameSinkId& host_buffer_frame_sink_id() {
+ return host_frame_sink_manager_->buffer_frame_sink_id();
+ }
+
+ private:
+ std::unique_ptr<TestFrameSinkManagerImpl> frame_sink_manager_;
+ std::unique_ptr<TestHostFrameSinkManager> host_frame_sink_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestAggregatorTest);
};
// TODO(gklassen): Add tests for 3D use cases as suggested by and with
@@ -120,41 +291,44 @@ class HitTestAggregatorTest : public testing::Test {
// +----------+
//
TEST_F(HitTestAggregatorTest, OneSurface) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->surface_id = display_surface_id;
hit_test_region_list->flags = mojom::kHitTestMine;
hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
- aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list));
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->SubmitHitTestRegionList(display_surface_id,
+ std::move(hit_test_region_list));
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(1, aggregator_.GetPendingCount());
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(display_surface_id);
+ aggregator->CallOnSurfaceWillDraw(display_surface_id);
- EXPECT_EQ(0, aggregator_.GetPendingCount());
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.Aggregate(display_surface_id);
- aggregator_.Swap();
+ aggregator->Aggregate(display_surface_id);
+ aggregator->Swap();
+ aggregator->SwapHandles();
// Expect 1 entry routing all events to the one surface (display root).
- EXPECT_EQ(1, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 1);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(display_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, display_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 0);
}
// One opaque embedder with two regions.
@@ -167,68 +341,75 @@ TEST_F(HitTestAggregatorTest, OneSurface) {
// +--------------+
//
TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_r1 = mojom::HitTestRegion::New();
+ e_hit_test_region_r1->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_r1->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_r1->flags = mojom::kHitTestMine;
e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400);
auto e_hit_test_region_r2 = mojom::HitTestRegion::New();
+ e_hit_test_region_r2->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_r2->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_r2->flags = mojom::kHitTestMine;
e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r1));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r2));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r1));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r2));
// Submit mojom::HitTestRegionList.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
// Add Surfaces to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->Count(), 0);
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
- EXPECT_EQ(3, aggregator_.Count());
+ aggregator->Swap();
+ aggregator->SwapHandles();
+ EXPECT_EQ(aggregator->Count(), 3);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 2);
region = &regions[1];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(gfx::Rect(100, 100, 200, 400), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 400));
+ EXPECT_EQ(region->child_count, 0);
region = &regions[2];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(gfx::Rect(400, 100, 300, 400), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->rect, gfx::Rect(400, 100, 300, 400));
+ EXPECT_EQ(region->child_count, 0);
}
// One embedder with two children.
@@ -242,94 +423,99 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) {
//
TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c1->surface_id = c1_surface_id;
+ e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
+ e_hit_test_region_c1->local_surface_id = c1_surface_id.local_surface_id();
e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300);
auto e_hit_test_region_c2 = mojom::HitTestRegion::New();
e_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c2->surface_id = c2_surface_id;
+ e_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
+ e_hit_test_region_c2->local_surface_id = c2_surface_id.local_surface_id();
e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c2));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c2));
- auto c1_hit_test_data = mojom::HitTestRegionList::New();
- c1_hit_test_data->surface_id = c1_surface_id;
+ auto c1_hit_test_region_list = mojom::HitTestRegionList::New();
- auto c2_hit_test_data = mojom::HitTestRegionList::New();
- c2_hit_test_data->surface_id = c2_surface_id;
+ auto c2_hit_test_region_list = mojom::HitTestRegionList::New();
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c1_surface_id,
+ std::move(c1_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
- aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data));
- EXPECT_EQ(3, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c2_surface_id,
+ std::move(c2_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 3);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(c2_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c2_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.CallOnSurfaceWillDraw(c1_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c1_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(3, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 3);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(3, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 3);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 2);
region = &regions[1];
- EXPECT_EQ(mojom::kHitTestChildSurface, region->flags);
- EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 200, 300), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestChildSurface);
+ EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 300));
+ EXPECT_EQ(region->child_count, 0);
region = &regions[2];
- EXPECT_EQ(mojom::kHitTestChildSurface, region->flags);
- EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(400, 100, 400, 300), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestChildSurface);
+ EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(400, 100, 400, 300));
+ EXPECT_EQ(region->child_count, 0);
}
// Occluded child frame (OOPIF).
@@ -344,86 +530,91 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) {
//
TEST_F(HitTestAggregatorTest, OccludedChildFrame) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_div = mojom::HitTestRegion::New();
e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->surface_id = e_surface_id;
+ e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->surface_id = c_surface_id;
+ e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
- auto c_hit_test_data = mojom::HitTestRegionList::New();
- c_hit_test_data->surface_id = c_surface_id;
- c_hit_test_data->flags = mojom::kHitTestMine;
- c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+ auto c_hit_test_region_list = mojom::HitTestRegionList::New();
+ c_hit_test_region_list->flags = mojom::kHitTestMine;
+ c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c_surface_id,
+ std::move(c_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.CallOnSurfaceWillDraw(c_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(3, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 3);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 2);
region = &regions[1];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region->child_count, 0);
region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 200, 500), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500));
+ EXPECT_EQ(region->child_count, 0);
}
// Foreground child frame (OOPIF).
@@ -439,86 +630,91 @@ TEST_F(HitTestAggregatorTest, OccludedChildFrame) {
//
TEST_F(HitTestAggregatorTest, ForegroundChildFrame) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_div = mojom::HitTestRegion::New();
e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->surface_id = e_surface_id;
+ e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->surface_id = c_surface_id;
+ e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_data = mojom::HitTestRegionList::New();
- c_hit_test_data->surface_id = c_surface_id;
- c_hit_test_data->flags = mojom::kHitTestMine;
- c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+ auto c_hit_test_region_list = mojom::HitTestRegionList::New();
+ c_hit_test_region_list->flags = mojom::kHitTestMine;
+ c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c_surface_id,
+ std::move(c_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.CallOnSurfaceWillDraw(c_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(3, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 3);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 2);
region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 200, 500), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500));
+ EXPECT_EQ(region->child_count, 0);
region = &regions[2];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region->child_count, 0);
}
// One embedder with a clipped child with a tab and transparent background.
@@ -534,128 +730,135 @@ TEST_F(HitTestAggregatorTest, ForegroundChildFrame) {
//
TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
SurfaceId a_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
SurfaceId b_surface_id = MakeSurfaceId(kDisplayFrameSink, 4);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->surface_id = c_surface_id;
- e_hit_test_region_c->rect.SetRect(200, 100, 1600, 800);
+ e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
+ e_hit_test_region_c->rect.SetRect(300, 100, 1600, 800);
e_hit_test_region_c->transform.Translate(200, 100);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
- auto c_hit_test_data = mojom::HitTestRegionList::New();
- c_hit_test_data->surface_id = c_surface_id;
- c_hit_test_data->flags = mojom::kHitTestIgnore;
- c_hit_test_data->bounds.SetRect(0, 0, 1600, 800);
+ auto c_hit_test_region_list = mojom::HitTestRegionList::New();
+ c_hit_test_region_list->flags = mojom::kHitTestIgnore;
+ c_hit_test_region_list->bounds.SetRect(0, 0, 1600, 800);
auto c_hit_test_region_a = mojom::HitTestRegion::New();
c_hit_test_region_a->flags = mojom::kHitTestChildSurface;
- c_hit_test_region_a->surface_id = a_surface_id;
+ c_hit_test_region_a->frame_sink_id = a_surface_id.frame_sink_id();
+ c_hit_test_region_a->local_surface_id = a_surface_id.local_surface_id();
c_hit_test_region_a->rect.SetRect(0, 0, 200, 100);
auto c_hit_test_region_b = mojom::HitTestRegion::New();
c_hit_test_region_b->flags = mojom::kHitTestChildSurface;
- c_hit_test_region_b->surface_id = b_surface_id;
+ c_hit_test_region_b->frame_sink_id = b_surface_id.frame_sink_id();
+ c_hit_test_region_b->local_surface_id = b_surface_id.local_surface_id();
c_hit_test_region_b->rect.SetRect(0, 100, 800, 600);
- c_hit_test_data->regions.push_back(std::move(c_hit_test_region_a));
- c_hit_test_data->regions.push_back(std::move(c_hit_test_region_b));
+ c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_a));
+ c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_b));
- auto a_hit_test_data = mojom::HitTestRegionList::New();
- a_hit_test_data->surface_id = a_surface_id;
- a_hit_test_data->flags = mojom::kHitTestMine;
- a_hit_test_data->bounds.SetRect(0, 0, 200, 100);
+ auto a_hit_test_region_list = mojom::HitTestRegionList::New();
+ a_hit_test_region_list->flags = mojom::kHitTestMine;
+ a_hit_test_region_list->bounds.SetRect(0, 0, 200, 100);
- auto b_hit_test_data = mojom::HitTestRegionList::New();
- b_hit_test_data->surface_id = b_surface_id;
- b_hit_test_data->flags = mojom::kHitTestMine;
- b_hit_test_data->bounds.SetRect(0, 100, 800, 600);
+ auto b_hit_test_region_list = mojom::HitTestRegionList::New();
+ b_hit_test_region_list->flags = mojom::kHitTestMine;
+ b_hit_test_region_list->bounds.SetRect(0, 100, 800, 600);
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c_surface_id,
+ std::move(c_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(a_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(a_surface_id,
+ std::move(a_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
- aggregator_.SubmitHitTestRegionList(std::move(b_hit_test_data));
- EXPECT_EQ(3, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(b_surface_id,
+ std::move(b_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 3);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(4, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 4);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(c_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
- aggregator_.CallOnSurfaceWillDraw(b_surface_id);
- EXPECT_EQ(3, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(b_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 3);
- aggregator_.CallOnSurfaceWillDraw(a_surface_id);
- EXPECT_EQ(4, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(a_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 4);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(4, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 4);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(3, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 3);
region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestIgnore);
- EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(200, 100, 1600, 800), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestIgnore, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(300, 100, 1600, 800));
+ EXPECT_EQ(region->child_count, 2);
gfx::Point point(300, 300);
- region->transform.TransformPointReverse(&point);
+ gfx::Transform transform(region->transform);
+ transform.TransformPointReverse(&point);
EXPECT_TRUE(point == gfx::Point(100, 200));
region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(a_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 200, 100), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, a_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 200, 100));
+ EXPECT_EQ(region->child_count, 0);
region = &regions[3];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(b_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 100, 800, 600), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, b_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 100, 800, 600));
+ EXPECT_EQ(region->child_count, 0);
}
// Three children deep.
@@ -672,124 +875,130 @@ TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) {
//
TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
SurfaceId c3_surface_id = MakeSurfaceId(kDisplayFrameSink, 4);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c1->surface_id = c1_surface_id;
+ e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
+ e_hit_test_region_c1->local_surface_id = c1_surface_id.local_surface_id();
e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
- auto c1_hit_test_data = mojom::HitTestRegionList::New();
- c1_hit_test_data->surface_id = c1_surface_id;
- c1_hit_test_data->flags = mojom::kHitTestMine;
- c1_hit_test_data->bounds.SetRect(0, 0, 600, 600);
+ auto c1_hit_test_region_list = mojom::HitTestRegionList::New();
+ c1_hit_test_region_list->flags = mojom::kHitTestMine;
+ c1_hit_test_region_list->bounds.SetRect(0, 0, 600, 600);
auto c1_hit_test_region_c2 = mojom::HitTestRegion::New();
c1_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
- c1_hit_test_region_c2->surface_id = c2_surface_id;
+ c1_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
+ c1_hit_test_region_c2->local_surface_id = c2_surface_id.local_surface_id();
c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500);
- c1_hit_test_data->regions.push_back(std::move(c1_hit_test_region_c2));
+ c1_hit_test_region_list->regions.push_back(std::move(c1_hit_test_region_c2));
- auto c2_hit_test_data = mojom::HitTestRegionList::New();
- c2_hit_test_data->surface_id = c2_surface_id;
- c2_hit_test_data->flags = mojom::kHitTestMine;
- c2_hit_test_data->bounds.SetRect(0, 0, 400, 400);
+ auto c2_hit_test_region_list = mojom::HitTestRegionList::New();
+ c2_hit_test_region_list->flags = mojom::kHitTestMine;
+ c2_hit_test_region_list->bounds.SetRect(0, 0, 400, 400);
auto c2_hit_test_region_c3 = mojom::HitTestRegion::New();
c2_hit_test_region_c3->flags = mojom::kHitTestChildSurface;
- c2_hit_test_region_c3->surface_id = c3_surface_id;
+ c2_hit_test_region_c3->frame_sink_id = c3_surface_id.frame_sink_id();
+ c2_hit_test_region_c3->local_surface_id = c3_surface_id.local_surface_id();
c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300);
- c2_hit_test_data->regions.push_back(std::move(c2_hit_test_region_c3));
+ c2_hit_test_region_list->regions.push_back(std::move(c2_hit_test_region_c3));
- auto c3_hit_test_data = mojom::HitTestRegionList::New();
- c3_hit_test_data->surface_id = c3_surface_id;
- c3_hit_test_data->flags = mojom::kHitTestMine;
- c3_hit_test_data->bounds.SetRect(0, 0, 200, 200);
+ auto c3_hit_test_region_list = mojom::HitTestRegionList::New();
+ c3_hit_test_region_list->flags = mojom::kHitTestMine;
+ c3_hit_test_region_list->bounds.SetRect(0, 0, 200, 200);
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c1_surface_id,
+ std::move(c1_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(c3_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c3_surface_id,
+ std::move(c3_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(3, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 3);
- aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data));
- EXPECT_EQ(4, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c2_surface_id,
+ std::move(c2_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 4);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(c2_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c2_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
- aggregator_.CallOnSurfaceWillDraw(c1_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c1_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(3, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 3);
- aggregator_.CallOnSurfaceWillDraw(c3_surface_id);
- EXPECT_EQ(4, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(c3_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 4);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(4, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 4);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(3, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 3);
region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 700, 700), region->rect);
- EXPECT_EQ(2, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 700, 700));
+ EXPECT_EQ(region->child_count, 2);
region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 500, 500), region->rect);
- EXPECT_EQ(1, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 500, 500));
+ EXPECT_EQ(region->child_count, 1);
region = &regions[3];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
- EXPECT_EQ(c3_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(100, 100, 300, 300), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
+ EXPECT_EQ(region->frame_sink_id, c3_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 300, 300));
+ EXPECT_EQ(region->child_count, 0);
}
// Missing / late child.
@@ -804,76 +1013,80 @@ TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) {
//
TEST_F(HitTestAggregatorTest, MissingChildFrame) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_div = mojom::HitTestRegion::New();
e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->surface_id = e_surface_id;
+ e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->surface_id = c_surface_id;
+ e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_data = mojom::HitTestRegionList::New();
- c_hit_test_data->surface_id = c_surface_id;
- c_hit_test_data->flags = mojom::kHitTestMine;
- c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+ auto c_hit_test_region_list = mojom::HitTestRegionList::New();
+ c_hit_test_region_list->flags = mojom::kHitTestMine;
+ c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order, but not the child.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(2, aggregator_.Count());
+ EXPECT_EQ(aggregator->Count(), 2);
- AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
AggregatedHitTestRegion* region = nullptr;
region = &regions[0];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
- EXPECT_EQ(1, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region->child_count, 1);
// Child would exist here but it was not included in the Display Frame.
region = &regions[1];
- EXPECT_EQ(mojom::kHitTestMine, region->flags);
- EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
- EXPECT_EQ(0, region->child_count);
+ EXPECT_EQ(region->flags, mojom::kHitTestMine);
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region->child_count, 0);
}
// Exceed limits to ensure that bounds and resize work.
@@ -898,34 +1111,36 @@ TEST_F(HitTestAggregatorTest, MissingChildFrame) {
//
TEST_F(HitTestAggregatorTest, ExceedLimits) {
- EXPECT_EQ(0, aggregator_.Count());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->Count(), 0);
- EXPECT_LT(aggregator_.GetHitTestRegionListSize(), 4096);
+ EXPECT_LT(aggregator->GetHitTestRegionListSize(), 4096);
SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
int next_surface_id = CreateAndSubmitHitTestRegionListWith8Children(1, 3);
int surface_count = next_surface_id - 1;
- EXPECT_EQ(surface_count, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), surface_count);
// Mark Surfaces as added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->Count(), 0);
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
for (int i = 1; i <= surface_count; i++) {
SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, i);
- aggregator_.CallOnSurfaceWillDraw(surface_id);
+ aggregator->CallOnSurfaceWillDraw(surface_id);
}
- EXPECT_EQ(surface_count, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->GetActiveCount(), surface_count);
// Aggregate and swap.
- aggregator_.Aggregate(display_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
+ aggregator->Aggregate(display_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
// Expect 4680 regions:
// 8 children 4 levels deep 8*8*8*8 is 4096
@@ -933,85 +1148,97 @@ TEST_F(HitTestAggregatorTest, ExceedLimits) {
// 1 root + 1
// -----
// 4681.
- EXPECT_EQ(4681, aggregator_.Count());
+ EXPECT_GE(aggregator->GetHitTestRegionListSize(), 4681);
+
+ EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
+ AggregatedHitTestRegion* regions = host_regions();
- EXPECT_GE(aggregator_.GetHitTestRegionListSize(), 4681);
+ uint32_t count = 0;
+ while (regions->child_count != kEndOfList) {
+ regions++;
+ count++;
+ }
+ EXPECT_EQ(count, 4681u);
}
TEST_F(HitTestAggregatorTest, ActiveRegionCount) {
- EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+ TestHitTestAggregator* aggregator = GetAggregator(kDisplayFrameSink);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 0);
SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
- auto e_hit_test_data = mojom::HitTestRegionList::New();
- e_hit_test_data->surface_id = e_surface_id;
- e_hit_test_data->flags = mojom::kHitTestMine;
- e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+ auto e_hit_test_region_list = mojom::HitTestRegionList::New();
+ e_hit_test_region_list->flags = mojom::kHitTestMine;
+ e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_div = mojom::HitTestRegion::New();
e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->surface_id = e_surface_id;
+ e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->surface_id = c_surface_id;
+ e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_data = mojom::HitTestRegionList::New();
- c_hit_test_data->surface_id = c_surface_id;
- c_hit_test_data->flags = mojom::kHitTestMine;
- c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+ auto c_hit_test_region_list = mojom::HitTestRegionList::New();
+ c_hit_test_region_list->flags = mojom::kHitTestMine;
+ c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
- EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 0);
// Submit in unexpected order.
- EXPECT_EQ(0, aggregator_.GetPendingCount());
+ EXPECT_EQ(aggregator->GetPendingCount(), 0);
- aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
- EXPECT_EQ(1, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(c_surface_id,
+ std::move(c_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 1);
- aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
- EXPECT_EQ(2, aggregator_.GetPendingCount());
+ aggregator->SubmitHitTestRegionList(e_surface_id,
+ std::move(e_hit_test_region_list));
+ EXPECT_EQ(aggregator->GetPendingCount(), 2);
- EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 0);
// Surfaces added to DisplayFrame in unexpected order.
- EXPECT_EQ(0, aggregator_.Count());
- EXPECT_EQ(0, aggregator_.GetActiveCount());
+ EXPECT_EQ(aggregator->Count(), 0);
+ EXPECT_EQ(aggregator->GetActiveCount(), 0);
- aggregator_.CallOnSurfaceWillDraw(e_surface_id);
- EXPECT_EQ(1, aggregator_.GetActiveCount());
- EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+ aggregator->CallOnSurfaceWillDraw(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 1);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 2);
- aggregator_.CallOnSurfaceWillDraw(c_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveCount());
- EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+ aggregator->CallOnSurfaceWillDraw(c_surface_id);
+ EXPECT_EQ(aggregator->GetActiveCount(), 2);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 2);
// Aggregate and swap.
- aggregator_.Aggregate(e_surface_id);
- EXPECT_EQ(0, aggregator_.Count());
- EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+ aggregator->Aggregate(e_surface_id);
+ EXPECT_EQ(aggregator->Count(), 0);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 2);
- aggregator_.Swap();
+ aggregator->Swap();
+ aggregator->SwapHandles();
- EXPECT_EQ(3, aggregator_.Count());
- EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+ EXPECT_EQ(aggregator->Count(), 3);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 2);
// Discard Surface and ensure active count goes down.
- aggregator_.CallOnSurfaceDiscarded(c_surface_id);
- EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+ aggregator->CallOnSurfaceDiscarded(c_surface_id);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 2);
- aggregator_.CallOnSurfaceDiscarded(e_surface_id);
- EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+ aggregator->CallOnSurfaceDiscarded(e_surface_id);
+ EXPECT_EQ(aggregator->GetActiveRegionCount(), 0);
}
} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/DEPS b/chromium/components/viz/service/surfaces/DEPS
new file mode 100644
index 00000000000..d2568d7dd11
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/DEPS
@@ -0,0 +1,12 @@
+include_rules = [
+ "+components/viz/common",
+ "+components/viz/service/display",
+ "+components/viz/service/frame_sinks",
+ "+mojo/public/cpp/bindings/struct_traits.h",
+]
+
+specific_include_rules = {
+ ".*_unittest\.cc": [
+ "+components/viz/service/frame_sinks",
+ ],
+}
diff --git a/chromium/components/viz/service/surfaces/direct_surface_reference_factory.cc b/chromium/components/viz/service/surfaces/direct_surface_reference_factory.cc
new file mode 100644
index 00000000000..1cde4a6b05c
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/direct_surface_reference_factory.cc
@@ -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.
+
+#include "components/viz/service/surfaces/direct_surface_reference_factory.h"
+
+#include <vector>
+
+#include "components/viz/service/surfaces/surface.h"
+
+namespace viz {
+
+DirectSurfaceReferenceFactory::DirectSurfaceReferenceFactory(
+ base::WeakPtr<SurfaceManager> manager)
+ : manager_(manager) {}
+
+DirectSurfaceReferenceFactory::~DirectSurfaceReferenceFactory() = default;
+void DirectSurfaceReferenceFactory::SatisfySequence(
+ const SurfaceSequence& sequence) const {
+ if (!manager_)
+ return;
+ manager_->SatisfySequence(sequence);
+}
+
+void DirectSurfaceReferenceFactory::RequireSequence(
+ const SurfaceId& surface_id,
+ const SurfaceSequence& sequence) const {
+ manager_->RequireSequence(surface_id, sequence);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/direct_surface_reference_factory.h b/chromium/components/viz/service/surfaces/direct_surface_reference_factory.h
new file mode 100644
index 00000000000..13485785828
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/direct_surface_reference_factory.h
@@ -0,0 +1,42 @@
+// 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_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
+
+#include "base/compiler_specific.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+class SurfaceManager;
+
+// The surface reference factory that interacts directly with SurfaceManager.
+// You probably don't need to instantiate this class directly.
+// Use SurfaceManager::reference_factory() instead.
+class VIZ_SERVICE_EXPORT DirectSurfaceReferenceFactory final
+ : public SequenceSurfaceReferenceFactory {
+ public:
+ explicit DirectSurfaceReferenceFactory(base::WeakPtr<SurfaceManager> manager);
+
+ private:
+ ~DirectSurfaceReferenceFactory() override;
+
+ // SequenceSurfaceReferenceFactory implementation:
+ void SatisfySequence(const SurfaceSequence& sequence) const override;
+ void RequireSequence(const SurfaceId& surface_id,
+ const SurfaceSequence& sequence) const override;
+
+ base::WeakPtr<SurfaceManager> manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectSurfaceReferenceFactory);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
diff --git a/chromium/components/viz/service/surfaces/surface.cc b/chromium/components/viz/service/surfaces/surface.cc
new file mode 100644
index 00000000000..526660193bb
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface.cc
@@ -0,0 +1,418 @@
+// 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/viz/service/surfaces/surface.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/common/surfaces/local_surface_id_allocator.h"
+#include "components/viz/service/surfaces/surface_client.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+Surface::Surface(const SurfaceInfo& surface_info,
+ SurfaceManager* surface_manager,
+ base::WeakPtr<SurfaceClient> surface_client,
+ BeginFrameSource* begin_frame_source,
+ bool needs_sync_tokens)
+ : surface_info_(surface_info),
+ surface_manager_(surface_manager),
+ surface_client_(std::move(surface_client)),
+ deadline_(begin_frame_source),
+ needs_sync_tokens_(needs_sync_tokens) {
+ deadline_.AddObserver(this);
+}
+
+Surface::~Surface() {
+ ClearCopyRequests();
+ surface_manager_->SurfaceDiscarded(this);
+
+ UnrefFrameResourcesAndRunDrawCallback(std::move(pending_frame_data_));
+ UnrefFrameResourcesAndRunDrawCallback(std::move(active_frame_data_));
+
+ deadline_.Cancel();
+ deadline_.RemoveObserver(this);
+}
+
+void Surface::SetPreviousFrameSurface(Surface* surface) {
+ DCHECK(surface && (HasActiveFrame() || HasPendingFrame()));
+ previous_frame_surface_id_ = surface->surface_id();
+ cc::CompositorFrame& frame = active_frame_data_ ? active_frame_data_->frame
+ : pending_frame_data_->frame;
+ surface->TakeLatencyInfo(&frame.metadata.latency_info);
+ surface->TakeLatencyInfoFromPendingFrame(&frame.metadata.latency_info);
+}
+
+void Surface::RefResources(const std::vector<TransferableResource>& resources) {
+ if (surface_client_)
+ surface_client_->RefResources(resources);
+}
+
+void Surface::UnrefResources(const std::vector<ReturnedResource>& resources) {
+ if (surface_client_)
+ surface_client_->UnrefResources(resources);
+}
+
+void Surface::RejectCompositorFramesToFallbackSurfaces() {
+ std::vector<FrameSinkId> frame_sink_ids_for_dependencies;
+ for (const SurfaceId& surface_id :
+ GetPendingFrame().metadata.activation_dependencies) {
+ frame_sink_ids_for_dependencies.push_back(surface_id.frame_sink_id());
+ }
+
+ for (const SurfaceId& surface_id :
+ GetPendingFrame().metadata.referenced_surfaces) {
+ // A surface ID in |referenced_surfaces| that has a corresponding surface
+ // ID in |activation_dependencies| with the same frame sink ID is said to
+ // be a fallback surface that can be used in place of the primary surface
+ // if the deadline passes before the dependency becomes available.
+ auto it = std::find(frame_sink_ids_for_dependencies.begin(),
+ frame_sink_ids_for_dependencies.end(),
+ surface_id.frame_sink_id());
+ bool is_fallback_surface = it != frame_sink_ids_for_dependencies.end();
+ if (!is_fallback_surface)
+ continue;
+
+ Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
+ // A misbehaving client may report a non-existent surface ID as a
+ // |referenced_surface|. In that case, |surface| would be nullptr, and
+ // there is nothing to do here.
+ if (surface)
+ surface->Close();
+ }
+}
+
+void Surface::Close() {
+ closed_ = true;
+}
+
+bool Surface::QueueFrame(cc::CompositorFrame frame,
+ uint64_t frame_index,
+ base::OnceClosure callback,
+ const WillDrawCallback& will_draw_callback) {
+ late_activation_dependencies_.clear();
+
+ if (frame.size_in_pixels() != surface_info_.size_in_pixels() ||
+ frame.device_scale_factor() != surface_info_.device_scale_factor()) {
+ TRACE_EVENT_INSTANT0("cc", "Surface invariants violation",
+ TRACE_EVENT_SCOPE_THREAD);
+ return false;
+ }
+
+ if (closed_) {
+ std::vector<ReturnedResource> resources =
+ TransferableResource::ReturnResources(frame.resource_list);
+ surface_client_->ReturnResources(resources);
+ std::move(callback).Run();
+ return true;
+ }
+
+ if (active_frame_data_ || pending_frame_data_)
+ previous_frame_surface_id_ = surface_id();
+
+ TakeLatencyInfoFromPendingFrame(&frame.metadata.latency_info);
+
+ base::Optional<FrameData> previous_pending_frame_data =
+ std::move(pending_frame_data_);
+ pending_frame_data_.reset();
+
+ UpdateActivationDependencies(frame);
+
+ // Receive and track the resources referenced from the cc::CompositorFrame
+ // regardless of whether it's pending or active.
+ surface_client_->ReceiveFromChild(frame.resource_list);
+
+ if (activation_dependencies_.empty()) {
+ // If there are no blockers, then immediately activate the frame.
+ ActivateFrame(FrameData(std::move(frame), frame_index, std::move(callback),
+ will_draw_callback));
+ } else {
+ pending_frame_data_ = FrameData(std::move(frame), frame_index,
+ std::move(callback), will_draw_callback);
+
+ RejectCompositorFramesToFallbackSurfaces();
+
+ // Ask the surface manager to inform |this| when its dependencies are
+ // resolved.
+ surface_manager_->RequestSurfaceResolution(this);
+ }
+
+ // Returns resources for the previous pending frame.
+ UnrefFrameResourcesAndRunDrawCallback(std::move(previous_pending_frame_data));
+
+ return true;
+}
+
+void Surface::RequestCopyOfOutput(
+ std::unique_ptr<CopyOutputRequest> copy_request) {
+ if (!active_frame_data_) {
+ copy_request->SendEmptyResult();
+ return;
+ }
+
+ std::vector<std::unique_ptr<CopyOutputRequest>>& copy_requests =
+ active_frame_data_->frame.render_pass_list.back()->copy_requests;
+
+ if (copy_request->has_source()) {
+ const base::UnguessableToken& source = copy_request->source();
+ // Remove existing CopyOutputRequests made on the Surface by the same
+ // source.
+ base::EraseIf(copy_requests,
+ [&source](const std::unique_ptr<CopyOutputRequest>& x) {
+ return x->has_source() && x->source() == source;
+ });
+ }
+ copy_requests.push_back(std::move(copy_request));
+}
+
+void Surface::NotifySurfaceIdAvailable(const SurfaceId& surface_id) {
+ auto it = activation_dependencies_.find(surface_id);
+ // This surface may no longer have blockers if the deadline has passed.
+ if (it == activation_dependencies_.end())
+ return;
+
+ activation_dependencies_.erase(it);
+
+ if (!activation_dependencies_.empty())
+ return;
+
+ // All blockers have been cleared. The surface can be activated now.
+ ActivatePendingFrame();
+}
+
+void Surface::ActivatePendingFrameForDeadline() {
+ if (!pending_frame_data_ ||
+ !pending_frame_data_->frame.metadata.can_activate_before_dependencies) {
+ return;
+ }
+
+ // If a frame is being activated because of a deadline, then clear its set
+ // of blockers.
+ late_activation_dependencies_ = std::move(activation_dependencies_);
+ activation_dependencies_.clear();
+ ActivatePendingFrame();
+}
+
+Surface::FrameData::FrameData(cc::CompositorFrame&& frame,
+ uint64_t frame_index,
+ base::OnceClosure draw_callback,
+ const WillDrawCallback& will_draw_callback)
+ : frame(std::move(frame)),
+ frame_index(frame_index),
+ draw_callback(std::move(draw_callback)),
+ will_draw_callback(will_draw_callback) {}
+
+Surface::FrameData::FrameData(FrameData&& other) = default;
+
+Surface::FrameData& Surface::FrameData::operator=(FrameData&& other) = default;
+
+Surface::FrameData::~FrameData() = default;
+
+void Surface::ActivatePendingFrame() {
+ DCHECK(pending_frame_data_);
+ FrameData frame_data = std::move(*pending_frame_data_);
+ pending_frame_data_.reset();
+ ActivateFrame(std::move(frame_data));
+}
+
+// A frame is activated if all its Surface ID dependences are active or a
+// deadline has hit and the frame was forcibly activated.
+void Surface::ActivateFrame(FrameData frame_data) {
+ deadline_.Cancel();
+
+ // Save root pass copy requests.
+ std::vector<std::unique_ptr<CopyOutputRequest>> old_copy_requests;
+ if (active_frame_data_) {
+ std::swap(old_copy_requests,
+ active_frame_data_->frame.render_pass_list.back()->copy_requests);
+ }
+
+ ClearCopyRequests();
+
+ TakeLatencyInfo(&frame_data.frame.metadata.latency_info);
+
+ base::Optional<FrameData> previous_frame_data = std::move(active_frame_data_);
+
+ active_frame_data_ = std::move(frame_data);
+
+ for (auto& copy_request : old_copy_requests)
+ RequestCopyOfOutput(std::move(copy_request));
+
+ UnrefFrameResourcesAndRunDrawCallback(std::move(previous_frame_data));
+
+ if (!seen_first_frame_activation_) {
+ seen_first_frame_activation_ = true;
+ surface_manager_->FirstSurfaceActivation(surface_info_);
+ }
+
+ if (surface_client_)
+ surface_client_->OnSurfaceActivated(this);
+
+ surface_manager_->SurfaceActivated(this);
+}
+
+void Surface::UpdateActivationDependencies(
+ const cc::CompositorFrame& current_frame) {
+ base::flat_set<SurfaceId> new_activation_dependencies;
+
+ for (const SurfaceId& surface_id :
+ current_frame.metadata.activation_dependencies) {
+ Surface* dependency = surface_manager_->GetSurfaceForId(surface_id);
+ // If a activation dependency does not have a corresponding active frame in
+ // the display compositor, then it blocks this frame.
+ if (!dependency || !dependency->HasActiveFrame())
+ new_activation_dependencies.insert(surface_id);
+ }
+
+ // If this Surface has a previous pending frame, then we must determine the
+ // changes in dependencies so that we can update the SurfaceDependencyTracker
+ // map.
+ base::flat_set<SurfaceId> added_dependencies;
+ base::flat_set<SurfaceId> removed_dependencies;
+ ComputeChangeInDependencies(activation_dependencies_,
+ new_activation_dependencies, &added_dependencies,
+ &removed_dependencies);
+
+ // If there is a change in the dependency set, then inform SurfaceManager.
+ if (!added_dependencies.empty() || !removed_dependencies.empty()) {
+ surface_manager_->SurfaceDependenciesChanged(this, added_dependencies,
+ removed_dependencies);
+ }
+
+ activation_dependencies_ = std::move(new_activation_dependencies);
+}
+
+void Surface::ComputeChangeInDependencies(
+ const base::flat_set<SurfaceId>& existing_dependencies,
+ const base::flat_set<SurfaceId>& new_dependencies,
+ base::flat_set<SurfaceId>* added_dependencies,
+ base::flat_set<SurfaceId>* removed_dependencies) {
+ for (const SurfaceId& surface_id : existing_dependencies) {
+ if (!new_dependencies.count(surface_id))
+ removed_dependencies->insert(surface_id);
+ }
+
+ for (const SurfaceId& surface_id : new_dependencies) {
+ if (!existing_dependencies.count(surface_id))
+ added_dependencies->insert(surface_id);
+ }
+}
+
+void Surface::TakeCopyOutputRequests(Surface::CopyRequestsMap* copy_requests) {
+ DCHECK(copy_requests->empty());
+ if (!active_frame_data_)
+ return;
+
+ for (const auto& render_pass : active_frame_data_->frame.render_pass_list) {
+ for (auto& request : render_pass->copy_requests) {
+ copy_requests->insert(
+ std::make_pair(render_pass->id, std::move(request)));
+ }
+ render_pass->copy_requests.clear();
+ }
+}
+
+const cc::CompositorFrame& Surface::GetActiveFrame() const {
+ DCHECK(active_frame_data_);
+ return active_frame_data_->frame;
+}
+
+const cc::CompositorFrame& Surface::GetPendingFrame() {
+ DCHECK(pending_frame_data_);
+ return pending_frame_data_->frame;
+}
+
+void Surface::TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info) {
+ if (!active_frame_data_)
+ return;
+ TakeLatencyInfoFromFrame(&active_frame_data_->frame, latency_info);
+}
+
+void Surface::RunDrawCallback() {
+ if (active_frame_data_ && !active_frame_data_->draw_callback.is_null())
+ std::move(active_frame_data_->draw_callback).Run();
+}
+
+void Surface::RunWillDrawCallback(const gfx::Rect& damage_rect) {
+ if (!active_frame_data_ || active_frame_data_->will_draw_callback.is_null())
+ return;
+
+ active_frame_data_->will_draw_callback.Run(surface_id().local_surface_id(),
+ damage_rect);
+}
+
+void Surface::AddDestructionDependency(SurfaceSequence sequence) {
+ destruction_dependencies_.push_back(sequence);
+}
+
+void Surface::SatisfyDestructionDependencies(
+ base::flat_set<SurfaceSequence>* sequences,
+ base::flat_set<FrameSinkId>* valid_frame_sink_ids) {
+ base::EraseIf(destruction_dependencies_,
+ [sequences, valid_frame_sink_ids](SurfaceSequence seq) {
+ return (!!sequences->erase(seq) ||
+ !valid_frame_sink_ids->count(seq.frame_sink_id));
+ });
+}
+
+void Surface::OnDeadline() {
+ ActivatePendingFrameForDeadline();
+}
+
+void Surface::UnrefFrameResourcesAndRunDrawCallback(
+ base::Optional<FrameData> frame_data) {
+ if (!frame_data || !surface_client_)
+ return;
+
+ std::vector<ReturnedResource> resources =
+ TransferableResource::ReturnResources(frame_data->frame.resource_list);
+ // No point in returning same sync token to sender.
+ for (auto& resource : resources)
+ resource.sync_token.Clear();
+ surface_client_->UnrefResources(resources);
+
+ if (!frame_data->draw_callback.is_null())
+ std::move(frame_data->draw_callback).Run();
+}
+
+void Surface::ClearCopyRequests() {
+ if (active_frame_data_) {
+ for (const auto& render_pass : active_frame_data_->frame.render_pass_list) {
+ for (const auto& copy_request : render_pass->copy_requests)
+ copy_request->SendEmptyResult();
+ }
+ }
+}
+
+void Surface::TakeLatencyInfoFromPendingFrame(
+ std::vector<ui::LatencyInfo>* latency_info) {
+ if (!pending_frame_data_)
+ return;
+ TakeLatencyInfoFromFrame(&pending_frame_data_->frame, latency_info);
+}
+
+// static
+void Surface::TakeLatencyInfoFromFrame(
+ cc::CompositorFrame* frame,
+ std::vector<ui::LatencyInfo>* latency_info) {
+ if (latency_info->empty()) {
+ frame->metadata.latency_info.swap(*latency_info);
+ return;
+ }
+ std::copy(frame->metadata.latency_info.begin(),
+ frame->metadata.latency_info.end(),
+ std::back_inserter(*latency_info));
+ frame->metadata.latency_info.clear();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface.h b/chromium/components/viz/service/surfaces/surface.h
new file mode 100644
index 00000000000..5544f2fa7b2
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface.h
@@ -0,0 +1,266 @@
+// 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_set>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "cc/output/compositor_frame.h"
+#include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
+#include "components/viz/service/surfaces/surface_dependency_deadline.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class CopyOutputRequest;
+}
+
+namespace ui {
+class LatencyInfo;
+}
+
+namespace viz {
+
+class SurfaceClient;
+class SurfaceManager;
+
+// A Surface is a representation of a sequence of CompositorFrames with a
+// common set of properties uniquely identified by a SurfaceId. In particular,
+// all CompositorFrames submitted to a single Surface share properties described
+// in SurfaceInfo: device scale factor and size. A Surface can hold up to two
+// CompositorFrames at a given time:
+//
+// Active frame: An active frame is a candidate for display. A
+// CompositorFrame is active if it has been explicitly marked
+// as active after a deadline has passed or all its
+// dependencies are active.
+//
+// Pending frame: A pending CompositorFrame cannot be displayed on screen. A
+// CompositorFrame is pending if it has unresolved
+// dependencies: surface Ids to which there are no active
+// CompositorFrames.
+//
+// This two stage mechanism for managing CompositorFrames from a client exists
+// to enable best-effort synchronization across clients. A surface subtree will
+// remain pending until all dependencies are resolved: all clients have
+// submitted CompositorFrames corresponding to a new property of the subtree
+// (e.g. a new size).
+//
+// Clients are assumed to be untrusted and so a client may not submit a
+// CompositorFrame to satisfy the dependency of the parent. Thus, by default, a
+// surface has an activation deadline associated with its dependencies. If the
+// deadline passes, then the CompositorFrame will activate despite missing
+// dependencies. The activated CompositorFrame can specify fallback behavior in
+// the event of missing dependencies at display time.
+class VIZ_SERVICE_EXPORT Surface final : public SurfaceDeadlineObserver {
+ public:
+ using WillDrawCallback =
+ base::RepeatingCallback<void(const LocalSurfaceId&, const gfx::Rect&)>;
+
+ Surface(const SurfaceInfo& surface_info,
+ SurfaceManager* surface_manager,
+ base::WeakPtr<SurfaceClient> surface_client,
+ BeginFrameSource* begin_frame_source,
+ bool needs_sync_tokens);
+ ~Surface();
+
+ const SurfaceId& surface_id() const { return surface_info_.id(); }
+ const SurfaceId& previous_frame_surface_id() const {
+ return previous_frame_surface_id_;
+ }
+
+ base::WeakPtr<SurfaceClient> client() { return surface_client_; }
+
+ bool has_deadline() const { return deadline_.has_deadline(); }
+ const SurfaceDependencyDeadline& deadline() const { return deadline_; }
+
+ bool InheritActivationDeadlineFrom(
+ const SurfaceDependencyDeadline& deadline) {
+ return deadline_.InheritFrom(deadline);
+ }
+
+ // Sets a deadline a number of frames ahead to active the currently pending
+ // CompositorFrame held by this surface.
+ void SetActivationDeadline(uint32_t number_of_frames_to_deadline) {
+ deadline_.Set(number_of_frames_to_deadline);
+ }
+
+ void SetPreviousFrameSurface(Surface* surface);
+
+ // Increments the reference count on resources specified by |resources|.
+ void RefResources(const std::vector<TransferableResource>& resources);
+
+ // Decrements the reference count on resources specified by |resources|.
+ void UnrefResources(const std::vector<ReturnedResource>& resources);
+
+ bool needs_sync_tokens() const { return needs_sync_tokens_; }
+
+ // Returns false if |frame| is invalid.
+ // |draw_callback| is called once to notify the client that the previously
+ // submitted cc::CompositorFrame is processed and that another frame can be
+ // there is visible damage.
+ // |will_draw_callback| is called when |surface| is scheduled for a draw and
+ // there is visible damage.
+ bool QueueFrame(cc::CompositorFrame frame,
+ uint64_t frame_index,
+ base::OnceClosure draw_callback,
+ const WillDrawCallback& will_draw_callback);
+ void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> copy_request);
+
+ // Notifies the Surface that a blocking SurfaceId now has an active
+ // frame.
+ void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
+
+ // Called if a deadline has been hit and this surface is not yet active but
+ // it's marked as respecting deadlines.
+ void ActivatePendingFrameForDeadline();
+
+ using CopyRequestsMap =
+ std::multimap<cc::RenderPassId, std::unique_ptr<CopyOutputRequest>>;
+
+ // Adds each CopyOutputRequest in the current frame to copy_requests. The
+ // caller takes ownership of them. |copy_requests| is keyed by cc::RenderPass
+ // ids.
+ void TakeCopyOutputRequests(CopyRequestsMap* copy_requests);
+
+ // Returns the most recent frame that is eligible to be rendered.
+ // You must check whether HasActiveFrame() returns true before calling this
+ // method.
+ const cc::CompositorFrame& GetActiveFrame() const;
+
+ // Returns the currently pending frame. You must check where HasPendingFrame()
+ // returns true before calling this method.
+ const cc::CompositorFrame& GetPendingFrame();
+
+ // Returns a number that increments by 1 every time a new frame is enqueued.
+ uint64_t GetActiveFrameIndex() const {
+ return active_frame_data_->frame_index;
+ }
+
+ void TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
+ void RunDrawCallback();
+ void RunWillDrawCallback(const gfx::Rect& damage_rect);
+
+ // Add a SurfaceSequence that must be satisfied before the Surface is
+ // destroyed.
+ void AddDestructionDependency(SurfaceSequence sequence);
+
+ // Satisfy all destruction dependencies that are contained in sequences, and
+ // remove them from sequences.
+ void SatisfyDestructionDependencies(
+ base::flat_set<SurfaceSequence>* sequences,
+ base::flat_set<FrameSinkId>* valid_id_namespaces);
+ size_t GetDestructionDependencyCount() const {
+ return destruction_dependencies_.size();
+ }
+
+ const std::vector<SurfaceId>* active_referenced_surfaces() const {
+ return active_frame_data_
+ ? &active_frame_data_->frame.metadata.referenced_surfaces
+ : nullptr;
+ }
+
+ // Returns the set of dependencies blocking this surface's pending frame
+ // that themselves have not yet activated.
+ const base::flat_set<SurfaceId>& activation_dependencies() const {
+ return activation_dependencies_;
+ }
+
+ // Returns the set of activation dependencies that have been ignored because
+ // the last cc::CompositorFrame was activated due to a deadline. Late
+ // dependencies activate immediately when they arrive.
+ const base::flat_set<SurfaceId>& late_activation_dependencies() const {
+ return late_activation_dependencies_;
+ }
+
+ bool HasActiveFrame() const { return active_frame_data_.has_value(); }
+ bool HasPendingFrame() const { return pending_frame_data_.has_value(); }
+ bool HasUndrawnActiveFrame() const {
+ return HasActiveFrame() && active_frame_data_->draw_callback;
+ }
+
+ // SurfaceDeadlineObserver implementation:
+ void OnDeadline() override;
+
+ private:
+ struct FrameData {
+ FrameData(cc::CompositorFrame&& frame,
+ uint64_t frame_index,
+ base::OnceClosure draw_callback,
+ const WillDrawCallback& will_draw_callback);
+ FrameData(FrameData&& other);
+ ~FrameData();
+ FrameData& operator=(FrameData&& other);
+ cc::CompositorFrame frame;
+ uint64_t frame_index;
+ base::OnceClosure draw_callback;
+ WillDrawCallback will_draw_callback;
+ };
+
+ // Rejects CompositorFrames submitted to surfaces referenced from this
+ // cc::CompositorFrame as fallbacks. This saves some CPU cycles to allow
+ // children to catch up to the parent.
+ void RejectCompositorFramesToFallbackSurfaces();
+
+ // Called to prevent additional CompositorFrames from being accepted into this
+ // surface. Once a Surface is closed, it cannot accept CompositorFrames again.
+ void Close();
+
+ void ActivatePendingFrame();
+ // Called when all of the surface's dependencies have been resolved.
+ void ActivateFrame(FrameData frame_data);
+ void UpdateActivationDependencies(const cc::CompositorFrame& current_frame);
+ void ComputeChangeInDependencies(
+ const base::flat_set<SurfaceId>& existing_dependencies,
+ const base::flat_set<SurfaceId>& new_dependencies,
+ base::flat_set<SurfaceId>* added_dependencies,
+ base::flat_set<SurfaceId>* removed_dependencies);
+
+ void UnrefFrameResourcesAndRunDrawCallback(
+ base::Optional<FrameData> frame_data);
+ void ClearCopyRequests();
+
+ void TakeLatencyInfoFromPendingFrame(
+ std::vector<ui::LatencyInfo>* latency_info);
+ static void TakeLatencyInfoFromFrame(
+ cc::CompositorFrame* frame,
+ std::vector<ui::LatencyInfo>* latency_info);
+
+ const SurfaceInfo surface_info_;
+ SurfaceId previous_frame_surface_id_;
+ SurfaceManager* const surface_manager_;
+ base::WeakPtr<SurfaceClient> surface_client_;
+ SurfaceDependencyDeadline deadline_;
+
+ base::Optional<FrameData> pending_frame_data_;
+ base::Optional<FrameData> active_frame_data_;
+ bool closed_ = false;
+ bool seen_first_frame_activation_ = false;
+ const bool needs_sync_tokens_;
+ std::vector<SurfaceSequence> destruction_dependencies_;
+
+ base::flat_set<SurfaceId> activation_dependencies_;
+ base::flat_set<SurfaceId> late_activation_dependencies_;
+
+ DISALLOW_COPY_AND_ASSIGN(Surface);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_
diff --git a/chromium/components/viz/service/surfaces/surface_client.h b/chromium/components/viz/service/surfaces/surface_client.h
new file mode 100644
index 00000000000..599564f5c25
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_client.h
@@ -0,0 +1,55 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_CLIENT_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_CLIENT_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace cc {
+struct ReturnedResource;
+struct TransferableResource;
+} // namespace cc
+
+namespace viz {
+
+class Surface;
+
+class VIZ_SERVICE_EXPORT SurfaceClient {
+ public:
+ SurfaceClient() = default;
+
+ virtual ~SurfaceClient() = default;
+
+ // Called when |surface| has a new CompositorFrame available for display.
+ virtual void OnSurfaceActivated(Surface* surface) = 0;
+
+ // Increments the reference count on resources specified by |resources|.
+ virtual void RefResources(
+ const std::vector<TransferableResource>& resources) = 0;
+
+ // Decrements the reference count on resources specified by |resources|.
+ virtual void UnrefResources(
+ const std::vector<ReturnedResource>& resources) = 0;
+
+ // ReturnResources gets called when the display compositor is done using the
+ // resources so that the client can use them.
+ virtual void ReturnResources(
+ const std::vector<ReturnedResource>& resources) = 0;
+
+ // Increments the reference count of resources received from a child
+ // compositor.
+ virtual void ReceiveFromChild(
+ const std::vector<TransferableResource>& resources) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SurfaceClient);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_CLIENT_H_
diff --git a/chromium/components/viz/service/surfaces/surface_deadline_observer.h b/chromium/components/viz/service/surfaces/surface_deadline_observer.h
new file mode 100644
index 00000000000..5f8982d972a
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_deadline_observer.h
@@ -0,0 +1,18 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_DEADLINE_OBSERVER_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEADLINE_OBSERVER_H_
+
+namespace viz {
+
+class SurfaceDeadlineObserver {
+ public:
+ // Called when a deadline passes for a set of dependencies.
+ virtual void OnDeadline() = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEADLINE_OBSERVER_H_
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
new file mode 100644
index 00000000000..c22d77db495
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -0,0 +1,77 @@
+// 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/viz/service/surfaces/surface_dependency_deadline.h"
+
+namespace viz {
+
+SurfaceDependencyDeadline::SurfaceDependencyDeadline(
+ BeginFrameSource* begin_frame_source)
+ : begin_frame_source_(begin_frame_source) {
+ DCHECK(begin_frame_source_);
+}
+
+SurfaceDependencyDeadline::~SurfaceDependencyDeadline() {
+ // The deadline must be canceled before destruction.
+ DCHECK(!number_of_frames_to_deadline_);
+}
+
+void SurfaceDependencyDeadline::Set(uint32_t number_of_frames_to_deadline) {
+ DCHECK_GT(number_of_frames_to_deadline, 0u);
+ DCHECK(!number_of_frames_to_deadline_);
+ number_of_frames_to_deadline_ = number_of_frames_to_deadline;
+ begin_frame_source_->AddObserver(this);
+}
+
+void SurfaceDependencyDeadline::Cancel() {
+ if (!number_of_frames_to_deadline_)
+ return;
+ begin_frame_source_->RemoveObserver(this);
+ number_of_frames_to_deadline_.reset();
+}
+
+bool SurfaceDependencyDeadline::InheritFrom(
+ const SurfaceDependencyDeadline& other) {
+ if (*this == other)
+ return false;
+
+ Cancel();
+ last_begin_frame_args_ = other.last_begin_frame_args_;
+ begin_frame_source_ = other.begin_frame_source_;
+ number_of_frames_to_deadline_ = other.number_of_frames_to_deadline_;
+ if (number_of_frames_to_deadline_)
+ begin_frame_source_->AddObserver(this);
+ return true;
+}
+
+bool SurfaceDependencyDeadline::operator==(
+ const SurfaceDependencyDeadline& other) {
+ return begin_frame_source_ == other.begin_frame_source_ &&
+ number_of_frames_to_deadline_ == other.number_of_frames_to_deadline_;
+}
+
+// BeginFrameObserver implementation.
+void SurfaceDependencyDeadline::OnBeginFrame(const BeginFrameArgs& args) {
+ last_begin_frame_args_ = args;
+ // OnBeginFrame might get called immediately after cancellation if some other
+ // deadline triggered this deadline to be canceled.
+ if (!number_of_frames_to_deadline_ || args.type == BeginFrameArgs::MISSED)
+ return;
+
+ if (--(*number_of_frames_to_deadline_) > 0)
+ return;
+
+ Cancel();
+ for (auto& observer : observer_list_)
+ observer.OnDeadline();
+}
+
+const BeginFrameArgs& SurfaceDependencyDeadline::LastUsedBeginFrameArgs()
+ const {
+ return last_begin_frame_args_;
+}
+
+void SurfaceDependencyDeadline::OnBeginFrameSourcePausedChanged(bool paused) {}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.h b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h
new file mode 100644
index 00000000000..f8dfb405ac6
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h
@@ -0,0 +1,60 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
+
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+
+#include "components/viz/service/surfaces/surface_deadline_observer.h"
+
+namespace viz {
+
+class SurfaceDependencyDeadline : public BeginFrameObserver {
+ public:
+ explicit SurfaceDependencyDeadline(BeginFrameSource* begin_frame_source);
+ ~SurfaceDependencyDeadline() override;
+
+ void Set(uint32_t number_of_frames_to_deadline);
+ void Cancel();
+
+ void AddObserver(SurfaceDeadlineObserver* obs) {
+ observer_list_.AddObserver(obs);
+ }
+
+ void RemoveObserver(SurfaceDeadlineObserver* obs) {
+ observer_list_.RemoveObserver(obs);
+ }
+
+ bool has_deadline() const {
+ return number_of_frames_to_deadline_.has_value();
+ }
+
+ // Takes on the same BeginFrameSource and deadline as |other|. Returns
+ // false if they're already the same, and true otherwise.
+ bool InheritFrom(const SurfaceDependencyDeadline& other);
+
+ bool operator==(const SurfaceDependencyDeadline& other);
+ bool operator!=(const SurfaceDependencyDeadline& other) {
+ return !(*this == other);
+ }
+
+ // BeginFrameObserver implementation.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override;
+
+ private:
+ base::ObserverList<SurfaceDeadlineObserver> observer_list_;
+ BeginFrameSource* begin_frame_source_ = nullptr;
+ base::Optional<uint32_t> number_of_frames_to_deadline_;
+
+ BeginFrameArgs last_begin_frame_args_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceDependencyDeadline);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_tracker.cc b/chromium/components/viz/service/surfaces/surface_dependency_tracker.cc
new file mode 100644
index 00000000000..e07b22e44ee
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_dependency_tracker.cc
@@ -0,0 +1,205 @@
+// 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/viz/service/surfaces/surface_dependency_tracker.h"
+
+#include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+
+namespace viz {
+
+namespace {
+constexpr uint32_t kDefaultNumberOfFramesToDeadline = 4;
+}
+
+SurfaceDependencyTracker::SurfaceDependencyTracker(
+ SurfaceManager* surface_manager)
+ : surface_manager_(surface_manager) {}
+
+SurfaceDependencyTracker::~SurfaceDependencyTracker() = default;
+
+void SurfaceDependencyTracker::RequestSurfaceResolution(Surface* surface) {
+ DCHECK(surface->HasPendingFrame());
+
+ const cc::CompositorFrame& pending_frame = surface->GetPendingFrame();
+
+ if (IsSurfaceLate(surface)) {
+ ActivateLateSurfaceSubtree(surface);
+ return;
+ }
+
+ // Activation dependencies that aren't currently known to the surface manager
+ // or do not have an active cc::CompositorFrame block this frame.
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
+ Surface* dependency = surface_manager_->GetSurfaceForId(surface_id);
+ if (!dependency || !dependency->HasActiveFrame()) {
+ blocked_surfaces_from_dependency_[surface_id].insert(
+ surface->surface_id());
+ }
+ }
+
+ blocked_surfaces_by_id_.insert(surface->surface_id());
+
+ UpdateSurfaceDeadline(surface);
+}
+
+void SurfaceDependencyTracker::OnSurfaceActivated(Surface* surface) {
+ if (!surface->late_activation_dependencies().empty())
+ surfaces_with_missing_dependencies_.insert(surface->surface_id());
+ else
+ surfaces_with_missing_dependencies_.erase(surface->surface_id());
+ blocked_surfaces_by_id_.erase(surface->surface_id());
+ NotifySurfaceIdAvailable(surface->surface_id());
+}
+
+void SurfaceDependencyTracker::OnSurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies) {
+ // Update the |blocked_surfaces_from_dependency_| map with the changes in
+ // dependencies.
+ for (const SurfaceId& surface_id : added_dependencies)
+ blocked_surfaces_from_dependency_[surface_id].insert(surface->surface_id());
+
+ for (const SurfaceId& surface_id : removed_dependencies) {
+ auto it = blocked_surfaces_from_dependency_.find(surface_id);
+ it->second.erase(surface->surface_id());
+ if (it->second.empty())
+ blocked_surfaces_from_dependency_.erase(it);
+ }
+}
+
+void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) {
+ surfaces_with_missing_dependencies_.erase(surface->surface_id());
+
+ // If the surface being destroyed doesn't have a pending frame then we have
+ // nothing to do here.
+ if (!surface->HasPendingFrame())
+ return;
+
+ const cc::CompositorFrame& pending_frame = surface->GetPendingFrame();
+
+ DCHECK(!pending_frame.metadata.activation_dependencies.empty());
+
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
+ auto it = blocked_surfaces_from_dependency_.find(surface_id);
+ if (it == blocked_surfaces_from_dependency_.end())
+ continue;
+
+ auto& blocked_surface_ids = it->second;
+ auto blocked_surface_ids_it =
+ blocked_surface_ids.find(surface->surface_id());
+ if (blocked_surface_ids_it != blocked_surface_ids.end()) {
+ blocked_surface_ids.erase(surface->surface_id());
+ if (blocked_surface_ids.empty())
+ blocked_surfaces_from_dependency_.erase(surface_id);
+ }
+ }
+
+ blocked_surfaces_by_id_.erase(surface->surface_id());
+
+ // Pretend that the discarded surface's SurfaceId is now available to
+ // unblock dependencies because we now know the surface will never activate.
+ NotifySurfaceIdAvailable(surface->surface_id());
+}
+
+void SurfaceDependencyTracker::ActivateLateSurfaceSubtree(Surface* surface) {
+ DCHECK(surface->HasPendingFrame());
+
+ const cc::CompositorFrame& pending_frame = surface->GetPendingFrame();
+
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
+ Surface* dependency = surface_manager_->GetSurfaceForId(surface_id);
+ if (dependency && dependency->HasPendingFrame())
+ ActivateLateSurfaceSubtree(dependency);
+ }
+
+ surface->ActivatePendingFrameForDeadline();
+}
+
+void SurfaceDependencyTracker::UpdateSurfaceDeadline(Surface* surface) {
+ DCHECK(surface->HasPendingFrame());
+
+ const cc::CompositorFrame& pending_frame = surface->GetPendingFrame();
+
+ // Determine an activation deadline for the pending cc::CompositorFrame.
+ bool needs_deadline = pending_frame.metadata.can_activate_before_dependencies;
+ if (!needs_deadline)
+ return;
+
+ bool deadline_changed = false;
+
+ // Inherit the deadline from the first parent blocked on this surface.
+ auto it = blocked_surfaces_from_dependency_.find(surface->surface_id());
+ if (it != blocked_surfaces_from_dependency_.end()) {
+ const base::flat_set<SurfaceId>& dependent_parent_ids = it->second;
+ for (const SurfaceId& parent_id : dependent_parent_ids) {
+ Surface* parent = surface_manager_->GetSurfaceForId(parent_id);
+ if (parent && parent->has_deadline()) {
+ deadline_changed =
+ surface->InheritActivationDeadlineFrom(parent->deadline());
+ break;
+ }
+ }
+ }
+ // If there are no CompositorFrames currently blocked on this surface, then
+ // set a default deadline for this surface.
+ if (!surface->has_deadline()) {
+ surface->SetActivationDeadline(kDefaultNumberOfFramesToDeadline);
+ deadline_changed = true;
+ }
+
+ if (!deadline_changed)
+ return;
+
+ // Recursively propagate the newly set deadline to children.
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
+ Surface* dependency = surface_manager_->GetSurfaceForId(surface_id);
+ if (dependency && dependency->HasPendingFrame())
+ UpdateSurfaceDeadline(dependency);
+ }
+}
+
+bool SurfaceDependencyTracker::IsSurfaceLate(Surface* surface) {
+ for (const SurfaceId& surface_id : surfaces_with_missing_dependencies_) {
+ Surface* activated_surface = surface_manager_->GetSurfaceForId(surface_id);
+ DCHECK(activated_surface->HasActiveFrame());
+ if (activated_surface->late_activation_dependencies().count(
+ surface->surface_id())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SurfaceDependencyTracker::NotifySurfaceIdAvailable(
+ const SurfaceId& surface_id) {
+ auto it = blocked_surfaces_from_dependency_.find(surface_id);
+ if (it == blocked_surfaces_from_dependency_.end())
+ return;
+
+ // Unblock surfaces that depend on this |surface_id|.
+ base::flat_set<SurfaceId> blocked_surfaces_by_id(it->second);
+ blocked_surfaces_from_dependency_.erase(it);
+
+ // Tell each surface about the availability of its blocker.
+ for (const SurfaceId& blocked_surface_by_id : blocked_surfaces_by_id) {
+ Surface* blocked_surface =
+ surface_manager_->GetSurfaceForId(blocked_surface_by_id);
+ if (!blocked_surface) {
+ // A blocked surface may have been garbage collected during dependency
+ // resolution.
+ DCHECK(!blocked_surfaces_by_id_.count(blocked_surface_by_id));
+ continue;
+ }
+ blocked_surface->NotifySurfaceIdAvailable(surface_id);
+ }
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_tracker.h b/chromium/components/viz/service/surfaces/surface_dependency_tracker.h
new file mode 100644
index 00000000000..8f7a03243d3
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_dependency_tracker.h
@@ -0,0 +1,81 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_TRACKER_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_TRACKER_H_
+
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+class SurfaceManager;
+
+// SurfaceDependencyTracker tracks unresolved dependencies blocking
+// CompositorFrames from activating. This class maintains a map from
+// a dependent surface ID to a set of Surfaces that have CompositorFrames
+// blocked on that surface ID. SurfaceDependencyTracker observes when
+// dependent frames activate, and informs blocked surfaces.
+//
+// When a blocking cc::CompositorFrame is first submitted,
+// SurfaceDependencyTracker will begin listening for BeginFrames, setting a
+// deadline some number of BeginFrames in the future. If there are unresolved
+// dependencies when the deadline hits, then SurfaceDependencyTracker will clear
+// then and activate all pending CompositorFrames. Once there are no more
+// remaining pending frames, then SurfaceDependencyTracker will stop observing
+// BeginFrames.
+class VIZ_SERVICE_EXPORT SurfaceDependencyTracker {
+ public:
+ explicit SurfaceDependencyTracker(SurfaceManager* surface_manager);
+ ~SurfaceDependencyTracker();
+
+ // Called when |surface| has a pending cc::CompositorFrame and it wishes to be
+ // informed when that surface's dependencies are resolved.
+ void RequestSurfaceResolution(Surface* surface);
+
+ void OnSurfaceActivated(Surface* surface);
+ void OnSurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies);
+ void OnSurfaceDiscarded(Surface* surface);
+
+ private:
+ // If |surface| has a dependent embedder frame, then it inherits the parent's
+ // deadline and propagates that deadline to children.
+ void UpdateSurfaceDeadline(Surface* surface);
+
+ // Activates this |surface| and its entire dependency tree.
+ void ActivateLateSurfaceSubtree(Surface* surface);
+
+ // Indicates whether |surface| is late. A surface is late if it hasn't had its
+ // first activation before a embedder is forced to activate its own
+ // cc::CompositorFrame. A surface may no longer be considered late if the set
+ // of activation dependencies for dependent surfaces change.
+ bool IsSurfaceLate(Surface* surface);
+
+ // Informs all Surfaces with pending frames blocked on the provided
+ // |surface_id| that there is now an active frame available in Surface
+ // corresponding to |surface_id|.
+ void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
+
+ SurfaceManager* const surface_manager_;
+
+ // A map from a SurfaceId to the set of Surfaces blocked on that SurfaceId.
+ std::unordered_map<SurfaceId, base::flat_set<SurfaceId>, SurfaceIdHash>
+ blocked_surfaces_from_dependency_;
+
+ // The set of SurfaceIds corresponding that are known to have blockers.
+ base::flat_set<SurfaceId> blocked_surfaces_by_id_;
+
+ // The set of SurfaceIds corresponding to Surfaces that have active
+ // CompositorFrames with missing dependencies.
+ base::flat_set<SurfaceId> surfaces_with_missing_dependencies_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceDependencyTracker);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_DEPENDENCY_TRACKER_H_
diff --git a/chromium/components/viz/service/surfaces/surface_hittest.cc b/chromium/components/viz/service/surfaces/surface_hittest.cc
new file mode 100644
index 00000000000..e107af48f54
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_hittest.cc
@@ -0,0 +1,300 @@
+// 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/viz/service/surfaces/surface_hittest.h"
+
+#include "cc/output/compositor_frame.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_hittest_delegate.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/transform.h"
+
+namespace viz {
+
+SurfaceHittest::SurfaceHittest(SurfaceHittestDelegate* delegate,
+ SurfaceManager* manager)
+ : delegate_(delegate), manager_(manager) {}
+
+SurfaceHittest::~SurfaceHittest() {}
+
+SurfaceId SurfaceHittest::GetTargetSurfaceAtPoint(
+ const SurfaceId& root_surface_id,
+ const gfx::Point& point,
+ gfx::Transform* transform) {
+ SurfaceId out_surface_id = root_surface_id;
+
+ // Reset the output transform to identity.
+ if (transform)
+ *transform = gfx::Transform();
+
+ std::set<const cc::RenderPass*> referenced_passes;
+ GetTargetSurfaceAtPointInternal(root_surface_id, 0, point, &referenced_passes,
+ &out_surface_id, transform);
+
+ return out_surface_id;
+}
+
+bool SurfaceHittest::GetTransformToTargetSurface(
+ const SurfaceId& root_surface_id,
+ const SurfaceId& target_surface_id,
+ gfx::Transform* transform) {
+ // Reset the output transform to identity.
+ if (transform)
+ *transform = gfx::Transform();
+
+ std::set<const cc::RenderPass*> referenced_passes;
+ return GetTransformToTargetSurfaceInternal(root_surface_id, target_surface_id,
+ 0, &referenced_passes, transform);
+}
+
+bool SurfaceHittest::TransformPointToTargetSurface(
+ const SurfaceId& original_surface_id,
+ const SurfaceId& target_surface_id,
+ gfx::Point* point) {
+ gfx::Transform transform;
+ // Two possibilities need to be considered: original_surface_id can be
+ // embedded in target_surface_id, or vice versa.
+ if (GetTransformToTargetSurface(target_surface_id, original_surface_id,
+ &transform)) {
+ if (transform.GetInverse(&transform))
+ transform.TransformPoint(point);
+ else
+ return false;
+ } else if (GetTransformToTargetSurface(original_surface_id, target_surface_id,
+ &transform)) {
+ // No need to invert the transform matrix in this case.
+ transform.TransformPoint(point);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool SurfaceHittest::GetTargetSurfaceAtPointInternal(
+ const SurfaceId& surface_id,
+ cc::RenderPassId render_pass_id,
+ const gfx::Point& point_in_root_target,
+ std::set<const cc::RenderPass*>* referenced_passes,
+ SurfaceId* out_surface_id,
+ gfx::Transform* out_transform) {
+ const cc::RenderPass* render_pass =
+ GetRenderPassForSurfaceById(surface_id, render_pass_id);
+ if (!render_pass)
+ return false;
+
+ // To avoid an infinite recursion, we need to skip the cc::RenderPass if it's
+ // already been referenced.
+ if (referenced_passes->find(render_pass) != referenced_passes->end())
+ return false;
+
+ referenced_passes->insert(render_pass);
+
+ // The |transform_to_root_target| matrix cannot be inverted if it has a
+ // z-scale of 0 or due to floating point errors.
+ gfx::Transform transform_from_root_target;
+ if (!render_pass->transform_to_root_target.GetInverse(
+ &transform_from_root_target)) {
+ return false;
+ }
+
+ gfx::Point point_in_render_pass_space(point_in_root_target);
+ transform_from_root_target.TransformPoint(&point_in_render_pass_space);
+
+ for (const cc::DrawQuad* quad : render_pass->quad_list) {
+ gfx::Transform target_to_quad_transform;
+ gfx::Point point_in_quad_space;
+ if (!PointInQuad(quad, point_in_render_pass_space,
+ &target_to_quad_transform, &point_in_quad_space)) {
+ continue;
+ }
+
+ if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+ // We've hit a cc::SurfaceDrawQuad, we need to recurse into this
+ // Surface.
+ const cc::SurfaceDrawQuad* surface_quad =
+ cc::SurfaceDrawQuad::MaterialCast(quad);
+
+ if (delegate_ &&
+ delegate_->RejectHitTarget(surface_quad, point_in_quad_space)) {
+ continue;
+ }
+
+ gfx::Transform transform_to_child_space;
+ if (GetTargetSurfaceAtPointInternal(
+ surface_quad->surface_id, 0, point_in_quad_space,
+ referenced_passes, out_surface_id, &transform_to_child_space)) {
+ *out_transform = transform_to_child_space * target_to_quad_transform *
+ transform_from_root_target;
+ return true;
+ } else if (delegate_ && delegate_->AcceptHitTarget(surface_quad,
+ point_in_quad_space)) {
+ *out_surface_id = surface_quad->surface_id;
+ *out_transform = transform_to_child_space * target_to_quad_transform *
+ transform_from_root_target;
+ return true;
+ }
+
+ continue;
+ }
+
+ if (quad->material == cc::DrawQuad::RENDER_PASS) {
+ // We've hit a cc::RenderPassDrawQuad, we need to recurse into this
+ // cc::RenderPass.
+ const cc::RenderPassDrawQuad* render_quad =
+ cc::RenderPassDrawQuad::MaterialCast(quad);
+
+ gfx::Transform transform_to_child_space;
+ if (GetTargetSurfaceAtPointInternal(
+ surface_id, render_quad->render_pass_id, point_in_root_target,
+ referenced_passes, out_surface_id, &transform_to_child_space)) {
+ *out_transform = transform_to_child_space;
+ return true;
+ }
+
+ continue;
+ }
+
+ // We've hit a different type of quad in the current Surface. There's no
+ // need to iterate anymore, this is the quad that receives the event.
+ *out_surface_id = surface_id;
+ return true;
+ }
+
+ // No quads were found beneath the provided |point|.
+ return false;
+}
+
+bool SurfaceHittest::GetTransformToTargetSurfaceInternal(
+ const SurfaceId& root_surface_id,
+ const SurfaceId& target_surface_id,
+ cc::RenderPassId render_pass_id,
+ std::set<const cc::RenderPass*>* referenced_passes,
+ gfx::Transform* out_transform) {
+ if (root_surface_id == target_surface_id) {
+ *out_transform = gfx::Transform();
+ return true;
+ }
+
+ const cc::RenderPass* render_pass =
+ GetRenderPassForSurfaceById(root_surface_id, render_pass_id);
+ if (!render_pass)
+ return false;
+
+ // To avoid an infinite recursion, we need to skip the cc::RenderPass if it's
+ // already been referenced.
+ if (referenced_passes->find(render_pass) != referenced_passes->end())
+ return false;
+
+ referenced_passes->insert(render_pass);
+
+ // The |transform_to_root_target| matrix cannot be inverted if it has a
+ // z-scale of 0 or due to floating point errors.
+ gfx::Transform transform_from_root_target;
+ if (!render_pass->transform_to_root_target.GetInverse(
+ &transform_from_root_target)) {
+ return false;
+ }
+
+ for (const cc::DrawQuad* quad : render_pass->quad_list) {
+ if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+ gfx::Transform target_to_quad_transform;
+ if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
+ &target_to_quad_transform)) {
+ return false;
+ }
+
+ const cc::SurfaceDrawQuad* surface_quad =
+ cc::SurfaceDrawQuad::MaterialCast(quad);
+ if (surface_quad->surface_id == target_surface_id) {
+ *out_transform = target_to_quad_transform * transform_from_root_target;
+ return true;
+ }
+
+ // This isn't the target surface. Let's recurse deeper to see if we can
+ // find the |target_surface_id| there.
+ gfx::Transform transform_to_child_space;
+ if (GetTransformToTargetSurfaceInternal(
+ surface_quad->surface_id, target_surface_id, 0, referenced_passes,
+ &transform_to_child_space)) {
+ *out_transform = transform_to_child_space * target_to_quad_transform *
+ transform_from_root_target;
+ return true;
+ }
+ continue;
+ }
+
+ if (quad->material == cc::DrawQuad::RENDER_PASS) {
+ // We've hit a cc::RenderPassDrawQuad, we need to recurse into this
+ // cc::RenderPass.
+ const cc::RenderPassDrawQuad* render_quad =
+ cc::RenderPassDrawQuad::MaterialCast(quad);
+
+ gfx::Transform transform_to_child_space;
+ if (GetTransformToTargetSurfaceInternal(
+ root_surface_id, target_surface_id, render_quad->render_pass_id,
+ referenced_passes, &transform_to_child_space)) {
+ *out_transform = transform_to_child_space;
+ return true;
+ }
+
+ continue;
+ }
+ }
+
+ // The target surface was not found.
+ return false;
+}
+
+const cc::RenderPass* SurfaceHittest::GetRenderPassForSurfaceById(
+ const SurfaceId& surface_id,
+ cc::RenderPassId render_pass_id) {
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
+ if (!surface)
+ return nullptr;
+ if (!surface->HasActiveFrame())
+ return nullptr;
+ const cc::CompositorFrame& surface_frame = surface->GetActiveFrame();
+
+ if (!render_pass_id)
+ return surface_frame.render_pass_list.back().get();
+
+ for (const auto& render_pass : surface_frame.render_pass_list) {
+ if (render_pass->id == render_pass_id)
+ return render_pass.get();
+ }
+
+ return nullptr;
+}
+
+bool SurfaceHittest::PointInQuad(const cc::DrawQuad* quad,
+ const gfx::Point& point_in_render_pass_space,
+ gfx::Transform* target_to_quad_transform,
+ gfx::Point* point_in_quad_space) {
+ // First we test against the clip_rect. The clip_rect is in target space, so
+ // we can test the point directly.
+ if (quad->shared_quad_state->is_clipped &&
+ !quad->shared_quad_state->clip_rect.Contains(
+ point_in_render_pass_space)) {
+ return false;
+ }
+
+ // We now transform the point to content space and test if it hits the
+ // rect.
+ if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
+ target_to_quad_transform)) {
+ return false;
+ }
+
+ *point_in_quad_space = point_in_render_pass_space;
+ target_to_quad_transform->TransformPoint(point_in_quad_space);
+
+ return quad->rect.Contains(*point_in_quad_space);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_hittest.h b/chromium/components/viz/service/surfaces/surface_hittest.h
new file mode 100644
index 00000000000..41b01c39246
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_hittest.h
@@ -0,0 +1,87 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_H_
+
+#include <set>
+
+#include "cc/quads/render_pass.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace gfx {
+class Point;
+class Transform;
+} // namespace gfx
+
+namespace cc {
+class DrawQuad;
+class RenderPass;
+} // namespace cc
+
+namespace viz {
+
+class SurfaceHittestDelegate;
+class SurfaceManager;
+
+// Performs a hittest in surface quads.
+class VIZ_SERVICE_EXPORT SurfaceHittest {
+ public:
+ SurfaceHittest(SurfaceHittestDelegate* delegate, SurfaceManager* manager);
+ ~SurfaceHittest();
+
+ // Returns the target surface that falls underneath the provided |point|.
+ // Also returns the |transform| to convert the |point| to the target surface's
+ // space.
+ SurfaceId GetTargetSurfaceAtPoint(const SurfaceId& root_surface_id,
+ const gfx::Point& point,
+ gfx::Transform* transform);
+
+ // Returns whether the target surface falls inside the provide root surface.
+ // Returns the |transform| to convert points from the root surface coordinate
+ // space to the target surface coordinate space.
+ bool GetTransformToTargetSurface(const SurfaceId& root_surface_id,
+ const SurfaceId& target_surface_id,
+ gfx::Transform* transform);
+
+ // Attempts to transform a point from the coordinate space of one surface to
+ // that of another, where one is surface is embedded within the other.
+ // Returns true if the transform is successfully applied, and false if
+ // neither surface is contained with the other.
+ bool TransformPointToTargetSurface(const SurfaceId& original_surface_id,
+ const SurfaceId& target_surface_id,
+ gfx::Point* point);
+
+ private:
+ bool GetTargetSurfaceAtPointInternal(
+ const SurfaceId& surface_id,
+ cc::RenderPassId render_pass_id,
+ const gfx::Point& point_in_root_target,
+ std::set<const cc::RenderPass*>* referenced_passes,
+ SurfaceId* out_surface_id,
+ gfx::Transform* out_transform);
+
+ bool GetTransformToTargetSurfaceInternal(
+ const SurfaceId& root_surface_id,
+ const SurfaceId& target_surface_id,
+ cc::RenderPassId render_pass_id,
+ std::set<const cc::RenderPass*>* referenced_passes,
+ gfx::Transform* out_transform);
+
+ const cc::RenderPass* GetRenderPassForSurfaceById(
+ const SurfaceId& surface_id,
+ cc::RenderPassId render_pass_id);
+
+ bool PointInQuad(const cc::DrawQuad* quad,
+ const gfx::Point& point_in_render_pass_space,
+ gfx::Transform* target_to_quad_transform,
+ gfx::Point* point_in_quad_space);
+
+ SurfaceHittestDelegate* const delegate_;
+ SurfaceManager* const manager_;
+};
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_H_
diff --git a/chromium/components/viz/service/surfaces/surface_hittest_delegate.h b/chromium/components/viz/service/surfaces/surface_hittest_delegate.h
new file mode 100644
index 00000000000..b05d4575b8a
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_hittest_delegate.h
@@ -0,0 +1,35 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_DELEGATE_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_DELEGATE_H_
+
+namespace gfx {
+class Point;
+} // namespace gfx
+
+namespace cc {
+class SurfaceDrawQuad;
+}
+
+namespace viz {
+
+// Clients of SurfaceHittest can provide a SurfaceHittestDelegate implementation
+// to override the hit target based on metadata outside of the Surfaces system.
+class SurfaceHittestDelegate {
+ public:
+ // Return true if this delegate rejects this |surface_quad| as a candidate hit
+ // target.
+ virtual bool RejectHitTarget(const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) = 0;
+
+ // Return true if this delegate accepts this |surface_quad| as a candidate hit
+ // target.
+ virtual bool AcceptHitTarget(const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_HITTEST_DELEGATE_H_
diff --git a/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc
new file mode 100644
index 00000000000..fe4aa176b74
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc
@@ -0,0 +1,505 @@
+// 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 <stddef.h>
+
+#include "cc/output/compositor_frame.h"
+#include "cc/test/fake_compositor_frame_sink_support_client.h"
+#include "components/viz/common/surfaces/local_surface_id_allocator.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_hittest.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/surface_hittest_test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+namespace {
+
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kNeedsSyncPoints = true;
+constexpr FrameSinkId kRootFrameSink(2, 0);
+constexpr FrameSinkId kChildFrameSink(65563, 0);
+constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);
+
+struct TestCase {
+ SurfaceId input_surface_id;
+ gfx::Point input_point;
+ SurfaceId expected_layer_tree_frame_sink_id;
+ gfx::Point expected_output_point;
+};
+
+void RunTests(SurfaceHittestDelegate* delegate,
+ SurfaceManager* manager,
+ TestCase* tests,
+ size_t test_count) {
+ SurfaceHittest hittest(delegate, manager);
+ for (size_t i = 0; i < test_count; ++i) {
+ const TestCase& test = tests[i];
+ gfx::Point point(test.input_point);
+ gfx::Transform transform;
+ EXPECT_EQ(test.expected_layer_tree_frame_sink_id,
+ hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point,
+ &transform));
+ transform.TransformPoint(&point);
+ EXPECT_EQ(test.expected_output_point, point);
+
+ // Verify that GetTransformToTargetSurface returns true and returns the same
+ // transform as returned by GetTargetSurfaceAtPoint.
+ gfx::Transform target_transform;
+ EXPECT_TRUE(hittest.GetTransformToTargetSurface(
+ test.input_surface_id, test.expected_layer_tree_frame_sink_id,
+ &target_transform));
+ EXPECT_EQ(transform, target_transform);
+ }
+}
+
+} // namespace
+
+using namespace test;
+
+class SurfaceHittestTest : public testing::Test {
+ public:
+ SurfaceHittestTest() = default;
+ ~SurfaceHittestTest() override = default;
+
+ CompositorFrameSinkSupport& root_support() { return *supports_[0]; }
+
+ CompositorFrameSinkSupport& child_support() { return *supports_[1]; }
+
+ SurfaceManager* surface_manager() {
+ return frame_sink_manager_.surface_manager();
+ }
+
+ // testing::Test:
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &frame_sink_manager_, kRootFrameSink, kIsRoot,
+ kNeedsSyncPoints));
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &frame_sink_manager_, kChildFrameSink, kIsChildRoot,
+ kNeedsSyncPoints));
+ }
+
+ void TearDown() override { supports_.clear(); }
+
+ private:
+ FrameSinkManagerImpl frame_sink_manager_;
+ std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_;
+ cc::FakeCompositorFrameSinkSupportClient support_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceHittestTest);
+};
+
+// This test verifies that hit testing on a surface that does not exist does
+// not crash.
+TEST_F(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) {
+ // Creates a root surface.
+ gfx::Rect root_rect(300, 300);
+ cc::RenderPass* root_pass = nullptr;
+ cc::CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+ // Add a reference to a non-existant child surface on the root surface.
+ SurfaceId child_surface_id(
+ kArbitraryFrameSink,
+ LocalSurfaceId(0xdeadbeef, base::UnguessableToken::Create()));
+ gfx::Rect child_rect(200, 200);
+ CreateSurfaceDrawQuad(root_pass, gfx::Transform(), root_rect, child_rect,
+ child_surface_id);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ {
+ SurfaceHittest hittest(nullptr, surface_manager());
+ // It is expected this test will complete without crashes.
+ gfx::Transform transform;
+ EXPECT_EQ(root_surface_id,
+ hittest.GetTargetSurfaceAtPoint(
+ root_surface_id, gfx::Point(100, 100), &transform));
+ }
+
+ root_support().EvictCurrentSurface();
+}
+
+TEST_F(SurfaceHittestTest, Hittest_SingleSurface) {
+ // Creates a root surface.
+ gfx::Rect root_rect(300, 300);
+ cc::RenderPass* root_pass = nullptr;
+ cc::CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+ TestCase tests[] = {
+ {root_surface_id, gfx::Point(100, 100), root_surface_id,
+ gfx::Point(100, 100)},
+ };
+
+ RunTests(nullptr, surface_manager(), tests, arraysize(tests));
+
+ root_support().EvictCurrentSurface();
+}
+
+TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
+ // Creates a root surface.
+ gfx::Rect root_rect(300, 300);
+ cc::RenderPass* root_pass = nullptr;
+ cc::CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+ // Add a reference to the child surface on the root surface.
+ LocalSurfaceIdAllocator child_allocator;
+ LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
+ SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ gfx::Rect child_rect(200, 200);
+ CreateSurfaceDrawQuad(
+ root_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_rect, child_surface_id);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ // Creates a child surface.
+ cc::RenderPass* child_pass = nullptr;
+ cc::CompositorFrame child_frame =
+ CreateCompositorFrame(child_rect, &child_pass);
+
+ // Add a solid quad in the child surface.
+ gfx::Rect child_solid_quad_rect(100, 100);
+ CreateSolidColorDrawQuad(
+ child_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_solid_quad_rect);
+
+ // Submit the frame.
+ child_support().SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
+ gfx::Point(10, 10)},
+ {root_surface_id, gfx::Point(99, 99), root_surface_id,
+ gfx::Point(99, 99)},
+ {root_surface_id, gfx::Point(100, 100), child_surface_id,
+ gfx::Point(50, 50)},
+ {root_surface_id, gfx::Point(199, 199), child_surface_id,
+ gfx::Point(149, 149)},
+ {root_surface_id, gfx::Point(200, 200), root_surface_id,
+ gfx::Point(200, 200)},
+ {root_surface_id, gfx::Point(290, 290), root_surface_id,
+ gfx::Point(290, 290)}};
+
+ RunTests(nullptr, surface_manager(), tests, arraysize(tests));
+
+ // Submit another root frame, with a slightly perturbed child Surface.
+ root_frame = CreateCompositorFrame(root_rect, &root_pass);
+ CreateSurfaceDrawQuad(
+ root_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_rect, child_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ // Verify that point (100, 100) no longer falls on the child surface.
+ // Verify that the transform to the child surface's space has also shifted.
+ {
+ SurfaceHittest hittest(nullptr, surface_manager());
+
+ gfx::Point point(100, 100);
+ gfx::Transform transform;
+ EXPECT_EQ(root_surface_id, hittest.GetTargetSurfaceAtPoint(
+ root_surface_id, point, &transform));
+ transform.TransformPoint(&point);
+ EXPECT_EQ(gfx::Point(100, 100), point);
+
+ gfx::Point point_in_target_space(100, 100);
+ gfx::Transform target_transform;
+ EXPECT_TRUE(hittest.GetTransformToTargetSurface(
+ root_surface_id, child_surface_id, &target_transform));
+ target_transform.TransformPoint(&point_in_target_space);
+ EXPECT_NE(transform, target_transform);
+ EXPECT_EQ(gfx::Point(25, 25), point_in_target_space);
+ }
+
+ root_support().EvictCurrentSurface();
+ child_support().EvictCurrentSurface();
+}
+
+// This test verifies that hit testing will progress to the next quad if it
+// encounters an invalid cc::RenderPassDrawQuad for whatever reason.
+TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
+ // Creates a root surface.
+ gfx::Rect root_rect(300, 300);
+ cc::RenderPass* root_pass = nullptr;
+ cc::CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+ // Create a cc::RenderPassDrawQuad to a non-existant cc::RenderPass.
+ int invalid_render_pass_id = 1337;
+ CreateRenderPassDrawQuad(root_pass, gfx::Transform(), root_rect, root_rect,
+ invalid_render_pass_id);
+
+ // Add a reference to the child surface on the root surface.
+ LocalSurfaceIdAllocator child_allocator;
+ LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
+ SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ gfx::Rect child_rect(200, 200);
+ CreateSurfaceDrawQuad(
+ root_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_rect, child_surface_id);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ // Creates a child surface.
+ cc::RenderPass* child_pass = nullptr;
+ cc::CompositorFrame child_frame =
+ CreateCompositorFrame(child_rect, &child_pass);
+
+ // Add a solid quad in the child surface.
+ gfx::Rect child_solid_quad_rect(100, 100);
+ CreateSolidColorDrawQuad(
+ child_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_solid_quad_rect);
+
+ // Submit the frame.
+ child_support().SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
+ gfx::Point(10, 10)},
+ {root_surface_id, gfx::Point(99, 99), root_surface_id,
+ gfx::Point(99, 99)},
+ {root_surface_id, gfx::Point(100, 100), child_surface_id,
+ gfx::Point(50, 50)},
+ {root_surface_id, gfx::Point(199, 199), child_surface_id,
+ gfx::Point(149, 149)},
+ {root_surface_id, gfx::Point(200, 200), root_surface_id,
+ gfx::Point(200, 200)},
+ {root_surface_id, gfx::Point(290, 290), root_surface_id,
+ gfx::Point(290, 290)}};
+
+ RunTests(nullptr, surface_manager(), tests, arraysize(tests));
+
+ root_support().EvictCurrentSurface();
+ child_support().EvictCurrentSurface();
+}
+
+TEST_F(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
+ // Create a CompositorFrame with two cc::RenderPasses.
+ gfx::Rect root_rect(300, 300);
+ cc::CompositorFrame root_frame = test::MakeCompositorFrame();
+ cc::RenderPassList& render_pass_list = root_frame.render_pass_list;
+
+ // Create a child cc::RenderPass.
+ int child_render_pass_id = 3;
+ gfx::Transform transform_to_root_target(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f,
+ 0.0f, 50.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ CreateRenderPass(child_render_pass_id, gfx::Rect(100, 100),
+ transform_to_root_target, &render_pass_list);
+
+ // Create the root cc::RenderPass.
+ int root_render_pass_id = 2;
+ CreateRenderPass(root_render_pass_id, root_rect, gfx::Transform(),
+ &render_pass_list);
+
+ cc::RenderPass* root_pass = nullptr;
+ root_pass = root_frame.render_pass_list.back().get();
+
+ // Create a cc::RenderPassDrawQuad.
+ gfx::Rect render_pass_quad_rect(100, 100);
+ CreateRenderPassDrawQuad(root_pass, transform_to_root_target, root_rect,
+ render_pass_quad_rect, child_render_pass_id);
+
+ // Add a solid quad in the child render pass.
+ cc::RenderPass* child_render_pass = root_frame.render_pass_list.front().get();
+ gfx::Rect child_solid_quad_rect(100, 100);
+ CreateSolidColorDrawQuad(child_render_pass, gfx::Transform(),
+ gfx::Rect(100, 100), child_solid_quad_rect);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ TestCase tests[] = {// These tests just miss the cc::RenderPassDrawQuad.
+ {root_surface_id, gfx::Point(49, 49), root_surface_id,
+ gfx::Point(49, 49)},
+ {root_surface_id, gfx::Point(150, 150), root_surface_id,
+ gfx::Point(150, 150)},
+ // These tests just hit the boundaries of the
+ // cc::RenderPassDrawQuad.
+ {root_surface_id, gfx::Point(50, 50), root_surface_id,
+ gfx::Point(50, 50)},
+ {root_surface_id, gfx::Point(149, 149), root_surface_id,
+ gfx::Point(149, 149)},
+ // These tests fall somewhere in the center of the
+ // cc::RenderPassDrawQuad.
+ {root_surface_id, gfx::Point(99, 99), root_surface_id,
+ gfx::Point(99, 99)},
+ {root_surface_id, gfx::Point(100, 100), root_surface_id,
+ gfx::Point(100, 100)}};
+
+ RunTests(nullptr, surface_manager(), tests, arraysize(tests));
+
+ root_support().EvictCurrentSurface();
+}
+
+TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
+ // Creates a root surface.
+ gfx::Rect root_rect(300, 300);
+ cc::RenderPass* root_pass = nullptr;
+ cc::CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+ // Add a reference to the child surface on the root surface.
+ LocalSurfaceIdAllocator child_allocator;
+ LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
+ SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ gfx::Rect child_rect(200, 200);
+ CreateSurfaceDrawQuad(
+ root_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_rect, child_surface_id);
+
+ // Submit the root frame.
+ LocalSurfaceIdAllocator root_allocator;
+ LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
+ SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
+ root_support().SubmitCompositorFrame(root_local_surface_id,
+ std::move(root_frame));
+
+ // Creates a child surface.
+ cc::RenderPass* child_pass = nullptr;
+ cc::CompositorFrame child_frame =
+ CreateCompositorFrame(child_rect, &child_pass);
+
+ // Add a solid quad in the child surface.
+ gfx::Rect child_solid_quad_rect(190, 190);
+ CreateSolidColorDrawQuad(
+ child_pass,
+ gfx::Transform(1.0f, 0.0f, 0.0f, 5.0f, 0.0f, 1.0f, 0.0f, 5.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+ root_rect, child_solid_quad_rect);
+
+ // Submit the frame.
+ child_support().SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ TestCase test_expectations_without_insets[] = {
+ {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5)},
+ {root_surface_id, gfx::Point(60, 60), child_surface_id,
+ gfx::Point(10, 10)},
+ {root_surface_id, gfx::Point(239, 239), child_surface_id,
+ gfx::Point(189, 189)},
+ {root_surface_id, gfx::Point(244, 244), child_surface_id,
+ gfx::Point(194, 194)},
+ {root_surface_id, gfx::Point(50, 50), root_surface_id,
+ gfx::Point(50, 50)},
+ {root_surface_id, gfx::Point(249, 249), root_surface_id,
+ gfx::Point(249, 249)},
+ };
+
+ TestSurfaceHittestDelegate empty_delegate;
+ RunTests(&empty_delegate, surface_manager(), test_expectations_without_insets,
+ arraysize(test_expectations_without_insets));
+
+ // Verify that insets have NOT affected hit targeting.
+ EXPECT_EQ(0, empty_delegate.reject_target_overrides());
+ EXPECT_EQ(0, empty_delegate.accept_target_overrides());
+
+ TestCase test_expectations_with_reject_insets[] = {
+ // Point (55, 55) falls outside the child surface due to the insets
+ // introduced above.
+ {root_surface_id, gfx::Point(55, 55), root_surface_id,
+ gfx::Point(55, 55)},
+ // These two points still fall within the child surface.
+ {root_surface_id, gfx::Point(60, 60), child_surface_id,
+ gfx::Point(10, 10)},
+ {root_surface_id, gfx::Point(239, 239), child_surface_id,
+ gfx::Point(189, 189)},
+ // Point (244, 244) falls outside the child surface due to the insets
+ // introduced above.
+ {root_surface_id, gfx::Point(244, 244), root_surface_id,
+ gfx::Point(244, 244)},
+ // Next two points also fall within within the insets indroduced above.
+ {root_surface_id, gfx::Point(50, 50), root_surface_id,
+ gfx::Point(50, 50)},
+ {root_surface_id, gfx::Point(249, 249), root_surface_id,
+ gfx::Point(249, 249)},
+ };
+
+ TestSurfaceHittestDelegate reject_delegate;
+ reject_delegate.AddInsetsForRejectSurface(child_surface_id,
+ gfx::Insets(10, 10, 10, 10));
+ RunTests(&reject_delegate, surface_manager(),
+ test_expectations_with_reject_insets,
+ arraysize(test_expectations_with_reject_insets));
+
+ // Verify that insets have affected hit targeting.
+ EXPECT_EQ(4, reject_delegate.reject_target_overrides());
+ EXPECT_EQ(0, reject_delegate.accept_target_overrides());
+
+ TestCase test_expectations_with_accept_insets[] = {
+ {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5)},
+ {root_surface_id, gfx::Point(60, 60), child_surface_id,
+ gfx::Point(10, 10)},
+ {root_surface_id, gfx::Point(239, 239), child_surface_id,
+ gfx::Point(189, 189)},
+ {root_surface_id, gfx::Point(244, 244), child_surface_id,
+ gfx::Point(194, 194)},
+ // Next two points fall within within the insets indroduced above.
+ {root_surface_id, gfx::Point(50, 50), child_surface_id, gfx::Point(0, 0)},
+ {root_surface_id, gfx::Point(249, 249), child_surface_id,
+ gfx::Point(199, 199)},
+ };
+
+ TestSurfaceHittestDelegate accept_delegate;
+ accept_delegate.AddInsetsForAcceptSurface(child_surface_id,
+ gfx::Insets(5, 5, 5, 5));
+ RunTests(&accept_delegate, surface_manager(),
+ test_expectations_with_accept_insets,
+ arraysize(test_expectations_with_accept_insets));
+
+ // Verify that insets have affected hit targeting.
+ EXPECT_EQ(0, accept_delegate.reject_target_overrides());
+ EXPECT_EQ(2, accept_delegate.accept_target_overrides());
+
+ root_support().EvictCurrentSurface();
+ child_support().EvictCurrentSurface();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_manager.cc b/chromium/components/viz/service/surfaces/surface_manager.cc
new file mode 100644
index 00000000000..5cd9715c251
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_manager.cc
@@ -0,0 +1,588 @@
+// 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/viz/service/surfaces/surface_manager.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <queue>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/viz/common/surfaces/local_surface_id_allocator.h"
+#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/service/surfaces/direct_surface_reference_factory.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_client.h"
+
+#if DCHECK_IS_ON()
+#include <sstream>
+#endif
+
+namespace viz {
+namespace {
+
+// Maximum bucket size for the UMA stat.
+constexpr int kUmaStatMax = 10;
+
+const char kUmaNumOldTemporaryReferences[] =
+ "Compositing.SurfaceManager.NumOldTemporaryReferences";
+
+} // namespace
+
+SurfaceManager::SurfaceReferenceInfo::SurfaceReferenceInfo() = default;
+
+SurfaceManager::SurfaceReferenceInfo::~SurfaceReferenceInfo() = default;
+
+SurfaceManager::TemporaryReferenceData::TemporaryReferenceData() = default;
+
+SurfaceManager::TemporaryReferenceData::~TemporaryReferenceData() = default;
+
+SurfaceManager::SurfaceManager(LifetimeType lifetime_type)
+ : lifetime_type_(lifetime_type),
+ dependency_tracker_(this),
+ root_surface_id_(FrameSinkId(0u, 0u),
+ LocalSurfaceId(1u, base::UnguessableToken::Create())),
+ weak_factory_(this) {
+ thread_checker_.DetachFromThread();
+ if (using_surface_references()) {
+ reference_factory_ = new StubSurfaceReferenceFactory();
+ temporary_reference_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(10), this,
+ &SurfaceManager::MarkOldTemporaryReference);
+ // TODO(kylechar): After collecting UMA stats on the number of old temporary
+ // references, we may want to turn the timer off when there are no temporary
+ // references to avoid waking the thread unnecessarily.
+ } else {
+ reference_factory_ =
+ new DirectSurfaceReferenceFactory(weak_factory_.GetWeakPtr());
+ }
+}
+
+SurfaceManager::~SurfaceManager() {
+ // All SurfaceClients and their surfaces are supposed to be
+ // destroyed before SurfaceManager.
+ DCHECK_EQ(surfaces_to_destroy_.size(), surface_map_.size());
+}
+
+#if DCHECK_IS_ON()
+std::string SurfaceManager::SurfaceReferencesToString() {
+ std::stringstream str;
+ SurfaceReferencesToStringImpl(root_surface_id_, "", &str);
+ // Temporary references will have an asterisk in front of them.
+ for (auto& map_entry : temporary_references_)
+ SurfaceReferencesToStringImpl(map_entry.first, "* ", &str);
+
+ return str.str();
+}
+#endif
+
+void SurfaceManager::RequestSurfaceResolution(Surface* surface) {
+ dependency_tracker_.RequestSurfaceResolution(surface);
+}
+
+Surface* SurfaceManager::CreateSurface(
+ base::WeakPtr<SurfaceClient> surface_client,
+ const SurfaceInfo& surface_info,
+ BeginFrameSource* begin_frame_source,
+ bool needs_sync_tokens) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(surface_info.is_valid());
+ DCHECK(surface_client);
+
+ // If no surface with this SurfaceId exists, simply create the surface
+ // and return.
+ auto it = surface_map_.find(surface_info.id());
+ if (it == surface_map_.end()) {
+ surface_map_[surface_info.id()] =
+ base::MakeUnique<Surface>(surface_info, this, surface_client,
+ begin_frame_source, needs_sync_tokens);
+ if (lifetime_type_ == LifetimeType::REFERENCES) {
+ // We can get into a situation where multiple CompositorFrames arrive for
+ // a FrameSink before the client can add any references for the frame.
+ // When the second frame with a new size arrives, the first will be
+ // destroyed in SurfaceFactory and then if there are no references it will
+ // be deleted during surface GC. A temporary reference, removed when a
+ // real reference is received, is added to prevent this from happening.
+ AddTemporaryReference(surface_info.id());
+ }
+ return surface_map_[surface_info.id()].get();
+ }
+
+ // If a surface with this SurfaceId exists, it must be marked as
+ // destroyed. Otherwise, we wouldn't receive a request to reuse the same
+ // SurfaceId. Remove the surface out of the garbage collector's queue and
+ // reuse it.
+ Surface* surface = it->second.get();
+ DCHECK(IsMarkedForDestruction(surface_info.id()));
+ surfaces_to_destroy_.erase(surface_info.id());
+ return surface;
+}
+
+void SurfaceManager::DestroySurface(const SurfaceId& surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(surface_map_.count(surface_id));
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceDestroyed(surface_id);
+ surfaces_to_destroy_.insert(surface_id);
+ GarbageCollectSurfaces();
+}
+
+void SurfaceManager::SurfaceWillDraw(const SurfaceId& surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceWillDraw(surface_id);
+}
+
+void SurfaceManager::RequireSequence(const SurfaceId& surface_id,
+ const SurfaceSequence& sequence) {
+ DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
+ auto* surface = GetSurfaceForId(surface_id);
+ if (!surface) {
+ DLOG(ERROR) << "Attempting to require callback on nonexistent surface";
+ return;
+ }
+ surface->AddDestructionDependency(sequence);
+}
+
+void SurfaceManager::SatisfySequence(const SurfaceSequence& sequence) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
+ satisfied_sequences_.insert(sequence);
+ GarbageCollectSurfaces();
+}
+
+void SurfaceManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id) {
+ bool inserted = valid_frame_sink_ids_.insert(frame_sink_id).second;
+ DCHECK(inserted);
+}
+
+void SurfaceManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) {
+ valid_frame_sink_ids_.erase(frame_sink_id);
+
+ // Remove any temporary references owned by |frame_sink_id|.
+ std::vector<SurfaceId> temp_refs_to_clear;
+ for (auto& map_entry : temporary_references_) {
+ base::Optional<FrameSinkId>& owner = map_entry.second.owner;
+ if (owner.has_value() && owner.value() == frame_sink_id)
+ temp_refs_to_clear.push_back(map_entry.first);
+ }
+
+ for (auto& surface_id : temp_refs_to_clear)
+ RemoveTemporaryReference(surface_id, false);
+
+ GarbageCollectSurfaces();
+}
+
+const SurfaceId& SurfaceManager::GetRootSurfaceId() const {
+ return root_surface_id_;
+}
+
+void SurfaceManager::AddSurfaceReferences(
+ const std::vector<SurfaceReference>& references) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ for (const auto& reference : references)
+ AddSurfaceReferenceImpl(reference.parent_id(), reference.child_id());
+}
+
+void SurfaceManager::RemoveSurfaceReferences(
+ const std::vector<SurfaceReference>& references) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ for (const auto& reference : references)
+ RemoveSurfaceReferenceImpl(reference.parent_id(), reference.child_id());
+
+ GarbageCollectSurfaces();
+}
+
+void SurfaceManager::AssignTemporaryReference(const SurfaceId& surface_id,
+ const FrameSinkId& owner) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
+
+ if (!HasTemporaryReference(surface_id))
+ return;
+
+ temporary_references_[surface_id].owner = owner;
+}
+
+void SurfaceManager::DropTemporaryReference(const SurfaceId& surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (lifetime_type_ != LifetimeType::REFERENCES ||
+ !HasTemporaryReference(surface_id)) {
+ return;
+ }
+
+ RemoveTemporaryReference(surface_id, false);
+}
+
+const base::flat_set<SurfaceId>& SurfaceManager::GetSurfacesReferencedByParent(
+ const SurfaceId& surface_id) const {
+ auto iter = references_.find(surface_id);
+ if (iter == references_.end())
+ return empty_surface_id_set_;
+ return iter->second.children;
+}
+
+const base::flat_set<SurfaceId>& SurfaceManager::GetSurfacesThatReferenceChild(
+ const SurfaceId& surface_id) const {
+ auto iter = references_.find(surface_id);
+ if (iter == references_.end())
+ return empty_surface_id_set_;
+ return iter->second.parents;
+}
+
+void SurfaceManager::GarbageCollectSurfaces() {
+ if (surfaces_to_destroy_.empty())
+ return;
+
+ SurfaceIdSet reachable_surfaces = using_surface_references()
+ ? GetLiveSurfacesForReferences()
+ : GetLiveSurfacesForSequences();
+
+ std::vector<SurfaceId> surfaces_to_delete;
+
+ // Delete all destroyed and unreachable surfaces.
+ for (auto iter = surfaces_to_destroy_.begin();
+ iter != surfaces_to_destroy_.end();) {
+ if (reachable_surfaces.count(*iter) == 0) {
+ surfaces_to_delete.push_back(*iter);
+ iter = surfaces_to_destroy_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+
+ // ~Surface() draw callback could modify |surfaces_to_destroy_|.
+ for (const SurfaceId& surface_id : surfaces_to_delete)
+ DestroySurfaceInternal(surface_id);
+}
+
+SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForReferences() {
+ DCHECK(using_surface_references());
+
+ SurfaceIdSet reachable_surfaces;
+
+ // Walk down from the root and mark each SurfaceId we encounter as
+ // reachable.
+ std::queue<SurfaceId> surface_queue;
+ surface_queue.push(root_surface_id_);
+
+ // All surfaces not marked for destruction are reachable.
+ for (auto& map_entry : surface_map_) {
+ if (!IsMarkedForDestruction(map_entry.first)) {
+ reachable_surfaces.insert(map_entry.first);
+ surface_queue.push(map_entry.first);
+ }
+ }
+
+ // All surfaces with temporary references are also reachable.
+ for (auto& map_entry : temporary_references_) {
+ const SurfaceId& surface_id = map_entry.first;
+ if (reachable_surfaces.insert(surface_id).second) {
+ surface_queue.push(surface_id);
+ }
+ }
+
+ while (!surface_queue.empty()) {
+ const auto& children = GetSurfacesReferencedByParent(surface_queue.front());
+ for (const SurfaceId& child_id : children) {
+ // Check for cycles when inserting into |reachable_surfaces|.
+ if (reachable_surfaces.insert(child_id).second)
+ surface_queue.push(child_id);
+ }
+ surface_queue.pop();
+ }
+
+ return reachable_surfaces;
+}
+
+SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForSequences() {
+ DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
+
+ // Simple mark and sweep GC.
+ // TODO(jbauman): Reduce the amount of work when nothing needs to be
+ // destroyed.
+ std::vector<SurfaceId> live_surfaces;
+ std::unordered_set<SurfaceId, SurfaceIdHash> live_surfaces_set;
+
+ // GC roots are surfaces that have not been destroyed, or have not had all
+ // their destruction dependencies satisfied.
+ for (auto& map_entry : surface_map_) {
+ const SurfaceId& surface_id = map_entry.first;
+ Surface* surface = map_entry.second.get();
+ surface->SatisfyDestructionDependencies(&satisfied_sequences_,
+ &valid_frame_sink_ids_);
+
+ if (!IsMarkedForDestruction(surface_id) ||
+ surface->GetDestructionDependencyCount() > 0) {
+ live_surfaces_set.insert(surface_id);
+ live_surfaces.push_back(surface_id);
+ }
+ }
+
+ // Mark all surfaces reachable from live surfaces by adding them to
+ // live_surfaces and live_surfaces_set.
+ for (size_t i = 0; i < live_surfaces.size(); i++) {
+ Surface* surf = surface_map_[live_surfaces[i]].get();
+ DCHECK(surf);
+
+ const auto& children = GetSurfacesReferencedByParent(surf->surface_id());
+ for (const SurfaceId& id : children) {
+ if (live_surfaces_set.count(id))
+ continue;
+
+ Surface* surf2 = GetSurfaceForId(id);
+ if (surf2) {
+ live_surfaces.push_back(id);
+ live_surfaces_set.insert(id);
+ }
+ }
+ }
+
+ return live_surfaces_set;
+}
+
+void SurfaceManager::AddSurfaceReferenceImpl(const SurfaceId& parent_id,
+ const SurfaceId& child_id) {
+ if (parent_id.frame_sink_id() == child_id.frame_sink_id()) {
+ DLOG(ERROR) << "Cannot add self reference from " << parent_id << " to "
+ << child_id;
+ return;
+ }
+
+ // We trust that |parent_id| either exists or is about to exist, since is not
+ // sent over IPC. We don't trust |child_id|, since it is sent over IPC.
+ if (surface_map_.count(child_id) == 0) {
+ DLOG(ERROR) << "No surface in map for " << child_id.ToString();
+ return;
+ }
+
+ references_[parent_id].children.insert(child_id);
+ references_[child_id].parents.insert(parent_id);
+
+ if (HasTemporaryReference(child_id))
+ RemoveTemporaryReference(child_id, true);
+}
+
+void SurfaceManager::RemoveSurfaceReferenceImpl(const SurfaceId& parent_id,
+ const SurfaceId& child_id) {
+ auto iter_parent = references_.find(parent_id);
+ auto iter_child = references_.find(child_id);
+ if (iter_parent == references_.end() || iter_child == references_.end())
+ return;
+
+ iter_parent->second.children.erase(child_id);
+ iter_child->second.parents.erase(parent_id);
+}
+
+void SurfaceManager::RemoveAllSurfaceReferences(const SurfaceId& surface_id) {
+ DCHECK(!HasTemporaryReference(surface_id));
+
+ auto iter = references_.find(surface_id);
+ if (iter != references_.end()) {
+ // Remove all references from |surface_id| to a child surface.
+ for (const SurfaceId& child_id : iter->second.children)
+ references_[child_id].parents.erase(surface_id);
+
+ // Remove all reference from parent surface to |surface_id|.
+ for (const SurfaceId& parent_id : iter->second.parents)
+ references_[parent_id].children.erase(surface_id);
+
+ references_.erase(iter);
+ }
+}
+
+bool SurfaceManager::HasTemporaryReference(const SurfaceId& surface_id) const {
+ return temporary_references_.count(surface_id) != 0;
+}
+
+void SurfaceManager::AddTemporaryReference(const SurfaceId& surface_id) {
+ DCHECK(!HasTemporaryReference(surface_id));
+
+ // Add an entry to |temporary_references_| with no owner for the temporary
+ // reference. Also add a range tracking entry so we know the order that
+ // surfaces were created for the FrameSinkId.
+ temporary_references_[surface_id].owner = base::Optional<FrameSinkId>();
+ temporary_reference_ranges_[surface_id.frame_sink_id()].push_back(
+ surface_id.local_surface_id());
+}
+
+void SurfaceManager::RemoveTemporaryReference(const SurfaceId& surface_id,
+ bool remove_range) {
+ DCHECK(HasTemporaryReference(surface_id));
+
+ const FrameSinkId& frame_sink_id = surface_id.frame_sink_id();
+ std::vector<LocalSurfaceId>& frame_sink_temp_refs =
+ temporary_reference_ranges_[frame_sink_id];
+
+ // Find the iterator to the range tracking entry for |surface_id|. Use that
+ // iterator and |remove_range| to find the right begin and end iterators for
+ // the temporary references we want to remove.
+ auto surface_id_iter =
+ std::find(frame_sink_temp_refs.begin(), frame_sink_temp_refs.end(),
+ surface_id.local_surface_id());
+ auto begin_iter =
+ remove_range ? frame_sink_temp_refs.begin() : surface_id_iter;
+ auto end_iter = surface_id_iter + 1;
+
+ // Remove temporary references and range tracking information.
+ for (auto iter = begin_iter; iter != end_iter; ++iter)
+ temporary_references_.erase(SurfaceId(frame_sink_id, *iter));
+ frame_sink_temp_refs.erase(begin_iter, end_iter);
+
+ // If last temporary reference is removed for |frame_sink_id| then cleanup
+ // range tracking map entry.
+ if (frame_sink_temp_refs.empty())
+ temporary_reference_ranges_.erase(frame_sink_id);
+}
+
+void SurfaceManager::MarkOldTemporaryReference() {
+ if (temporary_references_.empty()) {
+ UMA_HISTOGRAM_EXACT_LINEAR(kUmaNumOldTemporaryReferences, 0, kUmaStatMax);
+ return;
+ }
+
+ std::vector<SurfaceId> temporary_references_to_delete;
+ for (auto& map_entry : temporary_references_) {
+ TemporaryReferenceData& data = map_entry.second;
+ if (data.marked_as_old) {
+ // The temporary reference has existed for more than 10 seconds, a surface
+ // reference should have replaced it by now. To avoid permanently leaking
+ // memory delete the temporary reference.
+ DLOG(ERROR) << "Old/orphaned temporary reference to " << map_entry.first;
+ temporary_references_to_delete.push_back(map_entry.first);
+ } else {
+ data.marked_as_old = true;
+ }
+ }
+
+ // This number would ideally always be zero always but there is potential for
+ // a frame sink to get assigned a temporary reference and never use it.
+ UMA_HISTOGRAM_EXACT_LINEAR(kUmaNumOldTemporaryReferences,
+ temporary_references_to_delete.size(),
+ kUmaStatMax);
+
+ for (auto& surface_id : temporary_references_to_delete)
+ RemoveTemporaryReference(surface_id, false);
+}
+
+Surface* SurfaceManager::GetSurfaceForId(const SurfaceId& surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = surface_map_.find(surface_id);
+ if (it == surface_map_.end())
+ return nullptr;
+ return it->second.get();
+}
+
+bool SurfaceManager::SurfaceModified(const SurfaceId& surface_id,
+ const BeginFrameAck& ack) {
+ CHECK(thread_checker_.CalledOnValidThread());
+ bool changed = false;
+ for (auto& observer : observer_list_)
+ changed |= observer.OnSurfaceDamaged(surface_id, ack);
+ return changed;
+}
+
+void SurfaceManager::FirstSurfaceActivation(const SurfaceInfo& surface_info) {
+ CHECK(thread_checker_.CalledOnValidThread());
+
+ for (auto& observer : observer_list_)
+ observer.OnFirstSurfaceActivation(surface_info);
+}
+
+void SurfaceManager::SurfaceActivated(Surface* surface) {
+ // Trigger a display frame if necessary.
+ const cc::CompositorFrame& frame = surface->GetActiveFrame();
+ if (!SurfaceModified(surface->surface_id(), frame.metadata.begin_frame_ack)) {
+ TRACE_EVENT_INSTANT0("cc", "Damage not visible.", TRACE_EVENT_SCOPE_THREAD);
+ surface->RunDrawCallback();
+ }
+
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceActivated(surface->surface_id());
+
+ dependency_tracker_.OnSurfaceActivated(surface);
+}
+
+void SurfaceManager::SurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies) {
+ dependency_tracker_.OnSurfaceDependenciesChanged(surface, added_dependencies,
+ removed_dependencies);
+}
+
+void SurfaceManager::SurfaceDiscarded(Surface* surface) {
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceDiscarded(surface->surface_id());
+ dependency_tracker_.OnSurfaceDiscarded(surface);
+}
+
+void SurfaceManager::SurfaceDamageExpected(const SurfaceId& surface_id,
+ const BeginFrameArgs& args) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceDamageExpected(surface_id, args);
+}
+
+void SurfaceManager::DestroySurfaceInternal(const SurfaceId& surface_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = surface_map_.find(surface_id);
+ DCHECK(it != surface_map_.end());
+ // Make sure that the surface is removed from the map before being actually
+ // destroyed. An ack could be sent during the destruction of a surface which
+ // could trigger a synchronous frame submission to a half-destroyed surface
+ // and that's not desirable.
+ std::unique_ptr<Surface> doomed = std::move(it->second);
+ surface_map_.erase(it);
+ RemoveAllSurfaceReferences(surface_id);
+}
+
+#if DCHECK_IS_ON()
+void SurfaceManager::SurfaceReferencesToStringImpl(const SurfaceId& surface_id,
+ std::string indent,
+ std::stringstream* str) {
+ *str << indent;
+
+ // Print the current line for |surface_id|.
+ Surface* surface = GetSurfaceForId(surface_id);
+ if (surface) {
+ *str << surface->surface_id().ToString();
+ *str << (IsMarkedForDestruction(surface_id) ? " destroyed" : " live");
+
+ if (surface->HasPendingFrame()) {
+ // This provides the surface size from the root render pass.
+ const cc::CompositorFrame& frame = surface->GetPendingFrame();
+ *str << " pending " << frame.size_in_pixels().ToString();
+ }
+
+ if (surface->HasActiveFrame()) {
+ // This provides the surface size from the root render pass.
+ const cc::CompositorFrame& frame = surface->GetActiveFrame();
+ *str << " active " << frame.size_in_pixels().ToString();
+ }
+ } else {
+ *str << surface_id;
+ }
+ *str << "\n";
+
+ // If the current surface has references to children, sort children and print
+ // references for each child.
+ for (const SurfaceId& child_id : GetSurfacesReferencedByParent(surface_id))
+ SurfaceReferencesToStringImpl(child_id, indent + " ", str);
+}
+#endif // DCHECK_IS_ON()
+
+bool SurfaceManager::IsMarkedForDestruction(const SurfaceId& surface_id) {
+ return surfaces_to_destroy_.count(surface_id) != 0;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_manager.h b/chromium/components/viz/service/surfaces/surface_manager.h
new file mode 100644
index 00000000000..2955b7eeebb
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_manager.h
@@ -0,0 +1,332 @@
+// 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
+#include "components/viz/service/surfaces/surface_dependency_tracker.h"
+#include "components/viz/service/surfaces/surface_observer.h"
+#include "components/viz/service/surfaces/surface_reference.h"
+
+#if DCHECK_IS_ON()
+#include <iosfwd>
+#include <string>
+#endif
+
+namespace cc {
+class CompositorFrame;
+}
+
+namespace viz {
+
+namespace test {
+class SurfaceReferencesTest;
+class SurfaceSynchronizationTest;
+} // namespace test
+class Surface;
+struct BeginFrameAck;
+struct BeginFrameArgs;
+
+class VIZ_SERVICE_EXPORT SurfaceManager {
+ public:
+ enum class LifetimeType {
+ REFERENCES,
+ SEQUENCES,
+ };
+
+ explicit SurfaceManager(LifetimeType lifetime_type = LifetimeType::SEQUENCES);
+ ~SurfaceManager();
+
+#if DCHECK_IS_ON()
+ // Returns a string representation of all reachable surface references.
+ std::string SurfaceReferencesToString();
+#endif
+
+ void RequestSurfaceResolution(Surface* surface);
+
+ // Creates a Surface for the given SurfaceClient. The surface will be
+ // destroyed when DestroySurface is called, all of its destruction
+ // dependencies are satisfied, and it is not reachable from the root surface.
+ // If LifetimeType=REFERENCES, then a temporary reference will be added to
+ // the new Surface.
+ Surface* CreateSurface(base::WeakPtr<SurfaceClient> surface_client,
+ const SurfaceInfo& surface_info,
+ BeginFrameSource* begin_frame_source,
+ bool needs_sync_tokens);
+
+ // Destroy the Surface once a set of sequence numbers has been satisfied.
+ void DestroySurface(const SurfaceId& surface_id);
+
+ // Called when a surface has been added to the aggregated CompositorFrame
+ // and will notify observers with SurfaceObserver::OnSurfaceWillDraw.
+ void SurfaceWillDraw(const SurfaceId& surface_id);
+
+ Surface* GetSurfaceForId(const SurfaceId& surface_id);
+
+ void AddObserver(SurfaceObserver* obs) { observer_list_.AddObserver(obs); }
+
+ void RemoveObserver(SurfaceObserver* obs) {
+ observer_list_.RemoveObserver(obs);
+ }
+
+ // Called when a Surface is modified, e.g. when a CompositorFrame is
+ // activated, its producer confirms that no CompositorFrame will be submitted
+ // in response to a BeginFrame, or a CopyOutputRequest is issued.
+ //
+ // |ack.sequence_number| is only valid if called in response to a BeginFrame.
+ bool SurfaceModified(const SurfaceId& surface_id, const BeginFrameAck& ack);
+
+ // Called when a surface has an active frame for the first time.
+ void FirstSurfaceActivation(const SurfaceInfo& surface_info);
+
+ // Called when a CompositorFrame within |surface| has activated.
+ void SurfaceActivated(Surface* surface);
+
+ // Called when the dependencies of a pending CompositorFrame within |surface|
+ // has changed.
+ void SurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies);
+
+ // Called when |surface| is being destroyed.
+ void SurfaceDiscarded(Surface* surface);
+
+ // Called when a Surface's CompositorFrame producer has received a BeginFrame
+ // and, thus, is expected to produce damage soon.
+ void SurfaceDamageExpected(const SurfaceId& surface_id,
+ const BeginFrameArgs& args);
+
+ // Require that the given sequence number must be satisfied (using
+ // SatisfySequence) before the given surface can be destroyed.
+ void RequireSequence(const SurfaceId& surface_id,
+ const SurfaceSequence& sequence);
+
+ // Satisfies the given sequence number. Once all sequence numbers that
+ // a surface depends on are satisfied, the surface can be destroyed.
+ void SatisfySequence(const SurfaceSequence& sequence);
+
+ void RegisterFrameSinkId(const FrameSinkId& frame_sink_id);
+
+ // Invalidate a frame_sink_id that might still have associated sequences,
+ // possibly because a renderer process has crashed.
+ void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
+
+ // Register a relationship between two namespaces. This relationship means
+ // that surfaces from the child namespace will be displayed in the parent.
+ // Children are allowed to use any begin frame source that their parent can
+ // use.
+ void RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
+ const FrameSinkId& child_frame_sink_id);
+ void UnregisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
+ const FrameSinkId& child_frame_sink_id);
+
+ // Returns the top level root SurfaceId. Surfaces that are not reachable
+ // from the top level root may be garbage collected. It will not be a valid
+ // SurfaceId and will never correspond to a surface.
+ const SurfaceId& GetRootSurfaceId() const;
+
+ // Adds all surface references in |references|. This will remove any temporary
+ // references for child surface in a surface reference.
+ void AddSurfaceReferences(const std::vector<SurfaceReference>& references);
+
+ // Removes all surface references in |references| then runs garbage
+ // collection to delete unreachable surfaces.
+ void RemoveSurfaceReferences(const std::vector<SurfaceReference>& references);
+
+ // Assigns |owner| as the owner of the temporary reference to
+ // |surface_id|. If |owner| is invalidated the temporary reference
+ // will be removed. If a surface reference has already been added from the
+ // parent to |surface_id| then this will do nothing.
+ void AssignTemporaryReference(const SurfaceId& surface_id,
+ const FrameSinkId& owner);
+
+ // Drops the temporary reference for |surface_id|. If a surface reference has
+ // already been added from the parent to |surface_id| then this will do
+ // nothing.
+ void DropTemporaryReference(const SurfaceId& surface_id);
+
+ // Returns all surfaces referenced by parent |surface_id|. Will return an
+ // empty set if |surface_id| is unknown or has no references.
+ const base::flat_set<SurfaceId>& GetSurfacesReferencedByParent(
+ const SurfaceId& surface_id) const;
+
+ // Returns all surfaces that have a reference to child |surface_id|. Will
+ // return an empty set if |surface_id| is unknown or has no references to it.
+ const base::flat_set<SurfaceId>& GetSurfacesThatReferenceChild(
+ const SurfaceId& surface_id) const;
+
+ const scoped_refptr<SurfaceReferenceFactory>& reference_factory() {
+ return reference_factory_;
+ }
+
+ bool using_surface_references() const {
+ return lifetime_type_ == LifetimeType::REFERENCES;
+ }
+
+ private:
+ friend class test::SurfaceSynchronizationTest;
+ friend class test::SurfaceReferencesTest;
+
+ using SurfaceIdSet = std::unordered_set<SurfaceId, SurfaceIdHash>;
+
+ struct SurfaceReferenceInfo {
+ SurfaceReferenceInfo();
+ ~SurfaceReferenceInfo();
+
+ // Surfaces that have references to this surface.
+ base::flat_set<SurfaceId> parents;
+
+ // Surfaces that are referenced from this surface.
+ base::flat_set<SurfaceId> children;
+ };
+
+ struct TemporaryReferenceData {
+ TemporaryReferenceData();
+ ~TemporaryReferenceData();
+
+ // The FrameSinkId that is expected to embed this SurfaceId. This will
+ // initially be empty and set later by AssignTemporaryReference().
+ base::Optional<FrameSinkId> owner;
+
+ // Used to track old surface references, will be marked as true on first
+ // timer tick and will be true on second timer tick.
+ bool marked_as_old = false;
+ };
+
+ // Garbage collects all destroyed surfaces that aren't live.
+ void GarbageCollectSurfaces();
+
+ // Returns set of live surfaces for |lifetime_manager_| is REFERENCES.
+ SurfaceIdSet GetLiveSurfacesForReferences();
+
+ // Returns set of live surfaces for |lifetime_manager_| is SEQUENCES.
+ SurfaceIdSet GetLiveSurfacesForSequences();
+
+ // Adds a reference from |parent_id| to |child_id| without dealing with
+ // temporary references.
+ void AddSurfaceReferenceImpl(const SurfaceId& parent_id,
+ const SurfaceId& child_id);
+
+ // Removes a reference from a |parent_id| to |child_id|.
+ void RemoveSurfaceReferenceImpl(const SurfaceId& parent_id,
+ const SurfaceId& child_id);
+
+ // Removes all surface references to or from |surface_id|. Used when the
+ // surface is about to be deleted.
+ void RemoveAllSurfaceReferences(const SurfaceId& surface_id);
+
+ bool HasTemporaryReference(const SurfaceId& surface_id) const;
+
+ // Adds a temporary reference to |surface_id|. The reference will not have an
+ // owner initially.
+ void AddTemporaryReference(const SurfaceId& surface_id);
+
+ // Removes temporary reference to |surface_id|. If |remove_range| is true then
+ // all temporary references to surfaces with the same FrameSinkId as
+ // |surface_id| that were added before |surface_id| will also be removed.
+ void RemoveTemporaryReference(const SurfaceId& surface_id, bool remove_range);
+
+ // Marks old temporary references for logging and deletion.
+ void MarkOldTemporaryReference();
+
+ // Removes the surface from the surface map and destroys it.
+ void DestroySurfaceInternal(const SurfaceId& surface_id);
+
+#if DCHECK_IS_ON()
+ // Recursively prints surface references starting at |surface_id| to |str|.
+ void SurfaceReferencesToStringImpl(const SurfaceId& surface_id,
+ std::string indent,
+ std::stringstream* str);
+#endif
+
+ // Returns true if |surface_id| is in the garbage collector's queue.
+ bool IsMarkedForDestruction(const SurfaceId& surface_id);
+
+ // Use reference or sequence based lifetime management.
+ LifetimeType lifetime_type_;
+
+ // SurfaceDependencyTracker needs to be destroyed after Surfaces are destroyed
+ // because they will call back into the dependency tracker.
+ SurfaceDependencyTracker dependency_tracker_;
+
+ base::flat_map<SurfaceId, std::unique_ptr<Surface>> surface_map_;
+ base::ObserverList<SurfaceObserver> observer_list_;
+ base::ThreadChecker thread_checker_;
+
+ base::flat_set<SurfaceId> surfaces_to_destroy_;
+
+ // Set of SurfaceSequences that have been satisfied by a frame but not yet
+ // waited on.
+ base::flat_set<SurfaceSequence> satisfied_sequences_;
+
+ // Set of valid FrameSinkIds. When a FrameSinkId is removed from
+ // this set, any remaining (surface) sequences with that FrameSinkId are
+ // considered satisfied.
+ base::flat_set<FrameSinkId> valid_frame_sink_ids_;
+
+ // Root SurfaceId that references display root surfaces. There is no Surface
+ // with this id, it's for bookkeeping purposes only.
+ const SurfaceId root_surface_id_;
+
+ // Always empty set that is returned when there is no entry in |references_|
+ // for a SurfaceId.
+ const base::flat_set<SurfaceId> empty_surface_id_set_;
+
+ // The DirectSurfaceReferenceFactory that uses this manager to create surface
+ // references.
+ scoped_refptr<SurfaceReferenceFactory> reference_factory_;
+
+ // Keeps track of surface references for a surface. The graph of references is
+ // stored in both directions, so we know the parents and children for each
+ // surface.
+ std::unordered_map<SurfaceId, SurfaceReferenceInfo, SurfaceIdHash>
+ references_;
+
+ // A map of surfaces that have temporary references.
+ std::unordered_map<SurfaceId, TemporaryReferenceData, SurfaceIdHash>
+ temporary_references_;
+
+ // Range tracking information for temporary references. Each map entry is an
+ // is an ordered list of SurfaceIds that have temporary references with the
+ // same FrameSinkId. A SurfaceId can be reconstructed with:
+ // SurfaceId surface_id(key, value[index]);
+ // The LocalSurfaceIds are stored in the order the surfaces are created in. If
+ // a reference is added to a later SurfaceId then all temporary references up
+ // to that point will be removed. This is to handle clients getting out of
+ // sync, for example the embedded client producing new SurfaceIds faster than
+ // the embedding client can use them.
+ std::unordered_map<FrameSinkId, std::vector<LocalSurfaceId>, FrameSinkIdHash>
+ temporary_reference_ranges_;
+
+ // Timer that ticks every 10 seconds and calls MarkTemporaryReference().
+ base::RepeatingTimer temporary_reference_timer_;
+
+ base::WeakPtrFactory<SurfaceManager> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceManager);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
diff --git a/chromium/components/viz/service/surfaces/surface_observer.h b/chromium/components/viz/service/surfaces/surface_observer.h
new file mode 100644
index 00000000000..0bffb34569d
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_observer.h
@@ -0,0 +1,50 @@
+// 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_VIZ_SERVICE_SURFACES_SURFACE_OBSERVER_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_OBSERVER_H_
+
+namespace viz {
+
+class SurfaceId;
+class SurfaceInfo;
+struct BeginFrameAck;
+struct BeginFrameArgs;
+
+class SurfaceObserver {
+ public:
+ // Called when a CompositorFrame with a new SurfaceId activates for the first
+ // time.
+ virtual void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) = 0;
+
+ // Called when a CompositorFrame within |surface| activates.
+ virtual void OnSurfaceActivated(const SurfaceId& surface_id) = 0;
+
+ // Called when a Surface was marked to be destroyed.
+ virtual void OnSurfaceDestroyed(const SurfaceId& surface_id) = 0;
+
+ // Called when a Surface is modified, e.g. when a CompositorFrame is
+ // activated, its producer confirms that no CompositorFrame will be submitted
+ // in response to a BeginFrame, or a CopyOutputRequest is issued.
+ //
+ // |ack.sequence_number| is only valid if called in response to a BeginFrame.
+ // Should return true if this causes a Display to be damaged.
+ virtual bool OnSurfaceDamaged(const SurfaceId& surface_id,
+ const BeginFrameAck& ack) = 0;
+
+ // Called when a surface is garbage-collected.
+ virtual void OnSurfaceDiscarded(const SurfaceId& surface_id) = 0;
+
+ // Called when a Surface's CompositorFrame producer has received a BeginFrame
+ // and, thus, is expected to produce damage soon.
+ virtual void OnSurfaceDamageExpected(const SurfaceId& surface_id,
+ const BeginFrameArgs& args) = 0;
+
+ // Called when a surface has been added to the aggregated CompositorFrame.
+ virtual void OnSurfaceWillDraw(const SurfaceId& surface_id) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_OBSERVER_H_
diff --git a/chromium/components/viz/service/surfaces/surface_reference.cc b/chromium/components/viz/service/surfaces/surface_reference.cc
new file mode 100644
index 00000000000..7fb2b7735a6
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_reference.cc
@@ -0,0 +1,27 @@
+// 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/viz/service/surfaces/surface_reference.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace viz {
+
+SurfaceReference::SurfaceReference() = default;
+
+SurfaceReference::SurfaceReference(const SurfaceId& parent_id,
+ const SurfaceId& child_id)
+ : parent_id_(parent_id), child_id_(child_id) {}
+
+SurfaceReference::SurfaceReference(const SurfaceReference& other) = default;
+
+SurfaceReference::~SurfaceReference() = default;
+
+std::string SurfaceReference::ToString() const {
+ return base::StringPrintf("parent=%s, child=%s",
+ parent_id_.ToString().c_str(),
+ child_id_.ToString().c_str());
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_reference.h b/chromium/components/viz/service/surfaces/surface_reference.h
new file mode 100644
index 00000000000..1b4c0cfa1b6
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_reference.h
@@ -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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_REFERENCE_H_
+#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_REFERENCE_H_
+
+#include <string>
+
+#include "base/hash.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+// Hold a reference from an embedding (parent) to embedded (child) surface.
+class VIZ_SERVICE_EXPORT SurfaceReference {
+ public:
+ SurfaceReference();
+ SurfaceReference(const SurfaceId& parent_id, const SurfaceId& child_id);
+ SurfaceReference(const SurfaceReference& other);
+
+ ~SurfaceReference();
+
+ const SurfaceId& parent_id() const { return parent_id_; }
+ const SurfaceId& child_id() const { return child_id_; }
+
+ size_t hash() const {
+ return base::HashInts(static_cast<uint64_t>(parent_id_.hash()),
+ static_cast<uint64_t>(child_id_.hash()));
+ }
+
+ bool operator==(const SurfaceReference& other) const {
+ return parent_id_ == other.parent_id_ && child_id_ == other.child_id_;
+ }
+
+ bool operator!=(const SurfaceReference& other) const {
+ return !(*this == other);
+ }
+
+ bool operator<(const SurfaceReference& other) const {
+ return std::tie(parent_id_, child_id_) <
+ std::tie(other.parent_id_, other.child_id_);
+ }
+
+ std::string ToString() const;
+
+ private:
+ SurfaceId parent_id_;
+ SurfaceId child_id_;
+};
+
+struct SurfaceReferenceHash {
+ size_t operator()(const SurfaceReference& ref) const { return ref.hash(); }
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_REFERENCE_H_
diff --git a/chromium/components/viz/service/surfaces/surface_unittest.cc b/chromium/components/viz/service/surfaces/surface_unittest.cc
new file mode 100644
index 00000000000..c332b2a5d83
--- /dev/null
+++ b/chromium/components/viz/service/surfaces/surface_unittest.cc
@@ -0,0 +1,114 @@
+// 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/viz/service/surfaces/surface.h"
+#include "base/memory/ptr_util.h"
+#include "cc/test/scheduler_test_common.h"
+#include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/common/surfaces/local_surface_id_allocator.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface_dependency_tracker.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/compositor_frame_helpers.h"
+#include "components/viz/test/fake_external_begin_frame_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+namespace {
+
+constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
+constexpr bool kIsRoot = true;
+constexpr bool kNeedsSyncPoints = true;
+
+TEST(SurfaceTest, SurfaceLifetime) {
+ FrameSinkManagerImpl frame_sink_manager(
+ SurfaceManager::LifetimeType::SEQUENCES);
+ SurfaceManager* surface_manager = frame_sink_manager.surface_manager();
+ auto support = CompositorFrameSinkSupport::Create(
+ nullptr, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot,
+ kNeedsSyncPoints);
+
+ LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
+ SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
+ support->SubmitCompositorFrame(local_surface_id, test::MakeCompositorFrame());
+ EXPECT_TRUE(surface_manager->GetSurfaceForId(surface_id));
+ support->EvictCurrentSurface();
+
+ EXPECT_EQ(NULL, surface_manager->GetSurfaceForId(surface_id));
+}
+
+TEST(SurfaceTest, SurfaceIds) {
+ for (size_t i = 0; i < 3; ++i) {
+ LocalSurfaceIdAllocator allocator;
+ LocalSurfaceId id1 = allocator.GenerateId();
+ LocalSurfaceId id2 = allocator.GenerateId();
+ EXPECT_NE(id1, id2);
+ }
+}
+
+void TestCopyResultCallback(bool* called,
+ std::unique_ptr<CopyOutputResult> result) {
+ *called = true;
+}
+
+// Test that CopyOutputRequests can outlive the current frame and be
+// aggregated on the next frame.
+TEST(SurfaceTest, CopyRequestLifetime) {
+ FrameSinkManagerImpl frame_sink_manager;
+ SurfaceManager* surface_manager = frame_sink_manager.surface_manager();
+ auto support = CompositorFrameSinkSupport::Create(
+ nullptr, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot,
+ kNeedsSyncPoints);
+
+ LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
+ SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
+ cc::CompositorFrame frame = test::MakeCompositorFrame();
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame));
+ Surface* surface = surface_manager->GetSurfaceForId(surface_id);
+ ASSERT_TRUE(!!surface);
+
+ bool copy_called = false;
+ support->RequestCopyOfSurface(CopyOutputRequest::CreateRequest(
+ base::BindOnce(&TestCopyResultCallback, &copy_called)));
+ EXPECT_TRUE(surface_manager->GetSurfaceForId(surface_id));
+ EXPECT_FALSE(copy_called);
+
+ int max_frame = 3, start_id = 200;
+ for (int i = 0; i < max_frame; ++i) {
+ cc::CompositorFrame frame = test::MakeEmptyCompositorFrame();
+ frame.render_pass_list.push_back(cc::RenderPass::Create());
+ frame.render_pass_list.back()->id = i * 3 + start_id;
+ frame.render_pass_list.push_back(cc::RenderPass::Create());
+ frame.render_pass_list.back()->id = i * 3 + start_id + 1;
+ frame.render_pass_list.push_back(cc::RenderPass::Create());
+ frame.render_pass_list.back()->SetNew(i * 3 + start_id + 2,
+ gfx::Rect(0, 0, 20, 20), gfx::Rect(),
+ gfx::Transform());
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame));
+ }
+
+ int last_pass_id = (max_frame - 1) * 3 + start_id + 2;
+ // The copy request should stay on the Surface until TakeCopyOutputRequests
+ // is called.
+ EXPECT_FALSE(copy_called);
+ EXPECT_EQ(
+ 1u,
+ surface->GetActiveFrame().render_pass_list.back()->copy_requests.size());
+
+ Surface::CopyRequestsMap copy_requests;
+ surface->TakeCopyOutputRequests(&copy_requests);
+ EXPECT_EQ(1u, copy_requests.size());
+ // Last (root) pass should receive copy request.
+ ASSERT_EQ(1u, copy_requests.count(last_pass_id));
+ EXPECT_FALSE(copy_called);
+ copy_requests.find(last_pass_id)->second->SendEmptyResult();
+ EXPECT_TRUE(copy_called);
+
+ support->EvictCurrentSurface();
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/test/BUILD.gn b/chromium/components/viz/test/BUILD.gn
index 91e0425cddb..4c379db0a1e 100644
--- a/chromium/components/viz/test/BUILD.gn
+++ b/chromium/components/viz/test/BUILD.gn
@@ -7,16 +7,42 @@ import("//components/viz/viz.gni")
viz_static_library("test_support") {
testonly = true
sources = [
+ "begin_frame_args_test.cc",
+ "begin_frame_args_test.h",
+ "begin_frame_source_test.cc",
+ "begin_frame_source_test.h",
+ "compositor_frame_helpers.cc",
+ "compositor_frame_helpers.h",
+ "fake_delay_based_time_source.cc",
+ "fake_delay_based_time_source.h",
+ "fake_external_begin_frame_source.cc",
+ "fake_external_begin_frame_source.h",
+ "fake_surface_observer.cc",
+ "fake_surface_observer.h",
+ "mock_compositor_frame_sink_support_client.cc",
+ "mock_compositor_frame_sink_support_client.h",
+ "mock_helper.h",
+ "ordered_simple_task_runner.cc",
+ "ordered_simple_task_runner.h",
"paths.cc",
"paths.h",
+ "surface_hittest_test_helpers.cc",
+ "surface_hittest_test_helpers.h",
+ "test_frame_sink_manager.cc",
+ "test_frame_sink_manager.h",
+ "test_gpu_memory_buffer_manager.cc",
+ "test_gpu_memory_buffer_manager.h",
"test_layer_tree_frame_sink.cc",
"test_layer_tree_frame_sink.h",
]
deps = [
"//base",
+ "//base/test:test_support",
"//cc",
- "//cc/surfaces",
"//components/viz/service",
+ "//services/viz/privileged/interfaces/compositing",
+ "//testing/gmock",
+ "//testing/gtest",
"//ui/gfx/geometry",
]
}
@@ -34,3 +60,19 @@ viz_source_set("test_suite") {
"//ui/gl:test_support",
]
}
+
+viz_source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "begin_frame_source_test_unittest.cc",
+ "mock_helper_unittest.cc",
+ "ordered_simple_task_runner_unittest.cc",
+ ]
+ deps = [
+ ":test_support",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.cc b/chromium/components/wallpaper/wallpaper_manager_base.cc
index f048b0ca984..d26cc5a22a5 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.cc
+++ b/chromium/components/wallpaper/wallpaper_manager_base.cc
@@ -58,11 +58,6 @@ const unsigned kLoadMaxDelayMs = 2000;
// color.
const SkColor kDefaultWallpaperColor = SK_ColorGRAY;
-#if DCHECK_IS_ON()
-base::LazyInstance<base::SequenceChecker>::Leaky g_wallpaper_sequence_checker =
- LAZY_INSTANCE_INITIALIZER;
-#endif
-
// The path ids for directories.
int dir_user_data_path_id = -1; // chrome::DIR_USER_DATA
int dir_chromeos_wallpapers_path_id = -1; // chrome::DIR_CHROMEOS_WALLPAPERS
@@ -136,9 +131,9 @@ MovableOnDestroyCallback::~MovableOnDestroyCallback() {
callback_.Run();
}
-void AssertCalledOnWallpaperSequence() {
+void AssertCalledOnWallpaperSequence(base::SequencedTaskRunner* task_runner) {
#if DCHECK_IS_ON()
- DCHECK(g_wallpaper_sequence_checker.Get().CalledOnValidSequence());
+ DCHECK(task_runner->RunsTasksInCurrentSequence());
#endif
}
@@ -593,15 +588,6 @@ void WallpaperManagerBase::InitInitialUserWallpaper(const AccountId& account_id,
current_user_wallpaper_info_.type = DEFAULT;
current_user_wallpaper_info_.date = base::Time::Now().LocalMidnight();
- std::string device_wallpaper_url;
- std::string device_wallpaper_hash;
- if (ShouldSetDeviceWallpaper(account_id, &device_wallpaper_url,
- &device_wallpaper_hash)) {
- current_user_wallpaper_info_.location =
- GetDeviceWallpaperFilePath().value();
- current_user_wallpaper_info_.type = DEVICE;
- }
-
WallpaperInfo info = current_user_wallpaper_info_;
SetUserWallpaperInfo(account_id, info, is_persistent);
}
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.h b/chromium/components/wallpaper/wallpaper_manager_base.h
index 7fae834761a..5b9ce3f105e 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.h
+++ b/chromium/components/wallpaper/wallpaper_manager_base.h
@@ -7,12 +7,12 @@
#include <stddef.h>
-#include <deque>
#include <map>
#include <memory>
#include <string>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
@@ -59,7 +59,8 @@ using MovableOnDestroyCallbackHolder =
// Asserts that the current task is sequenced with any other task that calls
// this.
-void WALLPAPER_EXPORT AssertCalledOnWallpaperSequence();
+void WALLPAPER_EXPORT
+AssertCalledOnWallpaperSequence(base::SequencedTaskRunner* task_runner);
class WallpaperManagerBrowserTest;
@@ -599,7 +600,7 @@ class WALLPAPER_EXPORT WallpaperManagerBase {
base::Time last_load_finished_at_;
// last N wallpaper loads times.
- std::deque<base::TimeDelta> last_load_times_;
+ base::circular_deque<base::TimeDelta> last_load_times_;
base::FilePath default_small_wallpaper_file_;
base::FilePath default_large_wallpaper_file_;
diff --git a/chromium/components/wallpaper/wallpaper_resizer_unittest.cc b/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
index 553f54d9800..3b5d0161c8c 100644
--- a/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
+++ b/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
@@ -9,6 +9,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread.h"
@@ -84,12 +85,16 @@ class WallpaperResizerTest : public testing::Test,
return worker_thread_.task_runner();
}
- void WaitForResize() { base::RunLoop().Run(); }
+ void WaitForResize() {
+ active_runloop_ = base::MakeUnique<base::RunLoop>();
+ active_runloop_->Run();
+ }
- void OnWallpaperResized() override { message_loop_.QuitWhenIdle(); }
+ void OnWallpaperResized() override { active_runloop_->Quit(); }
private:
base::MessageLoop message_loop_;
+ std::unique_ptr<base::RunLoop> active_runloop_;
base::Thread worker_thread_;
DISALLOW_COPY_AND_ASSIGN(WallpaperResizerTest);
diff --git a/chromium/components/web_contents_delegate_android/BUILD.gn b/chromium/components/web_contents_delegate_android/BUILD.gn
index 988af1004e9..a76616470a0 100644
--- a/chromium/components/web_contents_delegate_android/BUILD.gn
+++ b/chromium/components/web_contents_delegate_android/BUILD.gn
@@ -4,6 +4,56 @@
import("//build/config/android/rules.gni")
+java_strings_grd("web_contents_delegate_android_strings_grd") {
+ grd_file = "java/strings/web_contents_delegate_android_strings.grd"
+ outputs = [
+ "values-am/web_contents_delegate_android_strings.xml",
+ "values-ar/web_contents_delegate_android_strings.xml",
+ "values-bg/web_contents_delegate_android_strings.xml",
+ "values-ca/web_contents_delegate_android_strings.xml",
+ "values-cs/web_contents_delegate_android_strings.xml",
+ "values-da/web_contents_delegate_android_strings.xml",
+ "values-de/web_contents_delegate_android_strings.xml",
+ "values-el/web_contents_delegate_android_strings.xml",
+ "values/web_contents_delegate_android_strings.xml",
+ "values-en-rGB/web_contents_delegate_android_strings.xml",
+ "values-es/web_contents_delegate_android_strings.xml",
+ "values-es-rUS/web_contents_delegate_android_strings.xml",
+ "values-fa/web_contents_delegate_android_strings.xml",
+ "values-fi/web_contents_delegate_android_strings.xml",
+ "values-tl/web_contents_delegate_android_strings.xml",
+ "values-fr/web_contents_delegate_android_strings.xml",
+ "values-hi/web_contents_delegate_android_strings.xml",
+ "values-hr/web_contents_delegate_android_strings.xml",
+ "values-hu/web_contents_delegate_android_strings.xml",
+ "values-in/web_contents_delegate_android_strings.xml",
+ "values-it/web_contents_delegate_android_strings.xml",
+ "values-iw/web_contents_delegate_android_strings.xml",
+ "values-ja/web_contents_delegate_android_strings.xml",
+ "values-ko/web_contents_delegate_android_strings.xml",
+ "values-lt/web_contents_delegate_android_strings.xml",
+ "values-lv/web_contents_delegate_android_strings.xml",
+ "values-nl/web_contents_delegate_android_strings.xml",
+ "values-nb/web_contents_delegate_android_strings.xml",
+ "values-pl/web_contents_delegate_android_strings.xml",
+ "values-pt-rBR/web_contents_delegate_android_strings.xml",
+ "values-pt-rPT/web_contents_delegate_android_strings.xml",
+ "values-ro/web_contents_delegate_android_strings.xml",
+ "values-ru/web_contents_delegate_android_strings.xml",
+ "values-sk/web_contents_delegate_android_strings.xml",
+ "values-sl/web_contents_delegate_android_strings.xml",
+ "values-sr/web_contents_delegate_android_strings.xml",
+ "values-sv/web_contents_delegate_android_strings.xml",
+ "values-sw/web_contents_delegate_android_strings.xml",
+ "values-th/web_contents_delegate_android_strings.xml",
+ "values-tr/web_contents_delegate_android_strings.xml",
+ "values-uk/web_contents_delegate_android_strings.xml",
+ "values-vi/web_contents_delegate_android_strings.xml",
+ "values-zh-rCN/web_contents_delegate_android_strings.xml",
+ "values-zh-rTW/web_contents_delegate_android_strings.xml",
+ ]
+}
+
static_library("web_contents_delegate_android") {
sources = [
"color_chooser_android.cc",
@@ -30,9 +80,9 @@ static_library("web_contents_delegate_android") {
android_resources("web_contents_delegate_android_java_resources") {
custom_package = "org.chromium.components.web_contents_delegate_android"
- resource_dirs = [ "android/java/res" ]
+ resource_dirs = [ "java/res" ]
deps = [
- "//components/strings:components_strings_grd",
+ ":web_contents_delegate_android_strings_grd",
]
}
@@ -44,25 +94,25 @@ android_library("web_contents_delegate_android_java") {
"//ui/android:ui_java",
]
java_files = [
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ValidationMessageBubble.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ValidationMessageBubble.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java",
]
}
generate_jni("web_contents_delegate_android_jni_headers") {
sources = [
- "android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/ValidationMessageBubble.java",
- "android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/ValidationMessageBubble.java",
+ "java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java",
]
jni_package = "web_contents_delegate_android"
}
diff --git a/chromium/components/web_contents_delegate_android/DEPS b/chromium/components/web_contents_delegate_android/DEPS
index 560840d67c2..01cb852e355 100644
--- a/chromium/components/web_contents_delegate_android/DEPS
+++ b/chromium/components/web_contents_delegate_android/DEPS
@@ -4,5 +4,5 @@ include_rules = [
"+jni",
"+ui/android",
"+ui/base",
- "+ui/gfx",
+ "+ui/gfx"
]
diff --git a/chromium/components/web_contents_delegate_android/android/DEPS b/chromium/components/web_contents_delegate_android/java/DEPS
index 45a78e4e2ce..45a78e4e2ce 100644
--- a/chromium/components/web_contents_delegate_android/android/DEPS
+++ b/chromium/components/web_contents_delegate_android/java/DEPS
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble.9.png b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble.9.png
index c487c9d45f2..c487c9d45f2 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble.9.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble.9.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble_arrow_up.png b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble_arrow_up.png
index b7f8013d461..b7f8013d461 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/bubble_arrow_up.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/bubble_arrow_up.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png
index 3994d635773..3994d635773 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/ic_warning.png b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/ic_warning.png
index 4214af1c7eb..4214af1c7eb 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-hdpi/ic_warning.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-hdpi/ic_warning.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble.9.png b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble.9.png
index 5b2e94fd5a4..5b2e94fd5a4 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble.9.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble.9.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble_arrow_up.png b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble_arrow_up.png
index f61783be5ec..f61783be5ec 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/bubble_arrow_up.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/bubble_arrow_up.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png
index 0ba0946f91d..0ba0946f91d 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/ic_warning.png b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/ic_warning.png
index 4faea06108d..4faea06108d 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-mdpi/ic_warning.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-mdpi/ic_warning.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble.9.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble.9.png
index f0aba155cb4..f0aba155cb4 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble.9.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble.9.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble_arrow_up.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble_arrow_up.png
index dd7b403c6ef..dd7b403c6ef 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/bubble_arrow_up.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/bubble_arrow_up.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png
index 1d00ca6f3b6..1d00ca6f3b6 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/ic_warning.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/ic_warning.png
index 74313343b34..74313343b34 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xhdpi/ic_warning.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xhdpi/ic_warning.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xxhdpi/ic_warning.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xxhdpi/ic_warning.png
index 5a663ce003e..5a663ce003e 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xxhdpi/ic_warning.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xxhdpi/ic_warning.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi/ic_warning.png b/chromium/components/web_contents_delegate_android/java/res/drawable-xxxhdpi/ic_warning.png
index 755d81d38cf..755d81d38cf 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi/ic_warning.png
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable-xxxhdpi/ic_warning.png
Binary files differ
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable/color_button_background.xml b/chromium/components/web_contents_delegate_android/java/res/drawable/color_button_background.xml
index 66bcce2e4d2..66bcce2e4d2 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable/color_button_background.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable/color_button_background.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/drawable/color_picker_border.xml b/chromium/components/web_contents_delegate_android/java/res/drawable/color_picker_border.xml
index 6cd6bbfbd68..6cd6bbfbd68 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/drawable/color_picker_border.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/drawable/color_picker_border.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_advanced_component.xml b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_advanced_component.xml
index a51c055b1b1..a51c055b1b1 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_advanced_component.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_advanced_component.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_content.xml b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml
index 552b27c66f3..552b27c66f3 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_content.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_title.xml b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_title.xml
index 52aa08eb8fb..52aa08eb8fb 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/layout/color_picker_dialog_title.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_title.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/layout/validation_message_bubble.xml b/chromium/components/web_contents_delegate_android/java/res/layout/validation_message_bubble.xml
index 5277e8085ac..5277e8085ac 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/layout/validation_message_bubble.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/layout/validation_message_bubble.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/values/colors.xml b/chromium/components/web_contents_delegate_android/java/res/values/colors.xml
index 4e3b0fbfdd8..4e3b0fbfdd8 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/values/colors.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/values/colors.xml
diff --git a/chromium/components/web_contents_delegate_android/android/java/res/values/dimens.xml b/chromium/components/web_contents_delegate_android/java/res/values/dimens.xml
index 92c60b10245..92c60b10245 100644
--- a/chromium/components/web_contents_delegate_android/android/java/res/values/dimens.xml
+++ b/chromium/components/web_contents_delegate_android/java/res/values/dimens.xml
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb
new file mode 100644
index 00000000000..b97457bb5d8
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+<translation id="1555130319947370107">ሰማያዊ</translation>
+<translation id="161042844686301425">ውሃ ሰማያዊ</translation>
+<translation id="2713444072780614174">ነጭ</translation>
+<translation id="3329013043687509092">የቀለም ሙሌት</translation>
+<translation id="4115378294792113321">ሮዝ</translation>
+<translation id="5901630391730855834">ቢጫ</translation>
+<translation id="6017514345406065928">አረንጓዴ</translation>
+<translation id="6042308850641462728">ተጨማሪ</translation>
+<translation id="6727102863431372879">አዘጋጅ</translation>
+<translation id="7535087603100972091">እሴት</translation>
+<translation id="7569983096843329377">ጥቁር</translation>
+<translation id="7658239707568436148">ይቅር</translation>
+<translation id="7942349550061667556">ቀይ</translation>
+<translation id="8889402386540077796">ለይ ቀለም</translation>
+<translation id="9068849894565669697">ቀለም ይምረጡ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb
new file mode 100644
index 00000000000..014ab4cb108
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+<translation id="1555130319947370107">أزرق</translation>
+<translation id="161042844686301425">سماوي</translation>
+<translation id="2713444072780614174">أبيض</translation>
+<translation id="3329013043687509092">تشبع اللون</translation>
+<translation id="4115378294792113321">أرجواني</translation>
+<translation id="5901630391730855834">أصفر</translation>
+<translation id="6017514345406065928">أخضر</translation>
+<translation id="6042308850641462728">المزيد</translation>
+<translation id="6727102863431372879">تعيين</translation>
+<translation id="7535087603100972091">القيمة</translation>
+<translation id="7569983096843329377">أسود</translation>
+<translation id="7658239707568436148">إلغاء</translation>
+<translation id="7942349550061667556">أحمر</translation>
+<translation id="8889402386540077796">تدرج اللون</translation>
+<translation id="9068849894565669697">اختيار اللون</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb
new file mode 100644
index 00000000000..66a42e7da39
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+<translation id="1555130319947370107">синьо</translation>
+<translation id="161042844686301425">синьозелено</translation>
+<translation id="2713444072780614174">бяло</translation>
+<translation id="3329013043687509092">Насищане</translation>
+<translation id="4115378294792113321">пурпурно</translation>
+<translation id="5901630391730855834">жълто</translation>
+<translation id="6017514345406065928">зелено</translation>
+<translation id="6042308850641462728">Още</translation>
+<translation id="6727102863431372879">Задаване</translation>
+<translation id="7535087603100972091">Стойност</translation>
+<translation id="7569983096843329377">черно</translation>
+<translation id="7658239707568436148">Отказ</translation>
+<translation id="7942349550061667556">червено</translation>
+<translation id="8889402386540077796">Цветови тон</translation>
+<translation id="9068849894565669697">Избор на цвят</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb
new file mode 100644
index 00000000000..dce1297ba40
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+<translation id="1555130319947370107">Blau</translation>
+<translation id="161042844686301425">Cian</translation>
+<translation id="2713444072780614174">Blanc</translation>
+<translation id="3329013043687509092">Saturació</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Groc</translation>
+<translation id="6017514345406065928">Verd</translation>
+<translation id="6042308850641462728">Més</translation>
+<translation id="6727102863431372879">Configura</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="7569983096843329377">Negre</translation>
+<translation id="7658239707568436148">Cancel·la</translation>
+<translation id="7942349550061667556">Vermell</translation>
+<translation id="8889402386540077796">To</translation>
+<translation id="9068849894565669697">Selecció de color</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb
new file mode 100644
index 00000000000..1b8d8388c83
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+<translation id="1555130319947370107">Modrá</translation>
+<translation id="161042844686301425">Azurová</translation>
+<translation id="2713444072780614174">Bílá</translation>
+<translation id="3329013043687509092">Sytost</translation>
+<translation id="4115378294792113321">Purpurová</translation>
+<translation id="5901630391730855834">Žlutá</translation>
+<translation id="6017514345406065928">Zelená</translation>
+<translation id="6042308850641462728">Více</translation>
+<translation id="6727102863431372879">Nastavit</translation>
+<translation id="7535087603100972091">Hodnota</translation>
+<translation id="7569983096843329377">Černá</translation>
+<translation id="7658239707568436148">Zrušit</translation>
+<translation id="7942349550061667556">Červená</translation>
+<translation id="8889402386540077796">Odstín</translation>
+<translation id="9068849894565669697">Výběr barvy</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb
new file mode 100644
index 00000000000..1e8dad8510b
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+<translation id="1555130319947370107">Blå</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Hvid</translation>
+<translation id="3329013043687509092">Mætning</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Gul</translation>
+<translation id="6017514345406065928">Grøn</translation>
+<translation id="6042308850641462728">Mere</translation>
+<translation id="6727102863431372879">Angiv</translation>
+<translation id="7535087603100972091">Værdi</translation>
+<translation id="7569983096843329377">Sort</translation>
+<translation id="7658239707568436148">Annuller</translation>
+<translation id="7942349550061667556">Rød</translation>
+<translation id="8889402386540077796">Farvetone</translation>
+<translation id="9068849894565669697">Vælg farve</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb
new file mode 100644
index 00000000000..c8a6c550320
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+<translation id="1555130319947370107">Blau</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Weiß</translation>
+<translation id="3329013043687509092">Sättigung</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Gelb</translation>
+<translation id="6017514345406065928">Grün</translation>
+<translation id="6042308850641462728">Mehr</translation>
+<translation id="6727102863431372879">Festlegen</translation>
+<translation id="7535087603100972091">Wert</translation>
+<translation id="7569983096843329377">Schwarz</translation>
+<translation id="7658239707568436148">Abbrechen</translation>
+<translation id="7942349550061667556">Rot</translation>
+<translation id="8889402386540077796">Farbton</translation>
+<translation id="9068849894565669697">Farbe auswählen</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb
new file mode 100644
index 00000000000..46782d2f55e
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+<translation id="1555130319947370107">Μπλε</translation>
+<translation id="161042844686301425">Κυανό</translation>
+<translation id="2713444072780614174">Λευκό</translation>
+<translation id="3329013043687509092">Κορεσμός</translation>
+<translation id="4115378294792113321">Ματζέντα</translation>
+<translation id="5901630391730855834">Κίτρινο</translation>
+<translation id="6017514345406065928">Πράσινο</translation>
+<translation id="6042308850641462728">Περισσότερα</translation>
+<translation id="6727102863431372879">Ορισμός</translation>
+<translation id="7535087603100972091">Τιμή</translation>
+<translation id="7569983096843329377">Μαύρο</translation>
+<translation id="7658239707568436148">Ακύρωση</translation>
+<translation id="7942349550061667556">Κόκκινο</translation>
+<translation id="8889402386540077796">Απόχρωση</translation>
+<translation id="9068849894565669697">Επιλογή χρώματος</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb
new file mode 100644
index 00000000000..d6ec75b4772
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+<translation id="1555130319947370107">Blue</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">White</translation>
+<translation id="3329013043687509092">Saturation</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Yellow</translation>
+<translation id="6017514345406065928">Green</translation>
+<translation id="6042308850641462728">More</translation>
+<translation id="6727102863431372879">Set</translation>
+<translation id="7535087603100972091">Value</translation>
+<translation id="7569983096843329377">Black</translation>
+<translation id="7658239707568436148">Cancel</translation>
+<translation id="7942349550061667556">Red</translation>
+<translation id="8889402386540077796">Hue</translation>
+<translation id="9068849894565669697">Select colour</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb
new file mode 100644
index 00000000000..77c880444b6
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+<translation id="1555130319947370107">Azul</translation>
+<translation id="161042844686301425">Cian</translation>
+<translation id="2713444072780614174">Blanco</translation>
+<translation id="3329013043687509092">Saturación</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Amarillo</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Más</translation>
+<translation id="6727102863431372879">Establecer</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="7569983096843329377">Negro</translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7942349550061667556">Rojo</translation>
+<translation id="8889402386540077796">Tono</translation>
+<translation id="9068849894565669697">Seleccionar color</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb
new file mode 100644
index 00000000000..d5f44cb867e
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+<translation id="1555130319947370107">Azul</translation>
+<translation id="161042844686301425">Cian</translation>
+<translation id="2713444072780614174">Blanco</translation>
+<translation id="3329013043687509092">Saturación</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Amarillo</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Más</translation>
+<translation id="6727102863431372879">Establecer</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="7569983096843329377">Negro</translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7942349550061667556">Rojo</translation>
+<translation id="8889402386540077796">Matiz</translation>
+<translation id="9068849894565669697">Seleccionar color</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb
new file mode 100644
index 00000000000..374834152a7
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fa">
+<translation id="1555130319947370107">آبی</translation>
+<translation id="161042844686301425">فیروزه‌ای</translation>
+<translation id="2713444072780614174">سفید</translation>
+<translation id="3329013043687509092">اشباع رنگ</translation>
+<translation id="4115378294792113321">سرخابی</translation>
+<translation id="5901630391730855834">زرد</translation>
+<translation id="6017514345406065928">سبز</translation>
+<translation id="6042308850641462728">بیشتر</translation>
+<translation id="6727102863431372879">تنظیم</translation>
+<translation id="7535087603100972091">مقدار</translation>
+<translation id="7569983096843329377">سیاه</translation>
+<translation id="7658239707568436148">لغو</translation>
+<translation id="7942349550061667556">قرمز</translation>
+<translation id="8889402386540077796">رنگ‌مایه</translation>
+<translation id="9068849894565669697">انتخاب رنگ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb
new file mode 100644
index 00000000000..6c0fff99a44
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+<translation id="1555130319947370107">Sininen</translation>
+<translation id="161042844686301425">Turkoosi</translation>
+<translation id="2713444072780614174">Valkoinen</translation>
+<translation id="3329013043687509092">Värikylläisyys</translation>
+<translation id="4115378294792113321">Purppura</translation>
+<translation id="5901630391730855834">Keltainen</translation>
+<translation id="6017514345406065928">Vihreä</translation>
+<translation id="6042308850641462728">Lisää</translation>
+<translation id="6727102863431372879">Aseta</translation>
+<translation id="7535087603100972091">Arvo</translation>
+<translation id="7569983096843329377">Musta</translation>
+<translation id="7658239707568436148">Peruuta</translation>
+<translation id="7942349550061667556">Punainen</translation>
+<translation id="8889402386540077796">Sävy</translation>
+<translation id="9068849894565669697">Valitse väri</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb
new file mode 100644
index 00000000000..38fd3acb352
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+<translation id="1555130319947370107">Asul</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Puti</translation>
+<translation id="3329013043687509092">Saturation</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Dilaw</translation>
+<translation id="6017514345406065928">Berde</translation>
+<translation id="6042308850641462728">Higit pa</translation>
+<translation id="6727102863431372879">Itakda</translation>
+<translation id="7535087603100972091">Value</translation>
+<translation id="7569983096843329377">Itim</translation>
+<translation id="7658239707568436148">Ikansela</translation>
+<translation id="7942349550061667556">Pula</translation>
+<translation id="8889402386540077796">Hue</translation>
+<translation id="9068849894565669697">Pumili ng kulay</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb
new file mode 100644
index 00000000000..79702bfdb8f
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+<translation id="1555130319947370107">Bleu</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Blanc</translation>
+<translation id="3329013043687509092">Saturation</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Jaune</translation>
+<translation id="6017514345406065928">Vert</translation>
+<translation id="6042308850641462728">Plus</translation>
+<translation id="6727102863431372879">Définir</translation>
+<translation id="7535087603100972091">Valeur</translation>
+<translation id="7569983096843329377">Noir</translation>
+<translation id="7658239707568436148">Annuler</translation>
+<translation id="7942349550061667556">Rouge</translation>
+<translation id="8889402386540077796">Teinte</translation>
+<translation id="9068849894565669697">Sélectionner couleur</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb
new file mode 100644
index 00000000000..d3d4cc7832a
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+<translation id="1555130319947370107">नीला</translation>
+<translation id="161042844686301425">स्यान</translation>
+<translation id="2713444072780614174">सफ़ेद</translation>
+<translation id="3329013043687509092">संतृप्तता</translation>
+<translation id="4115378294792113321">मैजेंटा</translation>
+<translation id="5901630391730855834">पीला</translation>
+<translation id="6017514345406065928">हरा</translation>
+<translation id="6042308850641462728">अधिक</translation>
+<translation id="6727102863431372879">सेट करें</translation>
+<translation id="7535087603100972091">मान</translation>
+<translation id="7569983096843329377">काला</translation>
+<translation id="7658239707568436148">अभी नहीं</translation>
+<translation id="7942349550061667556">लाल</translation>
+<translation id="8889402386540077796">रंग</translation>
+<translation id="9068849894565669697">रंग चुनें</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb
new file mode 100644
index 00000000000..724d1ecd3b6
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+<translation id="1555130319947370107">Plava</translation>
+<translation id="161042844686301425">Cijan</translation>
+<translation id="2713444072780614174">Bijela</translation>
+<translation id="3329013043687509092">Zasićenje</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Žuta</translation>
+<translation id="6017514345406065928">Zelena</translation>
+<translation id="6042308850641462728">Više</translation>
+<translation id="6727102863431372879">Postavi</translation>
+<translation id="7535087603100972091">Vrijednost</translation>
+<translation id="7569983096843329377">Crna</translation>
+<translation id="7658239707568436148">Odustani</translation>
+<translation id="7942349550061667556">Crvena</translation>
+<translation id="8889402386540077796">Ton</translation>
+<translation id="9068849894565669697">Odaberite boju</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb
new file mode 100644
index 00000000000..a572e7313f4
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+<translation id="1555130319947370107">Kék</translation>
+<translation id="161042844686301425">Cián</translation>
+<translation id="2713444072780614174">Fehér</translation>
+<translation id="3329013043687509092">Telítettség</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Sárga</translation>
+<translation id="6017514345406065928">Zöld</translation>
+<translation id="6042308850641462728">Hosszabban</translation>
+<translation id="6727102863431372879">Beállítás</translation>
+<translation id="7535087603100972091">Érték</translation>
+<translation id="7569983096843329377">Fekete</translation>
+<translation id="7658239707568436148">Mégse</translation>
+<translation id="7942349550061667556">Piros</translation>
+<translation id="8889402386540077796">Színárnyalat</translation>
+<translation id="9068849894565669697">Szín kiválasztása</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb
new file mode 100644
index 00000000000..b476691f85e
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+<translation id="1555130319947370107">Biru</translation>
+<translation id="161042844686301425">Sian</translation>
+<translation id="2713444072780614174">Putih</translation>
+<translation id="3329013043687509092">Saturasi</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Kuning</translation>
+<translation id="6017514345406065928">Hijau</translation>
+<translation id="6042308850641462728">Lainnya</translation>
+<translation id="6727102863431372879">Setel</translation>
+<translation id="7535087603100972091">Nilai</translation>
+<translation id="7569983096843329377">Hitam</translation>
+<translation id="7658239707568436148">Batal</translation>
+<translation id="7942349550061667556">Merah</translation>
+<translation id="8889402386540077796">Rona</translation>
+<translation id="9068849894565669697">Pilih warna</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb
new file mode 100644
index 00000000000..26d68d11395
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+<translation id="1555130319947370107">Blu</translation>
+<translation id="161042844686301425">Ciano</translation>
+<translation id="2713444072780614174">Bianco</translation>
+<translation id="3329013043687509092">Saturazione</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Giallo</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Più</translation>
+<translation id="6727102863431372879">Imposta</translation>
+<translation id="7535087603100972091">Valore</translation>
+<translation id="7569983096843329377">Nero</translation>
+<translation id="7658239707568436148">Annulla</translation>
+<translation id="7942349550061667556">Rosso</translation>
+<translation id="8889402386540077796">Tonalità</translation>
+<translation id="9068849894565669697">Seleziona colore</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb
new file mode 100644
index 00000000000..c9c1c2e3e30
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="iw">
+<translation id="1555130319947370107">כחול</translation>
+<translation id="161042844686301425">ציאן</translation>
+<translation id="2713444072780614174">לבן</translation>
+<translation id="3329013043687509092">רווייה</translation>
+<translation id="4115378294792113321">מגנטה</translation>
+<translation id="5901630391730855834">צהוב</translation>
+<translation id="6017514345406065928">ירוק</translation>
+<translation id="6042308850641462728">עוד</translation>
+<translation id="6727102863431372879">הגדר</translation>
+<translation id="7535087603100972091">ערך</translation>
+<translation id="7569983096843329377">שחור</translation>
+<translation id="7658239707568436148">ביטול</translation>
+<translation id="7942349550061667556">אדום</translation>
+<translation id="8889402386540077796">גוון</translation>
+<translation id="9068849894565669697">בחירת צבע</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb
new file mode 100644
index 00000000000..2c5bdc05451
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+<translation id="1555130319947370107">青</translation>
+<translation id="161042844686301425">シアン</translation>
+<translation id="2713444072780614174">白</translation>
+<translation id="3329013043687509092">彩度</translation>
+<translation id="4115378294792113321">マゼンタ</translation>
+<translation id="5901630391730855834">黄</translation>
+<translation id="6017514345406065928">緑</translation>
+<translation id="6042308850641462728">もっと見る</translation>
+<translation id="6727102863431372879">設定</translation>
+<translation id="7535087603100972091">値</translation>
+<translation id="7569983096843329377">黒</translation>
+<translation id="7658239707568436148">キャンセル</translation>
+<translation id="7942349550061667556">赤</translation>
+<translation id="8889402386540077796">色調</translation>
+<translation id="9068849894565669697">色の選択</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb
new file mode 100644
index 00000000000..6970fc9d28e
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+<translation id="1555130319947370107">파란색</translation>
+<translation id="161042844686301425">청록색</translation>
+<translation id="2713444072780614174">흰색</translation>
+<translation id="3329013043687509092">채도</translation>
+<translation id="4115378294792113321">자홍색</translation>
+<translation id="5901630391730855834">노란색</translation>
+<translation id="6017514345406065928">녹색</translation>
+<translation id="6042308850641462728">더보기</translation>
+<translation id="6727102863431372879">설정</translation>
+<translation id="7535087603100972091">값</translation>
+<translation id="7569983096843329377">검정색</translation>
+<translation id="7658239707568436148">취소</translation>
+<translation id="7942349550061667556">빨간색</translation>
+<translation id="8889402386540077796">색조</translation>
+<translation id="9068849894565669697">색상 선택</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb
new file mode 100644
index 00000000000..4f2e4d1b650
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+<translation id="1555130319947370107">Mėlyna</translation>
+<translation id="161042844686301425">Žydra</translation>
+<translation id="2713444072780614174">Balta</translation>
+<translation id="3329013043687509092">Spalvų sodrumas</translation>
+<translation id="4115378294792113321">Purpurinė</translation>
+<translation id="5901630391730855834">Geltona</translation>
+<translation id="6017514345406065928">Žalia</translation>
+<translation id="6042308850641462728">Daugiau</translation>
+<translation id="6727102863431372879">Nustatyti</translation>
+<translation id="7535087603100972091">Reikšmė</translation>
+<translation id="7569983096843329377">Juoda</translation>
+<translation id="7658239707568436148">Atšaukti</translation>
+<translation id="7942349550061667556">Raudona</translation>
+<translation id="8889402386540077796">Spalva</translation>
+<translation id="9068849894565669697">Pasirinkite spalvą</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb
new file mode 100644
index 00000000000..aa5d59cb277
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+<translation id="1555130319947370107">Zila</translation>
+<translation id="161042844686301425">Ciānzila</translation>
+<translation id="2713444072780614174">Balta</translation>
+<translation id="3329013043687509092">Piesātinājums</translation>
+<translation id="4115378294792113321">Fuksīnsarkana</translation>
+<translation id="5901630391730855834">Dzeltena</translation>
+<translation id="6017514345406065928">Zaļa</translation>
+<translation id="6042308850641462728">Vairāk</translation>
+<translation id="6727102863431372879">Iestatīt</translation>
+<translation id="7535087603100972091">Vērtība</translation>
+<translation id="7569983096843329377">Melna</translation>
+<translation id="7658239707568436148">Atcelt</translation>
+<translation id="7942349550061667556">Sarkana</translation>
+<translation id="8889402386540077796">Nokrāsa</translation>
+<translation id="9068849894565669697">Krāsas izvēle</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb
new file mode 100644
index 00000000000..dbc50fdaa53
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+<translation id="1555130319947370107">Blauw</translation>
+<translation id="161042844686301425">Cyaan</translation>
+<translation id="2713444072780614174">Wit</translation>
+<translation id="3329013043687509092">Verzadiging</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Geel</translation>
+<translation id="6017514345406065928">Groen</translation>
+<translation id="6042308850641462728">Meer</translation>
+<translation id="6727102863431372879">Instellen</translation>
+<translation id="7535087603100972091">Waarde</translation>
+<translation id="7569983096843329377">Zwart</translation>
+<translation id="7658239707568436148">Annuleren</translation>
+<translation id="7942349550061667556">Rood</translation>
+<translation id="8889402386540077796">Kleurtoon</translation>
+<translation id="9068849894565669697">Kleur selecteren</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb
new file mode 100644
index 00000000000..abb6d313cdd
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+<translation id="1555130319947370107">Blå</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Hvit</translation>
+<translation id="3329013043687509092">Metning</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Gul</translation>
+<translation id="6017514345406065928">Grønn</translation>
+<translation id="6042308850641462728">Mer</translation>
+<translation id="6727102863431372879">Angi</translation>
+<translation id="7535087603100972091">Verdi</translation>
+<translation id="7569983096843329377">Svart</translation>
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7942349550061667556">Rød</translation>
+<translation id="8889402386540077796">Fargetone</translation>
+<translation id="9068849894565669697">Velg farge</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb
new file mode 100644
index 00000000000..75dfdd640b5
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+<translation id="1555130319947370107">Niebieski</translation>
+<translation id="161042844686301425">Cyjan</translation>
+<translation id="2713444072780614174">Biały</translation>
+<translation id="3329013043687509092">Nasycenie</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Żółty</translation>
+<translation id="6017514345406065928">Zielony</translation>
+<translation id="6042308850641462728">Więcej</translation>
+<translation id="6727102863431372879">Ustaw</translation>
+<translation id="7535087603100972091">Wartość</translation>
+<translation id="7569983096843329377">Czarny</translation>
+<translation id="7658239707568436148">Anuluj</translation>
+<translation id="7942349550061667556">Czerwony</translation>
+<translation id="8889402386540077796">Odcień</translation>
+<translation id="9068849894565669697">Wybierz kolor</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb
new file mode 100644
index 00000000000..7eab6e0bbbf
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+<translation id="1555130319947370107">Azul</translation>
+<translation id="161042844686301425">Ciano</translation>
+<translation id="2713444072780614174">Branco</translation>
+<translation id="3329013043687509092">Saturação</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Amarelo</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Mais</translation>
+<translation id="6727102863431372879">Definir</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="7569983096843329377">Preto</translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7942349550061667556">Vermelho</translation>
+<translation id="8889402386540077796">Matiz</translation>
+<translation id="9068849894565669697">Selecionar cor</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb
new file mode 100644
index 00000000000..d86e46d1407
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+<translation id="1555130319947370107">Azul</translation>
+<translation id="161042844686301425">Turquesa</translation>
+<translation id="2713444072780614174">Branco</translation>
+<translation id="3329013043687509092">Saturação</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Amarelo</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Mais</translation>
+<translation id="6727102863431372879">Definir</translation>
+<translation id="7535087603100972091">Valor</translation>
+<translation id="7569983096843329377">Preto</translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7942349550061667556">Vermelho</translation>
+<translation id="8889402386540077796">Tonalidade</translation>
+<translation id="9068849894565669697">Selecionar cor</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb
new file mode 100644
index 00000000000..b3a135a6ef2
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+<translation id="1555130319947370107">Albastru</translation>
+<translation id="161042844686301425">Cyan</translation>
+<translation id="2713444072780614174">Alb</translation>
+<translation id="3329013043687509092">Saturație</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Galben</translation>
+<translation id="6017514345406065928">Verde</translation>
+<translation id="6042308850641462728">Mai multe</translation>
+<translation id="6727102863431372879">Setează</translation>
+<translation id="7535087603100972091">Valoare</translation>
+<translation id="7569983096843329377">Negru</translation>
+<translation id="7658239707568436148">Anulează</translation>
+<translation id="7942349550061667556">Roșu</translation>
+<translation id="8889402386540077796">Nuanță</translation>
+<translation id="9068849894565669697">Selectați culoarea</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb
new file mode 100644
index 00000000000..d93955edcfb
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+<translation id="1555130319947370107">Синий</translation>
+<translation id="161042844686301425">Голубой</translation>
+<translation id="2713444072780614174">Белый</translation>
+<translation id="3329013043687509092">Насыщенность</translation>
+<translation id="4115378294792113321">Пурпурный</translation>
+<translation id="5901630391730855834">Желтый</translation>
+<translation id="6017514345406065928">Зеленый</translation>
+<translation id="6042308850641462728">Подробнее...</translation>
+<translation id="6727102863431372879">Установить</translation>
+<translation id="7535087603100972091">Значение</translation>
+<translation id="7569983096843329377">Черный</translation>
+<translation id="7658239707568436148">Отмена</translation>
+<translation id="7942349550061667556">Красный</translation>
+<translation id="8889402386540077796">Тон</translation>
+<translation id="9068849894565669697">Выберите цвет</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb
new file mode 100644
index 00000000000..f8b1a8595f5
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+<translation id="1555130319947370107">Modrá</translation>
+<translation id="161042844686301425">Azúrová</translation>
+<translation id="2713444072780614174">Biela</translation>
+<translation id="3329013043687509092">Sýtosť</translation>
+<translation id="4115378294792113321">Purpurová</translation>
+<translation id="5901630391730855834">Žltá</translation>
+<translation id="6017514345406065928">Zelená</translation>
+<translation id="6042308850641462728">Viac</translation>
+<translation id="6727102863431372879">Nastaviť</translation>
+<translation id="7535087603100972091">Hodnota</translation>
+<translation id="7569983096843329377">Čierna</translation>
+<translation id="7658239707568436148">Zrušiť</translation>
+<translation id="7942349550061667556">Červená</translation>
+<translation id="8889402386540077796">Odtieň</translation>
+<translation id="9068849894565669697">Výber farby</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb
new file mode 100644
index 00000000000..16b97e7d118
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+<translation id="1555130319947370107">Modra</translation>
+<translation id="161042844686301425">Cianova</translation>
+<translation id="2713444072780614174">Bela</translation>
+<translation id="3329013043687509092">Nasičenost</translation>
+<translation id="4115378294792113321">Škrlatna</translation>
+<translation id="5901630391730855834">Rumena</translation>
+<translation id="6017514345406065928">Zelena</translation>
+<translation id="6042308850641462728">Več</translation>
+<translation id="6727102863431372879">Nastavi</translation>
+<translation id="7535087603100972091">Vrednost</translation>
+<translation id="7569983096843329377">Črna</translation>
+<translation id="7658239707568436148">Prekliči</translation>
+<translation id="7942349550061667556">Rdeča</translation>
+<translation id="8889402386540077796">Odtenek</translation>
+<translation id="9068849894565669697">Izbira barve</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb
new file mode 100644
index 00000000000..b1b1b6e814a
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+<translation id="1555130319947370107">Плава</translation>
+<translation id="161042844686301425">Плавозелена</translation>
+<translation id="2713444072780614174">Бела</translation>
+<translation id="3329013043687509092">Засићеност боја</translation>
+<translation id="4115378294792113321">Циклама</translation>
+<translation id="5901630391730855834">Жута</translation>
+<translation id="6017514345406065928">Зелена</translation>
+<translation id="6042308850641462728">Више</translation>
+<translation id="6727102863431372879">Постави</translation>
+<translation id="7535087603100972091">Вредност</translation>
+<translation id="7569983096843329377">Црна</translation>
+<translation id="7658239707568436148">Откажи</translation>
+<translation id="7942349550061667556">Црвена</translation>
+<translation id="8889402386540077796">Нијанса</translation>
+<translation id="9068849894565669697">Изаберите боју</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb
new file mode 100644
index 00000000000..d82147b35dc
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+<translation id="1555130319947370107">Blå</translation>
+<translation id="161042844686301425">Cyanblå</translation>
+<translation id="2713444072780614174">Vit</translation>
+<translation id="3329013043687509092">Mättnad</translation>
+<translation id="4115378294792113321">Magenta</translation>
+<translation id="5901630391730855834">Gul</translation>
+<translation id="6017514345406065928">Grön</translation>
+<translation id="6042308850641462728">Mer</translation>
+<translation id="6727102863431372879">Ange</translation>
+<translation id="7535087603100972091">Värde</translation>
+<translation id="7569983096843329377">Svart</translation>
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7942349550061667556">Röd</translation>
+<translation id="8889402386540077796">Nyans</translation>
+<translation id="9068849894565669697">Välj färg</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb
new file mode 100644
index 00000000000..ebea446806f
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sw">
+<translation id="1555130319947370107">Samawati</translation>
+<translation id="161042844686301425">Samawati-Kijani</translation>
+<translation id="2713444072780614174">Nyeupe</translation>
+<translation id="3329013043687509092">Kukolea</translation>
+<translation id="4115378294792113321">Rangi ya damu ya mzee</translation>
+<translation id="5901630391730855834">Manjano</translation>
+<translation id="6017514345406065928">Kijani</translation>
+<translation id="6042308850641462728">Zaidi</translation>
+<translation id="6727102863431372879">Weka</translation>
+<translation id="7535087603100972091">Thamani</translation>
+<translation id="7569983096843329377">Nyeusi</translation>
+<translation id="7658239707568436148">Ghairi</translation>
+<translation id="7942349550061667556">Nyekundu</translation>
+<translation id="8889402386540077796">Rangi</translation>
+<translation id="9068849894565669697">Chagua rangi</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb
new file mode 100644
index 00000000000..44f904b2088
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+<translation id="1555130319947370107">สีน้ำเงิน</translation>
+<translation id="161042844686301425">สีฟ้า</translation>
+<translation id="2713444072780614174">สีขาว</translation>
+<translation id="3329013043687509092">ความอิ่มตัวของสี</translation>
+<translation id="4115378294792113321">สีม่วงแดง</translation>
+<translation id="5901630391730855834">สีเหลือง</translation>
+<translation id="6017514345406065928">สีเขียว</translation>
+<translation id="6042308850641462728">เพิ่มเติม</translation>
+<translation id="6727102863431372879">ตั้งค่า</translation>
+<translation id="7535087603100972091">ราคา</translation>
+<translation id="7569983096843329377">สีดำ</translation>
+<translation id="7658239707568436148">ยกเลิก</translation>
+<translation id="7942349550061667556">สีแดง</translation>
+<translation id="8889402386540077796">โทนสี</translation>
+<translation id="9068849894565669697">เลือกสี</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb
new file mode 100644
index 00000000000..8207ecb0e29
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+<translation id="1555130319947370107">Mavi</translation>
+<translation id="161042844686301425">Camgöbeği</translation>
+<translation id="2713444072780614174">Beyaz</translation>
+<translation id="3329013043687509092">Doygunluk</translation>
+<translation id="4115378294792113321">Macenta</translation>
+<translation id="5901630391730855834">Sarı</translation>
+<translation id="6017514345406065928">Yeşil</translation>
+<translation id="6042308850641462728">Daha fazla</translation>
+<translation id="6727102863431372879">Ayarla</translation>
+<translation id="7535087603100972091">Değer</translation>
+<translation id="7569983096843329377">Siyah</translation>
+<translation id="7658239707568436148">İptal</translation>
+<translation id="7942349550061667556">Kırmızı</translation>
+<translation id="8889402386540077796">Ton</translation>
+<translation id="9068849894565669697">Renk seçin</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb
new file mode 100644
index 00000000000..14d5e75061b
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+<translation id="1555130319947370107">Синій</translation>
+<translation id="161042844686301425">Бірюзовий</translation>
+<translation id="2713444072780614174">Білий</translation>
+<translation id="3329013043687509092">Насиченість</translation>
+<translation id="4115378294792113321">Пурпурний</translation>
+<translation id="5901630391730855834">Жовтий</translation>
+<translation id="6017514345406065928">Зелений</translation>
+<translation id="6042308850641462728">Більше</translation>
+<translation id="6727102863431372879">Встановити</translation>
+<translation id="7535087603100972091">Яскравість</translation>
+<translation id="7569983096843329377">Чорний</translation>
+<translation id="7658239707568436148">Скасувати</translation>
+<translation id="7942349550061667556">Червоний</translation>
+<translation id="8889402386540077796">Тон</translation>
+<translation id="9068849894565669697">Вибрати колір</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb
new file mode 100644
index 00000000000..1089abef96f
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+<translation id="1555130319947370107">Xanh lam</translation>
+<translation id="161042844686301425">Lục lam</translation>
+<translation id="2713444072780614174">Trắng</translation>
+<translation id="3329013043687509092">Độ bão hòa</translation>
+<translation id="4115378294792113321">Đỏ thẫm</translation>
+<translation id="5901630391730855834">Vàng</translation>
+<translation id="6017514345406065928">Xanh lục</translation>
+<translation id="6042308850641462728">Thêm</translation>
+<translation id="6727102863431372879">Đặt</translation>
+<translation id="7535087603100972091">Giá trị</translation>
+<translation id="7569983096843329377">Đen</translation>
+<translation id="7658239707568436148">Hủy</translation>
+<translation id="7942349550061667556">Đỏ</translation>
+<translation id="8889402386540077796">Màu sắc</translation>
+<translation id="9068849894565669697">Chọn màu</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb
new file mode 100644
index 00000000000..25dd741eca5
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+<translation id="1555130319947370107">蓝色</translation>
+<translation id="161042844686301425">青色</translation>
+<translation id="2713444072780614174">白色</translation>
+<translation id="3329013043687509092">饱和度</translation>
+<translation id="4115378294792113321">洋红色</translation>
+<translation id="5901630391730855834">黄色</translation>
+<translation id="6017514345406065928">绿色</translation>
+<translation id="6042308850641462728">更多</translation>
+<translation id="6727102863431372879">设置</translation>
+<translation id="7535087603100972091">值</translation>
+<translation id="7569983096843329377">黑色</translation>
+<translation id="7658239707568436148">取消</translation>
+<translation id="7942349550061667556">红色</translation>
+<translation id="8889402386540077796">色调</translation>
+<translation id="9068849894565669697">选择颜色</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb
new file mode 100644
index 00000000000..55275965530
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+<translation id="1555130319947370107">藍色</translation>
+<translation id="161042844686301425">青色</translation>
+<translation id="2713444072780614174">白色</translation>
+<translation id="3329013043687509092">飽和度</translation>
+<translation id="4115378294792113321">洋紅色</translation>
+<translation id="5901630391730855834">黃色</translation>
+<translation id="6017514345406065928">綠色</translation>
+<translation id="6042308850641462728">更多</translation>
+<translation id="6727102863431372879">設定</translation>
+<translation id="7535087603100972091">值</translation>
+<translation id="7569983096843329377">黑色</translation>
+<translation id="7658239707568436148">取消</translation>
+<translation id="7942349550061667556">紅色</translation>
+<translation id="8889402386540077796">色調</translation>
+<translation id="9068849894565669697">選取顏色</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd b/chromium/components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd
new file mode 100644
index 00000000000..fa0a4f4b9b4
--- /dev/null
+++ b/chromium/components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<grit latest_public_release="0" current_release="1"
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
+ <outputs>
+ <output filename="values-am/web_contents_delegate_android_strings.xml" lang="am" type="android" />
+ <output filename="values-ar/web_contents_delegate_android_strings.xml" lang="ar" type="android" />
+ <output filename="values-bg/web_contents_delegate_android_strings.xml" lang="bg" type="android" />
+ <output filename="values-ca/web_contents_delegate_android_strings.xml" lang="ca" type="android" />
+ <output filename="values-cs/web_contents_delegate_android_strings.xml" lang="cs" type="android" />
+ <output filename="values-da/web_contents_delegate_android_strings.xml" lang="da" type="android" />
+ <output filename="values-de/web_contents_delegate_android_strings.xml" lang="de" type="android" />
+ <output filename="values-el/web_contents_delegate_android_strings.xml" lang="el" type="android" />
+ <output filename="values/web_contents_delegate_android_strings.xml" lang="en" type="android" />
+ <output filename="values-en-rGB/web_contents_delegate_android_strings.xml" lang="en-GB" type="android" />
+ <output filename="values-es/web_contents_delegate_android_strings.xml" lang="es" type="android" />
+ <output filename="values-es-rUS/web_contents_delegate_android_strings.xml" lang="es-419" type="android" />
+ <output filename="values-fa/web_contents_delegate_android_strings.xml" lang="fa" type="android" />
+ <output filename="values-fi/web_contents_delegate_android_strings.xml" lang="fi" type="android" />
+ <output filename="values-tl/web_contents_delegate_android_strings.xml" lang="fil" type="android" />
+ <output filename="values-fr/web_contents_delegate_android_strings.xml" lang="fr" type="android" />
+ <output filename="values-hi/web_contents_delegate_android_strings.xml" lang="hi" type="android" />
+ <output filename="values-hr/web_contents_delegate_android_strings.xml" lang="hr" type="android" />
+ <output filename="values-hu/web_contents_delegate_android_strings.xml" lang="hu" type="android" />
+ <output filename="values-in/web_contents_delegate_android_strings.xml" lang="id" type="android" />
+ <output filename="values-it/web_contents_delegate_android_strings.xml" lang="it" type="android" />
+ <output filename="values-iw/web_contents_delegate_android_strings.xml" lang="he" type="android" />
+ <output filename="values-ja/web_contents_delegate_android_strings.xml" lang="ja" type="android" />
+ <output filename="values-ko/web_contents_delegate_android_strings.xml" lang="ko" type="android" />
+ <output filename="values-lt/web_contents_delegate_android_strings.xml" lang="lt" type="android" />
+ <output filename="values-lv/web_contents_delegate_android_strings.xml" lang="lv" type="android" />
+ <output filename="values-nl/web_contents_delegate_android_strings.xml" lang="nl" type="android" />
+ <output filename="values-nb/web_contents_delegate_android_strings.xml" lang="no" type="android" />
+ <output filename="values-pl/web_contents_delegate_android_strings.xml" lang="pl" type="android" />
+ <output filename="values-pt-rBR/web_contents_delegate_android_strings.xml" lang="pt-BR" type="android" />
+ <output filename="values-pt-rPT/web_contents_delegate_android_strings.xml" lang="pt-PT" type="android" />
+ <output filename="values-ro/web_contents_delegate_android_strings.xml" lang="ro" type="android" />
+ <output filename="values-ru/web_contents_delegate_android_strings.xml" lang="ru" type="android" />
+ <output filename="values-sk/web_contents_delegate_android_strings.xml" lang="sk" type="android" />
+ <output filename="values-sl/web_contents_delegate_android_strings.xml" lang="sl" type="android" />
+ <output filename="values-sr/web_contents_delegate_android_strings.xml" lang="sr" type="android" />
+ <output filename="values-sv/web_contents_delegate_android_strings.xml" lang="sv" type="android" />
+ <output filename="values-sw/web_contents_delegate_android_strings.xml" lang="sw" type="android" />
+ <output filename="values-th/web_contents_delegate_android_strings.xml" lang="th" type="android" />
+ <output filename="values-tr/web_contents_delegate_android_strings.xml" lang="tr" type="android" />
+ <output filename="values-uk/web_contents_delegate_android_strings.xml" lang="uk" type="android" />
+ <output filename="values-vi/web_contents_delegate_android_strings.xml" lang="vi" type="android" />
+ <output filename="values-zh-rCN/web_contents_delegate_android_strings.xml" lang="zh-CN" type="android" />
+ <output filename="values-zh-rTW/web_contents_delegate_android_strings.xml" lang="zh-TW" type="android" />
+ </outputs>
+ <translations>
+ <file lang="am" path="translations/web_contents_delegate_android_strings_am.xtb" />
+ <file lang="ar" path="translations/web_contents_delegate_android_strings_ar.xtb" />
+ <file lang="bg" path="translations/web_contents_delegate_android_strings_bg.xtb" />
+ <file lang="ca" path="translations/web_contents_delegate_android_strings_ca.xtb" />
+ <file lang="cs" path="translations/web_contents_delegate_android_strings_cs.xtb" />
+ <file lang="da" path="translations/web_contents_delegate_android_strings_da.xtb" />
+ <file lang="de" path="translations/web_contents_delegate_android_strings_de.xtb" />
+ <file lang="el" path="translations/web_contents_delegate_android_strings_el.xtb" />
+ <file lang="en-GB" path="translations/web_contents_delegate_android_strings_en-GB.xtb" />
+ <file lang="es" path="translations/web_contents_delegate_android_strings_es.xtb" />
+ <file lang="es-419" path="translations/web_contents_delegate_android_strings_es-419.xtb" />
+ <file lang="fa" path="translations/web_contents_delegate_android_strings_fa.xtb" />
+ <file lang="fi" path="translations/web_contents_delegate_android_strings_fi.xtb" />
+ <file lang="fil" path="translations/web_contents_delegate_android_strings_fil.xtb" />
+ <file lang="fr" path="translations/web_contents_delegate_android_strings_fr.xtb" />
+ <file lang="hi" path="translations/web_contents_delegate_android_strings_hi.xtb" />
+ <file lang="hr" path="translations/web_contents_delegate_android_strings_hr.xtb" />
+ <file lang="hu" path="translations/web_contents_delegate_android_strings_hu.xtb" />
+ <file lang="id" path="translations/web_contents_delegate_android_strings_id.xtb" />
+ <file lang="it" path="translations/web_contents_delegate_android_strings_it.xtb" />
+ <file lang="iw" path="translations/web_contents_delegate_android_strings_iw.xtb" />
+ <file lang="ja" path="translations/web_contents_delegate_android_strings_ja.xtb" />
+ <file lang="ko" path="translations/web_contents_delegate_android_strings_ko.xtb" />
+ <file lang="lt" path="translations/web_contents_delegate_android_strings_lt.xtb" />
+ <file lang="lv" path="translations/web_contents_delegate_android_strings_lv.xtb" />
+ <file lang="nl" path="translations/web_contents_delegate_android_strings_nl.xtb" />
+ <file lang="no" path="translations/web_contents_delegate_android_strings_no.xtb" />
+ <file lang="pl" path="translations/web_contents_delegate_android_strings_pl.xtb" />
+ <file lang="pt-BR" path="translations/web_contents_delegate_android_strings_pt-BR.xtb" />
+ <file lang="pt-PT" path="translations/web_contents_delegate_android_strings_pt-PT.xtb" />
+ <file lang="ro" path="translations/web_contents_delegate_android_strings_ro.xtb" />
+ <file lang="ru" path="translations/web_contents_delegate_android_strings_ru.xtb" />
+ <file lang="sk" path="translations/web_contents_delegate_android_strings_sk.xtb" />
+ <file lang="sl" path="translations/web_contents_delegate_android_strings_sl.xtb" />
+ <file lang="sr" path="translations/web_contents_delegate_android_strings_sr.xtb" />
+ <file lang="sv" path="translations/web_contents_delegate_android_strings_sv.xtb" />
+ <file lang="sw" path="translations/web_contents_delegate_android_strings_sw.xtb" />
+ <file lang="th" path="translations/web_contents_delegate_android_strings_th.xtb" />
+ <file lang="tr" path="translations/web_contents_delegate_android_strings_tr.xtb" />
+ <file lang="uk" path="translations/web_contents_delegate_android_strings_uk.xtb" />
+ <file lang="vi" path="translations/web_contents_delegate_android_strings_vi.xtb" />
+ <file lang="zh-CN" path="translations/web_contents_delegate_android_strings_zh-CN.xtb" />
+ <file lang="zh-TW" path="translations/web_contents_delegate_android_strings_zh-TW.xtb" />
+ </translations>
+ <release allow_pseudo="false" seq="1">
+ <messages fallback_to_english="true">
+ <!-- Color picker -->
+ <message name="IDS_COLOR_PICKER_BUTTON_MORE" desc="Text for ColorPicker button to go to advanced view. [CHAR-LIMIT=20]">
+ More
+ </message>
+ <message name="IDS_COLOR_PICKER_HUE" desc="Label for hue slider in ColorPicker.">
+ Hue
+ </message>
+ <message name="IDS_COLOR_PICKER_SATURATION" desc="Label for saturation slider in ColorPicker.">
+ Saturation
+ </message>
+ <message name="IDS_COLOR_PICKER_VALUE" desc="Label for value slider in ColorPicker.">
+ Value
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_SET" desc="Label for button in ColorPicker dialog for user to accept the currently chosen color. [CHAR-LIMIT=20]">
+ Set
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_CANCEL" desc="Label for button in ColorPicker dialog for user to cancel picking a color. [CHAR-LIMIT=20]">
+ Cancel
+ </message>
+ <message name="IDS_COLOR_PICKER_DIALOG_TITLE" desc="Title of ColorPicker dialog. [CHAR-LIMIT=20]">
+ Select color
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_RED" desc="Accessibility label for button to select the red color.">
+ Red
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_CYAN" desc="Accessibility label for button to select the cyan color.">
+ Cyan
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_BLUE" desc="Accessibility label for button to select the blue color.">
+ Blue
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_GREEN" desc="Accessibility label for button to select the green color.">
+ Green
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_MAGENTA" desc="Accessibility label for button to select the magenta color.">
+ Magenta
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_YELLOW" desc="Accessibility label for button to select the yellow color.">
+ Yellow
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_BLACK" desc="Accessibility label for button to select the black color.">
+ Black
+ </message>
+ <message name="IDS_COLOR_PICKER_BUTTON_WHITE" desc="Accessibility label for button to select the white color.">
+ White
+ </message>
+ </messages>
+ </release>
+</grit>
diff --git a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
index 2f15a5e5c68..edfb81d0f1e 100644
--- a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
+++ b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
@@ -14,13 +14,6 @@
using base::android::ConvertUTF16ToJavaString;
namespace {
-
-gfx::Rect ScaleToRoundedRect(const gfx::Rect& rect, float scale) {
- gfx::RectF scaledRect(rect);
- scaledRect.Scale(scale);
- return ToNearestRect(scaledRect);
-}
-
gfx::Size ScaleToRoundedSize(const gfx::SizeF& size, float scale) {
return gfx::ToRoundedSize(gfx::ScaleSize(size, scale));
}
@@ -55,7 +48,9 @@ void ValidationMessageBubbleAndroid::ShowAtPositionRelativeToAnchor(
// Convert to physical unit before passing to Java.
float scale = view->GetDipScale() * view->page_scale();
- gfx::Rect anchor = ScaleToRoundedRect(anchor_in_screen, scale);
+ gfx::RectF anchor_f = gfx::RectF(anchor_in_screen);
+ anchor_f.Scale(scale);
+ gfx::Rect anchor = ToNearestRect(anchor_f);
gfx::Size viewport = ScaleToRoundedSize(view->viewport_size(), scale);
JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
index df91a2aecc4..326dbf6de54 100644
--- a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
+++ b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
@@ -28,6 +28,7 @@
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
using content::ColorChooser;
using content::RenderWidgetHostView;
@@ -302,8 +303,8 @@ void WebContentsDelegateAndroid::UpdateTargetURL(WebContents* source,
void WebContentsDelegateAndroid::HandleKeyboardEvent(
WebContents* source,
const content::NativeWebKeyboardEvent& event) {
- jobject key_event = event.os_event;
- if (key_event) {
+ const JavaRef<jobject>& key_event = event.os_event;
+ if (!key_event.is_null()) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
diff --git a/chromium/components/web_contents_delegate_android_strings.grdp b/chromium/components/web_contents_delegate_android_strings.grdp
deleted file mode 100644
index fcac7d1afc2..00000000000
--- a/chromium/components/web_contents_delegate_android_strings.grdp
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
-
- <!-- Color picker -->
- <message name="IDS_COLOR_PICKER_BUTTON_MORE" desc="Text for ColorPicker button to go to advanced view. [CHAR-LIMIT=20]" formatter_data="android_java">
- More
- </message>
- <message name="IDS_COLOR_PICKER_HUE" desc="Label for hue slider in ColorPicker." formatter_data="android_java">
- Hue
- </message>
- <message name="IDS_COLOR_PICKER_SATURATION" desc="Label for saturation slider in ColorPicker." formatter_data="android_java">
- Saturation
- </message>
- <message name="IDS_COLOR_PICKER_VALUE" desc="Label for value slider in ColorPicker." formatter_data="android_java">
- Value
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_SET" desc="Label for button in ColorPicker dialog for user to accept the currently chosen color. [CHAR-LIMIT=20]" formatter_data="android_java">
- Set
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_CANCEL" desc="Label for button in ColorPicker dialog for user to cancel picking a color. [CHAR-LIMIT=20]" formatter_data="android_java">
- Cancel
- </message>
- <message name="IDS_COLOR_PICKER_DIALOG_TITLE" desc="Title of ColorPicker dialog. [CHAR-LIMIT=20]" formatter_data="android_java">
- Select color
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_RED" desc="Accessibility label for button to select the red color." formatter_data="android_java">
- Red
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_CYAN" desc="Accessibility label for button to select the cyan color." formatter_data="android_java">
- Cyan
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_BLUE" desc="Accessibility label for button to select the blue color." formatter_data="android_java">
- Blue
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_GREEN" desc="Accessibility label for button to select the green color." formatter_data="android_java">
- Green
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_MAGENTA" desc="Accessibility label for button to select the magenta color." formatter_data="android_java">
- Magenta
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_YELLOW" desc="Accessibility label for button to select the yellow color." formatter_data="android_java">
- Yellow
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_BLACK" desc="Accessibility label for button to select the black color." formatter_data="android_java">
- Black
- </message>
- <message name="IDS_COLOR_PICKER_BUTTON_WHITE" desc="Accessibility label for button to select the white color." formatter_data="android_java">
- White
- </message>
-
-</grit-part> \ No newline at end of file
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.h b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
index fdb684f8618..ce5df83445a 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
@@ -5,9 +5,9 @@
#ifndef COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_
#define COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_
-#include <deque>
#include <memory>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "components/web_modal/single_web_contents_dialog_manager.h"
@@ -85,7 +85,7 @@ class WebContentsModalDialogManager
std::unique_ptr<SingleWebContentsDialogManager> manager;
};
- typedef std::deque<DialogState*> WebContentsModalDialogList;
+ typedef base::circular_deque<DialogState*> WebContentsModalDialogList;
// Utility function to get the dialog state for a dialog.
WebContentsModalDialogList::iterator FindDialogState(
diff --git a/chromium/components/web_resource/resource_request_allowed_notifier.cc b/chromium/components/web_resource/resource_request_allowed_notifier.cc
index 4842a43ce26..f0d57cc9267 100644
--- a/chromium/components/web_resource/resource_request_allowed_notifier.cc
+++ b/chromium/components/web_resource/resource_request_allowed_notifier.cc
@@ -21,14 +21,14 @@ ResourceRequestAllowedNotifier::ResourceRequestAllowedNotifier(
ResourceRequestAllowedNotifier::~ResourceRequestAllowedNotifier() {
if (observer_)
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
void ResourceRequestAllowedNotifier::Init(Observer* observer) {
DCHECK(!observer_ && observer);
observer_ = observer;
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
// Check this state during initialization. It is not expected to change until
// the corresponding notification is received.
@@ -102,7 +102,7 @@ void ResourceRequestAllowedNotifier::OnEulaAccepted() {
MaybeNotifyObserver();
}
-void ResourceRequestAllowedNotifier::OnConnectionTypeChanged(
+void ResourceRequestAllowedNotifier::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) {
// Only attempt to notify observers if this was previously waiting for the
// network to reconnect, and new network state is actually available. This
diff --git a/chromium/components/web_resource/resource_request_allowed_notifier.h b/chromium/components/web_resource/resource_request_allowed_notifier.h
index a6e9ac40e6b..2cda1595c74 100644
--- a/chromium/components/web_resource/resource_request_allowed_notifier.h
+++ b/chromium/components/web_resource/resource_request_allowed_notifier.h
@@ -37,7 +37,7 @@ namespace web_resource {
// global instance.
class ResourceRequestAllowedNotifier
: public EulaAcceptedNotifier::Observer,
- public net::NetworkChangeNotifier::ConnectionTypeObserver {
+ public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
// Observes resource request allowed state changes.
class Observer {
@@ -96,8 +96,8 @@ class ResourceRequestAllowedNotifier
// EulaAcceptedNotifier::Observer overrides:
void OnEulaAccepted() override;
- // net::NetworkChangeNotifier::ConnectionTypeObserver overrides:
- void OnConnectionTypeChanged(
+ // net::NetworkChangeNotifier::NetworkChangeObserver overrides:
+ void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
// Name of the command line switch to disable the network activity.
diff --git a/chromium/components/web_resource/resource_request_allowed_notifier_unittest.cc b/chromium/components/web_resource/resource_request_allowed_notifier_unittest.cc
index 014a0ec36a0..dc5fae9c56c 100644
--- a/chromium/components/web_resource/resource_request_allowed_notifier_unittest.cc
+++ b/chromium/components/web_resource/resource_request_allowed_notifier_unittest.cc
@@ -27,7 +27,7 @@ class TestNetworkChangeNotifier : public net::NetworkChangeNotifier {
void SimulateNetworkConnectionChange(
net::NetworkChangeNotifier::ConnectionType type) {
connection_type_to_return_ = type;
- net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
connection_type_to_return_);
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client.cc b/chromium/components/web_restrictions/browser/web_restrictions_client.cc
index ea67fdc1e20..a0fc8cf8fcd 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client.cc
@@ -39,11 +39,6 @@ bool CheckSupportsRequestTask(
} // namespace
-// static
-bool WebRestrictionsClient::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
WebRestrictionsClient::WebRestrictionsClient()
: initialized_(false), supports_request_(false) {
background_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client.h b/chromium/components/web_restrictions/browser/web_restrictions_client.h
index 3bd54d9342c..12ccc63e2d5 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client.h
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client.h
@@ -34,9 +34,6 @@ class WebRestrictionsClient {
WebRestrictionsClient();
~WebRestrictionsClient();
- // Register JNI methods.
- static bool Register(JNIEnv* env);
-
// Verify the content provider and query it for basic information like does it
// support handling requests. This should be called everytime the provider
// changes. An empty authority can be used to disable this class.
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc b/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc
index 6eab3d5beb9..3ff66b41a35 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc
@@ -19,36 +19,35 @@ WebRestrictionsClientResult::WebRestrictionsClientResult(
int WebRestrictionsClientResult::GetInt(int column) const {
return Java_WebRestrictionsClientResult_getInt(
- base::android::AttachCurrentThread(), jresult_.obj(), column);
+ base::android::AttachCurrentThread(), jresult_, column);
}
std::string WebRestrictionsClientResult::GetString(int column) const {
JNIEnv* env = base::android::AttachCurrentThread();
return base::android::ConvertJavaStringToUTF8(
- env,
- Java_WebRestrictionsClientResult_getString(env, jresult_.obj(), column));
+ env, Java_WebRestrictionsClientResult_getString(env, jresult_, column));
}
std::string WebRestrictionsClientResult::GetColumnName(int column) const {
JNIEnv* env = base::android::AttachCurrentThread();
return base::android::ConvertJavaStringToUTF8(
- env, Java_WebRestrictionsClientResult_getColumnName(env, jresult_.obj(),
- column));
+ env,
+ Java_WebRestrictionsClientResult_getColumnName(env, jresult_, column));
}
bool WebRestrictionsClientResult::ShouldProceed() const {
return Java_WebRestrictionsClientResult_shouldProceed(
- base::android::AttachCurrentThread(), jresult_.obj());
+ base::android::AttachCurrentThread(), jresult_);
}
int web_restrictions::WebRestrictionsClientResult::GetColumnCount() const {
return Java_WebRestrictionsClientResult_getColumnCount(
- base::android::AttachCurrentThread(), jresult_.obj());
+ base::android::AttachCurrentThread(), jresult_);
}
bool web_restrictions::WebRestrictionsClientResult::IsString(int column) const {
return Java_WebRestrictionsClientResult_isString(
- base::android::AttachCurrentThread(), jresult_.obj(), column);
+ base::android::AttachCurrentThread(), jresult_, column);
}
} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
index 933bb326569..89bf250acf1 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
@@ -27,7 +27,6 @@ class TestResourceThrottleDelegate
quit_closure_(quit_closure) {}
void Cancel() override {}
- void CancelAndIgnore() override {}
void CancelWithError(int error_code) override {
cancel_with_error_called_ = true;
error_code_ = error_code;
diff --git a/chromium/components/webcrypto/BUILD.gn b/chromium/components/webcrypto/BUILD.gn
index 576247ddf4e..fdb059bbd75 100644
--- a/chromium/components/webcrypto/BUILD.gn
+++ b/chromium/components/webcrypto/BUILD.gn
@@ -109,6 +109,7 @@ source_set("fuzzer_support") {
"//base",
"//crypto",
"//crypto:platform",
+ "//mojo/edk/system",
"//third_party/WebKit/public:blink",
]
}
diff --git a/chromium/components/webcrypto/DEPS b/chromium/components/webcrypto/DEPS
index 5d9852bf42d..8c722f91111 100644
--- a/chromium/components/webcrypto/DEPS
+++ b/chromium/components/webcrypto/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+crypto",
+ "+mojo/edk/embedder",
"+third_party/boringssl/src/include",
"+third_party/re2",
"+third_party/WebKit/public/platform",
diff --git a/chromium/components/webcrypto/fuzzer_support.cc b/chromium/components/webcrypto/fuzzer_support.cc
index 832a9b87e15..f0d119179d9 100644
--- a/chromium/components/webcrypto/fuzzer_support.cc
+++ b/chromium/components/webcrypto/fuzzer_support.cc
@@ -10,6 +10,7 @@
#include "components/webcrypto/algorithm_dispatch.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/status.h"
+#include "mojo/edk/embedder/embedder.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/web/WebKit.h"
@@ -19,10 +20,11 @@ namespace webcrypto {
namespace {
// This mock is used to initialize blink.
-class InitOnce : NON_EXPORTED_BASE(public blink::Platform) {
+class InitOnce : public blink::Platform {
public:
InitOnce() {
base::CommandLine::Init(0, nullptr);
+ mojo::edk::Init();
blink::Platform::Initialize(this);
}
~InitOnce() override {}
diff --git a/chromium/components/webdata/common/web_data_request_manager.h b/chromium/components/webdata/common/web_data_request_manager.h
index 2b96076ddfe..6f418efb47c 100644
--- a/chromium/components/webdata/common/web_data_request_manager.h
+++ b/chromium/components/webdata/common/web_data_request_manager.h
@@ -15,6 +15,7 @@
#include "base/atomicops.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_base.h"
@@ -24,10 +25,6 @@
class WebDataServiceConsumer;
class WebDataRequestManager;
-namespace base {
-class SequencedTaskRunner;
-}
-
//////////////////////////////////////////////////////////////////////////////
//
// WebData requests
diff --git a/chromium/components/webdata/common/web_data_service_base.cc b/chromium/components/webdata/common/web_data_service_base.cc
index f3cb0d58999..64ef475a253 100644
--- a/chromium/components/webdata/common/web_data_service_base.cc
+++ b/chromium/components/webdata/common/web_data_service_base.cc
@@ -22,13 +22,12 @@ using base::Time;
WebDataServiceBase::WebDataServiceBase(
scoped_refptr<WebDatabaseService> wdbs,
const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread)
- : base::RefCountedDeleteOnSequence<WebDataServiceBase>(ui_thread),
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
+ : base::RefCountedDeleteOnSequence<WebDataServiceBase>(ui_task_runner),
wdbs_(wdbs),
profile_error_callback_(callback) {}
-void WebDataServiceBase::ShutdownOnUIThread() {
-}
+void WebDataServiceBase::ShutdownOnUISequence() {}
void WebDataServiceBase::Init() {
DCHECK(wdbs_.get());
diff --git a/chromium/components/webdata/common/web_data_service_base.h b/chromium/components/webdata/common/web_data_service_base.h
index 0c442c698f3..ead8360b78e 100644
--- a/chromium/components/webdata/common/web_data_service_base.h
+++ b/chromium/components/webdata/common/web_data_service_base.h
@@ -21,7 +21,7 @@ class SingleThreadTaskRunner;
}
// Base for WebDataService class hierarchy.
-// WebDataServiceBase is destroyed on the UI thread.
+// WebDataServiceBase is destroyed on the UI sequence.
class WEBDATA_EXPORT WebDataServiceBase
: public base::RefCountedDeleteOnSequence<WebDataServiceBase> {
public:
@@ -46,11 +46,11 @@ class WEBDATA_EXPORT WebDataServiceBase
// WebDataServiceBase, which receive |wdbs| upon construction. The
// WebDataServiceWrapper handles the initializing and shutting down and of
// the |wdbs| object.
- // WebDataServiceBase is destroyed on |ui_thread|.
+ // WebDataServiceBase is destroyed on the UI sequence.
WebDataServiceBase(
scoped_refptr<WebDatabaseService> wdbs,
const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread);
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
// Cancel any pending request. You need to call this method if your
// WebDataServiceConsumer is about to be deleted.
@@ -58,7 +58,7 @@ class WEBDATA_EXPORT WebDataServiceBase
// Shutdown the web data service. The service can no longer be used after this
// call.
- virtual void ShutdownOnUIThread();
+ virtual void ShutdownOnUISequence();
// Initializes the web data service.
virtual void Init();
@@ -74,12 +74,12 @@ class WEBDATA_EXPORT WebDataServiceBase
virtual void RegisterDBLoadedCallback(const DBLoadedCallback& callback);
// Returns true if the database load has completetd successfully, and
- // ShutdownOnUIThread has not yet been called.
+ // ShutdownOnUISequence() has not yet been called.
virtual bool IsDatabaseLoaded();
// Returns a pointer to the DB (used by SyncableServices). May return NULL if
- // the database is not loaded or otherwise unavailable. Must be called on
- // DBThread.
+ // the database is not loaded or otherwise unavailable. Must be called on DB
+ // sequence.
virtual WebDatabase* GetDatabase();
protected:
diff --git a/chromium/components/webdata/common/web_database_service.cc b/chromium/components/webdata/common/web_database_service.cc
index 412ee9bdb04..ca409e51ef5 100644
--- a/chromium/components/webdata/common/web_database_service.cc
+++ b/chromium/components/webdata/common/web_database_service.cc
@@ -18,39 +18,37 @@
using base::Bind;
using base::FilePath;
-// Receives messages from the backend on the DB thread, posts them to
-// WebDatabaseService on the UI thread.
+// Receives messages from the backend on the DB sequence, posts them to
+// WebDatabaseService on the UI sequence.
class WebDatabaseService::BackendDelegate
: public WebDatabaseBackend::Delegate {
public:
BackendDelegate(const base::WeakPtr<WebDatabaseService>& web_database_service)
: web_database_service_(web_database_service),
- callback_thread_(base::ThreadTaskRunnerHandle::Get()) {}
+ callback_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
void DBLoaded(sql::InitStatus status,
const std::string& diagnostics) override {
- callback_thread_->PostTask(
+ callback_task_runner_->PostTask(
FROM_HERE, base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
web_database_service_, status, diagnostics));
}
private:
const base::WeakPtr<WebDatabaseService> web_database_service_;
- scoped_refptr<base::SingleThreadTaskRunner> callback_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
};
WebDatabaseService::WebDatabaseService(
const base::FilePath& path,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread)
- : base::RefCountedDeleteOnSequence<WebDatabaseService>(ui_thread),
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner)
+ : base::RefCountedDeleteOnSequence<WebDatabaseService>(ui_task_runner),
path_(path),
db_loaded_(false),
- db_thread_(db_thread),
+ db_task_runner_(db_task_runner),
weak_ptr_factory_(this) {
- // WebDatabaseService should be instantiated on UI thread.
- DCHECK(ui_thread->BelongsToCurrentThread());
- // WebDatabaseService requires DB thread if instantiated.
- DCHECK(db_thread.get());
+ DCHECK(ui_task_runner->RunsTasksInCurrentSequence());
+ DCHECK(db_task_runner_.get());
}
WebDatabaseService::~WebDatabaseService() {
@@ -59,14 +57,15 @@ WebDatabaseService::~WebDatabaseService() {
void WebDatabaseService::AddTable(std::unique_ptr<WebDatabaseTable> table) {
if (!web_db_backend_.get()) {
web_db_backend_ = new WebDatabaseBackend(
- path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()), db_thread_);
+ path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()),
+ db_task_runner_);
}
web_db_backend_->AddTable(std::move(table));
}
void WebDatabaseService::LoadDatabase() {
DCHECK(web_db_backend_.get());
- db_thread_->PostTask(
+ db_task_runner_->PostTask(
FROM_HERE, Bind(&WebDatabaseBackend::InitDatabase, web_db_backend_));
}
@@ -77,12 +76,12 @@ void WebDatabaseService::ShutdownDatabase() {
weak_ptr_factory_.InvalidateWeakPtrs();
if (!web_db_backend_.get())
return;
- db_thread_->PostTask(
+ db_task_runner_->PostTask(
FROM_HERE, Bind(&WebDatabaseBackend::ShutdownDatabase, web_db_backend_));
}
WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
- DCHECK(db_thread_->BelongsToCurrentThread());
+ DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
return web_db_backend_.get() ? web_db_backend_->database() : NULL;
}
@@ -96,7 +95,7 @@ void WebDatabaseService::ScheduleDBTask(
DCHECK(web_db_backend_.get());
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest(nullptr);
- db_thread_->PostTask(
+ db_task_runner_->PostTask(
from_here, Bind(&WebDatabaseBackend::DBWriteTaskWrapper, web_db_backend_,
task, base::Passed(&request)));
}
@@ -110,7 +109,7 @@ WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest(consumer);
WebDataServiceBase::Handle handle = request->GetHandle();
- db_thread_->PostTask(
+ db_task_runner_->PostTask(
from_here, Bind(&WebDatabaseBackend::DBReadTaskWrapper, web_db_backend_,
task, base::Passed(&request)));
return handle;
diff --git a/chromium/components/webdata/common/web_database_service.h b/chromium/components/webdata/common/web_database_service.h
index 7a507ba3f69..c33d6f0d495 100644
--- a/chromium/components/webdata/common/web_database_service.h
+++ b/chromium/components/webdata/common/web_database_service.h
@@ -53,11 +53,12 @@ class WEBDATA_EXPORT WebDatabaseService
using DBLoadErrorCallback =
base::Callback<void(sql::InitStatus, const std::string&)>;
- // Takes the path to the WebDatabase file.
- // WebDatabaseService lives on |ui_thread| and posts tasks to |db_thread|.
- WebDatabaseService(const base::FilePath& path,
- scoped_refptr<base::SingleThreadTaskRunner> ui_thread,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread);
+ // WebDatabaseService lives on the UI sequence and posts tasks to the DB
+ // sequence. |path| points to the WebDatabase file.
+ WebDatabaseService(
+ const base::FilePath& path,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner);
// Adds |table| as a WebDatabaseTable that will participate in
// managing the database, transferring ownership. All calls to this
@@ -77,18 +78,18 @@ class WEBDATA_EXPORT WebDatabaseService
// Returns a pointer to the WebDatabaseBackend.
scoped_refptr<WebDatabaseBackend> GetBackend() const;
- // Schedule an update/write task on the DB thread.
+ // Schedule an update/write task on the DB sequence.
virtual void ScheduleDBTask(
const tracked_objects::Location& from_here,
const WriteTask& task);
- // Schedule a read task on the DB thread.
+ // Schedule a read task on the DB sequence.
virtual WebDataServiceBase::Handle ScheduleDBTaskWithResult(
const tracked_objects::Location& from_here,
const ReadTask& task,
WebDataServiceConsumer* consumer);
- // Cancel an existing request for a task on the DB thread.
+ // Cancel an existing request for a task on the DB sequence.
// TODO(caitkp): Think about moving the definition of the Handle type to
// somewhere else.
virtual void CancelRequest(WebDataServiceBase::Handle h);
@@ -126,7 +127,7 @@ class WEBDATA_EXPORT WebDatabaseService
base::FilePath path_;
// The primary owner is |WebDatabaseService| but is refcounted because
- // PostTask on DB thread may outlive us.
+ // PostTask on DB sequence may outlive us.
scoped_refptr<WebDatabaseBackend> web_db_backend_;
// Callbacks to be called once the DB has loaded.
@@ -138,7 +139,7 @@ class WEBDATA_EXPORT WebDatabaseService
// True if the WebDatabase has loaded.
bool db_loaded_;
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
// All vended weak pointers are invalidated in ShutdownDatabase().
base::WeakPtrFactory<WebDatabaseService> weak_ptr_factory_;
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.cc b/chromium/components/webdata_services/web_data_service_wrapper.cc
index 9d3e6e7b2f6..2c1a9ac4251 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.cc
+++ b/chromium/components/webdata_services/web_data_service_wrapper.cc
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
@@ -39,14 +40,14 @@
namespace {
-void InitSyncableServicesOnDBThread(
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+void InitSyncableServicesOnDBSequence(
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
const syncer::SyncableService::StartSyncFlare& sync_flare,
const scoped_refptr<autofill::AutofillWebDataService>& autofill_web_data,
const base::FilePath& context_path,
const std::string& app_locale,
autofill::AutofillWebDataBackend* autofill_backend) {
- DCHECK(db_thread->BelongsToCurrentThread());
+ DCHECK(db_task_runner->RunsTasksInCurrentSequence());
// Currently only Autocomplete and Autofill profiles use the new Sync API, but
// all the database data should migrate to this API over time.
@@ -83,12 +84,17 @@ WebDataServiceWrapper::WebDataServiceWrapper() {
WebDataServiceWrapper::WebDataServiceWrapper(
const base::FilePath& context_path,
const std::string& application_locale,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const syncer::SyncableService::StartSyncFlare& flare,
const ShowErrorCallback& show_error_callback) {
base::FilePath path = context_path.Append(kWebDataFilename);
- web_database_ = new WebDatabaseService(path, ui_thread, db_thread);
+ // TODO(pkasting): http://crbug.com/740773 This should likely be sequenced,
+ // not single-threaded; it's also possible the various uses of this below
+ // should each use their own sequences instead of sharing this one.
+ auto db_task_runner = base::CreateSingleThreadTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+ web_database_ = new WebDatabaseService(path, ui_task_runner, db_task_runner);
// All tables objects that participate in managing the database must
// be added here.
@@ -108,23 +114,23 @@ WebDataServiceWrapper::WebDataServiceWrapper(
web_database_->LoadDatabase();
autofill_web_data_ = new autofill::AutofillWebDataService(
- web_database_, ui_thread, db_thread,
+ web_database_, ui_task_runner, db_task_runner,
base::Bind(show_error_callback, ERROR_LOADING_AUTOFILL));
autofill_web_data_->Init();
keyword_web_data_ = new KeywordWebDataService(
- web_database_, ui_thread,
+ web_database_, ui_task_runner,
base::Bind(show_error_callback, ERROR_LOADING_KEYWORD));
keyword_web_data_->Init();
- token_web_data_ = new TokenWebData(
- web_database_, ui_thread, db_thread,
- base::Bind(show_error_callback, ERROR_LOADING_TOKEN));
+ token_web_data_ =
+ new TokenWebData(web_database_, ui_task_runner, db_task_runner,
+ base::Bind(show_error_callback, ERROR_LOADING_TOKEN));
token_web_data_->Init();
#if defined(OS_WIN)
password_web_data_ = new PasswordWebDataService(
- web_database_, ui_thread,
+ web_database_, ui_task_runner,
base::Bind(show_error_callback, ERROR_LOADING_PASSWORD));
password_web_data_->Init();
#endif
@@ -133,11 +139,11 @@ WebDataServiceWrapper::WebDataServiceWrapper(
payment_manifest_web_data_ = new payments::PaymentManifestWebDataService(
web_database_,
base::Bind(show_error_callback, ERROR_LOADING_PAYMENT_MANIFEST),
- ui_thread);
+ ui_task_runner);
#endif
autofill_web_data_->GetAutofillBackend(
- base::Bind(&InitSyncableServicesOnDBThread, db_thread, flare,
+ base::Bind(&InitSyncableServicesOnDBSequence, db_task_runner, flare,
autofill_web_data_, context_path, application_locale));
}
@@ -145,16 +151,16 @@ WebDataServiceWrapper::~WebDataServiceWrapper() {
}
void WebDataServiceWrapper::Shutdown() {
- autofill_web_data_->ShutdownOnUIThread();
- keyword_web_data_->ShutdownOnUIThread();
- token_web_data_->ShutdownOnUIThread();
+ autofill_web_data_->ShutdownOnUISequence();
+ keyword_web_data_->ShutdownOnUISequence();
+ token_web_data_->ShutdownOnUISequence();
#if defined(OS_WIN)
- password_web_data_->ShutdownOnUIThread();
+ password_web_data_->ShutdownOnUISequence();
#endif
#if defined(OS_ANDROID)
- payment_manifest_web_data_->ShutdownOnUIThread();
+ payment_manifest_web_data_->ShutdownOnUISequence();
#endif
web_database_->ShutdownDatabase();
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.h b/chromium/components/webdata_services/web_data_service_wrapper.h
index c1096ad9841..2ad03979632 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.h
+++ b/chromium/components/webdata_services/web_data_service_wrapper.h
@@ -69,8 +69,7 @@ class WebDataServiceWrapper : public KeyedService {
WebDataServiceWrapper(
const base::FilePath& context_path,
const std::string& application_locale,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const syncer::SyncableService::StartSyncFlare& flare,
const ShowErrorCallback& show_error_callback);
~WebDataServiceWrapper() override;
diff --git a/chromium/components/wifi/wifi_test.cc b/chromium/components/wifi/wifi_test.cc
index b6cb8fdaad7..9440d64d53c 100644
--- a/chromium/components/wifi/wifi_test.cc
+++ b/chromium/components/wifi/wifi_test.cc
@@ -53,7 +53,7 @@ class WiFiTest {
DCHECK_NE(RESULT_PENDING, result);
result_ = result;
if (base::MessageLoop::current())
- base::MessageLoop::current()->QuitWhenIdle();
+ base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
void OnNetworksChanged(